Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux into mips-for-linux-next

Conflicts:
    include/linux/ssb/ssb_driver_gige.h

Also resolves a logical merge conflict in drivers/net/ethernet/broadcom/-
bgmac.c due to change of an API.
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f5fb072..2b4e89b 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -134,6 +134,8 @@
 
 source "drivers/clocksource/Kconfig"
 
+source "drivers/mailbox/Kconfig"
+
 source "drivers/iommu/Kconfig"
 
 source "drivers/remoteproc/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 7863b9f..a8d32f1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -130,6 +130,7 @@
 #common clk code
 obj-y				+= clk/
 
+obj-$(CONFIG_MAILBOX)		+= mailbox/
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
 obj-$(CONFIG_NFC)		+= nfc/
 obj-$(CONFIG_IOMMU_SUPPORT)	+= iommu/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 38c5078..78105b3 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -337,7 +337,7 @@
 	  systems require this timer. 
 
 config ACPI_CONTAINER
-	tristate "Container and Module Devices (EXPERIMENTAL)"
+	bool "Container and Module Devices (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
 	default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
 	help
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 2a4502b..474fcfe 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -37,7 +37,8 @@
 acpi-y				+= processor_core.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
-acpi-y				+= pci_root.o pci_link.o pci_irq.o pci_bind.o
+acpi-y				+= pci_root.o pci_link.o pci_irq.o
+acpi-y				+= csrt.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= power.o
 acpi-y				+= event.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index d5fdd36..6d5bf64 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -60,7 +60,7 @@
 #endif
 
 static int acpi_ac_add(struct acpi_device *device);
-static int acpi_ac_remove(struct acpi_device *device, int type);
+static int acpi_ac_remove(struct acpi_device *device);
 static void acpi_ac_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id ac_device_ids[] = {
@@ -337,7 +337,7 @@
 }
 #endif
 
-static int acpi_ac_remove(struct acpi_device *device, int type)
+static int acpi_ac_remove(struct acpi_device *device)
 {
 	struct acpi_ac *ac = NULL;
 
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index b679bf8..034d3e7 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -54,7 +54,7 @@
 #define MEMORY_POWER_OFF_STATE	2
 
 static int acpi_memory_device_add(struct acpi_device *device);
-static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_remove(struct acpi_device *device);
 
 static const struct acpi_device_id memory_device_ids[] = {
 	{ACPI_MEMORY_DEVICE_HID, 0},
@@ -153,51 +153,46 @@
 	return 0;
 }
 
-static int
-acpi_memory_get_device(acpi_handle handle,
-		       struct acpi_memory_device **mem_device)
+static int acpi_memory_get_device(acpi_handle handle,
+				  struct acpi_memory_device **mem_device)
 {
-	acpi_status status;
-	acpi_handle phandle;
 	struct acpi_device *device = NULL;
-	struct acpi_device *pdevice = NULL;
-	int result;
+	int result = 0;
 
+	acpi_scan_lock_acquire();
 
-	if (!acpi_bus_get_device(handle, &device) && device)
+	acpi_bus_get_device(handle, &device);
+	if (device)
 		goto end;
 
-	status = acpi_get_parent(handle, &phandle);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
-		return -EINVAL;
-	}
-
-	/* Get the parent device */
-	result = acpi_bus_get_device(phandle, &pdevice);
-	if (result) {
-		acpi_handle_warn(phandle, "Cannot get acpi bus device\n");
-		return -EINVAL;
-	}
-
 	/*
 	 * Now add the notified device.  This creates the acpi_device
 	 * and invokes .add function
 	 */
-	result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
+	result = acpi_bus_scan(handle);
 	if (result) {
-		acpi_handle_warn(handle, "Cannot add acpi bus\n");
-		return -EINVAL;
+		acpi_handle_warn(handle, "ACPI namespace scan failed\n");
+		result = -EINVAL;
+		goto out;
+	}
+	result = acpi_bus_get_device(handle, &device);
+	if (result) {
+		acpi_handle_warn(handle, "Missing device object\n");
+		result = -EINVAL;
+		goto out;
 	}
 
-      end:
+ end:
 	*mem_device = acpi_driver_data(device);
 	if (!(*mem_device)) {
 		dev_err(&device->dev, "driver data not found\n");
-		return -ENODEV;
+		result = -ENODEV;
+		goto out;
 	}
 
-	return 0;
+ out:
+	acpi_scan_lock_release();
+	return result;
 }
 
 static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
@@ -317,6 +312,7 @@
 	struct acpi_device *device;
 	struct acpi_eject_event *ej_event = NULL;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+	acpi_status status;
 
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
@@ -339,29 +335,40 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "\nReceived EJECT REQUEST notification for device\n"));
 
+		status = AE_ERROR;
+		acpi_scan_lock_acquire();
+
 		if (acpi_bus_get_device(handle, &device)) {
 			acpi_handle_err(handle, "Device doesn't exist\n");
-			break;
+			goto unlock;
 		}
 		mem_device = acpi_driver_data(device);
 		if (!mem_device) {
 			acpi_handle_err(handle, "Driver Data is NULL\n");
-			break;
+			goto unlock;
 		}
 
 		ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
 		if (!ej_event) {
 			pr_err(PREFIX "No memory, dropping EJECT\n");
-			break;
+			goto unlock;
 		}
 
-		ej_event->handle = handle;
+		get_device(&device->dev);
+		ej_event->device = device;
 		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-		acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
-					(void *)ej_event);
+		/* The eject is carried out asynchronously. */
+		status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+						 ej_event);
+		if (ACPI_FAILURE(status)) {
+			put_device(&device->dev);
+			kfree(ej_event);
+		}
 
-		/* eject is performed asynchronously */
-		return;
+ unlock:
+		acpi_scan_lock_release();
+		if (ACPI_SUCCESS(status))
+			return;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
@@ -372,7 +379,6 @@
 
 	/* Inform firmware that the hotplug operation has completed */
 	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-	return;
 }
 
 static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
@@ -427,7 +433,7 @@
 	return result;
 }
 
-static int acpi_memory_device_remove(struct acpi_device *device, int type)
+static int acpi_memory_device_remove(struct acpi_device *device)
 {
 	struct acpi_memory_device *mem_device = NULL;
 	int result;
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 16fa979..31de104 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -482,8 +482,7 @@
 	return 0;
 }
 
-static int acpi_pad_remove(struct acpi_device *device,
-	int type)
+static int acpi_pad_remove(struct acpi_device *device)
 {
 	mutex_lock(&isolated_cpus_lock);
 	acpi_pad_idle_cpus(0);
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index db129b9..26fce4b 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -13,6 +13,7 @@
 
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -21,18 +22,59 @@
 
 ACPI_MODULE_NAME("platform");
 
+/* Flags for acpi_create_platform_device */
+#define ACPI_PLATFORM_CLK	BIT(0)
+
+/*
+ * The following ACPI IDs are known to be suitable for representing as
+ * platform devices.
+ */
+static const struct acpi_device_id acpi_platform_device_ids[] = {
+
+	{ "PNP0D40" },
+
+	/* Haswell LPSS devices */
+	{ "INT33C0", ACPI_PLATFORM_CLK },
+	{ "INT33C1", ACPI_PLATFORM_CLK },
+	{ "INT33C2", ACPI_PLATFORM_CLK },
+	{ "INT33C3", ACPI_PLATFORM_CLK },
+	{ "INT33C4", ACPI_PLATFORM_CLK },
+	{ "INT33C5", ACPI_PLATFORM_CLK },
+	{ "INT33C6", ACPI_PLATFORM_CLK },
+	{ "INT33C7", ACPI_PLATFORM_CLK },
+
+	{ }
+};
+
+static int acpi_create_platform_clks(struct acpi_device *adev)
+{
+	static struct platform_device *pdev;
+
+	/* Create Lynxpoint LPSS clocks */
+	if (!pdev && !strncmp(acpi_device_hid(adev), "INT33C", 6)) {
+		pdev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
+		if (IS_ERR(pdev))
+			return PTR_ERR(pdev);
+	}
+
+	return 0;
+}
+
 /**
  * acpi_create_platform_device - Create platform device for ACPI device node
  * @adev: ACPI device node to create a platform device for.
+ * @id: ACPI device ID used to match @adev.
  *
  * Check if the given @adev can be represented as a platform device and, if
  * that's the case, create and register a platform device, populate its common
  * resources and returns a pointer to it.  Otherwise, return %NULL.
  *
- * The platform device's name will be taken from the @adev's _HID and _UID.
+ * Name of the platform device will be the same as @adev's.
  */
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
+static int acpi_create_platform_device(struct acpi_device *adev,
+				       const struct acpi_device_id *id)
 {
+	unsigned long flags = id->driver_data;
 	struct platform_device *pdev = NULL;
 	struct acpi_device *acpi_parent;
 	struct platform_device_info pdevinfo;
@@ -41,20 +83,28 @@
 	struct resource *resources;
 	int count;
 
+	if (flags & ACPI_PLATFORM_CLK) {
+		int ret = acpi_create_platform_clks(adev);
+		if (ret) {
+			dev_err(&adev->dev, "failed to create clocks\n");
+			return ret;
+		}
+	}
+
 	/* If the ACPI node already has a physical device attached, skip it. */
 	if (adev->physical_node_count)
-		return NULL;
+		return 0;
 
 	INIT_LIST_HEAD(&resource_list);
 	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
 	if (count <= 0)
-		return NULL;
+		return 0;
 
 	resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
 	if (!resources) {
 		dev_err(&adev->dev, "No memory for resources\n");
 		acpi_dev_free_resource_list(&resource_list);
-		return NULL;
+		return -ENOMEM;
 	}
 	count = 0;
 	list_for_each_entry(rentry, &resource_list, node)
@@ -100,5 +150,15 @@
 	}
 
 	kfree(resources);
-	return pdev;
+	return 1;
+}
+
+static struct acpi_scan_handler platform_handler = {
+	.ids = acpi_platform_device_ids,
+	.attach = acpi_create_platform_device,
+};
+
+void __init acpi_platform_init(void)
+{
+	acpi_scan_add_handler(&platform_handler);
 }
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index bc7a03d..a1b9bf5 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -31,6 +31,7 @@
 	evgpeinit.o	\
 	evgpeutil.o	\
 	evglock.o	\
+	evhandler.o	\
 	evmisc.o	\
 	evregion.o	\
 	evrgnini.o	\
@@ -90,6 +91,7 @@
 	nsobject.o	\
 	nsparse.o	\
 	nspredef.o	\
+	nsprepkg.o	\
 	nsrepair.o	\
 	nsrepair2.o	\
 	nssearch.o	\
@@ -104,7 +106,9 @@
 acpi-y +=		\
 	psargs.o	\
 	psloop.o	\
+	psobject.o	\
 	psopcode.o	\
+	psopinfo.o	\
 	psparse.o	\
 	psscope.o	\
 	pstree.o	\
@@ -126,7 +130,7 @@
 	rsutils.o	\
 	rsxface.o
 
-acpi-$(ACPI_FUTURE_USAGE) += rsdump.o
+acpi-$(ACPI_FUTURE_USAGE) += rsdump.o rsdumpinfo.o
 
 acpi-y +=		\
 	tbfadt.o	\
@@ -155,8 +159,10 @@
 	utmutex.o	\
 	utobject.o	\
 	utosi.o		\
+	utownerid.o	\
 	utresrc.o	\
 	utstate.o	\
+	utstring.o	\
 	utxface.o	\
 	utxfinit.o	\
 	utxferror.o	\
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 8a7d51b..8a6c4a0 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@
  *
  * Note: The order of these include files is important.
  */
+#include <acpi/acconfig.h>	/* Global configuration constants */
 #include "acmacros.h"		/* C macros */
 #include "aclocal.h"		/* Internal data types */
 #include "acobject.h"		/* ACPI internal object */
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 432a318..9feba08 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,21 @@
 						   char *block_arg))
 
 /*
+ * dbconvert - miscellaneous conversion routines
+ */
+ acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value);
+
+acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object);
+
+acpi_status
+acpi_db_convert_to_object(acpi_object_type type,
+			  char *string, union acpi_object *object);
+
+u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info);
+
+void acpi_db_dump_pld_buffer(union acpi_object *obj_desc);
+
+/*
  * dbmethod - control method commands
  */
 void
@@ -191,6 +206,8 @@
 acpi_db_create_execution_threads(char *num_threads_arg,
 				 char *num_loops_arg, char *method_name_arg);
 
+void acpi_db_delete_objects(u32 count, union acpi_object *objects);
+
 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
 u32 acpi_db_get_cache_info(struct acpi_memory_list *cache);
 #endif
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index ed33ebc..427db72 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index e975c67..ab0e977 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -158,10 +158,23 @@
 			    void *context);
 
 /*
- * evregion - Address Space handling
+ * evhandler - Address space handling
  */
+u8
+acpi_ev_has_default_handler(struct acpi_namespace_node *node,
+			    acpi_adr_space_type space_id);
+
 acpi_status acpi_ev_install_region_handlers(void);
 
+acpi_status
+acpi_ev_install_space_handler(struct acpi_namespace_node *node,
+			      acpi_adr_space_type space_id,
+			      acpi_adr_space_handler handler,
+			      acpi_adr_space_setup setup, void *context);
+
+/*
+ * evregion - Operation region support
+ */
 acpi_status acpi_ev_initialize_op_regions(void);
 
 acpi_status
@@ -180,12 +193,6 @@
 		      u8 acpi_ns_is_locked);
 
 acpi_status
-acpi_ev_install_space_handler(struct acpi_namespace_node *node,
-			      acpi_adr_space_type space_id,
-			      acpi_adr_space_handler handler,
-			      acpi_adr_space_setup setup, void *context);
-
-acpi_status
 acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
 			    acpi_adr_space_type space_id);
 
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 64472e4..ecb4992 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -192,14 +192,6 @@
 ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
 ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
 
-/* Mutex for _OSI support */
-
-ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
-
-/* Reader/Writer lock is used for namespace walk and dynamic table unload */
-
-ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
-
 /*****************************************************************************
  *
  * Mutual exclusion within ACPICA subsystem
@@ -233,6 +225,14 @@
 ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock;	/* For GPE data structs and registers */
 ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock;	/* For ACPI H/W except GPE registers */
 
+/* Mutex for _OSI support */
+
+ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+
+/* Reader/Writer lock is used for namespace walk and dynamic table unload */
+
+ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
+
 /*****************************************************************************
  *
  * Miscellaneous globals
@@ -252,7 +252,7 @@
 ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
 ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
 ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
-ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
+ACPI_EXTERN acpi_table_handler acpi_gbl_table_handler;
 ACPI_EXTERN void *acpi_gbl_table_handler_context;
 ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
 ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
@@ -304,6 +304,7 @@
 ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
 ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
 ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
+ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
 #endif
 
 /*****************************************************************************
@@ -365,19 +366,18 @@
  *
  ****************************************************************************/
 
-extern struct acpi_fixed_event_info
-    acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
-ACPI_EXTERN struct acpi_fixed_event_handler
-    acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
-ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
-ACPI_EXTERN struct acpi_gpe_block_info
-*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-
 #if (!ACPI_REDUCED_HARDWARE)
 
 ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
+ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
+ACPI_EXTERN struct acpi_gpe_block_info
+    *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
 ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler;
 ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
+ACPI_EXTERN struct acpi_fixed_event_handler
+    acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
+extern struct acpi_fixed_event_info
+    acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
 
 #endif				/* !ACPI_REDUCED_HARDWARE */
 
@@ -405,7 +405,7 @@
 
 /*****************************************************************************
  *
- * Debugger globals
+ * Debugger and Disassembler globals
  *
  ****************************************************************************/
 
@@ -413,8 +413,12 @@
 
 #ifdef ACPI_DISASSEMBLER
 
+u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
+
 ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
 ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
+ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
+ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
 #endif
 
 #ifdef ACPI_DEBUGGER
@@ -426,6 +430,7 @@
 ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
 ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
 ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
+ACPI_EXTERN u8 acpi_gbl_db_opt_no_region_support;
 
 ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS];
 ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS];
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index d902d31..6357e93 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index eb30863..8af8c9b 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -458,7 +458,7 @@
 
 void acpi_ex_relinquish_interpreter(void);
 
-void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
+u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
 
 void acpi_ex_acquire_global_lock(u32 rule);
 
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index ff8bd00..805f419 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -189,11 +189,10 @@
 #define ANOBJ_EVALUATED                 0x20	/* Set on first evaluation of node */
 #define ANOBJ_ALLOCATED_BUFFER          0x40	/* Method AML buffer is dynamic (install_method) */
 
-#define ANOBJ_IS_EXTERNAL               0x08	/* i_aSL only: This object created via External() */
-#define ANOBJ_METHOD_NO_RETVAL          0x10	/* i_aSL only: Method has no return value */
-#define ANOBJ_METHOD_SOME_NO_RETVAL     0x20	/* i_aSL only: Method has at least one return value */
-#define ANOBJ_IS_BIT_OFFSET             0x40	/* i_aSL only: Reference is a bit offset */
-#define ANOBJ_IS_REFERENCED             0x80	/* i_aSL only: Object was referenced */
+#define ANOBJ_IS_EXTERNAL               0x08	/* iASL only: This object created via External() */
+#define ANOBJ_METHOD_NO_RETVAL          0x10	/* iASL only: Method has no return value */
+#define ANOBJ_METHOD_SOME_NO_RETVAL     0x20	/* iASL only: Method has at least one return value */
+#define ANOBJ_IS_REFERENCED             0x80	/* iASL only: Object was referenced */
 
 /* Internal ACPI table management - master table list */
 
@@ -411,11 +410,10 @@
 	struct acpi_gpe_notify_info *next;
 };
 
-struct acpi_gpe_notify_object {
-	struct acpi_namespace_node *node;
-	struct acpi_gpe_notify_object *next;
-};
-
+/*
+ * GPE dispatch info. At any time, the GPE can have at most one type
+ * of dispatch - Method, Handler, or Implicit Notify.
+ */
 union acpi_gpe_dispatch_info {
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level */
 	struct acpi_gpe_handler_info *handler;  /* Installed GPE handler */
@@ -679,6 +677,8 @@
 	u8 type;		/* Opcode type */
 };
 
+/* Value associated with the parse object */
+
 union acpi_parse_value {
 	u64 integer;		/* Integer constant (Up to 64 bits) */
 	u32 size;		/* bytelist or field size */
@@ -1025,6 +1025,31 @@
 
 /*****************************************************************************
  *
+ * Disassembler
+ *
+ ****************************************************************************/
+
+struct acpi_external_list {
+	char *path;
+	char *internal_path;
+	struct acpi_external_list *next;
+	u32 value;
+	u16 length;
+	u8 type;
+	u8 flags;
+};
+
+/* Values for Flags field above */
+
+#define ACPI_IPATH_ALLOCATED    0x01
+
+struct acpi_external_file {
+	char *path;
+	struct acpi_external_file *next;
+};
+
+/*****************************************************************************
+ *
  * Debugger
  *
  ****************************************************************************/
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 5efad99..ed7943b 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,14 +49,18 @@
  * get into potential aligment issues -- see the STORE macros below.
  * Use with care.
  */
-#define ACPI_GET8(ptr)                  *ACPI_CAST_PTR (u8, ptr)
-#define ACPI_GET16(ptr)                 *ACPI_CAST_PTR (u16, ptr)
-#define ACPI_GET32(ptr)                 *ACPI_CAST_PTR (u32, ptr)
-#define ACPI_GET64(ptr)                 *ACPI_CAST_PTR (u64, ptr)
-#define ACPI_SET8(ptr)                  *ACPI_CAST_PTR (u8, ptr)
-#define ACPI_SET16(ptr)                 *ACPI_CAST_PTR (u16, ptr)
-#define ACPI_SET32(ptr)                 *ACPI_CAST_PTR (u32, ptr)
-#define ACPI_SET64(ptr)                 *ACPI_CAST_PTR (u64, ptr)
+#define ACPI_CAST8(ptr)                 ACPI_CAST_PTR (u8, (ptr))
+#define ACPI_CAST16(ptr)                ACPI_CAST_PTR (u16, (ptr))
+#define ACPI_CAST32(ptr)                ACPI_CAST_PTR (u32, (ptr))
+#define ACPI_CAST64(ptr)                ACPI_CAST_PTR (u64, (ptr))
+#define ACPI_GET8(ptr)                  (*ACPI_CAST8 (ptr))
+#define ACPI_GET16(ptr)                 (*ACPI_CAST16 (ptr))
+#define ACPI_GET32(ptr)                 (*ACPI_CAST32 (ptr))
+#define ACPI_GET64(ptr)                 (*ACPI_CAST64 (ptr))
+#define ACPI_SET8(ptr, val)             (*ACPI_CAST8 (ptr) = (u8) (val))
+#define ACPI_SET16(ptr, val)            (*ACPI_CAST16 (ptr) = (u16) (val))
+#define ACPI_SET32(ptr, val)            (*ACPI_CAST32 (ptr) = (u32) (val))
+#define ACPI_SET64(ptr, val)            (*ACPI_CAST64 (ptr) = (u64) (val))
 
 /*
  * printf() format helpers
@@ -293,6 +297,26 @@
 #define ACPI_16BIT_MASK     0x0000FFFF
 #define ACPI_24BIT_MASK     0x00FFFFFF
 
+/* Macros to extract flag bits from position zero */
+
+#define ACPI_GET_1BIT_FLAG(value)                   ((value) & ACPI_1BIT_MASK)
+#define ACPI_GET_2BIT_FLAG(value)                   ((value) & ACPI_2BIT_MASK)
+#define ACPI_GET_3BIT_FLAG(value)                   ((value) & ACPI_3BIT_MASK)
+#define ACPI_GET_4BIT_FLAG(value)                   ((value) & ACPI_4BIT_MASK)
+
+/* Macros to extract flag bits from position one and above */
+
+#define ACPI_EXTRACT_1BIT_FLAG(field, position)     (ACPI_GET_1BIT_FLAG ((field) >> position))
+#define ACPI_EXTRACT_2BIT_FLAG(field, position)     (ACPI_GET_2BIT_FLAG ((field) >> position))
+#define ACPI_EXTRACT_3BIT_FLAG(field, position)     (ACPI_GET_3BIT_FLAG ((field) >> position))
+#define ACPI_EXTRACT_4BIT_FLAG(field, position)     (ACPI_GET_4BIT_FLAG ((field) >> position))
+
+/* ACPI Pathname helpers */
+
+#define ACPI_IS_ROOT_PREFIX(c)      ((c) == (u8) 0x5C)	/* Backslash */
+#define ACPI_IS_PARENT_PREFIX(c)    ((c) == (u8) 0x5E)	/* Carat */
+#define ACPI_IS_PATH_SEPARATOR(c)   ((c) == (u8) 0x2E)	/* Period (dot) */
+
 /*
  * An object of type struct acpi_namespace_node can appear in some contexts
  * where a pointer to an object of type union acpi_operand_object can also
@@ -364,137 +388,6 @@
 
 #endif				/* ACPI_NO_ERROR_MESSAGES */
 
-/*
- * Debug macros that are conditionally compiled
- */
-#ifdef ACPI_DEBUG_OUTPUT
-/*
- * Function entry tracing
- */
-#define ACPI_FUNCTION_TRACE(a)          ACPI_FUNCTION_NAME(a) \
-			  acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
-#define ACPI_FUNCTION_TRACE_PTR(a, b)   ACPI_FUNCTION_NAME(a) \
-					   acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS, (void *)b)
-#define ACPI_FUNCTION_TRACE_U32(a, b)   ACPI_FUNCTION_NAME(a) \
-							 acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS, (u32)b)
-#define ACPI_FUNCTION_TRACE_STR(a, b)   ACPI_FUNCTION_NAME(a) \
-									  acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS, (char *)b)
-
-#define ACPI_FUNCTION_ENTRY()           acpi_ut_track_stack_ptr()
-
-/*
- * Function exit tracing.
- * WARNING: These macros include a return statement. This is usually considered
- * bad form, but having a separate exit macro is very ugly and difficult to maintain.
- * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros
- * so that "_AcpiFunctionName" is defined.
- *
- * Note: the DO_WHILE0 macro is used to prevent some compilers from complaining
- * about these constructs.
- */
-#ifdef ACPI_USE_DO_WHILE_0
-#define ACPI_DO_WHILE0(a)               do a while(0)
-#else
-#define ACPI_DO_WHILE0(a)               a
-#endif
-
-#define return_VOID                     ACPI_DO_WHILE0 ({ \
-											acpi_ut_exit (ACPI_DEBUG_PARAMETERS); \
-											return;})
-/*
- * There are two versions of most of the return macros. The default version is
- * safer, since it avoids side-effects by guaranteeing that the argument will
- * not be evaluated twice.
- *
- * A less-safe version of the macros is provided for optional use if the
- * compiler uses excessive CPU stack (for example, this may happen in the
- * debug case if code optimzation is disabled.)
- */
-#ifndef ACPI_SIMPLE_RETURN_MACROS
-
-#define return_ACPI_STATUS(s)           ACPI_DO_WHILE0 ({ \
-											register acpi_status _s = (s); \
-											acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, _s); \
-											return (_s); })
-#define return_PTR(s)                   ACPI_DO_WHILE0 ({ \
-											register void *_s = (void *) (s); \
-											acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \
-											return (_s); })
-#define return_VALUE(s)                 ACPI_DO_WHILE0 ({ \
-											register u64 _s = (s); \
-											acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \
-											return (_s); })
-#define return_UINT8(s)                 ACPI_DO_WHILE0 ({ \
-											register u8 _s = (u8) (s); \
-											acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
-											return (_s); })
-#define return_UINT32(s)                ACPI_DO_WHILE0 ({ \
-											register u32 _s = (u32) (s); \
-											acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
-											return (_s); })
-#else				/* Use original less-safe macros */
-
-#define return_ACPI_STATUS(s)           ACPI_DO_WHILE0 ({ \
-											acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, (s)); \
-											return((s)); })
-#define return_PTR(s)                   ACPI_DO_WHILE0 ({ \
-											acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \
-											return((s)); })
-#define return_VALUE(s)                 ACPI_DO_WHILE0 ({ \
-											acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) (s)); \
-											return((s)); })
-#define return_UINT8(s)                 return_VALUE(s)
-#define return_UINT32(s)                return_VALUE(s)
-
-#endif				/* ACPI_SIMPLE_RETURN_MACROS */
-
-/* Conditional execution */
-
-#define ACPI_DEBUG_EXEC(a)              a
-#define ACPI_DEBUG_ONLY_MEMBERS(a)      a;
-#define _VERBOSE_STRUCTURES
-
-/* Various object display routines for debug */
-
-#define ACPI_DUMP_STACK_ENTRY(a)        acpi_ex_dump_operand((a), 0)
-#define ACPI_DUMP_OPERANDS(a, b ,c)     acpi_ex_dump_operands(a, b, c)
-#define ACPI_DUMP_ENTRY(a, b)           acpi_ns_dump_entry (a, b)
-#define ACPI_DUMP_PATHNAME(a, b, c, d)  acpi_ns_dump_pathname(a, b, c, d)
-#define ACPI_DUMP_BUFFER(a, b)          acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT)
-
-#else
-/*
- * This is the non-debug case -- make everything go away,
- * leaving no executable debug code!
- */
-#define ACPI_DEBUG_EXEC(a)
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#define ACPI_FUNCTION_TRACE(a)
-#define ACPI_FUNCTION_TRACE_PTR(a, b)
-#define ACPI_FUNCTION_TRACE_U32(a, b)
-#define ACPI_FUNCTION_TRACE_STR(a, b)
-#define ACPI_FUNCTION_EXIT
-#define ACPI_FUNCTION_STATUS_EXIT(s)
-#define ACPI_FUNCTION_VALUE_EXIT(s)
-#define ACPI_FUNCTION_ENTRY()
-#define ACPI_DUMP_STACK_ENTRY(a)
-#define ACPI_DUMP_OPERANDS(a, b, c)
-#define ACPI_DUMP_ENTRY(a, b)
-#define ACPI_DUMP_TABLES(a, b)
-#define ACPI_DUMP_PATHNAME(a, b, c, d)
-#define ACPI_DUMP_BUFFER(a, b)
-#define ACPI_DEBUG_PRINT(pl)
-#define ACPI_DEBUG_PRINT_RAW(pl)
-
-#define return_VOID                     return
-#define return_ACPI_STATUS(s)           return(s)
-#define return_VALUE(s)                 return(s)
-#define return_UINT8(s)                 return(s)
-#define return_UINT32(s)                return(s)
-#define return_PTR(s)                   return(s)
-
-#endif				/* ACPI_DEBUG_OUTPUT */
-
 #if (!ACPI_REDUCED_HARDWARE)
 #define ACPI_HW_OPTIONAL_FUNCTION(addr)     addr
 #else
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 9b19d4b..02cd548 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -218,6 +218,18 @@
 			      u32 user_param_count,
 			      const union acpi_predefined_info *info);
 
+acpi_status
+acpi_ns_check_object_type(struct acpi_predefined_data *data,
+			  union acpi_operand_object **return_object_ptr,
+			  u32 expected_btypes, u32 package_index);
+
+/*
+ * nsprepkg - Validation of predefined name packages
+ */
+acpi_status
+acpi_ns_check_package(struct acpi_predefined_data *data,
+		      union acpi_operand_object **return_object_ptr);
+
 /*
  * nsnames - Name and Scope manipulation
  */
@@ -333,8 +345,6 @@
 /*
  * nsutils - Utility functions
  */
-u8 acpi_ns_valid_root_prefix(char prefix);
-
 acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node);
 
 u32 acpi_ns_local(acpi_object_type type);
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 24eb9ea..cc7ab6d 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -307,7 +307,7 @@
 	struct acpi_namespace_node *node;	/* Parent device */
 	void *context;
 	acpi_adr_space_setup setup;
-	union acpi_operand_object *region_list;	/* regions using this handler */
+	union acpi_operand_object *region_list;	/* Regions using this handler */
 	union acpi_operand_object *next;
 };
 
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index d786a51..3fc9ca7 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index eefcf47..aed3193 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -105,7 +105,28 @@
 union acpi_parse_object *acpi_ps_get_parent(union acpi_parse_object *op);
 
 /*
- * psopcode - AML Opcode information
+ * psobject - support for parse object processing
+ */
+acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+		       u8 *aml_op_start,
+		       union acpi_parse_object *unnamed_op,
+		       union acpi_parse_object **op);
+
+acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+		  u8 *aml_op_start, union acpi_parse_object **new_op);
+
+acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+		    union acpi_parse_object **op, acpi_status status);
+
+acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+			  union acpi_parse_object *op, acpi_status status);
+
+/*
+ * psopinfo - AML Opcode information
  */
 const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode);
 
@@ -211,8 +232,6 @@
 
 u8 acpi_ps_is_leading_char(u32 c);
 
-u8 acpi_ps_is_prefix_char(u32 c);
-
 #ifdef	ACPI_FUTURE_USAGE
 u32 acpi_ps_get_name(union acpi_parse_object *op);
 #endif				/* ACPI_FUTURE_USAGE */
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 9dfa1c8..752cc40 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -1,12 +1,11 @@
 /******************************************************************************
  *
  * Name: acpredef - Information table for ACPI predefined methods and objects
- *              $Revision: 1.1 $
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,13 +50,13 @@
  *
  * 1) PTYPE1 packages do not contain sub-packages.
  *
- * ACPI_PTYPE1_FIXED: Fixed length, 1 or 2 object types:
+ * ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types:
  *      object type
  *      count
  *      object type
  *      count
  *
- * ACPI_PTYPE1_VAR: Variable length:
+ * ACPI_PTYPE1_VAR: Variable-length length:
  *      object type (Int/Buf/Ref)
  *
  * ACPI_PTYPE1_OPTION: Package has some required and some optional elements
@@ -85,10 +84,10 @@
  *      count
  *      (Used for _CST)
  *
- * ACPI_PTYPE2_FIXED: Each subpackage is of fixed length
+ * ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length
  *      (Used for _PRT)
  *
- * ACPI_PTYPE2_MIN: Each subpackage has a variable but minimum length
+ * ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length
  *      (Used for _HPX)
  *
  * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length
@@ -124,7 +123,8 @@
  * These are the names that can actually be evaluated via acpi_evaluate_object.
  * Not present in this table are the following:
  *
- *      1) Predefined/Reserved names that are never evaluated via acpi_evaluate_object:
+ *      1) Predefined/Reserved names that are never evaluated via
+ *         acpi_evaluate_object:
  *          _Lxx and _Exx GPE methods
  *          _Qxx EC methods
  *          _T_x compiler temporary variables
@@ -149,6 +149,8 @@
  * information about the expected structure of the package. This information
  * is saved here (rather than in a separate table) in order to minimize the
  * overall size of the stored data.
+ *
+ * Note: The additional braces are intended to promote portability.
  */
 static const union acpi_predefined_info predefined_names[] = {
 	{{"_AC0", 0, ACPI_RTYPE_INTEGER}},
@@ -212,9 +214,8 @@
 	{{"_BCT", 1, ACPI_RTYPE_INTEGER}},
 	{{"_BDN", 0, ACPI_RTYPE_INTEGER}},
 	{{"_BFS", 1, 0}},
-	{{"_BIF", 0, ACPI_RTYPE_PACKAGE} }, /* Fixed-length (9 Int),(4 Str/Buf) */
-			  {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9,
-			     ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}, 4, 0} },
+	{{"_BIF", 0, ACPI_RTYPE_PACKAGE}},	/* Fixed-length (9 Int),(4 Str) */
+	{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING}, 4, 0}},
 
 	{{"_BIX", 0, ACPI_RTYPE_PACKAGE}},	/* Fixed-length (16 Int),(4 Str) */
 	{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING}, 4,
@@ -236,7 +237,8 @@
 	{{"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* See PCI firmware spec 3.0 */
 	{{"_CDM", 0, ACPI_RTYPE_INTEGER}},
 	{{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */
-			  {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}},
+	{{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0}, 0,
+	  0}},
 
 	{{"_CLS", 0, ACPI_RTYPE_PACKAGE}},	/* Fixed-length (3 Int) */
 	{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
@@ -251,7 +253,8 @@
 			  {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
 
 	{{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */
-			  {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}},
+	{{{ACPI_PTYPE2_PKG_COUNT, ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,
+	  0}},
 
 	{{"_CWS", 1, ACPI_RTYPE_INTEGER}},
 	{{"_DCK", 1, ACPI_RTYPE_INTEGER}},
@@ -342,8 +345,8 @@
 	{{"_MBM", 0, ACPI_RTYPE_PACKAGE}},	/* Fixed-length (8 Int) */
 	{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0}, 0, 0}},
 
-	{{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (2 Str) */
-			  {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 2,0}, 0,0}},
+	{{"_MLS", 0, ACPI_RTYPE_PACKAGE}},	/* Variable-length (Pkgs) each (1 Str/1 Buf) */
+	{{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER}, 1, 0}},
 
 	{{"_MSG", 1, 0}},
 	{{"_MSM", 4, ACPI_RTYPE_INTEGER}},
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index 0347d09..f691d0e 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -347,18 +347,21 @@
 extern struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[];
 
 /*
- * rsdump
+ * rsdumpinfo
  */
 extern struct acpi_rsdump_info acpi_rs_dump_irq[];
+extern struct acpi_rsdump_info acpi_rs_dump_prt[];
 extern struct acpi_rsdump_info acpi_rs_dump_dma[];
 extern struct acpi_rsdump_info acpi_rs_dump_start_dpf[];
 extern struct acpi_rsdump_info acpi_rs_dump_end_dpf[];
 extern struct acpi_rsdump_info acpi_rs_dump_io[];
+extern struct acpi_rsdump_info acpi_rs_dump_io_flags[];
 extern struct acpi_rsdump_info acpi_rs_dump_fixed_io[];
 extern struct acpi_rsdump_info acpi_rs_dump_vendor[];
 extern struct acpi_rsdump_info acpi_rs_dump_end_tag[];
 extern struct acpi_rsdump_info acpi_rs_dump_memory24[];
 extern struct acpi_rsdump_info acpi_rs_dump_memory32[];
+extern struct acpi_rsdump_info acpi_rs_dump_memory_flags[];
 extern struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[];
 extern struct acpi_rsdump_info acpi_rs_dump_address16[];
 extern struct acpi_rsdump_info acpi_rs_dump_address32[];
@@ -372,6 +375,7 @@
 extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[];
 extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[];
 extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[];
+extern struct acpi_rsdump_info acpi_rs_dump_general_flags[];
 #endif
 
 #endif				/* __ACRESRC_H__ */
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 937e66c..7896d85 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 6712965..7755e91 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index b0f5f92..0082fa0 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -483,39 +483,17 @@
 /*
  * utmisc
  */
-void ut_convert_backslashes(char *pathname);
-
 const char *acpi_ut_validate_exception(acpi_status status);
 
 u8 acpi_ut_is_pci_root_bridge(char *id);
 
 u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
 
-acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
-
-void acpi_ut_release_owner_id(acpi_owner_id * owner_id);
-
 acpi_status
 acpi_ut_walk_package_tree(union acpi_operand_object *source_object,
 			  void *target_object,
 			  acpi_pkg_callback walk_callback, void *context);
 
-void acpi_ut_strupr(char *src_string);
-
-void acpi_ut_strlwr(char *src_string);
-
-int acpi_ut_stricmp(char *string1, char *string2);
-
-void acpi_ut_print_string(char *string, u8 max_length);
-
-u8 acpi_ut_valid_acpi_name(u32 name);
-
-void acpi_ut_repair_name(char *name);
-
-u8 acpi_ut_valid_acpi_char(char character, u32 position);
-
-acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
-
 /* Values for Base above (16=Hex, 10=Decimal) */
 
 #define ACPI_ANY_BASE        0
@@ -532,15 +510,25 @@
 #endif
 
 /*
+ * utownerid - Support for Table/Method Owner IDs
+ */
+acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
+
+void acpi_ut_release_owner_id(acpi_owner_id * owner_id);
+
+/*
  * utresrc
  */
 acpi_status
-acpi_ut_walk_aml_resources(u8 *aml,
+acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
+			   u8 *aml,
 			   acpi_size aml_length,
 			   acpi_walk_aml_callback user_function,
 			   void **context);
 
-acpi_status acpi_ut_validate_resource(void *aml, u8 *return_index);
+acpi_status
+acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
+			  void *aml, u8 *return_index);
 
 u32 acpi_ut_get_descriptor_length(void *aml);
 
@@ -554,6 +542,27 @@
 acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag);
 
 /*
+ * utstring - String and character utilities
+ */
+void acpi_ut_strupr(char *src_string);
+
+void acpi_ut_strlwr(char *src_string);
+
+int acpi_ut_stricmp(char *string1, char *string2);
+
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
+
+void acpi_ut_print_string(char *string, u8 max_length);
+
+void ut_convert_backslashes(char *pathname);
+
+u8 acpi_ut_valid_acpi_name(u32 name);
+
+u8 acpi_ut_valid_acpi_char(char character, u32 position);
+
+void acpi_ut_repair_name(char *name);
+
+/*
  * utmutex - mutex support
  */
 acpi_status acpi_ut_mutex_initialize(void);
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index c26f8ff..48a3e33 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 9684496..87c2636 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -199,6 +199,12 @@
 struct aml_resource_large_header {
 AML_RESOURCE_LARGE_HEADER_COMMON};
 
+/* General Flags for address space resource descriptors */
+
+#define ACPI_RESOURCE_FLAG_DEC      2
+#define ACPI_RESOURCE_FLAG_MIF      4
+#define ACPI_RESOURCE_FLAG_MAF      8
+
 struct aml_resource_memory24 {
 	AML_RESOURCE_LARGE_HEADER_COMMON u8 flags;
 	u16 minimum;
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
index c8b5e25..fb09b08 100644
--- a/drivers/acpi/acpica/dsargs.c
+++ b/drivers/acpi/acpica/dsargs.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 57895db..7ea0f16 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index b5b904e..feadeed 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index 87eff70..bc8e63f 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 52eb4e0..a9ffd44 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
 #include "acinterp.h"
 #include "acnamesp.h"
 #ifdef	ACPI_DISASSEMBLER
-#include <acpi/acdisasm.h>
+#include "acdisasm.h"
 #endif
 
 #define _COMPONENT          ACPI_DISPATCHER
@@ -151,6 +151,7 @@
 
 	status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
 	if (ACPI_FAILURE(status)) {
+		acpi_ut_delete_object_desc(mutex_desc);
 		return_ACPI_STATUS(status);
 	}
 
@@ -378,7 +379,8 @@
 	 */
 	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
 	if (!info) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
+		status = AE_NO_MEMORY;
+		goto cleanup;
 	}
 
 	info->parameters = &this_walk_state->operands[0];
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index 9a83b7e..3da8046 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index c9f15d3..e20e9f84 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -388,7 +388,7 @@
 	union acpi_parse_object *parent;
 	union acpi_operand_object *obj_desc = NULL;
 	acpi_status status = AE_OK;
-	unsigned i;
+	u32 i;
 	u16 index;
 	u16 reference_count;
 
@@ -525,7 +525,7 @@
 		}
 
 		ACPI_INFO((AE_INFO,
-			   "Actual Package length (%u) is larger than NumElements field (%u), truncated\n",
+			   "Actual Package length (%u) is larger than NumElements field (%u), truncated",
 			   i, element_count));
 	} else if (i < element_count) {
 		/*
@@ -703,7 +703,7 @@
 				/* Truncate value if we are executing from a 32-bit ACPI table */
 
 #ifndef ACPI_NO_METHOD_EXECUTION
-				acpi_ex_truncate_for32bit_table(obj_desc);
+				(void)acpi_ex_truncate_for32bit_table(obj_desc);
 #endif
 				break;
 
@@ -725,8 +725,18 @@
 		case AML_TYPE_LITERAL:
 
 			obj_desc->integer.value = op->common.value.integer;
+
 #ifndef ACPI_NO_METHOD_EXECUTION
-			acpi_ex_truncate_for32bit_table(obj_desc);
+			if (acpi_ex_truncate_for32bit_table(obj_desc)) {
+
+				/* Warn if we found a 64-bit constant in a 32-bit table */
+
+				ACPI_WARNING((AE_INFO,
+					      "Truncated 64-bit constant found in 32-bit table: %8.8X%8.8X => %8.8X",
+					      ACPI_FORMAT_UINT64(op->common.
+								 value.integer),
+					      (u32)obj_desc->integer.value));
+			}
 #endif
 			break;
 
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index d09c6b4..ee6367b 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -486,18 +486,18 @@
 	ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
 
 	/*
-	 * This is where we evaluate the signature_string and oem_iDString
-	 * and oem_table_iDString of the data_table_region declaration
+	 * This is where we evaluate the Signature string, oem_id string,
+	 * and oem_table_id string of the Data Table Region declaration
 	 */
 	node = op->common.node;
 
-	/* next_op points to signature_string op */
+	/* next_op points to Signature string op */
 
 	next_op = op->common.value.arg;
 
 	/*
-	 * Evaluate/create the signature_string and oem_iDString
-	 * and oem_table_iDString operands
+	 * Evaluate/create the Signature string, oem_id string,
+	 * and oem_table_id string operands
 	 */
 	status = acpi_ds_create_operands(walk_state, next_op);
 	if (ACPI_FAILURE(status)) {
@@ -505,8 +505,8 @@
 	}
 
 	/*
-	 * Resolve the signature_string and oem_iDString
-	 * and oem_table_iDString operands
+	 * Resolve the Signature string, oem_id string,
+	 * and oem_table_id string operands
 	 */
 	status = acpi_ex_resolve_operands(op->common.aml_opcode,
 					  ACPI_WALK_OPERANDS, walk_state);
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index afeb99f..4d8c992 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -178,7 +178,7 @@
 
 	if (!op) {
 		ACPI_ERROR((AE_INFO, "Null Op"));
-		return_UINT8(TRUE);
+		return_VALUE(TRUE);
 	}
 
 	/*
@@ -210,7 +210,7 @@
 				  "At Method level, result of [%s] not used\n",
 				  acpi_ps_get_opcode_name(op->common.
 							  aml_opcode)));
-		return_UINT8(FALSE);
+		return_VALUE(FALSE);
 	}
 
 	/* Get info on the parent. The root_op is AML_SCOPE */
@@ -219,7 +219,7 @@
 	    acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
 	if (parent_info->class == AML_CLASS_UNKNOWN) {
 		ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
-		return_UINT8(FALSE);
+		return_VALUE(FALSE);
 	}
 
 	/*
@@ -307,7 +307,7 @@
 			  acpi_ps_get_opcode_name(op->common.parent->common.
 						  aml_opcode), op));
 
-	return_UINT8(TRUE);
+	return_VALUE(TRUE);
 
       result_not_used:
 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -316,7 +316,7 @@
 			  acpi_ps_get_opcode_name(op->common.parent->common.
 						  aml_opcode), op));
 
-	return_UINT8(FALSE);
+	return_VALUE(FALSE);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 5859393..44f8325 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -149,7 +149,7 @@
 
 	/* Truncate the predicate to 32-bits if necessary */
 
-	acpi_ex_truncate_for32bit_table(local_obj_desc);
+	(void)acpi_ex_truncate_for32bit_table(local_obj_desc);
 
 	/*
 	 * Save the result of the predicate evaluation on
@@ -706,7 +706,7 @@
 	 * ACPI 2.0 support for 64-bit integers: Truncate numeric
 	 * result value if we are executing from a 32-bit ACPI table
 	 */
-	acpi_ex_truncate_for32bit_table(walk_state->result_obj);
+	(void)acpi_ex_truncate_for32bit_table(walk_state->result_obj);
 
 	/*
 	 * Check if we just completed the evaluation of a
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 5575100..6e17c0e 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@
 #include "acnamesp.h"
 
 #ifdef ACPI_ASL_COMPILER
-#include <acpi/acdisasm.h>
+#include "acdisasm.h"
 #endif
 
 #define _COMPONENT          ACPI_DISPATCHER
@@ -178,7 +178,8 @@
 			 * Target of Scope() not found. Generate an External for it, and
 			 * insert the name into the namespace.
 			 */
-			acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0);
+			acpi_dm_add_to_external_list(op, path, ACPI_TYPE_DEVICE,
+						     0);
 			status =
 			    acpi_ns_lookup(walk_state->scope_info, path,
 					   object_type, ACPI_IMODE_LOAD_PASS1,
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
index 3798357..4407ff2 100644
--- a/drivers/acpi/acpica/dswload2.c
+++ b/drivers/acpi/acpica/dswload2.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -222,7 +222,7 @@
 			 */
 			ACPI_WARNING((AE_INFO,
 				      "Type override - [%4.4s] had invalid type (%s) "
-				      "for Scope operator, changed to type ANY\n",
+				      "for Scope operator, changed to type ANY",
 				      acpi_ut_get_node_name(node),
 				      acpi_ut_get_type_name(node->type)));
 
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index f6c4295..d67891d 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index 3e65a15..ecb12e2 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index d4acfbb..b8ea0b2 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index af14a71..a621481 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 36d1205..b9adb9a 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -561,8 +561,8 @@
 			status = AE_NO_MEMORY;
 		} else {
 			/*
-			 * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
-			 * control method that corresponds to this GPE
+			 * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the
+			 * _Lxx/_Exx control method that corresponds to this GPE
 			 */
 			info->prefix_node =
 			    local_gpe_event_info->dispatch.method_node;
@@ -707,7 +707,7 @@
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
 					"Unable to clear GPE%02X", gpe_number));
-			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+			return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
 		}
 	}
 
@@ -724,7 +724,7 @@
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status,
 				"Unable to disable GPE%02X", gpe_number));
-		return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+		return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
 	}
 
 	/*
@@ -765,7 +765,7 @@
 					 gpe_event_info);
 		if (ACPI_FAILURE(status)) {
 			ACPI_EXCEPTION((AE_INFO, status,
-					"Unable to queue handler for GPE%2X - event disabled",
+					"Unable to queue handler for GPE%02X - event disabled",
 					gpe_number));
 		}
 		break;
@@ -784,7 +784,7 @@
 		break;
 	}
 
-	return_UINT32(ACPI_INTERRUPT_HANDLED);
+	return_VALUE(ACPI_INTERRUPT_HANDLED);
 }
 
 #endif				/* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 1571a61..a2d688b 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -405,13 +405,13 @@
 		(*return_gpe_block) = gpe_block;
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
-			  "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
-			  (u32) gpe_block->block_base_number,
-			  (u32) (gpe_block->block_base_number +
-				(gpe_block->gpe_count - 1)),
-			  gpe_device->name.ascii, gpe_block->register_count,
-			  interrupt_number));
+	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+			      "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n",
+			      (u32)gpe_block->block_base_number,
+			      (u32)(gpe_block->block_base_number +
+				    (gpe_block->gpe_count - 1)),
+			      gpe_device->name.ascii, gpe_block->register_count,
+			      interrupt_number));
 
 	/* Update global count of currently available GPEs */
 
@@ -496,9 +496,11 @@
 	}
 
 	if (gpe_enabled_count) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INIT,
-				  "Enabled %u GPEs in this block\n",
-				  gpe_enabled_count));
+		ACPI_INFO((AE_INFO,
+			   "Enabled %u GPEs in block %02X to %02X",
+			   gpe_enabled_count, (u32)gpe_block->block_base_number,
+			   (u32)(gpe_block->block_base_number +
+				 (gpe_block->gpe_count - 1))));
 	}
 
 	gpe_block->initialized = TRUE;
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index da0add8..72b8f6b 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -86,6 +86,9 @@
 
 	ACPI_FUNCTION_TRACE(ev_gpe_initialize);
 
+	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+			      "Initializing General Purpose Events (GPEs):\n"));
+
 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 228a0c3..b24dbb8 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
new file mode 100644
index 0000000..d4f8311
--- /dev/null
+++ b/drivers/acpi/acpica/evhandler.c
@@ -0,0 +1,529 @@
+/******************************************************************************
+ *
+ * Module Name: evhandler - Support for Address Space handlers
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+
+#define _COMPONENT          ACPI_EVENTS
+ACPI_MODULE_NAME("evhandler")
+
+/* Local prototypes */
+static acpi_status
+acpi_ev_install_handler(acpi_handle obj_handle,
+			u32 level, void *context, void **return_value);
+
+/* These are the address spaces that will get default handlers */
+
+u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
+	ACPI_ADR_SPACE_SYSTEM_MEMORY,
+	ACPI_ADR_SPACE_SYSTEM_IO,
+	ACPI_ADR_SPACE_PCI_CONFIG,
+	ACPI_ADR_SPACE_DATA_TABLE
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_install_region_handlers
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Installs the core subsystem default address space handlers.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_install_region_handlers(void)
+{
+	acpi_status status;
+	u32 i;
+
+	ACPI_FUNCTION_TRACE(ev_install_region_handlers);
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/*
+	 * All address spaces (PCI Config, EC, SMBus) are scope dependent and
+	 * registration must occur for a specific device.
+	 *
+	 * In the case of the system memory and IO address spaces there is
+	 * currently no device associated with the address space. For these we
+	 * use the root.
+	 *
+	 * We install the default PCI config space handler at the root so that
+	 * this space is immediately available even though the we have not
+	 * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
+	 * specification which states that the PCI config space must be always
+	 * available -- even though we are nowhere near ready to find the PCI root
+	 * buses at this point.
+	 *
+	 * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
+	 * has already been installed (via acpi_install_address_space_handler).
+	 * Similar for AE_SAME_HANDLER.
+	 */
+	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+		status = acpi_ev_install_space_handler(acpi_gbl_root_node,
+						       acpi_gbl_default_address_spaces
+						       [i],
+						       ACPI_DEFAULT_HANDLER,
+						       NULL, NULL);
+		switch (status) {
+		case AE_OK:
+		case AE_SAME_HANDLER:
+		case AE_ALREADY_EXISTS:
+
+			/* These exceptions are all OK */
+
+			status = AE_OK;
+			break;
+
+		default:
+
+			goto unlock_and_exit;
+		}
+	}
+
+      unlock_and_exit:
+	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_has_default_handler
+ *
+ * PARAMETERS:  node                - Namespace node for the device
+ *              space_id            - The address space ID
+ *
+ * RETURN:      TRUE if default handler is installed, FALSE otherwise
+ *
+ * DESCRIPTION: Check if the default handler is installed for the requested
+ *              space ID.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ev_has_default_handler(struct acpi_namespace_node *node,
+			    acpi_adr_space_type space_id)
+{
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *handler_obj;
+
+	/* Must have an existing internal object */
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc) {
+		handler_obj = obj_desc->device.handler;
+
+		/* Walk the linked list of handlers for this object */
+
+		while (handler_obj) {
+			if (handler_obj->address_space.space_id == space_id) {
+				if (handler_obj->address_space.handler_flags &
+				    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
+					return (TRUE);
+				}
+			}
+
+			handler_obj = handler_obj->address_space.next;
+		}
+	}
+
+	return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_install_handler
+ *
+ * PARAMETERS:  walk_namespace callback
+ *
+ * DESCRIPTION: This routine installs an address handler into objects that are
+ *              of type Region or Device.
+ *
+ *              If the Object is a Device, and the device has a handler of
+ *              the same type then the search is terminated in that branch.
+ *
+ *              This is because the existing handler is closer in proximity
+ *              to any more regions than the one we are trying to install.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_install_handler(acpi_handle obj_handle,
+			u32 level, void *context, void **return_value)
+{
+	union acpi_operand_object *handler_obj;
+	union acpi_operand_object *next_handler_obj;
+	union acpi_operand_object *obj_desc;
+	struct acpi_namespace_node *node;
+	acpi_status status;
+
+	ACPI_FUNCTION_NAME(ev_install_handler);
+
+	handler_obj = (union acpi_operand_object *)context;
+
+	/* Parameter validation */
+
+	if (!handler_obj) {
+		return (AE_OK);
+	}
+
+	/* Convert and validate the device handle */
+
+	node = acpi_ns_validate_handle(obj_handle);
+	if (!node) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * We only care about regions and objects that are allowed to have
+	 * address space handlers
+	 */
+	if ((node->type != ACPI_TYPE_DEVICE) &&
+	    (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
+		return (AE_OK);
+	}
+
+	/* Check for an existing internal object */
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (!obj_desc) {
+
+		/* No object, just exit */
+
+		return (AE_OK);
+	}
+
+	/* Devices are handled different than regions */
+
+	if (obj_desc->common.type == ACPI_TYPE_DEVICE) {
+
+		/* Check if this Device already has a handler for this address space */
+
+		next_handler_obj = obj_desc->device.handler;
+		while (next_handler_obj) {
+
+			/* Found a handler, is it for the same address space? */
+
+			if (next_handler_obj->address_space.space_id ==
+			    handler_obj->address_space.space_id) {
+				ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+						  "Found handler for region [%s] in device %p(%p) "
+						  "handler %p\n",
+						  acpi_ut_get_region_name
+						  (handler_obj->address_space.
+						   space_id), obj_desc,
+						  next_handler_obj,
+						  handler_obj));
+
+				/*
+				 * Since the object we found it on was a device, then it
+				 * means that someone has already installed a handler for
+				 * the branch of the namespace from this device on. Just
+				 * bail out telling the walk routine to not traverse this
+				 * branch. This preserves the scoping rule for handlers.
+				 */
+				return (AE_CTRL_DEPTH);
+			}
+
+			/* Walk the linked list of handlers attached to this device */
+
+			next_handler_obj = next_handler_obj->address_space.next;
+		}
+
+		/*
+		 * As long as the device didn't have a handler for this space we
+		 * don't care about it. We just ignore it and proceed.
+		 */
+		return (AE_OK);
+	}
+
+	/* Object is a Region */
+
+	if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
+
+		/* This region is for a different address space, just ignore it */
+
+		return (AE_OK);
+	}
+
+	/*
+	 * Now we have a region and it is for the handler's address space type.
+	 *
+	 * First disconnect region for any previous handler (if any)
+	 */
+	acpi_ev_detach_region(obj_desc, FALSE);
+
+	/* Connect the region to the new handler */
+
+	status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE);
+	return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_install_space_handler
+ *
+ * PARAMETERS:  node            - Namespace node for the device
+ *              space_id        - The address space ID
+ *              handler         - Address of the handler
+ *              setup           - Address of the setup function
+ *              context         - Value passed to the handler on each access
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a handler for all op_regions of a given space_id.
+ *              Assumes namespace is locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_install_space_handler(struct acpi_namespace_node * node,
+			      acpi_adr_space_type space_id,
+			      acpi_adr_space_handler handler,
+			      acpi_adr_space_setup setup, void *context)
+{
+	union acpi_operand_object *obj_desc;
+	union acpi_operand_object *handler_obj;
+	acpi_status status;
+	acpi_object_type type;
+	u8 flags = 0;
+
+	ACPI_FUNCTION_TRACE(ev_install_space_handler);
+
+	/*
+	 * This registration is valid for only the types below and the root. This
+	 * is where the default handlers get placed.
+	 */
+	if ((node->type != ACPI_TYPE_DEVICE) &&
+	    (node->type != ACPI_TYPE_PROCESSOR) &&
+	    (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
+		status = AE_BAD_PARAMETER;
+		goto unlock_and_exit;
+	}
+
+	if (handler == ACPI_DEFAULT_HANDLER) {
+		flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
+
+		switch (space_id) {
+		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+			handler = acpi_ex_system_memory_space_handler;
+			setup = acpi_ev_system_memory_region_setup;
+			break;
+
+		case ACPI_ADR_SPACE_SYSTEM_IO:
+			handler = acpi_ex_system_io_space_handler;
+			setup = acpi_ev_io_space_region_setup;
+			break;
+
+		case ACPI_ADR_SPACE_PCI_CONFIG:
+			handler = acpi_ex_pci_config_space_handler;
+			setup = acpi_ev_pci_config_region_setup;
+			break;
+
+		case ACPI_ADR_SPACE_CMOS:
+			handler = acpi_ex_cmos_space_handler;
+			setup = acpi_ev_cmos_region_setup;
+			break;
+
+		case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+			handler = acpi_ex_pci_bar_space_handler;
+			setup = acpi_ev_pci_bar_region_setup;
+			break;
+
+		case ACPI_ADR_SPACE_DATA_TABLE:
+			handler = acpi_ex_data_table_space_handler;
+			setup = NULL;
+			break;
+
+		default:
+			status = AE_BAD_PARAMETER;
+			goto unlock_and_exit;
+		}
+	}
+
+	/* If the caller hasn't specified a setup routine, use the default */
+
+	if (!setup) {
+		setup = acpi_ev_default_region_setup;
+	}
+
+	/* Check for an existing internal object */
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (obj_desc) {
+		/*
+		 * The attached device object already exists. Make sure the handler
+		 * is not already installed.
+		 */
+		handler_obj = obj_desc->device.handler;
+
+		/* Walk the handler list for this device */
+
+		while (handler_obj) {
+
+			/* Same space_id indicates a handler already installed */
+
+			if (handler_obj->address_space.space_id == space_id) {
+				if (handler_obj->address_space.handler ==
+				    handler) {
+					/*
+					 * It is (relatively) OK to attempt to install the SAME
+					 * handler twice. This can easily happen with the
+					 * PCI_Config space.
+					 */
+					status = AE_SAME_HANDLER;
+					goto unlock_and_exit;
+				} else {
+					/* A handler is already installed */
+
+					status = AE_ALREADY_EXISTS;
+				}
+				goto unlock_and_exit;
+			}
+
+			/* Walk the linked list of handlers */
+
+			handler_obj = handler_obj->address_space.next;
+		}
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+				  "Creating object on Device %p while installing handler\n",
+				  node));
+
+		/* obj_desc does not exist, create one */
+
+		if (node->type == ACPI_TYPE_ANY) {
+			type = ACPI_TYPE_DEVICE;
+		} else {
+			type = node->type;
+		}
+
+		obj_desc = acpi_ut_create_internal_object(type);
+		if (!obj_desc) {
+			status = AE_NO_MEMORY;
+			goto unlock_and_exit;
+		}
+
+		/* Init new descriptor */
+
+		obj_desc->common.type = (u8)type;
+
+		/* Attach the new object to the Node */
+
+		status = acpi_ns_attach_object(node, obj_desc, type);
+
+		/* Remove local reference to the object */
+
+		acpi_ut_remove_reference(obj_desc);
+
+		if (ACPI_FAILURE(status)) {
+			goto unlock_and_exit;
+		}
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+			  "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
+			  acpi_ut_get_region_name(space_id), space_id,
+			  acpi_ut_get_node_name(node), node, obj_desc));
+
+	/*
+	 * Install the handler
+	 *
+	 * At this point there is no existing handler. Just allocate the object
+	 * for the handler and link it into the list.
+	 */
+	handler_obj =
+	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
+	if (!handler_obj) {
+		status = AE_NO_MEMORY;
+		goto unlock_and_exit;
+	}
+
+	/* Init handler obj */
+
+	handler_obj->address_space.space_id = (u8)space_id;
+	handler_obj->address_space.handler_flags = flags;
+	handler_obj->address_space.region_list = NULL;
+	handler_obj->address_space.node = node;
+	handler_obj->address_space.handler = handler;
+	handler_obj->address_space.context = context;
+	handler_obj->address_space.setup = setup;
+
+	/* Install at head of Device.address_space list */
+
+	handler_obj->address_space.next = obj_desc->device.handler;
+
+	/*
+	 * The Device object is the first reference on the handler_obj.
+	 * Each region that uses the handler adds a reference.
+	 */
+	obj_desc->device.handler = handler_obj;
+
+	/*
+	 * Walk the namespace finding all of the regions this
+	 * handler will manage.
+	 *
+	 * Start at the device and search the branch toward
+	 * the leaf nodes until either the leaf is encountered or
+	 * a device is detected that has an address handler of the
+	 * same type.
+	 *
+	 * In either case, back up and search down the remainder
+	 * of the branch
+	 */
+	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
+					ACPI_NS_WALK_UNLOCK,
+					acpi_ev_install_handler, NULL,
+					handler_obj, NULL);
+
+      unlock_and_exit:
+	return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 51f5379..c986b23 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 0cc6a16..6555e35 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -1,11 +1,11 @@
 /******************************************************************************
  *
- * Module Name: evregion - ACPI address_space (op_region) handler dispatch
+ * Module Name: evregion - Operation Region support
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -50,10 +50,9 @@
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evregion")
 
+extern u8 acpi_gbl_default_address_spaces[];
+
 /* Local prototypes */
-static u8
-acpi_ev_has_default_handler(struct acpi_namespace_node *node,
-			    acpi_adr_space_type space_id);
 
 static void acpi_ev_orphan_ec_reg_method(void);
 
@@ -61,135 +60,6 @@
 acpi_ev_reg_run(acpi_handle obj_handle,
 		u32 level, void *context, void **return_value);
 
-static acpi_status
-acpi_ev_install_handler(acpi_handle obj_handle,
-			u32 level, void *context, void **return_value);
-
-/* These are the address spaces that will get default handlers */
-
-#define ACPI_NUM_DEFAULT_SPACES     4
-
-static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
-	ACPI_ADR_SPACE_SYSTEM_MEMORY,
-	ACPI_ADR_SPACE_SYSTEM_IO,
-	ACPI_ADR_SPACE_PCI_CONFIG,
-	ACPI_ADR_SPACE_DATA_TABLE
-};
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_install_region_handlers
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Installs the core subsystem default address space handlers.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_install_region_handlers(void)
-{
-	acpi_status status;
-	u32 i;
-
-	ACPI_FUNCTION_TRACE(ev_install_region_handlers);
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/*
-	 * All address spaces (PCI Config, EC, SMBus) are scope dependent and
-	 * registration must occur for a specific device.
-	 *
-	 * In the case of the system memory and IO address spaces there is
-	 * currently no device associated with the address space. For these we
-	 * use the root.
-	 *
-	 * We install the default PCI config space handler at the root so that
-	 * this space is immediately available even though the we have not
-	 * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
-	 * specification which states that the PCI config space must be always
-	 * available -- even though we are nowhere near ready to find the PCI root
-	 * buses at this point.
-	 *
-	 * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
-	 * has already been installed (via acpi_install_address_space_handler).
-	 * Similar for AE_SAME_HANDLER.
-	 */
-	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
-		status = acpi_ev_install_space_handler(acpi_gbl_root_node,
-						       acpi_gbl_default_address_spaces
-						       [i],
-						       ACPI_DEFAULT_HANDLER,
-						       NULL, NULL);
-		switch (status) {
-		case AE_OK:
-		case AE_SAME_HANDLER:
-		case AE_ALREADY_EXISTS:
-
-			/* These exceptions are all OK */
-
-			status = AE_OK;
-			break;
-
-		default:
-
-			goto unlock_and_exit;
-		}
-	}
-
-      unlock_and_exit:
-	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_has_default_handler
- *
- * PARAMETERS:  node                - Namespace node for the device
- *              space_id            - The address space ID
- *
- * RETURN:      TRUE if default handler is installed, FALSE otherwise
- *
- * DESCRIPTION: Check if the default handler is installed for the requested
- *              space ID.
- *
- ******************************************************************************/
-
-static u8
-acpi_ev_has_default_handler(struct acpi_namespace_node *node,
-			    acpi_adr_space_type space_id)
-{
-	union acpi_operand_object *obj_desc;
-	union acpi_operand_object *handler_obj;
-
-	/* Must have an existing internal object */
-
-	obj_desc = acpi_ns_get_attached_object(node);
-	if (obj_desc) {
-		handler_obj = obj_desc->device.handler;
-
-		/* Walk the linked list of handlers for this object */
-
-		while (handler_obj) {
-			if (handler_obj->address_space.space_id == space_id) {
-				if (handler_obj->address_space.handler_flags &
-				    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
-					return (TRUE);
-				}
-			}
-
-			handler_obj = handler_obj->address_space.next;
-		}
-	}
-
-	return (FALSE);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_initialize_op_regions
@@ -241,91 +111,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_execute_reg_method
- *
- * PARAMETERS:  region_obj          - Region object
- *              function            - Passed to _REG: On (1) or Off (0)
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Execute _REG method for a region
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
-{
-	struct acpi_evaluate_info *info;
-	union acpi_operand_object *args[3];
-	union acpi_operand_object *region_obj2;
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(ev_execute_reg_method);
-
-	region_obj2 = acpi_ns_get_secondary_object(region_obj);
-	if (!region_obj2) {
-		return_ACPI_STATUS(AE_NOT_EXIST);
-	}
-
-	if (region_obj2->extra.method_REG == NULL) {
-		return_ACPI_STATUS(AE_OK);
-	}
-
-	/* Allocate and initialize the evaluation information block */
-
-	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
-	if (!info) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-
-	info->prefix_node = region_obj2->extra.method_REG;
-	info->pathname = NULL;
-	info->parameters = args;
-	info->flags = ACPI_IGNORE_RETURN_VALUE;
-
-	/*
-	 * The _REG method has two arguments:
-	 *
-	 * arg0 - Integer:
-	 *  Operation region space ID Same value as region_obj->Region.space_id
-	 *
-	 * arg1 - Integer:
-	 *  connection status 1 for connecting the handler, 0 for disconnecting
-	 *  the handler (Passed as a parameter)
-	 */
-	args[0] =
-	    acpi_ut_create_integer_object((u64) region_obj->region.space_id);
-	if (!args[0]) {
-		status = AE_NO_MEMORY;
-		goto cleanup1;
-	}
-
-	args[1] = acpi_ut_create_integer_object((u64) function);
-	if (!args[1]) {
-		status = AE_NO_MEMORY;
-		goto cleanup2;
-	}
-
-	args[2] = NULL;		/* Terminate list */
-
-	/* Execute the method, no return value */
-
-	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
-			(ACPI_TYPE_METHOD, info->prefix_node, NULL));
-
-	status = acpi_ns_evaluate(info);
-	acpi_ut_remove_reference(args[1]);
-
-      cleanup2:
-	acpi_ut_remove_reference(args[0]);
-
-      cleanup1:
-	ACPI_FREE(info);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ev_address_space_dispatch
  *
  * PARAMETERS:  region_obj          - Internal region object
@@ -709,351 +494,86 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_install_handler
+ * FUNCTION:    acpi_ev_execute_reg_method
  *
- * PARAMETERS:  walk_namespace callback
- *
- * DESCRIPTION: This routine installs an address handler into objects that are
- *              of type Region or Device.
- *
- *              If the Object is a Device, and the device has a handler of
- *              the same type then the search is terminated in that branch.
- *
- *              This is because the existing handler is closer in proximity
- *              to any more regions than the one we are trying to install.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ev_install_handler(acpi_handle obj_handle,
-			u32 level, void *context, void **return_value)
-{
-	union acpi_operand_object *handler_obj;
-	union acpi_operand_object *next_handler_obj;
-	union acpi_operand_object *obj_desc;
-	struct acpi_namespace_node *node;
-	acpi_status status;
-
-	ACPI_FUNCTION_NAME(ev_install_handler);
-
-	handler_obj = (union acpi_operand_object *)context;
-
-	/* Parameter validation */
-
-	if (!handler_obj) {
-		return (AE_OK);
-	}
-
-	/* Convert and validate the device handle */
-
-	node = acpi_ns_validate_handle(obj_handle);
-	if (!node) {
-		return (AE_BAD_PARAMETER);
-	}
-
-	/*
-	 * We only care about regions and objects that are allowed to have
-	 * address space handlers
-	 */
-	if ((node->type != ACPI_TYPE_DEVICE) &&
-	    (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
-		return (AE_OK);
-	}
-
-	/* Check for an existing internal object */
-
-	obj_desc = acpi_ns_get_attached_object(node);
-	if (!obj_desc) {
-
-		/* No object, just exit */
-
-		return (AE_OK);
-	}
-
-	/* Devices are handled different than regions */
-
-	if (obj_desc->common.type == ACPI_TYPE_DEVICE) {
-
-		/* Check if this Device already has a handler for this address space */
-
-		next_handler_obj = obj_desc->device.handler;
-		while (next_handler_obj) {
-
-			/* Found a handler, is it for the same address space? */
-
-			if (next_handler_obj->address_space.space_id ==
-			    handler_obj->address_space.space_id) {
-				ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
-						  "Found handler for region [%s] in device %p(%p) "
-						  "handler %p\n",
-						  acpi_ut_get_region_name
-						  (handler_obj->address_space.
-						   space_id), obj_desc,
-						  next_handler_obj,
-						  handler_obj));
-
-				/*
-				 * Since the object we found it on was a device, then it
-				 * means that someone has already installed a handler for
-				 * the branch of the namespace from this device on. Just
-				 * bail out telling the walk routine to not traverse this
-				 * branch. This preserves the scoping rule for handlers.
-				 */
-				return (AE_CTRL_DEPTH);
-			}
-
-			/* Walk the linked list of handlers attached to this device */
-
-			next_handler_obj = next_handler_obj->address_space.next;
-		}
-
-		/*
-		 * As long as the device didn't have a handler for this space we
-		 * don't care about it. We just ignore it and proceed.
-		 */
-		return (AE_OK);
-	}
-
-	/* Object is a Region */
-
-	if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
-
-		/* This region is for a different address space, just ignore it */
-
-		return (AE_OK);
-	}
-
-	/*
-	 * Now we have a region and it is for the handler's address space type.
-	 *
-	 * First disconnect region for any previous handler (if any)
-	 */
-	acpi_ev_detach_region(obj_desc, FALSE);
-
-	/* Connect the region to the new handler */
-
-	status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE);
-	return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_install_space_handler
- *
- * PARAMETERS:  node            - Namespace node for the device
- *              space_id        - The address space ID
- *              handler         - Address of the handler
- *              setup           - Address of the setup function
- *              context         - Value passed to the handler on each access
+ * PARAMETERS:  region_obj          - Region object
+ *              function            - Passed to _REG: On (1) or Off (0)
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Install a handler for all op_regions of a given space_id.
- *              Assumes namespace is locked
+ * DESCRIPTION: Execute _REG method for a region
  *
  ******************************************************************************/
 
 acpi_status
-acpi_ev_install_space_handler(struct acpi_namespace_node * node,
-			      acpi_adr_space_type space_id,
-			      acpi_adr_space_handler handler,
-			      acpi_adr_space_setup setup, void *context)
+acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
 {
-	union acpi_operand_object *obj_desc;
-	union acpi_operand_object *handler_obj;
+	struct acpi_evaluate_info *info;
+	union acpi_operand_object *args[3];
+	union acpi_operand_object *region_obj2;
 	acpi_status status;
-	acpi_object_type type;
-	u8 flags = 0;
 
-	ACPI_FUNCTION_TRACE(ev_install_space_handler);
+	ACPI_FUNCTION_TRACE(ev_execute_reg_method);
+
+	region_obj2 = acpi_ns_get_secondary_object(region_obj);
+	if (!region_obj2) {
+		return_ACPI_STATUS(AE_NOT_EXIST);
+	}
+
+	if (region_obj2->extra.method_REG == NULL) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
+	/* Allocate and initialize the evaluation information block */
+
+	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+	if (!info) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	info->prefix_node = region_obj2->extra.method_REG;
+	info->pathname = NULL;
+	info->parameters = args;
+	info->flags = ACPI_IGNORE_RETURN_VALUE;
 
 	/*
-	 * This registration is valid for only the types below and the root. This
-	 * is where the default handlers get placed.
-	 */
-	if ((node->type != ACPI_TYPE_DEVICE) &&
-	    (node->type != ACPI_TYPE_PROCESSOR) &&
-	    (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
-		status = AE_BAD_PARAMETER;
-		goto unlock_and_exit;
-	}
-
-	if (handler == ACPI_DEFAULT_HANDLER) {
-		flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
-
-		switch (space_id) {
-		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-			handler = acpi_ex_system_memory_space_handler;
-			setup = acpi_ev_system_memory_region_setup;
-			break;
-
-		case ACPI_ADR_SPACE_SYSTEM_IO:
-			handler = acpi_ex_system_io_space_handler;
-			setup = acpi_ev_io_space_region_setup;
-			break;
-
-		case ACPI_ADR_SPACE_PCI_CONFIG:
-			handler = acpi_ex_pci_config_space_handler;
-			setup = acpi_ev_pci_config_region_setup;
-			break;
-
-		case ACPI_ADR_SPACE_CMOS:
-			handler = acpi_ex_cmos_space_handler;
-			setup = acpi_ev_cmos_region_setup;
-			break;
-
-		case ACPI_ADR_SPACE_PCI_BAR_TARGET:
-			handler = acpi_ex_pci_bar_space_handler;
-			setup = acpi_ev_pci_bar_region_setup;
-			break;
-
-		case ACPI_ADR_SPACE_DATA_TABLE:
-			handler = acpi_ex_data_table_space_handler;
-			setup = NULL;
-			break;
-
-		default:
-			status = AE_BAD_PARAMETER;
-			goto unlock_and_exit;
-		}
-	}
-
-	/* If the caller hasn't specified a setup routine, use the default */
-
-	if (!setup) {
-		setup = acpi_ev_default_region_setup;
-	}
-
-	/* Check for an existing internal object */
-
-	obj_desc = acpi_ns_get_attached_object(node);
-	if (obj_desc) {
-		/*
-		 * The attached device object already exists. Make sure the handler
-		 * is not already installed.
-		 */
-		handler_obj = obj_desc->device.handler;
-
-		/* Walk the handler list for this device */
-
-		while (handler_obj) {
-
-			/* Same space_id indicates a handler already installed */
-
-			if (handler_obj->address_space.space_id == space_id) {
-				if (handler_obj->address_space.handler ==
-				    handler) {
-					/*
-					 * It is (relatively) OK to attempt to install the SAME
-					 * handler twice. This can easily happen with the
-					 * PCI_Config space.
-					 */
-					status = AE_SAME_HANDLER;
-					goto unlock_and_exit;
-				} else {
-					/* A handler is already installed */
-
-					status = AE_ALREADY_EXISTS;
-				}
-				goto unlock_and_exit;
-			}
-
-			/* Walk the linked list of handlers */
-
-			handler_obj = handler_obj->address_space.next;
-		}
-	} else {
-		ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
-				  "Creating object on Device %p while installing handler\n",
-				  node));
-
-		/* obj_desc does not exist, create one */
-
-		if (node->type == ACPI_TYPE_ANY) {
-			type = ACPI_TYPE_DEVICE;
-		} else {
-			type = node->type;
-		}
-
-		obj_desc = acpi_ut_create_internal_object(type);
-		if (!obj_desc) {
-			status = AE_NO_MEMORY;
-			goto unlock_and_exit;
-		}
-
-		/* Init new descriptor */
-
-		obj_desc->common.type = (u8) type;
-
-		/* Attach the new object to the Node */
-
-		status = acpi_ns_attach_object(node, obj_desc, type);
-
-		/* Remove local reference to the object */
-
-		acpi_ut_remove_reference(obj_desc);
-
-		if (ACPI_FAILURE(status)) {
-			goto unlock_and_exit;
-		}
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
-			  "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
-			  acpi_ut_get_region_name(space_id), space_id,
-			  acpi_ut_get_node_name(node), node, obj_desc));
-
-	/*
-	 * Install the handler
+	 * The _REG method has two arguments:
 	 *
-	 * At this point there is no existing handler. Just allocate the object
-	 * for the handler and link it into the list.
+	 * arg0 - Integer:
+	 *  Operation region space ID Same value as region_obj->Region.space_id
+	 *
+	 * arg1 - Integer:
+	 *  connection status 1 for connecting the handler, 0 for disconnecting
+	 *  the handler (Passed as a parameter)
 	 */
-	handler_obj =
-	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
-	if (!handler_obj) {
+	args[0] =
+	    acpi_ut_create_integer_object((u64)region_obj->region.space_id);
+	if (!args[0]) {
 		status = AE_NO_MEMORY;
-		goto unlock_and_exit;
+		goto cleanup1;
 	}
 
-	/* Init handler obj */
+	args[1] = acpi_ut_create_integer_object((u64)function);
+	if (!args[1]) {
+		status = AE_NO_MEMORY;
+		goto cleanup2;
+	}
 
-	handler_obj->address_space.space_id = (u8) space_id;
-	handler_obj->address_space.handler_flags = flags;
-	handler_obj->address_space.region_list = NULL;
-	handler_obj->address_space.node = node;
-	handler_obj->address_space.handler = handler;
-	handler_obj->address_space.context = context;
-	handler_obj->address_space.setup = setup;
+	args[2] = NULL;		/* Terminate list */
 
-	/* Install at head of Device.address_space list */
+	/* Execute the method, no return value */
 
-	handler_obj->address_space.next = obj_desc->device.handler;
+	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+			(ACPI_TYPE_METHOD, info->prefix_node, NULL));
 
-	/*
-	 * The Device object is the first reference on the handler_obj.
-	 * Each region that uses the handler adds a reference.
-	 */
-	obj_desc->device.handler = handler_obj;
+	status = acpi_ns_evaluate(info);
+	acpi_ut_remove_reference(args[1]);
 
-	/*
-	 * Walk the namespace finding all of the regions this
-	 * handler will manage.
-	 *
-	 * Start at the device and search the branch toward
-	 * the leaf nodes until either the leaf is encountered or
-	 * a device is detected that has an address handler of the
-	 * same type.
-	 *
-	 * In either case, back up and search down the remainder
-	 * of the branch
-	 */
-	status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
-					ACPI_NS_WALK_UNLOCK,
-					acpi_ev_install_handler, NULL,
-					handler_obj, NULL);
+      cleanup2:
+	acpi_ut_remove_reference(args[0]);
 
-      unlock_and_exit:
+      cleanup1:
+	ACPI_FREE(info);
 	return_ACPI_STATUS(status);
 }
 
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 1474241..3bb6167 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index f9661e2..f4b43be 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -89,7 +89,7 @@
 	 */
 	interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
 
-	return_UINT32(interrupt_handled);
+	return_VALUE(interrupt_handled);
 }
 
 /*******************************************************************************
@@ -120,7 +120,7 @@
 
 	interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
 
-	return_UINT32(interrupt_handled);
+	return_VALUE(interrupt_handled);
 }
 
 /******************************************************************************
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index ae668f3..ddffd68 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -56,13 +56,13 @@
  *
  * FUNCTION:    acpi_install_notify_handler
  *
- * PARAMETERS:  Device          - The device for which notifies will be handled
+ * PARAMETERS:  device          - The device for which notifies will be handled
  *              handler_type    - The type of handler:
  *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
  *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
  *                                  ACPI_ALL_NOTIFY:    Both System and Device
- *              Handler         - Address of the handler
- *              Context         - Value passed to the handler on each GPE
+ *              handler         - Address of the handler
+ *              context         - Value passed to the handler on each GPE
  *
  * RETURN:      Status
  *
@@ -217,12 +217,12 @@
  *
  * FUNCTION:    acpi_remove_notify_handler
  *
- * PARAMETERS:  Device          - The device for which the handler is installed
+ * PARAMETERS:  device          - The device for which the handler is installed
  *              handler_type    - The type of handler:
  *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
  *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
  *                                  ACPI_ALL_NOTIFY:    Both System and Device
- *              Handler         - Address of the handler
+ *              handler         - Address of the handler
  *
  * RETURN:      Status
  *
@@ -249,7 +249,8 @@
 	    (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
-	/* Make sure all deferred tasks are completed */
+
+	/* Make sure all deferred notify tasks are completed */
 
 	acpi_os_wait_events_complete();
 
@@ -596,7 +597,7 @@
 		return_ACPI_STATUS(status);
 	}
 
-	/* Allocate memory for the handler object */
+	/* Allocate and init handler object (before lock) */
 
 	handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
 	if (!handler) {
@@ -622,16 +623,15 @@
 		goto free_and_exit;
 	}
 
-	/* Allocate and init handler object */
-
 	handler->address = address;
 	handler->context = context;
 	handler->method_node = gpe_event_info->dispatch.method_node;
-	handler->original_flags = gpe_event_info->flags &
-			(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+	handler->original_flags = (u8)(gpe_event_info->flags &
+				       (ACPI_GPE_XRUPT_TYPE_MASK |
+				        ACPI_GPE_DISPATCH_MASK));
 
 	/*
-	 * If the GPE is associated with a method, it might have been enabled
+	 * If the GPE is associated with a method, it may have been enabled
 	 * automatically during initialization, in which case it has to be
 	 * disabled now to avoid spurious execution of the handler.
 	 */
@@ -646,7 +646,7 @@
 
 	gpe_event_info->dispatch.handler = handler;
 
-	/* Setup up dispatch flags to indicate handler (vs. method) */
+	/* Setup up dispatch flags to indicate handler (vs. method/notify) */
 
 	gpe_event_info->flags &=
 	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
@@ -697,7 +697,7 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	/* Make sure all deferred tasks are completed */
+	/* Make sure all deferred GPE tasks are completed */
 
 	acpi_os_wait_events_complete();
 
@@ -747,10 +747,10 @@
 	 * enabled, it should be enabled at this point to restore the
 	 * post-initialization configuration.
 	 */
-
-	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
-	    && handler->originally_enabled)
+	if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) &&
+	    handler->originally_enabled) {
 		(void)acpi_ev_add_gpe_reference(gpe_event_info);
+	}
 
 	/* Now we can free the handler object */
 
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 35520c6..d6e4e42 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,6 @@
  * DESCRIPTION: Transfers the system into ACPI mode.
  *
  ******************************************************************************/
-
 acpi_status acpi_enable(void)
 {
 	acpi_status status;
@@ -210,8 +209,8 @@
  *
  * FUNCTION:    acpi_disable_event
  *
- * PARAMETERS:  Event           - The fixed eventto be enabled
- *              Flags           - Reserved
+ * PARAMETERS:  event           - The fixed event to be disabled
+ *              flags           - Reserved
  *
  * RETURN:      Status
  *
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 3f30e75..aff4cc2 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
 ACPI_MODULE_NAME("evxfgpe")
 
 #if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
-/******************************************************************************
+/*******************************************************************************
  *
  * FUNCTION:    acpi_update_all_gpes
  *
@@ -172,6 +172,7 @@
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 	return_ACPI_STATUS(status);
 }
+
 ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
 
 
@@ -225,7 +226,7 @@
 		    ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
 	}
 
-	/* Validate WakeDevice is of type Device */
+	/* Validate wake_device is of type Device */
 
 	if (device_node->type != ACPI_TYPE_DEVICE) {
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
@@ -432,8 +433,8 @@
  *
  * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              event_status    - Where the current status of the event will
- *                                be returned
+ *              event_status        - Where the current status of the event
+ *                                    will be returned
  *
  * RETURN:      Status
  *
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 96b412d..96c9e5f 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 16219bd..d93b70b 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 #include "actables.h"
 #include "acdispat.h"
 #include "acevents.h"
+#include "amlcode.h"
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("exconfig")
@@ -120,8 +121,11 @@
 	acpi_ns_exec_module_code_list();
 	acpi_ex_enter_interpreter();
 
-	/* Update GPEs for any new _Lxx/_Exx methods. Ignore errors */
-
+	/*
+	 * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
+	 * responsible for discovering any new wake GPEs by running _PRW methods
+	 * that may have been loaded by this table.
+	 */
 	status = acpi_tb_get_owner_id(table_index, &owner_id);
 	if (ACPI_SUCCESS(status)) {
 		acpi_ev_update_gpes(owner_id);
@@ -158,12 +162,12 @@
 
 	ACPI_FUNCTION_TRACE(ex_load_table_op);
 
-	/* Validate lengths for the signature_string, OEMIDString, OEMtable_iD */
+	/* Validate lengths for the Signature, oem_id, and oem_table_id strings */
 
 	if ((operand[0]->string.length > ACPI_NAME_SIZE) ||
 	    (operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
 	    (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
+		return_ACPI_STATUS(AE_AML_STRING_LIMIT);
 	}
 
 	/* Find the ACPI table in the RSDT/XSDT */
@@ -210,8 +214,8 @@
 	/* parameter_path (optional parameter) */
 
 	if (operand[4]->string.length > 0) {
-		if ((operand[4]->string.pointer[0] != '\\') &&
-		    (operand[4]->string.pointer[0] != '^')) {
+		if ((operand[4]->string.pointer[0] != AML_ROOT_PREFIX) &&
+		    (operand[4]->string.pointer[0] != AML_PARENT_PREFIX)) {
 			/*
 			 * Path is not absolute, so it will be relative to the node
 			 * referenced by the root_path_string (or the NS root if omitted)
@@ -301,7 +305,7 @@
 		    acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ,
 						   region_offset, 8, &value);
 		if (ACPI_FAILURE(status)) {
-			return status;
+			return (status);
 		}
 
 		*buffer = (u8)value;
@@ -309,7 +313,7 @@
 		region_offset++;
 	}
 
-	return AE_OK;
+	return (AE_OK);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 4492a4e..d2b9613 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -176,7 +176,7 @@
 
 	/* Save the Result */
 
-	acpi_ex_truncate_for32bit_table(return_desc);
+	(void)acpi_ex_truncate_for32bit_table(return_desc);
 	*result_desc = return_desc;
 	return_ACPI_STATUS(AE_OK);
 }
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 66554bc..26a13f6 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index d7c9f51..7eb853c 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 858b43a..e5a3c24 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -464,9 +464,8 @@
 
 	ACPI_FUNCTION_NAME(ex_dump_operand)
 
-	    if (!
-		((ACPI_LV_EXEC & acpi_dbg_level)
-		  && (_COMPONENT & acpi_dbg_layer))) {
+	    /* Check if debug output enabled */
+	    if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) {
 		return;
 	}
 
@@ -811,9 +810,10 @@
 	ACPI_FUNCTION_ENTRY();
 
 	if (!flags) {
-		if (!
-		    ((ACPI_LV_OBJECTS & acpi_dbg_level)
-		      && (_COMPONENT & acpi_dbg_layer))) {
+
+		/* Check if debug output enabled */
+
+		if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_OBJECTS, _COMPONENT)) {
 			return;
 		}
 	}
@@ -999,9 +999,10 @@
 	}
 
 	if (!flags) {
-		if (!
-		    ((ACPI_LV_OBJECTS & acpi_dbg_level)
-		      && (_COMPONENT & acpi_dbg_layer))) {
+
+		/* Check if debug output enabled */
+
+		if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_OBJECTS, _COMPONENT)) {
 			return_VOID;
 		}
 	}
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index ebc55fb..7d4bae7 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index aa2ccfb..ec7f569 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -329,7 +329,6 @@
 static u8
 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
 {
-	ACPI_FUNCTION_NAME(ex_register_overflow);
 
 	if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
 		/*
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 8405870..72a2a13 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index d1f449d..7be0205 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -377,7 +377,8 @@
 		return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
 	}
 
-	/* Must have a valid thread. */
+	/* Must have a valid thread ID */
+
 	if (!walk_state->thread) {
 		ACPI_ERROR((AE_INFO,
 			    "Cannot release Mutex [%4.4s], null thread info",
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index 2ff578a..14689de 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index bbf01e9..b60c877 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -948,13 +948,7 @@
 					 */
 					return_desc =
 					    acpi_ut_create_integer_object((u64)
-									  temp_desc->
-									  buffer.
-									  pointer
-									  [operand
-									   [0]->
-									   reference.
-									   value]);
+									  temp_desc->buffer.pointer[operand[0]->reference.value]);
 					if (!return_desc) {
 						status = AE_NO_MEMORY;
 						goto cleanup;
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index ee5634a..e491e46 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 2c89b46..2d7491f 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 3e08695..b76b970 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index ba9db4d..d6eab81 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,7 @@
 		/* Invalid field access type */
 
 		ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
-		return_UINT32(0);
+		return_VALUE(0);
 	}
 
 	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
@@ -289,7 +289,7 @@
 	}
 
 	*return_byte_alignment = byte_alignment;
-	return_UINT32(bit_length);
+	return_VALUE(bit_length);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 1db2c0b..182abaf 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,9 @@
 		}
 
 		/*
-		 * Attempt to map from the requested address to the end of the region.
-		 * However, we will never map more than one page, nor will we cross
-		 * a page boundary.
+		 * October 2009: Attempt to map from the requested address to the
+		 * end of the region. However, we will never map more than one
+		 * page, nor will we cross a page boundary.
 		 */
 		map_length = (acpi_size)
 		    ((mem_info->address + mem_info->length) - address);
@@ -154,12 +154,15 @@
 		 * a page boundary, just map up to the page boundary, do not cross.
 		 * On some systems, crossing a page boundary while mapping regions
 		 * can cause warnings if the pages have different attributes
-		 * due to resource management
+		 * due to resource management.
+		 *
+		 * This has the added benefit of constraining a single mapping to
+		 * one page, which is similar to the original code that used a 4k
+		 * maximum window.
 		 */
 		page_boundary_map_length =
 		    ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address;
-
-		if (!page_boundary_map_length) {
+		if (page_boundary_map_length == 0) {
 			page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
 		}
 
@@ -236,19 +239,19 @@
 
 		switch (bit_width) {
 		case 8:
-			ACPI_SET8(logical_addr_ptr) = (u8) * value;
+			ACPI_SET8(logical_addr_ptr, *value);
 			break;
 
 		case 16:
-			ACPI_SET16(logical_addr_ptr) = (u16) * value;
+			ACPI_SET16(logical_addr_ptr, *value);
 			break;
 
 		case 32:
-			ACPI_SET32(logical_addr_ptr) = (u32) * value;
+			ACPI_SET32(logical_addr_ptr, *value);
 			break;
 
 		case 64:
-			ACPI_SET64(logical_addr_ptr) = (u64) * value;
+			ACPI_SET64(logical_addr_ptr, *value);
 			break;
 
 		default:
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 6239956..8565b6b 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index cc176b2..e4f9dfb 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index b9ebff2..9fb9f5e 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index 90431f1..93c6049 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -487,14 +487,33 @@
 	default:
 
 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "Storing %s (%p) directly into node (%p) with no implicit conversion\n",
+				  "Storing [%s] (%p) directly into node [%s] (%p)"
+				  " with no implicit conversion\n",
 				  acpi_ut_get_object_type_name(source_desc),
-				  source_desc, node));
+				  source_desc,
+				  acpi_ut_get_object_type_name(target_desc),
+				  node));
 
-		/* No conversions for all other types. Just attach the source object */
+		/*
+		 * No conversions for all other types. Directly store a copy of
+		 * the source object. NOTE: This is a departure from the ACPI
+		 * spec, which states "If conversion is impossible, abort the
+		 * running control method".
+		 *
+		 * This code implements "If conversion is impossible, treat the
+		 * Store operation as a CopyObject".
+		 */
+		status =
+		    acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
+						    walk_state);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
 
-		status = acpi_ns_attach_object(node, source_desc,
-					       source_desc->common.type);
+		status =
+		    acpi_ns_attach_object(node, new_desc,
+					  new_desc->common.type);
+		acpi_ut_remove_reference(new_desc);
 		break;
 	}
 
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 87153bb..1cefe77 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -253,7 +253,7 @@
 
 		/* Truncate value if we are executing from a 32-bit ACPI table */
 
-		acpi_ex_truncate_for32bit_table(dest_desc);
+		(void)acpi_ex_truncate_for32bit_table(dest_desc);
 		break;
 
 	case ACPI_TYPE_STRING:
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index b5f339c..26e3710 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index c8a0ad5..6578dee 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 264d22d..b205cbb 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -202,35 +202,39 @@
  *
  * PARAMETERS:  obj_desc        - Object to be truncated
  *
- * RETURN:      none
+ * RETURN:      TRUE if a truncation was performed, FALSE otherwise.
  *
  * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
  *              32-bit, as determined by the revision of the DSDT.
  *
  ******************************************************************************/
 
-void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
+u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
 {
 
 	ACPI_FUNCTION_ENTRY();
 
 	/*
 	 * Object must be a valid number and we must be executing
-	 * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
+	 * a control method. Object could be NS node for AML_INT_NAMEPATH_OP.
 	 */
 	if ((!obj_desc) ||
 	    (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) ||
 	    (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
-		return;
+		return (FALSE);
 	}
 
-	if (acpi_gbl_integer_byte_width == 4) {
+	if ((acpi_gbl_integer_byte_width == 4) &&
+	    (obj_desc->integer.value > (u64)ACPI_UINT32_MAX)) {
 		/*
-		 * We are running a method that exists in a 32-bit ACPI table.
+		 * We are executing in a 32-bit ACPI table.
 		 * Truncate the value to 32 bits by zeroing out the upper 32-bit field
 		 */
-		obj_desc->integer.value &= (u64) ACPI_UINT32_MAX;
+		obj_desc->integer.value &= (u64)ACPI_UINT32_MAX;
+		return (TRUE);
 	}
+
+	return (FALSE);
 }
 
 /*******************************************************************************
@@ -336,7 +340,7 @@
 	/* u64 is unsigned, so we don't worry about a '-' prefix */
 
 	if (value == 0) {
-		return_UINT32(1);
+		return_VALUE(1);
 	}
 
 	current_value = value;
@@ -350,7 +354,7 @@
 		num_digits++;
 	}
 
-	return_UINT32(num_digits);
+	return_VALUE(num_digits);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 90a9aea..deb3f61 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,8 +108,7 @@
 		 * enable bits to default
 		 */
 		status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
-					    (u32) acpi_gbl_FADT.acpi_disable,
-					    8);
+					    (u32)acpi_gbl_FADT.acpi_disable, 8);
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Attempting to enable Legacy (non-ACPI) mode\n"));
 		break;
@@ -152,18 +151,18 @@
 	 * system does not support mode transition.
 	 */
 	if (!acpi_gbl_FADT.smi_command) {
-		return_UINT32(ACPI_SYS_MODE_ACPI);
+		return_VALUE(ACPI_SYS_MODE_ACPI);
 	}
 
 	status = acpi_read_bit_register(ACPI_BITREG_SCI_ENABLE, &value);
 	if (ACPI_FAILURE(status)) {
-		return_UINT32(ACPI_SYS_MODE_LEGACY);
+		return_VALUE(ACPI_SYS_MODE_LEGACY);
 	}
 
 	if (value) {
-		return_UINT32(ACPI_SYS_MODE_ACPI);
+		return_VALUE(ACPI_SYS_MODE_ACPI);
 	} else {
-		return_UINT32(ACPI_SYS_MODE_LEGACY);
+		return_VALUE(ACPI_SYS_MODE_LEGACY);
 	}
 }
 
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 94996f9..5e5f762 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -200,7 +200,6 @@
  * FUNCTION:    acpi_hw_extended_wake
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - Reserved, set to zero
  *
  * RETURN:      Status
  *
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 6456004..20d02e9 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -69,8 +69,10 @@
 
 u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info)
 {
-	return (u32)1 << (gpe_event_info->gpe_number -
-		 gpe_event_info->register_info->base_gpe_number);
+
+	return ((u32)1 <<
+		(gpe_event_info->gpe_number -
+		 gpe_event_info->register_info->base_gpe_number));
 }
 
 /******************************************************************************
@@ -133,7 +135,7 @@
 		break;
 
 	default:
-		ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u\n", action));
+		ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action));
 		return (AE_BAD_PARAMETER);
 	}
 
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index 65bc345..0889a62 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index f4e5750..083d655 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
 
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acnamesp.h"
 #include "acevents.h"
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -364,8 +363,7 @@
  * DESCRIPTION: Read from the specified ACPI register
  *
  ******************************************************************************/
-acpi_status
-acpi_hw_register_read(u32 register_id, u32 * return_value)
+acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
 {
 	u32 value = 0;
 	acpi_status status;
@@ -485,7 +483,7 @@
 						&acpi_gbl_xpm1b_status);
 		break;
 
-	case ACPI_REGISTER_PM1_ENABLE:	/* PM1 A/B: 16-bit access */
+	case ACPI_REGISTER_PM1_ENABLE:	/* PM1 A/B: 16-bit access each */
 
 		status = acpi_hw_write_multiple(value,
 						&acpi_gbl_xpm1a_enable,
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 3fddde0..e3828cc 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
 #include <acpi/acpi.h>
 #include <linux/acpi.h>
 #include "accommon.h"
-#include <linux/module.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwsleep")
@@ -178,7 +177,7 @@
 		 * to still read the right value. Ideally, this block would go
 		 * away entirely.
 		 */
-		acpi_os_stall(10000000);
+		acpi_os_stall(10 * ACPI_USEC_PER_SEC);
 
 		status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
 						sleep_enable_reg_info->
@@ -323,7 +322,8 @@
 	 * and use it to determine whether the system is rebooting or
 	 * resuming. Clear WAK_STS for compatibility.
 	 */
-	acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
+	(void)acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS,
+				      ACPI_CLEAR_STATUS);
 	acpi_gbl_system_awake_and_running = TRUE;
 
 	/* Enable power button */
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index bfdce22..0c1a8bb 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -176,10 +176,11 @@
 	/*
 	 * Compute Duration (Requires a 64-bit multiply and divide):
 	 *
-	 * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY;
+	 * time_elapsed (microseconds) =
+	 *  (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;
 	 */
-	status = acpi_ut_short_divide(((u64) delta_ticks) * 1000000,
-				      PM_TIMER_FREQUENCY, &quotient, NULL);
+	status = acpi_ut_short_divide(((u64)delta_ticks) * ACPI_USEC_PER_SEC,
+				      ACPI_PM_TIMER_FREQUENCY, &quotient, NULL);
 
 	*time_elapsed = (u32) quotient;
 	return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index b6aae58..eab70d5 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -135,7 +135,7 @@
 	if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) {
 		ACPI_ERROR((AE_INFO,
 			    "Bad BitWidth parameter: %8.8X", bit_width));
-		return AE_BAD_PARAMETER;
+		return (AE_BAD_PARAMETER);
 	}
 
 	port_info = acpi_protected_ports;
@@ -234,11 +234,11 @@
 	status = acpi_hw_validate_io_request(address, width);
 	if (ACPI_SUCCESS(status)) {
 		status = acpi_os_read_port(address, value, width);
-		return status;
+		return (status);
 	}
 
 	if (status != AE_AML_ILLEGAL_ADDRESS) {
-		return status;
+		return (status);
 	}
 
 	/*
@@ -253,7 +253,7 @@
 		if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
 			status = acpi_os_read_port(address, &one_byte, 8);
 			if (ACPI_FAILURE(status)) {
-				return status;
+				return (status);
 			}
 
 			*value |= (one_byte << i);
@@ -262,7 +262,7 @@
 		address++;
 	}
 
-	return AE_OK;
+	return (AE_OK);
 }
 
 /******************************************************************************
@@ -297,11 +297,11 @@
 	status = acpi_hw_validate_io_request(address, width);
 	if (ACPI_SUCCESS(status)) {
 		status = acpi_os_write_port(address, value, width);
-		return status;
+		return (status);
 	}
 
 	if (status != AE_AML_ILLEGAL_ADDRESS) {
-		return status;
+		return (status);
 	}
 
 	/*
@@ -317,12 +317,12 @@
 			status =
 			    acpi_os_write_port(address, (value >> i) & 0xFF, 8);
 			if (ACPI_FAILURE(status)) {
-				return status;
+				return (status);
 			}
 		}
 
 		address++;
 	}
 
-	return AE_OK;
+	return (AE_OK);
 }
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 05a154c..04c2e16 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -80,10 +80,10 @@
 
 	if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
 		/*
-		 * For I/O space, write directly to the OSL. This
-		 * bypasses the port validation mechanism, which may
-		 * block a valid write to the reset register. Spec
-		 * section 4.7.3.6 requires register width to be 8.
+		 * For I/O space, write directly to the OSL. This bypasses the port
+		 * validation mechanism, which may block a valid write to the reset
+		 * register.
+		 * Spec section 4.7.3.6 requires register width to be 8.
 		 */
 		status =
 		    acpi_os_write_port((acpi_io_address) reset_reg->address,
@@ -333,7 +333,7 @@
  * FUNCTION:    acpi_write_bit_register
  *
  * PARAMETERS:  register_id     - ID of ACPI Bit Register to access
- *              Value           - Value to write to the register, in bit
+ *              value           - Value to write to the register, in bit
  *                                position zero. The bit is automatically
  *                                shifted to the correct position.
  *
@@ -440,17 +440,41 @@
  *              *sleep_type_a        - Where SLP_TYPa is returned
  *              *sleep_type_b        - Where SLP_TYPb is returned
  *
- * RETURN:      status - ACPI status
+ * RETURN:      Status
  *
- * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
- *              state.
+ * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested
+ *              sleep state via the appropriate \_Sx object.
+ *
+ *  The sleep state package returned from the corresponding \_Sx_ object
+ *  must contain at least one integer.
+ *
+ *  March 2005:
+ *  Added support for a package that contains two integers. This
+ *  goes against the ACPI specification which defines this object as a
+ *  package with one encoded DWORD integer. However, existing practice
+ *  by many BIOS vendors is to return a package with 2 or more integer
+ *  elements, at least one per sleep type (A/B).
+ *
+ *  January 2013:
+ *  Therefore, we must be prepared to accept a package with either a
+ *  single integer or multiple integers.
+ *
+ *  The single integer DWORD format is as follows:
+ *      BYTE 0 - Value for the PM1A SLP_TYP register
+ *      BYTE 1 - Value for the PM1B SLP_TYP register
+ *      BYTE 2-3 - Reserved
+ *
+ *  The dual integer format is as follows:
+ *      Integer 0 - Value for the PM1A SLP_TYP register
+ *      Integer 1 - Value for the PM1A SLP_TYP register
  *
  ******************************************************************************/
 acpi_status
 acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
 {
-	acpi_status status = AE_OK;
+	acpi_status status;
 	struct acpi_evaluate_info *info;
+	union acpi_operand_object **elements;
 
 	ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data);
 
@@ -467,18 +491,14 @@
 		return_ACPI_STATUS(AE_NO_MEMORY);
 	}
 
+	/*
+	 * Evaluate the \_Sx namespace object containing the register values
+	 * for this state
+	 */
 	info->pathname =
 	    ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
-
-	/* Evaluate the namespace object containing the values for this state */
-
 	status = acpi_ns_evaluate(info);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-				  "%s while evaluating SleepState [%s]\n",
-				  acpi_format_exception(status),
-				  info->pathname));
-
 		goto cleanup;
 	}
 
@@ -487,64 +507,67 @@
 	if (!info->return_object) {
 		ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
 			    info->pathname));
-		status = AE_NOT_EXIST;
+		status = AE_AML_NO_RETURN_VALUE;
+		goto cleanup;
 	}
 
-	/* It must be of type Package */
+	/* Return object must be of type Package */
 
-	else if (info->return_object->common.type != ACPI_TYPE_PACKAGE) {
+	if (info->return_object->common.type != ACPI_TYPE_PACKAGE) {
 		ACPI_ERROR((AE_INFO,
 			    "Sleep State return object is not a Package"));
 		status = AE_AML_OPERAND_TYPE;
+		goto cleanup1;
 	}
 
 	/*
-	 * The package must have at least two elements. NOTE (March 2005): This
-	 * goes against the current ACPI spec which defines this object as a
-	 * package with one encoded DWORD element. However, existing practice
-	 * by BIOS vendors seems to be to have 2 or more elements, at least
-	 * one per sleep type (A/B).
+	 * Any warnings about the package length or the object types have
+	 * already been issued by the predefined name module -- there is no
+	 * need to repeat them here.
 	 */
-	else if (info->return_object->package.count < 2) {
-		ACPI_ERROR((AE_INFO,
-			    "Sleep State return package does not have at least two elements"));
-		status = AE_AML_NO_OPERAND;
+	elements = info->return_object->package.elements;
+	switch (info->return_object->package.count) {
+	case 0:
+		status = AE_AML_PACKAGE_LIMIT;
+		break;
+
+	case 1:
+		if (elements[0]->common.type != ACPI_TYPE_INTEGER) {
+			status = AE_AML_OPERAND_TYPE;
+			break;
+		}
+
+		/* A valid _Sx_ package with one integer */
+
+		*sleep_type_a = (u8)elements[0]->integer.value;
+		*sleep_type_b = (u8)(elements[0]->integer.value >> 8);
+		break;
+
+	case 2:
+	default:
+		if ((elements[0]->common.type != ACPI_TYPE_INTEGER) ||
+		    (elements[1]->common.type != ACPI_TYPE_INTEGER)) {
+			status = AE_AML_OPERAND_TYPE;
+			break;
+		}
+
+		/* A valid _Sx_ package with two integers */
+
+		*sleep_type_a = (u8)elements[0]->integer.value;
+		*sleep_type_b = (u8)elements[1]->integer.value;
+		break;
 	}
 
-	/* The first two elements must both be of type Integer */
-
-	else if (((info->return_object->package.elements[0])->common.type
-		  != ACPI_TYPE_INTEGER) ||
-		 ((info->return_object->package.elements[1])->common.type
-		  != ACPI_TYPE_INTEGER)) {
-		ACPI_ERROR((AE_INFO,
-			    "Sleep State return package elements are not both Integers "
-			    "(%s, %s)",
-			    acpi_ut_get_object_type_name(info->return_object->
-							 package.elements[0]),
-			    acpi_ut_get_object_type_name(info->return_object->
-							 package.elements[1])));
-		status = AE_AML_OPERAND_TYPE;
-	} else {
-		/* Valid _Sx_ package size, type, and value */
-
-		*sleep_type_a = (u8)
-		    (info->return_object->package.elements[0])->integer.value;
-		*sleep_type_b = (u8)
-		    (info->return_object->package.elements[1])->integer.value;
-	}
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"While evaluating SleepState [%s], bad Sleep object %p type %s",
-				info->pathname, info->return_object,
-				acpi_ut_get_object_type_name(info->
-							     return_object)));
-	}
-
+      cleanup1:
 	acpi_ut_remove_reference(info->return_object);
 
       cleanup:
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"While evaluating Sleep State [%s]",
+				info->pathname));
+	}
+
 	ACPI_FREE(info);
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index ae443fe2..35eebda 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,9 +41,9 @@
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
+#include <linux/export.h>
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include <linux/module.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwxfsleep")
@@ -207,7 +207,7 @@
 				    (u32)acpi_gbl_FADT.s4_bios_request, 8);
 
 	do {
-		acpi_os_stall(1000);
+		acpi_os_stall(ACPI_USEC_PER_MSEC);
 		status =
 		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
 		if (ACPI_FAILURE(status)) {
@@ -350,7 +350,7 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
+ * DESCRIPTION: Enter a system sleep state
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
  ******************************************************************************/
@@ -382,8 +382,9 @@
  * RETURN:      Status
  *
  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
- *              sleep.
- *              Called with interrupts DISABLED.
+ *              sleep. Called with interrupts DISABLED.
+ *              We break wake/resume into 2 stages so that OSPM can handle
+ *              various OS-specific tasks between the two steps.
  *
  ******************************************************************************/
 acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index d70eaf3..8769cf8 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 15143c4..2437373 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 924b3c7..ce6e973 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <acpi/acpi.h>
 #include "accommon.h"
 #include "acnamesp.h"
+#include <acpi/acoutput.h>
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsdump")
@@ -77,8 +78,9 @@
 
 	ACPI_FUNCTION_NAME(ns_print_pathname);
 
-	if (!(acpi_dbg_level & ACPI_LV_NAMES)
-	    || !(acpi_dbg_layer & ACPI_NAMESPACE)) {
+	/* Check if debug output enabled */
+
+	if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_NAMES, ACPI_NAMESPACE)) {
 		return;
 	}
 
@@ -127,7 +129,7 @@
 
 	/* Do this only if the requested debug level and component are enabled */
 
-	if (!(acpi_dbg_level & level) || !(acpi_dbg_layer & component)) {
+	if (!ACPI_IS_DEBUG_ENABLED(level, component)) {
 		return_VOID;
 	}
 
@@ -729,5 +731,5 @@
 			     ACPI_OWNER_ID_MAX, search_handle);
 	return_VOID;
 }
-#endif				/* _ACPI_ASL_COMPILER */
-#endif				/* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */
+#endif
+#endif
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 944d4c8..409ae80 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,6 @@
  */
 
 #include <acpi/acpi.h>
-#include "accommon.h"
 
 /* TBD: This entire module is apparently obsolete and should be removed */
 
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 69074be..1538f3e 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 4328e2a..2a431ec 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@
 #include "acnamesp.h"
 #include "acdispat.h"
 #include "acinterp.h"
-#include <linux/nmi.h>
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsinit")
@@ -87,7 +86,7 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
 			  "**** Starting initialization of namespace objects ****\n"));
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
-			      "Completing Region/Field/Buffer/Package initialization:"));
+			      "Completing Region/Field/Buffer/Package initialization:\n"));
 
 	/* Set all init info to zero */
 
@@ -103,7 +102,7 @@
 	}
 
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
-			      "\nInitialized %u/%u Regions %u/%u Fields %u/%u "
+			      "    Initialized %u/%u Regions %u/%u Fields %u/%u "
 			      "Buffers %u/%u Packages (%u nodes)\n",
 			      info.op_region_init, info.op_region_count,
 			      info.field_init, info.field_count,
@@ -150,7 +149,7 @@
 
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
 			      "Initializing Device/Processor/Thermal objects "
-			      "by executing _INI methods:"));
+			      "and executing _INI/_STA methods:\n"));
 
 	/* Tree analysis: find all subtrees that contain _INI methods */
 
@@ -208,7 +207,7 @@
 	}
 
 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
-			      "\nExecuted %u _INI methods requiring %u _STA executions "
+			      "    Executed %u _INI methods requiring %u _STA executions "
 			      "(examined %u objects)\n",
 			      info.num_INI, info.num_STA, info.device_count));
 
@@ -350,14 +349,6 @@
 	}
 
 	/*
-	 * Print a dot for each object unless we are going to print the entire
-	 * pathname
-	 */
-	if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
-		ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
-	}
-
-	/*
 	 * We ignore errors from above, and always return OK, since we don't want
 	 * to abort the walk on any single error.
 	 */
@@ -572,20 +563,10 @@
 	info->parameters = NULL;
 	info->flags = ACPI_IGNORE_RETURN_VALUE;
 
-	/*
-	 * Some hardware relies on this being executed as atomically
-	 * as possible (without an NMI being received in the middle of
-	 * this) - so disable NMIs and initialize the device:
-	 */
 	status = acpi_ns_evaluate(info);
 
 	if (ACPI_SUCCESS(status)) {
 		walk_info->num_INI++;
-
-		if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
-		    (!(acpi_dbg_level & ACPI_LV_INFO))) {
-			ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
-		}
 	}
 #ifdef ACPI_DEBUG_OUTPUT
 	else if (status != AE_NOT_FOUND) {
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index 911f991..0a7badc 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 55a175e..90a0380 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,8 @@
  *              the node, In external format (name segments separated by path
  *              separators.)
  *
- * DESCRIPTION: Used for debug printing in acpi_ns_search_table().
+ * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually
+ *              for error and debug statements.
  *
  ******************************************************************************/
 
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index e69f7fa..7a736f4 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 233f756..35dde81 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 2419f41..224c300 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -1,12 +1,11 @@
 /******************************************************************************
  *
  * Module Name: nspredef - Validation of ACPI predefined methods and objects
- *              $Revision: 1.1 $
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,27 +73,6 @@
  ******************************************************************************/
 /* Local prototypes */
 static acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
-		      union acpi_operand_object **return_object_ptr);
-
-static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
-			   const union acpi_predefined_info *package,
-			   union acpi_operand_object **elements, u32 count);
-
-static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
-			       union acpi_operand_object **elements,
-			       u8 type1,
-			       u32 count1,
-			       u8 type2, u32 count2, u32 start_index);
-
-static acpi_status
-acpi_ns_check_object_type(struct acpi_predefined_data *data,
-			  union acpi_operand_object **return_object_ptr,
-			  u32 expected_btypes, u32 package_index);
-
-static acpi_status
 acpi_ns_check_reference(struct acpi_predefined_data *data,
 			union acpi_operand_object *return_object);
 
@@ -148,7 +126,7 @@
 
 	pathname = acpi_ns_get_external_pathname(node);
 	if (!pathname) {
-		return AE_OK;	/* Could not get pathname, ignore */
+		return (AE_OK);	/* Could not get pathname, ignore */
 	}
 
 	/*
@@ -408,564 +386,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ns_check_package
- *
- * PARAMETERS:  data            - Pointer to validation data structure
- *              return_object_ptr - Pointer to the object returned from the
- *                                evaluation of a method or object
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Check a returned package object for the correct count and
- *              correct type of all sub-objects.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
-		      union acpi_operand_object **return_object_ptr)
-{
-	union acpi_operand_object *return_object = *return_object_ptr;
-	const union acpi_predefined_info *package;
-	union acpi_operand_object **elements;
-	acpi_status status = AE_OK;
-	u32 expected_count;
-	u32 count;
-	u32 i;
-
-	ACPI_FUNCTION_NAME(ns_check_package);
-
-	/* The package info for this name is in the next table entry */
-
-	package = data->predefined + 1;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
-			  "%s Validating return Package of Type %X, Count %X\n",
-			  data->pathname, package->ret_info.type,
-			  return_object->package.count));
-
-	/*
-	 * For variable-length Packages, we can safely remove all embedded
-	 * and trailing NULL package elements
-	 */
-	acpi_ns_remove_null_elements(data, package->ret_info.type,
-				     return_object);
-
-	/* Extract package count and elements array */
-
-	elements = return_object->package.elements;
-	count = return_object->package.count;
-
-	/* The package must have at least one element, else invalid */
-
-	if (!count) {
-		ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
-				      "Return Package has no elements (empty)"));
-
-		return (AE_AML_OPERAND_VALUE);
-	}
-
-	/*
-	 * Decode the type of the expected package contents
-	 *
-	 * PTYPE1 packages contain no subpackages
-	 * PTYPE2 packages contain sub-packages
-	 */
-	switch (package->ret_info.type) {
-	case ACPI_PTYPE1_FIXED:
-
-		/*
-		 * The package count is fixed and there are no sub-packages
-		 *
-		 * If package is too small, exit.
-		 * If package is larger than expected, issue warning but continue
-		 */
-		expected_count =
-		    package->ret_info.count1 + package->ret_info.count2;
-		if (count < expected_count) {
-			goto package_too_small;
-		} else if (count > expected_count) {
-			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
-					  "%s: Return Package is larger than needed - "
-					  "found %u, expected %u\n",
-					  data->pathname, count,
-					  expected_count));
-		}
-
-		/* Validate all elements of the returned package */
-
-		status = acpi_ns_check_package_elements(data, elements,
-							package->ret_info.
-							object_type1,
-							package->ret_info.
-							count1,
-							package->ret_info.
-							object_type2,
-							package->ret_info.
-							count2, 0);
-		break;
-
-	case ACPI_PTYPE1_VAR:
-
-		/*
-		 * The package count is variable, there are no sub-packages, and all
-		 * elements must be of the same type
-		 */
-		for (i = 0; i < count; i++) {
-			status = acpi_ns_check_object_type(data, elements,
-							   package->ret_info.
-							   object_type1, i);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-			elements++;
-		}
-		break;
-
-	case ACPI_PTYPE1_OPTION:
-
-		/*
-		 * The package count is variable, there are no sub-packages. There are
-		 * a fixed number of required elements, and a variable number of
-		 * optional elements.
-		 *
-		 * Check if package is at least as large as the minimum required
-		 */
-		expected_count = package->ret_info3.count;
-		if (count < expected_count) {
-			goto package_too_small;
-		}
-
-		/* Variable number of sub-objects */
-
-		for (i = 0; i < count; i++) {
-			if (i < package->ret_info3.count) {
-
-				/* These are the required package elements (0, 1, or 2) */
-
-				status =
-				    acpi_ns_check_object_type(data, elements,
-							      package->
-							      ret_info3.
-							      object_type[i],
-							      i);
-				if (ACPI_FAILURE(status)) {
-					return (status);
-				}
-			} else {
-				/* These are the optional package elements */
-
-				status =
-				    acpi_ns_check_object_type(data, elements,
-							      package->
-							      ret_info3.
-							      tail_object_type,
-							      i);
-				if (ACPI_FAILURE(status)) {
-					return (status);
-				}
-			}
-			elements++;
-		}
-		break;
-
-	case ACPI_PTYPE2_REV_FIXED:
-
-		/* First element is the (Integer) revision */
-
-		status = acpi_ns_check_object_type(data, elements,
-						   ACPI_RTYPE_INTEGER, 0);
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-
-		elements++;
-		count--;
-
-		/* Examine the sub-packages */
-
-		status =
-		    acpi_ns_check_package_list(data, package, elements, count);
-		break;
-
-	case ACPI_PTYPE2_PKG_COUNT:
-
-		/* First element is the (Integer) count of sub-packages to follow */
-
-		status = acpi_ns_check_object_type(data, elements,
-						   ACPI_RTYPE_INTEGER, 0);
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-
-		/*
-		 * Count cannot be larger than the parent package length, but allow it
-		 * to be smaller. The >= accounts for the Integer above.
-		 */
-		expected_count = (u32) (*elements)->integer.value;
-		if (expected_count >= count) {
-			goto package_too_small;
-		}
-
-		count = expected_count;
-		elements++;
-
-		/* Examine the sub-packages */
-
-		status =
-		    acpi_ns_check_package_list(data, package, elements, count);
-		break;
-
-	case ACPI_PTYPE2:
-	case ACPI_PTYPE2_FIXED:
-	case ACPI_PTYPE2_MIN:
-	case ACPI_PTYPE2_COUNT:
-	case ACPI_PTYPE2_FIX_VAR:
-
-		/*
-		 * These types all return a single Package that consists of a
-		 * variable number of sub-Packages.
-		 *
-		 * First, ensure that the first element is a sub-Package. If not,
-		 * the BIOS may have incorrectly returned the object as a single
-		 * package instead of a Package of Packages (a common error if
-		 * there is only one entry). We may be able to repair this by
-		 * wrapping the returned Package with a new outer Package.
-		 */
-		if (*elements
-		    && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) {
-
-			/* Create the new outer package and populate it */
-
-			status =
-			    acpi_ns_wrap_with_package(data, return_object,
-						      return_object_ptr);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-
-			/* Update locals to point to the new package (of 1 element) */
-
-			return_object = *return_object_ptr;
-			elements = return_object->package.elements;
-			count = 1;
-		}
-
-		/* Examine the sub-packages */
-
-		status =
-		    acpi_ns_check_package_list(data, package, elements, count);
-		break;
-
-	default:
-
-		/* Should not get here if predefined info table is correct */
-
-		ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
-				      "Invalid internal return type in table entry: %X",
-				      package->ret_info.type));
-
-		return (AE_AML_INTERNAL);
-	}
-
-	return (status);
-
-package_too_small:
-
-	/* Error exit for the case with an incorrect package count */
-
-	ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
-			      "Return Package is too small - found %u elements, expected %u",
-			      count, expected_count));
-
-	return (AE_AML_OPERAND_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_check_package_list
- *
- * PARAMETERS:  data            - Pointer to validation data structure
- *              package         - Pointer to package-specific info for method
- *              elements        - Element list of parent package. All elements
- *                                of this list should be of type Package.
- *              count           - Count of subpackages
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Examine a list of subpackages
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
-			   const union acpi_predefined_info *package,
-			   union acpi_operand_object **elements, u32 count)
-{
-	union acpi_operand_object *sub_package;
-	union acpi_operand_object **sub_elements;
-	acpi_status status;
-	u32 expected_count;
-	u32 i;
-	u32 j;
-
-	/*
-	 * Validate each sub-Package in the parent Package
-	 *
-	 * NOTE: assumes list of sub-packages contains no NULL elements.
-	 * Any NULL elements should have been removed by earlier call
-	 * to acpi_ns_remove_null_elements.
-	 */
-	for (i = 0; i < count; i++) {
-		sub_package = *elements;
-		sub_elements = sub_package->package.elements;
-		data->parent_package = sub_package;
-
-		/* Each sub-object must be of type Package */
-
-		status = acpi_ns_check_object_type(data, &sub_package,
-						   ACPI_RTYPE_PACKAGE, i);
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-
-		/* Examine the different types of expected sub-packages */
-
-		data->parent_package = sub_package;
-		switch (package->ret_info.type) {
-		case ACPI_PTYPE2:
-		case ACPI_PTYPE2_PKG_COUNT:
-		case ACPI_PTYPE2_REV_FIXED:
-
-			/* Each subpackage has a fixed number of elements */
-
-			expected_count =
-			    package->ret_info.count1 + package->ret_info.count2;
-			if (sub_package->package.count < expected_count) {
-				goto package_too_small;
-			}
-
-			status =
-			    acpi_ns_check_package_elements(data, sub_elements,
-							   package->ret_info.
-							   object_type1,
-							   package->ret_info.
-							   count1,
-							   package->ret_info.
-							   object_type2,
-							   package->ret_info.
-							   count2, 0);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-			break;
-
-		case ACPI_PTYPE2_FIX_VAR:
-			/*
-			 * Each subpackage has a fixed number of elements and an
-			 * optional element
-			 */
-			expected_count =
-			    package->ret_info.count1 + package->ret_info.count2;
-			if (sub_package->package.count < expected_count) {
-				goto package_too_small;
-			}
-
-			status =
-			    acpi_ns_check_package_elements(data, sub_elements,
-							   package->ret_info.
-							   object_type1,
-							   package->ret_info.
-							   count1,
-							   package->ret_info.
-							   object_type2,
-							   sub_package->package.
-							   count -
-							   package->ret_info.
-							   count1, 0);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-			break;
-
-		case ACPI_PTYPE2_FIXED:
-
-			/* Each sub-package has a fixed length */
-
-			expected_count = package->ret_info2.count;
-			if (sub_package->package.count < expected_count) {
-				goto package_too_small;
-			}
-
-			/* Check the type of each sub-package element */
-
-			for (j = 0; j < expected_count; j++) {
-				status =
-				    acpi_ns_check_object_type(data,
-							      &sub_elements[j],
-							      package->
-							      ret_info2.
-							      object_type[j],
-							      j);
-				if (ACPI_FAILURE(status)) {
-					return (status);
-				}
-			}
-			break;
-
-		case ACPI_PTYPE2_MIN:
-
-			/* Each sub-package has a variable but minimum length */
-
-			expected_count = package->ret_info.count1;
-			if (sub_package->package.count < expected_count) {
-				goto package_too_small;
-			}
-
-			/* Check the type of each sub-package element */
-
-			status =
-			    acpi_ns_check_package_elements(data, sub_elements,
-							   package->ret_info.
-							   object_type1,
-							   sub_package->package.
-							   count, 0, 0, 0);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-			break;
-
-		case ACPI_PTYPE2_COUNT:
-
-			/*
-			 * First element is the (Integer) count of elements, including
-			 * the count field (the ACPI name is num_elements)
-			 */
-			status = acpi_ns_check_object_type(data, sub_elements,
-							   ACPI_RTYPE_INTEGER,
-							   0);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-
-			/*
-			 * Make sure package is large enough for the Count and is
-			 * is as large as the minimum size
-			 */
-			expected_count = (u32)(*sub_elements)->integer.value;
-			if (sub_package->package.count < expected_count) {
-				goto package_too_small;
-			}
-			if (sub_package->package.count <
-			    package->ret_info.count1) {
-				expected_count = package->ret_info.count1;
-				goto package_too_small;
-			}
-			if (expected_count == 0) {
-				/*
-				 * Either the num_entries element was originally zero or it was
-				 * a NULL element and repaired to an Integer of value zero.
-				 * In either case, repair it by setting num_entries to be the
-				 * actual size of the subpackage.
-				 */
-				expected_count = sub_package->package.count;
-				(*sub_elements)->integer.value = expected_count;
-			}
-
-			/* Check the type of each sub-package element */
-
-			status =
-			    acpi_ns_check_package_elements(data,
-							   (sub_elements + 1),
-							   package->ret_info.
-							   object_type1,
-							   (expected_count - 1),
-							   0, 0, 1);
-			if (ACPI_FAILURE(status)) {
-				return (status);
-			}
-			break;
-
-		default:	/* Should not get here, type was validated by caller */
-
-			return (AE_AML_INTERNAL);
-		}
-
-		elements++;
-	}
-
-	return (AE_OK);
-
-package_too_small:
-
-	/* The sub-package count was smaller than required */
-
-	ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
-			      "Return Sub-Package[%u] is too small - found %u elements, expected %u",
-			      i, sub_package->package.count, expected_count));
-
-	return (AE_AML_OPERAND_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_check_package_elements
- *
- * PARAMETERS:  data            - Pointer to validation data structure
- *              elements        - Pointer to the package elements array
- *              type1           - Object type for first group
- *              count1          - Count for first group
- *              type2           - Object type for second group
- *              count2          - Count for second group
- *              start_index     - Start of the first group of elements
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Check that all elements of a package are of the correct object
- *              type. Supports up to two groups of different object types.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
-			       union acpi_operand_object **elements,
-			       u8 type1,
-			       u32 count1,
-			       u8 type2, u32 count2, u32 start_index)
-{
-	union acpi_operand_object **this_element = elements;
-	acpi_status status;
-	u32 i;
-
-	/*
-	 * Up to two groups of package elements are supported by the data
-	 * structure. All elements in each group must be of the same type.
-	 * The second group can have a count of zero.
-	 */
-	for (i = 0; i < count1; i++) {
-		status = acpi_ns_check_object_type(data, this_element,
-						   type1, i + start_index);
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-		this_element++;
-	}
-
-	for (i = 0; i < count2; i++) {
-		status = acpi_ns_check_object_type(data, this_element,
-						   type2,
-						   (i + count1 + start_index));
-		if (ACPI_FAILURE(status)) {
-			return (status);
-		}
-		this_element++;
-	}
-
-	return (AE_OK);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ns_check_object_type
  *
  * PARAMETERS:  data            - Pointer to validation data structure
@@ -983,7 +403,7 @@
  *
  ******************************************************************************/
 
-static acpi_status
+acpi_status
 acpi_ns_check_object_type(struct acpi_predefined_data *data,
 			  union acpi_operand_object **return_object_ptr,
 			  u32 expected_btypes, u32 package_index)
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
new file mode 100644
index 0000000..a401554
--- /dev/null
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -0,0 +1,621 @@
+/******************************************************************************
+ *
+ * Module Name: nsprepkg - Validation of package objects for predefined names
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsprepkg")
+
+/* Local prototypes */
+static acpi_status
+acpi_ns_check_package_list(struct acpi_predefined_data *data,
+			   const union acpi_predefined_info *package,
+			   union acpi_operand_object **elements, u32 count);
+
+static acpi_status
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+			       union acpi_operand_object **elements,
+			       u8 type1,
+			       u32 count1,
+			       u8 type2, u32 count2, u32 start_index);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_check_package
+ *
+ * PARAMETERS:  data                - Pointer to validation data structure
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Check a returned package object for the correct count and
+ *              correct type of all sub-objects.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_check_package(struct acpi_predefined_data *data,
+		      union acpi_operand_object **return_object_ptr)
+{
+	union acpi_operand_object *return_object = *return_object_ptr;
+	const union acpi_predefined_info *package;
+	union acpi_operand_object **elements;
+	acpi_status status = AE_OK;
+	u32 expected_count;
+	u32 count;
+	u32 i;
+
+	ACPI_FUNCTION_NAME(ns_check_package);
+
+	/* The package info for this name is in the next table entry */
+
+	package = data->predefined + 1;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
+			  "%s Validating return Package of Type %X, Count %X\n",
+			  data->pathname, package->ret_info.type,
+			  return_object->package.count));
+
+	/*
+	 * For variable-length Packages, we can safely remove all embedded
+	 * and trailing NULL package elements
+	 */
+	acpi_ns_remove_null_elements(data, package->ret_info.type,
+				     return_object);
+
+	/* Extract package count and elements array */
+
+	elements = return_object->package.elements;
+	count = return_object->package.count;
+
+	/* The package must have at least one element, else invalid */
+
+	if (!count) {
+		ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+				      "Return Package has no elements (empty)"));
+
+		return (AE_AML_OPERAND_VALUE);
+	}
+
+	/*
+	 * Decode the type of the expected package contents
+	 *
+	 * PTYPE1 packages contain no subpackages
+	 * PTYPE2 packages contain sub-packages
+	 */
+	switch (package->ret_info.type) {
+	case ACPI_PTYPE1_FIXED:
+
+		/*
+		 * The package count is fixed and there are no sub-packages
+		 *
+		 * If package is too small, exit.
+		 * If package is larger than expected, issue warning but continue
+		 */
+		expected_count =
+		    package->ret_info.count1 + package->ret_info.count2;
+		if (count < expected_count) {
+			goto package_too_small;
+		} else if (count > expected_count) {
+			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+					  "%s: Return Package is larger than needed - "
+					  "found %u, expected %u\n",
+					  data->pathname, count,
+					  expected_count));
+		}
+
+		/* Validate all elements of the returned package */
+
+		status = acpi_ns_check_package_elements(data, elements,
+							package->ret_info.
+							object_type1,
+							package->ret_info.
+							count1,
+							package->ret_info.
+							object_type2,
+							package->ret_info.
+							count2, 0);
+		break;
+
+	case ACPI_PTYPE1_VAR:
+
+		/*
+		 * The package count is variable, there are no sub-packages, and all
+		 * elements must be of the same type
+		 */
+		for (i = 0; i < count; i++) {
+			status = acpi_ns_check_object_type(data, elements,
+							   package->ret_info.
+							   object_type1, i);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+			elements++;
+		}
+		break;
+
+	case ACPI_PTYPE1_OPTION:
+
+		/*
+		 * The package count is variable, there are no sub-packages. There are
+		 * a fixed number of required elements, and a variable number of
+		 * optional elements.
+		 *
+		 * Check if package is at least as large as the minimum required
+		 */
+		expected_count = package->ret_info3.count;
+		if (count < expected_count) {
+			goto package_too_small;
+		}
+
+		/* Variable number of sub-objects */
+
+		for (i = 0; i < count; i++) {
+			if (i < package->ret_info3.count) {
+
+				/* These are the required package elements (0, 1, or 2) */
+
+				status =
+				    acpi_ns_check_object_type(data, elements,
+							      package->
+							      ret_info3.
+							      object_type[i],
+							      i);
+				if (ACPI_FAILURE(status)) {
+					return (status);
+				}
+			} else {
+				/* These are the optional package elements */
+
+				status =
+				    acpi_ns_check_object_type(data, elements,
+							      package->
+							      ret_info3.
+							      tail_object_type,
+							      i);
+				if (ACPI_FAILURE(status)) {
+					return (status);
+				}
+			}
+			elements++;
+		}
+		break;
+
+	case ACPI_PTYPE2_REV_FIXED:
+
+		/* First element is the (Integer) revision */
+
+		status = acpi_ns_check_object_type(data, elements,
+						   ACPI_RTYPE_INTEGER, 0);
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+
+		elements++;
+		count--;
+
+		/* Examine the sub-packages */
+
+		status =
+		    acpi_ns_check_package_list(data, package, elements, count);
+		break;
+
+	case ACPI_PTYPE2_PKG_COUNT:
+
+		/* First element is the (Integer) count of sub-packages to follow */
+
+		status = acpi_ns_check_object_type(data, elements,
+						   ACPI_RTYPE_INTEGER, 0);
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+
+		/*
+		 * Count cannot be larger than the parent package length, but allow it
+		 * to be smaller. The >= accounts for the Integer above.
+		 */
+		expected_count = (u32)(*elements)->integer.value;
+		if (expected_count >= count) {
+			goto package_too_small;
+		}
+
+		count = expected_count;
+		elements++;
+
+		/* Examine the sub-packages */
+
+		status =
+		    acpi_ns_check_package_list(data, package, elements, count);
+		break;
+
+	case ACPI_PTYPE2:
+	case ACPI_PTYPE2_FIXED:
+	case ACPI_PTYPE2_MIN:
+	case ACPI_PTYPE2_COUNT:
+	case ACPI_PTYPE2_FIX_VAR:
+
+		/*
+		 * These types all return a single Package that consists of a
+		 * variable number of sub-Packages.
+		 *
+		 * First, ensure that the first element is a sub-Package. If not,
+		 * the BIOS may have incorrectly returned the object as a single
+		 * package instead of a Package of Packages (a common error if
+		 * there is only one entry). We may be able to repair this by
+		 * wrapping the returned Package with a new outer Package.
+		 */
+		if (*elements
+		    && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) {
+
+			/* Create the new outer package and populate it */
+
+			status =
+			    acpi_ns_wrap_with_package(data, return_object,
+						      return_object_ptr);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+
+			/* Update locals to point to the new package (of 1 element) */
+
+			return_object = *return_object_ptr;
+			elements = return_object->package.elements;
+			count = 1;
+		}
+
+		/* Examine the sub-packages */
+
+		status =
+		    acpi_ns_check_package_list(data, package, elements, count);
+		break;
+
+	default:
+
+		/* Should not get here if predefined info table is correct */
+
+		ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+				      "Invalid internal return type in table entry: %X",
+				      package->ret_info.type));
+
+		return (AE_AML_INTERNAL);
+	}
+
+	return (status);
+
+      package_too_small:
+
+	/* Error exit for the case with an incorrect package count */
+
+	ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+			      "Return Package is too small - found %u elements, expected %u",
+			      count, expected_count));
+
+	return (AE_AML_OPERAND_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_check_package_list
+ *
+ * PARAMETERS:  data            - Pointer to validation data structure
+ *              package         - Pointer to package-specific info for method
+ *              elements        - Element list of parent package. All elements
+ *                                of this list should be of type Package.
+ *              count           - Count of subpackages
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Examine a list of subpackages
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_package_list(struct acpi_predefined_data *data,
+			   const union acpi_predefined_info *package,
+			   union acpi_operand_object **elements, u32 count)
+{
+	union acpi_operand_object *sub_package;
+	union acpi_operand_object **sub_elements;
+	acpi_status status;
+	u32 expected_count;
+	u32 i;
+	u32 j;
+
+	/*
+	 * Validate each sub-Package in the parent Package
+	 *
+	 * NOTE: assumes list of sub-packages contains no NULL elements.
+	 * Any NULL elements should have been removed by earlier call
+	 * to acpi_ns_remove_null_elements.
+	 */
+	for (i = 0; i < count; i++) {
+		sub_package = *elements;
+		sub_elements = sub_package->package.elements;
+		data->parent_package = sub_package;
+
+		/* Each sub-object must be of type Package */
+
+		status = acpi_ns_check_object_type(data, &sub_package,
+						   ACPI_RTYPE_PACKAGE, i);
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+
+		/* Examine the different types of expected sub-packages */
+
+		data->parent_package = sub_package;
+		switch (package->ret_info.type) {
+		case ACPI_PTYPE2:
+		case ACPI_PTYPE2_PKG_COUNT:
+		case ACPI_PTYPE2_REV_FIXED:
+
+			/* Each subpackage has a fixed number of elements */
+
+			expected_count =
+			    package->ret_info.count1 + package->ret_info.count2;
+			if (sub_package->package.count < expected_count) {
+				goto package_too_small;
+			}
+
+			status =
+			    acpi_ns_check_package_elements(data, sub_elements,
+							   package->ret_info.
+							   object_type1,
+							   package->ret_info.
+							   count1,
+							   package->ret_info.
+							   object_type2,
+							   package->ret_info.
+							   count2, 0);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+			break;
+
+		case ACPI_PTYPE2_FIX_VAR:
+			/*
+			 * Each subpackage has a fixed number of elements and an
+			 * optional element
+			 */
+			expected_count =
+			    package->ret_info.count1 + package->ret_info.count2;
+			if (sub_package->package.count < expected_count) {
+				goto package_too_small;
+			}
+
+			status =
+			    acpi_ns_check_package_elements(data, sub_elements,
+							   package->ret_info.
+							   object_type1,
+							   package->ret_info.
+							   count1,
+							   package->ret_info.
+							   object_type2,
+							   sub_package->package.
+							   count -
+							   package->ret_info.
+							   count1, 0);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+			break;
+
+		case ACPI_PTYPE2_FIXED:
+
+			/* Each sub-package has a fixed length */
+
+			expected_count = package->ret_info2.count;
+			if (sub_package->package.count < expected_count) {
+				goto package_too_small;
+			}
+
+			/* Check the type of each sub-package element */
+
+			for (j = 0; j < expected_count; j++) {
+				status =
+				    acpi_ns_check_object_type(data,
+							      &sub_elements[j],
+							      package->
+							      ret_info2.
+							      object_type[j],
+							      j);
+				if (ACPI_FAILURE(status)) {
+					return (status);
+				}
+			}
+			break;
+
+		case ACPI_PTYPE2_MIN:
+
+			/* Each sub-package has a variable but minimum length */
+
+			expected_count = package->ret_info.count1;
+			if (sub_package->package.count < expected_count) {
+				goto package_too_small;
+			}
+
+			/* Check the type of each sub-package element */
+
+			status =
+			    acpi_ns_check_package_elements(data, sub_elements,
+							   package->ret_info.
+							   object_type1,
+							   sub_package->package.
+							   count, 0, 0, 0);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+			break;
+
+		case ACPI_PTYPE2_COUNT:
+
+			/*
+			 * First element is the (Integer) count of elements, including
+			 * the count field (the ACPI name is num_elements)
+			 */
+			status = acpi_ns_check_object_type(data, sub_elements,
+							   ACPI_RTYPE_INTEGER,
+							   0);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+
+			/*
+			 * Make sure package is large enough for the Count and is
+			 * is as large as the minimum size
+			 */
+			expected_count = (u32)(*sub_elements)->integer.value;
+			if (sub_package->package.count < expected_count) {
+				goto package_too_small;
+			}
+			if (sub_package->package.count <
+			    package->ret_info.count1) {
+				expected_count = package->ret_info.count1;
+				goto package_too_small;
+			}
+			if (expected_count == 0) {
+				/*
+				 * Either the num_entries element was originally zero or it was
+				 * a NULL element and repaired to an Integer of value zero.
+				 * In either case, repair it by setting num_entries to be the
+				 * actual size of the subpackage.
+				 */
+				expected_count = sub_package->package.count;
+				(*sub_elements)->integer.value = expected_count;
+			}
+
+			/* Check the type of each sub-package element */
+
+			status =
+			    acpi_ns_check_package_elements(data,
+							   (sub_elements + 1),
+							   package->ret_info.
+							   object_type1,
+							   (expected_count - 1),
+							   0, 0, 1);
+			if (ACPI_FAILURE(status)) {
+				return (status);
+			}
+			break;
+
+		default:	/* Should not get here, type was validated by caller */
+
+			return (AE_AML_INTERNAL);
+		}
+
+		elements++;
+	}
+
+	return (AE_OK);
+
+      package_too_small:
+
+	/* The sub-package count was smaller than required */
+
+	ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+			      "Return Sub-Package[%u] is too small - found %u elements, expected %u",
+			      i, sub_package->package.count, expected_count));
+
+	return (AE_AML_OPERAND_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_check_package_elements
+ *
+ * PARAMETERS:  data            - Pointer to validation data structure
+ *              elements        - Pointer to the package elements array
+ *              type1           - Object type for first group
+ *              count1          - Count for first group
+ *              type2           - Object type for second group
+ *              count2          - Count for second group
+ *              start_index     - Start of the first group of elements
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Check that all elements of a package are of the correct object
+ *              type. Supports up to two groups of different object types.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+			       union acpi_operand_object **elements,
+			       u8 type1,
+			       u32 count1,
+			       u8 type2, u32 count2, u32 start_index)
+{
+	union acpi_operand_object **this_element = elements;
+	acpi_status status;
+	u32 i;
+
+	/*
+	 * Up to two groups of package elements are supported by the data
+	 * structure. All elements in each group must be of the same type.
+	 * The second group can have a count of zero.
+	 */
+	for (i = 0; i < count1; i++) {
+		status = acpi_ns_check_object_type(data, this_element,
+						   type1, i + start_index);
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+		this_element++;
+	}
+
+	for (i = 0; i < count2; i++) {
+		status = acpi_ns_check_object_type(data, this_element,
+						   type2,
+						   (i + count1 + start_index));
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+		this_element++;
+	}
+
+	return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 8c5f292..9e83335 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 9018925..ba4d982 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,8 @@
  */
 typedef
 acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data,
-				    union acpi_operand_object **return_object_ptr);
+				    union acpi_operand_object
+				    **return_object_ptr);
 
 typedef struct acpi_repair_info {
 	char name[ACPI_NAME_SIZE];
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index 1d2d8ff..5d43efc 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -328,6 +328,11 @@
 		if ((status == AE_OK) && (flags & ACPI_NS_ERROR_IF_FOUND)) {
 			status = AE_ALREADY_EXISTS;
 		}
+#ifdef ACPI_ASL_COMPILER
+		if (*return_node && (*return_node)->type == ACPI_TYPE_ANY) {
+			(*return_node)->flags |= ANOBJ_IS_EXTERNAL;
+		}
+#endif
 
 		/* Either found it or there was an error: finished either way */
 
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index b5b4cb7..686420d 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,14 +46,11 @@
 #include "accommon.h"
 #include "acnamesp.h"
 #include "amlcode.h"
-#include "actables.h"
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsutils")
 
 /* Local prototypes */
-static u8 acpi_ns_valid_path_separator(char sep);
-
 #ifdef ACPI_OBSOLETE_FUNCTIONS
 acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
 #endif
@@ -99,42 +96,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ns_valid_root_prefix
- *
- * PARAMETERS:  prefix          - Character to be checked
- *
- * RETURN:      TRUE if a valid prefix
- *
- * DESCRIPTION: Check if a character is a valid ACPI Root prefix
- *
- ******************************************************************************/
-
-u8 acpi_ns_valid_root_prefix(char prefix)
-{
-
-	return ((u8) (prefix == '\\'));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_valid_path_separator
- *
- * PARAMETERS:  sep         - Character to be checked
- *
- * RETURN:      TRUE if a valid path separator
- *
- * DESCRIPTION: Check if a character is a valid ACPI path separator
- *
- ******************************************************************************/
-
-static u8 acpi_ns_valid_path_separator(char sep)
-{
-
-	return ((u8) (sep == '.'));
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ns_get_type
  *
  * PARAMETERS:  node        - Parent Node to be examined
@@ -151,10 +112,10 @@
 
 	if (!node) {
 		ACPI_WARNING((AE_INFO, "Null Node parameter"));
-		return_UINT32(ACPI_TYPE_ANY);
+		return_VALUE(ACPI_TYPE_ANY);
 	}
 
-	return_UINT32((acpi_object_type) node->type);
+	return_VALUE(node->type);
 }
 
 /*******************************************************************************
@@ -179,10 +140,10 @@
 		/* Type code out of range  */
 
 		ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
-		return_UINT32(ACPI_NS_NORMAL);
+		return_VALUE(ACPI_NS_NORMAL);
 	}
 
-	return_UINT32((u32) acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
+	return_VALUE(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
 }
 
 /*******************************************************************************
@@ -218,19 +179,19 @@
 	 *
 	 * strlen() + 1 covers the first name_seg, which has no path separator
 	 */
-	if (acpi_ns_valid_root_prefix(*next_external_char)) {
+	if (ACPI_IS_ROOT_PREFIX(*next_external_char)) {
 		info->fully_qualified = TRUE;
 		next_external_char++;
 
 		/* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */
 
-		while (acpi_ns_valid_root_prefix(*next_external_char)) {
+		while (ACPI_IS_ROOT_PREFIX(*next_external_char)) {
 			next_external_char++;
 		}
 	} else {
 		/* Handle Carat prefixes */
 
-		while (*next_external_char == '^') {
+		while (ACPI_IS_PARENT_PREFIX(*next_external_char)) {
 			info->num_carats++;
 			next_external_char++;
 		}
@@ -244,7 +205,7 @@
 	if (*next_external_char) {
 		info->num_segments = 1;
 		for (i = 0; next_external_char[i]; i++) {
-			if (acpi_ns_valid_path_separator(next_external_char[i])) {
+			if (ACPI_IS_PATH_SEPARATOR(next_external_char[i])) {
 				info->num_segments++;
 			}
 		}
@@ -282,7 +243,7 @@
 	/* Setup the correct prefixes, counts, and pointers */
 
 	if (info->fully_qualified) {
-		internal_name[0] = '\\';
+		internal_name[0] = AML_ROOT_PREFIX;
 
 		if (num_segments <= 1) {
 			result = &internal_name[1];
@@ -302,7 +263,7 @@
 		i = 0;
 		if (info->num_carats) {
 			for (i = 0; i < info->num_carats; i++) {
-				internal_name[i] = '^';
+				internal_name[i] = AML_PARENT_PREFIX;
 			}
 		}
 
@@ -322,7 +283,7 @@
 
 	for (; num_segments; num_segments--) {
 		for (i = 0; i < ACPI_NAME_SIZE; i++) {
-			if (acpi_ns_valid_path_separator(*external_name) ||
+			if (ACPI_IS_PATH_SEPARATOR(*external_name) ||
 			    (*external_name == 0)) {
 
 				/* Pad the segment with underscore(s) if segment is short */
@@ -339,7 +300,7 @@
 
 		/* Now we must have a path separator, or the pathname is bad */
 
-		if (!acpi_ns_valid_path_separator(*external_name) &&
+		if (!ACPI_IS_PATH_SEPARATOR(*external_name) &&
 		    (*external_name != 0)) {
 			return_ACPI_STATUS(AE_BAD_PATHNAME);
 		}
@@ -457,13 +418,13 @@
 	/* Check for a prefix (one '\' | one or more '^') */
 
 	switch (internal_name[0]) {
-	case '\\':
+	case AML_ROOT_PREFIX:
 		prefix_length = 1;
 		break;
 
-	case '^':
+	case AML_PARENT_PREFIX:
 		for (i = 0; i < internal_name_length; i++) {
-			if (internal_name[i] == '^') {
+			if (ACPI_IS_PARENT_PREFIX(internal_name[i])) {
 				prefix_length = i + 1;
 			} else {
 				break;
@@ -664,17 +625,17 @@
 
 u32 acpi_ns_opens_scope(acpi_object_type type)
 {
-	ACPI_FUNCTION_TRACE_STR(ns_opens_scope, acpi_ut_get_type_name(type));
+	ACPI_FUNCTION_ENTRY();
 
-	if (!acpi_ut_valid_object_type(type)) {
+	if (type > ACPI_TYPE_LOCAL_MAX) {
 
 		/* type code out of range  */
 
 		ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
-		return_UINT32(ACPI_NS_NORMAL);
+		return (ACPI_NS_NORMAL);
 	}
 
-	return_UINT32(((u32) acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);
+	return (((u32)acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);
 }
 
 /*******************************************************************************
@@ -710,6 +671,8 @@
 
 	ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname));
 
+	/* Simplest case is a null pathname */
+
 	if (!pathname) {
 		*return_node = prefix_node;
 		if (!prefix_node) {
@@ -718,6 +681,13 @@
 		return_ACPI_STATUS(AE_OK);
 	}
 
+	/* Quick check for a reference to the root */
+
+	if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) {
+		*return_node = acpi_gbl_root_node;
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Convert path to internal representation */
 
 	status = acpi_ns_internalize_name(pathname, &internal_path);
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 0483877..e70911a 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,12 +76,12 @@
 
 		/* It's really the parent's _scope_ that we want */
 
-		return parent_node->child;
+		return (parent_node->child);
 	}
 
 	/* Otherwise just return the next peer */
 
-	return child_node->peer;
+	return (child_node->peer);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index d6a9f77..fc69949 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -236,7 +236,7 @@
 	 * 2) No handle, not fully qualified pathname (error)
 	 * 3) Valid handle
 	 */
-	if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) {
+	if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) {
 
 		/* The path is fully qualified, just evaluate by name */
 
@@ -492,7 +492,7 @@
 	 */
 	status = acpi_ut_acquire_read_lock(&acpi_gbl_namespace_rw_lock);
 	if (ACPI_FAILURE(status)) {
-		return status;
+		return_ACPI_STATUS(status);
 	}
 
 	/*
@@ -550,7 +550,7 @@
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
+		return (status);
 	}
 
 	node = acpi_ns_validate_handle(obj_handle);
@@ -602,17 +602,22 @@
 
 			/* Walk the CID list */
 
-			found = 0;
+			found = FALSE;
 			for (i = 0; i < cid->count; i++) {
 				if (ACPI_STRCMP(cid->ids[i].string, info->hid)
 				    == 0) {
-					found = 1;
+
+					/* Found a matching CID */
+
+					found = TRUE;
 					break;
 				}
 			}
+
 			ACPI_FREE(cid);
-			if (!found)
+			if (!found) {
 				return (AE_OK);
+			}
 		}
 	}
 
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 811c6f1..f3a4d95 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -107,7 +107,7 @@
 	 *
 	 * Error for <null Parent + relative path>
 	 */
-	if (acpi_ns_valid_root_prefix(pathname[0])) {
+	if (ACPI_IS_ROOT_PREFIX(pathname[0])) {
 
 		/* Pathname is fully qualified (starts with '\') */
 
@@ -290,7 +290,7 @@
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE(status)) {
-		goto cleanup;
+		return (status);
 	}
 
 	node = acpi_ns_validate_handle(handle);
@@ -539,14 +539,14 @@
 	/* Parameter validation */
 
 	if (!buffer) {
-		return AE_BAD_PARAMETER;
+		return (AE_BAD_PARAMETER);
 	}
 
 	/* Table must be a DSDT or SSDT */
 
 	if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) &&
 	    !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
-		return AE_BAD_HEADER;
+		return (AE_BAD_HEADER);
 	}
 
 	/* First AML opcode in the table must be a control method */
@@ -554,7 +554,7 @@
 	parser_state.aml = buffer + sizeof(struct acpi_table_header);
 	opcode = acpi_ps_peek_opcode(&parser_state);
 	if (opcode != AML_METHOD_OP) {
-		return AE_BAD_PARAMETER;
+		return (AE_BAD_PARAMETER);
 	}
 
 	/* Extract method information from the raw AML */
@@ -572,13 +572,13 @@
 	 */
 	aml_buffer = ACPI_ALLOCATE(aml_length);
 	if (!aml_buffer) {
-		return AE_NO_MEMORY;
+		return (AE_NO_MEMORY);
 	}
 
 	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
 	if (!method_obj) {
 		ACPI_FREE(aml_buffer);
-		return AE_NO_MEMORY;
+		return (AE_NO_MEMORY);
 	}
 
 	/* Lock namespace for acpi_ns_lookup, we may be creating a new node */
@@ -644,12 +644,12 @@
 	/* Remove local reference to the method object */
 
 	acpi_ut_remove_reference(method_obj);
-	return status;
+	return (status);
 
 error_exit:
 
 	ACPI_FREE(aml_buffer);
 	ACPI_FREE(method_obj);
-	return status;
+	return (status);
 }
 ACPI_EXPORT_SYMBOL(acpi_install_method)
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index 9d029da..c0853ef 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index cb79e2d..f51308c 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,7 +108,7 @@
 	/* Byte 0 is a special case, either bits [0:3] or [0:5] are used */
 
 	package_length |= (aml[0] & byte_zero_mask);
-	return_UINT32(package_length);
+	return_VALUE(package_length);
 }
 
 /*******************************************************************************
@@ -162,7 +162,7 @@
 
 	/* Point past any namestring prefix characters (backslash or carat) */
 
-	while (acpi_ps_is_prefix_char(*end)) {
+	while (ACPI_IS_ROOT_PREFIX(*end) || ACPI_IS_PARENT_PREFIX(*end)) {
 		end++;
 	}
 
@@ -798,7 +798,8 @@
 		subop = acpi_ps_peek_opcode(parser_state);
 		if (subop == 0 ||
 		    acpi_ps_is_leading_char(subop) ||
-		    acpi_ps_is_prefix_char(subop)) {
+		    ACPI_IS_ROOT_PREFIX(subop) ||
+		    ACPI_IS_PARENT_PREFIX(subop)) {
 
 			/* null_name or name_string */
 
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 5607805..63c4554 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,352 +58,17 @@
 #define _COMPONENT          ACPI_PARSER
 ACPI_MODULE_NAME("psloop")
 
-static u32 acpi_gbl_depth = 0;
-
 /* Local prototypes */
-
-static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
-
-static acpi_status
-acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
-		       u8 * aml_op_start,
-		       union acpi_parse_object *unnamed_op,
-		       union acpi_parse_object **op);
-
-static acpi_status
-acpi_ps_create_op(struct acpi_walk_state *walk_state,
-		  u8 * aml_op_start, union acpi_parse_object **new_op);
-
 static acpi_status
 acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
 		      u8 * aml_op_start, union acpi_parse_object *op);
 
-static acpi_status
-acpi_ps_complete_op(struct acpi_walk_state *walk_state,
-		    union acpi_parse_object **op, acpi_status status);
-
-static acpi_status
-acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
-			  union acpi_parse_object *op, acpi_status status);
-
 static void
 acpi_ps_link_module_code(union acpi_parse_object *parent_op,
 			 u8 *aml_start, u32 aml_length, acpi_owner_id owner_id);
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ps_get_aml_opcode
- *
- * PARAMETERS:  walk_state          - Current state
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Extract the next AML opcode from the input stream.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
-{
-
-	ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
-
-	walk_state->aml_offset =
-	    (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
-				walk_state->parser_state.aml_start);
-	walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
-
-	/*
-	 * First cut to determine what we have found:
-	 * 1) A valid AML opcode
-	 * 2) A name string
-	 * 3) An unknown/invalid opcode
-	 */
-	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
-
-	switch (walk_state->op_info->class) {
-	case AML_CLASS_ASCII:
-	case AML_CLASS_PREFIX:
-		/*
-		 * Starts with a valid prefix or ASCII char, this is a name
-		 * string. Convert the bare name string to a namepath.
-		 */
-		walk_state->opcode = AML_INT_NAMEPATH_OP;
-		walk_state->arg_types = ARGP_NAMESTRING;
-		break;
-
-	case AML_CLASS_UNKNOWN:
-
-		/* The opcode is unrecognized. Complain and skip unknown opcodes */
-
-		if (walk_state->pass_number == 2) {
-			ACPI_ERROR((AE_INFO,
-				    "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring",
-				    walk_state->opcode,
-				    (u32)(walk_state->aml_offset +
-					  sizeof(struct acpi_table_header))));
-
-			ACPI_DUMP_BUFFER(walk_state->parser_state.aml - 16, 48);
-
-#ifdef ACPI_ASL_COMPILER
-			/*
-			 * This is executed for the disassembler only. Output goes
-			 * to the disassembled ASL output file.
-			 */
-			acpi_os_printf
-			    ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n",
-			     walk_state->opcode,
-			     (u32)(walk_state->aml_offset +
-				   sizeof(struct acpi_table_header)));
-
-			/* Dump the context surrounding the invalid opcode */
-
-			acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
-					     aml - 16), 48, DB_BYTE_DISPLAY,
-					    walk_state->aml_offset +
-					    sizeof(struct acpi_table_header) -
-					    16);
-			acpi_os_printf(" */\n");
-#endif
-		}
-
-		/* Increment past one-byte or two-byte opcode */
-
-		walk_state->parser_state.aml++;
-		if (walk_state->opcode > 0xFF) {	/* Can only happen if first byte is 0x5B */
-			walk_state->parser_state.aml++;
-		}
-
-		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
-
-	default:
-
-		/* Found opcode info, this is a normal opcode */
-
-		walk_state->parser_state.aml +=
-		    acpi_ps_get_opcode_size(walk_state->opcode);
-		walk_state->arg_types = walk_state->op_info->parse_args;
-		break;
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_build_named_op
- *
- * PARAMETERS:  walk_state          - Current state
- *              aml_op_start        - Begin of named Op in AML
- *              unnamed_op          - Early Op (not a named Op)
- *              op                  - Returned Op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Parse a named Op
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
-		       u8 * aml_op_start,
-		       union acpi_parse_object *unnamed_op,
-		       union acpi_parse_object **op)
-{
-	acpi_status status = AE_OK;
-	union acpi_parse_object *arg = NULL;
-
-	ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
-
-	unnamed_op->common.value.arg = NULL;
-	unnamed_op->common.arg_list_length = 0;
-	unnamed_op->common.aml_opcode = walk_state->opcode;
-
-	/*
-	 * Get and append arguments until we find the node that contains
-	 * the name (the type ARGP_NAME).
-	 */
-	while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
-	       (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
-		status =
-		    acpi_ps_get_next_arg(walk_state,
-					 &(walk_state->parser_state),
-					 GET_CURRENT_ARG_TYPE(walk_state->
-							      arg_types), &arg);
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-
-		acpi_ps_append_arg(unnamed_op, arg);
-		INCREMENT_ARG_LIST(walk_state->arg_types);
-	}
-
-	/*
-	 * Make sure that we found a NAME and didn't run out of arguments
-	 */
-	if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
-		return_ACPI_STATUS(AE_AML_NO_OPERAND);
-	}
-
-	/* We know that this arg is a name, move to next arg */
-
-	INCREMENT_ARG_LIST(walk_state->arg_types);
-
-	/*
-	 * Find the object. This will either insert the object into
-	 * the namespace or simply look it up
-	 */
-	walk_state->op = NULL;
-
-	status = walk_state->descending_callback(walk_state, op);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
-		return_ACPI_STATUS(status);
-	}
-
-	if (!*op) {
-		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
-	}
-
-	status = acpi_ps_next_parse_state(walk_state, *op, status);
-	if (ACPI_FAILURE(status)) {
-		if (status == AE_CTRL_PENDING) {
-			return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
-		}
-		return_ACPI_STATUS(status);
-	}
-
-	acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
-	acpi_gbl_depth++;
-
-	if ((*op)->common.aml_opcode == AML_REGION_OP ||
-	    (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
-		/*
-		 * Defer final parsing of an operation_region body, because we don't
-		 * have enough info in the first pass to parse it correctly (i.e.,
-		 * there may be method calls within the term_arg elements of the body.)
-		 *
-		 * However, we must continue parsing because the opregion is not a
-		 * standalone package -- we don't know where the end is at this point.
-		 *
-		 * (Length is unknown until parse of the body complete)
-		 */
-		(*op)->named.data = aml_op_start;
-		(*op)->named.length = 0;
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_create_op
- *
- * PARAMETERS:  walk_state          - Current state
- *              aml_op_start        - Op start in AML
- *              new_op              - Returned Op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get Op from AML
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_create_op(struct acpi_walk_state *walk_state,
-		  u8 * aml_op_start, union acpi_parse_object **new_op)
-{
-	acpi_status status = AE_OK;
-	union acpi_parse_object *op;
-	union acpi_parse_object *named_op = NULL;
-	union acpi_parse_object *parent_scope;
-	u8 argument_count;
-	const struct acpi_opcode_info *op_info;
-
-	ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
-
-	status = acpi_ps_get_aml_opcode(walk_state);
-	if (status == AE_CTRL_PARSE_CONTINUE) {
-		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
-	}
-
-	/* Create Op structure and append to parent's argument list */
-
-	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
-	op = acpi_ps_alloc_op(walk_state->opcode);
-	if (!op) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-
-	if (walk_state->op_info->flags & AML_NAMED) {
-		status =
-		    acpi_ps_build_named_op(walk_state, aml_op_start, op,
-					   &named_op);
-		acpi_ps_free_op(op);
-		if (ACPI_FAILURE(status)) {
-			return_ACPI_STATUS(status);
-		}
-
-		*new_op = named_op;
-		return_ACPI_STATUS(AE_OK);
-	}
-
-	/* Not a named opcode, just allocate Op and append to parent */
-
-	if (walk_state->op_info->flags & AML_CREATE) {
-		/*
-		 * Backup to beginning of create_XXXfield declaration
-		 * body_length is unknown until we parse the body
-		 */
-		op->named.data = aml_op_start;
-		op->named.length = 0;
-	}
-
-	if (walk_state->opcode == AML_BANK_FIELD_OP) {
-		/*
-		 * Backup to beginning of bank_field declaration
-		 * body_length is unknown until we parse the body
-		 */
-		op->named.data = aml_op_start;
-		op->named.length = 0;
-	}
-
-	parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
-	acpi_ps_append_arg(parent_scope, op);
-
-	if (parent_scope) {
-		op_info =
-		    acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
-		if (op_info->flags & AML_HAS_TARGET) {
-			argument_count =
-			    acpi_ps_get_argument_count(op_info->type);
-			if (parent_scope->common.arg_list_length >
-			    argument_count) {
-				op->common.flags |= ACPI_PARSEOP_TARGET;
-			}
-		} else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
-			op->common.flags |= ACPI_PARSEOP_TARGET;
-		}
-	}
-
-	if (walk_state->descending_callback != NULL) {
-		/*
-		 * Find the object. This will either insert the object into
-		 * the namespace or simply look it up
-		 */
-		walk_state->op = *new_op = op;
-
-		status = walk_state->descending_callback(walk_state, &op);
-		status = acpi_ps_next_parse_state(walk_state, op, status);
-		if (status == AE_CTRL_PENDING) {
-			status = AE_CTRL_PARSE_PENDING;
-		}
-	}
-
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ps_get_arguments
  *
  * PARAMETERS:  walk_state          - Current state
@@ -711,288 +376,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ps_complete_op
- *
- * PARAMETERS:  walk_state          - Current state
- *              op                  - Returned Op
- *              status              - Parse status before complete Op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Complete Op
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_complete_op(struct acpi_walk_state *walk_state,
-		    union acpi_parse_object **op, acpi_status status)
-{
-	acpi_status status2;
-
-	ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
-
-	/*
-	 * Finished one argument of the containing scope
-	 */
-	walk_state->parser_state.scope->parse_scope.arg_count--;
-
-	/* Close this Op (will result in parse subtree deletion) */
-
-	status2 = acpi_ps_complete_this_op(walk_state, *op);
-	if (ACPI_FAILURE(status2)) {
-		return_ACPI_STATUS(status2);
-	}
-
-	*op = NULL;
-
-	switch (status) {
-	case AE_OK:
-		break;
-
-	case AE_CTRL_TRANSFER:
-
-		/* We are about to transfer to a called method */
-
-		walk_state->prev_op = NULL;
-		walk_state->prev_arg_types = walk_state->arg_types;
-		return_ACPI_STATUS(status);
-
-	case AE_CTRL_END:
-
-		acpi_ps_pop_scope(&(walk_state->parser_state), op,
-				  &walk_state->arg_types,
-				  &walk_state->arg_count);
-
-		if (*op) {
-			walk_state->op = *op;
-			walk_state->op_info =
-			    acpi_ps_get_opcode_info((*op)->common.aml_opcode);
-			walk_state->opcode = (*op)->common.aml_opcode;
-
-			status = walk_state->ascending_callback(walk_state);
-			status =
-			    acpi_ps_next_parse_state(walk_state, *op, status);
-
-			status2 = acpi_ps_complete_this_op(walk_state, *op);
-			if (ACPI_FAILURE(status2)) {
-				return_ACPI_STATUS(status2);
-			}
-		}
-
-		status = AE_OK;
-		break;
-
-	case AE_CTRL_BREAK:
-	case AE_CTRL_CONTINUE:
-
-		/* Pop off scopes until we find the While */
-
-		while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
-			acpi_ps_pop_scope(&(walk_state->parser_state), op,
-					  &walk_state->arg_types,
-					  &walk_state->arg_count);
-		}
-
-		/* Close this iteration of the While loop */
-
-		walk_state->op = *op;
-		walk_state->op_info =
-		    acpi_ps_get_opcode_info((*op)->common.aml_opcode);
-		walk_state->opcode = (*op)->common.aml_opcode;
-
-		status = walk_state->ascending_callback(walk_state);
-		status = acpi_ps_next_parse_state(walk_state, *op, status);
-
-		status2 = acpi_ps_complete_this_op(walk_state, *op);
-		if (ACPI_FAILURE(status2)) {
-			return_ACPI_STATUS(status2);
-		}
-
-		status = AE_OK;
-		break;
-
-	case AE_CTRL_TERMINATE:
-
-		/* Clean up */
-		do {
-			if (*op) {
-				status2 =
-				    acpi_ps_complete_this_op(walk_state, *op);
-				if (ACPI_FAILURE(status2)) {
-					return_ACPI_STATUS(status2);
-				}
-
-				acpi_ut_delete_generic_state
-				    (acpi_ut_pop_generic_state
-				     (&walk_state->control_state));
-			}
-
-			acpi_ps_pop_scope(&(walk_state->parser_state), op,
-					  &walk_state->arg_types,
-					  &walk_state->arg_count);
-
-		} while (*op);
-
-		return_ACPI_STATUS(AE_OK);
-
-	default:		/* All other non-AE_OK status */
-
-		do {
-			if (*op) {
-				status2 =
-				    acpi_ps_complete_this_op(walk_state, *op);
-				if (ACPI_FAILURE(status2)) {
-					return_ACPI_STATUS(status2);
-				}
-			}
-
-			acpi_ps_pop_scope(&(walk_state->parser_state), op,
-					  &walk_state->arg_types,
-					  &walk_state->arg_count);
-
-		} while (*op);
-
-#if 0
-		/*
-		 * TBD: Cleanup parse ops on error
-		 */
-		if (*op == NULL) {
-			acpi_ps_pop_scope(parser_state, op,
-					  &walk_state->arg_types,
-					  &walk_state->arg_count);
-		}
-#endif
-		walk_state->prev_op = NULL;
-		walk_state->prev_arg_types = walk_state->arg_types;
-		return_ACPI_STATUS(status);
-	}
-
-	/* This scope complete? */
-
-	if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
-		acpi_ps_pop_scope(&(walk_state->parser_state), op,
-				  &walk_state->arg_types,
-				  &walk_state->arg_count);
-		ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
-	} else {
-		*op = NULL;
-	}
-
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_complete_final_op
- *
- * PARAMETERS:  walk_state          - Current state
- *              op                  - Current Op
- *              status              - Current parse status before complete last
- *                                    Op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Complete last Op.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
-			  union acpi_parse_object *op, acpi_status status)
-{
-	acpi_status status2;
-
-	ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
-
-	/*
-	 * Complete the last Op (if not completed), and clear the scope stack.
-	 * It is easily possible to end an AML "package" with an unbounded number
-	 * of open scopes (such as when several ASL blocks are closed with
-	 * sequential closing braces). We want to terminate each one cleanly.
-	 */
-	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
-			  op));
-	do {
-		if (op) {
-			if (walk_state->ascending_callback != NULL) {
-				walk_state->op = op;
-				walk_state->op_info =
-				    acpi_ps_get_opcode_info(op->common.
-							    aml_opcode);
-				walk_state->opcode = op->common.aml_opcode;
-
-				status =
-				    walk_state->ascending_callback(walk_state);
-				status =
-				    acpi_ps_next_parse_state(walk_state, op,
-							     status);
-				if (status == AE_CTRL_PENDING) {
-					status =
-					    acpi_ps_complete_op(walk_state, &op,
-								AE_OK);
-					if (ACPI_FAILURE(status)) {
-						return_ACPI_STATUS(status);
-					}
-				}
-
-				if (status == AE_CTRL_TERMINATE) {
-					status = AE_OK;
-
-					/* Clean up */
-					do {
-						if (op) {
-							status2 =
-							    acpi_ps_complete_this_op
-							    (walk_state, op);
-							if (ACPI_FAILURE
-							    (status2)) {
-								return_ACPI_STATUS
-								    (status2);
-							}
-						}
-
-						acpi_ps_pop_scope(&
-								  (walk_state->
-								   parser_state),
-								  &op,
-								  &walk_state->
-								  arg_types,
-								  &walk_state->
-								  arg_count);
-
-					} while (op);
-
-					return_ACPI_STATUS(status);
-				}
-
-				else if (ACPI_FAILURE(status)) {
-
-					/* First error is most important */
-
-					(void)
-					    acpi_ps_complete_this_op(walk_state,
-								     op);
-					return_ACPI_STATUS(status);
-				}
-			}
-
-			status2 = acpi_ps_complete_this_op(walk_state, op);
-			if (ACPI_FAILURE(status2)) {
-				return_ACPI_STATUS(status2);
-			}
-		}
-
-		acpi_ps_pop_scope(&(walk_state->parser_state), &op,
-				  &walk_state->arg_types,
-				  &walk_state->arg_count);
-
-	} while (op);
-
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ps_parse_loop
  *
  * PARAMETERS:  walk_state          - Current state
@@ -1177,10 +560,6 @@
 		walk_state->op_info =
 		    acpi_ps_get_opcode_info(op->common.aml_opcode);
 		if (walk_state->op_info->flags & AML_NAMED) {
-			if (acpi_gbl_depth) {
-				acpi_gbl_depth--;
-			}
-
 			if (op->common.aml_opcode == AML_REGION_OP ||
 			    op->common.aml_opcode == AML_DATA_REGION_OP) {
 				/*
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
new file mode 100644
index 0000000..12c4028
--- /dev/null
+++ b/drivers/acpi/acpica/psobject.c
@@ -0,0 +1,647 @@
+/******************************************************************************
+ *
+ * Module Name: psobject - Support for parse objects
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+
+#define _COMPONENT          ACPI_PARSER
+ACPI_MODULE_NAME("psobject")
+
+/* Local prototypes */
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_aml_opcode
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
+{
+
+	ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
+
+	walk_state->aml_offset =
+	    (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml,
+			       walk_state->parser_state.aml_start);
+	walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
+
+	/*
+	 * First cut to determine what we have found:
+	 * 1) A valid AML opcode
+	 * 2) A name string
+	 * 3) An unknown/invalid opcode
+	 */
+	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+
+	switch (walk_state->op_info->class) {
+	case AML_CLASS_ASCII:
+	case AML_CLASS_PREFIX:
+		/*
+		 * Starts with a valid prefix or ASCII char, this is a name
+		 * string. Convert the bare name string to a namepath.
+		 */
+		walk_state->opcode = AML_INT_NAMEPATH_OP;
+		walk_state->arg_types = ARGP_NAMESTRING;
+		break;
+
+	case AML_CLASS_UNKNOWN:
+
+		/* The opcode is unrecognized. Complain and skip unknown opcodes */
+
+		if (walk_state->pass_number == 2) {
+			ACPI_ERROR((AE_INFO,
+				    "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring",
+				    walk_state->opcode,
+				    (u32)(walk_state->aml_offset +
+					  sizeof(struct acpi_table_header))));
+
+			ACPI_DUMP_BUFFER((walk_state->parser_state.aml - 16),
+					 48);
+
+#ifdef ACPI_ASL_COMPILER
+			/*
+			 * This is executed for the disassembler only. Output goes
+			 * to the disassembled ASL output file.
+			 */
+			acpi_os_printf
+			    ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n",
+			     walk_state->opcode,
+			     (u32)(walk_state->aml_offset +
+				   sizeof(struct acpi_table_header)));
+
+			/* Dump the context surrounding the invalid opcode */
+
+			acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
+					     aml - 16), 48, DB_BYTE_DISPLAY,
+					    (walk_state->aml_offset +
+					     sizeof(struct acpi_table_header) -
+					     16));
+			acpi_os_printf(" */\n");
+#endif
+		}
+
+		/* Increment past one-byte or two-byte opcode */
+
+		walk_state->parser_state.aml++;
+		if (walk_state->opcode > 0xFF) {	/* Can only happen if first byte is 0x5B */
+			walk_state->parser_state.aml++;
+		}
+
+		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+
+	default:
+
+		/* Found opcode info, this is a normal opcode */
+
+		walk_state->parser_state.aml +=
+		    acpi_ps_get_opcode_size(walk_state->opcode);
+		walk_state->arg_types = walk_state->op_info->parse_args;
+		break;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_build_named_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Begin of named Op in AML
+ *              unnamed_op          - Early Op (not a named Op)
+ *              op                  - Returned Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+		       u8 *aml_op_start,
+		       union acpi_parse_object *unnamed_op,
+		       union acpi_parse_object **op)
+{
+	acpi_status status = AE_OK;
+	union acpi_parse_object *arg = NULL;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
+
+	unnamed_op->common.value.arg = NULL;
+	unnamed_op->common.arg_list_length = 0;
+	unnamed_op->common.aml_opcode = walk_state->opcode;
+
+	/*
+	 * Get and append arguments until we find the node that contains
+	 * the name (the type ARGP_NAME).
+	 */
+	while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+	       (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+		status =
+		    acpi_ps_get_next_arg(walk_state,
+					 &(walk_state->parser_state),
+					 GET_CURRENT_ARG_TYPE(walk_state->
+							      arg_types), &arg);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+		acpi_ps_append_arg(unnamed_op, arg);
+		INCREMENT_ARG_LIST(walk_state->arg_types);
+	}
+
+	/*
+	 * Make sure that we found a NAME and didn't run out of arguments
+	 */
+	if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+		return_ACPI_STATUS(AE_AML_NO_OPERAND);
+	}
+
+	/* We know that this arg is a name, move to next arg */
+
+	INCREMENT_ARG_LIST(walk_state->arg_types);
+
+	/*
+	 * Find the object. This will either insert the object into
+	 * the namespace or simply look it up
+	 */
+	walk_state->op = NULL;
+
+	status = walk_state->descending_callback(walk_state, op);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+		return_ACPI_STATUS(status);
+	}
+
+	if (!*op) {
+		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+	}
+
+	status = acpi_ps_next_parse_state(walk_state, *op, status);
+	if (ACPI_FAILURE(status)) {
+		if (status == AE_CTRL_PENDING) {
+			return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+		}
+		return_ACPI_STATUS(status);
+	}
+
+	acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+
+	if ((*op)->common.aml_opcode == AML_REGION_OP ||
+	    (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
+		/*
+		 * Defer final parsing of an operation_region body, because we don't
+		 * have enough info in the first pass to parse it correctly (i.e.,
+		 * there may be method calls within the term_arg elements of the body.)
+		 *
+		 * However, we must continue parsing because the opregion is not a
+		 * standalone package -- we don't know where the end is at this point.
+		 *
+		 * (Length is unknown until parse of the body complete)
+		 */
+		(*op)->named.data = aml_op_start;
+		(*op)->named.length = 0;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_create_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Op start in AML
+ *              new_op              - Returned Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+		  u8 *aml_op_start, union acpi_parse_object **new_op)
+{
+	acpi_status status = AE_OK;
+	union acpi_parse_object *op;
+	union acpi_parse_object *named_op = NULL;
+	union acpi_parse_object *parent_scope;
+	u8 argument_count;
+	const struct acpi_opcode_info *op_info;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
+
+	status = acpi_ps_get_aml_opcode(walk_state);
+	if (status == AE_CTRL_PARSE_CONTINUE) {
+		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+	}
+
+	/* Create Op structure and append to parent's argument list */
+
+	walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+	op = acpi_ps_alloc_op(walk_state->opcode);
+	if (!op) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	if (walk_state->op_info->flags & AML_NAMED) {
+		status =
+		    acpi_ps_build_named_op(walk_state, aml_op_start, op,
+					   &named_op);
+		acpi_ps_free_op(op);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+		*new_op = named_op;
+		return_ACPI_STATUS(AE_OK);
+	}
+
+	/* Not a named opcode, just allocate Op and append to parent */
+
+	if (walk_state->op_info->flags & AML_CREATE) {
+		/*
+		 * Backup to beginning of create_XXXfield declaration
+		 * body_length is unknown until we parse the body
+		 */
+		op->named.data = aml_op_start;
+		op->named.length = 0;
+	}
+
+	if (walk_state->opcode == AML_BANK_FIELD_OP) {
+		/*
+		 * Backup to beginning of bank_field declaration
+		 * body_length is unknown until we parse the body
+		 */
+		op->named.data = aml_op_start;
+		op->named.length = 0;
+	}
+
+	parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
+	acpi_ps_append_arg(parent_scope, op);
+
+	if (parent_scope) {
+		op_info =
+		    acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
+		if (op_info->flags & AML_HAS_TARGET) {
+			argument_count =
+			    acpi_ps_get_argument_count(op_info->type);
+			if (parent_scope->common.arg_list_length >
+			    argument_count) {
+				op->common.flags |= ACPI_PARSEOP_TARGET;
+			}
+		} else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
+			op->common.flags |= ACPI_PARSEOP_TARGET;
+		}
+	}
+
+	if (walk_state->descending_callback != NULL) {
+		/*
+		 * Find the object. This will either insert the object into
+		 * the namespace or simply look it up
+		 */
+		walk_state->op = *new_op = op;
+
+		status = walk_state->descending_callback(walk_state, &op);
+		status = acpi_ps_next_parse_state(walk_state, op, status);
+		if (status == AE_CTRL_PENDING) {
+			status = AE_CTRL_PARSE_PENDING;
+		}
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_complete_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              op                  - Returned Op
+ *              status              - Parse status before complete Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+		    union acpi_parse_object **op, acpi_status status)
+{
+	acpi_status status2;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
+
+	/*
+	 * Finished one argument of the containing scope
+	 */
+	walk_state->parser_state.scope->parse_scope.arg_count--;
+
+	/* Close this Op (will result in parse subtree deletion) */
+
+	status2 = acpi_ps_complete_this_op(walk_state, *op);
+	if (ACPI_FAILURE(status2)) {
+		return_ACPI_STATUS(status2);
+	}
+
+	*op = NULL;
+
+	switch (status) {
+	case AE_OK:
+		break;
+
+	case AE_CTRL_TRANSFER:
+
+		/* We are about to transfer to a called method */
+
+		walk_state->prev_op = NULL;
+		walk_state->prev_arg_types = walk_state->arg_types;
+		return_ACPI_STATUS(status);
+
+	case AE_CTRL_END:
+
+		acpi_ps_pop_scope(&(walk_state->parser_state), op,
+				  &walk_state->arg_types,
+				  &walk_state->arg_count);
+
+		if (*op) {
+			walk_state->op = *op;
+			walk_state->op_info =
+			    acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+			walk_state->opcode = (*op)->common.aml_opcode;
+
+			status = walk_state->ascending_callback(walk_state);
+			status =
+			    acpi_ps_next_parse_state(walk_state, *op, status);
+
+			status2 = acpi_ps_complete_this_op(walk_state, *op);
+			if (ACPI_FAILURE(status2)) {
+				return_ACPI_STATUS(status2);
+			}
+		}
+
+		status = AE_OK;
+		break;
+
+	case AE_CTRL_BREAK:
+	case AE_CTRL_CONTINUE:
+
+		/* Pop off scopes until we find the While */
+
+		while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+			acpi_ps_pop_scope(&(walk_state->parser_state), op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+		}
+
+		/* Close this iteration of the While loop */
+
+		walk_state->op = *op;
+		walk_state->op_info =
+		    acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+		walk_state->opcode = (*op)->common.aml_opcode;
+
+		status = walk_state->ascending_callback(walk_state);
+		status = acpi_ps_next_parse_state(walk_state, *op, status);
+
+		status2 = acpi_ps_complete_this_op(walk_state, *op);
+		if (ACPI_FAILURE(status2)) {
+			return_ACPI_STATUS(status2);
+		}
+
+		status = AE_OK;
+		break;
+
+	case AE_CTRL_TERMINATE:
+
+		/* Clean up */
+		do {
+			if (*op) {
+				status2 =
+				    acpi_ps_complete_this_op(walk_state, *op);
+				if (ACPI_FAILURE(status2)) {
+					return_ACPI_STATUS(status2);
+				}
+
+				acpi_ut_delete_generic_state
+				    (acpi_ut_pop_generic_state
+				     (&walk_state->control_state));
+			}
+
+			acpi_ps_pop_scope(&(walk_state->parser_state), op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+
+		} while (*op);
+
+		return_ACPI_STATUS(AE_OK);
+
+	default:		/* All other non-AE_OK status */
+
+		do {
+			if (*op) {
+				status2 =
+				    acpi_ps_complete_this_op(walk_state, *op);
+				if (ACPI_FAILURE(status2)) {
+					return_ACPI_STATUS(status2);
+				}
+			}
+
+			acpi_ps_pop_scope(&(walk_state->parser_state), op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+
+		} while (*op);
+
+#if 0
+		/*
+		 * TBD: Cleanup parse ops on error
+		 */
+		if (*op == NULL) {
+			acpi_ps_pop_scope(parser_state, op,
+					  &walk_state->arg_types,
+					  &walk_state->arg_count);
+		}
+#endif
+		walk_state->prev_op = NULL;
+		walk_state->prev_arg_types = walk_state->arg_types;
+		return_ACPI_STATUS(status);
+	}
+
+	/* This scope complete? */
+
+	if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+		acpi_ps_pop_scope(&(walk_state->parser_state), op,
+				  &walk_state->arg_types,
+				  &walk_state->arg_count);
+		ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+	} else {
+		*op = NULL;
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_complete_final_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              op                  - Current Op
+ *              status              - Current parse status before complete last
+ *                                    Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+			  union acpi_parse_object *op, acpi_status status)
+{
+	acpi_status status2;
+
+	ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
+
+	/*
+	 * Complete the last Op (if not completed), and clear the scope stack.
+	 * It is easily possible to end an AML "package" with an unbounded number
+	 * of open scopes (such as when several ASL blocks are closed with
+	 * sequential closing braces). We want to terminate each one cleanly.
+	 */
+	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
+			  op));
+	do {
+		if (op) {
+			if (walk_state->ascending_callback != NULL) {
+				walk_state->op = op;
+				walk_state->op_info =
+				    acpi_ps_get_opcode_info(op->common.
+							    aml_opcode);
+				walk_state->opcode = op->common.aml_opcode;
+
+				status =
+				    walk_state->ascending_callback(walk_state);
+				status =
+				    acpi_ps_next_parse_state(walk_state, op,
+							     status);
+				if (status == AE_CTRL_PENDING) {
+					status =
+					    acpi_ps_complete_op(walk_state, &op,
+								AE_OK);
+					if (ACPI_FAILURE(status)) {
+						return_ACPI_STATUS(status);
+					}
+				}
+
+				if (status == AE_CTRL_TERMINATE) {
+					status = AE_OK;
+
+					/* Clean up */
+					do {
+						if (op) {
+							status2 =
+							    acpi_ps_complete_this_op
+							    (walk_state, op);
+							if (ACPI_FAILURE
+							    (status2)) {
+								return_ACPI_STATUS
+								    (status2);
+							}
+						}
+
+						acpi_ps_pop_scope(&
+								  (walk_state->
+								   parser_state),
+								  &op,
+								  &walk_state->
+								  arg_types,
+								  &walk_state->
+								  arg_count);
+
+					} while (op);
+
+					return_ACPI_STATUS(status);
+				}
+
+				else if (ACPI_FAILURE(status)) {
+
+					/* First error is most important */
+
+					(void)
+					    acpi_ps_complete_this_op(walk_state,
+								     op);
+					return_ACPI_STATUS(status);
+				}
+			}
+
+			status2 = acpi_ps_complete_this_op(walk_state, op);
+			if (ACPI_FAILURE(status2)) {
+				return_ACPI_STATUS(status2);
+			}
+		}
+
+		acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+				  &walk_state->arg_types,
+				  &walk_state->arg_count);
+
+	} while (op);
+
+	return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 1793d93..1b659e59 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,16 +43,12 @@
 
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acparser.h"
 #include "acopcode.h"
 #include "amlcode.h"
 
 #define _COMPONENT          ACPI_PARSER
 ACPI_MODULE_NAME("psopcode")
 
-static const u8 acpi_gbl_argument_count[] =
-    { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
-
 /*******************************************************************************
  *
  * NAME:        acpi_gbl_aml_op_info
@@ -63,7 +59,6 @@
  *              the operand type.
  *
  ******************************************************************************/
-
 /*
  * Summary of opcode types/flags
  *
@@ -181,7 +176,6 @@
 	AML_CREATE_QWORD_FIELD_OP
 
  ******************************************************************************/
-
 /*
  * Master Opcode information table. A summary of everything we know about each
  * opcode, all in one place.
@@ -656,169 +650,3 @@
 
 /*! [End] no source code translation !*/
 };
-
-/*
- * This table is directly indexed by the opcodes, and returns an
- * index into the table above
- */
-static const u8 acpi_gbl_short_op_index[256] = {
-/*              0     1     2     3     4     5     6     7  */
-/*              8     9     A     B     C     D     E     F  */
-/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
-/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK,
-/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK,
-/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
-/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
-/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
-/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
-/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
-/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC,
-/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
-/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK,
-/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
-/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
-/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30,
-/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72,
-/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74,
-/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A,
-/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61,
-/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK,
-/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
-};
-
-/*
- * This table is indexed by the second opcode of the extended opcode
- * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info)
- */
-static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = {
-/*              0     1     2     3     4     5     6     7  */
-/*              8     9     A     B     C     D     E     F  */
-/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK,
-/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B,
-/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
-/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK,
-/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
-/* 0x88 */ 0x7C,
-};
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_get_opcode_info
- *
- * PARAMETERS:  opcode              - The AML opcode
- *
- * RETURN:      A pointer to the info about the opcode.
- *
- * DESCRIPTION: Find AML opcode description based on the opcode.
- *              NOTE: This procedure must ALWAYS return a valid pointer!
- *
- ******************************************************************************/
-
-const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
-{
-	ACPI_FUNCTION_NAME(ps_get_opcode_info);
-
-	/*
-	 * Detect normal 8-bit opcode or extended 16-bit opcode
-	 */
-	if (!(opcode & 0xFF00)) {
-
-		/* Simple (8-bit) opcode: 0-255, can't index beyond table  */
-
-		return (&acpi_gbl_aml_op_info
-			[acpi_gbl_short_op_index[(u8) opcode]]);
-	}
-
-	if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) &&
-	    (((u8) opcode) <= MAX_EXTENDED_OPCODE)) {
-
-		/* Valid extended (16-bit) opcode */
-
-		return (&acpi_gbl_aml_op_info
-			[acpi_gbl_long_op_index[(u8) opcode]]);
-	}
-
-	/* Unknown AML opcode */
-
-	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-			  "Unknown AML opcode [%4.4X]\n", opcode));
-
-	return (&acpi_gbl_aml_op_info[_UNK]);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_get_opcode_name
- *
- * PARAMETERS:  opcode              - The AML opcode
- *
- * RETURN:      A pointer to the name of the opcode (ASCII String)
- *              Note: Never returns NULL.
- *
- * DESCRIPTION: Translate an opcode into a human-readable string
- *
- ******************************************************************************/
-
-char *acpi_ps_get_opcode_name(u16 opcode)
-{
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
-
-	const struct acpi_opcode_info *op;
-
-	op = acpi_ps_get_opcode_info(opcode);
-
-	/* Always guaranteed to return a valid pointer */
-
-	return (op->name);
-
-#else
-	return ("OpcodeName unavailable");
-
-#endif
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_get_argument_count
- *
- * PARAMETERS:  op_type             - Type associated with the AML opcode
- *
- * RETURN:      Argument count
- *
- * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
- *
- ******************************************************************************/
-
-u8 acpi_ps_get_argument_count(u32 op_type)
-{
-
-	if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
-		return (acpi_gbl_argument_count[op_type]);
-	}
-
-	return (0);
-}
diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c
new file mode 100644
index 0000000..9ba5301
--- /dev/null
+++ b/drivers/acpi/acpica/psopinfo.c
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ * Module Name: psopinfo - AML opcode information functions and dispatch tables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acopcode.h"
+#include "amlcode.h"
+
+#define _COMPONENT          ACPI_PARSER
+ACPI_MODULE_NAME("psopinfo")
+
+extern const u8 acpi_gbl_short_op_index[];
+extern const u8 acpi_gbl_long_op_index[];
+
+static const u8 acpi_gbl_argument_count[] =
+    { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_opcode_info
+ *
+ * PARAMETERS:  opcode              - The AML opcode
+ *
+ * RETURN:      A pointer to the info about the opcode.
+ *
+ * DESCRIPTION: Find AML opcode description based on the opcode.
+ *              NOTE: This procedure must ALWAYS return a valid pointer!
+ *
+ ******************************************************************************/
+
+const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
+{
+	ACPI_FUNCTION_NAME(ps_get_opcode_info);
+
+	/*
+	 * Detect normal 8-bit opcode or extended 16-bit opcode
+	 */
+	if (!(opcode & 0xFF00)) {
+
+		/* Simple (8-bit) opcode: 0-255, can't index beyond table  */
+
+		return (&acpi_gbl_aml_op_info
+			[acpi_gbl_short_op_index[(u8)opcode]]);
+	}
+
+	if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) &&
+	    (((u8)opcode) <= MAX_EXTENDED_OPCODE)) {
+
+		/* Valid extended (16-bit) opcode */
+
+		return (&acpi_gbl_aml_op_info
+			[acpi_gbl_long_op_index[(u8)opcode]]);
+	}
+
+	/* Unknown AML opcode */
+
+	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+			  "Unknown AML opcode [%4.4X]\n", opcode));
+
+	return (&acpi_gbl_aml_op_info[_UNK]);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_opcode_name
+ *
+ * PARAMETERS:  opcode              - The AML opcode
+ *
+ * RETURN:      A pointer to the name of the opcode (ASCII String)
+ *              Note: Never returns NULL.
+ *
+ * DESCRIPTION: Translate an opcode into a human-readable string
+ *
+ ******************************************************************************/
+
+char *acpi_ps_get_opcode_name(u16 opcode)
+{
+#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
+
+	const struct acpi_opcode_info *op;
+
+	op = acpi_ps_get_opcode_info(opcode);
+
+	/* Always guaranteed to return a valid pointer */
+
+	return (op->name);
+
+#else
+	return ("OpcodeName unavailable");
+
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_argument_count
+ *
+ * PARAMETERS:  op_type             - Type associated with the AML opcode
+ *
+ * RETURN:      Argument count
+ *
+ * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
+ *
+ ******************************************************************************/
+
+u8 acpi_ps_get_argument_count(u32 op_type)
+{
+
+	if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
+		return (acpi_gbl_argument_count[op_type]);
+	}
+
+	return (0);
+}
+
+/*
+ * This table is directly indexed by the opcodes It returns
+ * an index into the opcode table (acpi_gbl_aml_op_info)
+ */
+const u8 acpi_gbl_short_op_index[256] = {
+/*              0     1     2     3     4     5     6     7  */
+/*              8     9     A     B     C     D     E     F  */
+/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
+/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK,
+/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK,
+/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
+/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
+/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC,
+/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK,
+/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30,
+/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72,
+/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74,
+/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A,
+/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61,
+/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK,
+/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
+};
+
+/*
+ * This table is indexed by the second opcode of the extended opcode
+ * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info)
+ */
+const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = {
+/*              0     1     2     3     4     5     6     7  */
+/*              8     9     A     B     C     D     E     F  */
+/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK,
+/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B,
+/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
+/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK,
+/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+/* 0x88 */ 0x7C,
+};
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 2494caf..abc4c48 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 608dc20..6a4b6fb 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index fdb2e71..c1934bf 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 4137dcb..91fa73a 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -202,14 +202,6 @@
 }
 
 /*
- * Is "c" a namestring prefix character?
- */
-u8 acpi_ps_is_prefix_char(u32 c)
-{
-	return ((u8) (c == '\\' || c == '^'));
-}
-
-/*
  * Get op's name (4-byte name segment) or 0 if unnamed
  */
 #ifdef ACPI_FUTURE_USAGE
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index ab96cf4..abd6562 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index 963e162..f682542 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index 856ff07..f3a9276 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 147feb6..7816d4ee 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -84,7 +84,7 @@
 		bit_field &= (u16) (bit_field - 1);
 	}
 
-	return bits_set;
+	return (bits_set);
 }
 
 /*******************************************************************************
@@ -407,7 +407,9 @@
 
 		/* Validate the Resource Type and Resource Length */
 
-		status = acpi_ut_validate_resource(aml_buffer, &resource_index);
+		status =
+		    acpi_ut_validate_resource(NULL, aml_buffer,
+					      &resource_index);
 		if (ACPI_FAILURE(status)) {
 			/*
 			 * Exit on failure. Cannot continue because the descriptor length
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index 311cbc4..f8b55b4 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -98,7 +98,7 @@
 
 	/* Perform the AML-to-Resource conversion */
 
-	status = acpi_ut_walk_aml_resources(aml_buffer, aml_buffer_length,
+	status = acpi_ut_walk_aml_resources(NULL, aml_buffer, aml_buffer_length,
 					    acpi_rs_convert_aml_to_resources,
 					    &current_resource_ptr);
 	if (status == AE_AML_NO_RESOURCE_END_TAG) {
@@ -174,7 +174,7 @@
 	/* Do the conversion */
 
 	resource = output_buffer->pointer;
-	status = acpi_ut_walk_aml_resources(aml_start, aml_buffer_length,
+	status = acpi_ut_walk_aml_resources(NULL, aml_start, aml_buffer_length,
 					    acpi_rs_convert_aml_to_resources,
 					    &resource);
 	if (ACPI_FAILURE(status)) {
@@ -480,8 +480,7 @@
 	status = acpi_rs_get_aml_length(linked_list_buffer, &aml_size_needed);
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n",
-			  (u32) aml_size_needed,
-			  acpi_format_exception(status)));
+			  (u32)aml_size_needed, acpi_format_exception(status)));
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 4d11b072..cab5144 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -77,419 +77,16 @@
 static void
 acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
 
-#define ACPI_RSD_OFFSET(f)          (u8) ACPI_OFFSET (union acpi_resource_data,f)
-#define ACPI_PRT_OFFSET(f)          (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
-#define ACPI_RSD_TABLE_SIZE(name)   (sizeof(name) / sizeof (struct acpi_rsdump_info))
-
-/*******************************************************************************
- *
- * Resource Descriptor info tables
- *
- * Note: The first table entry must be a Title or Literal and must contain
- * the table length (number of table entries)
- *
- ******************************************************************************/
-
-struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
-	 "Descriptor Length", NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
-	 acpi_gbl_he_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
-	 acpi_gbl_ll_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing",
-	 acpi_gbl_shr_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count),
-	 "Interrupt Count", NULL},
-	{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]),
-	 "Interrupt List", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed",
-	 acpi_gbl_typ_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering",
-	 acpi_gbl_bm_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type",
-	 acpi_gbl_siz_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count",
-	 NULL},
-	{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List",
-	 NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
-	 "Start-Dependent-Functions", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
-	 "Descriptor Length", NULL},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
-	 "Compatibility Priority", acpi_gbl_config_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
-	 "Performance/Robustness", acpi_gbl_config_decode}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_end_dpf[1] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_dpf),
-	 "End-Dependent-Functions", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_io[6] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io), "I/O", NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(io.io_decode), "Address Decoding",
-	 acpi_gbl_io_decode},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.minimum), "Address Minimum", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.maximum), "Address Maximum", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.alignment), "Alignment", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.address_length), "Address Length",
-	 NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_fixed_io[3] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_io),
-	 "Fixed I/O", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_io.address), "Address", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_io.address_length),
-	 "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_vendor[3] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_vendor),
-	 "Vendor Specific", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(vendor.byte_length), "Length", NULL},
-	{ACPI_RSD_LONGLIST, ACPI_RSD_OFFSET(vendor.byte_data[0]), "Vendor Data",
-	 NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag",
-	 NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_memory24[6] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24),
-	 "24-Bit Memory Range", NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect),
-	 "Write Protect", acpi_gbl_rw_decode},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.alignment), "Alignment",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.address_length),
-	 "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_memory32[6] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32),
-	 "32-Bit Memory Range", NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect),
-	 "Write Protect", acpi_gbl_rw_decode},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.alignment), "Alignment",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.address_length),
-	 "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32),
-	 "32-Bit Fixed Memory Range", NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect),
-	 "Write Protect", acpi_gbl_rw_decode},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length),
-	 "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_address16[8] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16),
-	 "16-Bit WORD Address Space", NULL},
-	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset),
-	 "Translation Offset", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length),
-	 "Address Length", NULL},
-	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_address32[8] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32),
-	 "32-Bit DWORD Address Space", NULL},
-	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum",
-	 NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset),
-	 "Translation Offset", NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length),
-	 "Address Length", NULL},
-	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_address64[8] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64),
-	 "64-Bit QWORD Address Space", NULL},
-	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity",
-	 NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum",
-	 NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum",
-	 NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset),
-	 "Translation Offset", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length),
-	 "Address Length", NULL},
-	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64),
-	 "64-Bit Extended Address Space", NULL},
-	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity),
-	 "Granularity", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum),
-	 "Address Minimum", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum),
-	 "Address Maximum", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset),
-	 "Translation Offset", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length),
-	 "Address Length", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific),
-	 "Type-Specific Attribute", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_irq),
-	 "Extended IRQ", NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer),
-	 "Type", acpi_gbl_consume_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering),
-	 "Triggering", acpi_gbl_he_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity",
-	 acpi_gbl_ll_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing",
-	 acpi_gbl_shr_decode},
-	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL,
-	 NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count),
-	 "Interrupt Count", NULL},
-	{ACPI_RSD_DWORDLIST, ACPI_RSD_OFFSET(extended_irq.interrupts[0]),
-	 "Interrupt List", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_generic_reg),
-	 "Generic Register", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.space_id), "Space ID",
-	 NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_width), "Bit Width",
-	 NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_offset), "Bit Offset",
-	 NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.access_size),
-	 "Access Size", NULL},
-	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_gpio[16] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type),
-	 "ConnectionType", acpi_gbl_ct_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer),
-	 "ProducerConsumer", acpi_gbl_consume_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig",
-	 acpi_gbl_ppc_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharable",
-	 acpi_gbl_shr_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction),
-	 "IoRestriction", acpi_gbl_ior_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering",
-	 acpi_gbl_he_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity",
-	 acpi_gbl_ll_decode},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength",
-	 NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout),
-	 "DebounceTimeout", NULL},
-	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source),
-	 "ResourceSource", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length),
-	 "PinTableLength", NULL},
-	{ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength",
-	 NULL},
-	{ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData",
-	 NULL},
-};
-
-struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma),
-	 "FixedDma", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines),
-	 "RequestLines", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels",
-	 NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth",
-	 acpi_gbl_dts_decode},
-};
-
-#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \
-	{ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.revision_id),    "RevisionId",               NULL}, \
-	{ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.type),           "Type",                     acpi_gbl_sbt_decode}, \
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer",      acpi_gbl_consume_decode}, \
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode),     "SlaveMode",                acpi_gbl_sm_decode}, \
-	{ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId",         NULL}, \
-	{ACPI_RSD_UINT16,   ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength",         NULL}, \
-	{ACPI_RSD_SOURCE,   ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource",          NULL}, \
-	{ACPI_RSD_UINT16,   ACPI_RSD_OFFSET (common_serial_bus.vendor_length),  "VendorLength",             NULL}, \
-	{ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data),   "VendorData",               NULL},
-
-struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus),
-	 "Common Serial Bus", NULL},
-	ACPI_RS_DUMP_COMMON_SERIAL_BUS
-};
-
-struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus),
-	 "I2C Serial Bus", NULL},
-	ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
-					ACPI_RSD_OFFSET(i2c_serial_bus.
-							access_mode),
-					"AccessMode", acpi_gbl_am_decode},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed),
-	 "ConnectionSpeed", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address),
-	 "SlaveAddress", NULL},
-};
-
-struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus),
-	 "Spi Serial Bus", NULL},
-	ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
-					ACPI_RSD_OFFSET(spi_serial_bus.
-							wire_mode), "WireMode",
-					acpi_gbl_wm_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity),
-	 "DevicePolarity", acpi_gbl_dp_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length),
-	 "DataBitLength", NULL},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase),
-	 "ClockPhase", acpi_gbl_cph_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity),
-	 "ClockPolarity", acpi_gbl_cpo_decode},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection),
-	 "DeviceSelection", NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed),
-	 "ConnectionSpeed", NULL},
-};
-
-struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus),
-	 "Uart Serial Bus", NULL},
-	ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG,
-					ACPI_RSD_OFFSET(uart_serial_bus.
-							flow_control),
-					"FlowControl", acpi_gbl_fc_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits),
-	 "StopBits", acpi_gbl_sb_decode},
-	{ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits),
-	 "DataBits", acpi_gbl_bpb_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian",
-	 acpi_gbl_ed_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity",
-	 acpi_gbl_pt_decode},
-	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled),
-	 "LinesEnabled", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size),
-	 "RxFifoSize", NULL},
-	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size),
-	 "TxFifoSize", NULL},
-	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate),
-	 "ConnectionSpeed", NULL},
-};
-
-/*
- * Tables used for common address descriptor flag fields
- */
-static struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_general_flags), NULL,
-	 NULL},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer),
-	 "Consumer/Producer", acpi_gbl_consume_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode",
-	 acpi_gbl_dec_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed),
-	 "Min Relocatability", acpi_gbl_min_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed),
-	 "Max Relocatability", acpi_gbl_max_decode}
-};
-
-static struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = {
-	{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags),
-	 "Resource Type", (void *)"Memory Range"},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect),
-	 "Write Protect", acpi_gbl_rw_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching),
-	 "Caching", acpi_gbl_mem_decode},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type),
-	 "Range Type", acpi_gbl_mtp_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation),
-	 "Translation", acpi_gbl_ttp_decode}
-};
-
-static struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = {
-	{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags),
-	 "Resource Type", (void *)"I/O Range"},
-	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type),
-	 "Range Type", acpi_gbl_rng_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation),
-	 "Translation", acpi_gbl_ttp_decode},
-	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type),
-	 "Translation Type", acpi_gbl_trs_decode}
-};
-
-/*
- * Table used to dump _PRT contents
- */
-static struct acpi_rsdump_info acpi_rs_dump_prt[5] = {
-	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_prt), NULL, NULL},
-	{ACPI_RSD_UINT64, ACPI_PRT_OFFSET(address), "Address", NULL},
-	{ACPI_RSD_UINT32, ACPI_PRT_OFFSET(pin), "Pin", NULL},
-	{ACPI_RSD_STRING, ACPI_PRT_OFFSET(source[0]), "Source", NULL},
-	{ACPI_RSD_UINT32, ACPI_PRT_OFFSET(source_index), "Source Index", NULL}
-};
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_rs_dump_descriptor
  *
- * PARAMETERS:  Resource
+ * PARAMETERS:  resource            - Buffer containing the resource
+ *              table               - Table entry to decode the resource
  *
  * RETURN:      None
  *
- * DESCRIPTION:
+ * DESCRIPTION: Dump a resource descriptor based on a dump table entry.
  *
  ******************************************************************************/
 
@@ -654,7 +251,8 @@
 			/*
 			 * Optional resource_source for Address resources
 			 */
-			acpi_rs_dump_resource_source(ACPI_CAST_PTR(struct
+			acpi_rs_dump_resource_source(ACPI_CAST_PTR
+						     (struct
 								   acpi_resource_source,
 								   target));
 			break;
@@ -765,8 +363,9 @@
 
 	ACPI_FUNCTION_ENTRY();
 
-	if (!(acpi_dbg_level & ACPI_LV_RESOURCES)
-	    || !(_COMPONENT & acpi_dbg_layer)) {
+	/* Check if debug output enabled */
+
+	if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) {
 		return;
 	}
 
@@ -827,8 +426,9 @@
 
 	ACPI_FUNCTION_ENTRY();
 
-	if (!(acpi_dbg_level & ACPI_LV_RESOURCES)
-	    || !(_COMPONENT & acpi_dbg_layer)) {
+	/* Check if debug output enabled */
+
+	if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) {
 		return;
 	}
 
diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c
new file mode 100644
index 0000000..46192bd
--- /dev/null
+++ b/drivers/acpi/acpica/rsdumpinfo.c
@@ -0,0 +1,454 @@
+/*******************************************************************************
+ *
+ * Module Name: rsdumpinfo - Tables used to display resource descriptors.
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acresrc.h"
+
+#define _COMPONENT          ACPI_RESOURCES
+ACPI_MODULE_NAME("rsdumpinfo")
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#define ACPI_RSD_OFFSET(f)          (u8) ACPI_OFFSET (union acpi_resource_data,f)
+#define ACPI_PRT_OFFSET(f)          (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
+#define ACPI_RSD_TABLE_SIZE(name)   (sizeof(name) / sizeof (struct acpi_rsdump_info))
+/*******************************************************************************
+ *
+ * Resource Descriptor info tables
+ *
+ * Note: The first table entry must be a Title or Literal and must contain
+ * the table length (number of table entries)
+ *
+ ******************************************************************************/
+struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
+	 "Descriptor Length", NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
+	 acpi_gbl_he_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
+	 acpi_gbl_ll_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing",
+	 acpi_gbl_shr_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count),
+	 "Interrupt Count", NULL},
+	{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]),
+	 "Interrupt List", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed",
+	 acpi_gbl_typ_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering",
+	 acpi_gbl_bm_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type",
+	 acpi_gbl_siz_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count",
+	 NULL},
+	{ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List",
+	 NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
+	 "Start-Dependent-Functions", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
+	 "Descriptor Length", NULL},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
+	 "Compatibility Priority", acpi_gbl_config_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
+	 "Performance/Robustness", acpi_gbl_config_decode}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_end_dpf[1] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_dpf),
+	 "End-Dependent-Functions", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_io[6] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io), "I/O", NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(io.io_decode), "Address Decoding",
+	 acpi_gbl_io_decode},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.minimum), "Address Minimum", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.maximum), "Address Maximum", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.alignment), "Alignment", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.address_length), "Address Length",
+	 NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_io[3] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_io),
+	 "Fixed I/O", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_io.address), "Address", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_io.address_length),
+	 "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_vendor[3] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_vendor),
+	 "Vendor Specific", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(vendor.byte_length), "Length", NULL},
+	{ACPI_RSD_LONGLIST, ACPI_RSD_OFFSET(vendor.byte_data[0]), "Vendor Data",
+	 NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag",
+	 NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_memory24[6] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24),
+	 "24-Bit Memory Range", NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect),
+	 "Write Protect", acpi_gbl_rw_decode},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.alignment), "Alignment",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.address_length),
+	 "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_memory32[6] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32),
+	 "32-Bit Memory Range", NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect),
+	 "Write Protect", acpi_gbl_rw_decode},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.alignment), "Alignment",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.address_length),
+	 "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32),
+	 "32-Bit Fixed Memory Range", NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect),
+	 "Write Protect", acpi_gbl_rw_decode},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length),
+	 "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_address16[8] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16),
+	 "16-Bit WORD Address Space", NULL},
+	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset),
+	 "Translation Offset", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length),
+	 "Address Length", NULL},
+	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_address32[8] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32),
+	 "32-Bit DWORD Address Space", NULL},
+	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum",
+	 NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset),
+	 "Translation Offset", NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length),
+	 "Address Length", NULL},
+	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_address64[8] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64),
+	 "64-Bit QWORD Address Space", NULL},
+	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity",
+	 NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum",
+	 NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum",
+	 NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset),
+	 "Translation Offset", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length),
+	 "Address Length", NULL},
+	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64),
+	 "64-Bit Extended Address Space", NULL},
+	{ACPI_RSD_ADDRESS, 0, NULL, NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity),
+	 "Granularity", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum),
+	 "Address Minimum", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum),
+	 "Address Maximum", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset),
+	 "Translation Offset", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length),
+	 "Address Length", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific),
+	 "Type-Specific Attribute", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_irq),
+	 "Extended IRQ", NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer),
+	 "Type", acpi_gbl_consume_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering),
+	 "Triggering", acpi_gbl_he_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity",
+	 acpi_gbl_ll_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing",
+	 acpi_gbl_shr_decode},
+	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL,
+	 NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count),
+	 "Interrupt Count", NULL},
+	{ACPI_RSD_DWORDLIST, ACPI_RSD_OFFSET(extended_irq.interrupts[0]),
+	 "Interrupt List", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_generic_reg),
+	 "Generic Register", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.space_id), "Space ID",
+	 NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_width), "Bit Width",
+	 NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_offset), "Bit Offset",
+	 NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.access_size),
+	 "Access Size", NULL},
+	{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_gpio[16] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type),
+	 "ConnectionType", acpi_gbl_ct_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer),
+	 "ProducerConsumer", acpi_gbl_consume_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig",
+	 acpi_gbl_ppc_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharing",
+	 acpi_gbl_shr_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction),
+	 "IoRestriction", acpi_gbl_ior_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering",
+	 acpi_gbl_he_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity",
+	 acpi_gbl_ll_decode},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength",
+	 NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout),
+	 "DebounceTimeout", NULL},
+	{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source),
+	 "ResourceSource", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length),
+	 "PinTableLength", NULL},
+	{ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength",
+	 NULL},
+	{ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData",
+	 NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma),
+	 "FixedDma", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines),
+	 "RequestLines", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels",
+	 NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth",
+	 acpi_gbl_dts_decode},
+};
+
+#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \
+	{ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.revision_id),    "RevisionId",               NULL}, \
+	{ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.type),           "Type",                     acpi_gbl_sbt_decode}, \
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer",      acpi_gbl_consume_decode}, \
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode),     "SlaveMode",                acpi_gbl_sm_decode}, \
+	{ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId",         NULL}, \
+	{ACPI_RSD_UINT16,   ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength",         NULL}, \
+	{ACPI_RSD_SOURCE,   ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource",          NULL}, \
+	{ACPI_RSD_UINT16,   ACPI_RSD_OFFSET (common_serial_bus.vendor_length),  "VendorLength",             NULL}, \
+	{ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data),   "VendorData",               NULL},
+
+struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus),
+	 "Common Serial Bus", NULL},
+	ACPI_RS_DUMP_COMMON_SERIAL_BUS
+};
+
+struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus),
+	 "I2C Serial Bus", NULL},
+	ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
+					ACPI_RSD_OFFSET(i2c_serial_bus.
+							access_mode),
+					"AccessMode", acpi_gbl_am_decode},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed),
+	 "ConnectionSpeed", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address),
+	 "SlaveAddress", NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus),
+	 "Spi Serial Bus", NULL},
+	ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
+					ACPI_RSD_OFFSET(spi_serial_bus.
+							wire_mode), "WireMode",
+					acpi_gbl_wm_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity),
+	 "DevicePolarity", acpi_gbl_dp_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length),
+	 "DataBitLength", NULL},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase),
+	 "ClockPhase", acpi_gbl_cph_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity),
+	 "ClockPolarity", acpi_gbl_cpo_decode},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection),
+	 "DeviceSelection", NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed),
+	 "ConnectionSpeed", NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus),
+	 "Uart Serial Bus", NULL},
+	ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG,
+					ACPI_RSD_OFFSET(uart_serial_bus.
+							flow_control),
+					"FlowControl", acpi_gbl_fc_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits),
+	 "StopBits", acpi_gbl_sb_decode},
+	{ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits),
+	 "DataBits", acpi_gbl_bpb_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian",
+	 acpi_gbl_ed_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity",
+	 acpi_gbl_pt_decode},
+	{ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled),
+	 "LinesEnabled", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size),
+	 "RxFifoSize", NULL},
+	{ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size),
+	 "TxFifoSize", NULL},
+	{ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate),
+	 "ConnectionSpeed", NULL},
+};
+
+/*
+ * Tables used for common address descriptor flag fields
+ */
+struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_general_flags), NULL,
+	 NULL},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer),
+	 "Consumer/Producer", acpi_gbl_consume_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode",
+	 acpi_gbl_dec_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed),
+	 "Min Relocatability", acpi_gbl_min_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed),
+	 "Max Relocatability", acpi_gbl_max_decode}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = {
+	{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags),
+	 "Resource Type", (void *)"Memory Range"},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect),
+	 "Write Protect", acpi_gbl_rw_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching),
+	 "Caching", acpi_gbl_mem_decode},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type),
+	 "Range Type", acpi_gbl_mtp_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation),
+	 "Translation", acpi_gbl_ttp_decode}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = {
+	{ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags),
+	 "Resource Type", (void *)"I/O Range"},
+	{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type),
+	 "Range Type", acpi_gbl_rng_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation),
+	 "Translation", acpi_gbl_ttp_decode},
+	{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type),
+	 "Translation Type", acpi_gbl_trs_decode}
+};
+
+/*
+ * Table used to dump _PRT contents
+ */
+struct acpi_rsdump_info acpi_rs_dump_prt[5] = {
+	{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_prt), NULL, NULL},
+	{ACPI_RSD_UINT64, ACPI_PRT_OFFSET(address), "Address", NULL},
+	{ACPI_RSD_UINT32, ACPI_PRT_OFFSET(pin), "Pin", NULL},
+	{ACPI_RSD_STRING, ACPI_PRT_OFFSET(source[0]), "Source", NULL},
+	{ACPI_RSD_UINT32, ACPI_PRT_OFFSET(source_index), "Source Index", NULL}
+};
+
+#endif
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index a9fa515..41fed78 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index f6a0810..ca18375 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index e23a9ec..364decc 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@
  * acpi_rs_get_irq
  *
  ******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
+struct acpi_rsconvert_info acpi_rs_get_irq[9] = {
 	{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ,
 	 ACPI_RS_SIZE(struct acpi_resource_irq),
 	 ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)},
@@ -80,41 +80,7 @@
 
 	{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3},
 
-	/* Get flags: Triggering[0], Polarity[3], Sharing[4] */
-
-	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
-	 AML_OFFSET(irq.flags),
-	 0},
-
-	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.polarity),
-	 AML_OFFSET(irq.flags),
-	 3},
-
-	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable),
-	 AML_OFFSET(irq.flags),
-	 4}
-};
-
-/*******************************************************************************
- *
- * acpi_rs_set_irq
- *
- ******************************************************************************/
-
-struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
-	/* Start with a default descriptor of length 3 */
-
-	{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ,
-	 sizeof(struct aml_resource_irq),
-	 ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)},
-
-	/* Convert interrupt list to 16-bit IRQ bitmask */
-
-	{ACPI_RSC_BITMASK16, ACPI_RS_OFFSET(data.irq.interrupts[0]),
-	 AML_OFFSET(irq.irq_mask),
-	 ACPI_RS_OFFSET(data.irq.interrupt_count)},
-
-	/* Set the flags byte */
+	/* Get flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */
 
 	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
 	 AML_OFFSET(irq.flags),
@@ -128,6 +94,48 @@
 	 AML_OFFSET(irq.flags),
 	 4},
 
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.wake_capable),
+	 AML_OFFSET(irq.flags),
+	 5}
+};
+
+/*******************************************************************************
+ *
+ * acpi_rs_set_irq
+ *
+ ******************************************************************************/
+
+struct acpi_rsconvert_info acpi_rs_set_irq[14] = {
+	/* Start with a default descriptor of length 3 */
+
+	{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ,
+	 sizeof(struct aml_resource_irq),
+	 ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)},
+
+	/* Convert interrupt list to 16-bit IRQ bitmask */
+
+	{ACPI_RSC_BITMASK16, ACPI_RS_OFFSET(data.irq.interrupts[0]),
+	 AML_OFFSET(irq.irq_mask),
+	 ACPI_RS_OFFSET(data.irq.interrupt_count)},
+
+	/* Set flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */
+
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
+	 AML_OFFSET(irq.flags),
+	 0},
+
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.polarity),
+	 AML_OFFSET(irq.flags),
+	 3},
+
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable),
+	 AML_OFFSET(irq.flags),
+	 4},
+
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.wake_capable),
+	 AML_OFFSET(irq.flags),
+	 5},
+
 	/*
 	 * All done if the output descriptor length is required to be 3
 	 * (i.e., optimization to 2 bytes cannot be attempted)
@@ -181,7 +189,7 @@
  *
  ******************************************************************************/
 
-struct acpi_rsconvert_info acpi_rs_convert_ext_irq[9] = {
+struct acpi_rsconvert_info acpi_rs_convert_ext_irq[10] = {
 	{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_EXTENDED_IRQ,
 	 ACPI_RS_SIZE(struct acpi_resource_extended_irq),
 	 ACPI_RSC_TABLE_SIZE(acpi_rs_convert_ext_irq)},
@@ -190,8 +198,10 @@
 	 sizeof(struct aml_resource_extended_irq),
 	 0},
 
-	/* Flag bits */
-
+	/*
+	 * Flags: Producer/Consumer[0], Triggering[1], Polarity[2],
+	 *        Sharing[3], Wake[4]
+	 */
 	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.producer_consumer),
 	 AML_OFFSET(extended_irq.flags),
 	 0},
@@ -208,19 +218,21 @@
 	 AML_OFFSET(extended_irq.flags),
 	 3},
 
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.wake_capable),
+	 AML_OFFSET(extended_irq.flags),
+	 4},
+
 	/* IRQ Table length (Byte4) */
 
 	{ACPI_RSC_COUNT, ACPI_RS_OFFSET(data.extended_irq.interrupt_count),
 	 AML_OFFSET(extended_irq.interrupt_count),
-	 sizeof(u32)}
-	,
+	 sizeof(u32)},
 
 	/* Copy every IRQ in the table, each is 32 bits */
 
 	{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.extended_irq.interrupts[0]),
 	 AML_OFFSET(extended_irq.interrupts[0]),
-	 0}
-	,
+	 0},
 
 	/* Optional resource_source (Index and String) */
 
@@ -285,7 +297,6 @@
 	 * request_lines
 	 * Channels
 	 */
-
 	{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_dma.request_lines),
 	 AML_OFFSET(fixed_dma.request_lines),
 	 2},
@@ -293,5 +304,4 @@
 	{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_dma.width),
 	 AML_OFFSET(fixed_dma.width),
 	 1},
-
 };
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 8b64db9..ee2e206 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -217,9 +217,10 @@
 
 		/* Perform final sanity check on the new AML resource descriptor */
 
-		status =
-		    acpi_ut_validate_resource(ACPI_CAST_PTR
-					      (union aml_resource, aml), NULL);
+		status = acpi_ut_validate_resource(NULL,
+						   ACPI_CAST_PTR(union
+								 aml_resource,
+								 aml), NULL);
 		if (ACPI_FAILURE(status)) {
 			return_ACPI_STATUS(status);
 		}
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index 4fd611a..ebc773a 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -156,8 +156,7 @@
 
 	{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length),
 	 0,
-	 sizeof(u8)}
-	,
+	 sizeof(u8)},
 
 	/* Vendor data */
 
@@ -181,8 +180,7 @@
 
 	{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length),
 	 0,
-	 sizeof(u8)}
-	,
+	 sizeof(u8)},
 
 	/* Vendor data */
 
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index c6f291c..d5bf05a 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -136,30 +136,30 @@
 			/*
 			 * Mask and shift the flag bit
 			 */
-			ACPI_SET8(destination) = (u8)
-			    ((ACPI_GET8(source) >> info->value) & 0x01);
+			ACPI_SET8(destination,
+				  ((ACPI_GET8(source) >> info->value) & 0x01));
 			break;
 
 		case ACPI_RSC_2BITFLAG:
 			/*
 			 * Mask and shift the flag bits
 			 */
-			ACPI_SET8(destination) = (u8)
-			    ((ACPI_GET8(source) >> info->value) & 0x03);
+			ACPI_SET8(destination,
+				  ((ACPI_GET8(source) >> info->value) & 0x03));
 			break;
 
 		case ACPI_RSC_3BITFLAG:
 			/*
 			 * Mask and shift the flag bits
 			 */
-			ACPI_SET8(destination) = (u8)
-			    ((ACPI_GET8(source) >> info->value) & 0x07);
+			ACPI_SET8(destination,
+				  ((ACPI_GET8(source) >> info->value) & 0x07));
 			break;
 
 		case ACPI_RSC_COUNT:
 
 			item_count = ACPI_GET8(source);
-			ACPI_SET8(destination) = (u8) item_count;
+			ACPI_SET8(destination, item_count);
 
 			resource->length = resource->length +
 			    (info->value * (item_count - 1));
@@ -168,7 +168,7 @@
 		case ACPI_RSC_COUNT16:
 
 			item_count = aml_resource_length;
-			ACPI_SET16(destination) = item_count;
+			ACPI_SET16(destination, item_count);
 
 			resource->length = resource->length +
 			    (info->value * (item_count - 1));
@@ -181,13 +181,13 @@
 
 			resource->length = resource->length + item_count;
 			item_count = item_count / 2;
-			ACPI_SET16(destination) = item_count;
+			ACPI_SET16(destination, item_count);
 			break;
 
 		case ACPI_RSC_COUNT_GPIO_VEN:
 
 			item_count = ACPI_GET8(source);
-			ACPI_SET8(destination) = (u8)item_count;
+			ACPI_SET8(destination, item_count);
 
 			resource->length = resource->length +
 			    (info->value * item_count);
@@ -216,7 +216,7 @@
 			}
 
 			resource->length = resource->length + item_count;
-			ACPI_SET16(destination) = item_count;
+			ACPI_SET16(destination, item_count);
 			break;
 
 		case ACPI_RSC_COUNT_SERIAL_VEN:
@@ -224,7 +224,7 @@
 			item_count = ACPI_GET16(source) - info->value;
 
 			resource->length = resource->length + item_count;
-			ACPI_SET16(destination) = item_count;
+			ACPI_SET16(destination, item_count);
 			break;
 
 		case ACPI_RSC_COUNT_SERIAL_RES:
@@ -234,7 +234,7 @@
 			    - ACPI_GET16(source) - info->value;
 
 			resource->length = resource->length + item_count;
-			ACPI_SET16(destination) = item_count;
+			ACPI_SET16(destination, item_count);
 			break;
 
 		case ACPI_RSC_LENGTH:
@@ -385,7 +385,7 @@
 			}
 
 			target = ACPI_ADD_PTR(char, resource, info->value);
-			ACPI_SET8(target) = (u8) item_count;
+			ACPI_SET8(target, item_count);
 			break;
 
 		case ACPI_RSC_BITMASK16:
@@ -401,7 +401,7 @@
 			}
 
 			target = ACPI_ADD_PTR(char, resource, info->value);
-			ACPI_SET8(target) = (u8) item_count;
+			ACPI_SET8(target, item_count);
 			break;
 
 		case ACPI_RSC_EXIT_NE:
@@ -514,37 +514,40 @@
 			/*
 			 * Clear the flag byte
 			 */
-			ACPI_SET8(destination) = 0;
+			ACPI_SET8(destination, 0);
 			break;
 
 		case ACPI_RSC_1BITFLAG:
 			/*
 			 * Mask and shift the flag bit
 			 */
-			ACPI_SET8(destination) |= (u8)
-			    ((ACPI_GET8(source) & 0x01) << info->value);
+			ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
+				     ((ACPI_GET8(source) & 0x01) << info->
+				      value));
 			break;
 
 		case ACPI_RSC_2BITFLAG:
 			/*
 			 * Mask and shift the flag bits
 			 */
-			ACPI_SET8(destination) |= (u8)
-			    ((ACPI_GET8(source) & 0x03) << info->value);
+			ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
+				     ((ACPI_GET8(source) & 0x03) << info->
+				      value));
 			break;
 
 		case ACPI_RSC_3BITFLAG:
 			/*
 			 * Mask and shift the flag bits
 			 */
-			ACPI_SET8(destination) |= (u8)
-			    ((ACPI_GET8(source) & 0x07) << info->value);
+			ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
+				     ((ACPI_GET8(source) & 0x07) << info->
+				      value));
 			break;
 
 		case ACPI_RSC_COUNT:
 
 			item_count = ACPI_GET8(source);
-			ACPI_SET8(destination) = (u8) item_count;
+			ACPI_SET8(destination, item_count);
 
 			aml_length =
 			    (u16) (aml_length +
@@ -561,18 +564,18 @@
 		case ACPI_RSC_COUNT_GPIO_PIN:
 
 			item_count = ACPI_GET16(source);
-			ACPI_SET16(destination) = (u16)aml_length;
+			ACPI_SET16(destination, aml_length);
 
 			aml_length = (u16)(aml_length + item_count * 2);
 			target = ACPI_ADD_PTR(void, aml, info->value);
-			ACPI_SET16(target) = (u16)aml_length;
+			ACPI_SET16(target, aml_length);
 			acpi_rs_set_resource_length(aml_length, aml);
 			break;
 
 		case ACPI_RSC_COUNT_GPIO_VEN:
 
 			item_count = ACPI_GET16(source);
-			ACPI_SET16(destination) = (u16)item_count;
+			ACPI_SET16(destination, item_count);
 
 			aml_length =
 			    (u16)(aml_length + (info->value * item_count));
@@ -584,7 +587,7 @@
 			/* Set resource source string length */
 
 			item_count = ACPI_GET16(source);
-			ACPI_SET16(destination) = (u16)aml_length;
+			ACPI_SET16(destination, aml_length);
 
 			/* Compute offset for the Vendor Data */
 
@@ -594,7 +597,7 @@
 			/* Set vendor offset only if there is vendor data */
 
 			if (resource->data.gpio.vendor_length) {
-				ACPI_SET16(target) = (u16)aml_length;
+				ACPI_SET16(target, aml_length);
 			}
 
 			acpi_rs_set_resource_length(aml_length, aml);
@@ -603,7 +606,7 @@
 		case ACPI_RSC_COUNT_SERIAL_VEN:
 
 			item_count = ACPI_GET16(source);
-			ACPI_SET16(destination) = item_count + info->value;
+			ACPI_SET16(destination, item_count + info->value);
 			aml_length = (u16)(aml_length + item_count);
 			acpi_rs_set_resource_length(aml_length, aml);
 			break;
@@ -686,7 +689,8 @@
 			 * Optional resource_source (Index and String)
 			 */
 			aml_length =
-			    acpi_rs_set_resource_source(aml, (acpi_rs_length)
+			    acpi_rs_set_resource_source(aml,
+							(acpi_rs_length)
 							aml_length, source);
 			acpi_rs_set_resource_length(aml_length, aml);
 			break;
@@ -706,10 +710,12 @@
 			/*
 			 * 8-bit encoded bitmask (DMA macro)
 			 */
-			ACPI_SET8(destination) = (u8)
-			    acpi_rs_encode_bitmask(source,
-						   *ACPI_ADD_PTR(u8, resource,
-								 info->value));
+			ACPI_SET8(destination,
+				  acpi_rs_encode_bitmask(source,
+							 *ACPI_ADD_PTR(u8,
+								       resource,
+								       info->
+								       value)));
 			break;
 
 		case ACPI_RSC_BITMASK16:
diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c
index 9aa5e68..fe49fc4 100644
--- a/drivers/acpi/acpica/rsserial.c
+++ b/drivers/acpi/acpica/rsserial.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@
  * acpi_rs_convert_gpio
  *
  ******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_convert_gpio[17] = {
+struct acpi_rsconvert_info acpi_rs_convert_gpio[18] = {
 	{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO,
 	 ACPI_RS_SIZE(struct acpi_resource_gpio),
 	 ACPI_RSC_TABLE_SIZE(acpi_rs_convert_gpio)},
@@ -75,10 +75,14 @@
 	 AML_OFFSET(gpio.flags),
 	 0},
 
-	{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable),
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable),
 	 AML_OFFSET(gpio.int_flags),
 	 3},
 
+	{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.wake_capable),
+	 AML_OFFSET(gpio.int_flags),
+	 4},
+
 	{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.io_restriction),
 	 AML_OFFSET(gpio.int_flags),
 	 0},
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 37d5241..a44953c 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,7 +108,7 @@
 		mask |= (0x1 << list[i]);
 	}
 
-	return mask;
+	return (mask);
 }
 
 /*******************************************************************************
@@ -358,8 +358,10 @@
 		 *
 		 * Zero the entire area of the buffer.
 		 */
-		total_length = (u32)
-		ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1;
+		total_length =
+		    (u32)
+		    ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) +
+		    1;
 		total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length);
 
 		ACPI_MEMSET(resource_source->string_ptr, 0, total_length);
@@ -675,7 +677,9 @@
 	/* Execute the method, no parameters */
 
 	status =
-	    acpi_ut_evaluate_object(handle, path, ACPI_BTYPE_BUFFER, &obj_desc);
+	    acpi_ut_evaluate_object(ACPI_CAST_PTR
+				    (struct acpi_namespace_node, handle), path,
+				    ACPI_BTYPE_BUFFER, &obj_desc);
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 5aad744..15d6eae 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -423,7 +423,7 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Walk a resource template for the specified evice to find a
+ * DESCRIPTION: Walk a resource template for the specified device to find a
  *              vendor-defined resource that matches the supplied UUID and
  *              UUID subtype. Returns a struct acpi_resource of type Vendor.
  *
@@ -522,57 +522,42 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_walk_resources
+ * FUNCTION:    acpi_walk_resource_buffer
  *
- * PARAMETERS:  device_handle   - Handle to the device object for the
- *                                device we are querying
- *              name            - Method name of the resources we want.
- *                                (METHOD_NAME__CRS, METHOD_NAME__PRS, or
- *                                METHOD_NAME__AEI)
+ * PARAMETERS:  buffer          - Formatted buffer returned by one of the
+ *                                various Get*Resource functions
  *              user_function   - Called for each resource
  *              context         - Passed to user_function
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Retrieves the current or possible resource list for the
- *              specified device. The user_function is called once for
- *              each resource in the list.
+ * DESCRIPTION: Walks the input resource template. The user_function is called
+ *              once for each resource in the list.
  *
  ******************************************************************************/
+
 acpi_status
-acpi_walk_resources(acpi_handle device_handle,
-		    char *name,
-		    acpi_walk_resource_callback user_function, void *context)
+acpi_walk_resource_buffer(struct acpi_buffer * buffer,
+			  acpi_walk_resource_callback user_function,
+			  void *context)
 {
-	acpi_status status;
-	struct acpi_buffer buffer;
+	acpi_status status = AE_OK;
 	struct acpi_resource *resource;
 	struct acpi_resource *resource_end;
 
-	ACPI_FUNCTION_TRACE(acpi_walk_resources);
+	ACPI_FUNCTION_TRACE(acpi_walk_resource_buffer);
 
 	/* Parameter validation */
 
-	if (!device_handle || !user_function || !name ||
-	    (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) &&
-	     !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) &&
-	     !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) {
+	if (!buffer || !buffer->pointer || !user_function) {
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	/* Get the _CRS/_PRS/_AEI resource list */
+	/* Buffer contains the resource list and length */
 
-	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
-	status = acpi_rs_get_method_data(device_handle, name, &buffer);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/* Buffer now contains the resource list */
-
-	resource = ACPI_CAST_PTR(struct acpi_resource, buffer.pointer);
+	resource = ACPI_CAST_PTR(struct acpi_resource, buffer->pointer);
 	resource_end =
-	    ACPI_ADD_PTR(struct acpi_resource, buffer.pointer, buffer.length);
+	    ACPI_ADD_PTR(struct acpi_resource, buffer->pointer, buffer->length);
 
 	/* Walk the resource list until the end_tag is found (or buffer end) */
 
@@ -606,11 +591,63 @@
 
 		/* Get the next resource descriptor */
 
-		resource =
-		    ACPI_ADD_PTR(struct acpi_resource, resource,
-				 resource->length);
+		resource = ACPI_NEXT_RESOURCE(resource);
 	}
 
+	return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_walk_resource_buffer)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_walk_resources
+ *
+ * PARAMETERS:  device_handle   - Handle to the device object for the
+ *                                device we are querying
+ *              name            - Method name of the resources we want.
+ *                                (METHOD_NAME__CRS, METHOD_NAME__PRS, or
+ *                                METHOD_NAME__AEI)
+ *              user_function   - Called for each resource
+ *              context         - Passed to user_function
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Retrieves the current or possible resource list for the
+ *              specified device. The user_function is called once for
+ *              each resource in the list.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_walk_resources(acpi_handle device_handle,
+		    char *name,
+		    acpi_walk_resource_callback user_function, void *context)
+{
+	acpi_status status;
+	struct acpi_buffer buffer;
+
+	ACPI_FUNCTION_TRACE(acpi_walk_resources);
+
+	/* Parameter validation */
+
+	if (!device_handle || !user_function || !name ||
+	    (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) &&
+	     !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) &&
+	     !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	/* Get the _CRS/_PRS/_AEI resource list */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_rs_get_method_data(device_handle, name, &buffer);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/* Walk the resource list and cleanup */
+
+	status = acpi_walk_resource_buffer(&buffer, user_function, context);
 	ACPI_FREE(buffer.pointer);
 	return_ACPI_STATUS(status);
 }
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 3906518..74181bf 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -172,6 +172,7 @@
  * FUNCTION:    acpi_tb_init_generic_address
  *
  * PARAMETERS:  generic_address     - GAS struct to be initialized
+ *              space_id            - ACPI Space ID for this register
  *              byte_width          - Width of this register
  *              address             - Address of the register
  *
@@ -407,8 +408,8 @@
 	 * should be zero are indeed zero. This will workaround BIOSs that
 	 * inadvertently place values in these fields.
 	 *
-	 * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
-	 * offset 45, 55, 95, and the word located at offset 109, 110.
+	 * The ACPI 1.0 reserved fields that will be zeroed are the bytes located
+	 * at offset 45, 55, 95, and the word located at offset 109, 110.
 	 *
 	 * Note: The FADT revision value is unreliable. Only the length can be
 	 * trusted.
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index 77d1db2..e4f4f02 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index f540ae4..e57cd38 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 285e24b..ce3d5db 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,7 @@
 					 ACPI_CAST_INDIRECT_PTR(struct
 								acpi_table_header,
 								&acpi_gbl_FACS));
-	return status;
+	return (status);
 }
 #endif				/* !ACPI_REDUCED_HARDWARE */
 
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index f563278..b35a5e6 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
 #include <linux/export.h>
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acnamesp.h"
 #include "actables.h"
 
 #define _COMPONENT          ACPI_TABLES
@@ -437,7 +436,7 @@
  *
  ******************************************************************************/
 acpi_status
-acpi_install_table_handler(acpi_tbl_handler handler, void *context)
+acpi_install_table_handler(acpi_table_handler handler, void *context)
 {
 	acpi_status status;
 
@@ -483,7 +482,7 @@
  * DESCRIPTION: Remove table event handler
  *
  ******************************************************************************/
-acpi_status acpi_remove_table_handler(acpi_tbl_handler handler)
+acpi_status acpi_remove_table_handler(acpi_table_handler handler)
 {
 	acpi_status status;
 
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index a5e1e4e..67e046e 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -192,7 +192,7 @@
 		(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+	ACPI_INFO((AE_INFO, "All ACPI Tables successfully acquired"));
 
       unlock_and_exit:
 	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 28f3302..7c2ecfb 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
index 6488030..698b9d3 100644
--- a/drivers/acpi/acpica/utaddress.c
+++ b/drivers/acpi/acpica/utaddress.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -214,7 +214,7 @@
 
 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
-		return_UINT32(0);
+		return_VALUE(0);
 	}
 
 	range_info = acpi_gbl_address_range_list[space_id];
@@ -256,7 +256,7 @@
 		range_info = range_info->next;
 	}
 
-	return_UINT32(overlap_count);
+	return_VALUE(overlap_count);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index ed29d47..e0ffb58 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index e1d40ed..e0e8579 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index 294692a..e4c9291 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -785,7 +785,7 @@
 
 		status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex);
 		if (ACPI_FAILURE(status)) {
-			return status;
+			return (status);
 		}
 		break;
 
@@ -795,7 +795,7 @@
 						  &dest_desc->event.
 						  os_semaphore);
 		if (ACPI_FAILURE(status)) {
-			return status;
+			return (status);
 		}
 		break;
 
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index 5d95166..c57d9cc 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -166,11 +166,9 @@
 	acpi_thread_id thread_id;
 	va_list args;
 
-	/*
-	 * Stay silent if the debug level or component ID is disabled
-	 */
-	if (!(requested_debug_level & acpi_dbg_level) ||
-	    !(component_id & acpi_dbg_layer)) {
+	/* Check if debug output enabled */
+
+	if (!ACPI_IS_DEBUG_ENABLED(requested_debug_level, component_id)) {
 		return;
 	}
 
@@ -236,8 +234,9 @@
 {
 	va_list args;
 
-	if (!(requested_debug_level & acpi_dbg_level) ||
-	    !(component_id & acpi_dbg_layer)) {
+	/* Check if debug output enabled */
+
+	if (!ACPI_IS_DEBUG_ENABLED(requested_debug_level, component_id)) {
 		return;
 	}
 
@@ -272,9 +271,13 @@
 	acpi_gbl_nesting_level++;
 	acpi_ut_track_stack_ptr();
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s\n", acpi_gbl_fn_entry_str);
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s\n", acpi_gbl_fn_entry_str);
+	}
 }
 
 ACPI_EXPORT_SYMBOL(acpi_ut_trace)
@@ -304,9 +307,14 @@
 	acpi_gbl_nesting_level++;
 	acpi_ut_track_stack_ptr();
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s %p\n", acpi_gbl_fn_entry_str, pointer);
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s %p\n", acpi_gbl_fn_entry_str,
+				 pointer);
+	}
 }
 
 /*******************************************************************************
@@ -335,9 +343,14 @@
 	acpi_gbl_nesting_level++;
 	acpi_ut_track_stack_ptr();
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s %s\n", acpi_gbl_fn_entry_str, string);
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s %s\n", acpi_gbl_fn_entry_str,
+				 string);
+	}
 }
 
 /*******************************************************************************
@@ -366,9 +379,14 @@
 	acpi_gbl_nesting_level++;
 	acpi_ut_track_stack_ptr();
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s %08X\n", acpi_gbl_fn_entry_str, integer);
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s %08X\n",
+				 acpi_gbl_fn_entry_str, integer);
+	}
 }
 
 /*******************************************************************************
@@ -393,9 +411,13 @@
 	     const char *module_name, u32 component_id)
 {
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s\n", acpi_gbl_fn_exit_str);
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s\n", acpi_gbl_fn_exit_str);
+	}
 
 	acpi_gbl_nesting_level--;
 }
@@ -425,17 +447,23 @@
 		    u32 component_id, acpi_status status)
 {
 
-	if (ACPI_SUCCESS(status)) {
-		acpi_debug_print(ACPI_LV_FUNCTIONS,
-				 line_number, function_name, module_name,
-				 component_id, "%s %s\n", acpi_gbl_fn_exit_str,
-				 acpi_format_exception(status));
-	} else {
-		acpi_debug_print(ACPI_LV_FUNCTIONS,
-				 line_number, function_name, module_name,
-				 component_id, "%s ****Exception****: %s\n",
-				 acpi_gbl_fn_exit_str,
-				 acpi_format_exception(status));
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		if (ACPI_SUCCESS(status)) {
+			acpi_debug_print(ACPI_LV_FUNCTIONS,
+					 line_number, function_name,
+					 module_name, component_id, "%s %s\n",
+					 acpi_gbl_fn_exit_str,
+					 acpi_format_exception(status));
+		} else {
+			acpi_debug_print(ACPI_LV_FUNCTIONS,
+					 line_number, function_name,
+					 module_name, component_id,
+					 "%s ****Exception****: %s\n",
+					 acpi_gbl_fn_exit_str,
+					 acpi_format_exception(status));
+		}
 	}
 
 	acpi_gbl_nesting_level--;
@@ -465,10 +493,15 @@
 		   const char *module_name, u32 component_id, u64 value)
 {
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str,
-			 ACPI_FORMAT_UINT64(value));
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s %8.8X%8.8X\n",
+				 acpi_gbl_fn_exit_str,
+				 ACPI_FORMAT_UINT64(value));
+	}
 
 	acpi_gbl_nesting_level--;
 }
@@ -497,9 +530,14 @@
 		 const char *module_name, u32 component_id, u8 *ptr)
 {
 
-	acpi_debug_print(ACPI_LV_FUNCTIONS,
-			 line_number, function_name, module_name, component_id,
-			 "%s %p\n", acpi_gbl_fn_exit_str, ptr);
+	/* Check if enabled up-front for performance */
+
+	if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+		acpi_debug_print(ACPI_LV_FUNCTIONS,
+				 line_number, function_name, module_name,
+				 component_id, "%s %p\n", acpi_gbl_fn_exit_str,
+				 ptr);
+	}
 
 	acpi_gbl_nesting_level--;
 }
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index 60a1584..11e2e02 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 7981054..2541de4 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -340,7 +340,7 @@
 {
 	union acpi_operand_object **internal_obj;
 
-	ACPI_FUNCTION_TRACE(ut_delete_internal_object_list);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Walk the null-terminated internal list */
 
@@ -351,7 +351,7 @@
 	/* Free the combined parameter pointer list and object array */
 
 	ACPI_FREE(obj_list);
-	return_VOID;
+	return;
 }
 
 /*******************************************************************************
@@ -484,7 +484,7 @@
 	union acpi_generic_state *state;
 	u32 i;
 
-	ACPI_FUNCTION_TRACE_PTR(ut_update_object_reference, object);
+	ACPI_FUNCTION_NAME(ut_update_object_reference);
 
 	while (object) {
 
@@ -493,7 +493,7 @@
 		if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) {
 			ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
 					  "Object %p is NS handle\n", object));
-			return_ACPI_STATUS(AE_OK);
+			return (AE_OK);
 		}
 
 		/*
@@ -530,18 +530,42 @@
 			 */
 			for (i = 0; i < object->package.count; i++) {
 				/*
-				 * Push each element onto the stack for later processing.
-				 * Note: There can be null elements within the package,
-				 * these are simply ignored
+				 * Null package elements are legal and can be simply
+				 * ignored.
 				 */
-				status =
-				    acpi_ut_create_update_state_and_push
-				    (object->package.elements[i], action,
-				     &state_list);
-				if (ACPI_FAILURE(status)) {
-					goto error_exit;
+				next_object = object->package.elements[i];
+				if (!next_object) {
+					continue;
+				}
+
+				switch (next_object->common.type) {
+				case ACPI_TYPE_INTEGER:
+				case ACPI_TYPE_STRING:
+				case ACPI_TYPE_BUFFER:
+					/*
+					 * For these very simple sub-objects, we can just
+					 * update the reference count here and continue.
+					 * Greatly increases performance of this operation.
+					 */
+					acpi_ut_update_ref_count(next_object,
+								 action);
+					break;
+
+				default:
+					/*
+					 * For complex sub-objects, push them onto the stack
+					 * for later processing (this eliminates recursion.)
+					 */
+					status =
+					    acpi_ut_create_update_state_and_push
+					    (next_object, action, &state_list);
+					if (ACPI_FAILURE(status)) {
+						goto error_exit;
+					}
+					break;
 				}
 			}
+			next_object = NULL;
 			break;
 
 		case ACPI_TYPE_BUFFER_FIELD:
@@ -619,7 +643,7 @@
 		}
 	}
 
-	return_ACPI_STATUS(AE_OK);
+	return (AE_OK);
 
       error_exit:
 
@@ -633,7 +657,7 @@
 		acpi_ut_delete_generic_state(state);
 	}
 
-	return_ACPI_STATUS(status);
+	return (status);
 }
 
 /*******************************************************************************
@@ -652,12 +676,12 @@
 void acpi_ut_add_reference(union acpi_operand_object *object)
 {
 
-	ACPI_FUNCTION_TRACE_PTR(ut_add_reference, object);
+	ACPI_FUNCTION_NAME(ut_add_reference);
 
 	/* Ensure that we have a valid object */
 
 	if (!acpi_ut_valid_internal_object(object)) {
-		return_VOID;
+		return;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
@@ -667,7 +691,7 @@
 	/* Increment the reference count */
 
 	(void)acpi_ut_update_object_reference(object, REF_INCREMENT);
-	return_VOID;
+	return;
 }
 
 /*******************************************************************************
@@ -685,7 +709,7 @@
 void acpi_ut_remove_reference(union acpi_operand_object *object)
 {
 
-	ACPI_FUNCTION_TRACE_PTR(ut_remove_reference, object);
+	ACPI_FUNCTION_NAME(ut_remove_reference);
 
 	/*
 	 * Allow a NULL pointer to be passed in, just ignore it. This saves
@@ -694,13 +718,13 @@
 	 */
 	if (!object ||
 	    (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {
-		return_VOID;
+		return;
 	}
 
 	/* Ensure that we have a valid object */
 
 	if (!acpi_ut_valid_internal_object(object)) {
-		return_VOID;
+		return;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
@@ -713,5 +737,5 @@
 	 * of all subobjects!)
 	 */
 	(void)acpi_ut_update_object_reference(object, REF_DECREMENT);
-	return_VOID;
+	return;
 }
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index a9c65fb..c3f3a7e 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -68,7 +68,7 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
+acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
 			char *path,
 			u32 expected_return_btypes,
 			union acpi_operand_object **return_desc)
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index 23b9894..a0ab7c0 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index ed18931..ffecf4b 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -293,11 +293,11 @@
 
 	/* GPE support */
 
+	acpi_gbl_all_gpes_initialized = FALSE;
 	acpi_gbl_gpe_xrupt_list_head = NULL;
 	acpi_gbl_gpe_fadt_blocks[0] = NULL;
 	acpi_gbl_gpe_fadt_blocks[1] = NULL;
 	acpi_current_gpe_count = 0;
-	acpi_gbl_all_gpes_initialized = FALSE;
 
 	acpi_gbl_global_event_handler = NULL;
 
@@ -357,17 +357,24 @@
 	acpi_gbl_root_node_struct.peer = NULL;
 	acpi_gbl_root_node_struct.object = NULL;
 
+#ifdef ACPI_DISASSEMBLER
+	acpi_gbl_external_list = NULL;
+#endif
+
 #ifdef ACPI_DEBUG_OUTPUT
 	acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
 #endif
 
 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
 	acpi_gbl_display_final_mem_stats = FALSE;
+	acpi_gbl_disable_mem_tracking = FALSE;
 #endif
 
 	return_ACPI_STATUS(AE_OK);
 }
 
+/* Public globals */
+
 ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
 ACPI_EXPORT_SYMBOL(acpi_dbg_level)
 ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index 774c3ae..43a170a 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 246798e..c5d1ac4 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index b1eb7f1..5c26ad4 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,11 +66,11 @@
 	lock->num_readers = 0;
 	status = acpi_os_create_mutex(&lock->reader_mutex);
 	if (ACPI_FAILURE(status)) {
-		return status;
+		return (status);
 	}
 
 	status = acpi_os_create_mutex(&lock->writer_mutex);
-	return status;
+	return (status);
 }
 
 void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock)
@@ -108,7 +108,7 @@
 
 	status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER);
 	if (ACPI_FAILURE(status)) {
-		return status;
+		return (status);
 	}
 
 	/* Acquire the write lock only for the first reader */
@@ -121,7 +121,7 @@
 	}
 
 	acpi_os_release_mutex(lock->reader_mutex);
-	return status;
+	return (status);
 }
 
 acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock)
@@ -130,7 +130,7 @@
 
 	status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER);
 	if (ACPI_FAILURE(status)) {
-		return status;
+		return (status);
 	}
 
 	/* Release the write lock only for the very last reader */
@@ -141,7 +141,7 @@
 	}
 
 	acpi_os_release_mutex(lock->reader_mutex);
-	return status;
+	return (status);
 }
 
 /*******************************************************************************
@@ -165,7 +165,7 @@
 	acpi_status status;
 
 	status = acpi_os_acquire_mutex(lock->writer_mutex, ACPI_WAIT_FOREVER);
-	return status;
+	return (status);
 }
 
 void acpi_ut_release_write_lock(struct acpi_rw_lock *lock)
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index 4956367..909fe66 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 9286a69..785fdd0 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,36 +48,6 @@
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utmisc")
 
-#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP
-/*******************************************************************************
- *
- * FUNCTION:    ut_convert_backslashes
- *
- * PARAMETERS:  pathname        - File pathname string to be converted
- *
- * RETURN:      Modifies the input Pathname
- *
- * DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within
- *              the entire input file pathname string.
- *
- ******************************************************************************/
-void ut_convert_backslashes(char *pathname)
-{
-
-	if (!pathname) {
-		return;
-	}
-
-	while (*pathname) {
-		if (*pathname == '\\') {
-			*pathname = '/';
-		}
-
-		pathname++;
-	}
-}
-#endif
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_is_pci_root_bridge
@@ -89,7 +59,6 @@
  * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
  *
  ******************************************************************************/
-
 u8 acpi_ut_is_pci_root_bridge(char *id)
 {
 
@@ -136,362 +105,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_allocate_owner_id
- *
- * PARAMETERS:  owner_id        - Where the new owner ID is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to
- *              track objects created by the table or method, to be deleted
- *              when the method exits or the table is unloaded.
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
-{
-	u32 i;
-	u32 j;
-	u32 k;
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(ut_allocate_owner_id);
-
-	/* Guard against multiple allocations of ID to the same location */
-
-	if (*owner_id) {
-		ACPI_ERROR((AE_INFO, "Owner ID [0x%2.2X] already exists",
-			    *owner_id));
-		return_ACPI_STATUS(AE_ALREADY_EXISTS);
-	}
-
-	/* Mutex for the global ID mask */
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
-	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
-	}
-
-	/*
-	 * Find a free owner ID, cycle through all possible IDs on repeated
-	 * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index may have
-	 * to be scanned twice.
-	 */
-	for (i = 0, j = acpi_gbl_last_owner_id_index;
-	     i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) {
-		if (j >= ACPI_NUM_OWNERID_MASKS) {
-			j = 0;	/* Wraparound to start of mask array */
-		}
-
-		for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) {
-			if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) {
-
-				/* There are no free IDs in this mask */
-
-				break;
-			}
-
-			if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) {
-				/*
-				 * Found a free ID. The actual ID is the bit index plus one,
-				 * making zero an invalid Owner ID. Save this as the last ID
-				 * allocated and update the global ID mask.
-				 */
-				acpi_gbl_owner_id_mask[j] |= (1 << k);
-
-				acpi_gbl_last_owner_id_index = (u8)j;
-				acpi_gbl_next_owner_id_offset = (u8)(k + 1);
-
-				/*
-				 * Construct encoded ID from the index and bit position
-				 *
-				 * Note: Last [j].k (bit 255) is never used and is marked
-				 * permanently allocated (prevents +1 overflow)
-				 */
-				*owner_id =
-				    (acpi_owner_id) ((k + 1) + ACPI_MUL_32(j));
-
-				ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
-						  "Allocated OwnerId: %2.2X\n",
-						  (unsigned int)*owner_id));
-				goto exit;
-			}
-		}
-
-		acpi_gbl_next_owner_id_offset = 0;
-	}
-
-	/*
-	 * All owner_ids have been allocated. This typically should
-	 * not happen since the IDs are reused after deallocation. The IDs are
-	 * allocated upon table load (one per table) and method execution, and
-	 * they are released when a table is unloaded or a method completes
-	 * execution.
-	 *
-	 * If this error happens, there may be very deep nesting of invoked control
-	 * methods, or there may be a bug where the IDs are not released.
-	 */
-	status = AE_OWNER_ID_LIMIT;
-	ACPI_ERROR((AE_INFO,
-		    "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT"));
-
-      exit:
-	(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
-	return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_release_owner_id
- *
- * PARAMETERS:  owner_id_ptr        - Pointer to a previously allocated owner_ID
- *
- * RETURN:      None. No error is returned because we are either exiting a
- *              control method or unloading a table. Either way, we would
- *              ignore any error anyway.
- *
- * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255
- *
- ******************************************************************************/
-
-void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
-{
-	acpi_owner_id owner_id = *owner_id_ptr;
-	acpi_status status;
-	u32 index;
-	u32 bit;
-
-	ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id);
-
-	/* Always clear the input owner_id (zero is an invalid ID) */
-
-	*owner_id_ptr = 0;
-
-	/* Zero is not a valid owner_ID */
-
-	if (owner_id == 0) {
-		ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%2.2X", owner_id));
-		return_VOID;
-	}
-
-	/* Mutex for the global ID mask */
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
-	if (ACPI_FAILURE(status)) {
-		return_VOID;
-	}
-
-	/* Normalize the ID to zero */
-
-	owner_id--;
-
-	/* Decode ID to index/offset pair */
-
-	index = ACPI_DIV_32(owner_id);
-	bit = 1 << ACPI_MOD_32(owner_id);
-
-	/* Free the owner ID only if it is valid */
-
-	if (acpi_gbl_owner_id_mask[index] & bit) {
-		acpi_gbl_owner_id_mask[index] ^= bit;
-	} else {
-		ACPI_ERROR((AE_INFO,
-			    "Release of non-allocated OwnerId: 0x%2.2X",
-			    owner_id + 1));
-	}
-
-	(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
-	return_VOID;
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strupr (strupr)
- *
- * PARAMETERS:  src_string      - The source string to convert
- *
- * RETURN:      None
- *
- * DESCRIPTION: Convert string to uppercase
- *
- * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
- *
- ******************************************************************************/
-
-void acpi_ut_strupr(char *src_string)
-{
-	char *string;
-
-	ACPI_FUNCTION_ENTRY();
-
-	if (!src_string) {
-		return;
-	}
-
-	/* Walk entire string, uppercasing the letters */
-
-	for (string = src_string; *string; string++) {
-		*string = (char)ACPI_TOUPPER(*string);
-	}
-
-	return;
-}
-
-#ifdef ACPI_ASL_COMPILER
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strlwr (strlwr)
- *
- * PARAMETERS:  src_string      - The source string to convert
- *
- * RETURN:      None
- *
- * DESCRIPTION: Convert string to lowercase
- *
- * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
- *
- ******************************************************************************/
-
-void acpi_ut_strlwr(char *src_string)
-{
-	char *string;
-
-	ACPI_FUNCTION_ENTRY();
-
-	if (!src_string) {
-		return;
-	}
-
-	/* Walk entire string, lowercasing the letters */
-
-	for (string = src_string; *string; string++) {
-		*string = (char)ACPI_TOLOWER(*string);
-	}
-
-	return;
-}
-
-/******************************************************************************
- *
- * FUNCTION:    acpi_ut_stricmp
- *
- * PARAMETERS:  string1             - first string to compare
- *              string2             - second string to compare
- *
- * RETURN:      int that signifies string relationship. Zero means strings
- *              are equal.
- *
- * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare
- *              strings with no case sensitivity)
- *
- ******************************************************************************/
-
-int acpi_ut_stricmp(char *string1, char *string2)
-{
-	int c1;
-	int c2;
-
-	do {
-		c1 = tolower((int)*string1);
-		c2 = tolower((int)*string2);
-
-		string1++;
-		string2++;
-	}
-	while ((c1 == c2) && (c1));
-
-	return (c1 - c2);
-}
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_print_string
- *
- * PARAMETERS:  string          - Null terminated ASCII string
- *              max_length      - Maximum output length
- *
- * RETURN:      None
- *
- * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape
- *              sequences.
- *
- ******************************************************************************/
-
-void acpi_ut_print_string(char *string, u8 max_length)
-{
-	u32 i;
-
-	if (!string) {
-		acpi_os_printf("<\"NULL STRING PTR\">");
-		return;
-	}
-
-	acpi_os_printf("\"");
-	for (i = 0; string[i] && (i < max_length); i++) {
-
-		/* Escape sequences */
-
-		switch (string[i]) {
-		case 0x07:
-			acpi_os_printf("\\a");	/* BELL */
-			break;
-
-		case 0x08:
-			acpi_os_printf("\\b");	/* BACKSPACE */
-			break;
-
-		case 0x0C:
-			acpi_os_printf("\\f");	/* FORMFEED */
-			break;
-
-		case 0x0A:
-			acpi_os_printf("\\n");	/* LINEFEED */
-			break;
-
-		case 0x0D:
-			acpi_os_printf("\\r");	/* CARRIAGE RETURN */
-			break;
-
-		case 0x09:
-			acpi_os_printf("\\t");	/* HORIZONTAL TAB */
-			break;
-
-		case 0x0B:
-			acpi_os_printf("\\v");	/* VERTICAL TAB */
-			break;
-
-		case '\'':	/* Single Quote */
-		case '\"':	/* Double Quote */
-		case '\\':	/* Backslash */
-			acpi_os_printf("\\%c", (int)string[i]);
-			break;
-
-		default:
-
-			/* Check for printable character or hex escape */
-
-			if (ACPI_IS_PRINT(string[i])) {
-				/* This is a normal character */
-
-				acpi_os_printf("%c", (int)string[i]);
-			} else {
-				/* All others will be Hex escapes */
-
-				acpi_os_printf("\\x%2.2X", (s32) string[i]);
-			}
-			break;
-		}
-	}
-	acpi_os_printf("\"");
-
-	if (i == max_length && string[i]) {
-		acpi_os_printf("...");
-	}
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ut_dword_byte_swap
  *
  * PARAMETERS:  value           - Value to be converted
@@ -559,379 +172,6 @@
 	}
 }
 
-#ifdef ACPI_DEBUG_OUTPUT
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_display_init_pathname
- *
- * PARAMETERS:  type                - Object type of the node
- *              obj_handle          - Handle whose pathname will be displayed
- *              path                - Additional path string to be appended.
- *                                      (NULL if no extra path)
- *
- * RETURN:      acpi_status
- *
- * DESCRIPTION: Display full pathname of an object, DEBUG ONLY
- *
- ******************************************************************************/
-
-void
-acpi_ut_display_init_pathname(u8 type,
-			      struct acpi_namespace_node *obj_handle,
-			      char *path)
-{
-	acpi_status status;
-	struct acpi_buffer buffer;
-
-	ACPI_FUNCTION_ENTRY();
-
-	/* Only print the path if the appropriate debug level is enabled */
-
-	if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
-		return;
-	}
-
-	/* Get the full pathname to the node */
-
-	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
-	status = acpi_ns_handle_to_pathname(obj_handle, &buffer);
-	if (ACPI_FAILURE(status)) {
-		return;
-	}
-
-	/* Print what we're doing */
-
-	switch (type) {
-	case ACPI_TYPE_METHOD:
-		acpi_os_printf("Executing  ");
-		break;
-
-	default:
-		acpi_os_printf("Initializing ");
-		break;
-	}
-
-	/* Print the object type and pathname */
-
-	acpi_os_printf("%-12s %s",
-		       acpi_ut_get_type_name(type), (char *)buffer.pointer);
-
-	/* Extra path is used to append names like _STA, _INI, etc. */
-
-	if (path) {
-		acpi_os_printf(".%s", path);
-	}
-	acpi_os_printf("\n");
-
-	ACPI_FREE(buffer.pointer);
-}
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_valid_acpi_char
- *
- * PARAMETERS:  char            - The character to be examined
- *              position        - Byte position (0-3)
- *
- * RETURN:      TRUE if the character is valid, FALSE otherwise
- *
- * DESCRIPTION: Check for a valid ACPI character. Must be one of:
- *              1) Upper case alpha
- *              2) numeric
- *              3) underscore
- *
- *              We allow a '!' as the last character because of the ASF! table
- *
- ******************************************************************************/
-
-u8 acpi_ut_valid_acpi_char(char character, u32 position)
-{
-
-	if (!((character >= 'A' && character <= 'Z') ||
-	      (character >= '0' && character <= '9') || (character == '_'))) {
-
-		/* Allow a '!' in the last position */
-
-		if (character == '!' && position == 3) {
-			return (TRUE);
-		}
-
-		return (FALSE);
-	}
-
-	return (TRUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_valid_acpi_name
- *
- * PARAMETERS:  name            - The name to be examined
- *
- * RETURN:      TRUE if the name is valid, FALSE otherwise
- *
- * DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
- *              1) Upper case alpha
- *              2) numeric
- *              3) underscore
- *
- ******************************************************************************/
-
-u8 acpi_ut_valid_acpi_name(u32 name)
-{
-	u32 i;
-
-	ACPI_FUNCTION_ENTRY();
-
-	for (i = 0; i < ACPI_NAME_SIZE; i++) {
-		if (!acpi_ut_valid_acpi_char
-		    ((ACPI_CAST_PTR(char, &name))[i], i)) {
-			return (FALSE);
-		}
-	}
-
-	return (TRUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_repair_name
- *
- * PARAMETERS:  name            - The ACPI name to be repaired
- *
- * RETURN:      Repaired version of the name
- *
- * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and
- *              return the new name. NOTE: the Name parameter must reside in
- *              read/write memory, cannot be a const.
- *
- * An ACPI Name must consist of valid ACPI characters. We will repair the name
- * if necessary because we don't want to abort because of this, but we want
- * all namespace names to be printable. A warning message is appropriate.
- *
- * This issue came up because there are in fact machines that exhibit
- * this problem, and we want to be able to enable ACPI support for them,
- * even though there are a few bad names.
- *
- ******************************************************************************/
-
-void acpi_ut_repair_name(char *name)
-{
-	u32 i;
-	u8 found_bad_char = FALSE;
-	u32 original_name;
-
-	ACPI_FUNCTION_NAME(ut_repair_name);
-
-	ACPI_MOVE_NAME(&original_name, name);
-
-	/* Check each character in the name */
-
-	for (i = 0; i < ACPI_NAME_SIZE; i++) {
-		if (acpi_ut_valid_acpi_char(name[i], i)) {
-			continue;
-		}
-
-		/*
-		 * Replace a bad character with something printable, yet technically
-		 * still invalid. This prevents any collisions with existing "good"
-		 * names in the namespace.
-		 */
-		name[i] = '*';
-		found_bad_char = TRUE;
-	}
-
-	if (found_bad_char) {
-
-		/* Report warning only if in strict mode or debug mode */
-
-		if (!acpi_gbl_enable_interpreter_slack) {
-			ACPI_WARNING((AE_INFO,
-				      "Found bad character(s) in name, repaired: [%4.4s]\n",
-				      name));
-		} else {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Found bad character(s) in name, repaired: [%4.4s]\n",
-					  name));
-		}
-	}
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strtoul64
- *
- * PARAMETERS:  string          - Null terminated string
- *              base            - Radix of the string: 16 or ACPI_ANY_BASE;
- *                                ACPI_ANY_BASE means 'in behalf of to_integer'
- *              ret_integer     - Where the converted integer is returned
- *
- * RETURN:      Status and Converted value
- *
- * DESCRIPTION: Convert a string into an unsigned value. Performs either a
- *              32-bit or 64-bit conversion, depending on the current mode
- *              of the interpreter.
- *              NOTE: Does not support Octal strings, not needed.
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
-{
-	u32 this_digit = 0;
-	u64 return_value = 0;
-	u64 quotient;
-	u64 dividend;
-	u32 to_integer_op = (base == ACPI_ANY_BASE);
-	u32 mode32 = (acpi_gbl_integer_byte_width == 4);
-	u8 valid_digits = 0;
-	u8 sign_of0x = 0;
-	u8 term = 0;
-
-	ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
-
-	switch (base) {
-	case ACPI_ANY_BASE:
-	case 16:
-		break;
-
-	default:
-		/* Invalid Base */
-		return_ACPI_STATUS(AE_BAD_PARAMETER);
-	}
-
-	if (!string) {
-		goto error_exit;
-	}
-
-	/* Skip over any white space in the buffer */
-
-	while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) {
-		string++;
-	}
-
-	if (to_integer_op) {
-		/*
-		 * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'.
-		 * We need to determine if it is decimal or hexadecimal.
-		 */
-		if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) {
-			sign_of0x = 1;
-			base = 16;
-
-			/* Skip over the leading '0x' */
-			string += 2;
-		} else {
-			base = 10;
-		}
-	}
-
-	/* Any string left? Check that '0x' is not followed by white space. */
-
-	if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') {
-		if (to_integer_op) {
-			goto error_exit;
-		} else {
-			goto all_done;
-		}
-	}
-
-	/*
-	 * Perform a 32-bit or 64-bit conversion, depending upon the current
-	 * execution mode of the interpreter
-	 */
-	dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
-
-	/* Main loop: convert the string to a 32- or 64-bit integer */
-
-	while (*string) {
-		if (ACPI_IS_DIGIT(*string)) {
-
-			/* Convert ASCII 0-9 to Decimal value */
-
-			this_digit = ((u8)*string) - '0';
-		} else if (base == 10) {
-
-			/* Digit is out of range; possible in to_integer case only */
-
-			term = 1;
-		} else {
-			this_digit = (u8)ACPI_TOUPPER(*string);
-			if (ACPI_IS_XDIGIT((char)this_digit)) {
-
-				/* Convert ASCII Hex char to value */
-
-				this_digit = this_digit - 'A' + 10;
-			} else {
-				term = 1;
-			}
-		}
-
-		if (term) {
-			if (to_integer_op) {
-				goto error_exit;
-			} else {
-				break;
-			}
-		} else if ((valid_digits == 0) && (this_digit == 0)
-			   && !sign_of0x) {
-
-			/* Skip zeros */
-			string++;
-			continue;
-		}
-
-		valid_digits++;
-
-		if (sign_of0x
-		    && ((valid_digits > 16)
-			|| ((valid_digits > 8) && mode32))) {
-			/*
-			 * This is to_integer operation case.
-			 * No any restrictions for string-to-integer conversion,
-			 * see ACPI spec.
-			 */
-			goto error_exit;
-		}
-
-		/* Divide the digit into the correct position */
-
-		(void)acpi_ut_short_divide((dividend - (u64)this_digit),
-					   base, &quotient, NULL);
-
-		if (return_value > quotient) {
-			if (to_integer_op) {
-				goto error_exit;
-			} else {
-				break;
-			}
-		}
-
-		return_value *= base;
-		return_value += this_digit;
-		string++;
-	}
-
-	/* All done, normal exit */
-
-      all_done:
-
-	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
-			  ACPI_FORMAT_UINT64(return_value)));
-
-	*ret_integer = return_value;
-	return_ACPI_STATUS(AE_OK);
-
-      error_exit:
-	/* Base was set/validated above */
-
-	if (base == 10) {
-		return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT);
-	} else {
-		return_ACPI_STATUS(AE_BAD_HEX_CONSTANT);
-	}
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_create_update_state_and_push
@@ -1097,3 +337,71 @@
 
 	return_ACPI_STATUS(AE_AML_INTERNAL);
 }
+
+#ifdef ACPI_DEBUG_OUTPUT
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_display_init_pathname
+ *
+ * PARAMETERS:  type                - Object type of the node
+ *              obj_handle          - Handle whose pathname will be displayed
+ *              path                - Additional path string to be appended.
+ *                                      (NULL if no extra path)
+ *
+ * RETURN:      acpi_status
+ *
+ * DESCRIPTION: Display full pathname of an object, DEBUG ONLY
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_display_init_pathname(u8 type,
+			      struct acpi_namespace_node *obj_handle,
+			      char *path)
+{
+	acpi_status status;
+	struct acpi_buffer buffer;
+
+	ACPI_FUNCTION_ENTRY();
+
+	/* Only print the path if the appropriate debug level is enabled */
+
+	if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
+		return;
+	}
+
+	/* Get the full pathname to the node */
+
+	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+	status = acpi_ns_handle_to_pathname(obj_handle, &buffer);
+	if (ACPI_FAILURE(status)) {
+		return;
+	}
+
+	/* Print what we're doing */
+
+	switch (type) {
+	case ACPI_TYPE_METHOD:
+		acpi_os_printf("Executing  ");
+		break;
+
+	default:
+		acpi_os_printf("Initializing ");
+		break;
+	}
+
+	/* Print the object type and pathname */
+
+	acpi_os_printf("%-12s %s",
+		       acpi_ut_get_type_name(type), (char *)buffer.pointer);
+
+	/* Extra path is used to append names like _STA, _INI, etc. */
+
+	if (path) {
+		acpi_os_printf(".%s", path);
+	}
+	acpi_os_printf("\n");
+
+	ACPI_FREE(buffer.pointer);
+}
+#endif
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 5ccf57c..22feb99 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index 5c52ca7..1099f5c 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -419,7 +419,7 @@
 {
 	ACPI_FUNCTION_TRACE_PTR(ut_delete_object_desc, object);
 
-	/* Object must be a union acpi_operand_object */
+	/* Object must be of type union acpi_operand_object */
 
 	if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
 		ACPI_ERROR((AE_INFO,
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 676285d..36a7d36 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c
new file mode 100644
index 0000000..835340b
--- /dev/null
+++ b/drivers/acpi/acpica/utownerid.c
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ *
+ * Module Name: utownerid - Support for Table/Method Owner IDs
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utownerid")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_allocate_owner_id
+ *
+ * PARAMETERS:  owner_id        - Where the new owner ID is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to
+ *              track objects created by the table or method, to be deleted
+ *              when the method exits or the table is unloaded.
+ *
+ ******************************************************************************/
+acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
+{
+	u32 i;
+	u32 j;
+	u32 k;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(ut_allocate_owner_id);
+
+	/* Guard against multiple allocations of ID to the same location */
+
+	if (*owner_id) {
+		ACPI_ERROR((AE_INFO, "Owner ID [0x%2.2X] already exists",
+			    *owner_id));
+		return_ACPI_STATUS(AE_ALREADY_EXISTS);
+	}
+
+	/* Mutex for the global ID mask */
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/*
+	 * Find a free owner ID, cycle through all possible IDs on repeated
+	 * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index may have
+	 * to be scanned twice.
+	 */
+	for (i = 0, j = acpi_gbl_last_owner_id_index;
+	     i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) {
+		if (j >= ACPI_NUM_OWNERID_MASKS) {
+			j = 0;	/* Wraparound to start of mask array */
+		}
+
+		for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) {
+			if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) {
+
+				/* There are no free IDs in this mask */
+
+				break;
+			}
+
+			if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) {
+				/*
+				 * Found a free ID. The actual ID is the bit index plus one,
+				 * making zero an invalid Owner ID. Save this as the last ID
+				 * allocated and update the global ID mask.
+				 */
+				acpi_gbl_owner_id_mask[j] |= (1 << k);
+
+				acpi_gbl_last_owner_id_index = (u8)j;
+				acpi_gbl_next_owner_id_offset = (u8)(k + 1);
+
+				/*
+				 * Construct encoded ID from the index and bit position
+				 *
+				 * Note: Last [j].k (bit 255) is never used and is marked
+				 * permanently allocated (prevents +1 overflow)
+				 */
+				*owner_id =
+				    (acpi_owner_id) ((k + 1) + ACPI_MUL_32(j));
+
+				ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
+						  "Allocated OwnerId: %2.2X\n",
+						  (unsigned int)*owner_id));
+				goto exit;
+			}
+		}
+
+		acpi_gbl_next_owner_id_offset = 0;
+	}
+
+	/*
+	 * All owner_ids have been allocated. This typically should
+	 * not happen since the IDs are reused after deallocation. The IDs are
+	 * allocated upon table load (one per table) and method execution, and
+	 * they are released when a table is unloaded or a method completes
+	 * execution.
+	 *
+	 * If this error happens, there may be very deep nesting of invoked control
+	 * methods, or there may be a bug where the IDs are not released.
+	 */
+	status = AE_OWNER_ID_LIMIT;
+	ACPI_ERROR((AE_INFO,
+		    "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT"));
+
+      exit:
+	(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_release_owner_id
+ *
+ * PARAMETERS:  owner_id_ptr        - Pointer to a previously allocated owner_ID
+ *
+ * RETURN:      None. No error is returned because we are either exiting a
+ *              control method or unloading a table. Either way, we would
+ *              ignore any error anyway.
+ *
+ * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255
+ *
+ ******************************************************************************/
+
+void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
+{
+	acpi_owner_id owner_id = *owner_id_ptr;
+	acpi_status status;
+	u32 index;
+	u32 bit;
+
+	ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id);
+
+	/* Always clear the input owner_id (zero is an invalid ID) */
+
+	*owner_id_ptr = 0;
+
+	/* Zero is not a valid owner_ID */
+
+	if (owner_id == 0) {
+		ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%2.2X", owner_id));
+		return_VOID;
+	}
+
+	/* Mutex for the global ID mask */
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
+	if (ACPI_FAILURE(status)) {
+		return_VOID;
+	}
+
+	/* Normalize the ID to zero */
+
+	owner_id--;
+
+	/* Decode ID to index/offset pair */
+
+	index = ACPI_DIV_32(owner_id);
+	bit = 1 << ACPI_MOD_32(owner_id);
+
+	/* Free the owner ID only if it is valid */
+
+	if (acpi_gbl_owner_id_mask[index] & bit) {
+		acpi_gbl_owner_id_mask[index] ^= bit;
+	} else {
+		ACPI_ERROR((AE_INFO,
+			    "Release of non-allocated OwnerId: 0x%2.2X",
+			    owner_id + 1));
+	}
+
+	(void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
+	return_VOID;
+}
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index e38bef4..cb7fa49 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -127,7 +127,9 @@
 
 const char *acpi_gbl_shr_decode[] = {
 	"Exclusive",
-	"Shared"
+	"Shared",
+	"ExclusiveAndWake",	/* ACPI 5.0 */
+	"SharedAndWake"		/* ACPI 5.0 */
 };
 
 const char *acpi_gbl_siz_decode[] = {
@@ -383,26 +385,16 @@
 	ACPI_VARIABLE_LENGTH	/* 0E *serial_bus */
 };
 
-/*
- * For the iASL compiler/disassembler, we don't want any error messages
- * because the disassembler uses the resource validation code to determine
- * if Buffer objects are actually Resource Templates.
- */
-#ifdef ACPI_ASL_COMPILER
-#define ACPI_RESOURCE_ERROR(plist)
-#else
-#define ACPI_RESOURCE_ERROR(plist)  ACPI_ERROR(plist)
-#endif
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_walk_aml_resources
  *
- * PARAMETERS:  aml             - Pointer to the raw AML resource template
- *              aml_length      - Length of the entire template
- *              user_function   - Called once for each descriptor found. If
- *                                NULL, a pointer to the end_tag is returned
- *              context         - Passed to user_function
+ * PARAMETERS:  walk_state          - Current walk info
+ * PARAMETERS:  aml                 - Pointer to the raw AML resource template
+ *              aml_length          - Length of the entire template
+ *              user_function       - Called once for each descriptor found. If
+ *                                    NULL, a pointer to the end_tag is returned
+ *              context             - Passed to user_function
  *
  * RETURN:      Status
  *
@@ -412,7 +404,8 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ut_walk_aml_resources(u8 * aml,
+acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
+			   u8 *aml,
 			   acpi_size aml_length,
 			   acpi_walk_aml_callback user_function, void **context)
 {
@@ -441,7 +434,8 @@
 
 		/* Validate the Resource Type and Resource Length */
 
-		status = acpi_ut_validate_resource(aml, &resource_index);
+		status =
+		    acpi_ut_validate_resource(walk_state, aml, &resource_index);
 		if (ACPI_FAILURE(status)) {
 			/*
 			 * Exit on failure. Cannot continue because the descriptor length
@@ -498,7 +492,8 @@
 
 		/* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */
 
-		(void)acpi_ut_validate_resource(end_tag, &resource_index);
+		(void)acpi_ut_validate_resource(walk_state, end_tag,
+						&resource_index);
 		status =
 		    user_function(end_tag, 2, offset, resource_index, context);
 		if (ACPI_FAILURE(status)) {
@@ -513,9 +508,10 @@
  *
  * FUNCTION:    acpi_ut_validate_resource
  *
- * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
- *              return_index    - Where the resource index is returned. NULL
- *                                if the index is not required.
+ * PARAMETERS:  walk_state          - Current walk info
+ *              aml                 - Pointer to the raw AML resource descriptor
+ *              return_index        - Where the resource index is returned. NULL
+ *                                    if the index is not required.
  *
  * RETURN:      Status, and optionally the Index into the global resource tables
  *
@@ -525,7 +521,9 @@
  *
  ******************************************************************************/
 
-acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
+acpi_status
+acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
+			  void *aml, u8 *return_index)
 {
 	union aml_resource *aml_resource;
 	u8 resource_type;
@@ -627,10 +625,12 @@
 		if ((aml_resource->common_serial_bus.type == 0) ||
 		    (aml_resource->common_serial_bus.type >
 		     AML_RESOURCE_MAX_SERIALBUSTYPE)) {
-			ACPI_RESOURCE_ERROR((AE_INFO,
-					     "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
-					     aml_resource->common_serial_bus.
-					     type));
+			if (walk_state) {
+				ACPI_ERROR((AE_INFO,
+					    "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
+					    aml_resource->common_serial_bus.
+					    type));
+			}
 			return (AE_AML_INVALID_RESOURCE_TYPE);
 		}
 	}
@@ -645,18 +645,22 @@
 
       invalid_resource:
 
-	ACPI_RESOURCE_ERROR((AE_INFO,
-			     "Invalid/unsupported resource descriptor: Type 0x%2.2X",
-			     resource_type));
+	if (walk_state) {
+		ACPI_ERROR((AE_INFO,
+			    "Invalid/unsupported resource descriptor: Type 0x%2.2X",
+			    resource_type));
+	}
 	return (AE_AML_INVALID_RESOURCE_TYPE);
 
       bad_resource_length:
 
-	ACPI_RESOURCE_ERROR((AE_INFO,
-			     "Invalid resource descriptor length: Type "
-			     "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
-			     resource_type, resource_length,
-			     minimum_resource_length));
+	if (walk_state) {
+		ACPI_ERROR((AE_INFO,
+			    "Invalid resource descriptor length: Type "
+			    "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
+			    resource_type, resource_length,
+			    minimum_resource_length));
+	}
 	return (AE_AML_BAD_RESOURCE_LENGTH);
 }
 
@@ -800,8 +804,7 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc,
-			     u8 ** end_tag)
+acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
 {
 	acpi_status status;
 
@@ -816,7 +819,7 @@
 
 	/* Validate the template and get a pointer to the end_tag */
 
-	status = acpi_ut_walk_aml_resources(obj_desc->buffer.pointer,
+	status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
 					    obj_desc->buffer.length, NULL,
 					    (void **)end_tag);
 
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index cee0473..a6b729d 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,14 +97,13 @@
 acpi_ut_push_generic_state(union acpi_generic_state **list_head,
 			   union acpi_generic_state *state)
 {
-	ACPI_FUNCTION_TRACE(ut_push_generic_state);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Push the state object onto the front of the list (stack) */
 
 	state->common.next = *list_head;
 	*list_head = state;
-
-	return_VOID;
+	return;
 }
 
 /*******************************************************************************
@@ -124,7 +123,7 @@
 {
 	union acpi_generic_state *state;
 
-	ACPI_FUNCTION_TRACE(ut_pop_generic_state);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Remove the state object at the head of the list (stack) */
 
@@ -136,7 +135,7 @@
 		*list_head = state->common.next;
 	}
 
-	return_PTR(state);
+	return (state);
 }
 
 /*******************************************************************************
@@ -186,13 +185,13 @@
 {
 	union acpi_generic_state *state;
 
-	ACPI_FUNCTION_TRACE(ut_create_thread_state);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Create the generic state object */
 
 	state = acpi_ut_create_generic_state();
 	if (!state) {
-		return_PTR(NULL);
+		return (NULL);
 	}
 
 	/* Init fields specific to the update struct */
@@ -207,7 +206,7 @@
 		state->thread.thread_id = (acpi_thread_id) 1;
 	}
 
-	return_PTR((struct acpi_thread_state *)state);
+	return ((struct acpi_thread_state *)state);
 }
 
 /*******************************************************************************
@@ -230,13 +229,13 @@
 {
 	union acpi_generic_state *state;
 
-	ACPI_FUNCTION_TRACE_PTR(ut_create_update_state, object);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Create the generic state object */
 
 	state = acpi_ut_create_generic_state();
 	if (!state) {
-		return_PTR(NULL);
+		return (NULL);
 	}
 
 	/* Init fields specific to the update struct */
@@ -244,8 +243,7 @@
 	state->common.descriptor_type = ACPI_DESC_TYPE_STATE_UPDATE;
 	state->update.object = object;
 	state->update.value = action;
-
-	return_PTR(state);
+	return (state);
 }
 
 /*******************************************************************************
@@ -267,13 +265,13 @@
 {
 	union acpi_generic_state *state;
 
-	ACPI_FUNCTION_TRACE_PTR(ut_create_pkg_state, internal_object);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Create the generic state object */
 
 	state = acpi_ut_create_generic_state();
 	if (!state) {
-		return_PTR(NULL);
+		return (NULL);
 	}
 
 	/* Init fields specific to the update struct */
@@ -283,8 +281,7 @@
 	state->pkg.dest_object = external_object;
 	state->pkg.index = index;
 	state->pkg.num_packages = 1;
-
-	return_PTR(state);
+	return (state);
 }
 
 /*******************************************************************************
@@ -304,21 +301,20 @@
 {
 	union acpi_generic_state *state;
 
-	ACPI_FUNCTION_TRACE(ut_create_control_state);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Create the generic state object */
 
 	state = acpi_ut_create_generic_state();
 	if (!state) {
-		return_PTR(NULL);
+		return (NULL);
 	}
 
 	/* Init fields specific to the control struct */
 
 	state->common.descriptor_type = ACPI_DESC_TYPE_STATE_CONTROL;
 	state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING;
-
-	return_PTR(state);
+	return (state);
 }
 
 /*******************************************************************************
@@ -336,12 +332,12 @@
 
 void acpi_ut_delete_generic_state(union acpi_generic_state *state)
 {
-	ACPI_FUNCTION_TRACE(ut_delete_generic_state);
+	ACPI_FUNCTION_ENTRY();
 
 	/* Ignore null state */
 
 	if (state) {
 		(void)acpi_os_release_object(acpi_gbl_state_cache, state);
 	}
-	return_VOID;
+	return;
 }
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
new file mode 100644
index 0000000..b3e36a8
--- /dev/null
+++ b/drivers/acpi/acpica/utstring.c
@@ -0,0 +1,574 @@
+/*******************************************************************************
+ *
+ * Module Name: utstring - Common functions for strings and characters
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utstring")
+
+/*
+ * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit
+ * version of strtoul.
+ */
+#ifdef ACPI_ASL_COMPILER
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strlwr (strlwr)
+ *
+ * PARAMETERS:  src_string      - The source string to convert
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Convert string to lowercase
+ *
+ * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
+ *
+ ******************************************************************************/
+void acpi_ut_strlwr(char *src_string)
+{
+	char *string;
+
+	ACPI_FUNCTION_ENTRY();
+
+	if (!src_string) {
+		return;
+	}
+
+	/* Walk entire string, lowercasing the letters */
+
+	for (string = src_string; *string; string++) {
+		*string = (char)ACPI_TOLOWER(*string);
+	}
+
+	return;
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_stricmp (stricmp)
+ *
+ * PARAMETERS:  string1             - first string to compare
+ *              string2             - second string to compare
+ *
+ * RETURN:      int that signifies string relationship. Zero means strings
+ *              are equal.
+ *
+ * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare
+ *              strings with no case sensitivity)
+ *
+ ******************************************************************************/
+
+int acpi_ut_stricmp(char *string1, char *string2)
+{
+	int c1;
+	int c2;
+
+	do {
+		c1 = tolower((int)*string1);
+		c2 = tolower((int)*string2);
+
+		string1++;
+		string2++;
+	}
+	while ((c1 == c2) && (c1));
+
+	return (c1 - c2);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strupr (strupr)
+ *
+ * PARAMETERS:  src_string      - The source string to convert
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Convert string to uppercase
+ *
+ * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
+ *
+ ******************************************************************************/
+
+void acpi_ut_strupr(char *src_string)
+{
+	char *string;
+
+	ACPI_FUNCTION_ENTRY();
+
+	if (!src_string) {
+		return;
+	}
+
+	/* Walk entire string, uppercasing the letters */
+
+	for (string = src_string; *string; string++) {
+		*string = (char)ACPI_TOUPPER(*string);
+	}
+
+	return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strtoul64
+ *
+ * PARAMETERS:  string          - Null terminated string
+ *              base            - Radix of the string: 16 or ACPI_ANY_BASE;
+ *                                ACPI_ANY_BASE means 'in behalf of to_integer'
+ *              ret_integer     - Where the converted integer is returned
+ *
+ * RETURN:      Status and Converted value
+ *
+ * DESCRIPTION: Convert a string into an unsigned value. Performs either a
+ *              32-bit or 64-bit conversion, depending on the current mode
+ *              of the interpreter.
+ *              NOTE: Does not support Octal strings, not needed.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
+{
+	u32 this_digit = 0;
+	u64 return_value = 0;
+	u64 quotient;
+	u64 dividend;
+	u32 to_integer_op = (base == ACPI_ANY_BASE);
+	u32 mode32 = (acpi_gbl_integer_byte_width == 4);
+	u8 valid_digits = 0;
+	u8 sign_of0x = 0;
+	u8 term = 0;
+
+	ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
+
+	switch (base) {
+	case ACPI_ANY_BASE:
+	case 16:
+		break;
+
+	default:
+		/* Invalid Base */
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	if (!string) {
+		goto error_exit;
+	}
+
+	/* Skip over any white space in the buffer */
+
+	while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) {
+		string++;
+	}
+
+	if (to_integer_op) {
+		/*
+		 * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'.
+		 * We need to determine if it is decimal or hexadecimal.
+		 */
+		if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) {
+			sign_of0x = 1;
+			base = 16;
+
+			/* Skip over the leading '0x' */
+			string += 2;
+		} else {
+			base = 10;
+		}
+	}
+
+	/* Any string left? Check that '0x' is not followed by white space. */
+
+	if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') {
+		if (to_integer_op) {
+			goto error_exit;
+		} else {
+			goto all_done;
+		}
+	}
+
+	/*
+	 * Perform a 32-bit or 64-bit conversion, depending upon the current
+	 * execution mode of the interpreter
+	 */
+	dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
+
+	/* Main loop: convert the string to a 32- or 64-bit integer */
+
+	while (*string) {
+		if (ACPI_IS_DIGIT(*string)) {
+
+			/* Convert ASCII 0-9 to Decimal value */
+
+			this_digit = ((u8)*string) - '0';
+		} else if (base == 10) {
+
+			/* Digit is out of range; possible in to_integer case only */
+
+			term = 1;
+		} else {
+			this_digit = (u8)ACPI_TOUPPER(*string);
+			if (ACPI_IS_XDIGIT((char)this_digit)) {
+
+				/* Convert ASCII Hex char to value */
+
+				this_digit = this_digit - 'A' + 10;
+			} else {
+				term = 1;
+			}
+		}
+
+		if (term) {
+			if (to_integer_op) {
+				goto error_exit;
+			} else {
+				break;
+			}
+		} else if ((valid_digits == 0) && (this_digit == 0)
+			   && !sign_of0x) {
+
+			/* Skip zeros */
+			string++;
+			continue;
+		}
+
+		valid_digits++;
+
+		if (sign_of0x
+		    && ((valid_digits > 16)
+			|| ((valid_digits > 8) && mode32))) {
+			/*
+			 * This is to_integer operation case.
+			 * No any restrictions for string-to-integer conversion,
+			 * see ACPI spec.
+			 */
+			goto error_exit;
+		}
+
+		/* Divide the digit into the correct position */
+
+		(void)acpi_ut_short_divide((dividend - (u64)this_digit),
+					   base, &quotient, NULL);
+
+		if (return_value > quotient) {
+			if (to_integer_op) {
+				goto error_exit;
+			} else {
+				break;
+			}
+		}
+
+		return_value *= base;
+		return_value += this_digit;
+		string++;
+	}
+
+	/* All done, normal exit */
+
+      all_done:
+
+	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
+			  ACPI_FORMAT_UINT64(return_value)));
+
+	*ret_integer = return_value;
+	return_ACPI_STATUS(AE_OK);
+
+      error_exit:
+	/* Base was set/validated above */
+
+	if (base == 10) {
+		return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT);
+	} else {
+		return_ACPI_STATUS(AE_BAD_HEX_CONSTANT);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_print_string
+ *
+ * PARAMETERS:  string          - Null terminated ASCII string
+ *              max_length      - Maximum output length
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape
+ *              sequences.
+ *
+ ******************************************************************************/
+
+void acpi_ut_print_string(char *string, u8 max_length)
+{
+	u32 i;
+
+	if (!string) {
+		acpi_os_printf("<\"NULL STRING PTR\">");
+		return;
+	}
+
+	acpi_os_printf("\"");
+	for (i = 0; string[i] && (i < max_length); i++) {
+
+		/* Escape sequences */
+
+		switch (string[i]) {
+		case 0x07:
+			acpi_os_printf("\\a");	/* BELL */
+			break;
+
+		case 0x08:
+			acpi_os_printf("\\b");	/* BACKSPACE */
+			break;
+
+		case 0x0C:
+			acpi_os_printf("\\f");	/* FORMFEED */
+			break;
+
+		case 0x0A:
+			acpi_os_printf("\\n");	/* LINEFEED */
+			break;
+
+		case 0x0D:
+			acpi_os_printf("\\r");	/* CARRIAGE RETURN */
+			break;
+
+		case 0x09:
+			acpi_os_printf("\\t");	/* HORIZONTAL TAB */
+			break;
+
+		case 0x0B:
+			acpi_os_printf("\\v");	/* VERTICAL TAB */
+			break;
+
+		case '\'':	/* Single Quote */
+		case '\"':	/* Double Quote */
+		case '\\':	/* Backslash */
+			acpi_os_printf("\\%c", (int)string[i]);
+			break;
+
+		default:
+
+			/* Check for printable character or hex escape */
+
+			if (ACPI_IS_PRINT(string[i])) {
+				/* This is a normal character */
+
+				acpi_os_printf("%c", (int)string[i]);
+			} else {
+				/* All others will be Hex escapes */
+
+				acpi_os_printf("\\x%2.2X", (s32) string[i]);
+			}
+			break;
+		}
+	}
+	acpi_os_printf("\"");
+
+	if (i == max_length && string[i]) {
+		acpi_os_printf("...");
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_valid_acpi_char
+ *
+ * PARAMETERS:  char            - The character to be examined
+ *              position        - Byte position (0-3)
+ *
+ * RETURN:      TRUE if the character is valid, FALSE otherwise
+ *
+ * DESCRIPTION: Check for a valid ACPI character. Must be one of:
+ *              1) Upper case alpha
+ *              2) numeric
+ *              3) underscore
+ *
+ *              We allow a '!' as the last character because of the ASF! table
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_valid_acpi_char(char character, u32 position)
+{
+
+	if (!((character >= 'A' && character <= 'Z') ||
+	      (character >= '0' && character <= '9') || (character == '_'))) {
+
+		/* Allow a '!' in the last position */
+
+		if (character == '!' && position == 3) {
+			return (TRUE);
+		}
+
+		return (FALSE);
+	}
+
+	return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_valid_acpi_name
+ *
+ * PARAMETERS:  name            - The name to be examined
+ *
+ * RETURN:      TRUE if the name is valid, FALSE otherwise
+ *
+ * DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
+ *              1) Upper case alpha
+ *              2) numeric
+ *              3) underscore
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_valid_acpi_name(u32 name)
+{
+	u32 i;
+
+	ACPI_FUNCTION_ENTRY();
+
+	for (i = 0; i < ACPI_NAME_SIZE; i++) {
+		if (!acpi_ut_valid_acpi_char
+		    ((ACPI_CAST_PTR(char, &name))[i], i)) {
+			return (FALSE);
+		}
+	}
+
+	return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_repair_name
+ *
+ * PARAMETERS:  name            - The ACPI name to be repaired
+ *
+ * RETURN:      Repaired version of the name
+ *
+ * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and
+ *              return the new name. NOTE: the Name parameter must reside in
+ *              read/write memory, cannot be a const.
+ *
+ * An ACPI Name must consist of valid ACPI characters. We will repair the name
+ * if necessary because we don't want to abort because of this, but we want
+ * all namespace names to be printable. A warning message is appropriate.
+ *
+ * This issue came up because there are in fact machines that exhibit
+ * this problem, and we want to be able to enable ACPI support for them,
+ * even though there are a few bad names.
+ *
+ ******************************************************************************/
+
+void acpi_ut_repair_name(char *name)
+{
+	u32 i;
+	u8 found_bad_char = FALSE;
+	u32 original_name;
+
+	ACPI_FUNCTION_NAME(ut_repair_name);
+
+	ACPI_MOVE_NAME(&original_name, name);
+
+	/* Check each character in the name */
+
+	for (i = 0; i < ACPI_NAME_SIZE; i++) {
+		if (acpi_ut_valid_acpi_char(name[i], i)) {
+			continue;
+		}
+
+		/*
+		 * Replace a bad character with something printable, yet technically
+		 * still invalid. This prevents any collisions with existing "good"
+		 * names in the namespace.
+		 */
+		name[i] = '*';
+		found_bad_char = TRUE;
+	}
+
+	if (found_bad_char) {
+
+		/* Report warning only if in strict mode or debug mode */
+
+		if (!acpi_gbl_enable_interpreter_slack) {
+			ACPI_WARNING((AE_INFO,
+				      "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]",
+				      original_name, name));
+		} else {
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					  "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]",
+					  original_name, name));
+		}
+	}
+}
+
+#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP
+/*******************************************************************************
+ *
+ * FUNCTION:    ut_convert_backslashes
+ *
+ * PARAMETERS:  pathname        - File pathname string to be converted
+ *
+ * RETURN:      Modifies the input Pathname
+ *
+ * DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within
+ *              the entire input file pathname string.
+ *
+ ******************************************************************************/
+
+void ut_convert_backslashes(char *pathname)
+{
+
+	if (!pathname) {
+		return;
+	}
+
+	while (*pathname) {
+		if (*pathname == '\\') {
+			*pathname = '/';
+		}
+
+		pathname++;
+	}
+}
+#endif
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index a424a9e..62774c7 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -436,10 +436,10 @@
 	struct acpi_memory_list *mem_list;
 	acpi_status status;
 
-	ACPI_FUNCTION_TRACE(ut_remove_allocation);
+	ACPI_FUNCTION_NAME(ut_remove_allocation);
 
 	if (acpi_gbl_disable_mem_tracking) {
-		return_ACPI_STATUS(AE_OK);
+		return (AE_OK);
 	}
 
 	mem_list = acpi_gbl_global_list;
@@ -450,12 +450,12 @@
 		ACPI_ERROR((module, line,
 			    "Empty allocation list, nothing to free!"));
 
-		return_ACPI_STATUS(AE_OK);
+		return (AE_OK);
 	}
 
 	status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
 	if (ACPI_FAILURE(status)) {
-		return_ACPI_STATUS(status);
+		return (status);
 	}
 
 	/* Unlink */
@@ -470,15 +470,15 @@
 		(allocation->next)->previous = allocation->previous;
 	}
 
+	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",
+			  &allocation->user_space, allocation->size));
+
 	/* Mark the segment as deleted */
 
 	ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n",
-			  allocation->size));
-
 	status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
-	return_ACPI_STATUS(status);
+	return (status);
 }
 
 /*******************************************************************************
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 390db0c..48efb44 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,11 +44,7 @@
 #include <linux/export.h>
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acevents.h"
-#include "acnamesp.h"
 #include "acdebug.h"
-#include "actables.h"
-#include "acinterp.h"
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utxface")
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index d4d3826..976b6c7 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -297,9 +297,9 @@
  *
  * PARAMETERS:  module_name     - Caller's module name (for error output)
  *              line_number     - Caller's line number (for error output)
- *              Pathname        - Full pathname to the node
+ *              pathname        - Full pathname to the node
  *              node_flags      - From Namespace node for the method/object
- *              Format          - Printf format string + additional args
+ *              format          - Printf format string + additional args
  *
  * RETURN:      None
  *
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 14f5236..41ebaaf 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c
index 0a40a85..3122997 100644
--- a/drivers/acpi/acpica/utxfmutex.c
+++ b/drivers/acpi/acpica/utxfmutex.c
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index e6defd8..1e5d8a4 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -29,6 +29,7 @@
 #include <linux/time.h>
 #include <linux/cper.h>
 #include <linux/acpi.h>
+#include <linux/pci.h>
 #include <linux/aer.h>
 
 /*
@@ -249,6 +250,10 @@
 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
 			    const struct acpi_hest_generic_data *gdata)
 {
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+	struct pci_dev *dev;
+#endif
+
 	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
 		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
 		       pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
@@ -281,10 +286,18 @@
 	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
 	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
 #ifdef CONFIG_ACPI_APEI_PCIEAER
-	if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
-		struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
-		cper_print_aer(pfx, gdata->error_severity, aer_regs);
+	dev = pci_get_domain_bus_and_slot(pcie->device_id.segment,
+			pcie->device_id.bus, pcie->device_id.function);
+	if (!dev) {
+		pr_err("PCI AER Cannot get PCI device %04x:%02x:%02x.%d\n",
+			pcie->device_id.segment, pcie->device_id.bus,
+			pcie->device_id.slot, pcie->device_id.function);
+		return;
 	}
+	if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO)
+		cper_print_aer(pfx, dev, gdata->error_severity,
+				(struct aer_capability_regs *) pcie->aer_info);
+	pci_dev_put(dev);
 #endif
 }
 
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 7efaeaa..c5cd5b5 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1111,7 +1111,7 @@
 	return result;
 }
 
-static int acpi_battery_remove(struct acpi_device *device, int type)
+static int acpi_battery_remove(struct acpi_device *device)
 {
 	struct acpi_battery *battery = NULL;
 
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 1f0d457..01708a1 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -178,276 +178,6 @@
 }
 EXPORT_SYMBOL(acpi_bus_get_private_data);
 
-/* --------------------------------------------------------------------------
-                                 Power Management
-   -------------------------------------------------------------------------- */
-
-static const char *state_string(int state)
-{
-	switch (state) {
-	case ACPI_STATE_D0:
-		return "D0";
-	case ACPI_STATE_D1:
-		return "D1";
-	case ACPI_STATE_D2:
-		return "D2";
-	case ACPI_STATE_D3_HOT:
-		return "D3hot";
-	case ACPI_STATE_D3_COLD:
-		return "D3";
-	default:
-		return "(unknown)";
-	}
-}
-
-static int __acpi_bus_get_power(struct acpi_device *device, int *state)
-{
-	int result = ACPI_STATE_UNKNOWN;
-
-	if (!device || !state)
-		return -EINVAL;
-
-	if (!device->flags.power_manageable) {
-		/* TBD: Non-recursive algorithm for walking up hierarchy. */
-		*state = device->parent ?
-			device->parent->power.state : ACPI_STATE_D0;
-		goto out;
-	}
-
-	/*
-	 * Get the device's power state either directly (via _PSC) or
-	 * indirectly (via power resources).
-	 */
-	if (device->power.flags.explicit_get) {
-		unsigned long long psc;
-		acpi_status status = acpi_evaluate_integer(device->handle,
-							   "_PSC", NULL, &psc);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		result = psc;
-	}
-	/* The test below covers ACPI_STATE_UNKNOWN too. */
-	if (result <= ACPI_STATE_D2) {
-	  ; /* Do nothing. */
-	} else if (device->power.flags.power_resources) {
-		int error = acpi_power_get_inferred_state(device, &result);
-		if (error)
-			return error;
-	} else if (result == ACPI_STATE_D3_HOT) {
-		result = ACPI_STATE_D3;
-	}
-
-	/*
-	 * If we were unsure about the device parent's power state up to this
-	 * point, the fact that the device is in D0 implies that the parent has
-	 * to be in D0 too.
-	 */
-	if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
-	    && result == ACPI_STATE_D0)
-		device->parent->power.state = ACPI_STATE_D0;
-
-	*state = result;
-
- out:
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
-			  device->pnp.bus_id, state_string(*state)));
-
-	return 0;
-}
-
-
-/**
- * acpi_device_set_power - Set power state of an ACPI device.
- * @device: Device to set the power state of.
- * @state: New power state to set.
- *
- * Callers must ensure that the device is power manageable before using this
- * function.
- */
-int acpi_device_set_power(struct acpi_device *device, int state)
-{
-	int result = 0;
-	acpi_status status = AE_OK;
-	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
-
-	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
-		return -EINVAL;
-
-	/* Make sure this is a valid target state */
-
-	if (state == device->power.state) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
-				  state_string(state)));
-		return 0;
-	}
-
-	if (!device->power.states[state].flags.valid) {
-		printk(KERN_WARNING PREFIX "Device does not support %s\n",
-		       state_string(state));
-		return -ENODEV;
-	}
-	if (device->parent && (state < device->parent->power.state)) {
-		printk(KERN_WARNING PREFIX
-			      "Cannot set device to a higher-powered"
-			      " state than parent\n");
-		return -ENODEV;
-	}
-
-	/* For D3cold we should execute _PS3, not _PS4. */
-	if (state == ACPI_STATE_D3_COLD)
-		object_name[3] = '3';
-
-	/*
-	 * Transition Power
-	 * ----------------
-	 * On transitions to a high-powered state we first apply power (via
-	 * power resources) then evalute _PSx.  Conversly for transitions to
-	 * a lower-powered state.
-	 */
-	if (state < device->power.state) {
-		if (device->power.state >= ACPI_STATE_D3_HOT &&
-		    state != ACPI_STATE_D0) {
-			printk(KERN_WARNING PREFIX
-			      "Cannot transition to non-D0 state from D3\n");
-			return -ENODEV;
-		}
-		if (device->power.flags.power_resources) {
-			result = acpi_power_transition(device, state);
-			if (result)
-				goto end;
-		}
-		if (device->power.states[state].flags.explicit_set) {
-			status = acpi_evaluate_object(device->handle,
-						      object_name, NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				result = -ENODEV;
-				goto end;
-			}
-		}
-	} else {
-		if (device->power.states[state].flags.explicit_set) {
-			status = acpi_evaluate_object(device->handle,
-						      object_name, NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				result = -ENODEV;
-				goto end;
-			}
-		}
-		if (device->power.flags.power_resources) {
-			result = acpi_power_transition(device, state);
-			if (result)
-				goto end;
-		}
-	}
-
-      end:
-	if (result)
-		printk(KERN_WARNING PREFIX
-			      "Device [%s] failed to transition to %s\n",
-			      device->pnp.bus_id, state_string(state));
-	else {
-		device->power.state = state;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Device [%s] transitioned to %s\n",
-				  device->pnp.bus_id, state_string(state)));
-	}
-
-	return result;
-}
-EXPORT_SYMBOL(acpi_device_set_power);
-
-
-int acpi_bus_set_power(acpi_handle handle, int state)
-{
-	struct acpi_device *device;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	if (result)
-		return result;
-
-	if (!device->flags.power_manageable) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				"Device [%s] is not power manageable\n",
-				dev_name(&device->dev)));
-		return -ENODEV;
-	}
-
-	return acpi_device_set_power(device, state);
-}
-EXPORT_SYMBOL(acpi_bus_set_power);
-
-
-int acpi_bus_init_power(struct acpi_device *device)
-{
-	int state;
-	int result;
-
-	if (!device)
-		return -EINVAL;
-
-	device->power.state = ACPI_STATE_UNKNOWN;
-
-	result = __acpi_bus_get_power(device, &state);
-	if (result)
-		return result;
-
-	if (device->power.flags.power_resources)
-		result = acpi_power_on_resources(device, state);
-
-	if (!result)
-		device->power.state = state;
-
-	return result;
-}
-
-
-int acpi_bus_update_power(acpi_handle handle, int *state_p)
-{
-	struct acpi_device *device;
-	int state;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	if (result)
-		return result;
-
-	result = __acpi_bus_get_power(device, &state);
-	if (result)
-		return result;
-
-	result = acpi_device_set_power(device, state);
-	if (!result && state_p)
-		*state_p = state;
-
-	return result;
-}
-EXPORT_SYMBOL_GPL(acpi_bus_update_power);
-
-
-bool acpi_bus_power_manageable(acpi_handle handle)
-{
-	struct acpi_device *device;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	return result ? false : device->flags.power_manageable;
-}
-
-EXPORT_SYMBOL(acpi_bus_power_manageable);
-
-bool acpi_bus_can_wakeup(acpi_handle handle)
-{
-	struct acpi_device *device;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	return result ? false : device->wakeup.flags.valid;
-}
-
-EXPORT_SYMBOL(acpi_bus_can_wakeup);
-
 static void acpi_print_osc_error(acpi_handle handle,
 	struct acpi_osc_context *context, char *error)
 {
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index f0d936b..86c7d54 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -75,7 +75,7 @@
 MODULE_DEVICE_TABLE(acpi, button_device_ids);
 
 static int acpi_button_add(struct acpi_device *device);
-static int acpi_button_remove(struct acpi_device *device, int type);
+static int acpi_button_remove(struct acpi_device *device);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
 
 #ifdef CONFIG_PM_SLEEP
@@ -433,7 +433,7 @@
 	return error;
 }
 
-static int acpi_button_remove(struct acpi_device *device, int type)
+static int acpi_button_remove(struct acpi_device *device)
 {
 	struct acpi_button *button = acpi_driver_data(device);
 
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 811910b..5523ba7 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -34,46 +34,34 @@
 #include <linux/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
-#include <acpi/container.h>
 
 #define PREFIX "ACPI: "
 
-#define ACPI_CONTAINER_DEVICE_NAME	"ACPI container device"
-#define ACPI_CONTAINER_CLASS		"container"
-
-#define INSTALL_NOTIFY_HANDLER		1
-#define UNINSTALL_NOTIFY_HANDLER	2
-
 #define _COMPONENT			ACPI_CONTAINER_COMPONENT
 ACPI_MODULE_NAME("container");
 
-MODULE_AUTHOR("Anil S Keshavamurthy");
-MODULE_DESCRIPTION("ACPI container driver");
-MODULE_LICENSE("GPL");
-
-static int acpi_container_add(struct acpi_device *device);
-static int acpi_container_remove(struct acpi_device *device, int type);
-
 static const struct acpi_device_id container_device_ids[] = {
 	{"ACPI0004", 0},
 	{"PNP0A05", 0},
 	{"PNP0A06", 0},
 	{"", 0},
 };
-MODULE_DEVICE_TABLE(acpi, container_device_ids);
 
-static struct acpi_driver acpi_container_driver = {
-	.name = "container",
-	.class = ACPI_CONTAINER_CLASS,
+static int container_device_attach(struct acpi_device *device,
+				   const struct acpi_device_id *not_used)
+{
+	/*
+	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
+	 * -ENODEV for containers.
+	 */
+	return 1;
+}
+
+static struct acpi_scan_handler container_device_handler = {
 	.ids = container_device_ids,
-	.ops = {
-		.add = acpi_container_add,
-		.remove = acpi_container_remove,
-		},
+	.attach = container_device_attach,
 };
 
-/*******************************************************************/
-
 static int is_device_present(acpi_handle handle)
 {
 	acpi_handle temp;
@@ -92,73 +80,6 @@
 	return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
 }
 
-static bool is_container_device(const char *hid)
-{
-	const struct acpi_device_id *container_id;
-
-	for (container_id = container_device_ids;
-	     container_id->id[0]; container_id++) {
-		if (!strcmp((char *)container_id->id, hid))
-			return true;
-	}
-
-	return false;
-}
-
-/*******************************************************************/
-static int acpi_container_add(struct acpi_device *device)
-{
-	struct acpi_container *container;
-
-	container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
-	if (!container)
-		return -ENOMEM;
-
-	container->handle = device->handle;
-	strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
-	strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
-	device->driver_data = container;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
-			  acpi_device_name(device), acpi_device_bid(device)));
-
-	return 0;
-}
-
-static int acpi_container_remove(struct acpi_device *device, int type)
-{
-	acpi_status status = AE_OK;
-	struct acpi_container *pc = NULL;
-
-	pc = acpi_driver_data(device);
-	kfree(pc);
-	return status;
-}
-
-static int container_device_add(struct acpi_device **device, acpi_handle handle)
-{
-	acpi_handle phandle;
-	struct acpi_device *pdev;
-	int result;
-
-
-	if (acpi_get_parent(handle, &phandle)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_get_device(phandle, &pdev)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
-		return -ENODEV;
-	}
-
-	result = acpi_bus_start(*device);
-
-	return result;
-}
-
 static void container_notify_cb(acpi_handle handle, u32 type, void *context)
 {
 	struct acpi_device *device = NULL;
@@ -167,6 +88,8 @@
 	acpi_status status;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 
+	acpi_scan_lock_acquire();
+
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* Fall through */
@@ -182,7 +105,7 @@
 				/* device exist and this is a remove request */
 				device->flags.eject_pending = 1;
 				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-				return;
+				goto out;
 			}
 			break;
 		}
@@ -190,11 +113,16 @@
 		if (!ACPI_FAILURE(status) || device)
 			break;
 
-		result = container_device_add(&device, handle);
+		result = acpi_bus_scan(handle);
 		if (result) {
 			acpi_handle_warn(handle, "Failed to add container\n");
 			break;
 		}
+		result = acpi_bus_get_device(handle, &device);
+		if (result) {
+			acpi_handle_warn(handle, "Missing device object\n");
+			break;
+		}
 
 		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 		ost_code = ACPI_OST_SC_SUCCESS;
@@ -204,98 +132,59 @@
 		if (!acpi_bus_get_device(handle, &device) && device) {
 			device->flags.eject_pending = 1;
 			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-			return;
+			goto out;
 		}
 		break;
 
 	default:
 		/* non-hotplug event; possibly handled by other handler */
-		return;
+		goto out;
 	}
 
 	/* Inform firmware that the hotplug operation has completed */
 	(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-	return;
+
+ out:
+	acpi_scan_lock_release();
 }
 
-static acpi_status
-container_walk_namespace_cb(acpi_handle handle,
-			    u32 lvl, void *context, void **rv)
+static bool is_container(acpi_handle handle)
 {
-	char *hid = NULL;
 	struct acpi_device_info *info;
-	acpi_status status;
-	int *action = context;
+	bool ret = false;
 
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_FAILURE(status)) {
-		return AE_OK;
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return false;
+
+	if (info->valid & ACPI_VALID_HID) {
+		const struct acpi_device_id *id;
+
+		for (id = container_device_ids; id->id[0]; id++) {
+			ret = !strcmp((char *)id->id, info->hardware_id.string);
+			if (ret)
+				break;
+		}
 	}
-
-	if (info->valid & ACPI_VALID_HID)
-		hid = info->hardware_id.string;
-
-	if (hid == NULL) {
-		goto end;
-	}
-
-	if (!is_container_device(hid))
-		goto end;
-
-	switch (*action) {
-	case INSTALL_NOTIFY_HANDLER:
-		acpi_install_notify_handler(handle,
-					    ACPI_SYSTEM_NOTIFY,
-					    container_notify_cb, NULL);
-		break;
-	case UNINSTALL_NOTIFY_HANDLER:
-		acpi_remove_notify_handler(handle,
-					   ACPI_SYSTEM_NOTIFY,
-					   container_notify_cb);
-		break;
-	default:
-		break;
-	}
-
-      end:
 	kfree(info);
+	return ret;
+}
+
+static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
+							  u32 lvl, void *ctxt,
+							  void **retv)
+{
+	if (is_container(handle))
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    container_notify_cb, NULL);
 
 	return AE_OK;
 }
 
-static int __init acpi_container_init(void)
+void __init acpi_container_init(void)
 {
-	int result = 0;
-	int action = INSTALL_NOTIFY_HANDLER;
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+			    acpi_container_register_notify_handler, NULL,
+			    NULL, NULL);
 
-	result = acpi_bus_register_driver(&acpi_container_driver);
-	if (result < 0) {
-		return (result);
-	}
-
-	/* register notify handler to every container device */
-	acpi_walk_namespace(ACPI_TYPE_DEVICE,
-			    ACPI_ROOT_OBJECT,
-			    ACPI_UINT32_MAX,
-			    container_walk_namespace_cb, NULL, &action, NULL);
-
-	return (0);
+	acpi_scan_add_handler(&container_device_handler);
 }
-
-static void __exit acpi_container_exit(void)
-{
-	int action = UNINSTALL_NOTIFY_HANDLER;
-
-
-	acpi_walk_namespace(ACPI_TYPE_DEVICE,
-			    ACPI_ROOT_OBJECT,
-			    ACPI_UINT32_MAX,
-			    container_walk_namespace_cb, NULL, &action, NULL);
-
-	acpi_bus_unregister_driver(&acpi_container_driver);
-
-	return;
-}
-
-module_init(acpi_container_init);
-module_exit(acpi_container_exit);
diff --git a/drivers/acpi/csrt.c b/drivers/acpi/csrt.c
new file mode 100644
index 0000000..5c15a91
--- /dev/null
+++ b/drivers/acpi/csrt.c
@@ -0,0 +1,159 @@
+/*
+ * Support for Core System Resources Table (CSRT)
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *	    Andy Shevchenko <andriy.shevchenko@linux.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.
+ */
+
+#define pr_fmt(fmt) "ACPI: CSRT: " fmt
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+
+ACPI_MODULE_NAME("CSRT");
+
+static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev,
+					      const struct acpi_csrt_group *grp)
+{
+	const struct acpi_csrt_shared_info *si;
+	struct resource res[3];
+	size_t nres;
+	int ret;
+
+	memset(res, 0, sizeof(res));
+	nres = 0;
+
+	si = (const struct acpi_csrt_shared_info *)&grp[1];
+	/*
+	 * The peripherals that are listed on CSRT typically support only
+	 * 32-bit addresses so we only use the low part of MMIO base for
+	 * now.
+	 */
+	if (!si->mmio_base_high && si->mmio_base_low) {
+		/*
+		 * There is no size of the memory resource in shared_info
+		 * so we assume that it is 4k here.
+		 */
+		res[nres].start = si->mmio_base_low;
+		res[nres].end = res[0].start + SZ_4K - 1;
+		res[nres++].flags = IORESOURCE_MEM;
+	}
+
+	if (si->gsi_interrupt) {
+		int irq = acpi_register_gsi(NULL, si->gsi_interrupt,
+					    si->interrupt_mode,
+					    si->interrupt_polarity);
+		res[nres].start = irq;
+		res[nres].end = irq;
+		res[nres++].flags = IORESOURCE_IRQ;
+	}
+
+	if (si->base_request_line || si->num_handshake_signals) {
+		/*
+		 * We pass the driver a DMA resource describing the range
+		 * of request lines the device supports.
+		 */
+		res[nres].start = si->base_request_line;
+		res[nres].end = res[nres].start + si->num_handshake_signals - 1;
+		res[nres++].flags = IORESOURCE_DMA;
+	}
+
+	ret = platform_device_add_resources(pdev, res, nres);
+	if (ret) {
+		if (si->gsi_interrupt)
+			acpi_unregister_gsi(si->gsi_interrupt);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __init
+acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp)
+{
+	struct platform_device *pdev;
+	char vendor[5], name[16];
+	int ret, i;
+
+	vendor[0] = grp->vendor_id;
+	vendor[1] = grp->vendor_id >> 8;
+	vendor[2] = grp->vendor_id >> 16;
+	vendor[3] = grp->vendor_id >> 24;
+	vendor[4] = '\0';
+
+	if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
+		return -ENODEV;
+
+	snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id);
+	pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO);
+	if (!pdev)
+		return -ENOMEM;
+
+	/* Add resources based on the shared info */
+	ret = acpi_csrt_parse_shared_info(pdev, grp);
+	if (ret)
+		goto fail;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto fail;
+
+	for (i = 0; i < pdev->num_resources; i++)
+		dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]);
+
+	return 0;
+
+fail:
+	platform_device_put(pdev);
+	return ret;
+}
+
+/*
+ * CSRT or Core System Resources Table is a proprietary ACPI table
+ * introduced by Microsoft. This table can contain devices that are not in
+ * the system DSDT table. In particular DMA controllers might be described
+ * here.
+ *
+ * We present these devices as normal platform devices that don't have ACPI
+ * IDs or handle. The platform device name will be something like
+ * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto.
+ */
+void __init acpi_csrt_init(void)
+{
+	struct acpi_csrt_group *grp, *end;
+	struct acpi_table_csrt *csrt;
+	acpi_status status;
+	int ret;
+
+	status = acpi_get_table(ACPI_SIG_CSRT, 0,
+				(struct acpi_table_header **)&csrt);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			pr_warn("failed to get the CSRT table\n");
+		return;
+	}
+
+	pr_debug("parsing CSRT table for devices\n");
+
+	grp = (struct acpi_csrt_group *)(csrt + 1);
+	end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
+
+	while (grp < end) {
+		ret = acpi_csrt_parse_resource_group(grp);
+		if (ret) {
+			pr_warn("error in parsing resource group: %d\n", ret);
+			return;
+		}
+
+		grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
+	}
+}
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
index 5d42c24..6adfc70 100644
--- a/drivers/acpi/custom_method.c
+++ b/drivers/acpi/custom_method.c
@@ -1,5 +1,5 @@
 /*
- * debugfs.c - ACPI debugfs interface to userspace.
+ * custom_method.c - debugfs interface for customizing ACPI control method
  */
 
 #include <linux/init.h>
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index c6ff606..dd314ef 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -30,6 +30,12 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
+
+#define _COMPONENT	ACPI_POWER_COMPONENT
+ACPI_MODULE_NAME("device_pm");
 
 static DEFINE_MUTEX(acpi_pm_notifier_lock);
 
@@ -94,6 +100,293 @@
 }
 
 /**
+ * acpi_power_state_string - String representation of ACPI device power state.
+ * @state: ACPI device power state to return the string representation of.
+ */
+const char *acpi_power_state_string(int state)
+{
+	switch (state) {
+	case ACPI_STATE_D0:
+		return "D0";
+	case ACPI_STATE_D1:
+		return "D1";
+	case ACPI_STATE_D2:
+		return "D2";
+	case ACPI_STATE_D3_HOT:
+		return "D3hot";
+	case ACPI_STATE_D3_COLD:
+		return "D3cold";
+	default:
+		return "(unknown)";
+	}
+}
+
+/**
+ * acpi_device_get_power - Get power state of an ACPI device.
+ * @device: Device to get the power state of.
+ * @state: Place to store the power state of the device.
+ *
+ * This function does not update the device's power.state field, but it may
+ * update its parent's power.state field (when the parent's power state is
+ * unknown and the device's power state turns out to be D0).
+ */
+int acpi_device_get_power(struct acpi_device *device, int *state)
+{
+	int result = ACPI_STATE_UNKNOWN;
+
+	if (!device || !state)
+		return -EINVAL;
+
+	if (!device->flags.power_manageable) {
+		/* TBD: Non-recursive algorithm for walking up hierarchy. */
+		*state = device->parent ?
+			device->parent->power.state : ACPI_STATE_D0;
+		goto out;
+	}
+
+	/*
+	 * Get the device's power state either directly (via _PSC) or
+	 * indirectly (via power resources).
+	 */
+	if (device->power.flags.explicit_get) {
+		unsigned long long psc;
+		acpi_status status = acpi_evaluate_integer(device->handle,
+							   "_PSC", NULL, &psc);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		result = psc;
+	}
+	/* The test below covers ACPI_STATE_UNKNOWN too. */
+	if (result <= ACPI_STATE_D2) {
+	  ; /* Do nothing. */
+	} else if (device->power.flags.power_resources) {
+		int error = acpi_power_get_inferred_state(device, &result);
+		if (error)
+			return error;
+	} else if (result == ACPI_STATE_D3_HOT) {
+		result = ACPI_STATE_D3;
+	}
+
+	/*
+	 * If we were unsure about the device parent's power state up to this
+	 * point, the fact that the device is in D0 implies that the parent has
+	 * to be in D0 too.
+	 */
+	if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
+	    && result == ACPI_STATE_D0)
+		device->parent->power.state = ACPI_STATE_D0;
+
+	*state = result;
+
+ out:
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
+			  device->pnp.bus_id, acpi_power_state_string(*state)));
+
+	return 0;
+}
+
+static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
+{
+	if (adev->power.states[state].flags.explicit_set) {
+		char method[5] = { '_', 'P', 'S', '0' + state, '\0' };
+		acpi_status status;
+
+		status = acpi_evaluate_object(adev->handle, method, NULL, NULL);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+	}
+	return 0;
+}
+
+/**
+ * acpi_device_set_power - Set power state of an ACPI device.
+ * @device: Device to set the power state of.
+ * @state: New power state to set.
+ *
+ * Callers must ensure that the device is power manageable before using this
+ * function.
+ */
+int acpi_device_set_power(struct acpi_device *device, int state)
+{
+	int result = 0;
+	bool cut_power = false;
+
+	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+		return -EINVAL;
+
+	/* Make sure this is a valid target state */
+
+	if (state == device->power.state) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+				  acpi_power_state_string(state)));
+		return 0;
+	}
+
+	if (!device->power.states[state].flags.valid) {
+		printk(KERN_WARNING PREFIX "Device does not support %s\n",
+		       acpi_power_state_string(state));
+		return -ENODEV;
+	}
+	if (device->parent && (state < device->parent->power.state)) {
+		printk(KERN_WARNING PREFIX
+			      "Cannot set device to a higher-powered"
+			      " state than parent\n");
+		return -ENODEV;
+	}
+
+	/* For D3cold we should first transition into D3hot. */
+	if (state == ACPI_STATE_D3_COLD
+	    && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
+		state = ACPI_STATE_D3_HOT;
+		cut_power = true;
+	}
+
+	if (state < device->power.state && state != ACPI_STATE_D0
+	    && device->power.state >= ACPI_STATE_D3_HOT) {
+		printk(KERN_WARNING PREFIX
+			"Cannot transition to non-D0 state from D3\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Transition Power
+	 * ----------------
+	 * In accordance with the ACPI specification first apply power (via
+	 * power resources) and then evalute _PSx.
+	 */
+	if (device->power.flags.power_resources) {
+		result = acpi_power_transition(device, state);
+		if (result)
+			goto end;
+	}
+	result = acpi_dev_pm_explicit_set(device, state);
+	if (result)
+		goto end;
+
+	if (cut_power) {
+		device->power.state = state;
+		state = ACPI_STATE_D3_COLD;
+		result = acpi_power_transition(device, state);
+	}
+
+ end:
+	if (result) {
+		printk(KERN_WARNING PREFIX
+			      "Device [%s] failed to transition to %s\n",
+			      device->pnp.bus_id,
+			      acpi_power_state_string(state));
+	} else {
+		device->power.state = state;
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Device [%s] transitioned to %s\n",
+				  device->pnp.bus_id,
+				  acpi_power_state_string(state)));
+	}
+
+	return result;
+}
+EXPORT_SYMBOL(acpi_device_set_power);
+
+int acpi_bus_set_power(acpi_handle handle, int state)
+{
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	if (result)
+		return result;
+
+	if (!device->flags.power_manageable) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"Device [%s] is not power manageable\n",
+				dev_name(&device->dev)));
+		return -ENODEV;
+	}
+
+	return acpi_device_set_power(device, state);
+}
+EXPORT_SYMBOL(acpi_bus_set_power);
+
+int acpi_bus_init_power(struct acpi_device *device)
+{
+	int state;
+	int result;
+
+	if (!device)
+		return -EINVAL;
+
+	device->power.state = ACPI_STATE_UNKNOWN;
+
+	result = acpi_device_get_power(device, &state);
+	if (result)
+		return result;
+
+	if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
+		result = acpi_power_on_resources(device, state);
+		if (result)
+			return result;
+
+		result = acpi_dev_pm_explicit_set(device, state);
+		if (result)
+			return result;
+	} else if (state == ACPI_STATE_UNKNOWN) {
+		/* No power resources and missing _PSC? Try to force D0. */
+		state = ACPI_STATE_D0;
+		result = acpi_dev_pm_explicit_set(device, state);
+		if (result)
+			return result;
+	}
+	device->power.state = state;
+	return 0;
+}
+
+int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+	struct acpi_device *device;
+	int state;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	if (result)
+		return result;
+
+	result = acpi_device_get_power(device, &state);
+	if (result)
+		return result;
+
+	if (state == ACPI_STATE_UNKNOWN)
+		state = ACPI_STATE_D0;
+
+	result = acpi_device_set_power(device, state);
+	if (!result && state_p)
+		*state_p = state;
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_update_power);
+
+bool acpi_bus_power_manageable(acpi_handle handle)
+{
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	return result ? false : device->flags.power_manageable;
+}
+EXPORT_SYMBOL(acpi_bus_power_manageable);
+
+bool acpi_bus_can_wakeup(acpi_handle handle)
+{
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	return result ? false : device->wakeup.flags.valid;
+}
+EXPORT_SYMBOL(acpi_bus_can_wakeup);
+
+/**
  * acpi_device_power_state - Get preferred power state of ACPI device.
  * @dev: Device whose preferred target power state to return.
  * @adev: ACPI device node corresponding to @dev.
@@ -213,7 +506,7 @@
 	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
 	struct acpi_device *adev;
 
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+	if (!handle || acpi_bus_get_device(handle, &adev)) {
 		dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
 		return -ENODEV;
 	}
@@ -290,7 +583,7 @@
 		return -EINVAL;
 
 	handle = DEVICE_ACPI_HANDLE(phys_dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+	if (!handle || acpi_bus_get_device(handle, &adev)) {
 		dev_dbg(phys_dev, "ACPI handle without context in %s!\n",
 			__func__);
 		return -ENODEV;
@@ -304,7 +597,7 @@
 				      void *context) {}
 #endif /* CONFIG_PM_RUNTIME */
 
- #ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_SLEEP
 /**
  * __acpi_device_sleep_wake - Enable or disable device to wake up the system.
  * @dev: Device to enable/desible to wake up the system.
@@ -334,7 +627,7 @@
 		return -EINVAL;
 
 	handle = DEVICE_ACPI_HANDLE(dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+	if (!handle || acpi_bus_get_device(handle, &adev)) {
 		dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
 		return -ENODEV;
 	}
@@ -353,7 +646,7 @@
  * acpi_dev_pm_get_node - Get ACPI device node for the given physical device.
  * @dev: Device to get the ACPI node for.
  */
-static struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
+struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
 {
 	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
 	struct acpi_device *adev;
@@ -665,3 +958,59 @@
 	}
 }
 EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);
+
+/**
+ * acpi_dev_pm_add_dependent - Add physical device depending for PM.
+ * @handle: Handle of ACPI device node.
+ * @depdev: Device depending on that node for PM.
+ */
+void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev)
+{
+	struct acpi_device_physical_node *dep;
+	struct acpi_device *adev;
+
+	if (!depdev || acpi_bus_get_device(handle, &adev))
+		return;
+
+	mutex_lock(&adev->physical_node_lock);
+
+	list_for_each_entry(dep, &adev->power_dependent, node)
+		if (dep->dev == depdev)
+			goto out;
+
+	dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+	if (dep) {
+		dep->dev = depdev;
+		list_add_tail(&dep->node, &adev->power_dependent);
+	}
+
+ out:
+	mutex_unlock(&adev->physical_node_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent);
+
+/**
+ * acpi_dev_pm_remove_dependent - Remove physical device depending for PM.
+ * @handle: Handle of ACPI device node.
+ * @depdev: Device depending on that node for PM.
+ */
+void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
+{
+	struct acpi_device_physical_node *dep;
+	struct acpi_device *adev;
+
+	if (!depdev || acpi_bus_get_device(handle, &adev))
+		return;
+
+	mutex_lock(&adev->physical_node_lock);
+
+	list_for_each_entry(dep, &adev->power_dependent, node)
+		if (dep->dev == depdev) {
+			list_del(&dep->node);
+			kfree(dep);
+			break;
+		}
+
+	mutex_unlock(&adev->physical_node_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index f32bd47..4fdea38 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -310,8 +310,6 @@
 static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
 {
 	struct acpi_device *device;
-	struct acpi_device *parent_device;
-	acpi_handle parent;
 	int ret;
 
 	if (acpi_bus_get_device(handle, &device)) {
@@ -319,16 +317,11 @@
 		 * no device created for this object,
 		 * so we should create one.
 		 */
-		acpi_get_parent(handle, &parent);
-		if (acpi_bus_get_device(parent, &parent_device))
-			parent_device = NULL;
-
-		ret = acpi_bus_add(&device, parent_device, handle,
-			ACPI_BUS_TYPE_DEVICE);
-		if (ret) {
+		ret = acpi_bus_scan(handle);
+		if (ret)
 			pr_debug("error adding bus, %x\n", -ret);
-			return NULL;
-		}
+
+		acpi_bus_get_device(handle, &device);
 	}
 	return device;
 }
@@ -343,13 +336,9 @@
 static void dock_remove_acpi_device(acpi_handle handle)
 {
 	struct acpi_device *device;
-	int ret;
 
-	if (!acpi_bus_get_device(handle, &device)) {
-		ret = acpi_bus_trim(device, 1);
-		if (ret)
-			pr_debug("error removing bus, %x\n", -ret);
-	}
+	if (!acpi_bus_get_device(handle, &device))
+		acpi_bus_trim(device);
 }
 
 /**
@@ -755,7 +744,9 @@
 {
 	struct dock_data *data = context;
 
+	acpi_scan_lock_acquire();
 	dock_notify(data->handle, data->event, data->ds);
+	acpi_scan_lock_release();
 	kfree(data);
 }
 
@@ -768,20 +759,31 @@
 	if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
 	   && event != ACPI_NOTIFY_EJECT_REQUEST)
 		return 0;
+
+	acpi_scan_lock_acquire();
+
 	list_for_each_entry(dock_station, &dock_stations, sibling) {
 		if (dock_station->handle == handle) {
 			struct dock_data *dd;
+			acpi_status status;
 
 			dd = kmalloc(sizeof(*dd), GFP_KERNEL);
 			if (!dd)
-				return 0;
+				break;
+
 			dd->handle = handle;
 			dd->event = event;
 			dd->ds = dock_station;
-			acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
-			return 0 ;
+			status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
+							 dd);
+			if (ACPI_FAILURE(status))
+				kfree(dd);
+
+			break;
 		}
 	}
+
+	acpi_scan_lock_release();
 	return 0;
 }
 
@@ -836,7 +838,7 @@
 
 	struct dock_station *dock_station = dev->platform_data;
 
-	if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
+	if (!acpi_bus_get_device(dock_station->handle, &tmp))
 		return snprintf(buf, PAGE_SIZE, "1\n");
 	return snprintf(buf, PAGE_SIZE, "0\n");
 }
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 354007d..d45b287 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -852,7 +852,7 @@
 	return ret;
 }
 
-static int acpi_ec_remove(struct acpi_device *device, int type)
+static int acpi_ec_remove(struct acpi_device *device)
 {
 	struct acpi_ec *ec;
 	struct acpi_ec_query_handler *handler, *tmp;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 3bd6a54..f815da8 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -45,7 +45,7 @@
 MODULE_LICENSE("GPL");
 
 static int acpi_fan_add(struct acpi_device *device);
-static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_remove(struct acpi_device *device);
 
 static const struct acpi_device_id fan_device_ids[] = {
 	{"PNP0C0B", 0},
@@ -172,7 +172,7 @@
 	return result;
 }
 
-static int acpi_fan_remove(struct acpi_device *device, int type)
+static int acpi_fan_remove(struct acpi_device *device)
 {
 	struct thermal_cooling_device *cdev = acpi_driver_data(device);
 
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 35da181..ef6f155 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -68,6 +68,9 @@
 {
 	struct acpi_bus_type *tmp, *ret = NULL;
 
+	if (!type)
+		return NULL;
+
 	down_read(&bus_type_sem);
 	list_for_each_entry(tmp, &bus_type_list, list) {
 		if (tmp->bus == type) {
@@ -95,40 +98,31 @@
 	return ret;
 }
 
-/* Get device's handler per its address under its parent */
-struct acpi_find_child {
-	acpi_handle handle;
-	u64 address;
-};
-
-static acpi_status
-do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used,
+				      void *addr_p, void **ret_p)
 {
+	unsigned long long addr;
 	acpi_status status;
-	struct acpi_device_info *info;
-	struct acpi_find_child *find = context;
 
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_SUCCESS(status)) {
-		if ((info->address == find->address)
-			&& (info->valid & ACPI_VALID_ADR))
-			find->handle = handle;
-		kfree(info);
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
+	if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) {
+		*ret_p = handle;
+		return AE_CTRL_TERMINATE;
 	}
 	return AE_OK;
 }
 
 acpi_handle acpi_get_child(acpi_handle parent, u64 address)
 {
-	struct acpi_find_child find = { NULL, address };
+	void *ret = NULL;
 
 	if (!parent)
 		return NULL;
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, parent,
-			    1, do_acpi_find_child, NULL, &find, NULL);
-	return find.handle;
-}
 
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, NULL,
+			    do_acpi_find_child, &address, &ret);
+	return (acpi_handle)ret;
+}
 EXPORT_SYMBOL(acpi_get_child);
 
 static int acpi_bind_one(struct device *dev, acpi_handle handle)
@@ -269,28 +263,39 @@
 {
 	struct acpi_bus_type *type;
 	acpi_handle handle;
-	int ret = -EINVAL;
+	int ret;
 
 	ret = acpi_bind_one(dev, NULL);
-	if (!ret)
-		goto out;
-
-	if (!dev->bus || !dev->parent) {
+	if (ret && (!dev->bus || !dev->parent)) {
 		/* bridge devices genernally haven't bus or parent */
 		ret = acpi_find_bridge_device(dev, &handle);
-		goto end;
+		if (!ret) {
+			ret = acpi_bind_one(dev, handle);
+			if (ret)
+				goto out;
+		}
 	}
+
 	type = acpi_get_bus_type(dev->bus);
-	if (!type) {
-		DBG("No ACPI bus support for %s\n", dev_name(dev));
-		ret = -EINVAL;
-		goto end;
+	if (ret) {
+		if (!type || !type->find_device) {
+			DBG("No ACPI bus support for %s\n", dev_name(dev));
+			ret = -EINVAL;
+			goto out;
+		}
+
+		ret = type->find_device(dev, &handle);
+		if (ret) {
+			DBG("Unable to get handle for %s\n", dev_name(dev));
+			goto out;
+		}
+		ret = acpi_bind_one(dev, handle);
+		if (ret)
+			goto out;
 	}
-	if ((ret = type->find_device(dev, &handle)) != 0)
-		DBG("Can't get handler for %s\n", dev_name(dev));
- end:
-	if (!ret)
-		acpi_bind_one(dev, handle);
+
+	if (type && type->setup)
+		type->setup(dev);
 
  out:
 #if ACPI_GLUE_DEBUG
@@ -309,6 +314,12 @@
 
 static int acpi_platform_notify_remove(struct device *dev)
 {
+	struct acpi_bus_type *type;
+
+	type = acpi_get_bus_type(dev->bus);
+	if (type && type->cleanup)
+		type->cleanup(dev);
+
 	acpi_unbind_one(dev);
 	return 0;
 }
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
index a0cc796..13b1d39 100644
--- a/drivers/acpi/hed.c
+++ b/drivers/acpi/hed.c
@@ -70,7 +70,7 @@
 	return 0;
 }
 
-static int acpi_hed_remove(struct acpi_device *device, int type)
+static int acpi_hed_remove(struct acpi_device *device)
 {
 	hed_handle = NULL;
 	return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 3c407cd..7909232 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -25,7 +25,16 @@
 
 int init_acpi_device_notify(void);
 int acpi_scan_init(void);
+void acpi_pci_root_init(void);
+void acpi_pci_link_init(void);
+void acpi_platform_init(void);
 int acpi_sysfs_init(void);
+void acpi_csrt_init(void);
+#ifdef CONFIG_ACPI_CONTAINER
+void acpi_container_init(void);
+#else
+static inline void acpi_container_init(void) {}
+#endif
 
 #ifdef CONFIG_DEBUG_FS
 extern struct dentry *acpi_debugfs_dir;
@@ -35,15 +44,33 @@
 #endif
 
 /* --------------------------------------------------------------------------
+                     Device Node Initialization / Removal
+   -------------------------------------------------------------------------- */
+#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
+			  ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
+
+int acpi_device_add(struct acpi_device *device,
+		    void (*release)(struct device *));
+void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
+			     int type, unsigned long long sta);
+void acpi_device_add_finalize(struct acpi_device *device);
+void acpi_free_ids(struct acpi_device *device);
+
+/* --------------------------------------------------------------------------
                                   Power Resource
    -------------------------------------------------------------------------- */
 int acpi_power_init(void);
+void acpi_power_resources_list_free(struct list_head *list);
+int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
+				 struct list_head *list);
+int acpi_add_power_resource(acpi_handle handle);
+void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
+int acpi_power_min_system_level(struct list_head *list);
 int acpi_device_sleep_wake(struct acpi_device *dev,
                            int enable, int sleep_state, int dev_state);
 int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
 int acpi_power_on_resources(struct acpi_device *device, int state);
 int acpi_power_transition(struct acpi_device *device, int state);
-int acpi_bus_init_power(struct acpi_device *device);
 
 int acpi_wakeup_device_init(void);
 void acpi_early_processor_set_pdc(void);
@@ -98,6 +125,4 @@
   -------------------------------------------------------------------------- */
 struct platform_device;
 
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
-
 #endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index cb31298..33e609f 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -116,14 +116,16 @@
 			struct acpi_srat_mem_affinity *p =
 			    (struct acpi_srat_mem_affinity *)header;
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s\n",
+					  "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s%s\n",
 					  (unsigned long)p->base_address,
 					  (unsigned long)p->length,
 					  p->proximity_domain,
 					  (p->flags & ACPI_SRAT_MEM_ENABLED)?
 					  "enabled" : "disabled",
 					  (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
-					  " hot-pluggable" : ""));
+					  " hot-pluggable" : "",
+					  (p->flags & ACPI_SRAT_MEM_NON_VOLATILE)?
+					  " non-volatile" : ""));
 		}
 #endif				/* ACPI_DEBUG_OUTPUT */
 		break;
@@ -273,7 +275,7 @@
 
 static int __init
 acpi_table_parse_srat(enum acpi_srat_type id,
-		      acpi_table_entry_handler handler, unsigned int max_entries)
+		      acpi_tbl_entry_handler handler, unsigned int max_entries)
 {
 	return acpi_table_parse_entries(ACPI_SIG_SRAT,
 					    sizeof(struct acpi_table_srat), id,
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bd22f86..908b02d 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -787,7 +787,7 @@
 
 	acpi_irq_handler = handler;
 	acpi_irq_context = context;
-	if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
+	if (request_irq(irq, acpi_irq, IRQF_SHARED | IRQF_NO_SUSPEND, "acpi", acpi_irq)) {
 		printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
 		acpi_irq_handler = NULL;
 		return AE_NOT_ACQUIRED;
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
deleted file mode 100644
index a1dee29..0000000
--- a/drivers/acpi/pci_bind.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- *  pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $)
- *
- *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
- *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or (at
- *  your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pci-acpi.h>
-#include <linux/acpi.h>
-#include <linux/pm_runtime.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT		ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_bind");
-
-static int acpi_pci_unbind(struct acpi_device *device)
-{
-	struct pci_dev *dev;
-
-	dev = acpi_get_pci_dev(device->handle);
-	if (!dev)
-		goto out;
-
-	device_set_run_wake(&dev->dev, false);
-	pci_acpi_remove_pm_notifier(device);
-	acpi_power_resource_unregister_device(&dev->dev, device->handle);
-
-	if (!dev->subordinate)
-		goto out;
-
-	acpi_pci_irq_del_prt(pci_domain_nr(dev->bus), dev->subordinate->number);
-
-	device->ops.bind = NULL;
-	device->ops.unbind = NULL;
-
-out:
-	pci_dev_put(dev);
-	return 0;
-}
-
-static int acpi_pci_bind(struct acpi_device *device)
-{
-	acpi_status status;
-	acpi_handle handle;
-	unsigned char bus;
-	struct pci_dev *dev;
-
-	dev = acpi_get_pci_dev(device->handle);
-	if (!dev)
-		return 0;
-
-	pci_acpi_add_pm_notifier(device, dev);
-	acpi_power_resource_register_device(&dev->dev, device->handle);
-	if (device->wakeup.flags.run_wake)
-		device_set_run_wake(&dev->dev, true);
-
-	/*
-	 * Install the 'bind' function to facilitate callbacks for
-	 * children of the P2P bridge.
-	 */
-	if (dev->subordinate) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Device %04x:%02x:%02x.%d is a PCI bridge\n",
-				  pci_domain_nr(dev->bus), dev->bus->number,
-				  PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)));
-		device->ops.bind = acpi_pci_bind;
-		device->ops.unbind = acpi_pci_unbind;
-	}
-
-	/*
-	 * Evaluate and parse _PRT, if exists.  This code allows parsing of
-	 * _PRT objects within the scope of non-bridge devices.  Note that
-	 * _PRTs within the scope of a PCI bridge assume the bridge's
-	 * subordinate bus number.
-	 *
-	 * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
-	 */
-	status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
-	if (ACPI_FAILURE(status))
-		goto out;
-
-	if (dev->subordinate)
-		bus = dev->subordinate->number;
-	else
-		bus = dev->bus->number;
-
-	acpi_pci_irq_add_prt(device->handle, pci_domain_nr(dev->bus), bus);
-
-out:
-	pci_dev_put(dev);
-	return 0;
-}
-
-int acpi_pci_bind_root(struct acpi_device *device)
-{
-	device->ops.bind = acpi_pci_bind;
-	device->ops.unbind = acpi_pci_unbind;
-
-	return 0;
-}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index a128082..ab764ed 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -53,23 +53,19 @@
 #define ACPI_PCI_LINK_FILE_STATUS	"state"
 #define ACPI_PCI_LINK_MAX_POSSIBLE	16
 
-static int acpi_pci_link_add(struct acpi_device *device);
-static int acpi_pci_link_remove(struct acpi_device *device, int type);
+static int acpi_pci_link_add(struct acpi_device *device,
+			     const struct acpi_device_id *not_used);
+static void acpi_pci_link_remove(struct acpi_device *device);
 
 static const struct acpi_device_id link_device_ids[] = {
 	{"PNP0C0F", 0},
 	{"", 0},
 };
-MODULE_DEVICE_TABLE(acpi, link_device_ids);
 
-static struct acpi_driver acpi_pci_link_driver = {
-	.name = "pci_link",
-	.class = ACPI_PCI_LINK_CLASS,
+static struct acpi_scan_handler pci_link_handler = {
 	.ids = link_device_ids,
-	.ops = {
-		.add = acpi_pci_link_add,
-		.remove = acpi_pci_link_remove,
-	},
+	.attach = acpi_pci_link_add,
+	.detach = acpi_pci_link_remove,
 };
 
 /*
@@ -692,7 +688,8 @@
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
-static int acpi_pci_link_add(struct acpi_device *device)
+static int acpi_pci_link_add(struct acpi_device *device,
+			     const struct acpi_device_id *not_used)
 {
 	int result;
 	struct acpi_pci_link *link;
@@ -746,7 +743,7 @@
 	if (result)
 		kfree(link);
 
-	return result;
+	return result < 0 ? result : 1;
 }
 
 static int acpi_pci_link_resume(struct acpi_pci_link *link)
@@ -766,7 +763,7 @@
 	}
 }
 
-static int acpi_pci_link_remove(struct acpi_device *device, int type)
+static void acpi_pci_link_remove(struct acpi_device *device)
 {
 	struct acpi_pci_link *link;
 
@@ -777,7 +774,6 @@
 	mutex_unlock(&acpi_link_lock);
 
 	kfree(link);
-	return 0;
 }
 
 /*
@@ -874,20 +870,10 @@
 	.resume = irqrouter_resume,
 };
 
-static int __init irqrouter_init_ops(void)
-{
-	if (!acpi_disabled && !acpi_noirq)
-		register_syscore_ops(&irqrouter_syscore_ops);
-
-	return 0;
-}
-
-device_initcall(irqrouter_init_ops);
-
-static int __init acpi_pci_link_init(void)
+void __init acpi_pci_link_init(void)
 {
 	if (acpi_noirq)
-		return 0;
+		return;
 
 	if (acpi_irq_balance == -1) {
 		/* no command line switch: enable balancing in IOAPIC mode */
@@ -896,11 +882,6 @@
 		else
 			acpi_irq_balance = 0;
 	}
-
-	if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
-		return -ENODEV;
-
-	return 0;
+	register_syscore_ops(&irqrouter_syscore_ops);
+	acpi_scan_add_handler(&pci_link_handler);
 }
-
-subsys_initcall(acpi_pci_link_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7928d4d..b3cc69c 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -45,9 +45,9 @@
 ACPI_MODULE_NAME("pci_root");
 #define ACPI_PCI_ROOT_CLASS		"pci_bridge"
 #define ACPI_PCI_ROOT_DEVICE_NAME	"PCI Root Bridge"
-static int acpi_pci_root_add(struct acpi_device *device);
-static int acpi_pci_root_remove(struct acpi_device *device, int type);
-static int acpi_pci_root_start(struct acpi_device *device);
+static int acpi_pci_root_add(struct acpi_device *device,
+			     const struct acpi_device_id *not_used);
+static void acpi_pci_root_remove(struct acpi_device *device);
 
 #define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
 				| OSC_ACTIVE_STATE_PWR_SUPPORT \
@@ -58,17 +58,11 @@
 	{"PNP0A03", 0},
 	{"", 0},
 };
-MODULE_DEVICE_TABLE(acpi, root_device_ids);
 
-static struct acpi_driver acpi_pci_root_driver = {
-	.name = "pci_root",
-	.class = ACPI_PCI_ROOT_CLASS,
+static struct acpi_scan_handler pci_root_handler = {
 	.ids = root_device_ids,
-	.ops = {
-		.add = acpi_pci_root_add,
-		.remove = acpi_pci_root_remove,
-		.start = acpi_pci_root_start,
-		},
+	.attach = acpi_pci_root_add,
+	.detach = acpi_pci_root_remove,
 };
 
 /* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
@@ -188,21 +182,6 @@
 	return AE_OK;
 }
 
-static void acpi_pci_bridge_scan(struct acpi_device *device)
-{
-	int status;
-	struct acpi_device *child = NULL;
-
-	if (device->flags.bus_address)
-		if (device->parent && device->parent->ops.bind) {
-			status = device->parent->ops.bind(device);
-			if (!status) {
-				list_for_each_entry(child, &device->children, node)
-					acpi_pci_bridge_scan(child);
-			}
-		}
-}
-
 static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766";
 
 static acpi_status acpi_pci_run_osc(acpi_handle handle,
@@ -445,14 +424,15 @@
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
-static int acpi_pci_root_add(struct acpi_device *device)
+static int acpi_pci_root_add(struct acpi_device *device,
+			     const struct acpi_device_id *not_used)
 {
 	unsigned long long segment, bus;
 	acpi_status status;
 	int result;
 	struct acpi_pci_root *root;
 	acpi_handle handle;
-	struct acpi_device *child;
+	struct acpi_pci_driver *driver;
 	u32 flags, base_flags;
 	bool is_osc_granted = false;
 
@@ -603,21 +583,6 @@
 		goto out_del_root;
 	}
 
-	/*
-	 * Attach ACPI-PCI Context
-	 * -----------------------
-	 * Thus binding the ACPI and PCI devices.
-	 */
-	result = acpi_pci_bind_root(device);
-	if (result)
-		goto out_del_root;
-
-	/*
-	 * Scan and bind all _ADR-Based Devices
-	 */
-	list_for_each_entry(child, &device->children, node)
-		acpi_pci_bridge_scan(child);
-
 	/* ASPM setting */
 	if (is_osc_granted) {
 		if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM)
@@ -632,24 +597,6 @@
 	if (device->wakeup.flags.run_wake)
 		device_set_run_wake(root->bus->bridge, true);
 
-	return 0;
-
-out_del_root:
-	mutex_lock(&acpi_pci_root_lock);
-	list_del(&root->node);
-	mutex_unlock(&acpi_pci_root_lock);
-
-	acpi_pci_irq_del_prt(root->segment, root->secondary.start);
-end:
-	kfree(root);
-	return result;
-}
-
-static int acpi_pci_root_start(struct acpi_device *device)
-{
-	struct acpi_pci_root *root = acpi_driver_data(device);
-	struct acpi_pci_driver *driver;
-
 	if (system_state != SYSTEM_BOOTING)
 		pci_assign_unassigned_bus_resources(root->bus);
 
@@ -664,11 +611,20 @@
 		pci_enable_bridges(root->bus);
 
 	pci_bus_add_devices(root->bus);
+	return 1;
 
-	return 0;
+out_del_root:
+	mutex_lock(&acpi_pci_root_lock);
+	list_del(&root->node);
+	mutex_unlock(&acpi_pci_root_lock);
+
+	acpi_pci_irq_del_prt(root->segment, root->secondary.start);
+end:
+	kfree(root);
+	return result;
 }
 
-static int acpi_pci_root_remove(struct acpi_device *device, int type)
+static void acpi_pci_root_remove(struct acpi_device *device)
 {
 	acpi_status status;
 	acpi_handle handle;
@@ -696,21 +652,14 @@
 	list_del(&root->node);
 	mutex_unlock(&acpi_pci_root_lock);
 	kfree(root);
-	return 0;
 }
 
-static int __init acpi_pci_root_init(void)
+void __init acpi_pci_root_init(void)
 {
 	acpi_hest_init();
 
-	if (acpi_pci_disabled)
-		return 0;
-
-	pci_acpi_crs_quirks();
-	if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
-		return -ENODEV;
-
-	return 0;
+	if (!acpi_pci_disabled) {
+		pci_acpi_crs_quirks();
+		acpi_scan_add_handler(&pci_root_handler);
+	}
 }
-
-subsys_initcall(acpi_pci_root_init);
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index d22585f..2c630c0 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -50,13 +50,12 @@
 ACPI_MODULE_NAME("pci_slot");
 
 #define MY_NAME "pci_slot"
-#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define err(format, arg...) pr_err("%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) pr_info("%s: " format , MY_NAME , ## arg)
 #define dbg(format, arg...)					\
 	do {							\
 		if (debug)					\
-			printk(KERN_DEBUG "%s: " format,	\
-				MY_NAME , ## arg);		\
+			pr_debug("%s: " format,	MY_NAME , ## arg); \
 	} while (0)
 
 #define SLOT_NAME_SIZE 21		/* Inspired by #define in acpiphp.h */
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 6e7b9d5..b820528 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -41,6 +41,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include "sleep.h"
@@ -58,88 +59,121 @@
 #define ACPI_POWER_RESOURCE_STATE_ON	0x01
 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
 
-static int acpi_power_add(struct acpi_device *device);
-static int acpi_power_remove(struct acpi_device *device, int type);
-
-static const struct acpi_device_id power_device_ids[] = {
-	{ACPI_POWER_HID, 0},
-	{"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, power_device_ids);
-
-#ifdef CONFIG_PM_SLEEP
-static int acpi_power_resume(struct device *dev);
-#endif
-static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
-
-static struct acpi_driver acpi_power_driver = {
-	.name = "power",
-	.class = ACPI_POWER_CLASS,
-	.ids = power_device_ids,
-	.ops = {
-		.add = acpi_power_add,
-		.remove = acpi_power_remove,
-		},
-	.drv.pm = &acpi_power_pm,
-};
-
-/*
- * A power managed device
- * A device may rely on multiple power resources.
- * */
-struct acpi_power_managed_device {
-	struct device *dev; /* The physical device */
-	acpi_handle *handle;
-};
-
-struct acpi_power_resource_device {
-	struct acpi_power_managed_device *device;
-	struct acpi_power_resource_device *next;
+struct acpi_power_dependent_device {
+	struct list_head node;
+	struct acpi_device *adev;
+	struct work_struct work;
 };
 
 struct acpi_power_resource {
-	struct acpi_device * device;
-	acpi_bus_id name;
+	struct acpi_device device;
+	struct list_head list_node;
+	struct list_head dependent;
+	char *name;
 	u32 system_level;
 	u32 order;
 	unsigned int ref_count;
 	struct mutex resource_lock;
-
-	/* List of devices relying on this power resource */
-	struct acpi_power_resource_device *devices;
-	struct mutex devices_lock;
 };
 
-static struct list_head acpi_power_resource_list;
+struct acpi_power_resource_entry {
+	struct list_head node;
+	struct acpi_power_resource *resource;
+};
+
+static LIST_HEAD(acpi_power_resource_list);
+static DEFINE_MUTEX(power_resource_list_lock);
 
 /* --------------------------------------------------------------------------
                              Power Resource Management
    -------------------------------------------------------------------------- */
 
-static int
-acpi_power_get_context(acpi_handle handle,
-		       struct acpi_power_resource **resource)
+static inline
+struct acpi_power_resource *to_power_resource(struct acpi_device *device)
 {
-	int result = 0;
-	struct acpi_device *device = NULL;
+	return container_of(device, struct acpi_power_resource, device);
+}
 
+static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
+{
+	struct acpi_device *device;
 
-	if (!resource)
-		return -ENODEV;
+	if (acpi_bus_get_device(handle, &device))
+		return NULL;
 
-	result = acpi_bus_get_device(handle, &device);
-	if (result) {
-		printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
-		return result;
+	return to_power_resource(device);
+}
+
+static int acpi_power_resources_list_add(acpi_handle handle,
+					 struct list_head *list)
+{
+	struct acpi_power_resource *resource = acpi_power_get_context(handle);
+	struct acpi_power_resource_entry *entry;
+
+	if (!resource || !list)
+		return -EINVAL;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->resource = resource;
+	if (!list_empty(list)) {
+		struct acpi_power_resource_entry *e;
+
+		list_for_each_entry(e, list, node)
+			if (e->resource->order > resource->order) {
+				list_add_tail(&entry->node, &e->node);
+				return 0;
+			}
 	}
-
-	*resource = acpi_driver_data(device);
-	if (!*resource)
-		return -ENODEV;
-
+	list_add_tail(&entry->node, list);
 	return 0;
 }
 
+void acpi_power_resources_list_free(struct list_head *list)
+{
+	struct acpi_power_resource_entry *entry, *e;
+
+	list_for_each_entry_safe(entry, e, list, node) {
+		list_del(&entry->node);
+		kfree(entry);
+	}
+}
+
+int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
+				 struct list_head *list)
+{
+	unsigned int i;
+	int err = 0;
+
+	for (i = start; i < package->package.count; i++) {
+		union acpi_object *element = &package->package.elements[i];
+		acpi_handle rhandle;
+
+		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
+			err = -ENODATA;
+			break;
+		}
+		rhandle = element->reference.handle;
+		if (!rhandle) {
+			err = -ENODEV;
+			break;
+		}
+		err = acpi_add_power_resource(rhandle);
+		if (err)
+			break;
+
+		err = acpi_power_resources_list_add(rhandle, list);
+		if (err)
+			break;
+	}
+	if (err)
+		acpi_power_resources_list_free(list);
+
+	return err;
+}
+
 static int acpi_power_get_state(acpi_handle handle, int *state)
 {
 	acpi_status status = AE_OK;
@@ -167,31 +201,23 @@
 	return 0;
 }
 
-static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
+static int acpi_power_get_list_state(struct list_head *list, int *state)
 {
+	struct acpi_power_resource_entry *entry;
 	int cur_state;
-	int i = 0;
 
 	if (!list || !state)
 		return -EINVAL;
 
 	/* The state of the list is 'on' IFF all resources are 'on'. */
-
-	for (i = 0; i < list->count; i++) {
-		struct acpi_power_resource *resource;
-		acpi_handle handle = list->handles[i];
+	list_for_each_entry(entry, list, node) {
+		struct acpi_power_resource *resource = entry->resource;
+		acpi_handle handle = resource->device.handle;
 		int result;
 
-		result = acpi_power_get_context(handle, &resource);
-		if (result)
-			return result;
-
 		mutex_lock(&resource->resource_lock);
-
 		result = acpi_power_get_state(handle, &cur_state);
-
 		mutex_unlock(&resource->resource_lock);
-
 		if (result)
 			return result;
 
@@ -203,54 +229,52 @@
 			  cur_state ? "on" : "off"));
 
 	*state = cur_state;
-
 	return 0;
 }
 
-/* Resume the device when all power resources in _PR0 are on */
-static void acpi_power_on_device(struct acpi_power_managed_device *device)
+static void acpi_power_resume_dependent(struct work_struct *work)
 {
-	struct acpi_device *acpi_dev;
-	acpi_handle handle = device->handle;
+	struct acpi_power_dependent_device *dep;
+	struct acpi_device_physical_node *pn;
+	struct acpi_device *adev;
 	int state;
 
-	if (acpi_bus_get_device(handle, &acpi_dev))
+	dep = container_of(work, struct acpi_power_dependent_device, work);
+	adev = dep->adev;
+	if (acpi_power_get_inferred_state(adev, &state))
 		return;
 
-	if(acpi_power_get_inferred_state(acpi_dev, &state))
+	if (state > ACPI_STATE_D0)
 		return;
 
-	if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev))
-		pm_request_resume(device->dev);
+	mutex_lock(&adev->physical_node_lock);
+
+	list_for_each_entry(pn, &adev->physical_node_list, node)
+		pm_request_resume(pn->dev);
+
+	list_for_each_entry(pn, &adev->power_dependent, node)
+		pm_request_resume(pn->dev);
+
+	mutex_unlock(&adev->physical_node_lock);
 }
 
 static int __acpi_power_on(struct acpi_power_resource *resource)
 {
 	acpi_status status = AE_OK;
 
-	status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
+	status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	/* Update the power resource's _device_ power state */
-	resource->device->power.state = ACPI_STATE_D0;
-
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
 			  resource->name));
 
 	return 0;
 }
 
-static int acpi_power_on(acpi_handle handle)
+static int acpi_power_on(struct acpi_power_resource *resource)
 {
-	int result = 0;
-	bool resume_device = false;
-	struct acpi_power_resource *resource = NULL;
-	struct acpi_power_resource_device *device_list;
-
-	result = acpi_power_get_context(handle, &resource);
-	if (result)
-		return result;
+	int result = 0;;
 
 	mutex_lock(&resource->resource_lock);
 
@@ -260,39 +284,38 @@
 				  resource->name));
 	} else {
 		result = __acpi_power_on(resource);
-		if (result)
+		if (result) {
 			resource->ref_count--;
-		else
-			resume_device = true;
+		} else {
+			struct acpi_power_dependent_device *dep;
+
+			list_for_each_entry(dep, &resource->dependent, node)
+				schedule_work(&dep->work);
+		}
 	}
 
 	mutex_unlock(&resource->resource_lock);
 
-	if (!resume_device)
-		return result;
-
-	mutex_lock(&resource->devices_lock);
-
-	device_list = resource->devices;
-	while (device_list) {
-		acpi_power_on_device(device_list->device);
-		device_list = device_list->next;
-	}
-
-	mutex_unlock(&resource->devices_lock);
-
 	return result;
 }
 
-static int acpi_power_off(acpi_handle handle)
+static int __acpi_power_off(struct acpi_power_resource *resource)
+{
+	acpi_status status;
+
+	status = acpi_evaluate_object(resource->device.handle, "_OFF",
+				      NULL, NULL);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned off\n",
+			  resource->name));
+	return 0;
+}
+
+static int acpi_power_off(struct acpi_power_resource *resource)
 {
 	int result = 0;
-	acpi_status status = AE_OK;
-	struct acpi_power_resource *resource = NULL;
-
-	result = acpi_power_get_context(handle, &resource);
-	if (result)
-		return result;
 
 	mutex_lock(&resource->resource_lock);
 
@@ -307,19 +330,10 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Power resource [%s] still in use\n",
 				  resource->name));
-		goto unlock;
-	}
-
-	status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
-	if (ACPI_FAILURE(status)) {
-		result = -ENODEV;
 	} else {
-		/* Update the power resource's _device_ power state */
-		resource->device->power.state = ACPI_STATE_D3;
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Power resource [%s] turned off\n",
-				  resource->name));
+		result = __acpi_power_off(resource);
+		if (result)
+			resource->ref_count++;
 	}
 
  unlock:
@@ -328,148 +342,202 @@
 	return result;
 }
 
-static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
+static int acpi_power_off_list(struct list_head *list)
 {
-	int i;
-
-	for (i = num_res - 1; i >= 0 ; i--)
-		acpi_power_off(list->handles[i]);
-}
-
-static void acpi_power_off_list(struct acpi_handle_list *list)
-{
-	__acpi_power_off_list(list, list->count);
-}
-
-static int acpi_power_on_list(struct acpi_handle_list *list)
-{
+	struct acpi_power_resource_entry *entry;
 	int result = 0;
-	int i;
 
-	for (i = 0; i < list->count; i++) {
-		result = acpi_power_on(list->handles[i]);
-		if (result) {
-			__acpi_power_off_list(list, i);
-			break;
-		}
+	list_for_each_entry_reverse(entry, list, node) {
+		result = acpi_power_off(entry->resource);
+		if (result)
+			goto err;
 	}
+	return 0;
+
+ err:
+	list_for_each_entry_continue(entry, list, node)
+		acpi_power_on(entry->resource);
 
 	return result;
 }
 
-static void __acpi_power_resource_unregister_device(struct device *dev,
-		acpi_handle res_handle)
+static int acpi_power_on_list(struct list_head *list)
 {
-	struct acpi_power_resource *resource = NULL;
-	struct acpi_power_resource_device *prev, *curr;
+	struct acpi_power_resource_entry *entry;
+	int result = 0;
 
-	if (acpi_power_get_context(res_handle, &resource))
-		return;
-
-	mutex_lock(&resource->devices_lock);
-	prev = NULL;
-	curr = resource->devices;
-	while (curr) {
-		if (curr->device->dev == dev) {
-			if (!prev)
-				resource->devices = curr->next;
-			else
-				prev->next = curr->next;
-
-			kfree(curr);
-			break;
-		}
-
-		prev = curr;
-		curr = curr->next;
+	list_for_each_entry(entry, list, node) {
+		result = acpi_power_on(entry->resource);
+		if (result)
+			goto err;
 	}
-	mutex_unlock(&resource->devices_lock);
-}
-
-/* Unlink dev from all power resources in _PR0 */
-void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle)
-{
-	struct acpi_device *acpi_dev;
-	struct acpi_handle_list *list;
-	int i;
-
-	if (!dev || !handle)
-		return;
-
-	if (acpi_bus_get_device(handle, &acpi_dev))
-		return;
-
-	list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
-
-	for (i = 0; i < list->count; i++)
-		__acpi_power_resource_unregister_device(dev,
-			list->handles[i]);
-}
-EXPORT_SYMBOL_GPL(acpi_power_resource_unregister_device);
-
-static int __acpi_power_resource_register_device(
-	struct acpi_power_managed_device *powered_device, acpi_handle handle)
-{
-	struct acpi_power_resource *resource = NULL;
-	struct acpi_power_resource_device *power_resource_device;
-	int result;
-
-	result = acpi_power_get_context(handle, &resource);
-	if (result)
-		return result;
-
-	power_resource_device = kzalloc(
-		sizeof(*power_resource_device), GFP_KERNEL);
-	if (!power_resource_device)
-		return -ENOMEM;
-
-	power_resource_device->device = powered_device;
-
-	mutex_lock(&resource->devices_lock);
-	power_resource_device->next = resource->devices;
-	resource->devices = power_resource_device;
-	mutex_unlock(&resource->devices_lock);
-
 	return 0;
+
+ err:
+	list_for_each_entry_continue_reverse(entry, list, node)
+		acpi_power_off(entry->resource);
+
+	return result;
 }
 
-/* Link dev to all power resources in _PR0 */
-int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
+static void acpi_power_add_dependent(struct acpi_power_resource *resource,
+				     struct acpi_device *adev)
 {
-	struct acpi_device *acpi_dev;
-	struct acpi_handle_list *list;
-	struct acpi_power_managed_device *powered_device;
-	int i, ret;
+	struct acpi_power_dependent_device *dep;
 
-	if (!dev || !handle)
-		return -ENODEV;
+	mutex_lock(&resource->resource_lock);
 
-	ret = acpi_bus_get_device(handle, &acpi_dev);
-	if (ret || !acpi_dev->power.flags.power_resources)
-		return -ENODEV;
+	list_for_each_entry(dep, &resource->dependent, node)
+		if (dep->adev == adev)
+			goto out;
 
-	powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL);
-	if (!powered_device)
-		return -ENOMEM;
+	dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+	if (!dep)
+		goto out;
 
-	powered_device->dev = dev;
-	powered_device->handle = handle;
+	dep->adev = adev;
+	INIT_WORK(&dep->work, acpi_power_resume_dependent);
+	list_add_tail(&dep->node, &resource->dependent);
 
-	list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
+ out:
+	mutex_unlock(&resource->resource_lock);
+}
 
-	for (i = 0; i < list->count; i++) {
-		ret = __acpi_power_resource_register_device(powered_device,
-			list->handles[i]);
+static void acpi_power_remove_dependent(struct acpi_power_resource *resource,
+					struct acpi_device *adev)
+{
+	struct acpi_power_dependent_device *dep;
+	struct work_struct *work = NULL;
 
+	mutex_lock(&resource->resource_lock);
+
+	list_for_each_entry(dep, &resource->dependent, node)
+		if (dep->adev == adev) {
+			list_del(&dep->node);
+			work = &dep->work;
+			break;
+		}
+
+	mutex_unlock(&resource->resource_lock);
+
+	if (work) {
+		cancel_work_sync(work);
+		kfree(dep);
+	}
+}
+
+static struct attribute *attrs[] = {
+	NULL,
+};
+
+static struct attribute_group attr_groups[] = {
+	[ACPI_STATE_D0] = {
+		.name = "power_resources_D0",
+		.attrs = attrs,
+	},
+	[ACPI_STATE_D1] = {
+		.name = "power_resources_D1",
+		.attrs = attrs,
+	},
+	[ACPI_STATE_D2] = {
+		.name = "power_resources_D2",
+		.attrs = attrs,
+	},
+	[ACPI_STATE_D3_HOT] = {
+		.name = "power_resources_D3hot",
+		.attrs = attrs,
+	},
+};
+
+static void acpi_power_hide_list(struct acpi_device *adev, int state)
+{
+	struct acpi_device_power_state *ps = &adev->power.states[state];
+	struct acpi_power_resource_entry *entry;
+
+	if (list_empty(&ps->resources))
+		return;
+
+	list_for_each_entry_reverse(entry, &ps->resources, node) {
+		struct acpi_device *res_dev = &entry->resource->device;
+
+		sysfs_remove_link_from_group(&adev->dev.kobj,
+					     attr_groups[state].name,
+					     dev_name(&res_dev->dev));
+	}
+	sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
+}
+
+static void acpi_power_expose_list(struct acpi_device *adev, int state)
+{
+	struct acpi_device_power_state *ps = &adev->power.states[state];
+	struct acpi_power_resource_entry *entry;
+	int ret;
+
+	if (list_empty(&ps->resources))
+		return;
+
+	ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
+	if (ret)
+		return;
+
+	list_for_each_entry(entry, &ps->resources, node) {
+		struct acpi_device *res_dev = &entry->resource->device;
+
+		ret = sysfs_add_link_to_group(&adev->dev.kobj,
+					      attr_groups[state].name,
+					      &res_dev->dev.kobj,
+					      dev_name(&res_dev->dev));
 		if (ret) {
-			acpi_power_resource_unregister_device(dev, handle);
+			acpi_power_hide_list(adev, state);
 			break;
 		}
 	}
-
-	return ret;
 }
-EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
+
+void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
+{
+	struct acpi_device_power_state *ps;
+	struct acpi_power_resource_entry *entry;
+	int state;
+
+	if (!adev->power.flags.power_resources)
+		return;
+
+	ps = &adev->power.states[ACPI_STATE_D0];
+	list_for_each_entry(entry, &ps->resources, node) {
+		struct acpi_power_resource *resource = entry->resource;
+
+		if (add)
+			acpi_power_add_dependent(resource, adev);
+		else
+			acpi_power_remove_dependent(resource, adev);
+	}
+
+	for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
+		if (add)
+			acpi_power_expose_list(adev, state);
+		else
+			acpi_power_hide_list(adev, state);
+	}
+}
+
+int acpi_power_min_system_level(struct list_head *list)
+{
+	struct acpi_power_resource_entry *entry;
+	int system_level = 5;
+
+	list_for_each_entry(entry, list, node) {
+		struct acpi_power_resource *resource = entry->resource;
+
+		if (system_level > resource->system_level)
+			system_level = resource->system_level;
+	}
+	return system_level;
+}
+
+/* --------------------------------------------------------------------------
+                             Device Power Management
+   -------------------------------------------------------------------------- */
 
 /**
  * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
@@ -542,7 +610,7 @@
  */
 int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
 {
-	int i, err = 0;
+	int err = 0;
 
 	if (!dev || !dev->wakeup.flags.valid)
 		return -EINVAL;
@@ -552,24 +620,17 @@
 	if (dev->wakeup.prepare_count++)
 		goto out;
 
-	/* Open power resource */
-	for (i = 0; i < dev->wakeup.resources.count; i++) {
-		int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
-		if (ret) {
-			printk(KERN_ERR PREFIX "Transition power state\n");
-			dev->wakeup.flags.valid = 0;
-			err = -ENODEV;
-			goto err_out;
-		}
+	err = acpi_power_on_list(&dev->wakeup.resources);
+	if (err) {
+		dev_err(&dev->dev, "Cannot turn wakeup power resources on\n");
+		dev->wakeup.flags.valid = 0;
+	} else {
+		/*
+		 * Passing 3 as the third argument below means the device may be
+		 * put into arbitrary power state afterward.
+		 */
+		err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
 	}
-
-	/*
-	 * Passing 3 as the third argument below means the device may be placed
-	 * in arbitrary power state afterwards.
-	 */
-	err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
-
- err_out:
 	if (err)
 		dev->wakeup.prepare_count = 0;
 
@@ -586,7 +647,7 @@
  */
 int acpi_disable_wakeup_device_power(struct acpi_device *dev)
 {
-	int i, err = 0;
+	int err = 0;
 
 	if (!dev || !dev->wakeup.flags.valid)
 		return -EINVAL;
@@ -607,15 +668,10 @@
 	if (err)
 		goto out;
 
-	/* Close power resource */
-	for (i = 0; i < dev->wakeup.resources.count; i++) {
-		int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
-		if (ret) {
-			printk(KERN_ERR PREFIX "Transition power state\n");
-			dev->wakeup.flags.valid = 0;
-			err = -ENODEV;
-			goto out;
-		}
+	err = acpi_power_off_list(&dev->wakeup.resources);
+	if (err) {
+		dev_err(&dev->dev, "Cannot turn wakeup power resources off\n");
+		dev->wakeup.flags.valid = 0;
 	}
 
  out:
@@ -623,14 +679,9 @@
 	return err;
 }
 
-/* --------------------------------------------------------------------------
-                             Device Power Management
-   -------------------------------------------------------------------------- */
-
 int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
 {
 	int result = 0;
-	struct acpi_handle_list *list = NULL;
 	int list_state = 0;
 	int i = 0;
 
@@ -642,8 +693,9 @@
 	 * required for a given D-state are 'on'.
 	 */
 	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
-		list = &device->power.states[i].resources;
-		if (list->count < 1)
+		struct list_head *list = &device->power.states[i].resources;
+
+		if (list_empty(list))
 			continue;
 
 		result = acpi_power_get_list_state(list, &list_state);
@@ -662,7 +714,7 @@
 
 int acpi_power_on_resources(struct acpi_device *device, int state)
 {
-	if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
+	if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3_HOT)
 		return -EINVAL;
 
 	return acpi_power_on_list(&device->power.states[state].resources);
@@ -675,7 +727,7 @@
 	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
 		return -EINVAL;
 
-	if (device->power.state == state)
+	if (device->power.state == state || !device->flags.power_manageable)
 		return 0;
 
 	if ((device->power.state < ACPI_STATE_D0)
@@ -703,118 +755,126 @@
 	return result;
 }
 
-/* --------------------------------------------------------------------------
-                                Driver Interface
-   -------------------------------------------------------------------------- */
-
-static int acpi_power_add(struct acpi_device *device)
+static void acpi_release_power_resource(struct device *dev)
 {
-	int result = 0, state;
-	acpi_status status = AE_OK;
-	struct acpi_power_resource *resource = NULL;
+	struct acpi_device *device = to_acpi_device(dev);
+	struct acpi_power_resource *resource;
+
+	resource = container_of(device, struct acpi_power_resource, device);
+
+	mutex_lock(&power_resource_list_lock);
+	list_del(&resource->list_node);
+	mutex_unlock(&power_resource_list_lock);
+
+	acpi_free_ids(device);
+	kfree(resource);
+}
+
+static ssize_t acpi_power_in_use_show(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf) {
+	struct acpi_power_resource *resource;
+
+	resource = to_power_resource(to_acpi_device(dev));
+	return sprintf(buf, "%u\n", !!resource->ref_count);
+}
+static DEVICE_ATTR(resource_in_use, 0444, acpi_power_in_use_show, NULL);
+
+static void acpi_power_sysfs_remove(struct acpi_device *device)
+{
+	device_remove_file(&device->dev, &dev_attr_resource_in_use);
+}
+
+int acpi_add_power_resource(acpi_handle handle)
+{
+	struct acpi_power_resource *resource;
+	struct acpi_device *device = NULL;
 	union acpi_object acpi_object;
 	struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
+	acpi_status status;
+	int state, result = -ENODEV;
 
+	acpi_bus_get_device(handle, &device);
+	if (device)
+		return 0;
 
-	if (!device)
-		return -EINVAL;
-
-	resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
+	resource = kzalloc(sizeof(*resource), GFP_KERNEL);
 	if (!resource)
 		return -ENOMEM;
 
-	resource->device = device;
+	device = &resource->device;
+	acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
+				ACPI_STA_DEFAULT);
 	mutex_init(&resource->resource_lock);
-	mutex_init(&resource->devices_lock);
-	strcpy(resource->name, device->pnp.bus_id);
+	INIT_LIST_HEAD(&resource->dependent);
+	resource->name = device->pnp.bus_id;
 	strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
-	device->driver_data = resource;
+	device->power.state = ACPI_STATE_UNKNOWN;
 
 	/* Evalute the object to get the system level and resource order. */
-	status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
-	if (ACPI_FAILURE(status)) {
-		result = -ENODEV;
-		goto end;
-	}
+	status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+	if (ACPI_FAILURE(status))
+		goto err;
+
 	resource->system_level = acpi_object.power_resource.system_level;
 	resource->order = acpi_object.power_resource.resource_order;
 
-	result = acpi_power_get_state(device->handle, &state);
+	result = acpi_power_get_state(handle, &state);
 	if (result)
-		goto end;
-
-	switch (state) {
-	case ACPI_POWER_RESOURCE_STATE_ON:
-		device->power.state = ACPI_STATE_D0;
-		break;
-	case ACPI_POWER_RESOURCE_STATE_OFF:
-		device->power.state = ACPI_STATE_D3;
-		break;
-	default:
-		device->power.state = ACPI_STATE_UNKNOWN;
-		break;
-	}
+		goto err;
 
 	printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
 	       acpi_device_bid(device), state ? "on" : "off");
 
-      end:
+	device->flags.match_driver = true;
+	result = acpi_device_add(device, acpi_release_power_resource);
 	if (result)
-		kfree(resource);
+		goto err;
 
-	return result;
-}
+	if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
+		device->remove = acpi_power_sysfs_remove;
 
-static int acpi_power_remove(struct acpi_device *device, int type)
-{
-	struct acpi_power_resource *resource;
-
-	if (!device)
-		return -EINVAL;
-
-	resource = acpi_driver_data(device);
-	if (!resource)
-		return -EINVAL;
-
-	kfree(resource);
-
+	mutex_lock(&power_resource_list_lock);
+	list_add(&resource->list_node, &acpi_power_resource_list);
+	mutex_unlock(&power_resource_list_lock);
+	acpi_device_add_finalize(device);
 	return 0;
+
+ err:
+	acpi_release_power_resource(&device->dev);
+	return result;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int acpi_power_resume(struct device *dev)
+#ifdef CONFIG_ACPI_SLEEP
+void acpi_resume_power_resources(void)
 {
-	int result = 0, state;
-	struct acpi_device *device;
 	struct acpi_power_resource *resource;
 
-	if (!dev)
-		return -EINVAL;
+	mutex_lock(&power_resource_list_lock);
 
-	device = to_acpi_device(dev);
-	resource = acpi_driver_data(device);
-	if (!resource)
-		return -EINVAL;
+	list_for_each_entry(resource, &acpi_power_resource_list, list_node) {
+		int result, state;
 
-	mutex_lock(&resource->resource_lock);
+		mutex_lock(&resource->resource_lock);
 
-	result = acpi_power_get_state(device->handle, &state);
-	if (result)
-		goto unlock;
+		result = acpi_power_get_state(resource->device.handle, &state);
+		if (result)
+			continue;
 
-	if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
-		result = __acpi_power_on(resource);
+		if (state == ACPI_POWER_RESOURCE_STATE_OFF
+		    && resource->ref_count) {
+			dev_info(&resource->device.dev, "Turning ON\n");
+			__acpi_power_on(resource);
+		} else if (state == ACPI_POWER_RESOURCE_STATE_ON
+		    && !resource->ref_count) {
+			dev_info(&resource->device.dev, "Turning OFF\n");
+			__acpi_power_off(resource);
+		}
 
- unlock:
-	mutex_unlock(&resource->resource_lock);
+		mutex_unlock(&resource->resource_lock);
+	}
 
-	return result;
+	mutex_unlock(&power_resource_list_lock);
 }
 #endif
-
-int __init acpi_power_init(void)
-{
-	INIT_LIST_HEAD(&acpi_power_resource_list);
-	return acpi_bus_register_driver(&acpi_power_driver);
-}
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index ef98796..52ce767 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -311,11 +311,12 @@
 			   dev->pnp.bus_id,
 			   (u32) dev->wakeup.sleep_state);
 
-		if (!dev->physical_node_count)
+		if (!dev->physical_node_count) {
 			seq_printf(seq, "%c%-8s\n",
-				dev->wakeup.flags.run_wake ?
-				'*' : ' ', "disabled");
-		else {
+				dev->wakeup.flags.run_wake ? '*' : ' ',
+				device_may_wakeup(&dev->dev) ?
+					"enabled" : "disabled");
+		} else {
 			struct device *ldev;
 			list_for_each_entry(entry, &dev->physical_node_list,
 					node) {
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index e83311b..cbf1f12 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -81,7 +81,7 @@
 MODULE_LICENSE("GPL");
 
 static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_remove(struct acpi_device *device, int type);
+static int acpi_processor_remove(struct acpi_device *device);
 static void acpi_processor_notify(struct acpi_device *device, u32 event);
 static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
 static int acpi_processor_handle_eject(struct acpi_processor *pr);
@@ -610,7 +610,7 @@
 	return result;
 }
 
-static int acpi_processor_remove(struct acpi_device *device, int type)
+static int acpi_processor_remove(struct acpi_device *device)
 {
 	struct acpi_processor *pr = NULL;
 
@@ -623,7 +623,7 @@
 	if (pr->id >= nr_cpu_ids)
 		goto free;
 
-	if (type == ACPI_BUS_REMOVAL_EJECT) {
+	if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) {
 		if (acpi_processor_handle_eject(pr))
 			return -EINVAL;
 	}
@@ -677,36 +677,17 @@
 	return 0;
 }
 
-static
-int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
-{
-	acpi_handle phandle;
-	struct acpi_device *pdev;
-
-
-	if (acpi_get_parent(handle, &phandle)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_get_device(phandle, &pdev)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
 static void acpi_processor_hotplug_notify(acpi_handle handle,
 					  u32 event, void *data)
 {
 	struct acpi_device *device = NULL;
 	struct acpi_eject_event *ej_event = NULL;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+	acpi_status status;
 	int result;
 
+	acpi_scan_lock_acquire();
+
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
@@ -721,12 +702,16 @@
 		if (!acpi_bus_get_device(handle, &device))
 			break;
 
-		result = acpi_processor_device_add(handle, &device);
+		result = acpi_bus_scan(handle);
 		if (result) {
 			acpi_handle_err(handle, "Unable to add the device\n");
 			break;
 		}
-
+		result = acpi_bus_get_device(handle, &device);
+		if (result) {
+			acpi_handle_err(handle, "Missing device object\n");
+			break;
+		}
 		ost_code = ACPI_OST_SC_SUCCESS;
 		break;
 
@@ -751,25 +736,32 @@
 			break;
 		}
 
-		ej_event->handle = handle;
+		get_device(&device->dev);
+		ej_event->device = device;
 		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-		acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
-					(void *)ej_event);
-
-		/* eject is performed asynchronously */
-		return;
+		/* The eject is carried out asynchronously. */
+		status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+						 ej_event);
+		if (ACPI_FAILURE(status)) {
+			put_device(&device->dev);
+			kfree(ej_event);
+			break;
+		}
+		goto out;
 
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
 
 		/* non-hotplug event; possibly handled by other handler */
-		return;
+		goto out;
 	}
 
 	/* Inform firmware that the hotplug operation has completed */
 	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-	return;
+
+ out:
+	acpi_scan_lock_release();
 }
 
 static acpi_status is_processor_device(acpi_handle handle)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index ed9a1cc..fc95308 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -28,19 +28,12 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>	/* need_resched() */
-#include <linux/pm_qos.h>
+#include <linux/sched.h>       /* need_resched() */
 #include <linux/clockchips.h>
 #include <linux/cpuidle.h>
-#include <linux/irqflags.h>
 
 /*
  * Include the apic definitions for x86 to have the APIC timer related defines
@@ -52,22 +45,14 @@
 #include <asm/apic.h>
 #endif
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
 #include <acpi/acpi_bus.h>
 #include <acpi/processor.h>
-#include <asm/processor.h>
 
 #define PREFIX "ACPI: "
 
 #define ACPI_PROCESSOR_CLASS            "processor"
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_idle");
-#define PM_TIMER_TICK_NS		(1000000000ULL/PM_TIMER_FREQUENCY)
-#define C2_OVERHEAD			1	/* 1us */
-#define C3_OVERHEAD			1	/* 1us */
-#define PM_TIMER_TICKS_TO_US(p)		(((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
 
 static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
 module_param(max_cstate, uint, 0000);
@@ -81,10 +66,11 @@
 
 static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);
 
+static struct acpi_processor_cx *acpi_cstate[CPUIDLE_STATE_MAX];
+
 static int disabled_by_idle_boot_param(void)
 {
 	return boot_option_idle_override == IDLE_POLL ||
-		boot_option_idle_override == IDLE_FORCE_MWAIT ||
 		boot_option_idle_override == IDLE_HALT;
 }
 
@@ -736,8 +722,7 @@
 		struct cpuidle_driver *drv, int index)
 {
 	struct acpi_processor *pr;
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+	struct acpi_processor_cx *cx = acpi_cstate[index];
 
 	pr = __this_cpu_read(processors);
 
@@ -760,8 +745,7 @@
  */
 static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
 {
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+	struct acpi_processor_cx *cx = acpi_cstate[index];
 
 	ACPI_FLUSH_CPU_CACHE();
 
@@ -791,8 +775,7 @@
 		struct cpuidle_driver *drv, int index)
 {
 	struct acpi_processor *pr;
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+	struct acpi_processor_cx *cx = acpi_cstate[index];
 
 	pr = __this_cpu_read(processors);
 
@@ -850,8 +833,7 @@
 		struct cpuidle_driver *drv, int index)
 {
 	struct acpi_processor *pr;
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
-	struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+	struct acpi_processor_cx *cx = acpi_cstate[index];
 
 	pr = __this_cpu_read(processors);
 
@@ -943,13 +925,13 @@
  * device i.e. per-cpu data
  *
  * @pr: the ACPI processor
+ * @dev : the cpuidle device
  */
-static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
+static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
+					   struct cpuidle_device *dev)
 {
 	int i, count = CPUIDLE_DRIVER_STATE_START;
 	struct acpi_processor_cx *cx;
-	struct cpuidle_state_usage *state_usage;
-	struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id);
 
 	if (!pr->flags.power_setup_done)
 		return -EINVAL;
@@ -968,7 +950,6 @@
 
 	for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
 		cx = &pr->power.states[i];
-		state_usage = &dev->states_usage[count];
 
 		if (!cx->valid)
 			continue;
@@ -979,8 +960,7 @@
 		    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
 			continue;
 #endif
-
-		cpuidle_set_statedata(state_usage, cx);
+		acpi_cstate[count] = cx;
 
 		count++;
 		if (count == CPUIDLE_STATE_MAX)
@@ -1104,7 +1084,7 @@
 	cpuidle_disable_device(dev);
 	acpi_processor_get_power_info(pr);
 	if (pr->flags.power) {
-		acpi_processor_setup_cpuidle_cx(pr);
+		acpi_processor_setup_cpuidle_cx(pr, dev);
 		ret = cpuidle_enable_device(dev);
 	}
 	cpuidle_resume_and_unlock();
@@ -1162,8 +1142,8 @@
 				continue;
 			acpi_processor_get_power_info(_pr);
 			if (_pr->flags.power) {
-				acpi_processor_setup_cpuidle_cx(_pr);
 				dev = per_cpu(acpi_cpuidle_device, cpu);
+				acpi_processor_setup_cpuidle_cx(_pr, dev);
 				cpuidle_enable_device(dev);
 			}
 		}
@@ -1232,7 +1212,7 @@
 			return -ENOMEM;
 		per_cpu(acpi_cpuidle_device, pr->id) = dev;
 
-		acpi_processor_setup_cpuidle_cx(pr);
+		acpi_processor_setup_cpuidle_cx(pr, dev);
 
 		/* Register per-cpu cpuidle_device. Cpuidle driver
 		 * must already be registered before registering device
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index ff0740e..e523245 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -130,7 +130,7 @@
 
 #define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
 
-static int acpi_sbs_remove(struct acpi_device *device, int type);
+static int acpi_sbs_remove(struct acpi_device *device);
 static int acpi_battery_get_state(struct acpi_battery *battery);
 
 static inline int battery_scale(int log)
@@ -949,11 +949,11 @@
 	acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
       end:
 	if (result)
-		acpi_sbs_remove(device, 0);
+		acpi_sbs_remove(device);
 	return result;
 }
 
-static int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device)
 {
 	struct acpi_sbs *sbs;
 	int id;
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index cf6129a..b78bc60 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -33,7 +33,7 @@
 };
 
 static int acpi_smbus_hc_add(struct acpi_device *device);
-static int acpi_smbus_hc_remove(struct acpi_device *device, int type);
+static int acpi_smbus_hc_remove(struct acpi_device *device);
 
 static const struct acpi_device_id sbs_device_ids[] = {
 	{"ACPI0001", 0},
@@ -296,7 +296,7 @@
 
 extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
 
-static int acpi_smbus_hc_remove(struct acpi_device *device, int type)
+static int acpi_smbus_hc_remove(struct acpi_device *device)
 {
 	struct acpi_smb_hc *hc;
 
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index c88be6c..daee749 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -29,29 +29,10 @@
 
 static const char *dummy_hid = "device";
 
-/*
- * The following ACPI IDs are known to be suitable for representing as
- * platform devices.
- */
-static const struct acpi_device_id acpi_platform_device_ids[] = {
-
-	{ "PNP0D40" },
-
-	/* Haswell LPSS devices */
-	{ "INT33C0", 0 },
-	{ "INT33C1", 0 },
-	{ "INT33C2", 0 },
-	{ "INT33C3", 0 },
-	{ "INT33C4", 0 },
-	{ "INT33C5", 0 },
-	{ "INT33C6", 0 },
-	{ "INT33C7", 0 },
-
-	{ }
-};
-
 static LIST_HEAD(acpi_device_list);
 static LIST_HEAD(acpi_bus_id_list);
+static DEFINE_MUTEX(acpi_scan_lock);
+static LIST_HEAD(acpi_scan_handlers_list);
 DEFINE_MUTEX(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
 
@@ -61,6 +42,27 @@
 	struct list_head node;
 };
 
+void acpi_scan_lock_acquire(void)
+{
+	mutex_lock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire);
+
+void acpi_scan_lock_release(void)
+{
+	mutex_unlock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+
+int acpi_scan_add_handler(struct acpi_scan_handler *handler)
+{
+	if (!handler || !handler->attach)
+		return -EINVAL;
+
+	list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
+	return 0;
+}
+
 /*
  * Creates hid/cid(s) string needed for modalias and uevent
  * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -115,39 +117,32 @@
  */
 void acpi_bus_hot_remove_device(void *context)
 {
-	struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
-	struct acpi_device *device;
-	acpi_handle handle = ej_event->handle;
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
 	acpi_handle temp;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
 	acpi_status status = AE_OK;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 
-	if (acpi_bus_get_device(handle, &device))
-		goto err_out;
+	mutex_lock(&acpi_scan_lock);
 
-	if (!device)
-		goto err_out;
+	/* If there is no handle, the device node has been unregistered. */
+	if (!device->handle) {
+		dev_dbg(&device->dev, "ACPI handle missing\n");
+		put_device(&device->dev);
+		goto out;
+	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 		"Hot-removing device %s...\n", dev_name(&device->dev)));
 
-	if (acpi_bus_trim(device, 1)) {
-		printk(KERN_ERR PREFIX
-				"Removing device failed\n");
-		goto err_out;
-	}
-
-	/* device has been freed */
+	acpi_bus_trim(device);
+	/* Device node has been unregistered. */
+	put_device(&device->dev);
 	device = NULL;
 
-	/* power off device */
-	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
-		printk(KERN_WARNING PREFIX
-				"Power-off device failed\n");
-
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
@@ -167,23 +162,46 @@
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
 		if (status != AE_NOT_FOUND)
-			printk(KERN_WARNING PREFIX
-					"Eject device failed\n");
-		goto err_out;
+			acpi_handle_warn(handle, "Eject failed\n");
+
+		/* Tell the firmware the hot-remove operation has failed. */
+		acpi_evaluate_hotplug_ost(handle, ej_event->event,
+					  ost_code, NULL);
 	}
 
-	kfree(context);
-	return;
-
-err_out:
-	/* Inform firmware the hot-remove operation has completed w/ error */
-	(void) acpi_evaluate_hotplug_ost(handle,
-				ej_event->event, ost_code, NULL);
+ out:
+	mutex_unlock(&acpi_scan_lock);
 	kfree(context);
 	return;
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
+static ssize_t real_power_state_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(dev);
+	int state;
+	int ret;
+
+	ret = acpi_device_get_power(adev, &state);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%s\n", acpi_power_state_string(state));
+}
+
+static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
+
+static ssize_t power_state_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(dev);
+
+	return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
+}
+
+static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
+
 static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
@@ -197,12 +215,10 @@
 	if ((!count) || (buf[0] != '1')) {
 		return -EINVAL;
 	}
-#ifndef FORCE_EJECT
-	if (acpi_device->driver == NULL) {
+	if (!acpi_device->driver && !acpi_device->handler) {
 		ret = -ENODEV;
 		goto err;
 	}
-#endif
 	status = acpi_get_type(acpi_device->handle, &type);
 	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
 		ret = -ENODEV;
@@ -215,7 +231,8 @@
 		goto err;
 	}
 
-	ej_event->handle = acpi_device->handle;
+	get_device(&acpi_device->dev);
+	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
 		/* event originated from ACPI eject notification */
 		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
@@ -223,11 +240,15 @@
 	} else {
 		/* event originated from user */
 		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(ej_event->handle,
+		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
 			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
 	}
 
-	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
+	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
+	if (ACPI_FAILURE(status)) {
+		put_device(&acpi_device->dev);
+		kfree(ej_event);
+	}
 err:
 	return ret;
 }
@@ -375,8 +396,22 @@
          * hot-removal function from userland.
          */
 	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-	if (ACPI_SUCCESS(status))
+	if (ACPI_SUCCESS(status)) {
 		result = device_create_file(&dev->dev, &dev_attr_eject);
+		if (result)
+			return result;
+	}
+
+	if (dev->flags.power_manageable) {
+		result = device_create_file(&dev->dev, &dev_attr_power_state);
+		if (result)
+			return result;
+
+		if (dev->power.flags.power_resources)
+			result = device_create_file(&dev->dev,
+						    &dev_attr_real_power_state);
+	}
+
 end:
 	return result;
 }
@@ -386,6 +421,13 @@
 	acpi_status status;
 	acpi_handle temp;
 
+	if (dev->flags.power_manageable) {
+		device_remove_file(&dev->dev, &dev_attr_power_state);
+		if (dev->power.flags.power_resources)
+			device_remove_file(&dev->dev,
+					   &dev_attr_real_power_state);
+	}
+
 	/*
 	 * If device has _STR, remove 'description' file
 	 */
@@ -454,9 +496,9 @@
 					       const struct device *dev)
 {
 	struct acpi_device *adev;
+	acpi_handle handle = ACPI_HANDLE(dev);
 
-	if (!ids || !ACPI_HANDLE(dev)
-	    || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev)))
+	if (!ids || !handle || acpi_bus_get_device(handle, &adev))
 		return NULL;
 
 	return __acpi_match_device(adev, ids);
@@ -470,7 +512,7 @@
 }
 EXPORT_SYMBOL(acpi_match_device_ids);
 
-static void acpi_free_ids(struct acpi_device *device)
+void acpi_free_ids(struct acpi_device *device)
 {
 	struct acpi_hardware_id *id, *tmp;
 
@@ -478,6 +520,23 @@
 		kfree(id->id);
 		kfree(id);
 	}
+	kfree(device->pnp.unique_id);
+}
+
+static void acpi_free_power_resources_lists(struct acpi_device *device)
+{
+	int i;
+
+	if (device->wakeup.flags.valid)
+		acpi_power_resources_list_free(&device->wakeup.resources);
+
+	if (!device->flags.power_manageable)
+		return;
+
+	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
+		struct acpi_device_power_state *ps = &device->power.states[i];
+		acpi_power_resources_list_free(&ps->resources);
+	}
 }
 
 static void acpi_device_release(struct device *dev)
@@ -485,7 +544,7 @@
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 
 	acpi_free_ids(acpi_dev);
-	kfree(acpi_dev->pnp.unique_id);
+	acpi_free_power_resources_lists(acpi_dev);
 	kfree(acpi_dev);
 }
 
@@ -494,7 +553,8 @@
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	struct acpi_driver *acpi_drv = to_acpi_driver(drv);
 
-	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
+	return acpi_dev->flags.match_driver
+		&& !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
 }
 
 static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
@@ -570,7 +630,6 @@
 }
 
 static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
-static int acpi_start_single_object(struct acpi_device *);
 static int acpi_device_probe(struct device * dev)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
@@ -579,15 +638,13 @@
 
 	ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
 	if (!ret) {
-		if (acpi_dev->bus_ops.acpi_op_start)
-			acpi_start_single_object(acpi_dev);
-
 		if (acpi_drv->ops.notify) {
 			ret = acpi_device_install_notify_handler(acpi_dev);
 			if (ret) {
 				if (acpi_drv->ops.remove)
-					acpi_drv->ops.remove(acpi_dev,
-						     acpi_dev->removal_type);
+					acpi_drv->ops.remove(acpi_dev);
+				acpi_dev->driver = NULL;
+				acpi_dev->driver_data = NULL;
 				return ret;
 			}
 		}
@@ -609,7 +666,7 @@
 		if (acpi_drv->ops.notify)
 			acpi_device_remove_notify_handler(acpi_dev);
 		if (acpi_drv->ops.remove)
-			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+			acpi_drv->ops.remove(acpi_dev);
 	}
 	acpi_dev->driver = NULL;
 	acpi_dev->driver_data = NULL;
@@ -626,12 +683,25 @@
 	.uevent		= acpi_device_uevent,
 };
 
-static int acpi_device_register(struct acpi_device *device)
+int acpi_device_add(struct acpi_device *device,
+		    void (*release)(struct device *))
 {
 	int result;
 	struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
 	int found = 0;
 
+	if (device->handle) {
+		acpi_status status;
+
+		status = acpi_attach_data(device->handle, acpi_bus_data_handler,
+					  device);
+		if (ACPI_FAILURE(status)) {
+			acpi_handle_err(device->handle,
+					"Unable to attach device data\n");
+			return -ENODEV;
+		}
+	}
+
 	/*
 	 * Linkage
 	 * -------
@@ -642,11 +712,13 @@
 	INIT_LIST_HEAD(&device->wakeup_list);
 	INIT_LIST_HEAD(&device->physical_node_list);
 	mutex_init(&device->physical_node_lock);
+	INIT_LIST_HEAD(&device->power_dependent);
 
 	new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
 	if (!new_bus_id) {
-		printk(KERN_ERR PREFIX "Memory allocation error\n");
-		return -ENOMEM;
+		pr_err(PREFIX "Memory allocation error\n");
+		result = -ENOMEM;
+		goto err_detach;
 	}
 
 	mutex_lock(&acpi_device_lock);
@@ -681,11 +753,11 @@
 	if (device->parent)
 		device->dev.parent = &device->parent->dev;
 	device->dev.bus = &acpi_bus_type;
-	device->dev.release = &acpi_device_release;
-	result = device_register(&device->dev);
+	device->dev.release = release;
+	result = device_add(&device->dev);
 	if (result) {
 		dev_err(&device->dev, "Error registering device\n");
-		goto end;
+		goto err;
 	}
 
 	result = acpi_device_setup_files(device);
@@ -695,16 +767,20 @@
 
 	device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
 	return 0;
-end:
+
+ err:
 	mutex_lock(&acpi_device_lock);
 	if (device->parent)
 		list_del(&device->node);
 	list_del(&device->wakeup_list);
 	mutex_unlock(&acpi_device_lock);
+
+ err_detach:
+	acpi_detach_data(device->handle, acpi_bus_data_handler);
 	return result;
 }
 
-static void acpi_device_unregister(struct acpi_device *device, int type)
+static void acpi_device_unregister(struct acpi_device *device)
 {
 	mutex_lock(&acpi_device_lock);
 	if (device->parent)
@@ -715,8 +791,20 @@
 
 	acpi_detach_data(device->handle, acpi_bus_data_handler);
 
+	acpi_power_add_remove_device(device, false);
 	acpi_device_remove_files(device);
-	device_unregister(&device->dev);
+	if (device->remove)
+		device->remove(device);
+
+	device_del(&device->dev);
+	/*
+	 * Transition the device to D3cold to drop the reference counts of all
+	 * power resources the device depends on and turn off the ones that have
+	 * no more references.
+	 */
+	acpi_device_set_power(device, ACPI_STATE_D3_COLD);
+	device->handle = NULL;
+	put_device(&device->dev);
 }
 
 /* --------------------------------------------------------------------------
@@ -760,24 +848,6 @@
 	return 0;
 }
 
-static int acpi_start_single_object(struct acpi_device *device)
-{
-	int result = 0;
-	struct acpi_driver *driver;
-
-
-	if (!(driver = device->driver))
-		return 0;
-
-	if (driver->ops.start) {
-		result = driver->ops.start(device);
-		if (result && driver->ops.remove)
-			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
-	}
-
-	return result;
-}
-
 /**
  * acpi_bus_register_driver - register a driver with the ACPI bus
  * @driver: driver being registered
@@ -821,29 +891,23 @@
    -------------------------------------------------------------------------- */
 static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
 {
+	struct acpi_device *device = NULL;
 	acpi_status status;
-	int ret;
-	struct acpi_device *device;
 
 	/*
 	 * Fixed hardware devices do not appear in the namespace and do not
 	 * have handles, but we fabricate acpi_devices for them, so we have
 	 * to deal with them specially.
 	 */
-	if (handle == NULL)
+	if (!handle)
 		return acpi_root;
 
 	do {
 		status = acpi_get_parent(handle, &handle);
-		if (status == AE_NULL_ENTRY)
-			return NULL;
 		if (ACPI_FAILURE(status))
-			return acpi_root;
-
-		ret = acpi_bus_get_device(handle, &device);
-		if (ret == 0)
-			return device;
-	} while (1);
+			return status == AE_NULL_ENTRY ? NULL : acpi_root;
+	} while (acpi_bus_get_device(handle, &device));
+	return device;
 }
 
 acpi_status
@@ -877,52 +941,43 @@
 	return;
 }
 
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
-	device->performance.state = ACPI_STATE_UNKNOWN;
-	return 0;
-}
-
-static acpi_status
-acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
-					     struct acpi_device_wakeup *wakeup)
+static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
+					struct acpi_device_wakeup *wakeup)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *package = NULL;
 	union acpi_object *element = NULL;
 	acpi_status status;
-	int i = 0;
+	int err = -ENODATA;
 
 	if (!wakeup)
-		return AE_BAD_PARAMETER;
+		return -EINVAL;
+
+	INIT_LIST_HEAD(&wakeup->resources);
 
 	/* _PRW */
 	status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
-		return status;
+		return err;
 	}
 
 	package = (union acpi_object *)buffer.pointer;
 
-	if (!package || (package->package.count < 2)) {
-		status = AE_BAD_DATA;
+	if (!package || package->package.count < 2)
 		goto out;
-	}
 
 	element = &(package->package.elements[0]);
-	if (!element) {
-		status = AE_BAD_DATA;
+	if (!element)
 		goto out;
-	}
+
 	if (element->type == ACPI_TYPE_PACKAGE) {
 		if ((element->package.count < 2) ||
 		    (element->package.elements[0].type !=
 		     ACPI_TYPE_LOCAL_REFERENCE)
-		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
-			status = AE_BAD_DATA;
+		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
 			goto out;
-		}
+
 		wakeup->gpe_device =
 		    element->package.elements[0].reference.handle;
 		wakeup->gpe_number =
@@ -931,38 +986,35 @@
 		wakeup->gpe_device = NULL;
 		wakeup->gpe_number = element->integer.value;
 	} else {
-		status = AE_BAD_DATA;
 		goto out;
 	}
 
 	element = &(package->package.elements[1]);
-	if (element->type != ACPI_TYPE_INTEGER) {
-		status = AE_BAD_DATA;
+	if (element->type != ACPI_TYPE_INTEGER)
 		goto out;
-	}
+
 	wakeup->sleep_state = element->integer.value;
 
-	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
-		status = AE_NO_MEMORY;
+	err = acpi_extract_power_resources(package, 2, &wakeup->resources);
+	if (err)
 		goto out;
-	}
-	wakeup->resources.count = package->package.count - 2;
-	for (i = 0; i < wakeup->resources.count; i++) {
-		element = &(package->package.elements[i + 2]);
-		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
-			status = AE_BAD_DATA;
-			goto out;
+
+	if (!list_empty(&wakeup->resources)) {
+		int sleep_state;
+
+		sleep_state = acpi_power_min_system_level(&wakeup->resources);
+		if (sleep_state < wakeup->sleep_state) {
+			acpi_handle_warn(handle, "Overriding _PRW sleep state "
+					 "(S%d) by S%d from power resources\n",
+					 (int)wakeup->sleep_state, sleep_state);
+			wakeup->sleep_state = sleep_state;
 		}
-
-		wakeup->resources.handles[i] = element->reference.handle;
 	}
-
 	acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
 
  out:
 	kfree(buffer.pointer);
-
-	return status;
+	return err;
 }
 
 static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
@@ -1002,17 +1054,17 @@
 {
 	acpi_handle temp;
 	acpi_status status = 0;
-	int psw_error;
+	int err;
 
 	/* Presence of _PRW indicates wake capable */
 	status = acpi_get_handle(device->handle, "_PRW", &temp);
 	if (ACPI_FAILURE(status))
 		return;
 
-	status = acpi_bus_extract_wakeup_device_power_package(device->handle,
-							      &device->wakeup);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
+	err = acpi_bus_extract_wakeup_device_power_package(device->handle,
+							   &device->wakeup);
+	if (err) {
+		dev_err(&device->dev, "_PRW evaluation error: %d\n", err);
 		return;
 	}
 
@@ -1025,20 +1077,73 @@
 	 * So it is necessary to call _DSW object first. Only when it is not
 	 * present will the _PSW object used.
 	 */
-	psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
-	if (psw_error)
+	err = acpi_device_sleep_wake(device, 0, 0, 0);
+	if (err)
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				"error in _DSW or _PSW evaluation\n"));
 }
 
-static void acpi_bus_add_power_resource(acpi_handle handle);
-
-static int acpi_bus_get_power_flags(struct acpi_device *device)
+static void acpi_bus_init_power_state(struct acpi_device *device, int state)
 {
-	acpi_status status = 0;
-	acpi_handle handle = NULL;
-	u32 i = 0;
+	struct acpi_device_power_state *ps = &device->power.states[state];
+	char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	acpi_handle handle;
+	acpi_status status;
 
+	INIT_LIST_HEAD(&ps->resources);
+
+	/* Evaluate "_PRx" to get referenced power resources */
+	status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer);
+	if (ACPI_SUCCESS(status)) {
+		union acpi_object *package = buffer.pointer;
+
+		if (buffer.length && package
+		    && package->type == ACPI_TYPE_PACKAGE
+		    && package->package.count) {
+			int err = acpi_extract_power_resources(package, 0,
+							       &ps->resources);
+			if (!err)
+				device->power.flags.power_resources = 1;
+		}
+		ACPI_FREE(buffer.pointer);
+	}
+
+	/* Evaluate "_PSx" to see if we can do explicit sets */
+	pathname[2] = 'S';
+	status = acpi_get_handle(device->handle, pathname, &handle);
+	if (ACPI_SUCCESS(status))
+		ps->flags.explicit_set = 1;
+
+	/*
+	 * State is valid if there are means to put the device into it.
+	 * D3hot is only valid if _PR3 present.
+	 */
+	if (!list_empty(&ps->resources)
+	    || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) {
+		ps->flags.valid = 1;
+		ps->flags.os_accessible = 1;
+	}
+
+	ps->power = -1;		/* Unknown - driver assigned */
+	ps->latency = -1;	/* Unknown - driver assigned */
+}
+
+static void acpi_bus_get_power_flags(struct acpi_device *device)
+{
+	acpi_status status;
+	acpi_handle handle;
+	u32 i;
+
+	/* Presence of _PS0|_PR0 indicates 'power manageable' */
+	status = acpi_get_handle(device->handle, "_PS0", &handle);
+	if (ACPI_FAILURE(status)) {
+		status = acpi_get_handle(device->handle, "_PR0", &handle);
+		if (ACPI_FAILURE(status))
+			return;
+	}
+
+	device->flags.power_manageable = 1;
 
 	/*
 	 * Power Management Flags
@@ -1053,40 +1158,10 @@
 	/*
 	 * Enumerate supported power management states
 	 */
-	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
-		struct acpi_device_power_state *ps = &device->power.states[i];
-		char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
+	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++)
+		acpi_bus_init_power_state(device, i);
 
-		/* Evaluate "_PRx" to se if power resources are referenced */
-		acpi_evaluate_reference(device->handle, object_name, NULL,
-					&ps->resources);
-		if (ps->resources.count) {
-			int j;
-
-			device->power.flags.power_resources = 1;
-			for (j = 0; j < ps->resources.count; j++)
-				acpi_bus_add_power_resource(ps->resources.handles[j]);
-		}
-
-		/* Evaluate "_PSx" to see if we can do explicit sets */
-		object_name[2] = 'S';
-		status = acpi_get_handle(device->handle, object_name, &handle);
-		if (ACPI_SUCCESS(status))
-			ps->flags.explicit_set = 1;
-
-		/*
-		 * State is valid if there are means to put the device into it.
-		 * D3hot is only valid if _PR3 present.
-		 */
-		if (ps->resources.count ||
-		    (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) {
-			ps->flags.valid = 1;
-			ps->flags.os_accessible = 1;
-		}
-
-		ps->power = -1;	/* Unknown - driver assigned */
-		ps->latency = -1;	/* Unknown - driver assigned */
-	}
+	INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
 
 	/* Set defaults for D0 and D3 states (always valid) */
 	device->power.states[ACPI_STATE_D0].flags.valid = 1;
@@ -1103,17 +1178,17 @@
 			device->power.flags.power_resources)
 		device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
 
-	acpi_bus_init_power(device);
-
-	return 0;
+	if (acpi_bus_init_power(device)) {
+		acpi_free_power_resources_lists(device);
+		device->flags.power_manageable = 0;
+	}
 }
 
-static int acpi_bus_get_flags(struct acpi_device *device)
+static void acpi_bus_get_flags(struct acpi_device *device)
 {
 	acpi_status status = AE_OK;
 	acpi_handle temp = NULL;
 
-
 	/* Presence of _STA indicates 'dynamic_status' */
 	status = acpi_get_handle(device->handle, "_STA", &temp);
 	if (ACPI_SUCCESS(status))
@@ -1133,21 +1208,6 @@
 		if (ACPI_SUCCESS(status))
 			device->flags.ejectable = 1;
 	}
-
-	/* Power resources cannot be power manageable. */
-	if (device->device_type == ACPI_BUS_TYPE_POWER)
-		return 0;
-
-	/* Presence of _PS0|_PR0 indicates 'power manageable' */
-	status = acpi_get_handle(device->handle, "_PS0", &temp);
-	if (ACPI_FAILURE(status))
-		status = acpi_get_handle(device->handle, "_PR0", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.power_manageable = 1;
-
-	/* TBD: Performance management */
-
-	return 0;
 }
 
 static void acpi_device_get_busid(struct acpi_device *device)
@@ -1372,56 +1432,32 @@
 	}
 }
 
-static int acpi_device_set_context(struct acpi_device *device)
+void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
+			     int type, unsigned long long sta)
 {
-	acpi_status status;
-
-	/*
-	 * Context
-	 * -------
-	 * Attach this 'struct acpi_device' to the ACPI object.  This makes
-	 * resolutions from handle->device very efficient.  Fixed hardware
-	 * devices have no handles, so we skip them.
-	 */
-	if (!device->handle)
-		return 0;
-
-	status = acpi_attach_data(device->handle,
-				  acpi_bus_data_handler, device);
-	if (ACPI_SUCCESS(status))
-		return 0;
-
-	printk(KERN_ERR PREFIX "Error attaching device data\n");
-	return -ENODEV;
+	INIT_LIST_HEAD(&device->pnp.ids);
+	device->device_type = type;
+	device->handle = handle;
+	device->parent = acpi_bus_get_parent(handle);
+	STRUCT_TO_INT(device->status) = sta;
+	acpi_device_get_busid(device);
+	acpi_device_set_id(device);
+	acpi_bus_get_flags(device);
+	device->flags.match_driver = false;
+	device_initialize(&device->dev);
+	dev_set_uevent_suppress(&device->dev, true);
 }
 
-static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
+void acpi_device_add_finalize(struct acpi_device *device)
 {
-	if (!dev)
-		return -EINVAL;
-
-	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
-	device_release_driver(&dev->dev);
-
-	if (!rmdevice)
-		return 0;
-
-	/*
-	 * unbind _ADR-Based Devices when hot removal
-	 */
-	if (dev->flags.bus_address) {
-		if ((dev->parent) && (dev->parent->ops.unbind))
-			dev->parent->ops.unbind(dev);
-	}
-	acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
-
-	return 0;
+	device->flags.match_driver = true;
+	dev_set_uevent_suppress(&device->dev, false);
+	kobject_uevent(&device->dev.kobj, KOBJ_ADD);
 }
 
 static int acpi_add_single_object(struct acpi_device **child,
 				  acpi_handle handle, int type,
-				  unsigned long long sta,
-				  struct acpi_bus_ops *ops)
+				  unsigned long long sta)
 {
 	int result;
 	struct acpi_device *device;
@@ -1433,102 +1469,25 @@
 		return -ENOMEM;
 	}
 
-	INIT_LIST_HEAD(&device->pnp.ids);
-	device->device_type = type;
-	device->handle = handle;
-	device->parent = acpi_bus_get_parent(handle);
-	device->bus_ops = *ops; /* workround for not call .start */
-	STRUCT_TO_INT(device->status) = sta;
-
-	acpi_device_get_busid(device);
-
-	/*
-	 * Flags
-	 * -----
-	 * Note that we only look for object handles -- cannot evaluate objects
-	 * until we know the device is present and properly initialized.
-	 */
-	result = acpi_bus_get_flags(device);
-	if (result)
-		goto end;
-
-	/*
-	 * Initialize Device
-	 * -----------------
-	 * TBD: Synch with Core's enumeration/initialization process.
-	 */
-	acpi_device_set_id(device);
-
-	/*
-	 * Power Management
-	 * ----------------
-	 */
-	if (device->flags.power_manageable) {
-		result = acpi_bus_get_power_flags(device);
-		if (result)
-			goto end;
-	}
-
-	/*
-	 * Wakeup device management
-	 *-----------------------
-	 */
+	acpi_init_device_object(device, handle, type, sta);
+	acpi_bus_get_power_flags(device);
 	acpi_bus_get_wakeup_device_flags(device);
 
-	/*
-	 * Performance Management
-	 * ----------------------
-	 */
-	if (device->flags.performance_manageable) {
-		result = acpi_bus_get_perf_flags(device);
-		if (result)
-			goto end;
-	}
-
-	if ((result = acpi_device_set_context(device)))
-		goto end;
-
-	result = acpi_device_register(device);
-
-	/*
-	 * Bind _ADR-Based Devices when hot add
-	 */
-	if (device->flags.bus_address) {
-		if (device->parent && device->parent->ops.bind)
-			device->parent->ops.bind(device);
-	}
-
-end:
-	if (!result) {
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			"Adding %s [%s] parent %s\n", dev_name(&device->dev),
-			 (char *) buffer.pointer,
-			 device->parent ? dev_name(&device->parent->dev) :
-					  "(null)"));
-		kfree(buffer.pointer);
-		*child = device;
-	} else
+	result = acpi_device_add(device, acpi_device_release);
+	if (result) {
 		acpi_device_release(&device->dev);
+		return result;
+	}
 
-	return result;
-}
-
-#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
-			  ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING)
-
-static void acpi_bus_add_power_resource(acpi_handle handle)
-{
-	struct acpi_bus_ops ops = {
-		.acpi_op_add = 1,
-		.acpi_op_start = 1,
-	};
-	struct acpi_device *device = NULL;
-
-	acpi_bus_get_device(handle, &device);
-	if (!device)
-		acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
-					ACPI_STA_DEFAULT, &ops);
+	acpi_power_add_remove_device(device, true);
+	acpi_device_add_finalize(device);
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n",
+		dev_name(&device->dev), (char *) buffer.pointer,
+		device->parent ? dev_name(&device->parent->dev) : "(null)"));
+	kfree(buffer.pointer);
+	*child = device;
+	return 0;
 }
 
 static int acpi_bus_type_and_status(acpi_handle handle, int *type,
@@ -1570,218 +1529,248 @@
 	return 0;
 }
 
-static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
-				      void *context, void **return_value)
+static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
+				      void *not_used, void **return_value)
 {
-	struct acpi_bus_ops *ops = context;
+	struct acpi_device *device = NULL;
 	int type;
 	unsigned long long sta;
-	struct acpi_device *device;
 	acpi_status status;
 	int result;
 
+	acpi_bus_get_device(handle, &device);
+	if (device)
+		goto out;
+
 	result = acpi_bus_type_and_status(handle, &type, &sta);
 	if (result)
 		return AE_OK;
 
+	if (type == ACPI_BUS_TYPE_POWER) {
+		acpi_add_power_resource(handle);
+		return AE_OK;
+	}
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;
 		acpi_handle temp;
 
 		status = acpi_get_handle(handle, "_PRW", &temp);
-		if (ACPI_SUCCESS(status))
+		if (ACPI_SUCCESS(status)) {
 			acpi_bus_extract_wakeup_device_power_package(handle,
 								     &wakeup);
+			acpi_power_resources_list_free(&wakeup.resources);
+		}
 		return AE_CTRL_DEPTH;
 	}
 
-	/*
-	 * We may already have an acpi_device from a previous enumeration.  If
-	 * so, we needn't add it again, but we may still have to start it.
-	 */
-	device = NULL;
-	acpi_bus_get_device(handle, &device);
-	if (ops->acpi_op_add && !device) {
-		acpi_add_single_object(&device, handle, type, sta, ops);
-		/* Is the device a known good platform device? */
-		if (device
-		    && !acpi_match_device_ids(device, acpi_platform_device_ids))
-			acpi_create_platform_device(device);
-	}
-
+	acpi_add_single_object(&device, handle, type, sta);
 	if (!device)
 		return AE_CTRL_DEPTH;
 
-	if (ops->acpi_op_start && !(ops->acpi_op_add)) {
-		status = acpi_start_single_object(device);
-		if (ACPI_FAILURE(status))
-			return AE_CTRL_DEPTH;
-	}
-
+ out:
 	if (!*return_value)
 		*return_value = device;
+
 	return AE_OK;
 }
 
-static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
-			 struct acpi_device **child)
+static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
 {
-	acpi_status status;
-	void *device = NULL;
+	struct acpi_scan_handler *handler;
 
-	status = acpi_bus_check_add(handle, 0, ops, &device);
-	if (ACPI_SUCCESS(status))
-		acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
-				    acpi_bus_check_add, NULL, ops, &device);
+	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+		const struct acpi_device_id *devid;
 
-	if (child)
-		*child = device;
+		for (devid = handler->ids; devid->id[0]; devid++) {
+			int ret;
 
-	if (device)
-		return 0;
-	else
-		return -ENODEV;
+			if (strcmp((char *)devid->id, id))
+				continue;
+
+			ret = handler->attach(device, devid);
+			if (ret > 0) {
+				device->handler = handler;
+				return ret;
+			} else if (ret < 0) {
+				return ret;
+			}
+		}
+	}
+	return 0;
 }
 
-/*
- * acpi_bus_add and acpi_bus_start
+static int acpi_scan_attach_handler(struct acpi_device *device)
+{
+	struct acpi_hardware_id *hwid;
+	int ret = 0;
+
+	list_for_each_entry(hwid, &device->pnp.ids, list) {
+		ret = acpi_scan_do_attach_handler(device, hwid->id);
+		if (ret)
+			break;
+
+	}
+	return ret;
+}
+
+static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
+					  void *not_used, void **ret_not_used)
+{
+	struct acpi_device *device;
+	unsigned long long sta_not_used;
+	int ret;
+
+	/*
+	 * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
+	 * namespace walks prematurely.
+	 */
+	if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
+		return AE_OK;
+
+	if (acpi_bus_get_device(handle, &device))
+		return AE_CTRL_DEPTH;
+
+	ret = acpi_scan_attach_handler(device);
+	if (ret)
+		return ret > 0 ? AE_OK : AE_CTRL_DEPTH;
+
+	ret = device_attach(&device->dev);
+	return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
+}
+
+/**
+ * acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
+ * @handle: Root of the namespace scope to scan.
  *
- * scan a given ACPI tree and (probably recently hot-plugged)
- * create and add or starts found devices.
+ * Scan a given ACPI tree (probably recently hot-plugged) and create and add
+ * found devices.
  *
- * If no devices were found -ENODEV is returned which does not
- * mean that this is a real error, there just have been no suitable
- * ACPI objects in the table trunk from which the kernel could create
- * a device and add/start an appropriate driver.
+ * If no devices were found, -ENODEV is returned, but it does not mean that
+ * there has been a real error.  There just have been no suitable ACPI objects
+ * in the table trunk from which the kernel could create a device and add an
+ * appropriate driver.
+ *
+ * Must be called under acpi_scan_lock.
  */
-
-int
-acpi_bus_add(struct acpi_device **child,
-	     struct acpi_device *parent, acpi_handle handle, int type)
+int acpi_bus_scan(acpi_handle handle)
 {
-	struct acpi_bus_ops ops;
+	void *device = NULL;
+	int error = 0;
 
-	memset(&ops, 0, sizeof(ops));
-	ops.acpi_op_add = 1;
-
-	return acpi_bus_scan(handle, &ops, child);
-}
-EXPORT_SYMBOL(acpi_bus_add);
-
-int acpi_bus_start(struct acpi_device *device)
-{
-	struct acpi_bus_ops ops;
-	int result;
+	if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
+		acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+				    acpi_bus_check_add, NULL, NULL, &device);
 
 	if (!device)
-		return -EINVAL;
+		error = -ENODEV;
+	else if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL)))
+		acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+				    acpi_bus_device_attach, NULL, NULL, NULL);
 
-	memset(&ops, 0, sizeof(ops));
-	ops.acpi_op_start = 1;
-
-	result = acpi_bus_scan(device->handle, &ops, NULL);
-
-	acpi_update_all_gpes();
-
-	return result;
+	return error;
 }
-EXPORT_SYMBOL(acpi_bus_start);
+EXPORT_SYMBOL(acpi_bus_scan);
 
-int acpi_bus_trim(struct acpi_device *start, int rmdevice)
+static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
+					  void *not_used, void **ret_not_used)
 {
-	acpi_status status;
-	struct acpi_device *parent, *child;
-	acpi_handle phandle, chandle;
-	acpi_object_type type;
-	u32 level = 1;
-	int err = 0;
+	struct acpi_device *device = NULL;
 
-	parent = start;
-	phandle = start->handle;
-	child = chandle = NULL;
+	if (!acpi_bus_get_device(handle, &device)) {
+		struct acpi_scan_handler *dev_handler = device->handler;
 
-	while ((level > 0) && parent && (!err)) {
-		status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
-					      chandle, &chandle);
+		device->removal_type = ACPI_BUS_REMOVAL_EJECT;
+		if (dev_handler) {
+			if (dev_handler->detach)
+				dev_handler->detach(device);
 
-		/*
-		 * If this scope is exhausted then move our way back up.
-		 */
-		if (ACPI_FAILURE(status)) {
-			level--;
-			chandle = phandle;
-			acpi_get_parent(phandle, &phandle);
-			child = parent;
-			parent = parent->parent;
-
-			if (level == 0)
-				err = acpi_bus_remove(child, rmdevice);
-			else
-				err = acpi_bus_remove(child, 1);
-
-			continue;
+			device->handler = NULL;
+		} else {
+			device_release_driver(&device->dev);
 		}
-
-		status = acpi_get_type(chandle, &type);
-		if (ACPI_FAILURE(status)) {
-			continue;
-		}
-		/*
-		 * If there is a device corresponding to chandle then
-		 * parse it (depth-first).
-		 */
-		if (acpi_bus_get_device(chandle, &child) == 0) {
-			level++;
-			phandle = chandle;
-			chandle = NULL;
-			parent = child;
-		}
-		continue;
 	}
-	return err;
+	return AE_OK;
+}
+
+static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
+				   void *not_used, void **ret_not_used)
+{
+	struct acpi_device *device = NULL;
+
+	if (!acpi_bus_get_device(handle, &device))
+		acpi_device_unregister(device);
+
+	return AE_OK;
+}
+
+/**
+ * acpi_bus_trim - Remove ACPI device node and all of its descendants
+ * @start: Root of the ACPI device nodes subtree to remove.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+void acpi_bus_trim(struct acpi_device *start)
+{
+	/*
+	 * Execute acpi_bus_device_detach() as a post-order callback to detach
+	 * all ACPI drivers from the device nodes being removed.
+	 */
+	acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
+			    acpi_bus_device_detach, NULL, NULL);
+	acpi_bus_device_detach(start->handle, 0, NULL, NULL);
+	/*
+	 * Execute acpi_bus_remove() as a post-order callback to remove device
+	 * nodes in the given namespace scope.
+	 */
+	acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
+			    acpi_bus_remove, NULL, NULL);
+	acpi_bus_remove(start->handle, 0, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(acpi_bus_trim);
 
 static int acpi_bus_scan_fixed(void)
 {
 	int result = 0;
-	struct acpi_device *device = NULL;
-	struct acpi_bus_ops ops;
-
-	memset(&ops, 0, sizeof(ops));
-	ops.acpi_op_add = 1;
-	ops.acpi_op_start = 1;
 
 	/*
 	 * Enumerate all fixed-feature devices.
 	 */
-	if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
+	if (!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
+		struct acpi_device *device = NULL;
+
 		result = acpi_add_single_object(&device, NULL,
 						ACPI_BUS_TYPE_POWER_BUTTON,
-						ACPI_STA_DEFAULT,
-						&ops);
+						ACPI_STA_DEFAULT);
+		if (result)
+			return result;
+
+		result = device_attach(&device->dev);
+		if (result < 0)
+			return result;
+
 		device_init_wakeup(&device->dev, true);
 	}
 
-	if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
+	if (!(acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON)) {
+		struct acpi_device *device = NULL;
+
 		result = acpi_add_single_object(&device, NULL,
 						ACPI_BUS_TYPE_SLEEP_BUTTON,
-						ACPI_STA_DEFAULT,
-						&ops);
+						ACPI_STA_DEFAULT);
+		if (result)
+			return result;
+
+		result = device_attach(&device->dev);
 	}
 
-	return result;
+	return result < 0 ? result : 0;
 }
 
 int __init acpi_scan_init(void)
 {
 	int result;
-	struct acpi_bus_ops ops;
-
-	memset(&ops, 0, sizeof(ops));
-	ops.acpi_op_add = 1;
-	ops.acpi_op_start = 1;
 
 	result = bus_register(&acpi_bus_type);
 	if (result) {
@@ -1789,20 +1778,33 @@
 		printk(KERN_ERR PREFIX "Could not register bus type\n");
 	}
 
-	acpi_power_init();
+	acpi_pci_root_init();
+	acpi_pci_link_init();
+	acpi_platform_init();
+	acpi_csrt_init();
+	acpi_container_init();
 
+	mutex_lock(&acpi_scan_lock);
 	/*
 	 * Enumerate devices in the ACPI namespace.
 	 */
-	result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
-
-	if (!result)
-		result = acpi_bus_scan_fixed();
-
+	result = acpi_bus_scan(ACPI_ROOT_OBJECT);
 	if (result)
-		acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
-	else
-		acpi_update_all_gpes();
+		goto out;
 
+	result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root);
+	if (result)
+		goto out;
+
+	result = acpi_bus_scan_fixed();
+	if (result) {
+		acpi_device_unregister(acpi_root);
+		goto out;
+	}
+
+	acpi_update_all_gpes();
+
+ out:
+	mutex_unlock(&acpi_scan_lock);
 	return result;
 }
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 2fcc67d..6d3a06a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -177,6 +177,14 @@
 	},
 	{
 	.callback = init_nvs_nosave,
+	.ident = "Sony Vaio VGN-FW41E_H",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW41E_H"),
+		},
+	},
+	{
+	.callback = init_nvs_nosave,
 	.ident = "Sony Vaio VGN-FW21E",
 	.matches = {
 		DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
@@ -386,6 +394,8 @@
 
 	acpi_target_sleep_state = ACPI_STATE_S0;
 
+	acpi_resume_power_resources();
+
 	/* If we were woken with the fixed power button, provide a small
 	 * hint to userspace in the form of a wakeup event on the fixed power
 	 * button device (if it can be found).
@@ -577,7 +587,28 @@
 	.end = acpi_pm_end,
 	.recover = acpi_pm_finish,
 };
-#endif /* CONFIG_SUSPEND */
+
+static void acpi_sleep_suspend_setup(void)
+{
+	int i;
+
+	for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
+		acpi_status status;
+		u8 type_a, type_b;
+
+		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+		if (ACPI_SUCCESS(status)) {
+			sleep_states[i] = 1;
+			pr_cont(" S%d", i);
+		}
+	}
+
+	suspend_set_ops(old_suspend_ordering ?
+		&acpi_suspend_ops_old : &acpi_suspend_ops);
+}
+#else /* !CONFIG_SUSPEND */
+static inline void acpi_sleep_suspend_setup(void) {}
+#endif /* !CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATION
 static unsigned long s4_hardware_signature;
@@ -698,7 +729,30 @@
 	.restore_cleanup = acpi_pm_thaw,
 	.recover = acpi_pm_finish,
 };
-#endif /* CONFIG_HIBERNATION */
+
+static void acpi_sleep_hibernate_setup(void)
+{
+	acpi_status status;
+	u8 type_a, type_b;
+
+	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+	if (ACPI_FAILURE(status))
+		return;
+
+	hibernation_set_ops(old_suspend_ordering ?
+			&acpi_hibernation_ops_old : &acpi_hibernation_ops);
+	sleep_states[ACPI_STATE_S4] = 1;
+	pr_cont(KERN_CONT " S4");
+	if (nosigcheck)
+		return;
+
+	acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
+	if (facs)
+		s4_hardware_signature = facs->hardware_signature;
+}
+#else /* !CONFIG_HIBERNATION */
+static inline void acpi_sleep_hibernate_setup(void) {}
+#endif /* !CONFIG_HIBERNATION */
 
 int acpi_suspend(u32 acpi_state)
 {
@@ -734,9 +788,6 @@
 {
 	acpi_status status;
 	u8 type_a, type_b;
-#ifdef CONFIG_SUSPEND
-	int i = 0;
-#endif
 
 	if (acpi_disabled)
 		return 0;
@@ -744,45 +795,19 @@
 	acpi_sleep_dmi_check();
 
 	sleep_states[ACPI_STATE_S0] = 1;
-	printk(KERN_INFO PREFIX "(supports S0");
+	pr_info(PREFIX "(supports S0");
 
-#ifdef CONFIG_SUSPEND
-	for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
-		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-		if (ACPI_SUCCESS(status)) {
-			sleep_states[i] = 1;
-			printk(KERN_CONT " S%d", i);
-		}
-	}
+	acpi_sleep_suspend_setup();
+	acpi_sleep_hibernate_setup();
 
-	suspend_set_ops(old_suspend_ordering ?
-		&acpi_suspend_ops_old : &acpi_suspend_ops);
-#endif
-
-#ifdef CONFIG_HIBERNATION
-	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-	if (ACPI_SUCCESS(status)) {
-		hibernation_set_ops(old_suspend_ordering ?
-			&acpi_hibernation_ops_old : &acpi_hibernation_ops);
-		sleep_states[ACPI_STATE_S4] = 1;
-		printk(KERN_CONT " S4");
-		if (!nosigcheck) {
-			acpi_get_table(ACPI_SIG_FACS, 1,
-				(struct acpi_table_header **)&facs);
-			if (facs)
-				s4_hardware_signature =
-					facs->hardware_signature;
-		}
-	}
-#endif
 	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
 	if (ACPI_SUCCESS(status)) {
 		sleep_states[ACPI_STATE_S5] = 1;
-		printk(KERN_CONT " S5");
+		pr_cont(" S5");
 		pm_power_off_prepare = acpi_power_off_prepare;
 		pm_power_off = acpi_power_off;
 	}
-	printk(KERN_CONT ")\n");
+	pr_cont(")\n");
 	/*
 	 * Register the tts_notifier to reboot notifier list so that the _TTS
 	 * object can also be evaluated when the system enters S5.
diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h
index 74d59c8..0143540 100644
--- a/drivers/acpi/sleep.h
+++ b/drivers/acpi/sleep.h
@@ -6,3 +6,5 @@
 
 extern struct list_head acpi_wakeup_device_list;
 extern struct mutex acpi_device_lock;
+
+extern void acpi_resume_power_resources(void);
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index ea61ca9..41c0504 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -498,7 +498,7 @@
 		result = acpi_get_gpe_device(index, handle);
 		if (result) {
 			ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
-					"Invalid GPE 0x%x\n", index));
+					"Invalid GPE 0x%x", index));
 			goto end;
 		}
 		result = acpi_get_gpe_status(*handle, index, status);
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 2572d97..d67a1fe 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -204,7 +204,7 @@
 acpi_table_parse_entries(char *id,
 			     unsigned long table_size,
 			     int entry_id,
-			     acpi_table_entry_handler handler,
+			     acpi_tbl_entry_handler handler,
 			     unsigned int max_entries)
 {
 	struct acpi_table_header *table_header = NULL;
@@ -269,7 +269,7 @@
 
 int __init
 acpi_table_parse_madt(enum acpi_madt_type id,
-		      acpi_table_entry_handler handler, unsigned int max_entries)
+		      acpi_tbl_entry_handler handler, unsigned int max_entries)
 {
 	return acpi_table_parse_entries(ACPI_SIG_MADT,
 					    sizeof(struct acpi_table_madt), id,
@@ -285,7 +285,7 @@
  * Scan the ACPI System Descriptor Table (STD) for a table matching @id,
  * run @handler on it.  Return 0 if table found, return on if not.
  */
-int __init acpi_table_parse(char *id, acpi_table_handler handler)
+int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
 {
 	struct acpi_table_header *table = NULL;
 	acpi_size tbl_size;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 506fbd4..8470771 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -97,7 +97,7 @@
 MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
 
 static int acpi_thermal_add(struct acpi_device *device);
-static int acpi_thermal_remove(struct acpi_device *device, int type);
+static int acpi_thermal_remove(struct acpi_device *device);
 static void acpi_thermal_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id  thermal_device_ids[] = {
@@ -288,7 +288,7 @@
 	if (flags != ACPI_TRIPS_INIT)	\
 		ACPI_EXCEPTION((AE_INFO, AE_ERROR,	\
 		"ACPI thermal trip point %s changed\n"	\
-		"Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
+		"Please send acpidump to linux-acpi@vger.kernel.org", str)); \
 } while (0)
 
 static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
@@ -531,6 +531,10 @@
 {
 	struct acpi_thermal *tz = data;
 
+	if (!tz->tz_enabled) {
+		pr_warn("thermal zone is disabled \n");
+		return;
+	}
 	thermal_zone_device_update(tz->thermal_zone);
 }
 
@@ -1111,7 +1115,7 @@
 	return result;
 }
 
-static int acpi_thermal_remove(struct acpi_device *device, int type)
+static int acpi_thermal_remove(struct acpi_device *device)
 {
 	struct acpi_thermal *tz = NULL;
 
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index ac9a69c..313f959 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -88,7 +88,7 @@
 
 static int register_count = 0;
 static int acpi_video_bus_add(struct acpi_device *device);
-static int acpi_video_bus_remove(struct acpi_device *device, int type);
+static int acpi_video_bus_remove(struct acpi_device *device);
 static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id video_device_ids[] = {
@@ -673,7 +673,7 @@
 			br->levels[i] = br->levels[i - level_ac_battery];
 		count += level_ac_battery;
 	} else if (level_ac_battery > 2)
-		ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n"));
+		ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package"));
 
 	/* Check if the _BCL package is in a reversed order */
 	if (max_level == br->levels[2]) {
@@ -682,7 +682,7 @@
 			acpi_video_cmp_level, NULL);
 	} else if (max_level != br->levels[count - 1])
 		ACPI_ERROR((AE_INFO,
-			    "Found unordered _BCL package\n"));
+			    "Found unordered _BCL package"));
 
 	br->count = count;
 	device->brightness = br;
@@ -1740,7 +1740,7 @@
 	return error;
 }
 
-static int acpi_video_bus_remove(struct acpi_device *device, int type)
+static int acpi_video_bus_remove(struct acpi_device *device)
 {
 	struct acpi_video_bus *video = NULL;
 
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 4979127..495aeed 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1061,6 +1061,86 @@
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+	int rc;
+	unsigned int maxvec;
+
+	if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+		rc = pci_enable_msi_block_auto(pdev, &maxvec);
+		if (rc > 0) {
+			if ((rc == maxvec) || (rc == 1))
+				return rc;
+			/*
+			 * Assume that advantage of multipe MSIs is negated,
+			 * so fallback to single MSI mode to save resources
+			 */
+			pci_disable_msi(pdev);
+			if (!pci_enable_msi(pdev))
+				return 1;
+		}
+	}
+
+	pci_intx(pdev, 1);
+	return 0;
+}
+
+/**
+ *	ahci_host_activate - start AHCI host, request IRQs and register it
+ *	@host: target ATA host
+ *	@irq: base IRQ number to request
+ *	@n_msis: number of MSIs allocated for this host
+ *	@irq_handler: irq_handler used when requesting IRQs
+ *	@irq_flags: irq_flags used when requesting IRQs
+ *
+ *	Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ *	when multiple MSIs were allocated. That is one MSI per port, starting
+ *	from @irq.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+	int i, rc;
+
+	/* Sharing Last Message among several ports is not supported */
+	if (n_msis < host->n_ports)
+		return -EINVAL;
+
+	rc = ata_host_start(host);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < host->n_ports; i++) {
+		rc = devm_request_threaded_irq(host->dev,
+			irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+			dev_driver_string(host->dev), host->ports[i]);
+		if (rc)
+			goto out_free_irqs;
+	}
+
+	for (i = 0; i < host->n_ports; i++)
+		ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+	rc = ata_host_register(host, &ahci_sht);
+	if (rc)
+		goto out_free_all_irqs;
+
+	return 0;
+
+out_free_all_irqs:
+	i = host->n_ports;
+out_free_irqs:
+	for (i--; i >= 0; i--)
+		devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+	return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	unsigned int board_id = ent->driver_data;
@@ -1069,7 +1149,7 @@
 	struct device *dev = &pdev->dev;
 	struct ahci_host_priv *hpriv;
 	struct ata_host *host;
-	int n_ports, i, rc;
+	int n_ports, n_msis, i, rc;
 	int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
 	VPRINTK("ENTER\n");
@@ -1156,11 +1236,12 @@
 	if (ahci_sb600_enable_64bit(pdev))
 		hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
 
-	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-		pci_intx(pdev, 1);
-
 	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+	n_msis = ahci_init_interrupts(pdev, hpriv);
+	if (n_msis > 1)
+		hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
 	/* save initial config */
 	ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1256,6 +1337,10 @@
 	ahci_pci_print_info(host);
 
 	pci_set_master(pdev);
+
+	if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
+		return ahci_host_activate(host, pdev->irq, n_msis);
+
 	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
 				 &ahci_sht);
 }
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 9be4712..b830e6c 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -231,6 +231,7 @@
 	AHCI_HFLAG_DELAY_ENGINE		= (1 << 15), /* do not start engine on
 						        port start (wait until
 						        error-handling stage) */
+	AHCI_HFLAG_MULTI_MSI		= (1 << 16), /* multiple PCI MSIs */
 
 	/* ap->flags bits */
 
@@ -297,6 +298,8 @@
 	unsigned int		ncq_saw_d2h:1;
 	unsigned int		ncq_saw_dmas:1;
 	unsigned int		ncq_saw_sdb:1;
+	u32			intr_status;	/* interrupts to handle */
+	spinlock_t		lock;		/* protects parent ata_port */
 	u32 			intr_mask;	/* interrupts to enable */
 	bool			fbs_supported;	/* set iff FBS is supported */
 	bool			fbs_enabled;	/* set iff FBS is enabled */
@@ -359,7 +362,10 @@
 			  struct ata_port_info *pi);
 int ahci_reset_em(struct ata_host *host);
 irqreturn_t ahci_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance);
 void ahci_print_info(struct ata_host *host, const char *scc_s);
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis);
 
 static inline void __iomem *__ahci_port_base(struct ata_host *host,
 					     unsigned int port_no)
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 6cd7805..34c8216 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1655,19 +1655,16 @@
 		ata_port_abort(ap);
 }
 
-static void ahci_port_intr(struct ata_port *ap)
+static void ahci_handle_port_interrupt(struct ata_port *ap,
+				       void __iomem *port_mmio, u32 status)
 {
-	void __iomem *port_mmio = ahci_port_base(ap);
 	struct ata_eh_info *ehi = &ap->link.eh_info;
 	struct ahci_port_priv *pp = ap->private_data;
 	struct ahci_host_priv *hpriv = ap->host->private_data;
 	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
-	u32 status, qc_active = 0;
+	u32 qc_active = 0;
 	int rc;
 
-	status = readl(port_mmio + PORT_IRQ_STAT);
-	writel(status, port_mmio + PORT_IRQ_STAT);
-
 	/* ignore BAD_PMP while resetting */
 	if (unlikely(resetting))
 		status &= ~PORT_IRQ_BAD_PMP;
@@ -1743,6 +1740,107 @@
 	}
 }
 
+void ahci_port_intr(struct ata_port *ap)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u32 status;
+
+	status = readl(port_mmio + PORT_IRQ_STAT);
+	writel(status, port_mmio + PORT_IRQ_STAT);
+
+	ahci_handle_port_interrupt(ap, port_mmio, status);
+}
+
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
+{
+	struct ata_port *ap = dev_instance;
+	struct ahci_port_priv *pp = ap->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	unsigned long flags;
+	u32 status;
+
+	spin_lock_irqsave(&ap->host->lock, flags);
+	status = pp->intr_status;
+	if (status)
+		pp->intr_status = 0;
+	spin_unlock_irqrestore(&ap->host->lock, flags);
+
+	spin_lock_bh(ap->lock);
+	ahci_handle_port_interrupt(ap, port_mmio, status);
+	spin_unlock_bh(ap->lock);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(ahci_thread_fn);
+
+void ahci_hw_port_interrupt(struct ata_port *ap)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_port_priv *pp = ap->private_data;
+	u32 status;
+
+	status = readl(port_mmio + PORT_IRQ_STAT);
+	writel(status, port_mmio + PORT_IRQ_STAT);
+
+	pp->intr_status |= status;
+}
+
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance)
+{
+	struct ata_port *ap_this = dev_instance;
+	struct ahci_port_priv *pp = ap_this->private_data;
+	struct ata_host *host = ap_this->host;
+	struct ahci_host_priv *hpriv = host->private_data;
+	void __iomem *mmio = hpriv->mmio;
+	unsigned int i;
+	u32 irq_stat, irq_masked;
+
+	VPRINTK("ENTER\n");
+
+	spin_lock(&host->lock);
+
+	irq_stat = readl(mmio + HOST_IRQ_STAT);
+
+	if (!irq_stat) {
+		u32 status = pp->intr_status;
+
+		spin_unlock(&host->lock);
+
+		VPRINTK("EXIT\n");
+
+		return status ? IRQ_WAKE_THREAD : IRQ_NONE;
+	}
+
+	irq_masked = irq_stat & hpriv->port_map;
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap;
+
+		if (!(irq_masked & (1 << i)))
+			continue;
+
+		ap = host->ports[i];
+		if (ap) {
+			ahci_hw_port_interrupt(ap);
+			VPRINTK("port %u\n", i);
+		} else {
+			VPRINTK("port %u (no irq)\n", i);
+			if (ata_ratelimit())
+				dev_warn(host->dev,
+					 "interrupt on disabled port %u\n", i);
+		}
+	}
+
+	writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+	spin_unlock(&host->lock);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL_GPL(ahci_hw_interrupt);
+
 irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 {
 	struct ata_host *host = dev_instance;
@@ -2196,6 +2294,14 @@
 	 */
 	pp->intr_mask = DEF_PORT_IRQ;
 
+	/*
+	 * Switch to per-port locking in case each port has its own MSI vector.
+	 */
+	if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
+		spin_lock_init(&pp->lock);
+		ap->lock = &pp->lock;
+	}
+
 	ap->private_data = pp;
 
 	/* engage engines, captain */
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index ef01ac0..6fc67f7 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -1029,30 +1029,20 @@
 {
 	struct scsi_device *sdev = dev->sdev;
 	acpi_handle handle;
-	struct device *device;
 
 	handle = ata_dev_acpi_handle(dev);
-	if (!handle)
-		return;
-
-	device = &sdev->sdev_gendev;
-
-	acpi_power_resource_register_device(device, handle);
+	if (handle)
+		acpi_dev_pm_remove_dependent(handle, &sdev->sdev_gendev);
 }
 
 static void ata_acpi_unregister_power_resource(struct ata_device *dev)
 {
 	struct scsi_device *sdev = dev->sdev;
 	acpi_handle handle;
-	struct device *device;
 
 	handle = ata_dev_acpi_handle(dev);
-	if (!handle)
-		return;
-
-	device = &sdev->sdev_gendev;
-
-	acpi_power_resource_unregister_device(device, handle);
+	if (handle)
+		acpi_dev_pm_remove_dependent(handle, &sdev->sdev_gendev);
 }
 
 void ata_acpi_bind(struct ata_device *dev)
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 5aa2d70..4e22ce3 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
 obj-$(CONFIG_SOC_BUS) += soc.o
+obj-$(CONFIG_PINCTRL) += pinctrl.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index e3bbed8..65631015 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -24,6 +24,7 @@
 #include <linux/wait.h>
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
+#include <linux/pinctrl/devinfo.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -269,6 +270,12 @@
 	WARN_ON(!list_empty(&dev->devres_head));
 
 	dev->driver = drv;
+
+	/* If using pinctrl, bind pins now before probing */
+	ret = pinctrl_bind_pins(dev);
+	if (ret)
+		goto probe_failed;
+
 	if (driver_sysfs_add(dev)) {
 		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
 			__func__, dev_name(dev));
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
new file mode 100644
index 0000000..67a274e
--- /dev/null
+++ b/drivers/base/pinctrl.c
@@ -0,0 +1,69 @@
+/*
+ * Driver core interface to the pinctrl subsystem.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/device.h>
+#include <linux/pinctrl/devinfo.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/slab.h>
+
+/**
+ * pinctrl_bind_pins() - called by the device core before probe
+ * @dev: the device that is just about to probe
+ */
+int pinctrl_bind_pins(struct device *dev)
+{
+	int ret;
+
+	dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
+	if (!dev->pins)
+		return -ENOMEM;
+
+	dev->pins->p = devm_pinctrl_get(dev);
+	if (IS_ERR(dev->pins->p)) {
+		dev_dbg(dev, "no pinctrl handle\n");
+		ret = PTR_ERR(dev->pins->p);
+		goto cleanup_alloc;
+	}
+
+	dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
+					PINCTRL_STATE_DEFAULT);
+	if (IS_ERR(dev->pins->default_state)) {
+		dev_dbg(dev, "no default pinctrl state\n");
+		ret = 0;
+		goto cleanup_get;
+	}
+
+	ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);
+	if (ret) {
+		dev_dbg(dev, "failed to activate default pinctrl state\n");
+		goto cleanup_get;
+	}
+
+	return 0;
+
+	/*
+	 * If no pinctrl handle or default state was found for this device,
+	 * let's explicitly free the pin container in the device, there is
+	 * no point in keeping it around.
+	 */
+cleanup_get:
+	devm_pinctrl_put(dev->pins->p);
+cleanup_alloc:
+	devm_kfree(dev, dev->pins);
+	dev->pins = NULL;
+
+	/* Only return deferrals */
+	if (ret != -EPROBE_DEFER)
+		ret = 0;
+
+	return ret;
+}
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index acc3a8d..9a6b05a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -433,8 +433,7 @@
  */
 void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 {
-	if (!work_pending(&genpd->power_off_work))
-		queue_work(pm_wq, &genpd->power_off_work);
+	queue_work(pm_wq, &genpd->power_off_work);
 }
 
 /**
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 50b2831..32ee0fc 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -162,7 +162,7 @@
 
 	return v;
 }
-EXPORT_SYMBOL(opp_get_voltage);
+EXPORT_SYMBOL_GPL(opp_get_voltage);
 
 /**
  * opp_get_freq() - Gets the frequency corresponding to an available opp
@@ -192,7 +192,7 @@
 
 	return f;
 }
-EXPORT_SYMBOL(opp_get_freq);
+EXPORT_SYMBOL_GPL(opp_get_freq);
 
 /**
  * opp_get_opp_count() - Get number of opps available in the opp list
@@ -225,7 +225,7 @@
 
 	return count;
 }
-EXPORT_SYMBOL(opp_get_opp_count);
+EXPORT_SYMBOL_GPL(opp_get_opp_count);
 
 /**
  * opp_find_freq_exact() - search for an exact frequency
@@ -276,7 +276,7 @@
 
 	return opp;
 }
-EXPORT_SYMBOL(opp_find_freq_exact);
+EXPORT_SYMBOL_GPL(opp_find_freq_exact);
 
 /**
  * opp_find_freq_ceil() - Search for an rounded ceil freq
@@ -323,7 +323,7 @@
 
 	return opp;
 }
-EXPORT_SYMBOL(opp_find_freq_ceil);
+EXPORT_SYMBOL_GPL(opp_find_freq_ceil);
 
 /**
  * opp_find_freq_floor() - Search for a rounded floor freq
@@ -374,7 +374,7 @@
 
 	return opp;
 }
-EXPORT_SYMBOL(opp_find_freq_floor);
+EXPORT_SYMBOL_GPL(opp_find_freq_floor);
 
 /**
  * opp_add()  - Add an OPP table from a table definitions
@@ -568,7 +568,7 @@
 {
 	return opp_set_availability(dev, freq, true);
 }
-EXPORT_SYMBOL(opp_enable);
+EXPORT_SYMBOL_GPL(opp_enable);
 
 /**
  * opp_disable() - Disable a specific OPP
@@ -590,7 +590,7 @@
 {
 	return opp_set_availability(dev, freq, false);
 }
-EXPORT_SYMBOL(opp_disable);
+EXPORT_SYMBOL_GPL(opp_disable);
 
 #ifdef CONFIG_CPU_FREQ
 /**
@@ -661,6 +661,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -678,6 +679,7 @@
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL_GPL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -738,4 +740,5 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(of_init_opp_table);
 #endif
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index e6ee5e8..79715e7 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -382,6 +382,12 @@
 {
 	unsigned int cec;
 
+	/*
+	 * active wakeup source should bring the system
+	 * out of PM_SUSPEND_FREEZE state
+	 */
+	freeze_wake();
+
 	ws->active = true;
 	ws->active_count++;
 	ws->last_time = ktime_get();
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 5e75d1b..cf12998 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_REGMAP) += regmap.o regcache.o
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
+obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
 obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
 obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 401d191..5a22bd3 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -16,6 +16,7 @@
 #include <linux/regmap.h>
 #include <linux/fs.h>
 #include <linux/list.h>
+#include <linux/wait.h>
 
 struct regmap;
 struct regcache_ops;
@@ -25,6 +26,7 @@
 	off_t min;
 	off_t max;
 	unsigned int base_reg;
+	unsigned int max_reg;
 };
 
 struct regmap_format {
@@ -39,6 +41,13 @@
 	unsigned int (*parse_val)(void *buf);
 };
 
+struct regmap_async {
+	struct list_head list;
+	struct work_struct cleanup;
+	struct regmap *map;
+	void *work_buf;
+};
+
 struct regmap {
 	struct mutex mutex;
 	spinlock_t spinlock;
@@ -53,6 +62,11 @@
 	void *bus_context;
 	const char *name;
 
+	spinlock_t async_lock;
+	wait_queue_head_t async_waitq;
+	struct list_head async_list;
+	int async_ret;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs;
 	const char *debugfs_name;
@@ -74,6 +88,11 @@
 	const struct regmap_access_table *volatile_table;
 	const struct regmap_access_table *precious_table;
 
+	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+
+	bool defer_caching;
+
 	u8 read_flag_mask;
 	u8 write_flag_mask;
 
@@ -175,7 +194,10 @@
 		      unsigned int val, unsigned int word_size);
 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
 
+void regmap_async_complete_cb(struct regmap_async *async, int ret);
+
 extern struct regcache_ops regcache_rbtree_ops;
 extern struct regcache_ops regcache_lzo_ops;
+extern struct regcache_ops regcache_flat_ops;
 
 #endif
diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c
new file mode 100644
index 0000000..d9762e4
--- /dev/null
+++ b/drivers/base/regmap/regcache-flat.c
@@ -0,0 +1,72 @@
+/*
+ * Register cache access API - flat caching support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/seq_file.h>
+
+#include "internal.h"
+
+static int regcache_flat_init(struct regmap *map)
+{
+	int i;
+	unsigned int *cache;
+
+	map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1),
+			     GFP_KERNEL);
+	if (!map->cache)
+		return -ENOMEM;
+
+	cache = map->cache;
+
+	for (i = 0; i < map->num_reg_defaults; i++)
+		cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def;
+
+	return 0;
+}
+
+static int regcache_flat_exit(struct regmap *map)
+{
+	kfree(map->cache);
+	map->cache = NULL;
+
+	return 0;
+}
+
+static int regcache_flat_read(struct regmap *map,
+			      unsigned int reg, unsigned int *value)
+{
+	unsigned int *cache = map->cache;
+
+	*value = cache[reg];
+
+	return 0;
+}
+
+static int regcache_flat_write(struct regmap *map, unsigned int reg,
+			       unsigned int value)
+{
+	unsigned int *cache = map->cache;
+
+	cache[reg] = value;
+
+	return 0;
+}
+
+struct regcache_ops regcache_flat_ops = {
+	.type = REGCACHE_FLAT,
+	.name = "flat",
+	.init = regcache_flat_init,
+	.exit = regcache_flat_exit,
+	.read = regcache_flat_read,
+	.write = regcache_flat_write,
+};
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 835883b..e69ff3e 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -22,6 +22,7 @@
 static const struct regcache_ops *cache_types[] = {
 	&regcache_rbtree_ops,
 	&regcache_lzo_ops,
+	&regcache_flat_ops,
 };
 
 static int regcache_hw_init(struct regmap *map)
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index d9a6c94..78d5f20 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -81,6 +81,8 @@
 	struct regmap_debugfs_off_cache *c = NULL;
 	loff_t p = 0;
 	unsigned int i, ret;
+	unsigned int fpos_offset;
+	unsigned int reg_offset;
 
 	/*
 	 * If we don't have a cache build one so we don't have to do a
@@ -93,6 +95,9 @@
 			    regmap_precious(map, i)) {
 				if (c) {
 					c->max = p - 1;
+					fpos_offset = c->max - c->min;
+					reg_offset = fpos_offset / map->debugfs_tot_len;
+					c->max_reg = c->base_reg + reg_offset;
 					list_add_tail(&c->list,
 						      &map->debugfs_off_cache);
 					c = NULL;
@@ -119,6 +124,9 @@
 	/* Close the last entry off if we didn't scan beyond it */
 	if (c) {
 		c->max = p - 1;
+		fpos_offset = c->max - c->min;
+		reg_offset = fpos_offset / map->debugfs_tot_len;
+		c->max_reg = c->base_reg + reg_offset;
 		list_add_tail(&c->list,
 			      &map->debugfs_off_cache);
 	}
@@ -128,25 +136,38 @@
 	 * allocate and we should never be in this code if there are
 	 * no registers at all.
 	 */
-	if (list_empty(&map->debugfs_off_cache)) {
-		WARN_ON(list_empty(&map->debugfs_off_cache));
-		return base;
-	}
+	WARN_ON(list_empty(&map->debugfs_off_cache));
+	ret = base;
 
-	/* Find the relevant block */
+	/* Find the relevant block:offset */
 	list_for_each_entry(c, &map->debugfs_off_cache, list) {
 		if (from >= c->min && from <= c->max) {
-			*pos = c->min;
-			return c->base_reg;
+			fpos_offset = from - c->min;
+			reg_offset = fpos_offset / map->debugfs_tot_len;
+			*pos = c->min + (reg_offset * map->debugfs_tot_len);
+			return c->base_reg + reg_offset;
 		}
 
-		*pos = c->min;
-		ret = c->base_reg;
+		*pos = c->max;
+		ret = c->max_reg;
 	}
 
 	return ret;
 }
 
+static inline void regmap_calc_tot_len(struct regmap *map,
+				       void *buf, size_t count)
+{
+	/* Calculate the length of a fixed format  */
+	if (!map->debugfs_tot_len) {
+		map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
+							   buf, count);
+		map->debugfs_val_len = 2 * map->format.val_bytes;
+		map->debugfs_tot_len = map->debugfs_reg_len +
+			map->debugfs_val_len + 3;      /* : \n */
+	}
+}
+
 static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
 				   unsigned int to, char __user *user_buf,
 				   size_t count, loff_t *ppos)
@@ -165,14 +186,7 @@
 	if (!buf)
 		return -ENOMEM;
 
-	/* Calculate the length of a fixed format  */
-	if (!map->debugfs_tot_len) {
-		map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
-							   buf, count);
-		map->debugfs_val_len = 2 * map->format.val_bytes;
-		map->debugfs_tot_len = map->debugfs_reg_len +
-			map->debugfs_val_len + 3;      /* : \n */
-	}
+	regmap_calc_tot_len(map, buf, count);
 
 	/* Work out which register we're starting at */
 	start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);
@@ -187,7 +201,7 @@
 		/* If we're in the region the user is trying to read */
 		if (p >= *ppos) {
 			/* ...but not beyond it */
-			if (buf_pos + 1 + map->debugfs_tot_len >= count)
+			if (buf_pos + map->debugfs_tot_len > count)
 				break;
 
 			/* Format the register */
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 5972ad9..4706c63 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -34,6 +34,7 @@
 	int irq;
 	int wake_count;
 
+	void *status_reg_buf;
 	unsigned int *status_buf;
 	unsigned int *mask_buf;
 	unsigned int *mask_buf_def;
@@ -87,6 +88,23 @@
 		if (ret != 0)
 			dev_err(d->map->dev, "Failed to sync masks in %x\n",
 				reg);
+
+		reg = d->chip->wake_base +
+			(i * map->reg_stride * d->irq_reg_stride);
+		if (d->wake_buf) {
+			if (d->chip->wake_invert)
+				ret = regmap_update_bits(d->map, reg,
+							 d->mask_buf_def[i],
+							 ~d->wake_buf[i]);
+			else
+				ret = regmap_update_bits(d->map, reg,
+							 d->mask_buf_def[i],
+							 d->wake_buf[i]);
+			if (ret != 0)
+				dev_err(d->map->dev,
+					"Failed to sync wakes in %x: %d\n",
+					reg, ret);
+		}
 	}
 
 	if (d->chip->runtime_pm)
@@ -129,16 +147,15 @@
 	struct regmap *map = d->map;
 	const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
 
-	if (!d->chip->wake_base)
-		return -EINVAL;
-
 	if (on) {
-		d->wake_buf[irq_data->reg_offset / map->reg_stride]
-			&= ~irq_data->mask;
+		if (d->wake_buf)
+			d->wake_buf[irq_data->reg_offset / map->reg_stride]
+				&= ~irq_data->mask;
 		d->wake_count++;
 	} else {
-		d->wake_buf[irq_data->reg_offset / map->reg_stride]
-			|= irq_data->mask;
+		if (d->wake_buf)
+			d->wake_buf[irq_data->reg_offset / map->reg_stride]
+				|= irq_data->mask;
 		d->wake_count--;
 	}
 
@@ -172,6 +189,62 @@
 	}
 
 	/*
+	 * Read in the statuses, using a single bulk read if possible
+	 * in order to reduce the I/O overheads.
+	 */
+	if (!map->use_single_rw && map->reg_stride == 1 &&
+	    data->irq_reg_stride == 1) {
+		u8 *buf8 = data->status_reg_buf;
+		u16 *buf16 = data->status_reg_buf;
+		u32 *buf32 = data->status_reg_buf;
+
+		BUG_ON(!data->status_reg_buf);
+
+		ret = regmap_bulk_read(map, chip->status_base,
+				       data->status_reg_buf,
+				       chip->num_regs);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to read IRQ status: %d\n",
+				ret);
+			return IRQ_NONE;
+		}
+
+		for (i = 0; i < data->chip->num_regs; i++) {
+			switch (map->format.val_bytes) {
+			case 1:
+				data->status_buf[i] = buf8[i];
+				break;
+			case 2:
+				data->status_buf[i] = buf16[i];
+				break;
+			case 4:
+				data->status_buf[i] = buf32[i];
+				break;
+			default:
+				BUG();
+				return IRQ_NONE;
+			}
+		}
+
+	} else {
+		for (i = 0; i < data->chip->num_regs; i++) {
+			ret = regmap_read(map, chip->status_base +
+					  (i * map->reg_stride
+					   * data->irq_reg_stride),
+					  &data->status_buf[i]);
+
+			if (ret != 0) {
+				dev_err(map->dev,
+					"Failed to read IRQ status: %d\n",
+					ret);
+				if (chip->runtime_pm)
+					pm_runtime_put(map->dev);
+				return IRQ_NONE;
+			}
+		}
+	}
+
+	/*
 	 * Ignore masked IRQs and ack if we need to; we ack early so
 	 * there is no race between handling and acknowleding the
 	 * interrupt.  We assume that typically few of the interrupts
@@ -179,18 +252,6 @@
 	 * doing a write per register.
 	 */
 	for (i = 0; i < data->chip->num_regs; i++) {
-		ret = regmap_read(map, chip->status_base + (i * map->reg_stride
-				   * data->irq_reg_stride),
-				   &data->status_buf[i]);
-
-		if (ret != 0) {
-			dev_err(map->dev, "Failed to read IRQ status: %d\n",
-					ret);
-			if (chip->runtime_pm)
-				pm_runtime_put(map->dev);
-			return IRQ_NONE;
-		}
-
 		data->status_buf[i] &= ~data->mask_buf[i];
 
 		if (data->status_buf[i] && chip->ack_base) {
@@ -316,11 +377,6 @@
 
 	d->irq_chip = regmap_irq_chip;
 	d->irq_chip.name = chip->name;
-	if (!chip->wake_base) {
-		d->irq_chip.irq_set_wake = NULL;
-		d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
-				     IRQCHIP_SKIP_SET_WAKE;
-	}
 	d->irq = irq;
 	d->map = map;
 	d->chip = chip;
@@ -331,6 +387,14 @@
 	else
 		d->irq_reg_stride = 1;
 
+	if (!map->use_single_rw && map->reg_stride == 1 &&
+	    d->irq_reg_stride == 1) {
+		d->status_reg_buf = kmalloc(map->format.val_bytes *
+					    chip->num_regs, GFP_KERNEL);
+		if (!d->status_reg_buf)
+			goto err_alloc;
+	}
+
 	mutex_init(&d->lock);
 
 	for (i = 0; i < chip->num_irqs; i++)
@@ -361,8 +425,15 @@
 			d->wake_buf[i] = d->mask_buf_def[i];
 			reg = chip->wake_base +
 				(i * map->reg_stride * d->irq_reg_stride);
-			ret = regmap_update_bits(map, reg, d->wake_buf[i],
-						 d->wake_buf[i]);
+
+			if (chip->wake_invert)
+				ret = regmap_update_bits(map, reg,
+							 d->mask_buf_def[i],
+							 0);
+			else
+				ret = regmap_update_bits(map, reg,
+							 d->mask_buf_def[i],
+							 d->wake_buf[i]);
 			if (ret != 0) {
 				dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
 					reg, ret);
@@ -401,6 +472,7 @@
 	kfree(d->mask_buf_def);
 	kfree(d->mask_buf);
 	kfree(d->status_buf);
+	kfree(d->status_reg_buf);
 	kfree(d);
 	return ret;
 }
@@ -422,6 +494,7 @@
 	kfree(d->wake_buf);
 	kfree(d->mask_buf_def);
 	kfree(d->mask_buf);
+	kfree(d->status_reg_buf);
 	kfree(d->status_buf);
 	kfree(d);
 }
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index f05fc74..98745dd 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -16,6 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -26,6 +27,7 @@
 struct regmap_mmio_context {
 	void __iomem *regs;
 	unsigned val_bytes;
+	struct clk *clk;
 };
 
 static int regmap_mmio_gather_write(void *context,
@@ -34,9 +36,16 @@
 {
 	struct regmap_mmio_context *ctx = context;
 	u32 offset;
+	int ret;
 
 	BUG_ON(reg_size != 4);
 
+	if (ctx->clk) {
+		ret = clk_enable(ctx->clk);
+		if (ret < 0)
+			return ret;
+	}
+
 	offset = *(u32 *)reg;
 
 	while (val_size) {
@@ -64,6 +73,9 @@
 		offset += ctx->val_bytes;
 	}
 
+	if (ctx->clk)
+		clk_disable(ctx->clk);
+
 	return 0;
 }
 
@@ -80,9 +92,16 @@
 {
 	struct regmap_mmio_context *ctx = context;
 	u32 offset;
+	int ret;
 
 	BUG_ON(reg_size != 4);
 
+	if (ctx->clk) {
+		ret = clk_enable(ctx->clk);
+		if (ret < 0)
+			return ret;
+	}
+
 	offset = *(u32 *)reg;
 
 	while (val_size) {
@@ -110,11 +129,20 @@
 		offset += ctx->val_bytes;
 	}
 
+	if (ctx->clk)
+		clk_disable(ctx->clk);
+
 	return 0;
 }
 
 static void regmap_mmio_free_context(void *context)
 {
+	struct regmap_mmio_context *ctx = context;
+
+	if (ctx->clk) {
+		clk_unprepare(ctx->clk);
+		clk_put(ctx->clk);
+	}
 	kfree(context);
 }
 
@@ -128,11 +156,14 @@
 	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
 };
 
-static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
+					const char *clk_id,
+					void __iomem *regs,
 					const struct regmap_config *config)
 {
 	struct regmap_mmio_context *ctx;
 	int min_stride;
+	int ret;
 
 	if (config->reg_bits != 32)
 		return ERR_PTR(-EINVAL);
@@ -179,37 +210,59 @@
 	ctx->regs = regs;
 	ctx->val_bytes = config->val_bits / 8;
 
+	if (clk_id == NULL)
+		return ctx;
+
+	ctx->clk = clk_get(dev, clk_id);
+	if (IS_ERR(ctx->clk)) {
+		ret = PTR_ERR(ctx->clk);
+		goto err_free;
+	}
+
+	ret = clk_prepare(ctx->clk);
+	if (ret < 0) {
+		clk_put(ctx->clk);
+		goto err_free;
+	}
+
 	return ctx;
+
+err_free:
+	kfree(ctx);
+
+	return ERR_PTR(ret);
 }
 
 /**
- * regmap_init_mmio(): Initialise register map
+ * regmap_init_mmio_clk(): Initialise register map with register clock
  *
  * @dev: Device that will be interacted with
+ * @clk_id: register clock consumer ID
  * @regs: Pointer to memory-mapped IO region
  * @config: Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer to
  * a struct regmap.
  */
-struct regmap *regmap_init_mmio(struct device *dev,
-				void __iomem *regs,
-				const struct regmap_config *config)
+struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
+				    void __iomem *regs,
+				    const struct regmap_config *config)
 {
 	struct regmap_mmio_context *ctx;
 
-	ctx = regmap_mmio_gen_context(regs, config);
+	ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
 	if (IS_ERR(ctx))
 		return ERR_CAST(ctx);
 
 	return regmap_init(dev, &regmap_mmio, ctx, config);
 }
-EXPORT_SYMBOL_GPL(regmap_init_mmio);
+EXPORT_SYMBOL_GPL(regmap_init_mmio_clk);
 
 /**
- * devm_regmap_init_mmio(): Initialise managed register map
+ * devm_regmap_init_mmio_clk(): Initialise managed register map with clock
  *
  * @dev: Device that will be interacted with
+ * @clk_id: register clock consumer ID
  * @regs: Pointer to memory-mapped IO region
  * @config: Configuration for register map
  *
@@ -217,18 +270,18 @@
  * to a struct regmap.  The regmap will be automatically freed by the
  * device management code.
  */
-struct regmap *devm_regmap_init_mmio(struct device *dev,
-				     void __iomem *regs,
-				     const struct regmap_config *config)
+struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
+					 void __iomem *regs,
+					 const struct regmap_config *config)
 {
 	struct regmap_mmio_context *ctx;
 
-	ctx = regmap_mmio_gen_context(regs, config);
+	ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
 	if (IS_ERR(ctx))
 		return ERR_CAST(ctx);
 
 	return devm_regmap_init(dev, &regmap_mmio, ctx, config);
 }
-EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
+EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk);
 
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index ffa46a9..4c506bd 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -15,6 +15,21 @@
 #include <linux/init.h>
 #include <linux/module.h>
 
+#include "internal.h"
+
+struct regmap_async_spi {
+	struct regmap_async core;
+	struct spi_message m;
+	struct spi_transfer t[2];
+};
+
+static void regmap_spi_complete(void *data)
+{
+	struct regmap_async_spi *async = data;
+
+	regmap_async_complete_cb(&async->core, async->m.status);
+}
+
 static int regmap_spi_write(void *context, const void *data, size_t count)
 {
 	struct device *dev = context;
@@ -40,6 +55,43 @@
 	return spi_sync(spi, &m);
 }
 
+static int regmap_spi_async_write(void *context,
+				  const void *reg, size_t reg_len,
+				  const void *val, size_t val_len,
+				  struct regmap_async *a)
+{
+	struct regmap_async_spi *async = container_of(a,
+						      struct regmap_async_spi,
+						      core);
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+
+	async->t[0].tx_buf = reg;
+	async->t[0].len = reg_len;
+	async->t[1].tx_buf = val;
+	async->t[1].len = val_len;
+
+	spi_message_init(&async->m);
+	spi_message_add_tail(&async->t[0], &async->m);
+	spi_message_add_tail(&async->t[1], &async->m);
+
+	async->m.complete = regmap_spi_complete;
+	async->m.context = async;
+
+	return spi_async(spi, &async->m);
+}
+
+static struct regmap_async *regmap_spi_async_alloc(void)
+{
+	struct regmap_async_spi *async_spi;
+
+	async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL);
+	if (!async_spi)
+		return NULL;
+
+	return &async_spi->core;
+}
+
 static int regmap_spi_read(void *context,
 			   const void *reg, size_t reg_size,
 			   void *val, size_t val_size)
@@ -53,6 +105,8 @@
 static struct regmap_bus regmap_spi = {
 	.write = regmap_spi_write,
 	.gather_write = regmap_spi_gather_write,
+	.async_write = regmap_spi_async_write,
+	.async_alloc = regmap_spi_async_alloc,
 	.read = regmap_spi_read,
 	.read_flag_mask = 0x80,
 };
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index f00b059..3d23675 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -16,6 +16,7 @@
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/rbtree.h>
+#include <linux/sched.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/regmap.h>
@@ -34,6 +35,22 @@
 			       unsigned int mask, unsigned int val,
 			       bool *change);
 
+static int _regmap_bus_read(void *context, unsigned int reg,
+			    unsigned int *val);
+static int _regmap_bus_formatted_write(void *context, unsigned int reg,
+				       unsigned int val);
+static int _regmap_bus_raw_write(void *context, unsigned int reg,
+				 unsigned int val);
+
+static void async_cleanup(struct work_struct *work)
+{
+	struct regmap_async *async = container_of(work, struct regmap_async,
+						  cleanup);
+
+	kfree(async->work_buf);
+	kfree(async);
+}
+
 bool regmap_reg_in_ranges(unsigned int reg,
 			  const struct regmap_range *ranges,
 			  unsigned int nranges)
@@ -372,7 +389,7 @@
 	enum regmap_endian reg_endian, val_endian;
 	int i, j;
 
-	if (!bus || !config)
+	if (!config)
 		goto err;
 
 	map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -386,7 +403,8 @@
 		map->unlock = config->unlock;
 		map->lock_arg = config->lock_arg;
 	} else {
-		if (bus->fast_io) {
+		if ((bus && bus->fast_io) ||
+		    config->fast_io) {
 			spin_lock_init(&map->spinlock);
 			map->lock = regmap_lock_spinlock;
 			map->unlock = regmap_unlock_spinlock;
@@ -423,13 +441,27 @@
 	map->cache_type = config->cache_type;
 	map->name = config->name;
 
+	spin_lock_init(&map->async_lock);
+	INIT_LIST_HEAD(&map->async_list);
+	init_waitqueue_head(&map->async_waitq);
+
 	if (config->read_flag_mask || config->write_flag_mask) {
 		map->read_flag_mask = config->read_flag_mask;
 		map->write_flag_mask = config->write_flag_mask;
-	} else {
+	} else if (bus) {
 		map->read_flag_mask = bus->read_flag_mask;
 	}
 
+	if (!bus) {
+		map->reg_read  = config->reg_read;
+		map->reg_write = config->reg_write;
+
+		map->defer_caching = false;
+		goto skip_format_initialization;
+	} else {
+		map->reg_read  = _regmap_bus_read;
+	}
+
 	reg_endian = config->reg_format_endian;
 	if (reg_endian == REGMAP_ENDIAN_DEFAULT)
 		reg_endian = bus->reg_format_endian_default;
@@ -500,6 +532,12 @@
 		}
 		break;
 
+	case 24:
+		if (reg_endian != REGMAP_ENDIAN_BIG)
+			goto err_map;
+		map->format.format_reg = regmap_format_24;
+		break;
+
 	case 32:
 		switch (reg_endian) {
 		case REGMAP_ENDIAN_BIG:
@@ -575,6 +613,16 @@
 		goto err_map;
 	}
 
+	if (map->format.format_write) {
+		map->defer_caching = false;
+		map->reg_write = _regmap_bus_formatted_write;
+	} else if (map->format.format_val) {
+		map->defer_caching = true;
+		map->reg_write = _regmap_bus_raw_write;
+	}
+
+skip_format_initialization:
+
 	map->range_tree = RB_ROOT;
 	for (i = 0; i < config->num_ranges; i++) {
 		const struct regmap_range_cfg *range_cfg = &config->ranges[i];
@@ -776,7 +824,7 @@
 	regcache_exit(map);
 	regmap_debugfs_exit(map);
 	regmap_range_exit(map);
-	if (map->bus->free_context)
+	if (map->bus && map->bus->free_context)
 		map->bus->free_context(map->bus_context);
 	kfree(map->work_buf);
 	kfree(map);
@@ -870,15 +918,20 @@
 }
 
 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
-			     const void *val, size_t val_len)
+			     const void *val, size_t val_len, bool async)
 {
 	struct regmap_range_node *range;
+	unsigned long flags;
 	u8 *u8 = map->work_buf;
+	void *work_val = map->work_buf + map->format.reg_bytes +
+		map->format.pad_bytes;
 	void *buf;
 	int ret = -ENOTSUPP;
 	size_t len;
 	int i;
 
+	BUG_ON(!map->bus);
+
 	/* Check for unwritable registers before we start */
 	if (map->writeable_reg)
 		for (i = 0; i < val_len / map->format.val_bytes; i++)
@@ -918,7 +971,7 @@
 			dev_dbg(map->dev, "Writing window %d/%zu\n",
 				win_residue, val_len / map->format.val_bytes);
 			ret = _regmap_raw_write(map, reg, val, win_residue *
-						map->format.val_bytes);
+						map->format.val_bytes, async);
 			if (ret != 0)
 				return ret;
 
@@ -941,6 +994,50 @@
 
 	u8[0] |= map->write_flag_mask;
 
+	if (async && map->bus->async_write) {
+		struct regmap_async *async = map->bus->async_alloc();
+		if (!async)
+			return -ENOMEM;
+
+		async->work_buf = kzalloc(map->format.buf_size,
+					  GFP_KERNEL | GFP_DMA);
+		if (!async->work_buf) {
+			kfree(async);
+			return -ENOMEM;
+		}
+
+		INIT_WORK(&async->cleanup, async_cleanup);
+		async->map = map;
+
+		/* If the caller supplied the value we can use it safely. */
+		memcpy(async->work_buf, map->work_buf, map->format.pad_bytes +
+		       map->format.reg_bytes + map->format.val_bytes);
+		if (val == work_val)
+			val = async->work_buf + map->format.pad_bytes +
+				map->format.reg_bytes;
+
+		spin_lock_irqsave(&map->async_lock, flags);
+		list_add_tail(&async->list, &map->async_list);
+		spin_unlock_irqrestore(&map->async_lock, flags);
+
+		ret = map->bus->async_write(map->bus_context, async->work_buf,
+					    map->format.reg_bytes +
+					    map->format.pad_bytes,
+					    val, val_len, async);
+
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to schedule write: %d\n",
+				ret);
+
+			spin_lock_irqsave(&map->async_lock, flags);
+			list_del(&async->list);
+			spin_unlock_irqrestore(&map->async_lock, flags);
+
+			kfree(async->work_buf);
+			kfree(async);
+		}
+	}
+
 	trace_regmap_hw_write_start(map->dev, reg,
 				    val_len / map->format.val_bytes);
 
@@ -948,8 +1045,7 @@
 	 * send the work_buf directly, otherwise try to do a gather
 	 * write.
 	 */
-	if (val == (map->work_buf + map->format.pad_bytes +
-		    map->format.reg_bytes))
+	if (val == work_val)
 		ret = map->bus->write(map->bus_context, map->work_buf,
 				      map->format.reg_bytes +
 				      map->format.pad_bytes +
@@ -981,14 +1077,62 @@
 	return ret;
 }
 
+static int _regmap_bus_formatted_write(void *context, unsigned int reg,
+				       unsigned int val)
+{
+	int ret;
+	struct regmap_range_node *range;
+	struct regmap *map = context;
+
+	BUG_ON(!map->bus || !map->format.format_write);
+
+	range = _regmap_range_lookup(map, reg);
+	if (range) {
+		ret = _regmap_select_page(map, &reg, range, 1);
+		if (ret != 0)
+			return ret;
+	}
+
+	map->format.format_write(map, reg, val);
+
+	trace_regmap_hw_write_start(map->dev, reg, 1);
+
+	ret = map->bus->write(map->bus_context, map->work_buf,
+			      map->format.buf_size);
+
+	trace_regmap_hw_write_done(map->dev, reg, 1);
+
+	return ret;
+}
+
+static int _regmap_bus_raw_write(void *context, unsigned int reg,
+				 unsigned int val)
+{
+	struct regmap *map = context;
+
+	BUG_ON(!map->bus || !map->format.format_val);
+
+	map->format.format_val(map->work_buf + map->format.reg_bytes
+			       + map->format.pad_bytes, val, 0);
+	return _regmap_raw_write(map, reg,
+				 map->work_buf +
+				 map->format.reg_bytes +
+				 map->format.pad_bytes,
+				 map->format.val_bytes, false);
+}
+
+static inline void *_regmap_map_get_context(struct regmap *map)
+{
+	return (map->bus) ? map : map->bus_context;
+}
+
 int _regmap_write(struct regmap *map, unsigned int reg,
 		  unsigned int val)
 {
-	struct regmap_range_node *range;
 	int ret;
-	BUG_ON(!map->format.format_write && !map->format.format_val);
+	void *context = _regmap_map_get_context(map);
 
-	if (!map->cache_bypass && map->format.format_write) {
+	if (!map->cache_bypass && !map->defer_caching) {
 		ret = regcache_write(map, reg, val);
 		if (ret != 0)
 			return ret;
@@ -1005,33 +1149,7 @@
 
 	trace_regmap_reg_write(map->dev, reg, val);
 
-	if (map->format.format_write) {
-		range = _regmap_range_lookup(map, reg);
-		if (range) {
-			ret = _regmap_select_page(map, &reg, range, 1);
-			if (ret != 0)
-				return ret;
-		}
-
-		map->format.format_write(map, reg, val);
-
-		trace_regmap_hw_write_start(map->dev, reg, 1);
-
-		ret = map->bus->write(map->bus_context, map->work_buf,
-				      map->format.buf_size);
-
-		trace_regmap_hw_write_done(map->dev, reg, 1);
-
-		return ret;
-	} else {
-		map->format.format_val(map->work_buf + map->format.reg_bytes
-				       + map->format.pad_bytes, val, 0);
-		return _regmap_raw_write(map, reg,
-					 map->work_buf +
-					 map->format.reg_bytes +
-					 map->format.pad_bytes,
-					 map->format.val_bytes);
-	}
+	return map->reg_write(context, reg, val);
 }
 
 /**
@@ -1082,6 +1200,8 @@
 {
 	int ret;
 
+	if (!map->bus)
+		return -EINVAL;
 	if (val_len % map->format.val_bytes)
 		return -EINVAL;
 	if (reg % map->reg_stride)
@@ -1089,7 +1209,7 @@
 
 	map->lock(map->lock_arg);
 
-	ret = _regmap_raw_write(map, reg, val, val_len);
+	ret = _regmap_raw_write(map, reg, val, val_len, false);
 
 	map->unlock(map->lock_arg);
 
@@ -1118,6 +1238,8 @@
 	size_t val_bytes = map->format.val_bytes;
 	void *wval;
 
+	if (!map->bus)
+		return -EINVAL;
 	if (!map->format.parse_val)
 		return -EINVAL;
 	if (reg % map->reg_stride)
@@ -1145,14 +1267,15 @@
 	if (map->use_single_rw) {
 		for (i = 0; i < val_count; i++) {
 			ret = regmap_raw_write(map,
-						reg + (i * map->reg_stride),
-						val + (i * val_bytes),
-						val_bytes);
+					       reg + (i * map->reg_stride),
+					       val + (i * val_bytes),
+					       val_bytes);
 			if (ret != 0)
 				return ret;
 		}
 	} else {
-		ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+		ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count,
+					false);
 	}
 
 	if (val_bytes != 1)
@@ -1164,6 +1287,48 @@
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_write);
 
+/**
+ * regmap_raw_write_async(): Write raw values to one or more registers
+ *                           asynchronously
+ *
+ * @map: Register map to write to
+ * @reg: Initial register to write to
+ * @val: Block of data to be written, laid out for direct transmission to the
+ *       device.  Must be valid until regmap_async_complete() is called.
+ * @val_len: Length of data pointed to by val.
+ *
+ * This function is intended to be used for things like firmware
+ * download where a large block of data needs to be transferred to the
+ * device.  No formatting will be done on the data provided.
+ *
+ * If supported by the underlying bus the write will be scheduled
+ * asynchronously, helping maximise I/O speed on higher speed buses
+ * like SPI.  regmap_async_complete() can be called to ensure that all
+ * asynchrnous writes have been completed.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_raw_write_async(struct regmap *map, unsigned int reg,
+			   const void *val, size_t val_len)
+{
+	int ret;
+
+	if (val_len % map->format.val_bytes)
+		return -EINVAL;
+	if (reg % map->reg_stride)
+		return -EINVAL;
+
+	map->lock(map->lock_arg);
+
+	ret = _regmap_raw_write(map, reg, val, val_len, true);
+
+	map->unlock(map->lock_arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_raw_write_async);
+
 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 			    unsigned int val_len)
 {
@@ -1171,6 +1336,8 @@
 	u8 *u8 = map->work_buf;
 	int ret;
 
+	BUG_ON(!map->bus);
+
 	range = _regmap_range_lookup(map, reg);
 	if (range) {
 		ret = _regmap_select_page(map, &reg, range,
@@ -1202,10 +1369,29 @@
 	return ret;
 }
 
+static int _regmap_bus_read(void *context, unsigned int reg,
+			    unsigned int *val)
+{
+	int ret;
+	struct regmap *map = context;
+
+	if (!map->format.parse_val)
+		return -EINVAL;
+
+	ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
+	if (ret == 0)
+		*val = map->format.parse_val(map->work_buf);
+
+	return ret;
+}
+
 static int _regmap_read(struct regmap *map, unsigned int reg,
 			unsigned int *val)
 {
 	int ret;
+	void *context = _regmap_map_get_context(map);
+
+	BUG_ON(!map->reg_read);
 
 	if (!map->cache_bypass) {
 		ret = regcache_read(map, reg, val);
@@ -1213,26 +1399,21 @@
 			return 0;
 	}
 
-	if (!map->format.parse_val)
-		return -EINVAL;
-
 	if (map->cache_only)
 		return -EBUSY;
 
-	ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
+	ret = map->reg_read(context, reg, val);
 	if (ret == 0) {
-		*val = map->format.parse_val(map->work_buf);
-
 #ifdef LOG_DEVICE
 		if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
 			dev_info(map->dev, "%x => %x\n", reg, *val);
 #endif
 
 		trace_regmap_reg_read(map->dev, reg, *val);
-	}
 
-	if (ret == 0 && !map->cache_bypass)
-		regcache_write(map, reg, *val);
+		if (!map->cache_bypass)
+			regcache_write(map, reg, *val);
+	}
 
 	return ret;
 }
@@ -1283,6 +1464,8 @@
 	unsigned int v;
 	int ret, i;
 
+	if (!map->bus)
+		return -EINVAL;
 	if (val_len % map->format.val_bytes)
 		return -EINVAL;
 	if (reg % map->reg_stride)
@@ -1334,6 +1517,8 @@
 	size_t val_bytes = map->format.val_bytes;
 	bool vol = regmap_volatile_range(map, reg, val_count);
 
+	if (!map->bus)
+		return -EINVAL;
 	if (!map->format.parse_val)
 		return -EINVAL;
 	if (reg % map->reg_stride)
@@ -1450,6 +1635,68 @@
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits_check);
 
+void regmap_async_complete_cb(struct regmap_async *async, int ret)
+{
+	struct regmap *map = async->map;
+	bool wake;
+
+	spin_lock(&map->async_lock);
+
+	list_del(&async->list);
+	wake = list_empty(&map->async_list);
+
+	if (ret != 0)
+		map->async_ret = ret;
+
+	spin_unlock(&map->async_lock);
+
+	schedule_work(&async->cleanup);
+
+	if (wake)
+		wake_up(&map->async_waitq);
+}
+EXPORT_SYMBOL_GPL(regmap_async_complete_cb);
+
+static int regmap_async_is_done(struct regmap *map)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&map->async_lock, flags);
+	ret = list_empty(&map->async_list);
+	spin_unlock_irqrestore(&map->async_lock, flags);
+
+	return ret;
+}
+
+/**
+ * regmap_async_complete: Ensure all asynchronous I/O has completed.
+ *
+ * @map: Map to operate on.
+ *
+ * Blocks until any pending asynchronous I/O has completed.  Returns
+ * an error code for any failed I/O operations.
+ */
+int regmap_async_complete(struct regmap *map)
+{
+	unsigned long flags;
+	int ret;
+
+	/* Nothing to do with no async support */
+	if (!map->bus->async_write)
+		return 0;
+
+	wait_event(map->async_waitq, regmap_async_is_done(map));
+
+	spin_lock_irqsave(&map->async_lock, flags);
+	ret = map->async_ret;
+	map->async_ret = 0;
+	spin_unlock_irqrestore(&map->async_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_async_complete);
+
 /**
  * regmap_register_patch: Register and apply register updates to be applied
  *                        on device initialistion
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index cb0c454..79595a0 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -31,6 +31,8 @@
 int bcma_bus_suspend(struct bcma_bus *bus);
 int bcma_bus_resume(struct bcma_bus *bus);
 #endif
+struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+					u8 unit);
 
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
@@ -45,6 +47,7 @@
 /* driver_chipcommon.c */
 #ifdef CONFIG_BCMA_DRIVER_MIPS
 void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+extern struct platform_device bcma_pflash_dev;
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
 
 /* driver_chipcommon_pmu.c */
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index e461ad2..28fa50a 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -329,7 +329,7 @@
 		return;
 	}
 
-	irq = bcma_core_mips_irq(cc->core);
+	irq = bcma_core_irq(cc->core);
 
 	/* Determine the registers of the UARTs */
 	cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c
index 1f0b83e..d4f699a 100644
--- a/drivers/bcma/driver_chipcommon_nflash.c
+++ b/drivers/bcma/driver_chipcommon_nflash.c
@@ -5,11 +5,11 @@
  * Licensed under the GNU/GPL. See COPYING for details.
  */
 
+#include "bcma_private.h"
+
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
-#include "bcma_private.h"
-
 struct platform_device bcma_nflash_dev = {
 	.name		= "bcma_nflash",
 	.num_resources	= 0,
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index c62c788..932b101 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -264,7 +264,7 @@
 }
 
 /* query bus clock frequency for PMU-enabled chipcommon */
-static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
+u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
 {
 	struct bcma_bus *bus = cc->core->bus;
 
@@ -293,6 +293,7 @@
 	}
 	return BCMA_CC_PMU_HT_CLOCK;
 }
+EXPORT_SYMBOL_GPL(bcma_pmu_get_bus_clock);
 
 /* query cpu clock frequency for PMU-enabled chipcommon */
 u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c
index 1e694db..e6ed4fe 100644
--- a/drivers/bcma/driver_chipcommon_sflash.c
+++ b/drivers/bcma/driver_chipcommon_sflash.c
@@ -5,11 +5,11 @@
  * Licensed under the GNU/GPL. See COPYING for details.
  */
 
+#include "bcma_private.h"
+
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
-#include "bcma_private.h"
-
 static struct resource bcma_sflash_resource = {
 	.name	= "bcma_sflash",
 	.start	= BCMA_SOC_FLASH2,
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 71f755c..45f0996 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -73,6 +73,16 @@
 	bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
 }
 
+static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+	if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+		return bcma_core_irq(cc->core);
+	else
+		return -EINVAL;
+}
+
 int bcma_gpio_init(struct bcma_drv_cc *cc)
 {
 	struct gpio_chip *chip = &cc->gpio;
@@ -85,6 +95,7 @@
 	chip->set		= bcma_gpio_set_value;
 	chip->direction_input	= bcma_gpio_direction_input;
 	chip->direction_output	= bcma_gpio_direction_output;
+	chip->to_irq		= bcma_gpio_to_irq;
 	chip->ngpio		= 16;
 	/* There is just one SoC in one device and its GPIO addresses should be
 	 * deterministic to address them more easily. The other buses could get
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 792daad..9a7f0e3 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -14,11 +14,33 @@
 
 #include <linux/bcma/bcma.h>
 
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
 #include <linux/time.h>
 
+static const char *part_probes[] = { "bcm47xxpart", NULL };
+
+static struct physmap_flash_data bcma_pflash_data = {
+	.part_probe_types	= part_probes,
+};
+
+static struct resource bcma_pflash_resource = {
+	.name	= "bcma_pflash",
+	.flags  = IORESOURCE_MEM,
+};
+
+struct platform_device bcma_pflash_dev = {
+	.name		= "physmap-flash",
+	.dev		= {
+		.platform_data  = &bcma_pflash_data,
+	},
+	.resource	= &bcma_pflash_resource,
+	.num_resources	= 1,
+};
+
 /* The 47162a0 hangs when reading MIPS DMP registers registers */
 static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
 {
@@ -74,28 +96,41 @@
 		return dev->core_index;
 	flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
 
-	return flag & 0x1F;
+	if (flag)
+		return flag & 0x1F;
+	else
+		return 0x3f;
 }
 
 /* Get the MIPS IRQ assignment for a specified device.
  * If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
  */
-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
 {
 	struct bcma_device *mdev = dev->bus->drv_mips.core;
 	u32 irqflag;
 	unsigned int irq;
 
 	irqflag = bcma_core_mips_irqflag(dev);
+	if (irqflag == 0x3f)
+		return 6;
 
-	for (irq = 1; irq <= 4; irq++)
+	for (irq = 0; irq <= 4; irq++)
 		if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
 		    (1 << irqflag))
 			return irq;
 
-	return 0;
+	return 5;
 }
-EXPORT_SYMBOL(bcma_core_mips_irq);
+
+unsigned int bcma_core_irq(struct bcma_device *dev)
+{
+	unsigned int mips_irq = bcma_core_mips_irq(dev);
+	return mips_irq <= 4 ? mips_irq + 2 : 0;
+}
+EXPORT_SYMBOL(bcma_core_irq);
 
 static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
 {
@@ -114,7 +149,7 @@
 		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
 			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
 			    ~(1 << irqflag));
-	else
+	else if (oldirq != 5)
 		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
 
 	/* assign the new one */
@@ -123,9 +158,9 @@
 			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
 			    (1 << irqflag));
 	} else {
-		u32 oldirqflag = bcma_read32(mdev,
-					     BCMA_MIPS_MIPS74K_INTMASK(irq));
-		if (oldirqflag) {
+		u32 irqinitmask = bcma_read32(mdev,
+					      BCMA_MIPS_MIPS74K_INTMASK(irq));
+		if (irqinitmask) {
 			struct bcma_device *core;
 
 			/* backplane irq line is in use, find out who uses
@@ -133,7 +168,7 @@
 			 */
 			list_for_each_entry(core, &bus->cores, list) {
 				if ((1 << bcma_core_mips_irqflag(core)) ==
-				    oldirqflag) {
+				    irqinitmask) {
 					bcma_core_mips_set_irq(core, 0);
 					break;
 				}
@@ -143,15 +178,31 @@
 			     1 << irqflag);
 	}
 
-	bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
-		  dev->id.id, oldirq + 2, irq + 2);
+	bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
+		   dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
+}
+
+static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
+					u16 coreid, u8 unit)
+{
+	struct bcma_device *core;
+
+	core = bcma_find_core_unit(bus, coreid, unit);
+	if (!core) {
+		bcma_warn(bus,
+			  "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
+			  coreid, unit);
+		return;
+	}
+
+	bcma_core_mips_set_irq(core, irq);
 }
 
 static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
 {
 	int i;
 	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
-	printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+	printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
 	for (i = 0; i <= 6; i++)
 		printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
 	printk("\n");
@@ -182,6 +233,7 @@
 {
 	struct bcma_bus *bus = mcore->core->bus;
 	struct bcma_drv_cc *cc = &bus->drv_cc;
+	struct bcma_pflash *pflash = &cc->pflash;
 
 	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 	case BCMA_CC_FLASHT_STSER:
@@ -191,15 +243,20 @@
 		break;
 	case BCMA_CC_FLASHT_PARA:
 		bcma_debug(bus, "Found parallel flash\n");
-		cc->pflash.present = true;
-		cc->pflash.window = BCMA_SOC_FLASH2;
-		cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
+		pflash->present = true;
+		pflash->window = BCMA_SOC_FLASH2;
+		pflash->window_size = BCMA_SOC_FLASH2_SZ;
 
 		if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
 		     BCMA_CC_FLASH_CFG_DS) == 0)
-			cc->pflash.buswidth = 1;
+			pflash->buswidth = 1;
 		else
-			cc->pflash.buswidth = 2;
+			pflash->buswidth = 2;
+
+		bcma_pflash_data.width = pflash->buswidth;
+		bcma_pflash_resource.start = pflash->window;
+		bcma_pflash_resource.end = pflash->window + pflash->window_size;
+
 		break;
 	default:
 		bcma_err(bus, "Flash type not supported\n");
@@ -227,6 +284,32 @@
 	mcore->early_setup_done = true;
 }
 
+static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
+{
+	struct bcma_device *cpu, *pcie, *i2s;
+
+	/* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
+	 * (IRQ flags > 7 are ignored when setting the interrupt masks)
+	 */
+	if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
+	    bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
+		return;
+
+	cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+	pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
+	i2s = bcma_find_core(bus, BCMA_CORE_I2S);
+	if (cpu && pcie && i2s &&
+	    bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
+	    bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
+	    bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
+		bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
+		bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
+		bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
+		bcma_debug(bus,
+			   "Moved i2s interrupt to oob line 7 instead of 8\n");
+	}
+}
+
 void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 {
 	struct bcma_bus *bus;
@@ -236,43 +319,55 @@
 	if (mcore->setup_done)
 		return;
 
-	bcma_info(bus, "Initializing MIPS core...\n");
+	bcma_debug(bus, "Initializing MIPS core...\n");
 
 	bcma_core_mips_early_init(mcore);
 
-	mcore->assigned_irqs = 1;
+	bcma_fix_i2s_irqflag(bus);
 
-	/* Assign IRQs to all cores on the bus */
-	list_for_each_entry(core, &bus->cores, list) {
-		int mips_irq;
-		if (core->irq)
-			continue;
-
-		mips_irq = bcma_core_mips_irq(core);
-		if (mips_irq > 4)
-			core->irq = 0;
-		else
-			core->irq = mips_irq + 2;
-		if (core->irq > 5)
-			continue;
-		switch (core->id.id) {
-		case BCMA_CORE_PCI:
-		case BCMA_CORE_PCIE:
-		case BCMA_CORE_ETHERNET:
-		case BCMA_CORE_ETHERNET_GBIT:
-		case BCMA_CORE_MAC_GBIT:
-		case BCMA_CORE_80211:
-		case BCMA_CORE_USB20_HOST:
-			/* These devices get their own IRQ line if available,
-			 * the rest goes on IRQ0
-			 */
-			if (mcore->assigned_irqs <= 4)
-				bcma_core_mips_set_irq(core,
-						       mcore->assigned_irqs++);
-			break;
+	switch (bus->chipinfo.id) {
+	case BCMA_CHIP_ID_BCM4716:
+	case BCMA_CHIP_ID_BCM4748:
+		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
+		bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
+		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
+		break;
+	case BCMA_CHIP_ID_BCM5356:
+	case BCMA_CHIP_ID_BCM47162:
+	case BCMA_CHIP_ID_BCM53572:
+		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+		break;
+	case BCMA_CHIP_ID_BCM5357:
+	case BCMA_CHIP_ID_BCM4749:
+		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
+		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
+		break;
+	case BCMA_CHIP_ID_BCM4706:
+		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
+		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
+					    0);
+		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
+		bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
+		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
+					    0);
+		break;
+	default:
+		list_for_each_entry(core, &bus->cores, list) {
+			core->irq = bcma_core_irq(core);
 		}
+		bcma_err(bus,
+			 "Unknown device (0x%x) found, can not configure IRQs\n",
+			 bus->chipinfo.id);
 	}
-	bcma_info(bus, "IRQ reconfiguration done\n");
+	bcma_debug(bus, "IRQ reconfiguration done\n");
 	bcma_core_mips_dump_irq(bus);
 
 	mcore->setup_done = true;
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
index af0c9fa..d3bde6c 100644
--- a/drivers/bcma/driver_pci_host.c
+++ b/drivers/bcma/driver_pci_host.c
@@ -94,19 +94,19 @@
 	if (dev == 0) {
 		/* we support only two functions on device 0 */
 		if (func > 1)
-			return -EINVAL;
+			goto out;
 
 		/* accesses to config registers with offsets >= 256
 		 * requires indirect access.
 		 */
 		if (off >= PCI_CONFIG_SPACE_SIZE) {
 			addr = (func << 12);
-			addr |= (off & 0x0FFF);
+			addr |= (off & 0x0FFC);
 			val = bcma_pcie_read_config(pc, addr);
 		} else {
 			addr = BCMA_CORE_PCI_PCICFG0;
 			addr |= (func << 8);
-			addr |= (off & 0xfc);
+			addr |= (off & 0xFC);
 			val = pcicore_read32(pc, addr);
 		}
 	} else {
@@ -119,11 +119,9 @@
 			goto out;
 
 		if (mips_busprobe32(val, mmio)) {
-			val = 0xffffffff;
+			val = 0xFFFFFFFF;
 			goto unmap;
 		}
-
-		val = readl(mmio);
 	}
 	val >>= (8 * (off & 3));
 
@@ -151,7 +149,7 @@
 				   const void *buf, int len)
 {
 	int err = -EINVAL;
-	u32 addr = 0, val = 0;
+	u32 addr, val;
 	void __iomem *mmio = 0;
 	u16 chipid = pc->core->bus->chipinfo.id;
 
@@ -159,16 +157,22 @@
 	if (unlikely(len != 1 && len != 2 && len != 4))
 		goto out;
 	if (dev == 0) {
+		/* we support only two functions on device 0 */
+		if (func > 1)
+			goto out;
+
 		/* accesses to config registers with offsets >= 256
 		 * requires indirect access.
 		 */
-		if (off < PCI_CONFIG_SPACE_SIZE) {
-			addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
+		if (off >= PCI_CONFIG_SPACE_SIZE) {
+			addr = (func << 12);
+			addr |= (off & 0x0FFC);
+			val = bcma_pcie_read_config(pc, addr);
+		} else {
+			addr = BCMA_CORE_PCI_PCICFG0;
 			addr |= (func << 8);
-			addr |= (off & 0xfc);
-			mmio = ioremap_nocache(addr, sizeof(val));
-			if (!mmio)
-				goto out;
+			addr |= (off & 0xFC);
+			val = pcicore_read32(pc, addr);
 		}
 	} else {
 		addr = bcma_get_cfgspace_addr(pc, dev, func, off);
@@ -180,19 +184,17 @@
 			goto out;
 
 		if (mips_busprobe32(val, mmio)) {
-			val = 0xffffffff;
+			val = 0xFFFFFFFF;
 			goto unmap;
 		}
 	}
 
 	switch (len) {
 	case 1:
-		val = readl(mmio);
 		val &= ~(0xFF << (8 * (off & 3)));
 		val |= *((const u8 *)buf) << (8 * (off & 3));
 		break;
 	case 2:
-		val = readl(mmio);
 		val &= ~(0xFFFF << (8 * (off & 3)));
 		val |= *((const u16 *)buf) << (8 * (off & 3));
 		break;
@@ -200,13 +202,14 @@
 		val = *((const u32 *)buf);
 		break;
 	}
-	if (dev == 0 && !addr) {
+	if (dev == 0) {
 		/* accesses to config registers with offsets >= 256
 		 * requires indirect access.
 		 */
-		addr = (func << 12);
-		addr |= (off & 0x0FFF);
-		bcma_pcie_write_config(pc, addr, val);
+		if (off >= PCI_CONFIG_SPACE_SIZE)
+			bcma_pcie_write_config(pc, addr, val);
+		else
+			pcicore_write32(pc, addr, val);
 	} else {
 		writel(val, mmio);
 
@@ -276,7 +279,7 @@
 	/* check for Header type 0 */
 	bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
 				sizeof(u8));
-	if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
+	if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL)
 		return cap_ptr;
 
 	/* check if the capability pointer field exists */
@@ -426,7 +429,7 @@
 	/* Reset RC */
 	usleep_range(3000, 5000);
 	pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
-	usleep_range(1000, 2000);
+	msleep(50);
 	pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
 			BCMA_CORE_PCI_CTL_RST_OE);
 
@@ -488,6 +491,17 @@
 
 	bcma_core_pci_enable_crs(pc);
 
+	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706 ||
+	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4716) {
+		u16 val16;
+		bcma_extpci_read_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
+					&val16, sizeof(val16));
+		val16 |= (2 << 5);	/* Max payload size of 512 */
+		val16 |= (2 << 12);	/* MRRS 512 */
+		bcma_extpci_write_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
+					 &val16, sizeof(val16));
+	}
+
 	/* Enable PCI bridge BAR0 memory & master access */
 	tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
 	bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
@@ -576,7 +590,7 @@
 	pr_info("PCI: Fixing up device %s\n", pci_name(dev));
 
 	/* Fix up interrupt lines */
-	dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
+	dev->irq = bcma_core_irq(pc_host->pdev->core);
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 
 	return 0;
@@ -595,6 +609,6 @@
 
 	pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
 			       pci_ops);
-	return bcma_core_mips_irq(pc_host->pdev->core) + 2;
+	return bcma_core_irq(pc_host->pdev->core);
 }
 EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 324f9de..9a6188a 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -81,8 +81,8 @@
 }
 EXPORT_SYMBOL_GPL(bcma_find_core);
 
-static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
-					       u8 unit)
+struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+					u8 unit)
 {
 	struct bcma_device *core;
 
@@ -149,6 +149,14 @@
 		dev_id++;
 	}
 
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+	if (bus->drv_cc.pflash.present) {
+		err = platform_device_register(&bcma_pflash_dev);
+		if (err)
+			bcma_err(bus, "Error registering parallel flash\n");
+	}
+#endif
+
 #ifdef CONFIG_BCMA_SFLASH
 	if (bus->drv_cc.sflash.present) {
 		err = platform_device_register(&bcma_sflash_dev);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 564156a..5814deb 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -461,7 +461,7 @@
 	int op_len, err;
 	void *req_buf;
 
-	if (!(((u64)1 << ((u64)op - 1)) & port->operations))
+	if (!(((u64)1 << (u64)op) & port->operations))
 		return -EOPNOTSUPP;
 
 	switch (op) {
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 765fa2b..8766a22 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -844,6 +844,7 @@
 		swd->unit[drive].swd = swd;
 	}
 
+	spin_lock_init(&swd->lock);
 	swd->queue = blk_init_queue(do_fd_request, &swd->lock);
 	if (!swd->queue) {
 		err = -ENOMEM;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index fe6d4be..e3f9a99 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -1041,7 +1041,7 @@
 	return hpet_alloc(&data);
 }
 
-static int hpet_acpi_remove(struct acpi_device *device, int type)
+static int hpet_acpi_remove(struct acpi_device *device)
 {
 	/* XXX need to unregister clocksource, dealloc mem, etc */
 	return -EINVAL;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index d780295..6386a98 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1142,7 +1142,7 @@
 	return 0;
 }
 
-static int sonypi_acpi_remove(struct acpi_device *device, int type)
+static int sonypi_acpi_remove(struct acpi_device *device)
 {
 	sonypi_acpi_device = NULL;
 	return 0;
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index ee90e87..14fde73 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,8 +1,13 @@
 # common clock types
 obj-$(CONFIG_HAVE_CLK)		+= clk-devres.o
 obj-$(CONFIG_CLKDEV_LOOKUP)	+= clkdev.o
-obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-fixed-rate.o clk-gate.o \
-				   clk-mux.o clk-divider.o clk-fixed-factor.o
+obj-$(CONFIG_COMMON_CLK)	+= clk.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-divider.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-fixed-factor.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-fixed-rate.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-gate.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-mux.o
+
 # SoCs specific
 obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
 obj-$(CONFIG_ARCH_NOMADIK)	+= clk-nomadik.o
@@ -20,8 +25,8 @@
 obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
-obj-$(CONFIG_ARCH_SUNXI)	+= clk-sunxi.o
 obj-$(CONFIG_ARCH_ZYNQ)		+= clk-zynq.o
+obj-$(CONFIG_X86)		+= x86/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index a9204c6..68b4021 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/string.h>
+#include <linux/log2.h>
 
 /*
  * DOC: basic adjustable divider clock that cannot gate
@@ -29,8 +30,7 @@
 
 #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
 
-#define div_mask(d)	((1 << (d->width)) - 1)
-#define is_power_of_two(i)	!(i & ~i)
+#define div_mask(d)	((1 << ((d)->width)) - 1)
 
 static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 {
@@ -137,7 +137,7 @@
 static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
 {
 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
-		return is_power_of_two(div);
+		return is_power_of_2(div);
 	if (divider->table)
 		return _is_valid_table_div(divider->table, div);
 	return true;
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index a489985..1ef271e 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -28,8 +28,11 @@
 		unsigned long parent_rate)
 {
 	struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
+	unsigned long long int rate;
 
-	return parent_rate * fix->mult / fix->div;
+	rate = (unsigned long long int)parent_rate * fix->mult;
+	do_div(rate, fix->div);
+	return (unsigned long)rate;
 }
 
 static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index af78ed6..dc58fbd 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -85,7 +85,7 @@
 /**
  * of_fixed_clk_setup() - Setup function for simple fixed rate clock
  */
-void __init of_fixed_clk_setup(struct device_node *node)
+void of_fixed_clk_setup(struct device_node *node)
 {
 	struct clk *clk;
 	const char *clk_name = node->name;
@@ -101,4 +101,5 @@
 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 }
 EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
+CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
 #endif
diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..2e08cb0 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
@@ -314,33 +316,23 @@
 {
 	hb_clk_init(node, &clk_pll_ops);
 }
+CLK_OF_DECLARE(hb_pll, "calxeda,hb-pll-clock", hb_pll_init);
 
 static void __init hb_a9periph_init(struct device_node *node)
 {
 	hb_clk_init(node, &a9periphclk_ops);
 }
+CLK_OF_DECLARE(hb_a9periph, "calxeda,hb-a9periph-clock", hb_a9periph_init);
 
 static void __init hb_a9bus_init(struct device_node *node)
 {
 	struct clk *clk = hb_clk_init(node, &a9bclk_ops);
 	clk_prepare_enable(clk);
 }
+CLK_OF_DECLARE(hb_a9bus, "calxeda,hb-a9bus-clock", hb_a9bus_init);
 
 static void __init hb_emmc_init(struct device_node *node)
 {
 	hb_clk_init(node, &periclk_ops);
 }
-
-static const __initconst struct of_device_id clk_match[] = {
-	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
-	{ .compatible = "calxeda,hb-pll-clock", .data = hb_pll_init, },
-	{ .compatible = "calxeda,hb-a9periph-clock", .data = hb_a9periph_init, },
-	{ .compatible = "calxeda,hb-a9bus-clock", .data = hb_a9bus_init, },
-	{ .compatible = "calxeda,hb-emmc-clock", .data = hb_emmc_init, },
-	{}
-};
-
-void __init highbank_clocks_init(void)
-{
-	of_clk_init(clk_match);
-}
+CLK_OF_DECLARE(hb_emmc, "calxeda,hb-emmc-clock", hb_emmc_init);
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index d098f72..9f57bc3 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -44,33 +44,23 @@
 	struct clk_lookup *lookup;
 };
 
-static struct max77686_clk *get_max77686_clk(struct clk_hw *hw)
+static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
 {
 	return container_of(hw, struct max77686_clk, hw);
 }
 
 static int max77686_clk_prepare(struct clk_hw *hw)
 {
-	struct max77686_clk *max77686;
-	int ret;
+	struct max77686_clk *max77686 = to_max77686_clk(hw);
 
-	max77686 = get_max77686_clk(hw);
-	if (!max77686)
-		return -ENOMEM;
-
-	ret = regmap_update_bits(max77686->iodev->regmap,
-		MAX77686_REG_32KHZ, max77686->mask, max77686->mask);
-
-	return ret;
+	return regmap_update_bits(max77686->iodev->regmap,
+				  MAX77686_REG_32KHZ, max77686->mask,
+				  max77686->mask);
 }
 
 static void max77686_clk_unprepare(struct clk_hw *hw)
 {
-	struct max77686_clk *max77686;
-
-	max77686 = get_max77686_clk(hw);
-	if (!max77686)
-		return;
+	struct max77686_clk *max77686 = to_max77686_clk(hw);
 
 	regmap_update_bits(max77686->iodev->regmap,
 		MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
@@ -78,14 +68,10 @@
 
 static int max77686_clk_is_enabled(struct clk_hw *hw)
 {
-	struct max77686_clk *max77686;
+	struct max77686_clk *max77686 = to_max77686_clk(hw);
 	int ret;
 	u32 val;
 
-	max77686 = get_max77686_clk(hw);
-	if (!max77686)
-		return -ENOMEM;
-
 	ret = regmap_read(max77686->iodev->regmap,
 				MAX77686_REG_32KHZ, &val);
 
@@ -130,9 +116,8 @@
 	if (IS_ERR(clk))
 		return -ENOMEM;
 
-	max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup),
-					GFP_KERNEL);
-	if (IS_ERR(max77686->lookup))
+	max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
+	if (!max77686->lookup)
 		return -ENOMEM;
 
 	max77686->lookup->con_id = hw->init->name;
@@ -151,13 +136,13 @@
 
 	max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
 					* MAX77686_CLKS_NUM, GFP_KERNEL);
-	if (IS_ERR(max77686_clks))
+	if (!max77686_clks)
 		return -ENOMEM;
 
 	for (i = 0; i < MAX77686_CLKS_NUM; i++) {
 		max77686_clks[i] = devm_kzalloc(&pdev->dev,
 					sizeof(struct max77686_clk), GFP_KERNEL);
-		if (IS_ERR(max77686_clks[i]))
+		if (!max77686_clks[i])
 			return -ENOMEM;
 	}
 
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
index a203ecc..f8e9d0c 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/clk-prima2.c
@@ -1025,20 +1025,67 @@
 	{},
 };
 
+enum prima2_clk_index {
+	/* 0    1     2      3      4      5      6       7         8      9 */
+	rtc,    osc,   pll1,  pll2,  pll3,  mem,   sys,   security, dsp,   gps,
+	mf,     io,    cpu,   uart0, uart1, uart2, tsc,   i2c0,     i2c1,  spi0,
+	spi1,   pwmc,  efuse, pulse, dmac0, dmac1, nand,  audio,    usp0,  usp1,
+	usp2,   vip,   gfx,   mm,    lcd,   vpp,   mmc01, mmc23,    mmc45, usbpll,
+	usb0,  usb1,  maxclk,
+};
+
+static __initdata struct clk_hw* prima2_clk_hw_array[maxclk] = {
+	NULL, /* dummy */
+	NULL,
+	&clk_pll1.hw,
+	&clk_pll2.hw,
+	&clk_pll3.hw,
+	&clk_mem.hw,
+	&clk_sys.hw,
+	&clk_security.hw,
+	&clk_dsp.hw,
+	&clk_gps.hw,
+	&clk_mf.hw,
+	&clk_io.hw,
+	&clk_cpu.hw,
+	&clk_uart0.hw,
+	&clk_uart1.hw,
+	&clk_uart2.hw,
+	&clk_tsc.hw,
+	&clk_i2c0.hw,
+	&clk_i2c1.hw,
+	&clk_spi0.hw,
+	&clk_spi1.hw,
+	&clk_pwmc.hw,
+	&clk_efuse.hw,
+	&clk_pulse.hw,
+	&clk_dmac0.hw,
+	&clk_dmac1.hw,
+	&clk_nand.hw,
+	&clk_audio.hw,
+	&clk_usp0.hw,
+	&clk_usp1.hw,
+	&clk_usp2.hw,
+	&clk_vip.hw,
+	&clk_gfx.hw,
+	&clk_mm.hw,
+	&clk_lcd.hw,
+	&clk_vpp.hw,
+	&clk_mmc01.hw,
+	&clk_mmc23.hw,
+	&clk_mmc45.hw,
+	&usb_pll_clk_hw,
+	&clk_usb0.hw,
+	&clk_usb1.hw,
+};
+
+static struct clk *prima2_clks[maxclk];
+static struct clk_onecell_data clk_data;
+
 void __init sirfsoc_of_clk_init(void)
 {
-	struct clk *clk;
 	struct device_node *np;
-
-	np = of_find_matching_node(NULL, clkc_ids);
-	if (!np)
-		panic("unable to find compatible clkc node in dtb\n");
-
-	sirfsoc_clk_vbase = of_iomap(np, 0);
-	if (!sirfsoc_clk_vbase)
-		panic("unable to map clkc registers\n");
-
-	of_node_put(np);
+	int i;
 
 	np = of_find_matching_node(NULL, rsc_ids);
 	if (!np)
@@ -1050,122 +1097,30 @@
 
 	of_node_put(np);
 
+	np = of_find_matching_node(NULL, clkc_ids);
+	if (!np)
+		return;
+
+	sirfsoc_clk_vbase = of_iomap(np, 0);
+	if (!sirfsoc_clk_vbase)
+		panic("unable to map clkc registers\n");
 
 	/* These are always available (RTC and 26MHz OSC)*/
-	clk = clk_register_fixed_rate(NULL, "rtc", NULL,
+	prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
 		CLK_IS_ROOT, 32768);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register_fixed_rate(NULL, "osc", NULL,
+	prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL,
 		CLK_IS_ROOT, 26000000);
-	BUG_ON(IS_ERR(clk));
 
-	clk = clk_register(NULL, &clk_pll1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_pll2.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_pll3.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_mem.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_sys.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_security.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b8030000.security");
-	clk = clk_register(NULL, &clk_dsp.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_gps.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "a8010000.gps");
-	clk = clk_register(NULL, &clk_mf.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_io.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "io");
-	clk = clk_register(NULL, &clk_cpu.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "cpu");
-	clk = clk_register(NULL, &clk_uart0.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0050000.uart");
-	clk = clk_register(NULL, &clk_uart1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0060000.uart");
-	clk = clk_register(NULL, &clk_uart2.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0070000.uart");
-	clk = clk_register(NULL, &clk_tsc.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0110000.tsc");
-	clk = clk_register(NULL, &clk_i2c0.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00e0000.i2c");
-	clk = clk_register(NULL, &clk_i2c1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00f0000.i2c");
-	clk = clk_register(NULL, &clk_spi0.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00d0000.spi");
-	clk = clk_register(NULL, &clk_spi1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0170000.spi");
-	clk = clk_register(NULL, &clk_pwmc.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0130000.pwm");
-	clk = clk_register(NULL, &clk_efuse.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0140000.efusesys");
-	clk = clk_register(NULL, &clk_pulse.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0150000.pulsec");
-	clk = clk_register(NULL, &clk_dmac0.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
-	clk = clk_register(NULL, &clk_dmac1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
-	clk = clk_register(NULL, &clk_nand.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0030000.nand");
-	clk = clk_register(NULL, &clk_audio.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0040000.audio");
-	clk = clk_register(NULL, &clk_usp0.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0080000.usp");
-	clk = clk_register(NULL, &clk_usp1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b0090000.usp");
-	clk = clk_register(NULL, &clk_usp2.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00a0000.usp");
-	clk = clk_register(NULL, &clk_vip.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00c0000.vip");
-	clk = clk_register(NULL, &clk_gfx.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "98000000.graphics");
-	clk = clk_register(NULL, &clk_mm.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "a0000000.multimedia");
-	clk = clk_register(NULL, &clk_lcd.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "90010000.display");
-	clk = clk_register(NULL, &clk_vpp.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "90020000.vpp");
-	clk = clk_register(NULL, &clk_mmc01.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_mmc23.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_mmc45.hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &usb_pll_clk_hw);
-	BUG_ON(IS_ERR(clk));
-	clk = clk_register(NULL, &clk_usb0.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00e0000.usb");
-	clk = clk_register(NULL, &clk_usb1.hw);
-	BUG_ON(IS_ERR(clk));
-	clk_register_clkdev(clk, NULL, "b00f0000.usb");
+	for (i = pll1; i < maxclk; i++) {
+		prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
+		BUG_ON(!prima2_clks[i]);
+	}
+	clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
+	clk_register_clkdev(prima2_clks[io],  NULL, "io");
+	clk_register_clkdev(prima2_clks[mem],  NULL, "mem");
+
+	clk_data.clks = prima2_clks;
+	clk_data.clk_num = maxclk;
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 }
diff --git a/drivers/clk/clk-sunxi.c b/drivers/clk/clk-sunxi.c
deleted file mode 100644
index 0e831b5..0000000
--- a/drivers/clk/clk-sunxi.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/clk/sunxi.h>
-#include <linux/of.h>
-
-static const __initconst struct of_device_id clk_match[] = {
-	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
-	{}
-};
-
-void __init sunxi_init_clocks(void)
-{
-	of_clk_init(clk_match);
-}
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index fe25570..b5538bb 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -41,6 +41,7 @@
 
 #define PLL_TYPE_VT8500		0
 #define PLL_TYPE_WM8650		1
+#define PLL_TYPE_WM8750		2
 
 struct clk_pll {
 	struct clk_hw	hw;
@@ -121,7 +122,16 @@
 				unsigned long *prate)
 {
 	struct clk_device *cdev = to_clk_device(hw);
-	u32 divisor = *prate / rate;
+	u32 divisor;
+
+	if (rate == 0)
+		return 0;
+
+	divisor = *prate / rate;
+
+	/* If prate / rate would be decimal, incr the divisor */
+	if (rate * divisor < *prate)
+		divisor++;
 
 	/*
 	 * If this is a request for SDMMC we have to adjust the divisor
@@ -138,9 +148,18 @@
 				unsigned long parent_rate)
 {
 	struct clk_device *cdev = to_clk_device(hw);
-	u32 divisor = parent_rate / rate;
+	u32 divisor;
 	unsigned long flags = 0;
 
+	if (rate == 0)
+		return 0;
+
+	divisor =  parent_rate / rate;
+
+	/* If prate / rate would be decimal, incr the divisor */
+	if (rate * divisor < *prate)
+		divisor++;
+
 	if (divisor == cdev->div_mask + 1)
 		divisor = 0;
 
@@ -272,7 +291,7 @@
 	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
 	clk_register_clkdev(clk, clk_name, NULL);
 }
-
+CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
 
 /* PLL clock related functions */
 
@@ -298,6 +317,16 @@
 #define WM8650_BITS_TO_VAL(m, d1, d2)					\
 				((d2 << 13) | (d1 << 10) | (m & 0x3FF))
 
+/* Helper macros for PLL_WM8750 */
+#define WM8750_PLL_MUL(x)	(((x >> 16) & 0xFF) + 1)
+#define WM8750_PLL_DIV(x)	((((x >> 8) & 1) + 1) * (1 << (x & 7)))
+
+#define WM8750_BITS_TO_FREQ(r, m, d1, d2)				\
+				(r * (m+1) / ((d1+1) * (1 << d2)))
+
+#define WM8750_BITS_TO_VAL(f, m, d1, d2)				\
+		((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
+
 
 static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
 				u32 *multiplier, u32 *prediv)
@@ -361,16 +390,87 @@
 	/* if we got here, it wasn't an exact match */
 	pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
 							rate - best_err);
-	*multiplier = mul;
-	*divisor1 = div1;
-	*divisor2 = div2;
+	*multiplier = best_mul;
+	*divisor1 = best_div1;
+	*divisor2 = best_div2;
+}
+
+static u32 wm8750_get_filter(u32 parent_rate, u32 divisor1)
+{
+	/* calculate frequency (MHz) after pre-divisor */
+	u32 freq = (parent_rate / 1000000) / (divisor1 + 1);
+
+	if ((freq < 10) || (freq > 200))
+		pr_warn("%s: PLL recommended input frequency 10..200Mhz (requested %d Mhz)\n",
+				__func__, freq);
+
+	if (freq >= 166)
+		return 7;
+	else if (freq >= 104)
+		return 6;
+	else if (freq >= 65)
+		return 5;
+	else if (freq >= 42)
+		return 4;
+	else if (freq >= 26)
+		return 3;
+	else if (freq >= 16)
+		return 2;
+	else if (freq >= 10)
+		return 1;
+
+	return 0;
+}
+
+static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
+				u32 *filter, u32 *multiplier, u32 *divisor1, u32 *divisor2)
+{
+	u32 mul, div1, div2;
+	u32 best_mul, best_div1, best_div2;
+	unsigned long tclk, rate_err, best_err;
+
+	best_err = (unsigned long)-1;
+
+	/* Find the closest match (lower or equal to requested) */
+	for (div1 = 1; div1 >= 0; div1--)
+		for (div2 = 7; div2 >= 0; div2--)
+			for (mul = 0; mul <= 255; mul++) {
+				tclk = parent_rate * (mul + 1) / ((div1 + 1) * (1 << div2));
+				if (tclk > rate)
+					continue;
+				/* error will always be +ve */
+				rate_err = rate - tclk;
+				if (rate_err == 0) {
+					*filter = wm8750_get_filter(parent_rate, div1);
+					*multiplier = mul;
+					*divisor1 = div1;
+					*divisor2 = div2;
+					return;
+				}
+
+				if (rate_err < best_err) {
+					best_err = rate_err;
+					best_mul = mul;
+					best_div1 = div1;
+					best_div2 = div2;
+				}
+			}
+
+	/* if we got here, it wasn't an exact match */
+	pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
+							rate - best_err);
+
+	*filter = wm8750_get_filter(parent_rate, best_div1);
+	*multiplier = best_mul;
+	*divisor1 = best_div1;
+	*divisor2 = best_div2;
 }
 
 static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 				unsigned long parent_rate)
 {
 	struct clk_pll *pll = to_clk_pll(hw);
-	u32 mul, div1, div2;
+	u32 filter, mul, div1, div2;
 	u32 pll_val;
 	unsigned long flags = 0;
 
@@ -385,6 +485,9 @@
 		wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
 		pll_val = WM8650_BITS_TO_VAL(mul, div1, div2);
 		break;
+	case PLL_TYPE_WM8750:
+		wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
+		pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
 	default:
 		pr_err("%s: invalid pll type\n", __func__);
 		return 0;
@@ -405,7 +508,7 @@
 				unsigned long *prate)
 {
 	struct clk_pll *pll = to_clk_pll(hw);
-	u32 mul, div1, div2;
+	u32 filter, mul, div1, div2;
 	long round_rate;
 
 	switch (pll->type) {
@@ -417,6 +520,9 @@
 		wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2);
 		round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2);
 		break;
+	case PLL_TYPE_WM8750:
+		wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
+		round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
 	default:
 		round_rate = 0;
 	}
@@ -440,6 +546,10 @@
 		pll_freq = parent_rate * WM8650_PLL_MUL(pll_val);
 		pll_freq /= WM8650_PLL_DIV(pll_val);
 		break;
+	case PLL_TYPE_WM8750:
+		pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
+		pll_freq /= WM8750_PLL_DIV(pll_val);
+		break;
 	default:
 		pll_freq = 0;
 	}
@@ -502,20 +612,19 @@
 {
 	vtwm_pll_clk_init(node, PLL_TYPE_VT8500);
 }
+CLK_OF_DECLARE(vt8500_pll, "via,vt8500-pll-clock", vt8500_pll_init);
 
 static void __init wm8650_pll_init(struct device_node *node)
 {
 	vtwm_pll_clk_init(node, PLL_TYPE_WM8650);
 }
+CLK_OF_DECLARE(wm8650_pll, "wm,wm8650-pll-clock", wm8650_pll_init);
 
-static const __initconst struct of_device_id clk_match[] = {
-	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
-	{ .compatible = "via,vt8500-pll-clock", .data = vt8500_pll_init, },
-	{ .compatible = "wm,wm8650-pll-clock", .data = wm8650_pll_init, },
-	{ .compatible = "via,vt8500-device-clock",
-					.data = vtwm_device_clk_init, },
-	{ /* sentinel */ }
-};
+static void __init wm8750_pll_init(struct device_node *node)
+{
+	vtwm_pll_clk_init(node, PLL_TYPE_WM8750);
+}
+CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
 
 void __init vtwm_clk_init(void __iomem *base)
 {
@@ -524,5 +633,5 @@
 
 	pmc_base = base;
 
-	of_clk_init(clk_match);
+	of_clk_init(NULL);
 }
diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c
index 37a3051..b14a25f 100644
--- a/drivers/clk/clk-zynq.c
+++ b/drivers/clk/clk-zynq.c
@@ -81,6 +81,7 @@
 	if (WARN_ON(ret))
 		return;
 }
+CLK_OF_DECLARE(zynq_pll, "xlnx,zynq-pll", zynq_pll_clk_setup);
 
 struct zynq_periph_clk {
 	struct clk_hw		hw;
@@ -187,6 +188,7 @@
 	if (WARN_ON(err))
 		return;
 }
+CLK_OF_DECLARE(zynq_periph, "xlnx,zynq-periph-clock", zynq_periph_clk_setup);
 
 /* CPU Clock domain is modelled as a mux with 4 children subclks, whose
  * derivative rates depend on CLK_621_TRUE
@@ -366,18 +368,10 @@
 	if (WARN_ON(err))
 		return;
 }
-
-static const __initconst struct of_device_id zynq_clk_match[] = {
-	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
-	{ .compatible = "xlnx,zynq-pll", .data = zynq_pll_clk_setup, },
-	{ .compatible = "xlnx,zynq-periph-clock",
-		.data = zynq_periph_clk_setup, },
-	{ .compatible = "xlnx,zynq-cpu-clock", .data = zynq_cpu_clk_setup, },
-	{}
-};
+CLK_OF_DECLARE(zynq_cpu, "xlnx,zynq-cpu-clock", zynq_cpu_clk_setup);
 
 void __init xilinx_zynq_clocks_init(void __iomem *slcr)
 {
 	slcr_base = slcr;
-	of_clk_init(zynq_clk_match);
+	of_clk_init(NULL);
 }
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 251e45d..fabbfe1 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/device.h>
+#include <linux/init.h>
 
 static DEFINE_SPINLOCK(enable_lock);
 static DEFINE_MUTEX(prepare_lock);
@@ -35,6 +36,137 @@
 static struct dentry *orphandir;
 static int inited = 0;
 
+static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+{
+	if (!c)
+		return;
+
+	seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
+		   level * 3 + 1, "",
+		   30 - level * 3, c->name,
+		   c->enable_count, c->prepare_count, c->rate);
+	seq_printf(s, "\n");
+}
+
+static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+				     int level)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+
+	if (!c)
+		return;
+
+	clk_summary_show_one(s, c, level);
+
+	hlist_for_each_entry(child, tmp, &c->children, child_node)
+		clk_summary_show_subtree(s, child, level + 1);
+}
+
+static int clk_summary_show(struct seq_file *s, void *data)
+{
+	struct clk *c;
+	struct hlist_node *tmp;
+
+	seq_printf(s, "   clock                        enable_cnt  prepare_cnt  rate\n");
+	seq_printf(s, "---------------------------------------------------------------------\n");
+
+	mutex_lock(&prepare_lock);
+
+	hlist_for_each_entry(c, tmp, &clk_root_list, child_node)
+		clk_summary_show_subtree(s, c, 0);
+
+	hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node)
+		clk_summary_show_subtree(s, c, 0);
+
+	mutex_unlock(&prepare_lock);
+
+	return 0;
+}
+
+
+static int clk_summary_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, clk_summary_show, inode->i_private);
+}
+
+static const struct file_operations clk_summary_fops = {
+	.open		= clk_summary_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+{
+	if (!c)
+		return;
+
+	seq_printf(s, "\"%s\": { ", c->name);
+	seq_printf(s, "\"enable_count\": %d,", c->enable_count);
+	seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
+	seq_printf(s, "\"rate\": %lu", c->rate);
+}
+
+static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+{
+	struct clk *child;
+	struct hlist_node *tmp;
+
+	if (!c)
+		return;
+
+	clk_dump_one(s, c, level);
+
+	hlist_for_each_entry(child, tmp, &c->children, child_node) {
+		seq_printf(s, ",");
+		clk_dump_subtree(s, child, level + 1);
+	}
+
+	seq_printf(s, "}");
+}
+
+static int clk_dump(struct seq_file *s, void *data)
+{
+	struct clk *c;
+	struct hlist_node *tmp;
+	bool first_node = true;
+
+	seq_printf(s, "{");
+
+	mutex_lock(&prepare_lock);
+
+	hlist_for_each_entry(c, tmp, &clk_root_list, child_node) {
+		if (!first_node)
+			seq_printf(s, ",");
+		first_node = false;
+		clk_dump_subtree(s, c, 0);
+	}
+
+	hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) {
+		seq_printf(s, ",");
+		clk_dump_subtree(s, c, 0);
+	}
+
+	mutex_unlock(&prepare_lock);
+
+	seq_printf(s, "}");
+	return 0;
+}
+
+
+static int clk_dump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, clk_dump, inode->i_private);
+}
+
+static const struct file_operations clk_dump_fops = {
+	.open		= clk_dump_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 /* caller must hold prepare_lock */
 static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
 {
@@ -168,12 +300,23 @@
 {
 	struct clk *clk;
 	struct hlist_node *tmp;
+	struct dentry *d;
 
 	rootdir = debugfs_create_dir("clk", NULL);
 
 	if (!rootdir)
 		return -ENOMEM;
 
+	d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, NULL,
+				&clk_summary_fops);
+	if (!d)
+		return -ENOMEM;
+
+	d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, NULL,
+				&clk_dump_fops);
+	if (!d)
+		return -ENOMEM;
+
 	orphandir = debugfs_create_dir("orphans", rootdir);
 
 	if (!orphandir)
@@ -259,32 +402,33 @@
 
 /***    helper functions   ***/
 
-inline const char *__clk_get_name(struct clk *clk)
+const char *__clk_get_name(struct clk *clk)
 {
 	return !clk ? NULL : clk->name;
 }
+EXPORT_SYMBOL_GPL(__clk_get_name);
 
-inline struct clk_hw *__clk_get_hw(struct clk *clk)
+struct clk_hw *__clk_get_hw(struct clk *clk)
 {
 	return !clk ? NULL : clk->hw;
 }
 
-inline u8 __clk_get_num_parents(struct clk *clk)
+u8 __clk_get_num_parents(struct clk *clk)
 {
 	return !clk ? 0 : clk->num_parents;
 }
 
-inline struct clk *__clk_get_parent(struct clk *clk)
+struct clk *__clk_get_parent(struct clk *clk)
 {
 	return !clk ? NULL : clk->parent;
 }
 
-inline unsigned int __clk_get_enable_count(struct clk *clk)
+unsigned int __clk_get_enable_count(struct clk *clk)
 {
 	return !clk ? 0 : clk->enable_count;
 }
 
-inline unsigned int __clk_get_prepare_count(struct clk *clk)
+unsigned int __clk_get_prepare_count(struct clk *clk)
 {
 	return !clk ? 0 : clk->prepare_count;
 }
@@ -310,7 +454,7 @@
 	return ret;
 }
 
-inline unsigned long __clk_get_flags(struct clk *clk)
+unsigned long __clk_get_flags(struct clk *clk)
 {
 	return !clk ? 0 : clk->flags;
 }
@@ -950,9 +1094,6 @@
 	/* change the rates */
 	clk_change_rate(top);
 
-	mutex_unlock(&prepare_lock);
-
-	return 0;
 out:
 	mutex_unlock(&prepare_lock);
 
@@ -1663,6 +1804,11 @@
 	void *data;
 };
 
+extern struct of_device_id __clk_of_table[];
+
+static const struct of_device_id __clk_of_table_sentinel
+	__used __section(__clk_of_table_end);
+
 static LIST_HEAD(of_clk_providers);
 static DEFINE_MUTEX(of_clk_lock);
 
@@ -1791,6 +1937,9 @@
 {
 	struct device_node *np;
 
+	if (!matches)
+		matches = __clk_of_table;
+
 	for_each_matching_node(np, matches) {
 		const struct of_device_id *match = of_match_node(matches, np);
 		of_clk_init_cb_t clk_init_cb = match->data;
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c
index 8fa5408..ebf141d 100644
--- a/drivers/clk/mvebu/clk-gating-ctrl.c
+++ b/drivers/clk/mvebu/clk-gating-ctrl.c
@@ -193,6 +193,7 @@
 	{ "runit", NULL, 7 },
 	{ "xor0", NULL, 8 },
 	{ "audio", NULL, 9 },
+	{ "powersave", "cpuclk", 11 },
 	{ "sata0", NULL, 14 },
 	{ "sata1", NULL, 15 },
 	{ "xor1", NULL, 16 },
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 8dd476e..b5c06f9 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -99,7 +99,7 @@
 int __init mx23_clocks_init(void)
 {
 	struct device_node *np;
-	int i;
+	u32 i;
 
 	clk_misc_init();
 
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index db3af08..126370a 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -154,7 +154,7 @@
 int __init mx28_clocks_init(void)
 {
 	struct device_node *np;
-	int i;
+	u32 i;
 
 	clk_misc_init();
 
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index dcb6ae0..256c8be 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -144,3 +144,4 @@
 		vexpress_config_func_put(osc->func);
 	kfree(osc);
 }
+CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
index c742ac7..f889f2f 100644
--- a/drivers/clk/versatile/clk-vexpress.c
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -99,19 +99,13 @@
 	return vexpress_sp810_timerclken[clkspec->args[0]];
 }
 
-static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
-	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
-	{ .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
-	{}
-};
-
 void __init vexpress_clk_of_init(void)
 {
 	struct device_node *node;
 	struct clk *clk;
 	struct clk *refclk, *timclk;
 
-	of_clk_init(vexpress_fixed_clk_match);
+	of_clk_init(NULL);
 
 	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
 	vexpress_sp810_init(of_iomap(node, 0));
diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile
new file mode 100644
index 0000000..f9ba4fa
--- /dev/null
+++ b/drivers/clk/x86/Makefile
@@ -0,0 +1,2 @@
+clk-x86-lpss-objs		:= clk-lpss.o clk-lpt.o
+obj-$(CONFIG_X86_INTEL_LPSS)	+= clk-x86-lpss.o
diff --git a/drivers/clk/x86/clk-lpss.c b/drivers/clk/x86/clk-lpss.c
new file mode 100644
index 0000000..b5e229f
--- /dev/null
+++ b/drivers/clk/x86/clk-lpss.c
@@ -0,0 +1,99 @@
+/*
+ * Intel Low Power Subsystem clocks.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *	    Heikki Krogerus <heikki.krogerus@linux.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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+static int clk_lpss_is_mmio_resource(struct acpi_resource *res, void *data)
+{
+	struct resource r;
+	return !acpi_dev_resource_memory(res, &r);
+}
+
+static acpi_status clk_lpss_find_mmio(acpi_handle handle, u32 level,
+				      void *data, void **retval)
+{
+	struct resource_list_entry *rentry;
+	struct list_head resource_list;
+	struct acpi_device *adev;
+	const char *uid = data;
+	int ret;
+
+	if (acpi_bus_get_device(handle, &adev))
+		return AE_OK;
+
+	if (uid) {
+		if (!adev->pnp.unique_id)
+			return AE_OK;
+		if (strcmp(uid, adev->pnp.unique_id))
+			return AE_OK;
+	}
+
+	INIT_LIST_HEAD(&resource_list);
+	ret = acpi_dev_get_resources(adev, &resource_list,
+				     clk_lpss_is_mmio_resource, NULL);
+	if (ret < 0)
+		return AE_NO_MEMORY;
+
+	list_for_each_entry(rentry, &resource_list, node)
+		if (resource_type(&rentry->res) == IORESOURCE_MEM) {
+			*(struct resource *)retval = rentry->res;
+			break;
+		}
+
+	acpi_dev_free_resource_list(&resource_list);
+	return AE_OK;
+}
+
+/**
+ * clk_register_lpss_gate - register LPSS clock gate
+ * @name: name of this clock gate
+ * @parent_name: parent clock name
+ * @hid: ACPI _HID of the device
+ * @uid: ACPI _UID of the device (optional)
+ * @offset: LPSS PRV_CLOCK_PARAMS offset
+ *
+ * Creates and registers LPSS clock gate.
+ */
+struct clk *clk_register_lpss_gate(const char *name, const char *parent_name,
+				   const char *hid, const char *uid,
+				   unsigned offset)
+{
+	struct resource res = { };
+	void __iomem *mmio_base;
+	acpi_status status;
+	struct clk *clk;
+
+	/*
+	 * First try to look the device and its mmio resource from the
+	 * ACPI namespace.
+	 */
+	status = acpi_get_devices(hid, clk_lpss_find_mmio, (void *)uid,
+				  (void **)&res);
+	if (ACPI_FAILURE(status) || !res.start)
+		return ERR_PTR(-ENODEV);
+
+	mmio_base = ioremap(res.start, resource_size(&res));
+	if (!mmio_base)
+		return ERR_PTR(-ENOMEM);
+
+	clk = clk_register_gate(NULL, name, parent_name, 0, mmio_base + offset,
+				0, 0, NULL);
+	if (IS_ERR(clk))
+		iounmap(mmio_base);
+
+	return clk;
+}
diff --git a/drivers/clk/x86/clk-lpss.h b/drivers/clk/x86/clk-lpss.h
new file mode 100644
index 0000000..e9460f4
--- /dev/null
+++ b/drivers/clk/x86/clk-lpss.h
@@ -0,0 +1,36 @@
+/*
+ * Intel Low Power Subsystem clock.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *	    Heikki Krogerus <heikki.krogerus@linux.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.
+ */
+
+#ifndef __CLK_LPSS_H
+#define __CLK_LPSS_H
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+
+#ifdef CONFIG_ACPI
+extern struct clk *clk_register_lpss_gate(const char *name,
+					  const char *parent_name,
+					  const char *hid, const char *uid,
+					  unsigned offset);
+#else
+static inline struct clk *clk_register_lpss_gate(const char *name,
+						 const char *parent_name,
+						 const char *hid,
+						 const char *uid,
+						 unsigned offset)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
+#endif /* __CLK_LPSS_H */
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
new file mode 100644
index 0000000..81298ae
--- /dev/null
+++ b/drivers/clk/x86/clk-lpt.c
@@ -0,0 +1,86 @@
+/*
+ * Intel Lynxpoint LPSS clocks.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *	    Heikki Krogerus <heikki.krogerus@linux.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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "clk-lpss.h"
+
+#define PRV_CLOCK_PARAMS 0x800
+
+static int lpt_clk_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+
+	/* LPSS free running clock */
+	clk = clk_register_fixed_rate(&pdev->dev, "lpss_clk", NULL, CLK_IS_ROOT,
+				      100000000);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	/* Shared DMA clock */
+	clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto");
+
+	/* SPI clocks */
+	clk = clk_register_lpss_gate("spi0_clk", "lpss_clk", "INT33C0", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C0:00");
+
+	clk = clk_register_lpss_gate("spi1_clk", "lpss_clk", "INT33C1", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C1:00");
+
+	/* I2C clocks */
+	clk = clk_register_lpss_gate("i2c0_clk", "lpss_clk", "INT33C2", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C2:00");
+
+	clk = clk_register_lpss_gate("i2c1_clk", "lpss_clk", "INT33C3", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C3:00");
+
+	/* UART clocks */
+	clk = clk_register_lpss_gate("uart0_clk", "lpss_clk", "INT33C4", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C4:00");
+
+	clk = clk_register_lpss_gate("uart1_clk", "lpss_clk", "INT33C5", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C5:00");
+
+	return 0;
+}
+
+static struct platform_driver lpt_clk_driver = {
+	.driver = {
+		.name = "clk-lpt",
+		.owner = THIS_MODULE,
+	},
+	.probe = lpt_clk_probe,
+};
+
+static int __init lpt_clk_init(void)
+{
+	return platform_driver_register(&lpt_clk_driver);
+}
+arch_initcall(lpt_clk_init);
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c
index 3cd1bd3..93d09d0 100644
--- a/drivers/clocksource/sunxi_timer.c
+++ b/drivers/clocksource/sunxi_timer.c
@@ -23,7 +23,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/sunxi_timer.h>
-#include <linux/clk/sunxi.h>
+#include <linux/clk-provider.h>
 
 #define TIMER_CTL_REG		0x00
 #define TIMER_CTL_ENABLE		(1 << 0)
@@ -124,7 +124,7 @@
 	if (irq <= 0)
 		panic("Can't parse IRQ");
 
-	sunxi_init_clocks();
+	of_clk_init(NULL);
 
 	clk = of_clk_get(node, 0);
 	if (IS_ERR(clk))
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 7b69591..f1b7e24 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -276,7 +276,7 @@
 
 	cn_already_initialized = 1;
 
-	proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
+	proc_create("connector", S_IRUGO, init_net.proc_net, &cn_file_ops);
 
 	return 0;
 }
@@ -287,7 +287,7 @@
 
 	cn_already_initialized = 0;
 
-	proc_net_remove(&init_net, "connector");
+	remove_proc_entry("connector", init_net.proc_net);
 
 	cn_queue_free_dev(dev->cbdev);
 	netlink_kernel_release(dev->nls);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index e0a899f..cbcb21e 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -185,7 +185,7 @@
 	  If in doubt, say N.
 
 config GENERIC_CPUFREQ_CPU0
-	bool "Generic CPU0 cpufreq driver"
+	tristate "Generic CPU0 cpufreq driver"
 	depends on HAVE_CLK && REGULATOR && PM_OPP && OF
 	select CPU_FREQ_TABLE
 	help
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a0b3661..7f333af 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -77,9 +77,39 @@
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
 
+config ARM_KIRKWOOD_CPUFREQ
+	def_bool ARCH_KIRKWOOD && OF
+	help
+	  This adds the CPUFreq driver for Marvell Kirkwood
+	  SoCs.
+
+config ARM_IMX6Q_CPUFREQ
+	tristate "Freescale i.MX6Q cpufreq support"
+	depends on SOC_IMX6Q
+	depends on REGULATOR_ANATOP
+	help
+	  This adds cpufreq driver support for Freescale i.MX6Q SOC.
+
+	  If in doubt, say N.
+
 config ARM_SPEAR_CPUFREQ
 	bool "SPEAr CPUFreq support"
 	depends on PLAT_SPEAR
 	default y
 	help
 	  This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	  This adds the CPUFreq driver for Calxeda Highbank SoC
+	  based boards.
+
+	  If in doubt, say N.
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 7227cd7..98e5abb 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -2,6 +2,19 @@
 # x86 CPU Frequency scaling drivers
 #
 
+config X86_INTEL_PSTATE
+       bool "Intel P state control"
+       depends on X86
+       help
+          This driver provides a P state for Intel core processors.
+	  The driver implements an internal governor and will become
+          the scaling driver and governor for Sandy bridge processors.
+
+	  When this driver is enabled it will become the perferred
+          scaling driver for Sandy bridge processors.
+
+	  If in doubt, say N.
+
 config X86_PCC_CPUFREQ
 	tristate "Processor Clocking Control interface driver"
 	depends on ACPI && ACPI_PROCESSOR
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index fadc4d4..5399c45 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -19,11 +19,12 @@
 ##################################################################################
 # x86 drivers.
 # Link order matters. K8 is preferred to ACPI because of firmware bugs in early
-# K8 systems. ACPI is preferred to all other hardware-specific drivers.
+# K8 systems. This is still the case but acpi-cpufreq errors out so that
+# powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers.
 # speedstep-* is preferred over p4-clockmod.
 
-obj-$(CONFIG_X86_POWERNOW_K8)		+= powernow-k8.o
 obj-$(CONFIG_X86_ACPI_CPUFREQ)		+= acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_POWERNOW_K8)		+= powernow-k8.o
 obj-$(CONFIG_X86_PCC_CPUFREQ)		+= pcc-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K6)		+= powernow-k6.o
 obj-$(CONFIG_X86_POWERNOW_K7)		+= powernow-k7.o
@@ -39,6 +40,7 @@
 obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO)	+= speedstep-centrino.o
 obj-$(CONFIG_X86_P4_CLOCKMOD)		+= p4-clockmod.o
 obj-$(CONFIG_X86_CPUFREQ_NFORCE2)	+= cpufreq-nforce2.o
+obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
 
 ##################################################################################
 # ARM SoC drivers
@@ -50,8 +52,11 @@
 obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
-obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)	+= kirkwood-cpufreq.o
+obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)	+= omap-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
+obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)		+= imx6q-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 7b0d49d..937bc28 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -734,7 +734,7 @@
 
 #ifdef CONFIG_SMP
 	dmi_check_system(sw_any_bug_dmi_table);
-	if (bios_with_sw_any_bug && cpumask_weight(policy->cpus) == 1) {
+	if (bios_with_sw_any_bug && !policy_is_shared(policy)) {
 		policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
 		cpumask_copy(policy->cpus, cpu_core_mask(cpu));
 	}
@@ -762,6 +762,12 @@
 
 	switch (perf->control_register.space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_IO:
+		if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+		    boot_cpu_data.x86 == 0xf) {
+			pr_debug("AMD K8 systems must use native drivers.\n");
+			result = -ENODEV;
+			goto err_unreg;
+		}
 		pr_debug("SYSTEM IO addr space\n");
 		data->cpu_feature = SYSTEM_IO_CAPABLE;
 		break;
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index debc5a7..4e5b7fb 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -12,12 +12,12 @@
 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 
 #include <linux/clk.h>
-#include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/opp.h>
+#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
@@ -146,7 +146,6 @@
 	 * share the clock and voltage and clock.  Use cpufreq affected_cpus
 	 * interface to have all CPUs scaled together.
 	 */
-	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
 	cpumask_setall(policy->cpus);
 
 	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
@@ -177,34 +176,32 @@
 	.attr = cpu0_cpufreq_attr,
 };
 
-static int cpu0_cpufreq_driver_init(void)
+static int cpu0_cpufreq_probe(struct platform_device *pdev)
 {
 	struct device_node *np;
 	int ret;
 
-	np = of_find_node_by_path("/cpus/cpu@0");
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (of_get_property(np, "operating-points", NULL))
+			break;
+	}
+
 	if (!np) {
 		pr_err("failed to find cpu0 node\n");
 		return -ENOENT;
 	}
 
-	cpu_dev = get_cpu_device(0);
-	if (!cpu_dev) {
-		pr_err("failed to get cpu0 device\n");
-		ret = -ENODEV;
-		goto out_put_node;
-	}
-
+	cpu_dev = &pdev->dev;
 	cpu_dev->of_node = np;
 
-	cpu_clk = clk_get(cpu_dev, NULL);
+	cpu_clk = devm_clk_get(cpu_dev, NULL);
 	if (IS_ERR(cpu_clk)) {
 		ret = PTR_ERR(cpu_clk);
 		pr_err("failed to get cpu0 clock: %d\n", ret);
 		goto out_put_node;
 	}
 
-	cpu_reg = regulator_get(cpu_dev, "cpu0");
+	cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
 	if (IS_ERR(cpu_reg)) {
 		pr_warn("failed to get cpu0 regulator\n");
 		cpu_reg = NULL;
@@ -267,7 +264,24 @@
 	of_node_put(np);
 	return ret;
 }
-late_initcall(cpu0_cpufreq_driver_init);
+
+static int cpu0_cpufreq_remove(struct platform_device *pdev)
+{
+	cpufreq_unregister_driver(&cpu0_cpufreq_driver);
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+	return 0;
+}
+
+static struct platform_driver cpu0_cpufreq_platdrv = {
+	.driver = {
+		.name	= "cpufreq-cpu0",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= cpu0_cpufreq_probe,
+	.remove		= cpu0_cpufreq_remove,
+};
+module_platform_driver(cpu0_cpufreq_platdrv);
 
 MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
 MODULE_DESCRIPTION("Generic CPU0 cpufreq driver");
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1f93dbd..b02824d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -59,8 +59,6 @@
  *   mode before doing so.
  *
  * Additional rules:
- * - All holders of the lock should check to make sure that the CPU they
- *   are concerned with are online after they get the lock.
  * - Governor routines that can be called in cpufreq hotplug path should not
  *   take this sem as top level hotplug notifier handler takes this.
  * - Lock should not be held across
@@ -70,38 +68,28 @@
 static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
 
 #define lock_policy_rwsem(mode, cpu)					\
-static int lock_policy_rwsem_##mode					\
-(int cpu)								\
+static int lock_policy_rwsem_##mode(int cpu)				\
 {									\
 	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);		\
 	BUG_ON(policy_cpu == -1);					\
 	down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));		\
-	if (unlikely(!cpu_online(cpu))) {				\
-		up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));	\
-		return -1;						\
-	}								\
 									\
 	return 0;							\
 }
 
 lock_policy_rwsem(read, cpu);
-
 lock_policy_rwsem(write, cpu);
 
-static void unlock_policy_rwsem_read(int cpu)
-{
-	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
-	BUG_ON(policy_cpu == -1);
-	up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
+#define unlock_policy_rwsem(mode, cpu)					\
+static void unlock_policy_rwsem_##mode(int cpu)				\
+{									\
+	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);		\
+	BUG_ON(policy_cpu == -1);					\
+	up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));		\
 }
 
-static void unlock_policy_rwsem_write(int cpu)
-{
-	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
-	BUG_ON(policy_cpu == -1);
-	up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
-}
-
+unlock_policy_rwsem(read, cpu);
+unlock_policy_rwsem(write, cpu);
 
 /* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy,
@@ -180,6 +168,9 @@
 
 struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 {
+	if (cpufreq_disabled())
+		return NULL;
+
 	return __cpufreq_cpu_get(cpu, false);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
@@ -198,6 +189,9 @@
 
 void cpufreq_cpu_put(struct cpufreq_policy *data)
 {
+	if (cpufreq_disabled())
+		return;
+
 	__cpufreq_cpu_put(data, false);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
@@ -261,14 +255,21 @@
 void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
 {
 	struct cpufreq_policy *policy;
+	unsigned long flags;
 
 	BUG_ON(irqs_disabled());
 
+	if (cpufreq_disabled())
+		return;
+
 	freqs->flags = cpufreq_driver->flags;
 	pr_debug("notification %u of frequency transition to %u kHz\n",
 		state, freqs->new);
 
+	spin_lock_irqsave(&cpufreq_driver_lock, flags);
 	policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
+	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
 	switch (state) {
 
 	case CPUFREQ_PRECHANGE:
@@ -294,7 +295,6 @@
 		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
 		pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
 			(unsigned long)freqs->cpu);
-		trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
 		trace_cpu_frequency(freqs->new, freqs->cpu);
 		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				CPUFREQ_POSTCHANGE, freqs);
@@ -543,8 +543,6 @@
  */
 static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
 {
-	if (cpumask_empty(policy->related_cpus))
-		return show_cpus(policy->cpus, buf);
 	return show_cpus(policy->related_cpus, buf);
 }
 
@@ -700,87 +698,6 @@
 	.release	= cpufreq_sysfs_release,
 };
 
-/*
- * Returns:
- *   Negative: Failure
- *   0:        Success
- *   Positive: When we have a managed CPU and the sysfs got symlinked
- */
-static int cpufreq_add_dev_policy(unsigned int cpu,
-				  struct cpufreq_policy *policy,
-				  struct device *dev)
-{
-	int ret = 0;
-#ifdef CONFIG_SMP
-	unsigned long flags;
-	unsigned int j;
-#ifdef CONFIG_HOTPLUG_CPU
-	struct cpufreq_governor *gov;
-
-	gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
-	if (gov) {
-		policy->governor = gov;
-		pr_debug("Restoring governor %s for cpu %d\n",
-		       policy->governor->name, cpu);
-	}
-#endif
-
-	for_each_cpu(j, policy->cpus) {
-		struct cpufreq_policy *managed_policy;
-
-		if (cpu == j)
-			continue;
-
-		/* Check for existing affected CPUs.
-		 * They may not be aware of it due to CPU Hotplug.
-		 * cpufreq_cpu_put is called when the device is removed
-		 * in __cpufreq_remove_dev()
-		 */
-		managed_policy = cpufreq_cpu_get(j);
-		if (unlikely(managed_policy)) {
-
-			/* Set proper policy_cpu */
-			unlock_policy_rwsem_write(cpu);
-			per_cpu(cpufreq_policy_cpu, cpu) = managed_policy->cpu;
-
-			if (lock_policy_rwsem_write(cpu) < 0) {
-				/* Should not go through policy unlock path */
-				if (cpufreq_driver->exit)
-					cpufreq_driver->exit(policy);
-				cpufreq_cpu_put(managed_policy);
-				return -EBUSY;
-			}
-
-			spin_lock_irqsave(&cpufreq_driver_lock, flags);
-			cpumask_copy(managed_policy->cpus, policy->cpus);
-			per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
-			spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
-			pr_debug("CPU already managed, adding link\n");
-			ret = sysfs_create_link(&dev->kobj,
-						&managed_policy->kobj,
-						"cpufreq");
-			if (ret)
-				cpufreq_cpu_put(managed_policy);
-			/*
-			 * Success. We only needed to be added to the mask.
-			 * Call driver->exit() because only the cpu parent of
-			 * the kobj needed to call init().
-			 */
-			if (cpufreq_driver->exit)
-				cpufreq_driver->exit(policy);
-
-			if (!ret)
-				return 1;
-			else
-				return ret;
-		}
-	}
-#endif
-	return ret;
-}
-
-
 /* symlink affected CPUs */
 static int cpufreq_add_dev_symlink(unsigned int cpu,
 				   struct cpufreq_policy *policy)
@@ -794,8 +711,6 @@
 
 		if (j == cpu)
 			continue;
-		if (!cpu_online(j))
-			continue;
 
 		pr_debug("CPU %u already managed, adding link\n", j);
 		managed_policy = cpufreq_cpu_get(cpu);
@@ -852,8 +767,6 @@
 
 	spin_lock_irqsave(&cpufreq_driver_lock, flags);
 	for_each_cpu(j, policy->cpus) {
-		if (!cpu_online(j))
-			continue;
 		per_cpu(cpufreq_cpu_data, j) = policy;
 		per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
 	}
@@ -885,6 +798,42 @@
 	return ret;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
+				  struct device *dev)
+{
+	struct cpufreq_policy *policy;
+	int ret = 0;
+	unsigned long flags;
+
+	policy = cpufreq_cpu_get(sibling);
+	WARN_ON(!policy);
+
+	__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+
+	lock_policy_rwsem_write(sibling);
+
+	spin_lock_irqsave(&cpufreq_driver_lock, flags);
+
+	cpumask_set_cpu(cpu, policy->cpus);
+	per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
+	per_cpu(cpufreq_cpu_data, cpu) = policy;
+	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+	unlock_policy_rwsem_write(sibling);
+
+	__cpufreq_governor(policy, CPUFREQ_GOV_START);
+	__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+	ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
+	if (ret) {
+		cpufreq_cpu_put(policy);
+		return ret;
+	}
+
+	return 0;
+}
+#endif
 
 /**
  * cpufreq_add_dev - add a CPU device
@@ -897,12 +846,12 @@
  */
 static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 {
-	unsigned int cpu = dev->id;
-	int ret = 0, found = 0;
+	unsigned int j, cpu = dev->id;
+	int ret = -ENOMEM;
 	struct cpufreq_policy *policy;
 	unsigned long flags;
-	unsigned int j;
 #ifdef CONFIG_HOTPLUG_CPU
+	struct cpufreq_governor *gov;
 	int sibling;
 #endif
 
@@ -919,6 +868,19 @@
 		cpufreq_cpu_put(policy);
 		return 0;
 	}
+
+#ifdef CONFIG_HOTPLUG_CPU
+	/* Check if this cpu was hot-unplugged earlier and has siblings */
+	spin_lock_irqsave(&cpufreq_driver_lock, flags);
+	for_each_online_cpu(sibling) {
+		struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
+		if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
+			spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+			return cpufreq_add_policy_cpu(cpu, sibling, dev);
+		}
+	}
+	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+#endif
 #endif
 
 	if (!try_module_get(cpufreq_driver->owner)) {
@@ -926,7 +888,6 @@
 		goto module_out;
 	}
 
-	ret = -ENOMEM;
 	policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
 	if (!policy)
 		goto nomem_out;
@@ -938,66 +899,58 @@
 		goto err_free_cpumask;
 
 	policy->cpu = cpu;
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	cpumask_copy(policy->cpus, cpumask_of(cpu));
 
 	/* Initially set CPU itself as the policy_cpu */
 	per_cpu(cpufreq_policy_cpu, cpu) = cpu;
-	ret = (lock_policy_rwsem_write(cpu) < 0);
-	WARN_ON(ret);
 
 	init_completion(&policy->kobj_unregister);
 	INIT_WORK(&policy->update, handle_update);
 
-	/* Set governor before ->init, so that driver could check it */
-#ifdef CONFIG_HOTPLUG_CPU
-	for_each_online_cpu(sibling) {
-		struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
-		if (cp && cp->governor &&
-		    (cpumask_test_cpu(cpu, cp->related_cpus))) {
-			policy->governor = cp->governor;
-			found = 1;
-			break;
-		}
-	}
-#endif
-	if (!found)
-		policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
 	 */
 	ret = cpufreq_driver->init(policy);
 	if (ret) {
 		pr_debug("initialization failed\n");
-		goto err_unlock_policy;
+		goto err_set_policy_cpu;
 	}
+
+	/* related cpus should atleast have policy->cpus */
+	cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+	/*
+	 * affected cpus must always be the one, which are online. We aren't
+	 * managing offline cpus here.
+	 */
+	cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
 	policy->user_policy.min = policy->min;
 	policy->user_policy.max = policy->max;
 
 	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
 				     CPUFREQ_START, policy);
 
-	ret = cpufreq_add_dev_policy(cpu, policy, dev);
-	if (ret) {
-		if (ret > 0)
-			/* This is a managed cpu, symlink created,
-			   exit with 0 */
-			ret = 0;
-		goto err_unlock_policy;
+#ifdef CONFIG_HOTPLUG_CPU
+	gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
+	if (gov) {
+		policy->governor = gov;
+		pr_debug("Restoring governor %s for cpu %d\n",
+		       policy->governor->name, cpu);
 	}
+#endif
 
 	ret = cpufreq_add_dev_interface(cpu, policy, dev);
 	if (ret)
 		goto err_out_unregister;
 
-	unlock_policy_rwsem_write(cpu);
-
 	kobject_uevent(&policy->kobj, KOBJ_ADD);
 	module_put(cpufreq_driver->owner);
 	pr_debug("initialization complete\n");
 
 	return 0;
 
-
 err_out_unregister:
 	spin_lock_irqsave(&cpufreq_driver_lock, flags);
 	for_each_cpu(j, policy->cpus)
@@ -1007,8 +960,8 @@
 	kobject_put(&policy->kobj);
 	wait_for_completion(&policy->kobj_unregister);
 
-err_unlock_policy:
-	unlock_policy_rwsem_write(cpu);
+err_set_policy_cpu:
+	per_cpu(cpufreq_policy_cpu, cpu) = -1;
 	free_cpumask_var(policy->related_cpus);
 err_free_cpumask:
 	free_cpumask_var(policy->cpus);
@@ -1020,6 +973,22 @@
 	return ret;
 }
 
+static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
+{
+	int j;
+
+	policy->last_cpu = policy->cpu;
+	policy->cpu = cpu;
+
+	for_each_cpu(j, policy->cpus)
+		per_cpu(cpufreq_policy_cpu, j) = cpu;
+
+#ifdef CONFIG_CPU_FREQ_TABLE
+	cpufreq_frequency_table_update_policy_cpu(policy);
+#endif
+	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+			CPUFREQ_UPDATE_POLICY_CPU, policy);
+}
 
 /**
  * __cpufreq_remove_dev - remove a CPU device
@@ -1030,129 +999,103 @@
  */
 static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
-	unsigned int cpu = dev->id;
+	unsigned int cpu = dev->id, ret, cpus;
 	unsigned long flags;
 	struct cpufreq_policy *data;
 	struct kobject *kobj;
 	struct completion *cmp;
-#ifdef CONFIG_SMP
 	struct device *cpu_dev;
-	unsigned int j;
-#endif
 
-	pr_debug("unregistering CPU %u\n", cpu);
+	pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
 
 	spin_lock_irqsave(&cpufreq_driver_lock, flags);
-	data = per_cpu(cpufreq_cpu_data, cpu);
 
-	if (!data) {
-		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-		unlock_policy_rwsem_write(cpu);
-		return -EINVAL;
-	}
+	data = per_cpu(cpufreq_cpu_data, cpu);
 	per_cpu(cpufreq_cpu_data, cpu) = NULL;
 
-
-#ifdef CONFIG_SMP
-	/* if this isn't the CPU which is the parent of the kobj, we
-	 * only need to unlink, put and exit
-	 */
-	if (unlikely(cpu != data->cpu)) {
-		pr_debug("removing link\n");
-		cpumask_clear_cpu(cpu, data->cpus);
-		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-		kobj = &dev->kobj;
-		cpufreq_cpu_put(data);
-		unlock_policy_rwsem_write(cpu);
-		sysfs_remove_link(kobj, "cpufreq");
-		return 0;
-	}
-#endif
-
-#ifdef CONFIG_SMP
-
-#ifdef CONFIG_HOTPLUG_CPU
-	strncpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name,
-			CPUFREQ_NAME_LEN);
-#endif
-
-	/* if we have other CPUs still registered, we need to unlink them,
-	 * or else wait_for_completion below will lock up. Clean the
-	 * per_cpu(cpufreq_cpu_data) while holding the lock, and remove
-	 * the sysfs links afterwards.
-	 */
-	if (unlikely(cpumask_weight(data->cpus) > 1)) {
-		for_each_cpu(j, data->cpus) {
-			if (j == cpu)
-				continue;
-			per_cpu(cpufreq_cpu_data, j) = NULL;
-		}
-	}
-
 	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-	if (unlikely(cpumask_weight(data->cpus) > 1)) {
-		for_each_cpu(j, data->cpus) {
-			if (j == cpu)
-				continue;
-			pr_debug("removing link for cpu %u\n", j);
-#ifdef CONFIG_HOTPLUG_CPU
-			strncpy(per_cpu(cpufreq_cpu_governor, j),
-				data->governor->name, CPUFREQ_NAME_LEN);
-#endif
-			cpu_dev = get_cpu_device(j);
-			kobj = &cpu_dev->kobj;
-			unlock_policy_rwsem_write(cpu);
-			sysfs_remove_link(kobj, "cpufreq");
-			lock_policy_rwsem_write(cpu);
-			cpufreq_cpu_put(data);
-		}
+	if (!data) {
+		pr_debug("%s: No cpu_data found\n", __func__);
+		return -EINVAL;
 	}
-#else
-	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-#endif
 
 	if (cpufreq_driver->target)
 		__cpufreq_governor(data, CPUFREQ_GOV_STOP);
 
-	kobj = &data->kobj;
-	cmp = &data->kobj_unregister;
-	unlock_policy_rwsem_write(cpu);
-	kobject_put(kobj);
-
-	/* we need to make sure that the underlying kobj is actually
-	 * not referenced anymore by anybody before we proceed with
-	 * unloading.
-	 */
-	pr_debug("waiting for dropping of refcount\n");
-	wait_for_completion(cmp);
-	pr_debug("wait complete\n");
-
-	lock_policy_rwsem_write(cpu);
-	if (cpufreq_driver->exit)
-		cpufreq_driver->exit(data);
-	unlock_policy_rwsem_write(cpu);
-
 #ifdef CONFIG_HOTPLUG_CPU
-	/* when the CPU which is the parent of the kobj is hotplugged
-	 * offline, check for siblings, and create cpufreq sysfs interface
-	 * and symlinks
-	 */
-	if (unlikely(cpumask_weight(data->cpus) > 1)) {
-		/* first sibling now owns the new sysfs dir */
-		cpumask_clear_cpu(cpu, data->cpus);
-		cpufreq_add_dev(get_cpu_device(cpumask_first(data->cpus)), NULL);
-
-		/* finally remove our own symlink */
-		lock_policy_rwsem_write(cpu);
-		__cpufreq_remove_dev(dev, sif);
-	}
+	if (!cpufreq_driver->setpolicy)
+		strncpy(per_cpu(cpufreq_cpu_governor, cpu),
+			data->governor->name, CPUFREQ_NAME_LEN);
 #endif
 
-	free_cpumask_var(data->related_cpus);
-	free_cpumask_var(data->cpus);
-	kfree(data);
+	WARN_ON(lock_policy_rwsem_write(cpu));
+	cpus = cpumask_weight(data->cpus);
+	cpumask_clear_cpu(cpu, data->cpus);
+	unlock_policy_rwsem_write(cpu);
 
+	if (cpu != data->cpu) {
+		sysfs_remove_link(&dev->kobj, "cpufreq");
+	} else if (cpus > 1) {
+		/* first sibling now owns the new sysfs dir */
+		cpu_dev = get_cpu_device(cpumask_first(data->cpus));
+		sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+		ret = kobject_move(&data->kobj, &cpu_dev->kobj);
+		if (ret) {
+			pr_err("%s: Failed to move kobj: %d", __func__, ret);
+
+			WARN_ON(lock_policy_rwsem_write(cpu));
+			cpumask_set_cpu(cpu, data->cpus);
+
+			spin_lock_irqsave(&cpufreq_driver_lock, flags);
+			per_cpu(cpufreq_cpu_data, cpu) = data;
+			spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+			unlock_policy_rwsem_write(cpu);
+
+			ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
+					"cpufreq");
+			return -EINVAL;
+		}
+
+		WARN_ON(lock_policy_rwsem_write(cpu));
+		update_policy_cpu(data, cpu_dev->id);
+		unlock_policy_rwsem_write(cpu);
+		pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
+				__func__, cpu_dev->id, cpu);
+	}
+
+	pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+	cpufreq_cpu_put(data);
+
+	/* If cpu is last user of policy, free policy */
+	if (cpus == 1) {
+		lock_policy_rwsem_read(cpu);
+		kobj = &data->kobj;
+		cmp = &data->kobj_unregister;
+		unlock_policy_rwsem_read(cpu);
+		kobject_put(kobj);
+
+		/* we need to make sure that the underlying kobj is actually
+		 * not referenced anymore by anybody before we proceed with
+		 * unloading.
+		 */
+		pr_debug("waiting for dropping of refcount\n");
+		wait_for_completion(cmp);
+		pr_debug("wait complete\n");
+
+		if (cpufreq_driver->exit)
+			cpufreq_driver->exit(data);
+
+		free_cpumask_var(data->related_cpus);
+		free_cpumask_var(data->cpus);
+		kfree(data);
+	} else if (cpufreq_driver->target) {
+		__cpufreq_governor(data, CPUFREQ_GOV_START);
+		__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+	}
+
+	per_cpu(cpufreq_policy_cpu, cpu) = -1;
 	return 0;
 }
 
@@ -1165,9 +1108,6 @@
 	if (cpu_is_offline(cpu))
 		return 0;
 
-	if (unlikely(lock_policy_rwsem_write(cpu)))
-		BUG();
-
 	retval = __cpufreq_remove_dev(dev, sif);
 	return retval;
 }
@@ -1216,9 +1156,13 @@
  */
 unsigned int cpufreq_quick_get(unsigned int cpu)
 {
-	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+	struct cpufreq_policy *policy;
 	unsigned int ret_freq = 0;
 
+	if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)
+		return cpufreq_driver->get(cpu);
+
+	policy = cpufreq_cpu_get(cpu);
 	if (policy) {
 		ret_freq = policy->cur;
 		cpufreq_cpu_put(policy);
@@ -1386,6 +1330,20 @@
 	.resume		= cpufreq_bp_resume,
 };
 
+/**
+ *	cpufreq_get_current_driver - return current driver's name
+ *
+ *	Return the name string of the currently loaded cpufreq driver
+ *	or NULL, if none.
+ */
+const char *cpufreq_get_current_driver(void)
+{
+	if (cpufreq_driver)
+		return cpufreq_driver->name;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(cpufreq_get_current_driver);
 
 /*********************************************************************
  *                     NOTIFIER LISTS INTERFACE                      *
@@ -1408,6 +1366,9 @@
 {
 	int ret;
 
+	if (cpufreq_disabled())
+		return -EINVAL;
+
 	WARN_ON(!init_cpufreq_transition_notifier_list_called);
 
 	switch (list) {
@@ -1442,6 +1403,9 @@
 {
 	int ret;
 
+	if (cpufreq_disabled())
+		return -EINVAL;
+
 	switch (list) {
 	case CPUFREQ_TRANSITION_NOTIFIER:
 		ret = srcu_notifier_chain_unregister(
@@ -1487,7 +1451,7 @@
 	if (target_freq == policy->cur)
 		return 0;
 
-	if (cpu_online(policy->cpu) && cpufreq_driver->target)
+	if (cpufreq_driver->target)
 		retval = cpufreq_driver->target(policy, target_freq, relation);
 
 	return retval;
@@ -1522,7 +1486,10 @@
 {
 	int ret = 0;
 
-	if (!(cpu_online(cpu) && cpufreq_driver->getavg))
+	if (cpufreq_disabled())
+		return ret;
+
+	if (!cpufreq_driver->getavg)
 		return 0;
 
 	policy = cpufreq_cpu_get(policy->cpu);
@@ -1577,6 +1544,11 @@
 						policy->cpu, event);
 	ret = policy->governor->governor(policy, event);
 
+	if (event == CPUFREQ_GOV_START)
+		policy->governor->initialized++;
+	else if (event == CPUFREQ_GOV_STOP)
+		policy->governor->initialized--;
+
 	/* we keep one module reference alive for
 			each CPU governed by this CPU */
 	if ((event != CPUFREQ_GOV_START) || ret)
@@ -1600,6 +1572,7 @@
 
 	mutex_lock(&cpufreq_governor_mutex);
 
+	governor->initialized = 0;
 	err = -EBUSY;
 	if (__find_governor(governor->name) == NULL) {
 		err = 0;
@@ -1797,7 +1770,7 @@
 			pr_debug("Driver did not initialize current freq");
 			data->cur = policy.cur;
 		} else {
-			if (data->cur != policy.cur)
+			if (data->cur != policy.cur && cpufreq_driver->target)
 				cpufreq_out_of_sync(cpu, data->cur,
 								policy.cur);
 		}
@@ -1829,9 +1802,6 @@
 			break;
 		case CPU_DOWN_PREPARE:
 		case CPU_DOWN_PREPARE_FROZEN:
-			if (unlikely(lock_policy_rwsem_write(cpu)))
-				BUG();
-
 			__cpufreq_remove_dev(dev, NULL);
 			break;
 		case CPU_DOWN_FAILED:
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 64ef737..4fd0006 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -25,7 +25,7 @@
 
 #include "cpufreq_governor.h"
 
-/* Conservative governor macors */
+/* Conservative governor macros */
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
 #define DEF_FREQUENCY_DOWN_THRESHOLD		(20)
 #define DEF_SAMPLING_DOWN_FACTOR		(1)
@@ -113,17 +113,20 @@
 
 static void cs_dbs_timer(struct work_struct *work)
 {
+	struct delayed_work *dw = to_delayed_work(work);
 	struct cs_cpu_dbs_info_s *dbs_info = container_of(work,
 			struct cs_cpu_dbs_info_s, cdbs.work.work);
-	unsigned int cpu = dbs_info->cdbs.cpu;
+	unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
+	struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info,
+			cpu);
 	int delay = delay_for_sampling_rate(cs_tuners.sampling_rate);
 
-	mutex_lock(&dbs_info->cdbs.timer_mutex);
+	mutex_lock(&core_dbs_info->cdbs.timer_mutex);
+	if (need_load_eval(&core_dbs_info->cdbs, cs_tuners.sampling_rate))
+		dbs_check_cpu(&cs_dbs_data, cpu);
 
-	dbs_check_cpu(&cs_dbs_data, cpu);
-
-	schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay);
-	mutex_unlock(&dbs_info->cdbs.timer_mutex);
+	schedule_delayed_work_on(smp_processor_id(), dw, delay);
+	mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
 }
 
 static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -141,7 +144,7 @@
 
 	/*
 	 * we only care if our internally tracked freq moves outside the 'valid'
-	 * ranges of freqency available to us otherwise we do not change it
+	 * ranges of frequency available to us otherwise we do not change it
 	*/
 	if (dbs_info->requested_freq > policy->max
 			|| dbs_info->requested_freq < policy->min)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 6c5f1d3..5a76086 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -161,25 +161,48 @@
 }
 EXPORT_SYMBOL_GPL(dbs_check_cpu);
 
-static inline void dbs_timer_init(struct dbs_data *dbs_data,
-		struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate)
+static inline void dbs_timer_init(struct dbs_data *dbs_data, int cpu,
+				  unsigned int sampling_rate)
 {
 	int delay = delay_for_sampling_rate(sampling_rate);
+	struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
 
-	INIT_DEFERRABLE_WORK(&cdbs->work, dbs_data->gov_dbs_timer);
-	schedule_delayed_work_on(cdbs->cpu, &cdbs->work, delay);
+	schedule_delayed_work_on(cpu, &cdbs->work, delay);
 }
 
-static inline void dbs_timer_exit(struct cpu_dbs_common_info *cdbs)
+static inline void dbs_timer_exit(struct dbs_data *dbs_data, int cpu)
 {
+	struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
+
 	cancel_delayed_work_sync(&cdbs->work);
 }
 
+/* Will return if we need to evaluate cpu load again or not */
+bool need_load_eval(struct cpu_dbs_common_info *cdbs,
+		unsigned int sampling_rate)
+{
+	if (policy_is_shared(cdbs->cur_policy)) {
+		ktime_t time_now = ktime_get();
+		s64 delta_us = ktime_us_delta(time_now, cdbs->time_stamp);
+
+		/* Do nothing if we recently have sampled */
+		if (delta_us < (s64)(sampling_rate / 2))
+			return false;
+		else
+			cdbs->time_stamp = time_now;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(need_load_eval);
+
 int cpufreq_governor_dbs(struct dbs_data *dbs_data,
 		struct cpufreq_policy *policy, unsigned int event)
 {
 	struct od_cpu_dbs_info_s *od_dbs_info = NULL;
 	struct cs_cpu_dbs_info_s *cs_dbs_info = NULL;
+	struct cs_ops *cs_ops = NULL;
+	struct od_ops *od_ops = NULL;
 	struct od_dbs_tuners *od_tuners = dbs_data->tuners;
 	struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 	struct cpu_dbs_common_info *cpu_cdbs;
@@ -192,109 +215,111 @@
 		cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
 		sampling_rate = &cs_tuners->sampling_rate;
 		ignore_nice = cs_tuners->ignore_nice;
+		cs_ops = dbs_data->gov_ops;
 	} else {
 		od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
 		sampling_rate = &od_tuners->sampling_rate;
 		ignore_nice = od_tuners->ignore_nice;
+		od_ops = dbs_data->gov_ops;
 	}
 
 	switch (event) {
 	case CPUFREQ_GOV_START:
-		if ((!cpu_online(cpu)) || (!policy->cur))
+		if (!policy->cur)
 			return -EINVAL;
 
 		mutex_lock(&dbs_data->mutex);
 
-		dbs_data->enable++;
-		cpu_cdbs->cpu = cpu;
 		for_each_cpu(j, policy->cpus) {
-			struct cpu_dbs_common_info *j_cdbs;
-			j_cdbs = dbs_data->get_cpu_cdbs(j);
+			struct cpu_dbs_common_info *j_cdbs =
+				dbs_data->get_cpu_cdbs(j);
 
+			j_cdbs->cpu = j;
 			j_cdbs->cur_policy = policy;
 			j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
 					&j_cdbs->prev_cpu_wall);
 			if (ignore_nice)
 				j_cdbs->prev_cpu_nice =
 					kcpustat_cpu(j).cpustat[CPUTIME_NICE];
+
+			mutex_init(&j_cdbs->timer_mutex);
+			INIT_DEFERRABLE_WORK(&j_cdbs->work,
+					     dbs_data->gov_dbs_timer);
 		}
 
-		/*
-		 * Start the timerschedule work, when this governor is used for
-		 * first time
-		 */
-		if (dbs_data->enable != 1)
-			goto second_time;
-
-		rc = sysfs_create_group(cpufreq_global_kobject,
-				dbs_data->attr_group);
-		if (rc) {
-			mutex_unlock(&dbs_data->mutex);
-			return rc;
+		if (!policy->governor->initialized) {
+			rc = sysfs_create_group(cpufreq_global_kobject,
+					dbs_data->attr_group);
+			if (rc) {
+				mutex_unlock(&dbs_data->mutex);
+				return rc;
+			}
 		}
 
-		/* policy latency is in nS. Convert it to uS first */
-		latency = policy->cpuinfo.transition_latency / 1000;
-		if (latency == 0)
-			latency = 1;
-
 		/*
 		 * conservative does not implement micro like ondemand
 		 * governor, thus we are bound to jiffes/HZ
 		 */
 		if (dbs_data->governor == GOV_CONSERVATIVE) {
-			struct cs_ops *ops = dbs_data->gov_ops;
+			cs_dbs_info->down_skip = 0;
+			cs_dbs_info->enable = 1;
+			cs_dbs_info->requested_freq = policy->cur;
 
-			cpufreq_register_notifier(ops->notifier_block,
-					CPUFREQ_TRANSITION_NOTIFIER);
+			if (!policy->governor->initialized) {
+				cpufreq_register_notifier(cs_ops->notifier_block,
+						CPUFREQ_TRANSITION_NOTIFIER);
 
-			dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
-				jiffies_to_usecs(10);
+				dbs_data->min_sampling_rate =
+					MIN_SAMPLING_RATE_RATIO *
+					jiffies_to_usecs(10);
+			}
 		} else {
-			struct od_ops *ops = dbs_data->gov_ops;
+			od_dbs_info->rate_mult = 1;
+			od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
+			od_ops->powersave_bias_init_cpu(cpu);
 
-			od_tuners->io_is_busy = ops->io_busy();
+			if (!policy->governor->initialized)
+				od_tuners->io_is_busy = od_ops->io_busy();
 		}
 
+		if (policy->governor->initialized)
+			goto unlock;
+
+		/* policy latency is in nS. Convert it to uS first */
+		latency = policy->cpuinfo.transition_latency / 1000;
+		if (latency == 0)
+			latency = 1;
+
 		/* Bring kernel and HW constraints together */
 		dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
 				MIN_LATENCY_MULTIPLIER * latency);
 		*sampling_rate = max(dbs_data->min_sampling_rate, latency *
 				LATENCY_MULTIPLIER);
-
-second_time:
-		if (dbs_data->governor == GOV_CONSERVATIVE) {
-			cs_dbs_info->down_skip = 0;
-			cs_dbs_info->enable = 1;
-			cs_dbs_info->requested_freq = policy->cur;
-		} else {
-			struct od_ops *ops = dbs_data->gov_ops;
-			od_dbs_info->rate_mult = 1;
-			od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
-			ops->powersave_bias_init_cpu(cpu);
-		}
+unlock:
 		mutex_unlock(&dbs_data->mutex);
 
-		mutex_init(&cpu_cdbs->timer_mutex);
-		dbs_timer_init(dbs_data, cpu_cdbs, *sampling_rate);
+		/* Initiate timer time stamp */
+		cpu_cdbs->time_stamp = ktime_get();
+
+		for_each_cpu(j, policy->cpus)
+			dbs_timer_init(dbs_data, j, *sampling_rate);
 		break;
 
 	case CPUFREQ_GOV_STOP:
 		if (dbs_data->governor == GOV_CONSERVATIVE)
 			cs_dbs_info->enable = 0;
 
-		dbs_timer_exit(cpu_cdbs);
+		for_each_cpu(j, policy->cpus)
+			dbs_timer_exit(dbs_data, j);
 
 		mutex_lock(&dbs_data->mutex);
 		mutex_destroy(&cpu_cdbs->timer_mutex);
-		dbs_data->enable--;
-		if (!dbs_data->enable) {
-			struct cs_ops *ops = dbs_data->gov_ops;
 
+		if (policy->governor->initialized == 1) {
 			sysfs_remove_group(cpufreq_global_kobject,
 					dbs_data->attr_group);
 			if (dbs_data->governor == GOV_CONSERVATIVE)
-				cpufreq_unregister_notifier(ops->notifier_block,
+				cpufreq_unregister_notifier(cs_ops->notifier_block,
 						CPUFREQ_TRANSITION_NOTIFIER);
 		}
 		mutex_unlock(&dbs_data->mutex);
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index f661654..d2ac911 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -82,6 +82,7 @@
 	 * the governor or limits.
 	 */
 	struct mutex timer_mutex;
+	ktime_t time_stamp;
 };
 
 struct od_cpu_dbs_info_s {
@@ -108,7 +109,7 @@
 	unsigned int sampling_rate;
 	unsigned int sampling_down_factor;
 	unsigned int up_threshold;
-	unsigned int down_differential;
+	unsigned int adj_up_threshold;
 	unsigned int powersave_bias;
 	unsigned int io_is_busy;
 };
@@ -129,7 +130,6 @@
 	#define GOV_CONSERVATIVE	1
 	int governor;
 	unsigned int min_sampling_rate;
-	unsigned int enable; /* number of CPUs using this policy */
 	struct attribute_group *attr_group;
 	void *tuners;
 
@@ -171,6 +171,8 @@
 
 u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
 void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
+bool need_load_eval(struct cpu_dbs_common_info *cdbs,
+		unsigned int sampling_rate);
 int cpufreq_governor_dbs(struct dbs_data *dbs_data,
 		struct cpufreq_policy *policy, unsigned int event);
 #endif /* _CPUFREQ_GOVERNER_H */
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 7731f7c..f3eb26c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -26,7 +26,7 @@
 
 #include "cpufreq_governor.h"
 
-/* On-demand governor macors */
+/* On-demand governor macros */
 #define DEF_FREQUENCY_DOWN_DIFFERENTIAL		(10)
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
 #define DEF_SAMPLING_DOWN_FACTOR		(1)
@@ -47,7 +47,8 @@
 static struct od_dbs_tuners od_tuners = {
 	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
 	.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
-	.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
+	.adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
+			    DEF_FREQUENCY_DOWN_DIFFERENTIAL,
 	.ignore_nice = 0,
 	.powersave_bias = 0,
 };
@@ -65,7 +66,7 @@
  * efficient idling at a higher frequency/voltage is.
  * Pavel Machek says this is not so for various generations of AMD and old
  * Intel systems.
- * Mike Chan (androidlcom) calis this is also not true for ARM.
+ * Mike Chan (android.com) claims this is also not true for ARM.
  * Because of this, whitelist specific known (series) of CPUs by default, and
  * leave all others up to the user.
  */
@@ -73,7 +74,7 @@
 {
 #if defined(CONFIG_X86)
 	/*
-	 * For Intel, Core 2 (model 15) andl later have an efficient idle.
+	 * For Intel, Core 2 (model 15) and later have an efficient idle.
 	 */
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
 			boot_cpu_data.x86 == 6 &&
@@ -158,8 +159,8 @@
 
 /*
  * Every sampling_rate, we check, if current idle time is less than 20%
- * (default), then we try to increase frequency Every sampling_rate, we look for
- * a the lowest frequency which can sustain the load while keeping idle time
+ * (default), then we try to increase frequency. Every sampling_rate, we look
+ * for the lowest frequency which can sustain the load while keeping idle time
  * over 30%. If such a frequency exist, we try to decrease to this frequency.
  *
  * Any frequency increase takes it to the maximum frequency. Frequency reduction
@@ -192,11 +193,9 @@
 	 * support the current CPU usage without triggering the up policy. To be
 	 * safe, we focus 10 points under the threshold.
 	 */
-	if (load_freq < (od_tuners.up_threshold - od_tuners.down_differential) *
-			policy->cur) {
+	if (load_freq < od_tuners.adj_up_threshold * policy->cur) {
 		unsigned int freq_next;
-		freq_next = load_freq / (od_tuners.up_threshold -
-				od_tuners.down_differential);
+		freq_next = load_freq / od_tuners.adj_up_threshold;
 
 		/* No longer fully busy, reset rate_mult */
 		dbs_info->rate_mult = 1;
@@ -218,33 +217,42 @@
 
 static void od_dbs_timer(struct work_struct *work)
 {
+	struct delayed_work *dw = to_delayed_work(work);
 	struct od_cpu_dbs_info_s *dbs_info =
 		container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work);
-	unsigned int cpu = dbs_info->cdbs.cpu;
-	int delay, sample_type = dbs_info->sample_type;
+	unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
+	struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info,
+			cpu);
+	int delay, sample_type = core_dbs_info->sample_type;
+	bool eval_load;
 
-	mutex_lock(&dbs_info->cdbs.timer_mutex);
+	mutex_lock(&core_dbs_info->cdbs.timer_mutex);
+	eval_load = need_load_eval(&core_dbs_info->cdbs,
+			od_tuners.sampling_rate);
 
 	/* Common NORMAL_SAMPLE setup */
-	dbs_info->sample_type = OD_NORMAL_SAMPLE;
+	core_dbs_info->sample_type = OD_NORMAL_SAMPLE;
 	if (sample_type == OD_SUB_SAMPLE) {
-		delay = dbs_info->freq_lo_jiffies;
-		__cpufreq_driver_target(dbs_info->cdbs.cur_policy,
-			dbs_info->freq_lo, CPUFREQ_RELATION_H);
+		delay = core_dbs_info->freq_lo_jiffies;
+		if (eval_load)
+			__cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
+						core_dbs_info->freq_lo,
+						CPUFREQ_RELATION_H);
 	} else {
-		dbs_check_cpu(&od_dbs_data, cpu);
-		if (dbs_info->freq_lo) {
+		if (eval_load)
+			dbs_check_cpu(&od_dbs_data, cpu);
+		if (core_dbs_info->freq_lo) {
 			/* Setup timer for SUB_SAMPLE */
-			dbs_info->sample_type = OD_SUB_SAMPLE;
-			delay = dbs_info->freq_hi_jiffies;
+			core_dbs_info->sample_type = OD_SUB_SAMPLE;
+			delay = core_dbs_info->freq_hi_jiffies;
 		} else {
 			delay = delay_for_sampling_rate(od_tuners.sampling_rate
-						* dbs_info->rate_mult);
+						* core_dbs_info->rate_mult);
 		}
 	}
 
-	schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay);
-	mutex_unlock(&dbs_info->cdbs.timer_mutex);
+	schedule_delayed_work_on(smp_processor_id(), dw, delay);
+	mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
 }
 
 /************************** sysfs interface ************************/
@@ -259,7 +267,7 @@
  * update_sampling_rate - update sampling rate effective immediately if needed.
  * @new_rate: new sampling rate
  *
- * If new rate is smaller than the old, simply updaing
+ * If new rate is smaller than the old, simply updating
  * dbs_tuners_int.sampling_rate might not be appropriate. For example, if the
  * original sampling_rate was 1 second and the requested new sampling rate is 10
  * ms because the user needs immediate reaction from ondemand governor, but not
@@ -287,7 +295,7 @@
 			cpufreq_cpu_put(policy);
 			continue;
 		}
-		dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu);
+		dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
 		cpufreq_cpu_put(policy);
 
 		mutex_lock(&dbs_info->cdbs.timer_mutex);
@@ -306,8 +314,7 @@
 			cancel_delayed_work_sync(&dbs_info->cdbs.work);
 			mutex_lock(&dbs_info->cdbs.timer_mutex);
 
-			schedule_delayed_work_on(dbs_info->cdbs.cpu,
-					&dbs_info->cdbs.work,
+			schedule_delayed_work_on(cpu, &dbs_info->cdbs.work,
 					usecs_to_jiffies(new_rate));
 
 		}
@@ -351,6 +358,10 @@
 			input < MIN_FREQUENCY_UP_THRESHOLD) {
 		return -EINVAL;
 	}
+	/* Calculate the new adj_up_threshold */
+	od_tuners.adj_up_threshold += input;
+	od_tuners.adj_up_threshold -= od_tuners.up_threshold;
+
 	od_tuners.up_threshold = input;
 	return count;
 }
@@ -507,7 +518,8 @@
 	if (idle_time != -1ULL) {
 		/* Idle micro accounting is supported. Use finer thresholds */
 		od_tuners.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
-		od_tuners.down_differential = MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
+		od_tuners.adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
+					     MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
 		/*
 		 * In nohz/micro accounting case we set the minimum frequency
 		 * not depending on HZ, but fixed (very low). The deferred
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 9d7732b..2fd779e 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -24,12 +24,6 @@
 
 static spinlock_t cpufreq_stats_lock;
 
-#define CPUFREQ_STATDEVICE_ATTR(_name, _mode, _show) \
-static struct freq_attr _attr_##_name = {\
-	.attr = {.name = __stringify(_name), .mode = _mode, }, \
-	.show = _show,\
-};
-
 struct cpufreq_stats {
 	unsigned int cpu;
 	unsigned int total_trans;
@@ -136,17 +130,17 @@
 		return PAGE_SIZE;
 	return len;
 }
-CPUFREQ_STATDEVICE_ATTR(trans_table, 0444, show_trans_table);
+cpufreq_freq_attr_ro(trans_table);
 #endif
 
-CPUFREQ_STATDEVICE_ATTR(total_trans, 0444, show_total_trans);
-CPUFREQ_STATDEVICE_ATTR(time_in_state, 0444, show_time_in_state);
+cpufreq_freq_attr_ro(total_trans);
+cpufreq_freq_attr_ro(time_in_state);
 
 static struct attribute *default_attrs[] = {
-	&_attr_total_trans.attr,
-	&_attr_time_in_state.attr,
+	&total_trans.attr,
+	&time_in_state.attr,
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
-	&_attr_trans_table.attr,
+	&trans_table.attr,
 #endif
 	NULL
 };
@@ -170,11 +164,13 @@
 static void cpufreq_stats_free_table(unsigned int cpu)
 {
 	struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+
 	if (stat) {
+		pr_debug("%s: Free stat table\n", __func__);
 		kfree(stat->time_in_state);
 		kfree(stat);
+		per_cpu(cpufreq_stats_table, cpu) = NULL;
 	}
-	per_cpu(cpufreq_stats_table, cpu) = NULL;
 }
 
 /* must be called early in the CPU removal sequence (before
@@ -183,8 +179,14 @@
 static void cpufreq_stats_free_sysfs(unsigned int cpu)
 {
 	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-	if (policy && policy->cpu == cpu)
+
+	if (!cpufreq_frequency_get_table(cpu))
+		return;
+
+	if (policy && !policy_is_shared(policy)) {
+		pr_debug("%s: Free sysfs stat\n", __func__);
 		sysfs_remove_group(&policy->kobj, &stats_attr_group);
+	}
 	if (policy)
 		cpufreq_cpu_put(policy);
 }
@@ -262,6 +264,19 @@
 	return ret;
 }
 
+static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
+{
+	struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
+			policy->last_cpu);
+
+	pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
+			policy->cpu, policy->last_cpu);
+	per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
+			policy->last_cpu);
+	per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
+	stat->cpu = policy->cpu;
+}
+
 static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
 		unsigned long val, void *data)
 {
@@ -269,6 +284,12 @@
 	struct cpufreq_policy *policy = data;
 	struct cpufreq_frequency_table *table;
 	unsigned int cpu = policy->cpu;
+
+	if (val == CPUFREQ_UPDATE_POLICY_CPU) {
+		cpufreq_stats_update_policy_cpu(policy);
+		return 0;
+	}
+
 	if (val != CPUFREQ_NOTIFY)
 		return 0;
 	table = cpufreq_frequency_get_table(cpu);
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index c8c3d29..bbeb9c0 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -118,8 +118,6 @@
 
 	switch (event) {
 	case CPUFREQ_GOV_START:
-		if (!cpu_online(cpu))
-			return -EINVAL;
 		BUG_ON(!policy->cur);
 		mutex_lock(&userspace_mutex);
 
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index 4f154bc..79a8486 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -128,9 +128,7 @@
 	policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
 
 	/* policy sharing between dual CPUs */
-	cpumask_copy(policy->cpus, cpu_present_mask);
-
-	policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+	cpumask_setall(policy->cpus);
 
 	return 0;
 }
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 7012ea8..69b676d 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -42,51 +42,56 @@
 	return clk_get_rate(exynos_info->cpu_clk) / 1000;
 }
 
-static int exynos_target(struct cpufreq_policy *policy,
-			  unsigned int target_freq,
-			  unsigned int relation)
+static int exynos_cpufreq_get_index(unsigned int freq)
 {
-	unsigned int index, old_index;
-	unsigned int arm_volt, safe_arm_volt = 0;
-	int ret = 0;
+	struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+	int index;
+
+	for (index = 0;
+		freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
+		if (freq_table[index].frequency == freq)
+			break;
+
+	if (freq_table[index].frequency == CPUFREQ_TABLE_END)
+		return -EINVAL;
+
+	return index;
+}
+
+static int exynos_cpufreq_scale(unsigned int target_freq)
+{
 	struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
 	unsigned int *volt_table = exynos_info->volt_table;
+	struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+	unsigned int arm_volt, safe_arm_volt = 0;
 	unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
-
-	mutex_lock(&cpufreq_lock);
+	int index, old_index;
+	int ret = 0;
 
 	freqs.old = policy->cur;
+	freqs.new = target_freq;
+	freqs.cpu = policy->cpu;
 
-	if (frequency_locked && target_freq != locking_frequency) {
-		ret = -EAGAIN;
+	if (freqs.new == freqs.old)
 		goto out;
-	}
 
 	/*
 	 * The policy max have been changed so that we cannot get proper
 	 * old_index with cpufreq_frequency_table_target(). Thus, ignore
 	 * policy and get the index from the raw freqeuncy table.
 	 */
-	for (old_index = 0;
-		freq_table[old_index].frequency != CPUFREQ_TABLE_END;
-		old_index++)
-		if (freq_table[old_index].frequency == freqs.old)
-			break;
-
-	if (freq_table[old_index].frequency == CPUFREQ_TABLE_END) {
-		ret = -EINVAL;
+	old_index = exynos_cpufreq_get_index(freqs.old);
+	if (old_index < 0) {
+		ret = old_index;
 		goto out;
 	}
 
-	if (cpufreq_frequency_table_target(policy, freq_table,
-					   target_freq, relation, &index)) {
-		ret = -EINVAL;
+	index = exynos_cpufreq_get_index(target_freq);
+	if (index < 0) {
+		ret = index;
 		goto out;
 	}
 
-	freqs.new = freq_table[index].frequency;
-	freqs.cpu = policy->cpu;
-
 	/*
 	 * ARM clock source will be changed APLL to MPLL temporary
 	 * To support this level, need to control regulator for
@@ -106,15 +111,25 @@
 	/* When the new frequency is higher than current frequency */
 	if ((freqs.new > freqs.old) && !safe_arm_volt) {
 		/* Firstly, voltage up to increase frequency */
-		regulator_set_voltage(arm_regulator, arm_volt,
-				arm_volt);
+		ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
+		if (ret) {
+			pr_err("%s: failed to set cpu voltage to %d\n",
+				__func__, arm_volt);
+			goto out;
+		}
 	}
 
-	if (safe_arm_volt)
-		regulator_set_voltage(arm_regulator, safe_arm_volt,
+	if (safe_arm_volt) {
+		ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
 				      safe_arm_volt);
-	if (freqs.new != freqs.old)
-		exynos_info->set_freq(old_index, index);
+		if (ret) {
+			pr_err("%s: failed to set cpu voltage to %d\n",
+				__func__, safe_arm_volt);
+			goto out;
+		}
+	}
+
+	exynos_info->set_freq(old_index, index);
 
 	for_each_cpu(freqs.cpu, policy->cpus)
 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -125,9 +140,45 @@
 		/* down the voltage after frequency change */
 		regulator_set_voltage(arm_regulator, arm_volt,
 				arm_volt);
+		if (ret) {
+			pr_err("%s: failed to set cpu voltage to %d\n",
+				__func__, arm_volt);
+			goto out;
+		}
 	}
 
 out:
+
+	cpufreq_cpu_put(policy);
+
+	return ret;
+}
+
+static int exynos_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq,
+			  unsigned int relation)
+{
+	struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+	unsigned int index;
+	unsigned int new_freq;
+	int ret = 0;
+
+	mutex_lock(&cpufreq_lock);
+
+	if (frequency_locked)
+		goto out;
+
+	if (cpufreq_frequency_table_target(policy, freq_table,
+					   target_freq, relation, &index)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	new_freq = freq_table[index].frequency;
+
+	ret = exynos_cpufreq_scale(new_freq);
+
+out:
 	mutex_unlock(&cpufreq_lock);
 
 	return ret;
@@ -163,51 +214,26 @@
 static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
 				       unsigned long pm_event, void *v)
 {
-	struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
-	static unsigned int saved_frequency;
-	unsigned int temp;
+	int ret;
 
-	mutex_lock(&cpufreq_lock);
 	switch (pm_event) {
 	case PM_SUSPEND_PREPARE:
-		if (frequency_locked)
-			goto out;
-
+		mutex_lock(&cpufreq_lock);
 		frequency_locked = true;
+		mutex_unlock(&cpufreq_lock);
 
-		if (locking_frequency) {
-			saved_frequency = exynos_getspeed(0);
+		ret = exynos_cpufreq_scale(locking_frequency);
+		if (ret < 0)
+			return NOTIFY_BAD;
 
-			mutex_unlock(&cpufreq_lock);
-			exynos_target(policy, locking_frequency,
-				      CPUFREQ_RELATION_H);
-			mutex_lock(&cpufreq_lock);
-		}
 		break;
 
 	case PM_POST_SUSPEND:
-		if (saved_frequency) {
-			/*
-			 * While frequency_locked, only locking_frequency
-			 * is valid for target(). In order to use
-			 * saved_frequency while keeping frequency_locked,
-			 * we temporarly overwrite locking_frequency.
-			 */
-			temp = locking_frequency;
-			locking_frequency = saved_frequency;
-
-			mutex_unlock(&cpufreq_lock);
-			exynos_target(policy, locking_frequency,
-				      CPUFREQ_RELATION_H);
-			mutex_lock(&cpufreq_lock);
-
-			locking_frequency = temp;
-		}
+		mutex_lock(&cpufreq_lock);
 		frequency_locked = false;
+		mutex_unlock(&cpufreq_lock);
 		break;
 	}
-out:
-	mutex_unlock(&cpufreq_lock);
 
 	return NOTIFY_OK;
 }
@@ -222,35 +248,34 @@
 
 	cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
 
-	locking_frequency = exynos_getspeed(0);
-
 	/* set the transition latency value */
 	policy->cpuinfo.transition_latency = 100000;
 
-	/*
-	 * EXYNOS4 multi-core processors has 2 cores
-	 * that the frequency cannot be set independently.
-	 * Each cpu is bound to the same speed.
-	 * So the affected cpu is all of the cpus.
-	 */
-	if (num_online_cpus() == 1) {
-		cpumask_copy(policy->related_cpus, cpu_possible_mask);
-		cpumask_copy(policy->cpus, cpu_online_mask);
-	} else {
-		policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
-		cpumask_setall(policy->cpus);
-	}
+	cpumask_setall(policy->cpus);
 
 	return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
 }
 
+static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static struct freq_attr *exynos_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
 static struct cpufreq_driver exynos_driver = {
 	.flags		= CPUFREQ_STICKY,
 	.verify		= exynos_verify_speed,
 	.target		= exynos_target,
 	.get		= exynos_getspeed,
 	.init		= exynos_cpufreq_cpu_init,
+	.exit		= exynos_cpufreq_cpu_exit,
 	.name		= "exynos_cpufreq",
+	.attr		= exynos_cpufreq_attr,
 #ifdef CONFIG_PM
 	.suspend	= exynos_cpufreq_suspend,
 	.resume		= exynos_cpufreq_resume,
@@ -288,6 +313,8 @@
 		goto err_vdd_arm;
 	}
 
+	locking_frequency = exynos_getspeed(0);
+
 	register_pm_notifier(&exynos_cpufreq_nb);
 
 	if (cpufreq_register_driver(&exynos_driver)) {
@@ -299,8 +326,7 @@
 err_cpufreq:
 	unregister_pm_notifier(&exynos_cpufreq_nb);
 
-	if (!IS_ERR(arm_regulator))
-		regulator_put(arm_regulator);
+	regulator_put(arm_regulator);
 err_vdd_arm:
 	kfree(exynos_info);
 	pr_debug("%s: failed initialization\n", __func__);
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
index fb148fa..de91755 100644
--- a/drivers/cpufreq/exynos4210-cpufreq.c
+++ b/drivers/cpufreq/exynos4210-cpufreq.c
@@ -20,97 +20,37 @@
 #include <mach/regs-clock.h>
 #include <mach/cpufreq.h>
 
-#define CPUFREQ_LEVEL_END	L5
-
-static int max_support_idx = L0;
-static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
-
 static struct clk *cpu_clk;
 static struct clk *moutcore;
 static struct clk *mout_mpll;
 static struct clk *mout_apll;
 
-struct cpufreq_clkdiv {
-	unsigned int index;
-	unsigned int clkdiv;
-};
-
-static unsigned int exynos4210_volt_table[CPUFREQ_LEVEL_END] = {
+static unsigned int exynos4210_volt_table[] = {
 	1250000, 1150000, 1050000, 975000, 950000,
 };
 
-
-static struct cpufreq_clkdiv exynos4210_clkdiv_table[CPUFREQ_LEVEL_END];
-
 static struct cpufreq_frequency_table exynos4210_freq_table[] = {
-	{L0, 1200*1000},
-	{L1, 1000*1000},
-	{L2, 800*1000},
-	{L3, 500*1000},
-	{L4, 200*1000},
+	{L0, 1200 * 1000},
+	{L1, 1000 * 1000},
+	{L2,  800 * 1000},
+	{L3,  500 * 1000},
+	{L4,  200 * 1000},
 	{0, CPUFREQ_TABLE_END},
 };
 
-static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {
+static struct apll_freq apll_freq_4210[] = {
 	/*
-	 * Clock divider value for following
-	 * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
-	 *		DIVATB, DIVPCLK_DBG, DIVAPLL }
+	 * values:
+	 * freq
+	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, RESERVED
+	 * clock divider for COPY, HPM, RESERVED
+	 * PLL M, P, S
 	 */
-
-	/* ARM L0: 1200MHz */
-	{ 0, 3, 7, 3, 4, 1, 7 },
-
-	/* ARM L1: 1000MHz */
-	{ 0, 3, 7, 3, 4, 1, 7 },
-
-	/* ARM L2: 800MHz */
-	{ 0, 3, 7, 3, 3, 1, 7 },
-
-	/* ARM L3: 500MHz */
-	{ 0, 3, 7, 3, 3, 1, 7 },
-
-	/* ARM L4: 200MHz */
-	{ 0, 1, 3, 1, 3, 1, 0 },
-};
-
-static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {
-	/*
-	 * Clock divider value for following
-	 * { DIVCOPY, DIVHPM }
-	 */
-
-	/* ARM L0: 1200MHz */
-	{ 5, 0 },
-
-	/* ARM L1: 1000MHz */
-	{ 4, 0 },
-
-	/* ARM L2: 800MHz */
-	{ 3, 0 },
-
-	/* ARM L3: 500MHz */
-	{ 3, 0 },
-
-	/* ARM L4: 200MHz */
-	{ 3, 0 },
-};
-
-static unsigned int exynos4210_apll_pms_table[CPUFREQ_LEVEL_END] = {
-	/* APLL FOUT L0: 1200MHz */
-	((150 << 16) | (3 << 8) | 1),
-
-	/* APLL FOUT L1: 1000MHz */
-	((250 << 16) | (6 << 8) | 1),
-
-	/* APLL FOUT L2: 800MHz */
-	((200 << 16) | (6 << 8) | 1),
-
-	/* APLL FOUT L3: 500MHz */
-	((250 << 16) | (6 << 8) | 2),
-
-	/* APLL FOUT L4: 200MHz */
-	((200 << 16) | (6 << 8) | 3),
+	APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
+	APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
+	APLL_FREQ(800,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
+	APLL_FREQ(500,  0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
+	APLL_FREQ(200,  0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
 };
 
 static void exynos4210_set_clkdiv(unsigned int div_index)
@@ -119,7 +59,7 @@
 
 	/* Change Divider - CPU0 */
 
-	tmp = exynos4210_clkdiv_table[div_index].clkdiv;
+	tmp = apll_freq_4210[div_index].clk_div_cpu0;
 
 	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
 
@@ -129,12 +69,7 @@
 
 	/* Change Divider - CPU1 */
 
-	tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
-
-	tmp &= ~((0x7 << 4) | 0x7);
-
-	tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
-		(clkdiv_cpu1[div_index][1] << 0));
+	tmp = apll_freq_4210[div_index].clk_div_cpu1;
 
 	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
 
@@ -162,7 +97,7 @@
 	/* 3. Change PLL PMS values */
 	tmp = __raw_readl(EXYNOS4_APLL_CON0);
 	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
-	tmp |= exynos4210_apll_pms_table[index];
+	tmp |= apll_freq_4210[index].mps;
 	__raw_writel(tmp, EXYNOS4_APLL_CON0);
 
 	/* 4. wait_lock_time */
@@ -179,10 +114,10 @@
 	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
 }
 
-bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
+static bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
 {
-	unsigned int old_pm = (exynos4210_apll_pms_table[old_index] >> 8);
-	unsigned int new_pm = (exynos4210_apll_pms_table[new_index] >> 8);
+	unsigned int old_pm = apll_freq_4210[old_index].mps >> 8;
+	unsigned int new_pm = apll_freq_4210[new_index].mps >> 8;
 
 	return (old_pm == new_pm) ? 0 : 1;
 }
@@ -200,7 +135,7 @@
 			/* 2. Change just s value in apll m,p,s value */
 			tmp = __raw_readl(EXYNOS4_APLL_CON0);
 			tmp &= ~(0x7 << 0);
-			tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
+			tmp |= apll_freq_4210[new_index].mps & 0x7;
 			__raw_writel(tmp, EXYNOS4_APLL_CON0);
 		} else {
 			/* Clock Configuration Procedure */
@@ -214,7 +149,7 @@
 			/* 1. Change just s value in apll m,p,s value */
 			tmp = __raw_readl(EXYNOS4_APLL_CON0);
 			tmp &= ~(0x7 << 0);
-			tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
+			tmp |= apll_freq_4210[new_index].mps & 0x7;
 			__raw_writel(tmp, EXYNOS4_APLL_CON0);
 
 			/* 2. Change the system clock divider values */
@@ -231,8 +166,6 @@
 
 int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
 {
-	int i;
-	unsigned int tmp;
 	unsigned long rate;
 
 	cpu_clk = clk_get(NULL, "armclk");
@@ -253,33 +186,9 @@
 	if (IS_ERR(mout_apll))
 		goto err_mout_apll;
 
-	tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
-
-	for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
-		tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
-			EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
-			EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
-			EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
-			EXYNOS4_CLKDIV_CPU0_ATB_MASK |
-			EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
-			EXYNOS4_CLKDIV_CPU0_APLL_MASK);
-
-		tmp |= ((clkdiv_cpu0[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
-			(clkdiv_cpu0[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
-			(clkdiv_cpu0[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
-			(clkdiv_cpu0[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
-			(clkdiv_cpu0[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
-			(clkdiv_cpu0[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
-			(clkdiv_cpu0[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
-
-		exynos4210_clkdiv_table[i].clkdiv = tmp;
-	}
-
 	info->mpll_freq_khz = rate;
-	info->pm_lock_idx = L2;
+	/* 800Mhz */
 	info->pll_safe_idx = L2;
-	info->max_support_idx = max_support_idx;
-	info->min_support_idx = min_support_idx;
 	info->cpu_clk = cpu_clk;
 	info->volt_table = exynos4210_volt_table;
 	info->freq_table = exynos4210_freq_table;
@@ -289,14 +198,11 @@
 	return 0;
 
 err_mout_apll:
-	if (!IS_ERR(mout_mpll))
-		clk_put(mout_mpll);
+	clk_put(mout_mpll);
 err_mout_mpll:
-	if (!IS_ERR(moutcore))
-		clk_put(moutcore);
+	clk_put(moutcore);
 err_moutcore:
-	if (!IS_ERR(cpu_clk))
-		clk_put(cpu_clk);
+	clk_put(cpu_clk);
 
 	pr_debug("%s: failed initialization\n", __func__);
 	return -EINVAL;
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index 8c5a7af..0661039 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -20,26 +20,18 @@
 #include <mach/regs-clock.h>
 #include <mach/cpufreq.h>
 
-#define CPUFREQ_LEVEL_END	(L13 + 1)
-
-static int max_support_idx;
-static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
-
 static struct clk *cpu_clk;
 static struct clk *moutcore;
 static struct clk *mout_mpll;
 static struct clk *mout_apll;
 
-struct cpufreq_clkdiv {
-	unsigned int	index;
-	unsigned int	clkdiv;
-	unsigned int	clkdiv1;
+static unsigned int exynos4x12_volt_table[] = {
+	1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
+	1000000,  987500,  975000,  950000,  925000,  900000,  900000
 };
 
-static unsigned int exynos4x12_volt_table[CPUFREQ_LEVEL_END];
-
 static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
-	{L0, 1500 * 1000},
+	{L0, CPUFREQ_ENTRY_INVALID},
 	{L1, 1400 * 1000},
 	{L2, 1300 * 1000},
 	{L3, 1200 * 1000},
@@ -56,247 +48,54 @@
 	{0, CPUFREQ_TABLE_END},
 };
 
-static struct cpufreq_clkdiv exynos4x12_clkdiv_table[CPUFREQ_LEVEL_END];
+static struct apll_freq *apll_freq_4x12;
 
-static unsigned int clkdiv_cpu0_4212[CPUFREQ_LEVEL_END][8] = {
+static struct apll_freq apll_freq_4212[] = {
 	/*
-	 * Clock divider value for following
-	 * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
-	 *		DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+	 * values:
+	 * freq
+	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
+	 * clock divider for COPY, HPM, RESERVED
+	 * PLL M, P, S
 	 */
-	/* ARM L0: 1500 MHz */
-	{ 0, 3, 7, 0, 6, 1, 2, 0 },
-
-	/* ARM L1: 1400 MHz */
-	{ 0, 3, 7, 0, 6, 1, 2, 0 },
-
-	/* ARM L2: 1300 MHz */
-	{ 0, 3, 7, 0, 5, 1, 2, 0 },
-
-	/* ARM L3: 1200 MHz */
-	{ 0, 3, 7, 0, 5, 1, 2, 0 },
-
-	/* ARM L4: 1100 MHz */
-	{ 0, 3, 6, 0, 4, 1, 2, 0 },
-
-	/* ARM L5: 1000 MHz */
-	{ 0, 2, 5, 0, 4, 1, 1, 0 },
-
-	/* ARM L6: 900 MHz */
-	{ 0, 2, 5, 0, 3, 1, 1, 0 },
-
-	/* ARM L7: 800 MHz */
-	{ 0, 2, 5, 0, 3, 1, 1, 0 },
-
-	/* ARM L8: 700 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L9: 600 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L10: 500 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L11: 400 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L12: 300 MHz */
-	{ 0, 2, 4, 0, 2, 1, 1, 0 },
-
-	/* ARM L13: 200 MHz */
-	{ 0, 1, 3, 0, 1, 1, 1, 0 },
+	APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
+	APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
+	APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
+	APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
+	APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
+	APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
+	APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
+	APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
+	APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
+	APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
+	APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
+	APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
+	APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
+	APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
 };
 
-static unsigned int clkdiv_cpu0_4412[CPUFREQ_LEVEL_END][8] = {
+static struct apll_freq apll_freq_4412[] = {
 	/*
-	 * Clock divider value for following
-	 * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
-	 *		DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+	 * values:
+	 * freq
+	 * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
+	 * clock divider for COPY, HPM, CORES
+	 * PLL M, P, S
 	 */
-	/* ARM L0: 1500 MHz */
-	{ 0, 3, 7, 0, 6, 1, 2, 0 },
-
-	/* ARM L1: 1400 MHz */
-	{ 0, 3, 7, 0, 6, 1, 2, 0 },
-
-	/* ARM L2: 1300 MHz */
-	{ 0, 3, 7, 0, 5, 1, 2, 0 },
-
-	/* ARM L3: 1200 MHz */
-	{ 0, 3, 7, 0, 5, 1, 2, 0 },
-
-	/* ARM L4: 1100 MHz */
-	{ 0, 3, 6, 0, 4, 1, 2, 0 },
-
-	/* ARM L5: 1000 MHz */
-	{ 0, 2, 5, 0, 4, 1, 1, 0 },
-
-	/* ARM L6: 900 MHz */
-	{ 0, 2, 5, 0, 3, 1, 1, 0 },
-
-	/* ARM L7: 800 MHz */
-	{ 0, 2, 5, 0, 3, 1, 1, 0 },
-
-	/* ARM L8: 700 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L9: 600 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L10: 500 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L11: 400 MHz */
-	{ 0, 2, 4, 0, 3, 1, 1, 0 },
-
-	/* ARM L12: 300 MHz */
-	{ 0, 2, 4, 0, 2, 1, 1, 0 },
-
-	/* ARM L13: 200 MHz */
-	{ 0, 1, 3, 0, 1, 1, 1, 0 },
-};
-
-static unsigned int clkdiv_cpu1_4212[CPUFREQ_LEVEL_END][2] = {
-	/* Clock divider value for following
-	 * { DIVCOPY, DIVHPM }
-	 */
-	/* ARM L0: 1500 MHz */
-	{ 6, 0 },
-
-	/* ARM L1: 1400 MHz */
-	{ 6, 0 },
-
-	/* ARM L2: 1300 MHz */
-	{ 5, 0 },
-
-	/* ARM L3: 1200 MHz */
-	{ 5, 0 },
-
-	/* ARM L4: 1100 MHz */
-	{ 4, 0 },
-
-	/* ARM L5: 1000 MHz */
-	{ 4, 0 },
-
-	/* ARM L6: 900 MHz */
-	{ 3, 0 },
-
-	/* ARM L7: 800 MHz */
-	{ 3, 0 },
-
-	/* ARM L8: 700 MHz */
-	{ 3, 0 },
-
-	/* ARM L9: 600 MHz */
-	{ 3, 0 },
-
-	/* ARM L10: 500 MHz */
-	{ 3, 0 },
-
-	/* ARM L11: 400 MHz */
-	{ 3, 0 },
-
-	/* ARM L12: 300 MHz */
-	{ 3, 0 },
-
-	/* ARM L13: 200 MHz */
-	{ 3, 0 },
-};
-
-static unsigned int clkdiv_cpu1_4412[CPUFREQ_LEVEL_END][3] = {
-	/* Clock divider value for following
-	 * { DIVCOPY, DIVHPM, DIVCORES }
-	 */
-	/* ARM L0: 1500 MHz */
-	{ 6, 0, 7 },
-
-	/* ARM L1: 1400 MHz */
-	{ 6, 0, 6 },
-
-	/* ARM L2: 1300 MHz */
-	{ 5, 0, 6 },
-
-	/* ARM L3: 1200 MHz */
-	{ 5, 0, 5 },
-
-	/* ARM L4: 1100 MHz */
-	{ 4, 0, 5 },
-
-	/* ARM L5: 1000 MHz */
-	{ 4, 0, 4 },
-
-	/* ARM L6: 900 MHz */
-	{ 3, 0, 4 },
-
-	/* ARM L7: 800 MHz */
-	{ 3, 0, 3 },
-
-	/* ARM L8: 700 MHz */
-	{ 3, 0, 3 },
-
-	/* ARM L9: 600 MHz */
-	{ 3, 0, 2 },
-
-	/* ARM L10: 500 MHz */
-	{ 3, 0, 2 },
-
-	/* ARM L11: 400 MHz */
-	{ 3, 0, 1 },
-
-	/* ARM L12: 300 MHz */
-	{ 3, 0, 1 },
-
-	/* ARM L13: 200 MHz */
-	{ 3, 0, 0 },
-};
-
-static unsigned int exynos4x12_apll_pms_table[CPUFREQ_LEVEL_END] = {
-	/* APLL FOUT L0: 1500 MHz */
-	((250 << 16) | (4 << 8) | (0x0)),
-
-	/* APLL FOUT L1: 1400 MHz */
-	((175 << 16) | (3 << 8) | (0x0)),
-
-	/* APLL FOUT L2: 1300 MHz */
-	((325 << 16) | (6 << 8) | (0x0)),
-
-	/* APLL FOUT L3: 1200 MHz */
-	((200 << 16) | (4 << 8) | (0x0)),
-
-	/* APLL FOUT L4: 1100 MHz */
-	((275 << 16) | (6 << 8) | (0x0)),
-
-	/* APLL FOUT L5: 1000 MHz */
-	((125 << 16) | (3 << 8) | (0x0)),
-
-	/* APLL FOUT L6: 900 MHz */
-	((150 << 16) | (4 << 8) | (0x0)),
-
-	/* APLL FOUT L7: 800 MHz */
-	((100 << 16) | (3 << 8) | (0x0)),
-
-	/* APLL FOUT L8: 700 MHz */
-	((175 << 16) | (3 << 8) | (0x1)),
-
-	/* APLL FOUT L9: 600 MHz */
-	((200 << 16) | (4 << 8) | (0x1)),
-
-	/* APLL FOUT L10: 500 MHz */
-	((125 << 16) | (3 << 8) | (0x1)),
-
-	/* APLL FOUT L11 400 MHz */
-	((100 << 16) | (3 << 8) | (0x1)),
-
-	/* APLL FOUT L12: 300 MHz */
-	((200 << 16) | (4 << 8) | (0x2)),
-
-	/* APLL FOUT L13: 200 MHz */
-	((100 << 16) | (3 << 8) | (0x2)),
-};
-
-static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = {
-	1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
-	1000000,  987500,  975000,  950000,  925000,  900000,  900000
+	APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
+	APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
+	APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
+	APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
+	APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
+	APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
+	APLL_FREQ(900,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
+	APLL_FREQ(800,  0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
+	APLL_FREQ(700,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
+	APLL_FREQ(600,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
+	APLL_FREQ(500,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
+	APLL_FREQ(400,  0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
+	APLL_FREQ(300,  0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
+	APLL_FREQ(200,  0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
 };
 
 static void exynos4x12_set_clkdiv(unsigned int div_index)
@@ -306,7 +105,7 @@
 
 	/* Change Divider - CPU0 */
 
-	tmp = exynos4x12_clkdiv_table[div_index].clkdiv;
+	tmp = apll_freq_4x12[div_index].clk_div_cpu0;
 
 	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
 
@@ -314,7 +113,7 @@
 		cpu_relax();
 
 	/* Change Divider - CPU1 */
-	tmp = exynos4x12_clkdiv_table[div_index].clkdiv1;
+	tmp = apll_freq_4x12[div_index].clk_div_cpu1;
 
 	__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
 	if (soc_is_exynos4212())
@@ -341,14 +140,14 @@
 	} while (tmp != 0x2);
 
 	/* 2. Set APLL Lock time */
-	pdiv = ((exynos4x12_apll_pms_table[index] >> 8) & 0x3f);
+	pdiv = ((apll_freq_4x12[index].mps >> 8) & 0x3f);
 
 	__raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK);
 
 	/* 3. Change PLL PMS values */
 	tmp = __raw_readl(EXYNOS4_APLL_CON0);
 	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
-	tmp |= exynos4x12_apll_pms_table[index];
+	tmp |= apll_freq_4x12[index].mps;
 	__raw_writel(tmp, EXYNOS4_APLL_CON0);
 
 	/* 4. wait_lock_time */
@@ -367,10 +166,10 @@
 	} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
 }
 
-bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
+static bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
 {
-	unsigned int old_pm = exynos4x12_apll_pms_table[old_index] >> 8;
-	unsigned int new_pm = exynos4x12_apll_pms_table[new_index] >> 8;
+	unsigned int old_pm = apll_freq_4x12[old_index].mps >> 8;
+	unsigned int new_pm = apll_freq_4x12[new_index].mps >> 8;
 
 	return (old_pm == new_pm) ? 0 : 1;
 }
@@ -387,7 +186,7 @@
 			/* 2. Change just s value in apll m,p,s value */
 			tmp = __raw_readl(EXYNOS4_APLL_CON0);
 			tmp &= ~(0x7 << 0);
-			tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+			tmp |= apll_freq_4x12[new_index].mps & 0x7;
 			__raw_writel(tmp, EXYNOS4_APLL_CON0);
 
 		} else {
@@ -402,7 +201,7 @@
 			/* 1. Change just s value in apll m,p,s value */
 			tmp = __raw_readl(EXYNOS4_APLL_CON0);
 			tmp &= ~(0x7 << 0);
-			tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+			tmp |= apll_freq_4x12[new_index].mps & 0x7;
 			__raw_writel(tmp, EXYNOS4_APLL_CON0);
 			/* 2. Change the system clock divider values */
 			exynos4x12_set_clkdiv(new_index);
@@ -416,27 +215,10 @@
 	}
 }
 
-static void __init set_volt_table(void)
-{
-	unsigned int i;
-
-	max_support_idx = L1;
-
-	/* Not supported */
-	exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
-
-	for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
-		exynos4x12_volt_table[i] = asv_voltage_4x12[i];
-}
-
 int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
 {
-	int i;
-	unsigned int tmp;
 	unsigned long rate;
 
-	set_volt_table();
-
 	cpu_clk = clk_get(NULL, "armclk");
 	if (IS_ERR(cpu_clk))
 		return PTR_ERR(cpu_clk);
@@ -455,66 +237,14 @@
 	if (IS_ERR(mout_apll))
 		goto err_mout_apll;
 
-	for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
-
-		exynos4x12_clkdiv_table[i].index = i;
-
-		tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
-
-		tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
-			EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
-			EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
-			EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
-			EXYNOS4_CLKDIV_CPU0_ATB_MASK |
-			EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
-			EXYNOS4_CLKDIV_CPU0_APLL_MASK);
-
-		if (soc_is_exynos4212()) {
-			tmp |= ((clkdiv_cpu0_4212[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
-				(clkdiv_cpu0_4212[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
-				(clkdiv_cpu0_4212[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
-				(clkdiv_cpu0_4212[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
-				(clkdiv_cpu0_4212[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
-				(clkdiv_cpu0_4212[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
-				(clkdiv_cpu0_4212[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
-		} else {
-			tmp &= ~EXYNOS4_CLKDIV_CPU0_CORE2_MASK;
-
-			tmp |= ((clkdiv_cpu0_4412[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
-				(clkdiv_cpu0_4412[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
-				(clkdiv_cpu0_4412[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
-				(clkdiv_cpu0_4412[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
-				(clkdiv_cpu0_4412[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
-				(clkdiv_cpu0_4412[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
-				(clkdiv_cpu0_4412[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT) |
-				(clkdiv_cpu0_4412[i][7] << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT));
-		}
-
-		exynos4x12_clkdiv_table[i].clkdiv = tmp;
-
-		tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
-
-		if (soc_is_exynos4212()) {
-			tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
-				EXYNOS4_CLKDIV_CPU1_HPM_MASK);
-			tmp |= ((clkdiv_cpu1_4212[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
-				(clkdiv_cpu1_4212[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT));
-		} else {
-			tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
-				EXYNOS4_CLKDIV_CPU1_HPM_MASK |
-				EXYNOS4_CLKDIV_CPU1_CORES_MASK);
-			tmp |= ((clkdiv_cpu1_4412[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
-				(clkdiv_cpu1_4412[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT) |
-				(clkdiv_cpu1_4412[i][2] << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT));
-		}
-		exynos4x12_clkdiv_table[i].clkdiv1 = tmp;
-	}
+	if (soc_is_exynos4212())
+		apll_freq_4x12 = apll_freq_4212;
+	else
+		apll_freq_4x12 = apll_freq_4412;
 
 	info->mpll_freq_khz = rate;
-	info->pm_lock_idx = L5;
+	/* 800Mhz */
 	info->pll_safe_idx = L7;
-	info->max_support_idx = max_support_idx;
-	info->min_support_idx = min_support_idx;
 	info->cpu_clk = cpu_clk;
 	info->volt_table = exynos4x12_volt_table;
 	info->freq_table = exynos4x12_freq_table;
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
index e64c253..b934486 100644
--- a/drivers/cpufreq/exynos5250-cpufreq.c
+++ b/drivers/cpufreq/exynos5250-cpufreq.c
@@ -21,23 +21,18 @@
 #include <mach/regs-clock.h>
 #include <mach/cpufreq.h>
 
-#define CPUFREQ_LEVEL_END	(L15 + 1)
-
-static int max_support_idx;
-static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
 static struct clk *cpu_clk;
 static struct clk *moutcore;
 static struct clk *mout_mpll;
 static struct clk *mout_apll;
 
-struct cpufreq_clkdiv {
-	unsigned int	index;
-	unsigned int	clkdiv;
-	unsigned int	clkdiv1;
+static unsigned int exynos5250_volt_table[] = {
+	1300000, 1250000, 1225000, 1200000, 1150000,
+	1125000, 1100000, 1075000, 1050000, 1025000,
+	1012500, 1000000,  975000,  950000,  937500,
+	925000
 };
 
-static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
-
 static struct cpufreq_frequency_table exynos5250_freq_table[] = {
 	{L0, 1700 * 1000},
 	{L1, 1600 * 1000},
@@ -47,8 +42,8 @@
 	{L5, 1200 * 1000},
 	{L6, 1100 * 1000},
 	{L7, 1000 * 1000},
-	{L8, 900 * 1000},
-	{L9, 800 * 1000},
+	{L8,  900 * 1000},
+	{L9,  800 * 1000},
 	{L10, 700 * 1000},
 	{L11, 600 * 1000},
 	{L12, 500 * 1000},
@@ -58,78 +53,30 @@
 	{0, CPUFREQ_TABLE_END},
 };
 
-static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
-
-static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
+static struct apll_freq apll_freq_5250[] = {
 	/*
-	 * Clock divider value for following
-	 * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
+	 * values:
+	 * freq
+	 * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2
+	 * clock divider for COPY, HPM, RESERVED
+	 * PLL M, P, S
 	 */
-	{ 0, 3, 7, 7, 7, 3, 5, 0 },	/* 1700 MHz */
-	{ 0, 3, 7, 7, 7, 1, 4, 0 },	/* 1600 MHz */
-	{ 0, 2, 7, 7, 7, 1, 4, 0 },	/* 1500 MHz */
-	{ 0, 2, 7, 7, 6, 1, 4, 0 },	/* 1400 MHz */
-	{ 0, 2, 7, 7, 6, 1, 3, 0 },	/* 1300 MHz */
-	{ 0, 2, 7, 7, 5, 1, 3, 0 },	/* 1200 MHz */
-	{ 0, 3, 7, 7, 5, 1, 3, 0 },	/* 1100 MHz */
-	{ 0, 1, 7, 7, 4, 1, 2, 0 },	/* 1000 MHz */
-	{ 0, 1, 7, 7, 4, 1, 2, 0 },	/* 900 MHz */
-	{ 0, 1, 7, 7, 4, 1, 2, 0 },	/* 800 MHz */
-	{ 0, 1, 7, 7, 3, 1, 1, 0 },	/* 700 MHz */
-	{ 0, 1, 7, 7, 3, 1, 1, 0 },	/* 600 MHz */
-	{ 0, 1, 7, 7, 2, 1, 1, 0 },	/* 500 MHz */
-	{ 0, 1, 7, 7, 2, 1, 1, 0 },	/* 400 MHz */
-	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 300 MHz */
-	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 200 MHz */
-};
-
-static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
-	/* Clock divider value for following
-	 * { COPY, HPM }
-	 */
-	{ 0, 2 },	/* 1700 MHz */
-	{ 0, 2 },	/* 1600 MHz */
-	{ 0, 2 },	/* 1500 MHz */
-	{ 0, 2 },	/* 1400 MHz */
-	{ 0, 2 },	/* 1300 MHz */
-	{ 0, 2 },	/* 1200 MHz */
-	{ 0, 2 },	/* 1100 MHz */
-	{ 0, 2 },	/* 1000 MHz */
-	{ 0, 2 },	/* 900 MHz */
-	{ 0, 2 },	/* 800 MHz */
-	{ 0, 2 },	/* 700 MHz */
-	{ 0, 2 },	/* 600 MHz */
-	{ 0, 2 },	/* 500 MHz */
-	{ 0, 2 },	/* 400 MHz */
-	{ 0, 2 },	/* 300 MHz */
-	{ 0, 2 },	/* 200 MHz */
-};
-
-static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
-	((425 << 16) | (6 << 8) | 0),	/* 1700 MHz */
-	((200 << 16) | (3 << 8) | 0),	/* 1600 MHz */
-	((250 << 16) | (4 << 8) | 0),	/* 1500 MHz */
-	((175 << 16) | (3 << 8) | 0),	/* 1400 MHz */
-	((325 << 16) | (6 << 8) | 0),	/* 1300 MHz */
-	((200 << 16) | (4 << 8) | 0),	/* 1200 MHz */
-	((275 << 16) | (6 << 8) | 0),	/* 1100 MHz */
-	((125 << 16) | (3 << 8) | 0),	/* 1000 MHz */
-	((150 << 16) | (4 << 8) | 0),	/* 900 MHz */
-	((100 << 16) | (3 << 8) | 0),	/* 800 MHz */
-	((175 << 16) | (3 << 8) | 1),	/* 700 MHz */
-	((200 << 16) | (4 << 8) | 1),	/* 600 MHz */
-	((125 << 16) | (3 << 8) | 1),	/* 500 MHz */
-	((100 << 16) | (3 << 8) | 1),	/* 400 MHz */
-	((200 << 16) | (4 << 8) | 2),	/* 300 MHz */
-	((100 << 16) | (3 << 8) | 2),	/* 200 MHz */
-};
-
-/* ASV group voltage table */
-static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
-	1300000, 1250000, 1225000, 1200000, 1150000,
-	1125000, 1100000, 1075000, 1050000, 1025000,
-	1012500, 1000000,  975000,  950000,  937500,
-	925000
+	APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
+	APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
+	APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
+	APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
+	APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
+	APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
+	APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
+	APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
+	APLL_FREQ(900,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
+	APLL_FREQ(800,  0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
+	APLL_FREQ(700,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
+	APLL_FREQ(600,  0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
+	APLL_FREQ(500,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
+	APLL_FREQ(400,  0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
+	APLL_FREQ(300,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
+	APLL_FREQ(200,  0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
 };
 
 static void set_clkdiv(unsigned int div_index)
@@ -138,7 +85,7 @@
 
 	/* Change Divider - CPU0 */
 
-	tmp = exynos5250_clkdiv_table[div_index].clkdiv;
+	tmp = apll_freq_5250[div_index].clk_div_cpu0;
 
 	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
 
@@ -146,7 +93,7 @@
 		cpu_relax();
 
 	/* Change Divider - CPU1 */
-	tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
+	tmp = apll_freq_5250[div_index].clk_div_cpu1;
 
 	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
 
@@ -169,14 +116,14 @@
 	} while (tmp != 0x2);
 
 	/* 2. Set APLL Lock time */
-	pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
+	pdiv = ((apll_freq_5250[new_index].mps >> 8) & 0x3f);
 
 	__raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
 
 	/* 3. Change PLL PMS values */
 	tmp = __raw_readl(EXYNOS5_APLL_CON0);
 	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
-	tmp |= exynos5_apll_pms_table[new_index];
+	tmp |= apll_freq_5250[new_index].mps;
 	__raw_writel(tmp, EXYNOS5_APLL_CON0);
 
 	/* 4. wait_lock_time */
@@ -196,10 +143,10 @@
 
 }
 
-bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
+static bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
 {
-	unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
-	unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
+	unsigned int old_pm = apll_freq_5250[old_index].mps >> 8;
+	unsigned int new_pm = apll_freq_5250[new_index].mps >> 8;
 
 	return (old_pm == new_pm) ? 0 : 1;
 }
@@ -216,7 +163,7 @@
 			/* 2. Change just s value in apll m,p,s value */
 			tmp = __raw_readl(EXYNOS5_APLL_CON0);
 			tmp &= ~(0x7 << 0);
-			tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+			tmp |= apll_freq_5250[new_index].mps & 0x7;
 			__raw_writel(tmp, EXYNOS5_APLL_CON0);
 
 		} else {
@@ -231,7 +178,7 @@
 			/* 1. Change just s value in apll m,p,s value */
 			tmp = __raw_readl(EXYNOS5_APLL_CON0);
 			tmp &= ~(0x7 << 0);
-			tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+			tmp |= apll_freq_5250[new_index].mps & 0x7;
 			__raw_writel(tmp, EXYNOS5_APLL_CON0);
 			/* 2. Change the system clock divider values */
 			set_clkdiv(new_index);
@@ -245,24 +192,10 @@
 	}
 }
 
-static void __init set_volt_table(void)
-{
-	unsigned int i;
-
-	max_support_idx = L0;
-
-	for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
-		exynos5250_volt_table[i] = asv_voltage_5250[i];
-}
-
 int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
 {
-	int i;
-	unsigned int tmp;
 	unsigned long rate;
 
-	set_volt_table();
-
 	cpu_clk = clk_get(NULL, "armclk");
 	if (IS_ERR(cpu_clk))
 		return PTR_ERR(cpu_clk);
@@ -281,44 +214,9 @@
 	if (IS_ERR(mout_apll))
 		goto err_mout_apll;
 
-	for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
-
-		exynos5250_clkdiv_table[i].index = i;
-
-		tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
-
-		tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
-			(0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
-			(0x7 << 24) | (0x7 << 28));
-
-		tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
-			(clkdiv_cpu0_5250[i][1] << 4) |
-			(clkdiv_cpu0_5250[i][2] << 8) |
-			(clkdiv_cpu0_5250[i][3] << 12) |
-			(clkdiv_cpu0_5250[i][4] << 16) |
-			(clkdiv_cpu0_5250[i][5] << 20) |
-			(clkdiv_cpu0_5250[i][6] << 24) |
-			(clkdiv_cpu0_5250[i][7] << 28));
-
-		exynos5250_clkdiv_table[i].clkdiv = tmp;
-
-		tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
-
-		tmp &= ~((0x7 << 0) | (0x7 << 4));
-
-		tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
-			(clkdiv_cpu1_5250[i][1] << 4));
-
-		exynos5250_clkdiv_table[i].clkdiv1 = tmp;
-	}
-
 	info->mpll_freq_khz = rate;
-	/* 1000Mhz */
-	info->pm_lock_idx = L7;
 	/* 800Mhz */
 	info->pll_safe_idx = L9;
-	info->max_support_idx = max_support_idx;
-	info->min_support_idx = min_support_idx;
 	info->cpu_clk = cpu_clk;
 	info->volt_table = exynos5250_volt_table;
 	info->freq_table = exynos5250_freq_table;
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 49cda25..d7a7966 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -63,9 +63,6 @@
 	pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
 					policy->min, policy->max, policy->cpu);
 
-	if (!cpu_online(policy->cpu))
-		return -EINVAL;
-
 	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
 				     policy->cpuinfo.max_freq);
 
@@ -121,9 +118,6 @@
 		break;
 	}
 
-	if (!cpu_online(policy->cpu))
-		return -EINVAL;
-
 	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
 		unsigned int freq = table[i].frequency;
 		if (freq == CPUFREQ_ENTRY_INVALID)
@@ -227,6 +221,15 @@
 }
 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
 
+void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy)
+{
+	pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n",
+			policy->cpu, policy->last_cpu);
+	per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table,
+			policy->last_cpu);
+	per_cpu(cpufreq_show_table, policy->last_cpu) = NULL;
+}
+
 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
 {
 	return per_cpu(cpufreq_show_table, cpu);
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..66e3a71
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * 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 driver provides the clk notifier callbacks that are used when
+ * the cpufreq-cpu0 driver changes to frequency to alert the highbank
+ * EnergyCore Management Engine (ECME) about the need to change
+ * voltage. The ECME interfaces with the actual voltage regulators.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+#include <linux/platform_device.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE	0x80000001
+#define HB_CPUFREQ_IPC_LEN	7
+#define HB_CPUFREQ_VOLT_RETRIES	15
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[HB_CPUFREQ_IPC_LEN];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < HB_CPUFREQ_IPC_LEN; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb,
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	} else if (action == POST_RATE_CHANGE) {
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+	struct platform_device_info devinfo = { .name = "cpufreq-cpu0", };
+	struct device *cpu_dev;
+	struct clk *cpu_clk;
+	struct device_node *np;
+	int ret;
+
+	if (!of_machine_is_compatible("calxeda,highbank"))
+		return -ENODEV;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np)
+		if (of_get_property(np, "operating-points", NULL))
+			break;
+
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+	/* Instantiate cpufreq-cpu0 */
+	platform_device_register_full(&devinfo);
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+module_init(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
new file mode 100644
index 0000000..d6b6ef3
--- /dev/null
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * 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 <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define PU_SOC_VOLTAGE_NORMAL	1250000
+#define PU_SOC_VOLTAGE_HIGH	1275000
+#define FREQ_1P2_GHZ		1200000000
+
+static struct regulator *arm_reg;
+static struct regulator *pu_reg;
+static struct regulator *soc_reg;
+
+static struct clk *arm_clk;
+static struct clk *pll1_sys_clk;
+static struct clk *pll1_sw_clk;
+static struct clk *step_clk;
+static struct clk *pll2_pfd2_396m_clk;
+
+static struct device *cpu_dev;
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int transition_latency;
+
+static int imx6q_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int imx6q_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(arm_clk) / 1000;
+}
+
+static int imx6q_set_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	struct opp *opp;
+	unsigned long freq_hz, volt, volt_old;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		dev_err(cpu_dev, "failed to match target frequency %d: %d\n",
+			target_freq, ret);
+		return ret;
+	}
+
+	freqs.new = freq_table[index].frequency;
+	freq_hz = freqs.new * 1000;
+	freqs.old = clk_get_rate(arm_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	rcu_read_lock();
+	opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
+	if (IS_ERR(opp)) {
+		rcu_read_unlock();
+		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+		return PTR_ERR(opp);
+	}
+
+	volt = opp_get_voltage(opp);
+	rcu_read_unlock();
+	volt_old = regulator_get_voltage(arm_reg);
+
+	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
+		freqs.old / 1000, volt_old / 1000,
+		freqs.new / 1000, volt / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+		if (ret) {
+			dev_err(cpu_dev,
+				"failed to scale vddarm up: %d\n", ret);
+			return ret;
+		}
+
+		/*
+		 * Need to increase vddpu and vddsoc for safety
+		 * if we are about to run at 1.2 GHz.
+		 */
+		if (freqs.new == FREQ_1P2_GHZ / 1000) {
+			regulator_set_voltage_tol(pu_reg,
+					PU_SOC_VOLTAGE_HIGH, 0);
+			regulator_set_voltage_tol(soc_reg,
+					PU_SOC_VOLTAGE_HIGH, 0);
+		}
+	}
+
+	/*
+	 * The setpoints are selected per PLL/PDF frequencies, so we need to
+	 * reprogram PLL for frequency scaling.  The procedure of reprogramming
+	 * PLL1 is as below.
+	 *
+	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
+	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
+	 *  - Disable pll2_pfd2_396m_clk
+	 */
+	clk_prepare_enable(pll2_pfd2_396m_clk);
+	clk_set_parent(step_clk, pll2_pfd2_396m_clk);
+	clk_set_parent(pll1_sw_clk, step_clk);
+	if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
+		clk_set_rate(pll1_sys_clk, freqs.new * 1000);
+		/*
+		 * If we are leaving 396 MHz set-point, we need to enable
+		 * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
+		 * their use count correct.
+		 */
+		if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
+			clk_prepare_enable(pll1_sys_clk);
+			clk_disable_unprepare(pll2_pfd2_396m_clk);
+		}
+		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+		clk_disable_unprepare(pll2_pfd2_396m_clk);
+	} else {
+		/*
+		 * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
+		 * to provide the frequency.
+		 */
+		clk_disable_unprepare(pll1_sys_clk);
+	}
+
+	/* Ensure the arm clock divider is what we expect */
+	ret = clk_set_rate(arm_clk, freqs.new * 1000);
+	if (ret) {
+		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
+		regulator_set_voltage_tol(arm_reg, volt_old, 0);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+		if (ret)
+			dev_warn(cpu_dev,
+				 "failed to scale vddarm down: %d\n", ret);
+
+		if (freqs.old == FREQ_1P2_GHZ / 1000) {
+			regulator_set_voltage_tol(pu_reg,
+					PU_SOC_VOLTAGE_NORMAL, 0);
+			regulator_set_voltage_tol(soc_reg,
+					PU_SOC_VOLTAGE_NORMAL, 0);
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		dev_err(cpu_dev, "invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(arm_clk) / 1000;
+	cpumask_setall(policy->cpus);
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int imx6q_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static struct freq_attr *imx6q_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver imx6q_cpufreq_driver = {
+	.verify = imx6q_verify_speed,
+	.target = imx6q_set_target,
+	.get = imx6q_get_speed,
+	.init = imx6q_cpufreq_init,
+	.exit = imx6q_cpufreq_exit,
+	.name = "imx6q-cpufreq",
+	.attr = imx6q_cpufreq_attr,
+};
+
+static int imx6q_cpufreq_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	struct opp *opp;
+	unsigned long min_volt, max_volt;
+	int num, ret;
+
+	cpu_dev = &pdev->dev;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		dev_err(cpu_dev, "failed to find cpu0 node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev->of_node = np;
+
+	arm_clk = devm_clk_get(cpu_dev, "arm");
+	pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys");
+	pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw");
+	step_clk = devm_clk_get(cpu_dev, "step");
+	pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m");
+	if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
+	    IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
+		dev_err(cpu_dev, "failed to get clocks\n");
+		ret = -ENOENT;
+		goto put_node;
+	}
+
+	arm_reg = devm_regulator_get(cpu_dev, "arm");
+	pu_reg = devm_regulator_get(cpu_dev, "pu");
+	soc_reg = devm_regulator_get(cpu_dev, "soc");
+	if (!arm_reg || !pu_reg || !soc_reg) {
+		dev_err(cpu_dev, "failed to get regulators\n");
+		ret = -ENOENT;
+		goto put_node;
+	}
+
+	/* We expect an OPP table supplied by platform */
+	num = opp_get_opp_count(cpu_dev);
+	if (num < 0) {
+		ret = num;
+		dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
+		goto put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+		goto put_node;
+	}
+
+	if (of_property_read_u32(np, "clock-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	/*
+	 * OPP is maintained in order of increasing frequency, and
+	 * freq_table initialised from OPP is therefore sorted in the
+	 * same order.
+	 */
+	rcu_read_lock();
+	opp = opp_find_freq_exact(cpu_dev,
+				  freq_table[0].frequency * 1000, true);
+	min_volt = opp_get_voltage(opp);
+	opp = opp_find_freq_exact(cpu_dev,
+				  freq_table[--num].frequency * 1000, true);
+	max_volt = opp_get_voltage(opp);
+	rcu_read_unlock();
+	ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
+	if (ret > 0)
+		transition_latency += ret * 1000;
+
+	/* Count vddpu and vddsoc latency in for 1.2 GHz support */
+	if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) {
+		ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL,
+						 PU_SOC_VOLTAGE_HIGH);
+		if (ret > 0)
+			transition_latency += ret * 1000;
+		ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL,
+						 PU_SOC_VOLTAGE_HIGH);
+		if (ret > 0)
+			transition_latency += ret * 1000;
+	}
+
+	ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
+	if (ret) {
+		dev_err(cpu_dev, "failed register driver: %d\n", ret);
+		goto free_freq_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+free_freq_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+put_node:
+	of_node_put(np);
+	return ret;
+}
+
+static int imx6q_cpufreq_remove(struct platform_device *pdev)
+{
+	cpufreq_unregister_driver(&imx6q_cpufreq_driver);
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+	return 0;
+}
+
+static struct platform_driver imx6q_cpufreq_platdrv = {
+	.driver = {
+		.name	= "imx6q-cpufreq",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= imx6q_cpufreq_probe,
+	.remove		= imx6q_cpufreq_remove,
+};
+module_platform_driver(imx6q_cpufreq_platdrv);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
new file mode 100644
index 0000000..096fde0
--- /dev/null
+++ b/drivers/cpufreq/intel_pstate.c
@@ -0,0 +1,823 @@
+/*
+ * cpufreq_snb.c: Native P state management for Intel processors
+ *
+ * (C) Copyright 2012 Intel Corporation
+ * Author: Dirk Brandewie <dirk.j.brandewie@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <trace/events/power.h>
+
+#include <asm/div64.h>
+#include <asm/msr.h>
+#include <asm/cpu_device_id.h>
+
+#define SAMPLE_COUNT		3
+
+#define FRAC_BITS 8
+#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
+#define fp_toint(X) ((X) >> FRAC_BITS)
+
+static inline int32_t mul_fp(int32_t x, int32_t y)
+{
+	return ((int64_t)x * (int64_t)y) >> FRAC_BITS;
+}
+
+static inline int32_t div_fp(int32_t x, int32_t y)
+{
+	return div_s64((int64_t)x << FRAC_BITS, (int64_t)y);
+}
+
+struct sample {
+	ktime_t start_time;
+	ktime_t end_time;
+	int core_pct_busy;
+	int pstate_pct_busy;
+	u64 duration_us;
+	u64 idletime_us;
+	u64 aperf;
+	u64 mperf;
+	int freq;
+};
+
+struct pstate_data {
+	int	current_pstate;
+	int	min_pstate;
+	int	max_pstate;
+	int	turbo_pstate;
+};
+
+struct _pid {
+	int setpoint;
+	int32_t integral;
+	int32_t p_gain;
+	int32_t i_gain;
+	int32_t d_gain;
+	int deadband;
+	int last_err;
+};
+
+struct cpudata {
+	int cpu;
+
+	char name[64];
+
+	struct timer_list timer;
+
+	struct pstate_adjust_policy *pstate_policy;
+	struct pstate_data pstate;
+	struct _pid pid;
+	struct _pid idle_pid;
+
+	int min_pstate_count;
+	int idle_mode;
+
+	ktime_t prev_sample;
+	u64	prev_idle_time_us;
+	u64	prev_aperf;
+	u64	prev_mperf;
+	int	sample_ptr;
+	struct sample samples[SAMPLE_COUNT];
+};
+
+static struct cpudata **all_cpu_data;
+struct pstate_adjust_policy {
+	int sample_rate_ms;
+	int deadband;
+	int setpoint;
+	int p_gain_pct;
+	int d_gain_pct;
+	int i_gain_pct;
+};
+
+static struct pstate_adjust_policy default_policy = {
+	.sample_rate_ms = 10,
+	.deadband = 0,
+	.setpoint = 109,
+	.p_gain_pct = 17,
+	.d_gain_pct = 0,
+	.i_gain_pct = 4,
+};
+
+struct perf_limits {
+	int no_turbo;
+	int max_perf_pct;
+	int min_perf_pct;
+	int32_t max_perf;
+	int32_t min_perf;
+};
+
+static struct perf_limits limits = {
+	.no_turbo = 0,
+	.max_perf_pct = 100,
+	.max_perf = int_tofp(1),
+	.min_perf_pct = 0,
+	.min_perf = 0,
+};
+
+static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
+			int deadband, int integral) {
+	pid->setpoint = setpoint;
+	pid->deadband  = deadband;
+	pid->integral  = int_tofp(integral);
+	pid->last_err  = setpoint - busy;
+}
+
+static inline void pid_p_gain_set(struct _pid *pid, int percent)
+{
+	pid->p_gain = div_fp(int_tofp(percent), int_tofp(100));
+}
+
+static inline void pid_i_gain_set(struct _pid *pid, int percent)
+{
+	pid->i_gain = div_fp(int_tofp(percent), int_tofp(100));
+}
+
+static inline void pid_d_gain_set(struct _pid *pid, int percent)
+{
+
+	pid->d_gain = div_fp(int_tofp(percent), int_tofp(100));
+}
+
+static signed int pid_calc(struct _pid *pid, int busy)
+{
+	signed int err, result;
+	int32_t pterm, dterm, fp_error;
+	int32_t integral_limit;
+
+	err = pid->setpoint - busy;
+	fp_error = int_tofp(err);
+
+	if (abs(err) <= pid->deadband)
+		return 0;
+
+	pterm = mul_fp(pid->p_gain, fp_error);
+
+	pid->integral += fp_error;
+
+	/* limit the integral term */
+	integral_limit = int_tofp(30);
+	if (pid->integral > integral_limit)
+		pid->integral = integral_limit;
+	if (pid->integral < -integral_limit)
+		pid->integral = -integral_limit;
+
+	dterm = mul_fp(pid->d_gain, (err - pid->last_err));
+	pid->last_err = err;
+
+	result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm;
+
+	return (signed int)fp_toint(result);
+}
+
+static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu)
+{
+	pid_p_gain_set(&cpu->pid, cpu->pstate_policy->p_gain_pct);
+	pid_d_gain_set(&cpu->pid, cpu->pstate_policy->d_gain_pct);
+	pid_i_gain_set(&cpu->pid, cpu->pstate_policy->i_gain_pct);
+
+	pid_reset(&cpu->pid,
+		cpu->pstate_policy->setpoint,
+		100,
+		cpu->pstate_policy->deadband,
+		0);
+}
+
+static inline void intel_pstate_idle_pid_reset(struct cpudata *cpu)
+{
+	pid_p_gain_set(&cpu->idle_pid, cpu->pstate_policy->p_gain_pct);
+	pid_d_gain_set(&cpu->idle_pid, cpu->pstate_policy->d_gain_pct);
+	pid_i_gain_set(&cpu->idle_pid, cpu->pstate_policy->i_gain_pct);
+
+	pid_reset(&cpu->idle_pid,
+		75,
+		50,
+		cpu->pstate_policy->deadband,
+		0);
+}
+
+static inline void intel_pstate_reset_all_pid(void)
+{
+	unsigned int cpu;
+	for_each_online_cpu(cpu) {
+		if (all_cpu_data[cpu])
+			intel_pstate_busy_pid_reset(all_cpu_data[cpu]);
+	}
+}
+
+/************************** debugfs begin ************************/
+static int pid_param_set(void *data, u64 val)
+{
+	*(u32 *)data = val;
+	intel_pstate_reset_all_pid();
+	return 0;
+}
+static int pid_param_get(void *data, u64 *val)
+{
+	*val = *(u32 *)data;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_pid_param, pid_param_get,
+			pid_param_set, "%llu\n");
+
+struct pid_param {
+	char *name;
+	void *value;
+};
+
+static struct pid_param pid_files[] = {
+	{"sample_rate_ms", &default_policy.sample_rate_ms},
+	{"d_gain_pct", &default_policy.d_gain_pct},
+	{"i_gain_pct", &default_policy.i_gain_pct},
+	{"deadband", &default_policy.deadband},
+	{"setpoint", &default_policy.setpoint},
+	{"p_gain_pct", &default_policy.p_gain_pct},
+	{NULL, NULL}
+};
+
+static struct dentry *debugfs_parent;
+static void intel_pstate_debug_expose_params(void)
+{
+	int i = 0;
+
+	debugfs_parent = debugfs_create_dir("pstate_snb", NULL);
+	if (IS_ERR_OR_NULL(debugfs_parent))
+		return;
+	while (pid_files[i].name) {
+		debugfs_create_file(pid_files[i].name, 0660,
+				debugfs_parent, pid_files[i].value,
+				&fops_pid_param);
+		i++;
+	}
+}
+
+/************************** debugfs end ************************/
+
+/************************** sysfs begin ************************/
+#define show_one(file_name, object)					\
+	static ssize_t show_##file_name					\
+	(struct kobject *kobj, struct attribute *attr, char *buf)	\
+	{								\
+		return sprintf(buf, "%u\n", limits.object);		\
+	}
+
+static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
+				const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+	limits.no_turbo = clamp_t(int, input, 0 , 1);
+
+	return count;
+}
+
+static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
+				const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+
+	limits.max_perf_pct = clamp_t(int, input, 0 , 100);
+	limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+	return count;
+}
+
+static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
+				const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+	limits.min_perf_pct = clamp_t(int, input, 0 , 100);
+	limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+
+	return count;
+}
+
+show_one(no_turbo, no_turbo);
+show_one(max_perf_pct, max_perf_pct);
+show_one(min_perf_pct, min_perf_pct);
+
+define_one_global_rw(no_turbo);
+define_one_global_rw(max_perf_pct);
+define_one_global_rw(min_perf_pct);
+
+static struct attribute *intel_pstate_attributes[] = {
+	&no_turbo.attr,
+	&max_perf_pct.attr,
+	&min_perf_pct.attr,
+	NULL
+};
+
+static struct attribute_group intel_pstate_attr_group = {
+	.attrs = intel_pstate_attributes,
+};
+static struct kobject *intel_pstate_kobject;
+
+static void intel_pstate_sysfs_expose_params(void)
+{
+	int rc;
+
+	intel_pstate_kobject = kobject_create_and_add("intel_pstate",
+						&cpu_subsys.dev_root->kobj);
+	BUG_ON(!intel_pstate_kobject);
+	rc = sysfs_create_group(intel_pstate_kobject,
+				&intel_pstate_attr_group);
+	BUG_ON(rc);
+}
+
+/************************** sysfs end ************************/
+
+static int intel_pstate_min_pstate(void)
+{
+	u64 value;
+	rdmsrl(0xCE, value);
+	return (value >> 40) & 0xFF;
+}
+
+static int intel_pstate_max_pstate(void)
+{
+	u64 value;
+	rdmsrl(0xCE, value);
+	return (value >> 8) & 0xFF;
+}
+
+static int intel_pstate_turbo_pstate(void)
+{
+	u64 value;
+	int nont, ret;
+	rdmsrl(0x1AD, value);
+	nont = intel_pstate_max_pstate();
+	ret = ((value) & 255);
+	if (ret <= nont)
+		ret = nont;
+	return ret;
+}
+
+static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
+{
+	int max_perf = cpu->pstate.turbo_pstate;
+	int min_perf;
+	if (limits.no_turbo)
+		max_perf = cpu->pstate.max_pstate;
+
+	max_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf));
+	*max = clamp_t(int, max_perf,
+			cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
+
+	min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf));
+	*min = clamp_t(int, min_perf,
+			cpu->pstate.min_pstate, max_perf);
+}
+
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
+{
+	int max_perf, min_perf;
+
+	intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
+
+	pstate = clamp_t(int, pstate, min_perf, max_perf);
+
+	if (pstate == cpu->pstate.current_pstate)
+		return;
+
+#ifndef MODULE
+	trace_cpu_frequency(pstate * 100000, cpu->cpu);
+#endif
+	cpu->pstate.current_pstate = pstate;
+	wrmsrl(MSR_IA32_PERF_CTL, pstate << 8);
+
+}
+
+static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
+{
+	int target;
+	target = cpu->pstate.current_pstate + steps;
+
+	intel_pstate_set_pstate(cpu, target);
+}
+
+static inline void intel_pstate_pstate_decrease(struct cpudata *cpu, int steps)
+{
+	int target;
+	target = cpu->pstate.current_pstate - steps;
+	intel_pstate_set_pstate(cpu, target);
+}
+
+static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
+{
+	sprintf(cpu->name, "Intel 2nd generation core");
+
+	cpu->pstate.min_pstate = intel_pstate_min_pstate();
+	cpu->pstate.max_pstate = intel_pstate_max_pstate();
+	cpu->pstate.turbo_pstate = intel_pstate_turbo_pstate();
+
+	/*
+	 * goto max pstate so we don't slow up boot if we are built-in if we are
+	 * a module we will take care of it during normal operation
+	 */
+	intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
+}
+
+static inline void intel_pstate_calc_busy(struct cpudata *cpu,
+					struct sample *sample)
+{
+	u64 core_pct;
+	sample->pstate_pct_busy = 100 - div64_u64(
+					sample->idletime_us * 100,
+					sample->duration_us);
+	core_pct = div64_u64(sample->aperf * 100, sample->mperf);
+	sample->freq = cpu->pstate.turbo_pstate * core_pct * 1000;
+
+	sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct),
+					100);
+}
+
+static inline void intel_pstate_sample(struct cpudata *cpu)
+{
+	ktime_t now;
+	u64 idle_time_us;
+	u64 aperf, mperf;
+
+	now = ktime_get();
+	idle_time_us = get_cpu_idle_time_us(cpu->cpu, NULL);
+
+	rdmsrl(MSR_IA32_APERF, aperf);
+	rdmsrl(MSR_IA32_MPERF, mperf);
+	/* for the first sample, don't actually record a sample, just
+	 * set the baseline */
+	if (cpu->prev_idle_time_us > 0) {
+		cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
+		cpu->samples[cpu->sample_ptr].start_time = cpu->prev_sample;
+		cpu->samples[cpu->sample_ptr].end_time = now;
+		cpu->samples[cpu->sample_ptr].duration_us =
+			ktime_us_delta(now, cpu->prev_sample);
+		cpu->samples[cpu->sample_ptr].idletime_us =
+			idle_time_us - cpu->prev_idle_time_us;
+
+		cpu->samples[cpu->sample_ptr].aperf = aperf;
+		cpu->samples[cpu->sample_ptr].mperf = mperf;
+		cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
+		cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
+
+		intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
+	}
+
+	cpu->prev_sample = now;
+	cpu->prev_idle_time_us = idle_time_us;
+	cpu->prev_aperf = aperf;
+	cpu->prev_mperf = mperf;
+}
+
+static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
+{
+	int sample_time, delay;
+
+	sample_time = cpu->pstate_policy->sample_rate_ms;
+	delay = msecs_to_jiffies(sample_time);
+	delay -= jiffies % delay;
+	mod_timer_pinned(&cpu->timer, jiffies + delay);
+}
+
+static inline void intel_pstate_idle_mode(struct cpudata *cpu)
+{
+	cpu->idle_mode = 1;
+}
+
+static inline void intel_pstate_normal_mode(struct cpudata *cpu)
+{
+	cpu->idle_mode = 0;
+}
+
+static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu)
+{
+	int32_t busy_scaled;
+	int32_t core_busy, turbo_pstate, current_pstate;
+
+	core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy);
+	turbo_pstate = int_tofp(cpu->pstate.turbo_pstate);
+	current_pstate = int_tofp(cpu->pstate.current_pstate);
+	busy_scaled = mul_fp(core_busy, div_fp(turbo_pstate, current_pstate));
+
+	return fp_toint(busy_scaled);
+}
+
+static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
+{
+	int busy_scaled;
+	struct _pid *pid;
+	signed int ctl = 0;
+	int steps;
+
+	pid = &cpu->pid;
+	busy_scaled = intel_pstate_get_scaled_busy(cpu);
+
+	ctl = pid_calc(pid, busy_scaled);
+
+	steps = abs(ctl);
+	if (ctl < 0)
+		intel_pstate_pstate_increase(cpu, steps);
+	else
+		intel_pstate_pstate_decrease(cpu, steps);
+}
+
+static inline void intel_pstate_adjust_idle_pstate(struct cpudata *cpu)
+{
+	int busy_scaled;
+	struct _pid *pid;
+	int ctl = 0;
+	int steps;
+
+	pid = &cpu->idle_pid;
+
+	busy_scaled = intel_pstate_get_scaled_busy(cpu);
+
+	ctl = pid_calc(pid, 100 - busy_scaled);
+
+	steps = abs(ctl);
+	if (ctl < 0)
+		intel_pstate_pstate_decrease(cpu, steps);
+	else
+		intel_pstate_pstate_increase(cpu, steps);
+
+	if (cpu->pstate.current_pstate == cpu->pstate.min_pstate)
+		intel_pstate_normal_mode(cpu);
+}
+
+static void intel_pstate_timer_func(unsigned long __data)
+{
+	struct cpudata *cpu = (struct cpudata *) __data;
+
+	intel_pstate_sample(cpu);
+
+	if (!cpu->idle_mode)
+		intel_pstate_adjust_busy_pstate(cpu);
+	else
+		intel_pstate_adjust_idle_pstate(cpu);
+
+#if defined(XPERF_FIX)
+	if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) {
+		cpu->min_pstate_count++;
+		if (!(cpu->min_pstate_count % 5)) {
+			intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
+			intel_pstate_idle_mode(cpu);
+		}
+	} else
+		cpu->min_pstate_count = 0;
+#endif
+	intel_pstate_set_sample_time(cpu);
+}
+
+#define ICPU(model, policy) \
+	{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy }
+
+static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
+	ICPU(0x2a, default_policy),
+	ICPU(0x2d, default_policy),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
+
+static int intel_pstate_init_cpu(unsigned int cpunum)
+{
+
+	const struct x86_cpu_id *id;
+	struct cpudata *cpu;
+
+	id = x86_match_cpu(intel_pstate_cpu_ids);
+	if (!id)
+		return -ENODEV;
+
+	all_cpu_data[cpunum] = kzalloc(sizeof(struct cpudata), GFP_KERNEL);
+	if (!all_cpu_data[cpunum])
+		return -ENOMEM;
+
+	cpu = all_cpu_data[cpunum];
+
+	intel_pstate_get_cpu_pstates(cpu);
+
+	cpu->cpu = cpunum;
+	cpu->pstate_policy =
+		(struct pstate_adjust_policy *)id->driver_data;
+	init_timer_deferrable(&cpu->timer);
+	cpu->timer.function = intel_pstate_timer_func;
+	cpu->timer.data =
+		(unsigned long)cpu;
+	cpu->timer.expires = jiffies + HZ/100;
+	intel_pstate_busy_pid_reset(cpu);
+	intel_pstate_idle_pid_reset(cpu);
+	intel_pstate_sample(cpu);
+	intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
+
+	add_timer_on(&cpu->timer, cpunum);
+
+	pr_info("Intel pstate controlling: cpu %d\n", cpunum);
+
+	return 0;
+}
+
+static unsigned int intel_pstate_get(unsigned int cpu_num)
+{
+	struct sample *sample;
+	struct cpudata *cpu;
+
+	cpu = all_cpu_data[cpu_num];
+	if (!cpu)
+		return 0;
+	sample = &cpu->samples[cpu->sample_ptr];
+	return sample->freq;
+}
+
+static int intel_pstate_set_policy(struct cpufreq_policy *policy)
+{
+	struct cpudata *cpu;
+	int min, max;
+
+	cpu = all_cpu_data[policy->cpu];
+
+	intel_pstate_get_min_max(cpu, &min, &max);
+
+	limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
+	limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
+	limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+
+	limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
+	limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
+	limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+
+	if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+		limits.min_perf_pct = 100;
+		limits.min_perf = int_tofp(1);
+		limits.max_perf_pct = 100;
+		limits.max_perf = int_tofp(1);
+		limits.no_turbo = 0;
+	}
+
+	return 0;
+}
+
+static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
+{
+	cpufreq_verify_within_limits(policy,
+				policy->cpuinfo.min_freq,
+				policy->cpuinfo.max_freq);
+
+	if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
+		(policy->policy != CPUFREQ_POLICY_PERFORMANCE))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int __cpuinit intel_pstate_cpu_exit(struct cpufreq_policy *policy)
+{
+	int cpu = policy->cpu;
+
+	del_timer(&all_cpu_data[cpu]->timer);
+	kfree(all_cpu_data[cpu]);
+	all_cpu_data[cpu] = NULL;
+	return 0;
+}
+
+static int __cpuinit intel_pstate_cpu_init(struct cpufreq_policy *policy)
+{
+	int rc, min_pstate, max_pstate;
+	struct cpudata *cpu;
+
+	rc = intel_pstate_init_cpu(policy->cpu);
+	if (rc)
+		return rc;
+
+	cpu = all_cpu_data[policy->cpu];
+
+	if (!limits.no_turbo &&
+		limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	else
+		policy->policy = CPUFREQ_POLICY_POWERSAVE;
+
+	intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate);
+	policy->min = min_pstate * 100000;
+	policy->max = max_pstate * 100000;
+
+	/* cpuinfo and default policy values */
+	policy->cpuinfo.min_freq = cpu->pstate.min_pstate * 100000;
+	policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate * 100000;
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	cpumask_set_cpu(policy->cpu, policy->cpus);
+
+	return 0;
+}
+
+static struct cpufreq_driver intel_pstate_driver = {
+	.flags		= CPUFREQ_CONST_LOOPS,
+	.verify		= intel_pstate_verify_policy,
+	.setpolicy	= intel_pstate_set_policy,
+	.get		= intel_pstate_get,
+	.init		= intel_pstate_cpu_init,
+	.exit		= intel_pstate_cpu_exit,
+	.name		= "intel_pstate",
+	.owner		= THIS_MODULE,
+};
+
+static void intel_pstate_exit(void)
+{
+	int cpu;
+
+	sysfs_remove_group(intel_pstate_kobject,
+				&intel_pstate_attr_group);
+	debugfs_remove_recursive(debugfs_parent);
+
+	cpufreq_unregister_driver(&intel_pstate_driver);
+
+	if (!all_cpu_data)
+		return;
+
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (all_cpu_data[cpu]) {
+			del_timer_sync(&all_cpu_data[cpu]->timer);
+			kfree(all_cpu_data[cpu]);
+		}
+	}
+
+	put_online_cpus();
+	vfree(all_cpu_data);
+}
+module_exit(intel_pstate_exit);
+
+static int __initdata no_load;
+
+static int __init intel_pstate_init(void)
+{
+	int rc = 0;
+	const struct x86_cpu_id *id;
+
+	if (no_load)
+		return -ENODEV;
+
+	id = x86_match_cpu(intel_pstate_cpu_ids);
+	if (!id)
+		return -ENODEV;
+
+	pr_info("Intel P-state driver initializing.\n");
+
+	all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus());
+	if (!all_cpu_data)
+		return -ENOMEM;
+	memset(all_cpu_data, 0, sizeof(void *) * num_possible_cpus());
+
+	rc = cpufreq_register_driver(&intel_pstate_driver);
+	if (rc)
+		goto out;
+
+	intel_pstate_debug_expose_params();
+	intel_pstate_sysfs_expose_params();
+	return rc;
+out:
+	intel_pstate_exit();
+	return -ENODEV;
+}
+device_initcall(intel_pstate_init);
+
+static int __init intel_pstate_setup(char *str)
+{
+	if (!str)
+		return -EINVAL;
+
+	if (!strcmp(str, "disable"))
+		no_load = 1;
+	return 0;
+}
+early_param("intel_pstate", intel_pstate_setup);
+
+MODULE_AUTHOR("Dirk Brandewie <dirk.j.brandewie@intel.com>");
+MODULE_DESCRIPTION("'intel_pstate' - P state driver Intel Core processors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
new file mode 100644
index 0000000..0e83e3c
--- /dev/null
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -0,0 +1,259 @@
+/*
+ *	kirkwood_freq.c: cpufreq driver for the Marvell kirkwood
+ *
+ *	Copyright (C) 2013 Andrew Lunn <andrew@lunn.ch>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <asm/proc-fns.h>
+
+#define CPU_SW_INT_BLK BIT(28)
+
+static struct priv
+{
+	struct clk *cpu_clk;
+	struct clk *ddr_clk;
+	struct clk *powersave_clk;
+	struct device *dev;
+	void __iomem *base;
+} priv;
+
+#define STATE_CPU_FREQ 0x01
+#define STATE_DDR_FREQ 0x02
+
+/*
+ * Kirkwood can swap the clock to the CPU between two clocks:
+ *
+ * - cpu clk
+ * - ddr clk
+ *
+ * The frequencies are set at runtime before registering this *
+ * table.
+ */
+static struct cpufreq_frequency_table kirkwood_freq_table[] = {
+	{STATE_CPU_FREQ,	0}, /* CPU uses cpuclk */
+	{STATE_DDR_FREQ,	0}, /* CPU uses ddrclk */
+	{0,			CPUFREQ_TABLE_END},
+};
+
+static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
+{
+	if (__clk_is_enabled(priv.powersave_clk))
+		return kirkwood_freq_table[1].frequency;
+	return kirkwood_freq_table[0].frequency;
+}
+
+static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int state = kirkwood_freq_table[index].index;
+	unsigned long reg;
+
+	freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
+	freqs.new = kirkwood_freq_table[index].frequency;
+	freqs.cpu = 0; /* Kirkwood is UP */
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n",
+		kirkwood_freq_table[index].frequency);
+	dev_dbg(priv.dev, "old frequency was %i KHz\n",
+		kirkwood_cpufreq_get_cpu_frequency(0));
+
+	if (freqs.old != freqs.new) {
+		local_irq_disable();
+
+		/* Disable interrupts to the CPU */
+		reg = readl_relaxed(priv.base);
+		reg |= CPU_SW_INT_BLK;
+		writel_relaxed(reg, priv.base);
+
+		switch (state) {
+		case STATE_CPU_FREQ:
+			clk_disable(priv.powersave_clk);
+			break;
+		case STATE_DDR_FREQ:
+			clk_enable(priv.powersave_clk);
+			break;
+		}
+
+		/* Wait-for-Interrupt, while the hardware changes frequency */
+		cpu_do_idle();
+
+		/* Enable interrupts to the CPU */
+		reg = readl_relaxed(priv.base);
+		reg &= ~CPU_SW_INT_BLK;
+		writel_relaxed(reg, priv.base);
+
+		local_irq_enable();
+	}
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+static int kirkwood_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, kirkwood_freq_table);
+}
+
+static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq,
+			    unsigned int relation)
+{
+	unsigned int index = 0;
+
+	if (cpufreq_frequency_table_target(policy, kirkwood_freq_table,
+				target_freq, relation, &index))
+		return -EINVAL;
+
+	kirkwood_cpufreq_set_cpu_state(index);
+
+	return 0;
+}
+
+/* Module init and exit code */
+static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	int result;
+
+	/* cpuinfo and default policy values */
+	policy->cpuinfo.transition_latency = 5000; /* 5uS */
+	policy->cur = kirkwood_cpufreq_get_cpu_frequency(0);
+
+	result = cpufreq_frequency_table_cpuinfo(policy, kirkwood_freq_table);
+	if (result)
+		return result;
+
+	cpufreq_frequency_table_get_attr(kirkwood_freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int kirkwood_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static struct freq_attr *kirkwood_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver kirkwood_cpufreq_driver = {
+	.get	= kirkwood_cpufreq_get_cpu_frequency,
+	.verify	= kirkwood_cpufreq_verify,
+	.target	= kirkwood_cpufreq_target,
+	.init	= kirkwood_cpufreq_cpu_init,
+	.exit	= kirkwood_cpufreq_cpu_exit,
+	.name	= "kirkwood-cpufreq",
+	.owner	= THIS_MODULE,
+	.attr	= kirkwood_cpufreq_attr,
+};
+
+static int kirkwood_cpufreq_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	struct resource *res;
+	int err;
+
+	priv.dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Cannot get memory resource\n");
+		return -ENODEV;
+	}
+	priv.base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!priv.base) {
+		dev_err(&pdev->dev, "Cannot ioremap\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np)
+		return -ENODEV;
+
+	priv.cpu_clk = of_clk_get_by_name(np, "cpu_clk");
+	if (IS_ERR(priv.cpu_clk)) {
+		dev_err(priv.dev, "Unable to get cpuclk");
+		return PTR_ERR(priv.cpu_clk);
+	}
+
+	clk_prepare_enable(priv.cpu_clk);
+	kirkwood_freq_table[0].frequency = clk_get_rate(priv.cpu_clk) / 1000;
+
+	priv.ddr_clk = of_clk_get_by_name(np, "ddrclk");
+	if (IS_ERR(priv.ddr_clk)) {
+		dev_err(priv.dev, "Unable to get ddrclk");
+		err = PTR_ERR(priv.ddr_clk);
+		goto out_cpu;
+	}
+
+	clk_prepare_enable(priv.ddr_clk);
+	kirkwood_freq_table[1].frequency = clk_get_rate(priv.ddr_clk) / 1000;
+
+	priv.powersave_clk = of_clk_get_by_name(np, "powersave");
+	if (IS_ERR(priv.powersave_clk)) {
+		dev_err(priv.dev, "Unable to get powersave");
+		err = PTR_ERR(priv.powersave_clk);
+		goto out_ddr;
+	}
+	clk_prepare(priv.powersave_clk);
+
+	of_node_put(np);
+	np = NULL;
+
+	err = cpufreq_register_driver(&kirkwood_cpufreq_driver);
+	if (!err)
+		return 0;
+
+	dev_err(priv.dev, "Failed to register cpufreq driver");
+
+	clk_disable_unprepare(priv.powersave_clk);
+out_ddr:
+	clk_disable_unprepare(priv.ddr_clk);
+out_cpu:
+	clk_disable_unprepare(priv.cpu_clk);
+	of_node_put(np);
+
+	return err;
+}
+
+static int kirkwood_cpufreq_remove(struct platform_device *pdev)
+{
+	cpufreq_unregister_driver(&kirkwood_cpufreq_driver);
+
+	clk_disable_unprepare(priv.powersave_clk);
+	clk_disable_unprepare(priv.ddr_clk);
+	clk_disable_unprepare(priv.cpu_clk);
+
+	return 0;
+}
+
+static struct platform_driver kirkwood_cpufreq_platform_driver = {
+	.probe = kirkwood_cpufreq_probe,
+	.remove = kirkwood_cpufreq_remove,
+	.driver = {
+		.name = "kirkwood-cpufreq",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(kirkwood_cpufreq_platform_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch");
+MODULE_DESCRIPTION("cpufreq driver for Marvell's kirkwood CPU");
+MODULE_ALIAS("platform:kirkwood-cpufreq");
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index 89b178a..d4c4989 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -181,7 +181,7 @@
 	/* secondary CPUs are tied to the primary one by the
 	 * cpufreq core if in the secondary policy we tell it that
 	 * it actually must be one policy together with all others. */
-	cpumask_copy(policy->cpus, cpu_online_mask);
+	cpumask_setall(policy->cpus);
 	cpufreq_frequency_table_get_attr(maple_cpu_freqs, policy->cpu);
 
 	return cpufreq_frequency_table_cpuinfo(policy,
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 97102b0..9128c07 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -214,10 +214,8 @@
 	 * interface to handle this scenario. Additional is_smp() check
 	 * is to keep SMP_ON_UP build working.
 	 */
-	if (is_smp()) {
-		policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	if (is_smp())
 		cpumask_setall(policy->cpus);
-	}
 
 	/* FIXME: what's the actual transition time? */
 	policy->cpuinfo.transition_latency = 300 * 1000;
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 056faf6..d13a136 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -1249,39 +1249,59 @@
 	.attr		= powernow_k8_attr,
 };
 
+static void __request_acpi_cpufreq(void)
+{
+	const char *cur_drv, *drv = "acpi-cpufreq";
+
+	cur_drv = cpufreq_get_current_driver();
+	if (!cur_drv)
+		goto request;
+
+	if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv))))
+		pr_warn(PFX "WTF driver: %s\n", cur_drv);
+
+	return;
+
+ request:
+	pr_warn(PFX "This CPU is not supported anymore, using acpi-cpufreq instead.\n");
+	request_module(drv);
+}
+
 /* driver entry point for init */
 static int __cpuinit powernowk8_init(void)
 {
 	unsigned int i, supported_cpus = 0;
-	int rv;
+	int ret;
 
 	if (static_cpu_has(X86_FEATURE_HW_PSTATE)) {
-		pr_warn(PFX "this CPU is not supported anymore, using acpi-cpufreq instead.\n");
-		request_module("acpi-cpufreq");
+		__request_acpi_cpufreq();
 		return -ENODEV;
 	}
 
 	if (!x86_match_cpu(powernow_k8_ids))
 		return -ENODEV;
 
+	get_online_cpus();
 	for_each_online_cpu(i) {
-		int rc;
-		smp_call_function_single(i, check_supported_cpu, &rc, 1);
-		if (rc == 0)
+		smp_call_function_single(i, check_supported_cpu, &ret, 1);
+		if (!ret)
 			supported_cpus++;
 	}
 
-	if (supported_cpus != num_online_cpus())
+	if (supported_cpus != num_online_cpus()) {
+		put_online_cpus();
 		return -ENODEV;
+	}
+	put_online_cpus();
 
-	rv = cpufreq_register_driver(&cpufreq_amd64_driver);
+	ret = cpufreq_register_driver(&cpufreq_amd64_driver);
+	if (ret)
+		return ret;
 
-	if (!rv)
-		pr_info(PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
-			num_online_nodes(), boot_cpu_data.x86_model_id,
-			supported_cpus);
+	pr_info(PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
+		num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
 
-	return rv;
+	return ret;
 }
 
 /* driver entry point for term */
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 4575cfe..7e4d773 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -30,7 +30,7 @@
 	u32 cnt;
 } spear_cpufreq;
 
-int spear_cpufreq_verify(struct cpufreq_policy *policy)
+static int spear_cpufreq_verify(struct cpufreq_policy *policy)
 {
 	return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl);
 }
@@ -157,7 +157,9 @@
 
 	freqs.new = newfreq / 1000;
 	freqs.new /= mult;
-	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
 	if (mult == 2)
 		ret = spear1340_set_cpu_rate(srcclk, newfreq);
@@ -170,7 +172,8 @@
 		freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000;
 	}
 
-	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 	return ret;
 }
 
@@ -188,8 +191,7 @@
 	policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency;
 	policy->cur = spear_cpufreq_get(0);
 
-	cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
-	cpumask_copy(policy->related_cpus, policy->cpus);
+	cpumask_setall(policy->cpus);
 
 	return 0;
 }
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index e1f6860..eba6929 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -144,7 +144,6 @@
 		return 0;
 	}
 
-	trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
 	trace_cpu_idle_rcuidle(next_state, dev->cpu);
 
 	if (cpuidle_state_is_coupled(dev, drv, next_state))
@@ -153,7 +152,6 @@
 	else
 		entered_state = cpuidle_enter_state(dev, drv, next_state);
 
-	trace_power_end_rcuidle(dev->cpu);
 	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
 
 	/* give the governor an opportunity to reflect on the outcome */
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index ad8bf2a..910b011 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -31,7 +31,7 @@
  *
  *FIXME: Produce a better mapping/linearisation.
  */
-struct scrubrate {
+static const struct scrubrate {
        u32 scrubval;           /* bit pattern for scrub rate */
        u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
 } scrubrates[] = {
@@ -239,7 +239,7 @@
  * DRAM base/limit associated with node_id
  */
 static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
-				   unsigned nid)
+				   u8 nid)
 {
 	u64 addr;
 
@@ -265,7 +265,7 @@
 						u64 sys_addr)
 {
 	struct amd64_pvt *pvt;
-	unsigned node_id;
+	u8 node_id;
 	u32 intlv_en, bits;
 
 	/*
@@ -602,111 +602,6 @@
 	return input_addr;
 }
 
-
-/*
- * @input_addr is an InputAddr associated with the node represented by mci.
- * Translate @input_addr to a DramAddr and return the result.
- */
-static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
-{
-	struct amd64_pvt *pvt;
-	unsigned node_id, intlv_shift;
-	u64 bits, dram_addr;
-	u32 intlv_sel;
-
-	/*
-	 * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
-	 * shows how to translate a DramAddr to an InputAddr. Here we reverse
-	 * this procedure. When translating from a DramAddr to an InputAddr, the
-	 * bits used for node interleaving are discarded.  Here we recover these
-	 * bits from the IntlvSel field of the DRAM Limit register (section
-	 * 3.4.4.2) for the node that input_addr is associated with.
-	 */
-	pvt = mci->pvt_info;
-	node_id = pvt->mc_node_id;
-
-	BUG_ON(node_id > 7);
-
-	intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
-	if (intlv_shift == 0) {
-		edac_dbg(1, "    InputAddr 0x%lx translates to DramAddr of same value\n",
-			 (unsigned long)input_addr);
-
-		return input_addr;
-	}
-
-	bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
-		(input_addr & 0xfff);
-
-	intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
-	dram_addr = bits + (intlv_sel << 12);
-
-	edac_dbg(1, "InputAddr 0x%lx translates to DramAddr 0x%lx (%d node interleave bits)\n",
-		 (unsigned long)input_addr,
-		 (unsigned long)dram_addr, intlv_shift);
-
-	return dram_addr;
-}
-
-/*
- * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
- * @dram_addr to a SysAddr.
- */
-static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	u64 hole_base, hole_offset, hole_size, base, sys_addr;
-	int ret = 0;
-
-	ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
-				      &hole_size);
-	if (!ret) {
-		if ((dram_addr >= hole_base) &&
-		    (dram_addr < (hole_base + hole_size))) {
-			sys_addr = dram_addr + hole_offset;
-
-			edac_dbg(1, "using DHAR to translate DramAddr 0x%lx to SysAddr 0x%lx\n",
-				 (unsigned long)dram_addr,
-				 (unsigned long)sys_addr);
-
-			return sys_addr;
-		}
-	}
-
-	base     = get_dram_base(pvt, pvt->mc_node_id);
-	sys_addr = dram_addr + base;
-
-	/*
-	 * The sys_addr we have computed up to this point is a 40-bit value
-	 * because the k8 deals with 40-bit values.  However, the value we are
-	 * supposed to return is a full 64-bit physical address.  The AMD
-	 * x86-64 architecture specifies that the most significant implemented
-	 * address bit through bit 63 of a physical address must be either all
-	 * 0s or all 1s.  Therefore we sign-extend the 40-bit sys_addr to a
-	 * 64-bit value below.  See section 3.4.2 of AMD publication 24592:
-	 * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
-	 * Programming.
-	 */
-	sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
-
-	edac_dbg(1, "    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
-		 pvt->mc_node_id, (unsigned long)dram_addr,
-		 (unsigned long)sys_addr);
-
-	return sys_addr;
-}
-
-/*
- * @input_addr is an InputAddr associated with the node given by mci. Translate
- * @input_addr to a SysAddr.
- */
-static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
-					 u64 input_addr)
-{
-	return dram_addr_to_sys_addr(mci,
-				     input_addr_to_dram_addr(mci, input_addr));
-}
-
 /* Map the Error address to a PAGE and PAGE OFFSET. */
 static inline void error_address_to_page_and_offset(u64 error_address,
 						    struct err_info *err)
@@ -939,7 +834,8 @@
 		struct amd64_pvt *pvt;
 		u64 cc6_base, tmp_addr;
 		u32 tmp;
-		u8 mce_nid, intlv_en;
+		u16 mce_nid;
+		u8 intlv_en;
 
 		if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
 			return addr;
@@ -979,10 +875,29 @@
 	return addr;
 }
 
+static struct pci_dev *pci_get_related_function(unsigned int vendor,
+						unsigned int device,
+						struct pci_dev *related)
+{
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_get_device(vendor, device, dev))) {
+		if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
+		    (dev->bus->number == related->bus->number) &&
+		    (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
+			break;
+	}
+
+	return dev;
+}
+
 static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
 {
+	struct amd_northbridge *nb;
+	struct pci_dev *misc, *f1 = NULL;
 	struct cpuinfo_x86 *c = &boot_cpu_data;
 	int off = range << 3;
+	u32 llim;
 
 	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
 	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
@@ -996,30 +911,32 @@
 	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off,  &pvt->ranges[range].base.hi);
 	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
 
-	/* Factor in CC6 save area by reading dst node's limit reg */
-	if (c->x86 == 0x15) {
-		struct pci_dev *f1 = NULL;
-		u8 nid = dram_dst_node(pvt, range);
-		u32 llim;
+	/* F15h: factor in CC6 save area by reading dst node's limit reg */
+	if (c->x86 != 0x15)
+		return;
 
-		f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
-		if (WARN_ON(!f1))
-			return;
+	nb = node_to_amd_nb(dram_dst_node(pvt, range));
+	if (WARN_ON(!nb))
+		return;
 
-		amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
+	misc = nb->misc;
+	f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
+	if (WARN_ON(!f1))
+		return;
 
-		pvt->ranges[range].lim.lo &= GENMASK(0, 15);
+	amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
 
-					    /* {[39:27],111b} */
-		pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
+	pvt->ranges[range].lim.lo &= GENMASK(0, 15);
 
-		pvt->ranges[range].lim.hi &= GENMASK(0, 7);
+				    /* {[39:27],111b} */
+	pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
 
-					    /* [47:40] */
-		pvt->ranges[range].lim.hi |= llim >> 13;
+	pvt->ranges[range].lim.hi &= GENMASK(0, 7);
 
-		pci_dev_put(f1);
-	}
+				    /* [47:40] */
+	pvt->ranges[range].lim.hi |= llim >> 13;
+
+	pci_dev_put(f1);
 }
 
 static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
@@ -1305,7 +1222,7 @@
 }
 
 /* Convert the sys_addr to the normalized DCT address */
-static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
+static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
 				 u64 sys_addr, bool hi_rng,
 				 u32 dct_sel_base_addr)
 {
@@ -1381,7 +1298,7 @@
  *	-EINVAL:  NOT FOUND
  *	0..csrow = Chip-Select Row
  */
-static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
+static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
 {
 	struct mem_ctl_info *mci;
 	struct amd64_pvt *pvt;
@@ -1672,23 +1589,6 @@
 	},
 };
 
-static struct pci_dev *pci_get_related_function(unsigned int vendor,
-						unsigned int device,
-						struct pci_dev *related)
-{
-	struct pci_dev *dev = NULL;
-
-	dev = pci_get_device(vendor, device, dev);
-	while (dev) {
-		if ((dev->bus->number == related->bus->number) &&
-		    (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
-			break;
-		dev = pci_get_device(vendor, device, dev);
-	}
-
-	return dev;
-}
-
 /*
  * These are tables of eigenvectors (one per line) which can be used for the
  * construction of the syndrome tables. The modified syndrome search algorithm
@@ -1696,7 +1596,7 @@
  *
  * Algorithm courtesy of Ross LaFetra from AMD.
  */
-static u16 x4_vectors[] = {
+static const u16 x4_vectors[] = {
 	0x2f57, 0x1afe, 0x66cc, 0xdd88,
 	0x11eb, 0x3396, 0x7f4c, 0xeac8,
 	0x0001, 0x0002, 0x0004, 0x0008,
@@ -1735,7 +1635,7 @@
 	0x19a9, 0x2efe, 0xb5cc, 0x6f88,
 };
 
-static u16 x8_vectors[] = {
+static const u16 x8_vectors[] = {
 	0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
 	0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
 	0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
@@ -1757,7 +1657,7 @@
 	0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
 };
 
-static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
+static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
 			   unsigned v_dim)
 {
 	unsigned int i, err_sym;
@@ -2181,7 +2081,7 @@
 }
 
 /* get all cores on this DCT */
-static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
+static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
 {
 	int cpu;
 
@@ -2191,7 +2091,7 @@
 }
 
 /* check MCG_CTL on all the cpus on this node */
-static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
+static bool amd64_nb_mce_bank_enabled_on_node(u16 nid)
 {
 	cpumask_var_t mask;
 	int cpu, nbe;
@@ -2224,7 +2124,7 @@
 	return ret;
 }
 
-static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
+static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
 {
 	cpumask_var_t cmask;
 	int cpu;
@@ -2262,7 +2162,7 @@
 	return 0;
 }
 
-static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
 				       struct pci_dev *F3)
 {
 	bool ret = true;
@@ -2314,7 +2214,7 @@
 	return ret;
 }
 
-static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
 					struct pci_dev *F3)
 {
 	u32 value, mask = 0x3;		/* UECC/CECC enable */
@@ -2353,7 +2253,7 @@
 	"'ecc_enable_override'.\n"
 	" (Note that use of the override may cause unknown side effects.)\n";
 
-static bool ecc_enabled(struct pci_dev *F3, u8 nid)
+static bool ecc_enabled(struct pci_dev *F3, u16 nid)
 {
 	u32 value;
 	u8 ecc_en = 0;
@@ -2474,7 +2374,7 @@
 	struct mem_ctl_info *mci = NULL;
 	struct edac_mc_layer layers[2];
 	int err = 0, ret;
-	u8 nid = get_node_id(F2);
+	u16 nid = amd_get_node_id(F2);
 
 	ret = -ENOMEM;
 	pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
@@ -2566,7 +2466,7 @@
 static int amd64_probe_one_instance(struct pci_dev *pdev,
 				    const struct pci_device_id *mc_type)
 {
-	u8 nid = get_node_id(pdev);
+	u16 nid = amd_get_node_id(pdev);
 	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
 	struct ecc_settings *s;
 	int ret = 0;
@@ -2616,7 +2516,7 @@
 {
 	struct mem_ctl_info *mci;
 	struct amd64_pvt *pvt;
-	u8 nid = get_node_id(pdev);
+	u16 nid = amd_get_node_id(pdev);
 	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
 	struct ecc_settings *s = ecc_stngs[nid];
 
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index e864f40..35637d8 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -292,12 +292,6 @@
 /* MSRs */
 #define MSR_MCGCTL_NBE			BIT(4)
 
-/* AMD sets the first MC device at device ID 0x18. */
-static inline u8 get_node_id(struct pci_dev *pdev)
-{
-	return PCI_SLOT(pdev->devfn) - 0x18;
-}
-
 enum amd_families {
 	K8_CPUS = 0,
 	F10_CPUS,
@@ -340,7 +334,7 @@
 	/* pci_device handles which we utilize */
 	struct pci_dev *F1, *F2, *F3;
 
-	unsigned mc_node_id;	/* MC index of this MC node */
+	u16 mc_node_id;		/* MC index of this MC node */
 	int ext_model;		/* extended model value of this node */
 	int channel_count;
 
@@ -393,7 +387,7 @@
 	u32 offset;
 };
 
-static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
+static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i)
 {
 	u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;
 
@@ -403,7 +397,7 @@
 	return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr;
 }
 
-static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i)
+static inline u64 get_dram_limit(struct amd64_pvt *pvt, u8 i)
 {
 	u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff;
 
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index ad637572..f3f0c93 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -39,30 +39,28 @@
  */
 
 /* transaction type */
-const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
-EXPORT_SYMBOL_GPL(tt_msgs);
+static const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
 
 /* cache level */
-const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
-EXPORT_SYMBOL_GPL(ll_msgs);
+static const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
 
 /* memory transaction type */
-const char * const rrrr_msgs[] = {
+static const char * const rrrr_msgs[] = {
        "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
 };
-EXPORT_SYMBOL_GPL(rrrr_msgs);
 
 /* participating processor */
 const char * const pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
 EXPORT_SYMBOL_GPL(pp_msgs);
 
 /* request timeout */
-const char * const to_msgs[] = { "no timeout", "timed out" };
-EXPORT_SYMBOL_GPL(to_msgs);
+static const char * const to_msgs[] = { "no timeout", "timed out" };
 
 /* memory or i/o */
-const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
-EXPORT_SYMBOL_GPL(ii_msgs);
+static const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
+
+/* internal error type */
+static const char * const uu_msgs[] = { "RESV", "RESV", "HWA", "RESV" };
 
 static const char * const f15h_mc1_mce_desc[] = {
 	"UC during a demand linefill from L2",
@@ -176,7 +174,7 @@
 	return f10h_mc0_mce(ec, xec);
 }
 
-static bool f14h_mc0_mce(u16 ec, u8 xec)
+static bool cat_mc0_mce(u16 ec, u8 xec)
 {
 	u8 r4	 = R4(ec);
 	bool ret = true;
@@ -330,22 +328,28 @@
 	return ret;
 }
 
-static bool f14h_mc1_mce(u16 ec, u8 xec)
+static bool cat_mc1_mce(u16 ec, u8 xec)
 {
 	u8 r4    = R4(ec);
 	bool ret = true;
 
-	if (MEM_ERROR(ec)) {
-		if (TT(ec) != 0 || LL(ec) != 1)
-			ret = false;
+	if (!MEM_ERROR(ec))
+		return false;
 
-		if (r4 == R4_IRD)
-			pr_cont("Data/tag array parity error for a tag hit.\n");
-		else if (r4 == R4_SNOOP)
-			pr_cont("Tag error during snoop/victimization.\n");
-		else
-			ret = false;
-	}
+	if (TT(ec) != TT_INSTR)
+		return false;
+
+	if (r4 == R4_IRD)
+		pr_cont("Data/tag array parity error for a tag hit.\n");
+	else if (r4 == R4_SNOOP)
+		pr_cont("Tag error during snoop/victimization.\n");
+	else if (xec == 0x0)
+		pr_cont("Tag parity error from victim castout.\n");
+	else if (xec == 0x2)
+		pr_cont("Microcode patch RAM parity error.\n");
+	else
+		ret = false;
+
 	return ret;
 }
 
@@ -399,12 +403,9 @@
 		pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n");
 }
 
-static void decode_mc2_mce(struct mce *m)
+static bool k8_mc2_mce(u16 ec, u8 xec)
 {
-	u16 ec = EC(m->status);
-	u8 xec = XEC(m->status, xec_mask);
-
-	pr_emerg(HW_ERR "MC2 Error");
+	bool ret = true;
 
 	if (xec == 0x1)
 		pr_cont(" in the write data buffers.\n");
@@ -429,24 +430,18 @@
 				pr_cont(": %s parity/ECC error during data "
 					"access from L2.\n", R4_MSG(ec));
 			else
-				goto wrong_mc2_mce;
+				ret = false;
 		} else
-			goto wrong_mc2_mce;
+			ret = false;
 	} else
-		goto wrong_mc2_mce;
+		ret = false;
 
-	return;
-
- wrong_mc2_mce:
-	pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n");
+	return ret;
 }
 
-static void decode_f15_mc2_mce(struct mce *m)
+static bool f15h_mc2_mce(u16 ec, u8 xec)
 {
-	u16 ec = EC(m->status);
-	u8 xec = XEC(m->status, xec_mask);
-
-	pr_emerg(HW_ERR "MC2 Error: ");
+	bool ret = true;
 
 	if (TLB_ERROR(ec)) {
 		if (xec == 0x0)
@@ -454,10 +449,10 @@
 		else if (xec == 0x1)
 			pr_cont("Poison data provided for TLB fill.\n");
 		else
-			goto wrong_f15_mc2_mce;
+			ret = false;
 	} else if (BUS_ERROR(ec)) {
 		if (xec > 2)
-			goto wrong_f15_mc2_mce;
+			ret = false;
 
 		pr_cont("Error during attempted NB data read.\n");
 	} else if (MEM_ERROR(ec)) {
@@ -471,14 +466,63 @@
 			break;
 
 		default:
-			goto wrong_f15_mc2_mce;
+			ret = false;
 		}
 	}
 
-	return;
+	return ret;
+}
 
- wrong_f15_mc2_mce:
-	pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n");
+static bool f16h_mc2_mce(u16 ec, u8 xec)
+{
+	u8 r4 = R4(ec);
+
+	if (!MEM_ERROR(ec))
+		return false;
+
+	switch (xec) {
+	case 0x04 ... 0x05:
+		pr_cont("%cBUFF parity error.\n", (r4 == R4_RD) ? 'I' : 'O');
+		break;
+
+	case 0x09 ... 0x0b:
+	case 0x0d ... 0x0f:
+		pr_cont("ECC error in L2 tag (%s).\n",
+			((r4 == R4_GEN)   ? "BankReq" :
+			((r4 == R4_SNOOP) ? "Prb"     : "Fill")));
+		break;
+
+	case 0x10 ... 0x19:
+	case 0x1b:
+		pr_cont("ECC error in L2 data array (%s).\n",
+			(((r4 == R4_RD) && !(xec & 0x3)) ? "Hit"  :
+			((r4 == R4_GEN)   ? "Attr" :
+			((r4 == R4_EVICT) ? "Vict" : "Fill"))));
+		break;
+
+	case 0x1c ... 0x1d:
+	case 0x1f:
+		pr_cont("Parity error in L2 attribute bits (%s).\n",
+			((r4 == R4_RD)  ? "Hit"  :
+			((r4 == R4_GEN) ? "Attr" : "Fill")));
+		break;
+
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+static void decode_mc2_mce(struct mce *m)
+{
+	u16 ec = EC(m->status);
+	u8 xec = XEC(m->status, xec_mask);
+
+	pr_emerg(HW_ERR "MC2 Error: ");
+
+	if (!fam_ops->mc2_mce(ec, xec))
+		pr_cont(HW_ERR "Corrupted MC2 MCE info?\n");
 }
 
 static void decode_mc3_mce(struct mce *m)
@@ -547,7 +591,7 @@
 		return;
 
 	case 0x19:
-		if (boot_cpu_data.x86 == 0x15)
+		if (boot_cpu_data.x86 == 0x15 || boot_cpu_data.x86 == 0x16)
 			pr_cont("Compute Unit Data Error.\n");
 		else
 			goto wrong_mc4_mce;
@@ -633,6 +677,10 @@
 
 static inline void amd_decode_err_code(u16 ec)
 {
+	if (INT_ERROR(ec)) {
+		pr_emerg(HW_ERR "internal: %s\n", UU_MSG(ec));
+		return;
+	}
 
 	pr_emerg(HW_ERR "cache level: %s", LL_MSG(ec));
 
@@ -702,10 +750,7 @@
 		break;
 
 	case 2:
-		if (c->x86 == 0x15)
-			decode_f15_mc2_mce(m);
-		else
-			decode_mc2_mce(m);
+		decode_mc2_mce(m);
 		break;
 
 	case 3:
@@ -740,7 +785,7 @@
 		((m->status & MCI_STATUS_PCC)	? "PCC"	  : "-"),
 		((m->status & MCI_STATUS_ADDRV)	? "AddrV" : "-"));
 
-	if (c->x86 == 0x15)
+	if (c->x86 == 0x15 || c->x86 == 0x16)
 		pr_cont("|%s|%s",
 			((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
 			((m->status & MCI_STATUS_POISON)   ? "Poison"   : "-"));
@@ -772,7 +817,7 @@
 	if (c->x86_vendor != X86_VENDOR_AMD)
 		return 0;
 
-	if (c->x86 < 0xf || c->x86 > 0x15)
+	if (c->x86 < 0xf || c->x86 > 0x16)
 		return 0;
 
 	fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
@@ -783,33 +828,46 @@
 	case 0xf:
 		fam_ops->mc0_mce = k8_mc0_mce;
 		fam_ops->mc1_mce = k8_mc1_mce;
+		fam_ops->mc2_mce = k8_mc2_mce;
 		break;
 
 	case 0x10:
 		fam_ops->mc0_mce = f10h_mc0_mce;
 		fam_ops->mc1_mce = k8_mc1_mce;
+		fam_ops->mc2_mce = k8_mc2_mce;
 		break;
 
 	case 0x11:
 		fam_ops->mc0_mce = k8_mc0_mce;
 		fam_ops->mc1_mce = k8_mc1_mce;
+		fam_ops->mc2_mce = k8_mc2_mce;
 		break;
 
 	case 0x12:
 		fam_ops->mc0_mce = f12h_mc0_mce;
 		fam_ops->mc1_mce = k8_mc1_mce;
+		fam_ops->mc2_mce = k8_mc2_mce;
 		break;
 
 	case 0x14:
 		nb_err_cpumask  = 0x3;
-		fam_ops->mc0_mce = f14h_mc0_mce;
-		fam_ops->mc1_mce = f14h_mc1_mce;
+		fam_ops->mc0_mce = cat_mc0_mce;
+		fam_ops->mc1_mce = cat_mc1_mce;
+		fam_ops->mc2_mce = k8_mc2_mce;
 		break;
 
 	case 0x15:
 		xec_mask = 0x1f;
 		fam_ops->mc0_mce = f15h_mc0_mce;
 		fam_ops->mc1_mce = f15h_mc1_mce;
+		fam_ops->mc2_mce = f15h_mc2_mce;
+		break;
+
+	case 0x16:
+		xec_mask = 0x1f;
+		fam_ops->mc0_mce = cat_mc0_mce;
+		fam_ops->mc1_mce = cat_mc1_mce;
+		fam_ops->mc2_mce = f16h_mc2_mce;
 		break;
 
 	default:
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 6796799..51b7e3a 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -14,6 +14,7 @@
 #define TLB_ERROR(x)			(((x) & 0xFFF0) == 0x0010)
 #define MEM_ERROR(x)			(((x) & 0xFF00) == 0x0100)
 #define BUS_ERROR(x)			(((x) & 0xF800) == 0x0800)
+#define INT_ERROR(x)			(((x) & 0xF4FF) == 0x0400)
 
 #define TT(x)				(((x) >> 2) & 0x3)
 #define TT_MSG(x)			tt_msgs[TT(x)]
@@ -25,6 +26,8 @@
 #define TO_MSG(x)			to_msgs[TO(x)]
 #define PP(x)				(((x) >> 9) & 0x3)
 #define PP_MSG(x)			pp_msgs[PP(x)]
+#define UU(x)				(((x) >> 8) & 0x3)
+#define UU_MSG(x)			uu_msgs[UU(x)]
 
 #define R4(x)				(((x) >> 4) & 0xf)
 #define R4_MSG(x)			((R4(x) < 9) ?  rrrr_msgs[R4(x)] : "Wrong R4!")
@@ -32,6 +35,8 @@
 #define MCI_STATUS_DEFERRED		BIT_64(44)
 #define MCI_STATUS_POISON		BIT_64(43)
 
+extern const char * const pp_msgs[];
+
 enum tt_ids {
 	TT_INSTR = 0,
 	TT_DATA,
@@ -65,19 +70,13 @@
 	R4_SNOOP,
 };
 
-extern const char * const tt_msgs[];
-extern const char * const ll_msgs[];
-extern const char * const rrrr_msgs[];
-extern const char * const pp_msgs[];
-extern const char * const to_msgs[];
-extern const char * const ii_msgs[];
-
 /*
  * per-family decoder ops
  */
 struct amd_decoder_ops {
 	bool (*mc0_mce)(u16, u8);
 	bool (*mc1_mce)(u16, u8);
+	bool (*mc2_mce)(u16, u8);
 };
 
 void amd_report_gart_errors(bool);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 42a840d..3eb32f6 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -301,7 +301,7 @@
 				       "[EDAC] PCI err", pci);
 		if (res < 0) {
 			printk(KERN_ERR
-			       "%s: Unable to requiest irq %d for "
+			       "%s: Unable to request irq %d for "
 			       "MPC85xx PCI err\n", __func__, pdata->irq);
 			irq_dispose_mapping(pdata->irq);
 			res = -ENODEV;
@@ -583,7 +583,7 @@
 				       "[EDAC] L2 err", edac_dev);
 		if (res < 0) {
 			printk(KERN_ERR
-			       "%s: Unable to requiest irq %d for "
+			       "%s: Unable to request irq %d for "
 			       "MPC85xx L2 err\n", __func__, pdata->irq);
 			irq_dispose_mapping(pdata->irq);
 			res = -ENODEV;
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index e7a711f5..2b27bff 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -270,7 +270,7 @@
 	if (type == cpu_to_be16(ETH_P_802_3))
 		return -1;
 	net = neigh->dev;
-	h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h));
+	h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h)));
 	h->h_proto = type;
 	memcpy(h->h_dest, neigh->ha, net->addr_len);
 	hh->hh_len = FWNET_HLEN;
@@ -282,7 +282,7 @@
 static void fwnet_header_cache_update(struct hh_cache *hh,
 		const struct net_device *net, const unsigned char *haddr)
 {
-	memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len);
+	memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
 }
 
 static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
@@ -398,11 +398,11 @@
 
 	new->datagram_label = datagram_label;
 	new->datagram_size = dg_size;
-	new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15);
+	new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net));
 	if (new->skb == NULL)
 		goto fail_w_fi;
 
-	skb_reserve(new->skb, (net->hard_header_len + 15) & ~15);
+	skb_reserve(new->skb, LL_RESERVED_SPACE(net));
 	new->pbuf = skb_put(new->skb, dg_size);
 	memcpy(new->pbuf + frag_off, frag_buf, frag_len);
 	list_add_tail(&new->pd_link, &peer->pd_list);
@@ -520,7 +520,7 @@
 	dev = netdev_priv(net);
 	/* Write metadata, and then pass to the receive level */
 	skb->dev = net;
-	skb->ip_summed = CHECKSUM_UNNECESSARY;  /* don't check it */
+	skb->ip_summed = CHECKSUM_NONE;
 
 	/*
 	 * Parse the encapsulation header. This actually does the job of
@@ -690,14 +690,14 @@
 		buf++;
 		len -= RFC2374_UNFRAG_HDR_SIZE;
 
-		skb = dev_alloc_skb(len + net->hard_header_len + 15);
+		skb = dev_alloc_skb(len + LL_RESERVED_SPACE(net));
 		if (unlikely(!skb)) {
 			dev_err(&net->dev, "out of memory\n");
 			net->stats.rx_dropped++;
 
 			return -ENOMEM;
 		}
-		skb_reserve(skb, (net->hard_header_len + 15) & ~15);
+		skb_reserve(skb, LL_RESERVED_SPACE(net));
 		memcpy(skb_put(skb, len), buf, len);
 
 		return fwnet_finish_incoming_packet(net, skb, source_node_id,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 682de75..e5116fa 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -657,12 +657,6 @@
 	  This driver provides support for driving the pins in output
 	  mode only. Input mode is not supported.
 
-config GPIO_AB8500
-	bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions"
-	depends on AB8500_CORE && BROKEN
-	help
-	  Select this to enable the AB8500 IC GPIO driver
-
 config GPIO_TPS6586X
 	bool "TPS6586X GPIO"
 	depends on MFD_TPS6586X
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c5aebd0..45a388c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,7 +10,6 @@
 obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o
 
 obj-$(CONFIG_GPIO_74X164)	+= gpio-74x164.o
-obj-$(CONFIG_GPIO_AB8500)	+= gpio-ab8500.o
 obj-$(CONFIG_GPIO_ADNP)		+= gpio-adnp.o
 obj-$(CONFIG_GPIO_ADP5520)	+= gpio-adp5520.o
 obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp5588.o
diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c
deleted file mode 100644
index 983ad42..0000000
--- a/drivers/gpio/gpio-ab8500.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * Author: BIBEK BASU <bibek.basu@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- *
- * 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 <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/ab8500.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpio.h>
-
-/*
- * GPIO registers offset
- * Bank: 0x10
- */
-#define AB8500_GPIO_SEL1_REG	0x00
-#define AB8500_GPIO_SEL2_REG	0x01
-#define AB8500_GPIO_SEL3_REG	0x02
-#define AB8500_GPIO_SEL4_REG	0x03
-#define AB8500_GPIO_SEL5_REG	0x04
-#define AB8500_GPIO_SEL6_REG	0x05
-
-#define AB8500_GPIO_DIR1_REG	0x10
-#define AB8500_GPIO_DIR2_REG	0x11
-#define AB8500_GPIO_DIR3_REG	0x12
-#define AB8500_GPIO_DIR4_REG	0x13
-#define AB8500_GPIO_DIR5_REG	0x14
-#define AB8500_GPIO_DIR6_REG	0x15
-
-#define AB8500_GPIO_OUT1_REG	0x20
-#define AB8500_GPIO_OUT2_REG	0x21
-#define AB8500_GPIO_OUT3_REG	0x22
-#define AB8500_GPIO_OUT4_REG	0x23
-#define AB8500_GPIO_OUT5_REG	0x24
-#define AB8500_GPIO_OUT6_REG	0x25
-
-#define AB8500_GPIO_PUD1_REG	0x30
-#define AB8500_GPIO_PUD2_REG	0x31
-#define AB8500_GPIO_PUD3_REG	0x32
-#define AB8500_GPIO_PUD4_REG	0x33
-#define AB8500_GPIO_PUD5_REG	0x34
-#define AB8500_GPIO_PUD6_REG	0x35
-
-#define AB8500_GPIO_IN1_REG	0x40
-#define AB8500_GPIO_IN2_REG	0x41
-#define AB8500_GPIO_IN3_REG	0x42
-#define AB8500_GPIO_IN4_REG	0x43
-#define AB8500_GPIO_IN5_REG	0x44
-#define AB8500_GPIO_IN6_REG	0x45
-#define AB8500_GPIO_ALTFUN_REG	0x45
-#define ALTFUN_REG_INDEX	6
-#define AB8500_NUM_GPIO		42
-#define AB8500_NUM_VIR_GPIO_IRQ	16
-
-enum ab8500_gpio_action {
-	NONE,
-	STARTUP,
-	SHUTDOWN,
-	MASK,
-	UNMASK
-};
-
-struct ab8500_gpio {
-	struct gpio_chip chip;
-	struct ab8500 *parent;
-	struct device *dev;
-	struct mutex lock;
-	u32 irq_base;
-	enum ab8500_gpio_action irq_action;
-	u16 rising;
-	u16 falling;
-};
-/**
- * to_ab8500_gpio() - get the pointer to ab8500_gpio
- * @chip:	Member of the structure ab8500_gpio
- */
-static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct ab8500_gpio, chip);
-}
-
-static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
-					unsigned offset, int val)
-{
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	u8 pos = offset % 8;
-	int ret;
-
-	reg = reg + (offset / 8);
-	ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev,
-				AB8500_MISC, reg, 1 << pos, val << pos);
-	if (ret < 0)
-		dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
-	return ret;
-}
-/**
- * ab8500_gpio_get() - Get the particular GPIO value
- * @chip: Gpio device
- * @offset: GPIO number to read
- */
-static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	u8 mask = 1 << (offset % 8);
-	u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8);
-	int ret;
-	u8 data;
-	ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
-						reg, &data);
-	if (ret < 0) {
-		dev_err(ab8500_gpio->dev, "%s read failed\n", __func__);
-		return ret;
-	}
-	return (data & mask) >> (offset % 8);
-}
-
-static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	int ret;
-	/* Write the data */
-	ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1);
-	if (ret < 0)
-		dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
-}
-
-static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-					int val)
-{
-	int ret;
-	/* set direction as output */
-	ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
-	if (ret < 0)
-		return ret;
-	/* disable pull down */
-	ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
-	if (ret < 0)
-		return ret;
-	/* set the output as 1 or 0 */
-	return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
-
-}
-
-static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-	/* set the register as input */
-	return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
-}
-
-static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	/*
-	 * Only some GPIOs are interrupt capable, and they are
-	 * organized in discontiguous clusters:
-	 *
-	 *	GPIO6 to GPIO13
-	 *	GPIO24 and GPIO25
-	 *	GPIO36 to GPIO41
-	 */
-	static struct ab8500_gpio_irq_cluster {
-		int start;
-		int end;
-	} clusters[] = {
-		{.start = 6,  .end = 13},
-		{.start = 24, .end = 25},
-		{.start = 36, .end = 41},
-	};
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	int base = ab8500_gpio->irq_base;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(clusters); i++) {
-		struct ab8500_gpio_irq_cluster *cluster = &clusters[i];
-
-		if (offset >= cluster->start && offset <= cluster->end)
-			return base + offset - cluster->start;
-
-		/* Advance by the number of gpios in this cluster */
-		base += cluster->end - cluster->start + 1;
-	}
-
-	return -EINVAL;
-}
-
-static struct gpio_chip ab8500gpio_chip = {
-	.label			= "ab8500_gpio",
-	.owner			= THIS_MODULE,
-	.direction_input	= ab8500_gpio_direction_input,
-	.get			= ab8500_gpio_get,
-	.direction_output	= ab8500_gpio_direction_output,
-	.set			= ab8500_gpio_set,
-	.to_irq			= ab8500_gpio_to_irq,
-};
-
-static unsigned int irq_to_rising(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-	int new_irq = offset +  AB8500_INT_GPIO6R
-			+ ab8500_gpio->parent->irq_base;
-	return new_irq;
-}
-
-static unsigned int irq_to_falling(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-	int new_irq = offset +  AB8500_INT_GPIO6F
-			+  ab8500_gpio->parent->irq_base;
-	return new_irq;
-
-}
-
-static unsigned int rising_to_irq(unsigned int irq, void *dev)
-{
-	struct ab8500_gpio *ab8500_gpio = dev;
-	int offset = irq - AB8500_INT_GPIO6R
-			- ab8500_gpio->parent->irq_base ;
-	int new_irq = offset + ab8500_gpio->irq_base;
-	return new_irq;
-}
-
-static unsigned int falling_to_irq(unsigned int irq, void *dev)
-{
-	struct ab8500_gpio *ab8500_gpio = dev;
-	int offset = irq - AB8500_INT_GPIO6F
-			- ab8500_gpio->parent->irq_base ;
-	int new_irq = offset + ab8500_gpio->irq_base;
-	return new_irq;
-
-}
-
-/*
- * IRQ handler
- */
-
-static irqreturn_t handle_rising(int irq, void *dev)
-{
-
-	handle_nested_irq(rising_to_irq(irq , dev));
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t handle_falling(int irq, void *dev)
-{
-
-	handle_nested_irq(falling_to_irq(irq, dev));
-	return IRQ_HANDLED;
-}
-
-static void ab8500_gpio_irq_lock(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	mutex_lock(&ab8500_gpio->lock);
-}
-
-static void ab8500_gpio_irq_sync_unlock(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-	bool rising = ab8500_gpio->rising & BIT(offset);
-	bool falling = ab8500_gpio->falling & BIT(offset);
-	int ret;
-
-	switch (ab8500_gpio->irq_action)	{
-	case STARTUP:
-		if (rising)
-			ret = request_threaded_irq(irq_to_rising(irq),
-					NULL, handle_rising,
-					IRQF_TRIGGER_RISING,
-					"ab8500-gpio-r", ab8500_gpio);
-		if (falling)
-			ret = request_threaded_irq(irq_to_falling(irq),
-				       NULL, handle_falling,
-				       IRQF_TRIGGER_FALLING,
-				       "ab8500-gpio-f", ab8500_gpio);
-		break;
-	case SHUTDOWN:
-		if (rising)
-			free_irq(irq_to_rising(irq), ab8500_gpio);
-		if (falling)
-			free_irq(irq_to_falling(irq), ab8500_gpio);
-		break;
-	case MASK:
-		if (rising)
-			disable_irq(irq_to_rising(irq));
-		if (falling)
-			disable_irq(irq_to_falling(irq));
-		break;
-	case UNMASK:
-		if (rising)
-			enable_irq(irq_to_rising(irq));
-		if (falling)
-			enable_irq(irq_to_falling(irq));
-		break;
-	case NONE:
-		break;
-	}
-	ab8500_gpio->irq_action = NONE;
-	ab8500_gpio->rising &= ~(BIT(offset));
-	ab8500_gpio->falling &= ~(BIT(offset));
-	mutex_unlock(&ab8500_gpio->lock);
-}
-
-
-static void ab8500_gpio_irq_mask(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = MASK;
-}
-
-static void ab8500_gpio_irq_unmask(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = UNMASK;
-}
-
-static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-
-	if (type == IRQ_TYPE_EDGE_BOTH) {
-		ab8500_gpio->rising =  BIT(offset);
-		ab8500_gpio->falling = BIT(offset);
-	} else if (type == IRQ_TYPE_EDGE_RISING) {
-		ab8500_gpio->rising =  BIT(offset);
-	} else  {
-		ab8500_gpio->falling = BIT(offset);
-	}
-	return 0;
-}
-
-unsigned int ab8500_gpio_irq_startup(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = STARTUP;
-	return 0;
-}
-
-void ab8500_gpio_irq_shutdown(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = SHUTDOWN;
-}
-
-static struct irq_chip ab8500_gpio_irq_chip = {
-	.name			= "ab8500-gpio",
-	.startup		= ab8500_gpio_irq_startup,
-	.shutdown		= ab8500_gpio_irq_shutdown,
-	.bus_lock		= ab8500_gpio_irq_lock,
-	.bus_sync_unlock	= ab8500_gpio_irq_sync_unlock,
-	.mask			= ab8500_gpio_irq_mask,
-	.unmask			= ab8500_gpio_irq_unmask,
-	.set_type		= ab8500_gpio_irq_set_type,
-};
-
-static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio)
-{
-	u32 base = ab8500_gpio->irq_base;
-	int irq;
-
-	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
-		set_irq_chip_data(irq, ab8500_gpio);
-		set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip,
-				handle_simple_irq);
-		set_irq_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
-		set_irq_flags(irq, IRQF_VALID);
-#else
-		set_irq_noprobe(irq);
-#endif
-	}
-
-	return 0;
-}
-
-static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio)
-{
-	int base = ab8500_gpio->irq_base;
-	int irq;
-
-	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
-#ifdef CONFIG_ARM
-		set_irq_flags(irq, 0);
-#endif
-		set_irq_chip_and_handler(irq, NULL, NULL);
-		set_irq_chip_data(irq, NULL);
-	}
-}
-
-static int ab8500_gpio_probe(struct platform_device *pdev)
-{
-	struct ab8500_platform_data *ab8500_pdata =
-				dev_get_platdata(pdev->dev.parent);
-	struct ab8500_gpio_platform_data *pdata;
-	struct ab8500_gpio *ab8500_gpio;
-	int ret;
-	int i;
-
-	pdata = ab8500_pdata->gpio;
-	if (!pdata)	{
-		dev_err(&pdev->dev, "gpio platform data missing\n");
-		return -ENODEV;
-	}
-
-	ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL);
-	if (ab8500_gpio == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return -ENOMEM;
-	}
-	ab8500_gpio->dev = &pdev->dev;
-	ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent);
-	ab8500_gpio->chip = ab8500gpio_chip;
-	ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO;
-	ab8500_gpio->chip.dev = &pdev->dev;
-	ab8500_gpio->chip.base = pdata->gpio_base;
-	ab8500_gpio->irq_base = pdata->irq_base;
-	/* initialize the lock */
-	mutex_init(&ab8500_gpio->lock);
-	/*
-	 * AB8500 core will handle and clear the IRQ
-	 * configre GPIO based on config-reg value.
-	 * These values are for selecting the PINs as
-	 * GPIO or alternate function
-	 */
-	for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++)	{
-		ret = abx500_set_register_interruptible(ab8500_gpio->dev,
-				AB8500_MISC, i,
-				pdata->config_reg[i]);
-		if (ret < 0)
-			goto out_free;
-	}
-	ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
-				AB8500_GPIO_ALTFUN_REG,
-				pdata->config_reg[ALTFUN_REG_INDEX]);
-	if (ret < 0)
-		goto out_free;
-
-	ret = ab8500_gpio_irq_init(ab8500_gpio);
-	if (ret)
-		goto out_free;
-	ret = gpiochip_add(&ab8500_gpio->chip);
-	if (ret) {
-		dev_err(&pdev->dev, "unable to add gpiochip: %d\n",
-				ret);
-		goto out_rem_irq;
-	}
-	platform_set_drvdata(pdev, ab8500_gpio);
-	return 0;
-
-out_rem_irq:
-	ab8500_gpio_irq_remove(ab8500_gpio);
-out_free:
-	mutex_destroy(&ab8500_gpio->lock);
-	kfree(ab8500_gpio);
-	return ret;
-}
-
-/*
- * ab8500_gpio_remove() - remove Ab8500-gpio driver
- * @pdev :	Platform device registered
- */
-static int ab8500_gpio_remove(struct platform_device *pdev)
-{
-	struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev);
-	int ret;
-
-	ret = gpiochip_remove(&ab8500_gpio->chip);
-	if (ret < 0) {
-		dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n",
-			ret);
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, NULL);
-	mutex_destroy(&ab8500_gpio->lock);
-	kfree(ab8500_gpio);
-
-	return 0;
-}
-
-static struct platform_driver ab8500_gpio_driver = {
-	.driver = {
-		.name = "ab8500-gpio",
-		.owner = THIS_MODULE,
-	},
-	.probe = ab8500_gpio_probe,
-	.remove = ab8500_gpio_remove,
-};
-
-static int __init ab8500_gpio_init(void)
-{
-	return platform_driver_register(&ab8500_gpio_driver);
-}
-arch_initcall(ab8500_gpio_init);
-
-static void __exit ab8500_gpio_exit(void)
-{
-	platform_driver_unregister(&ab8500_gpio_driver);
-}
-module_exit(ab8500_gpio_exit);
-
-MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>");
-MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO");
-MODULE_ALIAS("platform:ab8500-gpio");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index d542a14..a71a54a 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -89,41 +89,6 @@
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
 /**
- * of_gpio_named_count - Count GPIOs for a device
- * @np:		device node to count GPIOs for
- * @propname:	property name containing gpio specifier(s)
- *
- * The function returns the count of GPIOs specified for a node.
- *
- * Note that the empty GPIO specifiers counts too. For example,
- *
- * gpios = <0
- *          &pio1 1 2
- *          0
- *          &pio2 3 4>;
- *
- * defines four GPIOs (so this function will return 4), two of which
- * are not specified.
- */
-unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
-{
-	unsigned int cnt = 0;
-
-	do {
-		int ret;
-
-		ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
-						 cnt, NULL);
-		/* A hole in the gpios = <> counts anyway. */
-		if (ret < 0 && ret != -EEXIST)
-			break;
-	} while (++cnt);
-
-	return cnt;
-}
-EXPORT_SYMBOL(of_gpio_named_count);
-
-/**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
  * @gc:		pointer to the gpio_chip structure
  * @np:		device node of the GPIO chip
@@ -250,7 +215,7 @@
 		 * on the same GPIO chip.
 		 */
 		ret = gpiochip_add_pin_range(chip,
-					     pinctrl_dev_get_name(pctldev),
+					     pinctrl_dev_get_devname(pctldev),
 					     0, /* offset in gpiochip */
 					     pinspec.args[0],
 					     pinspec.args[1]);
diff --git a/drivers/gpu/drm/nouveau/core/core/falcon.c b/drivers/gpu/drm/nouveau/core/core/falcon.c
index 6b0843c..e05c157 100644
--- a/drivers/gpu/drm/nouveau/core/core/falcon.c
+++ b/drivers/gpu/drm/nouveau/core/core/falcon.c
@@ -73,8 +73,11 @@
 	nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
 
 	/* wait for 'uc halted' to be signalled before continuing */
-	if (falcon->secret) {
-		nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+	if (falcon->secret && falcon->version < 4) {
+		if (!falcon->version)
+			nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+		else
+			nv_wait(falcon, 0x180, 0x80000000, 0);
 		nv_wo32(falcon, 0x004, 0x00000010);
 	}
 
diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c
index f74c30a..48f0637 100644
--- a/drivers/gpu/drm/nouveau/core/core/subdev.c
+++ b/drivers/gpu/drm/nouveau/core/core/subdev.c
@@ -99,7 +99,7 @@
 	if (ret)
 		return ret;
 
-	mutex_init(&subdev->mutex);
+	__mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
 	subdev->name = subname;
 
 	if (parent) {
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h
index 5982935..106bb19 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/object.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/object.h
@@ -50,10 +50,13 @@
 
 extern struct nouveau_ofuncs nouveau_object_ofuncs;
 
+/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
+ * ".data". */
 struct nouveau_oclass {
 	u32 handle;
-	struct nouveau_ofuncs *ofuncs;
-	struct nouveau_omthds *omthds;
+	struct nouveau_ofuncs * const ofuncs;
+	struct nouveau_omthds * const omthds;
+	struct lock_class_key lock_class_key;
 };
 
 #define nv_oclass(o)    nv_object(o)->oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
index d6d1600..d62045f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
@@ -86,8 +86,8 @@
 			return ret;
 	}
 
-	if (!nouveau_mm_initialised(&pfb->tags) && tags) {
-		ret = nouveau_mm_init(&pfb->tags, 0, ++tags, 1);
+	if (!nouveau_mm_initialised(&pfb->tags)) {
+		ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index 487cb8c..eac236e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -99,7 +99,7 @@
 	struct nouveau_bios *bios = nouveau_bios(device);
 	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
 	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-	u32 size;
+	u32 size, tags = 0;
 	int ret;
 
 	pfb->ram.size = nv_rd32(pfb, 0x10020c);
@@ -140,10 +140,11 @@
 			return ret;
 
 		pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+		tags = nv_rd32(pfb, 0x100320);
 		break;
 	}
 
-	return nv_rd32(pfb, 0x100320);
+	return tags;
 }
 
 static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 69d7b1d..1699a90 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -28,6 +28,7 @@
  */
 
 #include <core/engine.h>
+#include <linux/swiotlb.h>
 
 #include <subdev/fb.h>
 #include <subdev/vm.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 8b090f1..5e7aef2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -245,6 +245,8 @@
 	return 0;
 }
 
+static struct lock_class_key drm_client_lock_class_key;
+
 static int
 nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 {
@@ -256,6 +258,7 @@
 	ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
 	if (ret)
 		return ret;
+	lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
 
 	dev->dev_private = drm;
 	drm->dev = dev;
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 7a44566..ee4cff5 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -2909,14 +2909,14 @@
 				return -EINVAL;
 			}
 			if (tiled) {
-				dst_offset = ib[idx+1];
+				dst_offset = radeon_get_ib_value(p, idx+1);
 				dst_offset <<= 8;
 
 				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
 				p->idx += count + 7;
 			} else {
-				dst_offset = ib[idx+1];
-				dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32;
+				dst_offset = radeon_get_ib_value(p, idx+1);
+				dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
 
 				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 				ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
@@ -2954,12 +2954,12 @@
 							DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
 							return -EINVAL;
 						}
-						dst_offset = ib[idx+1];
+						dst_offset = radeon_get_ib_value(p, idx+1);
 						dst_offset <<= 8;
-						dst2_offset = ib[idx+2];
+						dst2_offset = radeon_get_ib_value(p, idx+2);
 						dst2_offset <<= 8;
-						src_offset = ib[idx+8];
-						src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+						src_offset = radeon_get_ib_value(p, idx+8);
+						src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
 						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
 							dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n",
 								 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3014,12 +3014,12 @@
 							DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
 							return -EINVAL;
 						}
-						dst_offset = ib[idx+1];
+						dst_offset = radeon_get_ib_value(p, idx+1);
 						dst_offset <<= 8;
-						dst2_offset = ib[idx+2];
+						dst2_offset = radeon_get_ib_value(p, idx+2);
 						dst2_offset <<= 8;
-						src_offset = ib[idx+8];
-						src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+						src_offset = radeon_get_ib_value(p, idx+8);
+						src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
 						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
 							dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n",
 								 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3046,22 +3046,22 @@
 						/* detile bit */
 						if (idx_value & (1 << 31)) {
 							/* tiled src, linear dst */
-							src_offset = ib[idx+1];
+							src_offset = radeon_get_ib_value(p, idx+1);
 							src_offset <<= 8;
 							ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
 
-							dst_offset = ib[idx+7];
-							dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+							dst_offset = radeon_get_ib_value(p, idx+7);
+							dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
 							ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 							ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
 						} else {
 							/* linear src, tiled dst */
-							src_offset = ib[idx+7];
-							src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+							src_offset = radeon_get_ib_value(p, idx+7);
+							src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
 							ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
 							ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 
-							dst_offset = ib[idx+1];
+							dst_offset = radeon_get_ib_value(p, idx+1);
 							dst_offset <<= 8;
 							ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
 						}
@@ -3098,12 +3098,12 @@
 							DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
 							return -EINVAL;
 						}
-						dst_offset = ib[idx+1];
+						dst_offset = radeon_get_ib_value(p, idx+1);
 						dst_offset <<= 8;
-						dst2_offset = ib[idx+2];
+						dst2_offset = radeon_get_ib_value(p, idx+2);
 						dst2_offset <<= 8;
-						src_offset = ib[idx+8];
-						src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+						src_offset = radeon_get_ib_value(p, idx+8);
+						src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
 						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
 							dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n",
 								 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3135,22 +3135,22 @@
 						/* detile bit */
 						if (idx_value & (1 << 31)) {
 							/* tiled src, linear dst */
-							src_offset = ib[idx+1];
+							src_offset = radeon_get_ib_value(p, idx+1);
 							src_offset <<= 8;
 							ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
 
-							dst_offset = ib[idx+7];
-							dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+							dst_offset = radeon_get_ib_value(p, idx+7);
+							dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
 							ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 							ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
 						} else {
 							/* linear src, tiled dst */
-							src_offset = ib[idx+7];
-							src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+							src_offset = radeon_get_ib_value(p, idx+7);
+							src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
 							ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
 							ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 
-							dst_offset = ib[idx+1];
+							dst_offset = radeon_get_ib_value(p, idx+1);
 							dst_offset <<= 8;
 							ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
 						}
@@ -3176,10 +3176,10 @@
 					switch (misc) {
 					case 0:
 						/* L2L, byte */
-						src_offset = ib[idx+2];
-						src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-						dst_offset = ib[idx+1];
-						dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+						src_offset = radeon_get_ib_value(p, idx+2);
+						src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+						dst_offset = radeon_get_ib_value(p, idx+1);
+						dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
 						if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) {
 							dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n",
 								 src_offset + count, radeon_bo_size(src_reloc->robj));
@@ -3216,12 +3216,12 @@
 							DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n");
 							return -EINVAL;
 						}
-						dst_offset = ib[idx+1];
-						dst_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-						dst2_offset = ib[idx+2];
-						dst2_offset |= ((u64)(ib[idx+5] & 0xff)) << 32;
-						src_offset = ib[idx+3];
-						src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+						dst_offset = radeon_get_ib_value(p, idx+1);
+						dst_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+						dst2_offset = radeon_get_ib_value(p, idx+2);
+						dst2_offset |= ((u64)(radeon_get_ib_value(p, idx+5) & 0xff)) << 32;
+						src_offset = radeon_get_ib_value(p, idx+3);
+						src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
 						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
 							dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n",
 								 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3251,10 +3251,10 @@
 					}
 				} else {
 					/* L2L, dw */
-					src_offset = ib[idx+2];
-					src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-					dst_offset = ib[idx+1];
-					dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+					src_offset = radeon_get_ib_value(p, idx+2);
+					src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+					dst_offset = radeon_get_ib_value(p, idx+1);
+					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
 					if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
 						dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n",
 							 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3279,8 +3279,8 @@
 				DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n");
 				return -EINVAL;
 			}
-			dst_offset = ib[idx+1];
-			dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16;
+			dst_offset = radeon_get_ib_value(p, idx+1);
+			dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
 			if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
 				dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n",
 					 dst_offset, radeon_bo_size(dst_reloc->robj));
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 69ec24a..9b2512b 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -2623,14 +2623,14 @@
 				return -EINVAL;
 			}
 			if (tiled) {
-				dst_offset = ib[idx+1];
+				dst_offset = radeon_get_ib_value(p, idx+1);
 				dst_offset <<= 8;
 
 				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
 				p->idx += count + 5;
 			} else {
-				dst_offset = ib[idx+1];
-				dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32;
+				dst_offset = radeon_get_ib_value(p, idx+1);
+				dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
 
 				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 				ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
@@ -2658,32 +2658,32 @@
 				/* detile bit */
 				if (idx_value & (1 << 31)) {
 					/* tiled src, linear dst */
-					src_offset = ib[idx+1];
+					src_offset = radeon_get_ib_value(p, idx+1);
 					src_offset <<= 8;
 					ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
 
-					dst_offset = ib[idx+5];
-					dst_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+					dst_offset = radeon_get_ib_value(p, idx+5);
+					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
 					ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 					ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
 				} else {
 					/* linear src, tiled dst */
-					src_offset = ib[idx+5];
-					src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+					src_offset = radeon_get_ib_value(p, idx+5);
+					src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
 					ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
 					ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 
-					dst_offset = ib[idx+1];
+					dst_offset = radeon_get_ib_value(p, idx+1);
 					dst_offset <<= 8;
 					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
 				}
 				p->idx += 7;
 			} else {
 				if (p->family >= CHIP_RV770) {
-					src_offset = ib[idx+2];
-					src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-					dst_offset = ib[idx+1];
-					dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+					src_offset = radeon_get_ib_value(p, idx+2);
+					src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+					dst_offset = radeon_get_ib_value(p, idx+1);
+					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
 
 					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 					ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
@@ -2691,10 +2691,10 @@
 					ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 					p->idx += 5;
 				} else {
-					src_offset = ib[idx+2];
-					src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
-					dst_offset = ib[idx+1];
-					dst_offset |= ((u64)(ib[idx+3] & 0xff0000)) << 16;
+					src_offset = radeon_get_ib_value(p, idx+2);
+					src_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
+					dst_offset = radeon_get_ib_value(p, idx+1);
+					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff0000)) << 16;
 
 					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
 					ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
@@ -2724,8 +2724,8 @@
 				DRM_ERROR("bad DMA_PACKET_WRITE\n");
 				return -EINVAL;
 			}
-			dst_offset = ib[idx+1];
-			dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16;
+			dst_offset = radeon_get_ib_value(p, idx+1);
+			dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
 			if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
 				dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n",
 					 dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 1d8ff2f..93f760e 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -38,6 +38,7 @@
 #include <drm/radeon_drm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/swiotlb.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index b38ef6d..64630f1 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -2,7 +2,7 @@
 
 config HYPERV
 	tristate "Microsoft Hyper-V client drivers"
-	depends on X86 && ACPI && PCI
+	depends on X86 && ACPI && PCI && X86_LOCAL_APIC
 	help
 	  Select this option to run Linux as a Hyper-V client operating
 	  system.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 32f238f..89ac1cb 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -180,11 +180,11 @@
 	  will be called adm9240.
 
 config SENSORS_ADT7410
-	tristate "Analog Devices ADT7410"
+	tristate "Analog Devices ADT7410/ADT7420"
 	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
-	  ADT7410 temperature monitoring chip.
+	  ADT7410 and ADT7420 temperature monitoring chips.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called adt7410.
@@ -506,7 +506,8 @@
 	help
 	  If you say yes here you get support for ITE IT8705F, IT8712F,
 	  IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
-	  IT8782F, and IT8783E/F sensor chips, and the SiS950 clone.
+	  IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the
+	  SiS950 clone.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called it87.
@@ -529,8 +530,8 @@
 	  temperature sensors, which are used on many DDR3 memory modules for
 	  mobile devices and servers.  Support will include, but not be limited
 	  to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
-	  MCP98242, MCP98243, MCP9843, SE97, SE98, STTS424(E), STTS2002,
-	  STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
+	  MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E),
+	  STTS2002, STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called jc42.
@@ -854,6 +855,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called max6650.
 
+config SENSORS_MAX6697
+	tristate "Maxim MAX6697 and compatibles"
+	depends on I2C
+	help
+	  If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+	  MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+	  temperature sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max6697.
+
 config SENSORS_MCP3021
 	tristate "Microchip MCP3021 and compatibles"
 	depends on I2C
@@ -1145,6 +1157,16 @@
 	  This driver can also be build as a module.  If so, the module
 	  will be called amc6821.
 
+config SENSORS_INA209
+	tristate "TI / Burr Brown INA209"
+	depends on I2C
+	help
+	  If you say yes here you get support for the TI / Burr Brown INA209
+	  voltage / current / power monitor I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ina209.
+
 config SENSORS_INA2XX
 	tristate "Texas Instruments INA219 and compatibles"
 	depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 5da2874..8d6d97e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -65,6 +65,7 @@
 obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
+obj-$(CONFIG_SENSORS_INA209)	+= ina209.o
 obj-$(CONFIG_SENSORS_INA2XX)	+= ina2xx.o
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_JC42)	+= jc42.o
@@ -99,6 +100,7 @@
 obj-$(CONFIG_SENSORS_MAX6639)	+= max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)	+= max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
+obj-$(CONFIG_SENSORS_MAX6697)	+= max6697.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MCP3021)	+= mcp3021.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 1672e2a..6351aba 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -911,7 +911,7 @@
 	return res;
 }
 
-static int acpi_power_meter_remove(struct acpi_device *device, int type)
+static int acpi_power_meter_remove(struct acpi_device *device)
 {
 	struct acpi_power_meter_resource *resource;
 
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index f3a5d47..5d501ad 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -137,7 +137,7 @@
 	if (ret < 0)
 		return ret;
 
-	temp = SENSORS_LIMIT(temp, -40000, 85000);
+	temp = clamp_val(temp, -40000, 85000);
 	temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
 
 	mutex_lock(&data->lock);
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index fd1d1b1..71bcba8a 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -193,7 +193,7 @@
 	temp /= 1000;
 
 	mutex_lock(&data->update_lock);
-	data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
+	data->temp_max[index] = clamp_val(temp, -128, 127);
 	if (!read_only)
 		i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
 					  data->temp_max[index]);
@@ -218,7 +218,7 @@
 	temp /= 1000;
 
 	mutex_lock(&data->update_lock);
-	data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
+	data->temp_min[index] = clamp_val(temp, -128, 127);
 	if (!read_only)
 		i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
 					  data->temp_min[index]);
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 0f068e7..ea09046 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -197,7 +197,7 @@
 	};
 #define NEG12_OFFSET  16000
 #define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n, val)  (SENSORS_LIMIT(SCALE(val, adm1026_scaling[n], 192),\
+#define INS_TO_REG(n, val)  (clamp_val(SCALE(val, adm1026_scaling[n], 192),\
 	0, 255))
 #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
 
@@ -207,7 +207,7 @@
  *      22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
  */
 #define FAN_TO_REG(val, div)  ((val) <= 0 ? 0xff : \
-				SENSORS_LIMIT(1350000 / ((val) * (div)), \
+				clamp_val(1350000 / ((val) * (div)), \
 					      1, 254))
 #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \
 				1350000 / ((val) * (div)))
@@ -215,14 +215,14 @@
 #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
 
 /* Temperature is reported in 1 degC increments */
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
+#define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
 					/ 1000, -127, 127))
 #define TEMP_FROM_REG(val) ((val) * 1000)
-#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
+#define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
 					  / 1000, -127, 127))
 #define OFFSET_FROM_REG(val) ((val) * 1000)
 
-#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255))
+#define PWM_TO_REG(val) (clamp_val(val, 0, 255))
 #define PWM_FROM_REG(val) (val)
 
 #define PWM_MIN_TO_REG(val) ((val) & 0xf0)
@@ -233,7 +233,7 @@
  *   indicates that the DAC could be used to drive the fans, but in our
  *   example board (Arima HDAMA) it isn't connected to the fans at all.
  */
-#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val) * 255) + 500) / 2500), 0, 255))
+#define DAC_TO_REG(val) (clamp_val(((((val) * 255) + 500) / 2500), 0, 255))
 #define DAC_FROM_REG(val) (((val) * 2500) / 255)
 
 /*
@@ -933,7 +933,7 @@
 		return;
 
 	new_min = data->fan_min[fan] * old_div / new_div;
-	new_min = SENSORS_LIMIT(new_min, 1, 254);
+	new_min = clamp_val(new_min, 1, 254);
 	data->fan_min[fan] = new_min;
 	adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min);
 }
@@ -1527,7 +1527,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255);
+	data->pwm1.auto_pwm_min = clamp_val(val, 0, 255);
 	if (data->pwm1.enable == 2) { /* apply immediately */
 		data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
 			PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index c6a4631..253ea39 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -162,13 +162,13 @@
 static int FAN_TO_REG(int reg, int div)
 {
 	int tmp;
-	tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div);
+	tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
 	return tmp > 255 ? 255 : tmp;
 }
 
 #define FAN_DIV_FROM_REG(reg)		(1<<(((reg)&0xc0)>>6))
 
-#define PWM_TO_REG(val)			(SENSORS_LIMIT((val), 0, 255) >> 4)
+#define PWM_TO_REG(val)			(clamp_val((val), 0, 255) >> 4)
 #define PWM_FROM_REG(val)		((val) << 4)
 
 #define FAN_CHAN_FROM_REG(reg)		(((reg) >> 5) & 7)
@@ -675,7 +675,7 @@
 	if (ret)
 		return ret;
 
-	val = SENSORS_LIMIT(val, -15000, 15000);
+	val = clamp_val(val, -15000, 15000);
 	mutex_lock(&data->update_lock);
 	data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
@@ -696,7 +696,7 @@
 	if (ret)
 		return ret;
 
-	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+	val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
 	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
@@ -717,7 +717,7 @@
 	if (ret)
 		return ret;
 
-	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+	val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
 	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
@@ -738,7 +738,7 @@
 	if (ret)
 		return ret;
 
-	val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+	val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
 	mutex_lock(&data->update_lock);
 	data->temp_crit[nr] = TEMP_TO_REG(val);
 	adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index dafa477..2416628 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -98,13 +98,13 @@
 
 static inline u8 IN_TO_REG(unsigned long val, int n)
 {
-	return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+	return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
 }
 
 /* temperature range: -40..125, 127 disables temperature alarm */
 static inline s8 TEMP_TO_REG(long val)
 {
-	return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
+	return clamp_val(SCALE(val, 1, 1000), -40, 127);
 }
 
 /* two fans, each with low fan speed limit */
@@ -122,7 +122,7 @@
 /* analog out 0..1250mV */
 static inline u8 AOUT_TO_REG(unsigned long val)
 {
-	return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
+	return clamp_val(SCALE(val, 255, 1250), 0, 255);
 }
 
 static inline unsigned int AOUT_FROM_REG(u8 reg)
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 409b5c1..ba962ac 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -163,9 +163,9 @@
 
 	/* Bound Vref with min/max values if it was provided */
 	if (data->vref_mv)
-		data->vref_mv = SENSORS_LIMIT(data->vref_mv,
-					      ADS7828_EXT_VREF_MV_MIN,
-					      ADS7828_EXT_VREF_MV_MAX);
+		data->vref_mv = clamp_val(data->vref_mv,
+					  ADS7828_EXT_VREF_MV_MIN,
+					  ADS7828_EXT_VREF_MV_MAX);
 	else
 		data->vref_mv = ADS7828_INT_VREF_MV;
 
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 030c8d7..99a7290 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -78,10 +78,6 @@
 	adt7410,
 };
 
-/* Addresses scanned */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-					I2C_CLIENT_END };
-
 static const u8 ADT7410_REG_TEMP[4] = {
 	ADT7410_TEMPERATURE,		/* input */
 	ADT7410_T_ALARM_HIGH,		/* high */
@@ -173,8 +169,8 @@
 
 static s16 ADT7410_TEMP_TO_REG(long temp)
 {
-	return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
-					       ADT7410_TEMP_MAX) * 128, 1000);
+	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
+					   ADT7410_TEMP_MAX) * 128, 1000);
 }
 
 static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
@@ -269,9 +265,9 @@
 		return ret;
 	/* convert absolute hysteresis value to a 4 bit delta value */
 	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
-	hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
-	data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
-				   0, ADT7410_T_HYST_MASK);
+	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
+			       ADT7410_T_HYST_MASK);
 	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
 	if (ret)
 		return ret;
@@ -364,6 +360,7 @@
 	/*
 	 * Set to 16 bit resolution, continous conversion and comparator mode.
 	 */
+	ret &= ~ADT7410_MODE_MASK;
 	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
 			ADT7410_EVENT_MODE;
 	if (data->config != data->oldconfig) {
@@ -410,11 +407,12 @@
 
 static const struct i2c_device_id adt7410_ids[] = {
 	{ "adt7410", adt7410, },
+	{ "adt7420", adt7410, },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int adt7410_suspend(struct device *dev)
 {
 	int ret;
@@ -436,10 +434,8 @@
 	return ret;
 }
 
-static const struct dev_pm_ops adt7410_dev_pm_ops = {
-	.suspend	= adt7410_suspend,
-	.resume		= adt7410_resume,
-};
+static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
+
 #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
 #else
 #define ADT7410_DEV_PM_OPS NULL
@@ -454,11 +450,11 @@
 	.probe		= adt7410_probe,
 	.remove		= adt7410_remove,
 	.id_table	= adt7410_ids,
-	.address_list	= normal_i2c,
+	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 };
 
 module_i2c_driver(adt7410_driver);
 
 MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 98a7d81..69481d3 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -836,7 +836,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->temp_min[attr->index] = temp;
@@ -874,7 +874,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->temp_max[attr->index] = temp;
@@ -939,7 +939,7 @@
 
 	temp *= 1000; /* convert mV to uV */
 	temp = DIV_ROUND_CLOSEST(temp, x);
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->volt_max[attr->index] = temp;
@@ -981,7 +981,7 @@
 
 	temp *= 1000; /* convert mV to uV */
 	temp = DIV_ROUND_CLOSEST(temp, x);
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->volt_min[attr->index] = temp;
@@ -1071,7 +1071,7 @@
 
 	temp = FAN_RPM_TO_PERIOD(temp);
 	temp >>= 8;
-	temp = SENSORS_LIMIT(temp, 1, 255);
+	temp = clamp_val(temp, 1, 255);
 
 	mutex_lock(&data->lock);
 	data->fan_min[attr->index] = temp;
@@ -1149,7 +1149,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm[attr->index] = temp;
@@ -1179,7 +1179,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm_max = temp;
@@ -1211,7 +1211,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm_min[attr->index] = temp;
@@ -1246,7 +1246,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000);
-	temp = SENSORS_LIMIT(temp, 0, 15);
+	temp = clamp_val(temp, 0, 15);
 
 	/* package things up */
 	temp &= ADT7462_PWM_HYST_MASK;
@@ -1333,7 +1333,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 39ecb1a..b83bf4b 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -452,7 +452,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 60000);
+	temp = clamp_val(temp, 0, 60000);
 
 	mutex_lock(&data->lock);
 	data->auto_update_interval = temp;
@@ -481,7 +481,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, -1, 10);
+	temp = clamp_val(temp, -1, 10);
 
 	mutex_lock(&data->lock);
 	data->num_temp_sensors = temp;
@@ -515,7 +515,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000);
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->temp_min[attr->index] = temp;
@@ -549,7 +549,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000);
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->temp_max[attr->index] = temp;
@@ -604,7 +604,7 @@
 		return -EINVAL;
 
 	temp = FAN_RPM_TO_PERIOD(temp);
-	temp = SENSORS_LIMIT(temp, 1, 65534);
+	temp = clamp_val(temp, 1, 65534);
 
 	mutex_lock(&data->lock);
 	data->fan_max[attr->index] = temp;
@@ -641,7 +641,7 @@
 		return -EINVAL;
 
 	temp = FAN_RPM_TO_PERIOD(temp);
-	temp = SENSORS_LIMIT(temp, 1, 65534);
+	temp = clamp_val(temp, 1, 65534);
 
 	mutex_lock(&data->lock);
 	data->fan_min[attr->index] = temp;
@@ -717,7 +717,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm[attr->index] = temp;
@@ -749,7 +749,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm_max[attr->index] = temp;
@@ -782,7 +782,7 @@
 	if (kstrtol(buf, 10, &temp))
 		return -EINVAL;
 
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm_min[attr->index] = temp;
@@ -826,7 +826,7 @@
 		return -EINVAL;
 
 	temp = DIV_ROUND_CLOSEST(temp, 1000);
-	temp = SENSORS_LIMIT(temp, 0, 255);
+	temp = clamp_val(temp, 0, 255);
 
 	mutex_lock(&data->lock);
 	data->pwm_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index 989e54c..22d008b 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -201,10 +201,10 @@
 	u16 ret;
 
 	if (!(data->config5 & CONFIG5_TWOSCOMP)) {
-		val = SENSORS_LIMIT(val, -64000, 191000);
+		val = clamp_val(val, -64000, 191000);
 		ret = (val + 64500) / 1000;
 	} else {
-		val = SENSORS_LIMIT(val, -128000, 127000);
+		val = clamp_val(val, -128000, 127000);
 		if (val < -500)
 			ret = (256500 + val) / 1000;
 		else
@@ -240,7 +240,7 @@
 	if (rpm == 0)
 		return 0;
 
-	return SENSORS_LIMIT((90000 * 60) / rpm, 1, 0xFFFF);
+	return clamp_val((90000 * 60) / rpm, 1, 0xFFFF);
 }
 
 /* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
@@ -271,7 +271,7 @@
 		reg = (volt * 1024) / 2250;
 	else
 		reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250);
-	return SENSORS_LIMIT(reg, 0, 1023) & (0xff << 2);
+	return clamp_val(reg, 0, 1023) & (0xff << 2);
 }
 
 static u16 adt7475_read_word(struct i2c_client *client, int reg)
@@ -451,10 +451,10 @@
 	switch (sattr->nr) {
 	case OFFSET:
 		if (data->config5 & CONFIG5_TEMPOFFSET) {
-			val = SENSORS_LIMIT(val, -63000, 127000);
+			val = clamp_val(val, -63000, 127000);
 			out = data->temp[OFFSET][sattr->index] = val / 1000;
 		} else {
-			val = SENSORS_LIMIT(val, -63000, 64000);
+			val = clamp_val(val, -63000, 64000);
 			out = data->temp[OFFSET][sattr->index] = val / 500;
 		}
 		break;
@@ -471,7 +471,7 @@
 		adt7475_read_hystersis(client);
 
 		temp = reg2temp(data, data->temp[THERM][sattr->index]);
-		val = SENSORS_LIMIT(val, temp - 15000, temp);
+		val = clamp_val(val, temp - 15000, temp);
 		val = (temp - val) / 1000;
 
 		if (sattr->index != 1) {
@@ -577,7 +577,7 @@
 	 * to figure the range
 	 */
 	temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
-	val = SENSORS_LIMIT(val, temp + autorange_table[0],
+	val = clamp_val(val, temp + autorange_table[0],
 		temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]);
 	val -= temp;
 
@@ -701,7 +701,7 @@
 		break;
 	}
 
-	data->pwm[sattr->nr][sattr->index] = SENSORS_LIMIT(val, 0, 0xFF);
+	data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
 	i2c_smbus_write_byte_data(client, reg,
 				  data->pwm[sattr->nr][sattr->index]);
 
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index ae482e3..4fe49d2 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -241,7 +241,7 @@
 	int ret = kstrtol(buf, 10, &val);
 	if (ret)
 		return ret;
-	val = SENSORS_LIMIT(val / 1000, -128, 127);
+	val = clamp_val(val / 1000, -128, 127);
 
 	mutex_lock(&data->update_lock);
 	data->temp[ix] = val;
@@ -332,7 +332,7 @@
 		return ret;
 
 	mutex_lock(&data->update_lock);
-	data->pwm1 = SENSORS_LIMIT(val , 0, 255);
+	data->pwm1 = clamp_val(val , 0, 255);
 	i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -499,11 +499,11 @@
 	mutex_lock(&data->update_lock);
 	switch (ix) {
 	case 0:
-		ptemp[0] = SENSORS_LIMIT(val / 1000, 0,
-				data->temp1_auto_point_temp[1]);
-		ptemp[0] = SENSORS_LIMIT(ptemp[0], 0,
-				data->temp2_auto_point_temp[1]);
-		ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63);
+		ptemp[0] = clamp_val(val / 1000, 0,
+				     data->temp1_auto_point_temp[1]);
+		ptemp[0] = clamp_val(ptemp[0], 0,
+				     data->temp2_auto_point_temp[1]);
+		ptemp[0] = clamp_val(ptemp[0], 0, 63);
 		if (i2c_smbus_write_byte_data(
 					client,
 					AMC6821_REG_PSV_TEMP,
@@ -515,20 +515,12 @@
 		goto EXIT;
 		break;
 	case 1:
-		ptemp[1] = SENSORS_LIMIT(
-					val / 1000,
-					(ptemp[0] & 0x7C) + 4,
-					124);
+		ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
 		ptemp[1] &= 0x7C;
-		ptemp[2] = SENSORS_LIMIT(
-					ptemp[2], ptemp[1] + 1,
-					255);
+		ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255);
 		break;
 	case 2:
-		ptemp[2] = SENSORS_LIMIT(
-					val / 1000,
-					ptemp[1]+1,
-					255);
+		ptemp[2] = clamp_val(val / 1000, ptemp[1]+1, 255);
 		break;
 	default:
 		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
@@ -561,7 +553,7 @@
 		return ret;
 
 	mutex_lock(&data->update_lock);
-	data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254);
+	data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254);
 	if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP,
 			data->pwm1_auto_point_pwm[1])) {
 		dev_err(&client->dev, "Register write error, aborting.\n");
@@ -629,7 +621,7 @@
 	val = 1 > val ? 0xFFFF : 6000000/val;
 
 	mutex_lock(&data->update_lock);
-	data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF);
+	data->fan[ix] = (u16) clamp_val(val, 1, 0xFFFF);
 	if (i2c_smbus_write_byte_data(client, fan_reg_low[ix],
 			data->fan[ix] & 0xFF)) {
 		dev_err(&client->dev, "Register write error, aborting.\n");
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 520e5bf..6ac612c 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -114,7 +114,7 @@
  */
 static u8 IN_TO_REG(unsigned val)
 {
-	unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
+	unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX);
 	return (nval + 8) / 16;
 }
 
@@ -129,8 +129,8 @@
 		return 0;
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static int FAN_FROM_REG(u8 val, int div)
@@ -148,7 +148,7 @@
  */
 static u8 TEMP_TO_REG(long temp)
 {
-	int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
+	int ntemp = clamp_val(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
 	ntemp += (ntemp < 0 ? -500 : 500);
 	return (u8)(ntemp / 1000);
 }
@@ -164,7 +164,7 @@
  */
 static u8 ASB100_PWM_TO_REG(int pwm)
 {
-	pwm = SENSORS_LIMIT(pwm, 0, 255);
+	pwm = clamp_val(pwm, 0, 255);
 	return (u8)(pwm / 16);
 }
 
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
index b867aab7..da7f5b5 100644
--- a/drivers/hwmon/asc7621.c
+++ b/drivers/hwmon/asc7621.c
@@ -191,7 +191,7 @@
 	if (kstrtol(buf, 10, &reqval))
 		return -EINVAL;
 
-	reqval = SENSORS_LIMIT(reqval, 0, 255);
+	reqval = clamp_val(reqval, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->reg[param->msb[0]] = reqval;
@@ -224,7 +224,7 @@
 	if (kstrtol(buf, 10, &reqval))
 		return -EINVAL;
 
-	reqval = SENSORS_LIMIT(reqval, 0, param->mask[0]);
+	reqval = clamp_val(reqval, 0, param->mask[0]);
 
 	reqval = (reqval & param->mask[0]) << param->shift[0];
 
@@ -274,7 +274,7 @@
 	 * generating an alarm.
 	 */
 	reqval =
-	    (reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe));
+	    (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe));
 
 	mutex_lock(&data->update_lock);
 	data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
@@ -343,11 +343,11 @@
 	if (kstrtol(buf, 10, &reqval))
 		return -EINVAL;
 
-	reqval = SENSORS_LIMIT(reqval, 0, 0xffff);
+	reqval = clamp_val(reqval, 0, 0xffff);
 
 	reqval = reqval * 0xc0 / asc7621_in_scaling[nr];
 
-	reqval = SENSORS_LIMIT(reqval, 0, 0xff);
+	reqval = clamp_val(reqval, 0, 0xff);
 
 	mutex_lock(&data->update_lock);
 	data->reg[param->msb[0]] = reqval;
@@ -376,7 +376,7 @@
 	if (kstrtol(buf, 10, &reqval))
 		return -EINVAL;
 
-	reqval = SENSORS_LIMIT(reqval, -127000, 127000);
+	reqval = clamp_val(reqval, -127000, 127000);
 
 	temp = reqval / 1000;
 
@@ -432,7 +432,7 @@
 	if (kstrtol(buf, 10, &reqval))
 		return -EINVAL;
 
-	reqval = SENSORS_LIMIT(reqval, -32000, 31750);
+	reqval = clamp_val(reqval, -32000, 31750);
 	i = reqval / 1000;
 	f = reqval - (i * 1000);
 	temp = i << 2;
@@ -468,7 +468,7 @@
 	auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000;
 	regval =
 	    ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]);
-	temp = auto_point1 + asc7621_range_map[SENSORS_LIMIT(regval, 0, 15)];
+	temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)];
 	mutex_unlock(&data->update_lock);
 
 	return sprintf(buf, "%d\n", temp);
@@ -489,7 +489,7 @@
 
 	mutex_lock(&data->update_lock);
 	auto_point1 = data->reg[param->msb[1]] * 1000;
-	reqval = SENSORS_LIMIT(reqval, auto_point1 + 2000, auto_point1 + 80000);
+	reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000);
 
 	for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) {
 		if (reqval >= auto_point1 + asc7621_range_map[i]) {
@@ -523,7 +523,7 @@
 	regval = config | (altbit << 3);
 	mutex_unlock(&data->update_lock);
 
-	return sprintf(buf, "%u\n", map[SENSORS_LIMIT(regval, 0, 15)]);
+	return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]);
 }
 
 static ssize_t store_pwm_ac(struct device *dev,
@@ -663,7 +663,7 @@
 	u8 regval =
 	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 
-	regval = SENSORS_LIMIT(regval, 0, 15);
+	regval = clamp_val(regval, 0, 15);
 
 	return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]);
 }
@@ -711,7 +711,7 @@
 	u8 regval =
 	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 
-	regval = SENSORS_LIMIT(regval, 0, 7);
+	regval = clamp_val(regval, 0, 7);
 
 	return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]);
 
@@ -759,7 +759,7 @@
 	SETUP_SHOW_data_param(dev, attr);
 	u8 regval =
 	    (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
-	regval = SENSORS_LIMIT(regval, 0, 7);
+	regval = clamp_val(regval, 0, 7);
 
 	return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]);
 }
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 56dbcfb..b25c643 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -190,7 +190,7 @@
 };
 
 static int atk_add(struct acpi_device *device);
-static int atk_remove(struct acpi_device *device, int type);
+static int atk_remove(struct acpi_device *device);
 static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
 static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
 static void atk_free_sensors(struct atk_data *data);
@@ -1416,7 +1416,7 @@
 	return err;
 }
 
-static int atk_remove(struct acpi_device *device, int type)
+static int atk_remove(struct acpi_device *device)
 {
 	struct atk_data *data = device->driver_data;
 	dev_dbg(&device->dev, "removing...\n");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index d64923d..3f1e297 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -198,7 +198,7 @@
 static const struct tjmax __cpuinitconst tjmax_table[] = {
 	{ "CPU  230", 100000 },		/* Model 0x1c, stepping 2	*/
 	{ "CPU  330", 125000 },		/* Model 0x1c, stepping 2	*/
-	{ "CPU CE4110", 110000 },	/* Model 0x1c, stepping 10	*/
+	{ "CPU CE4110", 110000 },	/* Model 0x1c, stepping 10 Sodaville */
 	{ "CPU CE4150", 110000 },	/* Model 0x1c, stepping 10	*/
 	{ "CPU CE4170", 110000 },	/* Model 0x1c, stepping 10	*/
 };
@@ -212,7 +212,7 @@
 #define ANY 0xff
 
 static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
-	{ 0x1c, 10, 100000 },	/* D4xx, N4xx, D5xx, N5xx */
+	{ 0x1c, 10, 100000 },	/* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */
 	{ 0x1c, ANY, 90000 },	/* Z5xx, N2xx, possibly others
 				 * Note: Also matches 230 and 330,
 				 * which are covered by tjmax_table
@@ -222,6 +222,7 @@
 				 * is undetectable by software
 				 */
 	{ 0x27, ANY, 90000 },	/* Atom Medfield (Z2460) */
+	{ 0x35, ANY, 90000 },	/* Atom Clover Trail/Cloverview (Z2760) */
 	{ 0x36, ANY, 100000 },	/* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
 };
 
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 7430f70..c347c94 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -277,7 +277,7 @@
 
 static inline int IN_TO_REG(int val, int nominal)
 {
-	return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
+	return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255);
 }
 
 /*
@@ -293,8 +293,7 @@
 
 static inline int TEMP_TO_REG(int val)
 {
-	return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
-			     -128, 127);
+	return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127);
 }
 
 /* Temperature range */
@@ -332,7 +331,7 @@
 
 static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
 {
-	int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+	int hyst = clamp_val((val + 500) / 1000, 0, 15);
 
 	return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
 }
@@ -349,10 +348,10 @@
 static inline int FAN_TO_REG(int val, int tpc)
 {
 	if (tpc) {
-		return SENSORS_LIMIT(val / tpc, 0, 0xffff);
+		return clamp_val(val / tpc, 0, 0xffff);
 	} else {
 		return (val <= 0) ? 0xffff :
-			SENSORS_LIMIT(90000 * 60 / val, 0, 0xfffe);
+			clamp_val(90000 * 60 / val, 0, 0xfffe);
 	}
 }
 
@@ -1282,7 +1281,7 @@
 	mutex_lock(&data->update_lock);
 	switch (fn) {
 	case SYS_PWM:
-		data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+		data->pwm[ix] = clamp_val(val, 0, 255);
 		dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
 		break;
 	case SYS_PWM_FREQ:
@@ -1450,7 +1449,7 @@
 		break;
 	case SYS_PWM_AUTO_POINT1_PWM:
 		/* Only valid for pwm[1-3] */
-		data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+		data->pwm_min[ix] = clamp_val(val, 0, 255);
 		dme1737_write(data, DME1737_REG_PWM_MIN(ix),
 			      data->pwm_min[ix]);
 		break;
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 77f434c..b073056 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -405,7 +405,7 @@
 	if (rpm_target == 0)
 		data->fan_target = 0x1fff;
 	else
-		data->fan_target = SENSORS_LIMIT(
+		data->fan_target = clamp_val(
 			(FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target,
 			0, 0x1fff);
 
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
index 789bd4f..936898f 100644
--- a/drivers/hwmon/emc6w201.c
+++ b/drivers/hwmon/emc6w201.c
@@ -220,7 +220,7 @@
 			  : EMC6W201_REG_IN_HIGH(nr);
 
 	mutex_lock(&data->update_lock);
-	data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
+	data->in[sf][nr] = clamp_val(val, 0, 255);
 	err = emc6w201_write8(client, reg, data->in[sf][nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -257,7 +257,7 @@
 			  : EMC6W201_REG_TEMP_HIGH(nr);
 
 	mutex_lock(&data->update_lock);
-	data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
+	data->temp[sf][nr] = clamp_val(val, -127, 128);
 	err = emc6w201_write8(client, reg, data->temp[sf][nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -298,7 +298,7 @@
 		val = 0xFFFF;
 	} else {
 		val = DIV_ROUND_CLOSEST(5400000U, val);
-		val = SENSORS_LIMIT(val, 0, 0xFFFE);
+		val = clamp_val(val, 0, 0xFFFE);
 	}
 
 	mutex_lock(&data->update_lock);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index bb7275c..cfb02dd 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -1350,7 +1350,7 @@
 	if (err)
 		return err;
 
-	val = SENSORS_LIMIT(val, 23, 1500000);
+	val = clamp_val(val, 23, 1500000);
 	val = fan_to_reg(val);
 
 	mutex_lock(&data->update_lock);
@@ -1438,7 +1438,7 @@
 		return err;
 
 	val /= 8;
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
@@ -1542,7 +1542,7 @@
 		return err;
 
 	val /= 1000;
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
@@ -1589,8 +1589,7 @@
 
 	/* convert abs to relative and check */
 	data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
-	val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
-			    data->temp_high[nr]);
+	val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]);
 	val = data->temp_high[nr] - val;
 
 	/* convert value to register contents */
@@ -1627,7 +1626,7 @@
 		return err;
 
 	val /= 1000;
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
@@ -1754,7 +1753,7 @@
 	if (err)
 		return err;
 
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -1805,7 +1804,7 @@
 	if (err)
 		return err;
 
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
@@ -1932,7 +1931,7 @@
 	if (err)
 		return err;
 
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -1991,8 +1990,8 @@
 	mutex_lock(&data->update_lock);
 	data->pwm_auto_point_temp[nr][point] =
 		f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
-	val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
-				data->pwm_auto_point_temp[nr][point]);
+	val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15,
+			data->pwm_auto_point_temp[nr][point]);
 	val = data->pwm_auto_point_temp[nr][point] - val;
 
 	reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
@@ -2126,9 +2125,9 @@
 	val /= 1000;
 
 	if (data->auto_point_temp_signed)
-		val = SENSORS_LIMIT(val, -128, 127);
+		val = clamp_val(val, -128, 127);
 	else
-		val = SENSORS_LIMIT(val, 0, 127);
+		val = clamp_val(val, 0, 127);
 
 	mutex_lock(&data->update_lock);
 	f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index f7dba22..9e300e5 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -359,7 +359,7 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+	data->pwm[nr] = clamp_val(val, 0, 255);
 	f75375_write_pwm(client, nr);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -556,7 +556,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
 	mutex_lock(&data->update_lock);
 	data->in_max[nr] = val;
 	f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
@@ -577,7 +577,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+	val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
 	mutex_lock(&data->update_lock);
 	data->in_min[nr] = val;
 	f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
@@ -625,7 +625,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+	val = clamp_val(TEMP_TO_REG(val), 0, 127);
 	mutex_lock(&data->update_lock);
 	data->temp_high[nr] = val;
 	f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
@@ -646,7 +646,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+	val = clamp_val(TEMP_TO_REG(val), 0, 127);
 	mutex_lock(&data->update_lock);
 	data->temp_max_hyst[nr] = val;
 	f75375_write8(client, F75375_REG_TEMP_HYST(nr),
@@ -822,7 +822,7 @@
 		if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) ||
 		    !duty_mode_enabled(f75375s_pdata->pwm_enable[nr]))
 			continue;
-		data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255);
+		data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255);
 		f75375_write_pwm(client, nr);
 	}
 
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 519ce8b..8af2755 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -379,7 +379,7 @@
 	if (err)
 		return err;
 
-	v = SENSORS_LIMIT(v / 1000, -128, 127) + 128;
+	v = clamp_val(v / 1000, -128, 127) + 128;
 
 	mutex_lock(&data->update_lock);
 	i2c_smbus_write_byte_data(to_i2c_client(dev),
@@ -540,7 +540,7 @@
 
 	/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
 	if (v || data->kind == fscsyl) {
-		v = SENSORS_LIMIT(v, 128, 255);
+		v = clamp_val(v, 128, 255);
 		v = (v - 128) * 2 + 1;
 	}
 
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
index 8b2106f..ea6480b 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -171,7 +171,7 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->set_cnt = PWM_TO_CNT(SENSORS_LIMIT(val, 0, 255));
+	data->set_cnt = PWM_TO_CNT(clamp_val(val, 0, 255));
 	g760a_write_value(client, G760A_REG_SET_CNT, data->set_cnt);
 	mutex_unlock(&data->update_lock);
 
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 2c74673..e2e5909 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -86,7 +86,7 @@
 #define BOOL_FROM_REG(val)	((val) ? 0 : 1)
 #define BOOL_TO_REG(val)	((val) ? 0 : 1)
 
-#define TEMP_TO_REG(val)	SENSORS_LIMIT(((((val) < 0 ? \
+#define TEMP_TO_REG(val)	clamp_val(((((val) < 0 ? \
 				(val) - 500 : \
 				(val) + 500) / 1000) + 119), 0, 255)
 #define TEMP_FROM_REG(val)	(((val) - 119) * 1000)
@@ -96,15 +96,15 @@
 	long rpmdiv;
 	if (rpm == 0)
 		return 0;
-	rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div;
-	return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
+	rpmdiv = clamp_val(rpm, 1, 960000) * div;
+	return clamp_val((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
 }
 #define FAN_FROM_REG(val, div)	((val) == 0 ? 0 : (480000 / ((val) * (div))))
 
-#define IN_TO_REG(val)		SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
+#define IN_TO_REG(val)		clamp_val((((val) + 9) / 19), 0, 255)
 #define IN_FROM_REG(val)	((val) * 19)
 
-#define VDD_TO_REG(val)		SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_TO_REG(val)		clamp_val((((val) * 4 + 47) / 95), 0, 255)
 #define VDD_FROM_REG(val)	(((val) * 95 + 2) / 4)
 
 #define DIV_FROM_REG(val)	(1 << (val))
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index a21ff25..ed56e09 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -144,10 +144,10 @@
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
 
 #define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
-#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255)
 
 #define IN_FROM_REG(val) ((val) * 19)
-#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
+#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255)
 
 static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
 			    char *buf)
@@ -285,8 +285,7 @@
 #define DIV_FROM_REG(val) (1 << (val))
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
 #define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \
-	SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, \
-		      255))
+	clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255))
 
 static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
 			     char *buf)
@@ -450,7 +449,7 @@
 		get_fan_off, set_fan_off);
 
 #define TEMP_FROM_REG(val) (((val) - 130) * 1000)
-#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \
+#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \
 			(val) - 500 : (val) + 500) / 1000) + 130), 0, 255)
 
 static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 4e04c12..3978194 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -422,7 +422,7 @@
 
 	/* Fill GPIO pin array */
 	pdata->num_ctrl = of_gpio_count(node);
-	if (!pdata->num_ctrl) {
+	if (pdata->num_ctrl <= 0) {
 		dev_err(dev, "gpios DT property empty / missing");
 		return -ENODEV;
 	}
@@ -477,7 +477,7 @@
 	pdata->speed = speed;
 
 	/* Alarm GPIO if one exists */
-	if (of_gpio_named_count(node, "alarm-gpios")) {
+	if (of_gpio_named_count(node, "alarm-gpios") > 0) {
 		struct gpio_fan_alarm *alarm;
 		int val;
 		enum of_gpio_flags flags;
diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c
new file mode 100644
index 0000000..c6fdd5b
--- /dev/null
+++ b/drivers/hwmon/ina209.c
@@ -0,0 +1,636 @@
+/*
+ * Driver for the Texas Instruments / Burr Brown INA209
+ * Bidirectional Current/Power Monitor
+ *
+ * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from Ira W. Snyder's original driver submission
+ *	Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca>
+ *	Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Aligned with ina2xx driver
+ *	Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ *	Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * Datasheet:
+ * http://www.ti.com/lit/gpn/ina209
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* register definitions */
+#define INA209_CONFIGURATION		0x00
+#define INA209_STATUS			0x01
+#define INA209_STATUS_MASK		0x02
+#define INA209_SHUNT_VOLTAGE		0x03
+#define INA209_BUS_VOLTAGE		0x04
+#define INA209_POWER			0x05
+#define INA209_CURRENT			0x06
+#define INA209_SHUNT_VOLTAGE_POS_PEAK	0x07
+#define INA209_SHUNT_VOLTAGE_NEG_PEAK	0x08
+#define INA209_BUS_VOLTAGE_MAX_PEAK	0x09
+#define INA209_BUS_VOLTAGE_MIN_PEAK	0x0a
+#define INA209_POWER_PEAK		0x0b
+#define INA209_SHUNT_VOLTAGE_POS_WARN	0x0c
+#define INA209_SHUNT_VOLTAGE_NEG_WARN	0x0d
+#define INA209_POWER_WARN		0x0e
+#define INA209_BUS_VOLTAGE_OVER_WARN	0x0f
+#define INA209_BUS_VOLTAGE_UNDER_WARN	0x10
+#define INA209_POWER_OVER_LIMIT		0x11
+#define INA209_BUS_VOLTAGE_OVER_LIMIT	0x12
+#define INA209_BUS_VOLTAGE_UNDER_LIMIT	0x13
+#define INA209_CRITICAL_DAC_POS		0x14
+#define INA209_CRITICAL_DAC_NEG		0x15
+#define INA209_CALIBRATION		0x16
+
+#define INA209_REGISTERS		0x17
+
+#define INA209_CONFIG_DEFAULT		0x3c47	/* PGA=8, full range */
+#define INA209_SHUNT_DEFAULT		10000	/* uOhm */
+
+struct ina209_data {
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;	/* in jiffies */
+
+	u16 regs[INA209_REGISTERS];	/* All chip registers */
+
+	u16 config_orig;		/* Original configuration */
+	u16 calibration_orig;		/* Original calibration */
+	u16 update_interval;
+};
+
+static struct ina209_data *ina209_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ina209_data *data = i2c_get_clientdata(client);
+	struct ina209_data *ret = data;
+	s32 val;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid ||
+	    time_after(jiffies, data->last_updated + data->update_interval)) {
+		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+			val = i2c_smbus_read_word_swapped(client, i);
+			if (val < 0) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->regs[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/*
+ * Read a value from a device register and convert it to the
+ * appropriate sysfs units
+ */
+static long ina209_from_reg(const u8 reg, const u16 val)
+{
+	switch (reg) {
+	case INA209_SHUNT_VOLTAGE:
+	case INA209_SHUNT_VOLTAGE_POS_PEAK:
+	case INA209_SHUNT_VOLTAGE_NEG_PEAK:
+	case INA209_SHUNT_VOLTAGE_POS_WARN:
+	case INA209_SHUNT_VOLTAGE_NEG_WARN:
+		/* LSB=10 uV. Convert to mV. */
+		return DIV_ROUND_CLOSEST(val, 100);
+
+	case INA209_BUS_VOLTAGE:
+	case INA209_BUS_VOLTAGE_MAX_PEAK:
+	case INA209_BUS_VOLTAGE_MIN_PEAK:
+	case INA209_BUS_VOLTAGE_OVER_WARN:
+	case INA209_BUS_VOLTAGE_UNDER_WARN:
+	case INA209_BUS_VOLTAGE_OVER_LIMIT:
+	case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+		/* LSB=4 mV, last 3 bits unused */
+		return (val >> 3) * 4;
+
+	case INA209_CRITICAL_DAC_POS:
+		/* LSB=1 mV, in the upper 8 bits */
+		return val >> 8;
+
+	case INA209_CRITICAL_DAC_NEG:
+		/* LSB=1 mV, in the upper 8 bits */
+		return -1 * (val >> 8);
+
+	case INA209_POWER:
+	case INA209_POWER_PEAK:
+	case INA209_POWER_WARN:
+	case INA209_POWER_OVER_LIMIT:
+		/* LSB=20 mW. Convert to uW */
+		return val * 20 * 1000L;
+
+	case INA209_CURRENT:
+		/* LSB=1 mA (selected). Is in mA */
+		return val;
+	}
+
+	/* programmer goofed */
+	WARN_ON_ONCE(1);
+	return 0;
+}
+
+/*
+ * Take a value and convert it to register format, clamping the value
+ * to the appropriate range.
+ */
+static int ina209_to_reg(u8 reg, u16 old, long val)
+{
+	switch (reg) {
+	case INA209_SHUNT_VOLTAGE_POS_WARN:
+	case INA209_SHUNT_VOLTAGE_NEG_WARN:
+		/* Limit to +- 320 mV, 10 uV LSB */
+		return clamp_val(val, -320, 320) * 100;
+
+	case INA209_BUS_VOLTAGE_OVER_WARN:
+	case INA209_BUS_VOLTAGE_UNDER_WARN:
+	case INA209_BUS_VOLTAGE_OVER_LIMIT:
+	case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+		/*
+		 * Limit to 0-32000 mV, 4 mV LSB
+		 *
+		 * The last three bits aren't part of the value, but we'll
+		 * preserve them in their original state.
+		 */
+		return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3)
+		  | (old & 0x7);
+
+	case INA209_CRITICAL_DAC_NEG:
+		/*
+		 * Limit to -255-0 mV, 1 mV LSB
+		 * Convert the value to a positive value for the register
+		 *
+		 * The value lives in the top 8 bits only, be careful
+		 * and keep original value of other bits.
+		 */
+		return (clamp_val(-val, 0, 255) << 8) | (old & 0xff);
+
+	case INA209_CRITICAL_DAC_POS:
+		/*
+		 * Limit to 0-255 mV, 1 mV LSB
+		 *
+		 * The value lives in the top 8 bits only, be careful
+		 * and keep original value of other bits.
+		 */
+		return (clamp_val(val, 0, 255) << 8) | (old & 0xff);
+
+	case INA209_POWER_WARN:
+	case INA209_POWER_OVER_LIMIT:
+		/* 20 mW LSB */
+		return DIV_ROUND_CLOSEST(val, 20 * 1000);
+	}
+
+	/* Other registers are read-only, return access error */
+	return -EACCES;
+}
+
+static int ina209_interval_from_reg(u16 reg)
+{
+	return 68 >> (15 - ((reg >> 3) & 0x0f));
+}
+
+static u16 ina209_reg_from_interval(u16 config, long interval)
+{
+	int i, adc;
+
+	if (interval <= 0) {
+		adc = 8;
+	} else {
+		adc = 15;
+		for (i = 34 + 34 / 2; i; i >>= 1) {
+			if (i < interval)
+				break;
+			adc--;
+		}
+	}
+	return (config & 0xf807) | (adc << 3) | (adc << 7);
+}
+
+static ssize_t ina209_set_interval(struct device *dev,
+				   struct device_attribute *da,
+				   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ina209_data *data = ina209_update_device(dev);
+	long val;
+	u16 regval;
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION],
+					  val);
+	i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval);
+	data->regs[INA209_CONFIGURATION] = regval;
+	data->update_interval = ina209_interval_from_reg(regval);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t ina209_show_interval(struct device *dev,
+				    struct device_attribute *da, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ina209_data *data = i2c_get_clientdata(client);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
+}
+
+/*
+ * History is reset by writing 1 into bit 0 of the respective peak register.
+ * Since more than one peak register may be affected by the scope of a
+ * reset_history attribute write, use a bit mask in attr->index to identify
+ * which registers are affected.
+ */
+static u16 ina209_reset_history_regs[] = {
+	INA209_SHUNT_VOLTAGE_POS_PEAK,
+	INA209_SHUNT_VOLTAGE_NEG_PEAK,
+	INA209_BUS_VOLTAGE_MAX_PEAK,
+	INA209_BUS_VOLTAGE_MIN_PEAK,
+	INA209_POWER_PEAK
+};
+
+static ssize_t ina209_reset_history(struct device *dev,
+				    struct device_attribute *da,
+				    const char *buf,
+				    size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ina209_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	u32 mask = attr->index;
+	long val;
+	int i, ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) {
+		if (mask & (1 << i))
+			i2c_smbus_write_word_swapped(client,
+					ina209_reset_history_regs[i], 1);
+	}
+	data->valid = false;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t ina209_set_value(struct device *dev,
+				struct device_attribute *da,
+				const char *buf,
+				size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ina209_data *data = ina209_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int reg = attr->index;
+	long val;
+	int ret;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	ret = ina209_to_reg(reg, data->regs[reg], val);
+	if (ret < 0) {
+		count = ret;
+		goto abort;
+	}
+	i2c_smbus_write_word_swapped(client, reg, ret);
+	data->regs[reg] = ret;
+abort:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t ina209_show_value(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina209_data *data = ina209_update_device(dev);
+	long val;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	val = ina209_from_reg(attr->index, data->regs[attr->index]);
+	return snprintf(buf, PAGE_SIZE, "%ld\n", val);
+}
+
+static ssize_t ina209_show_alarm(struct device *dev,
+				 struct device_attribute *da,
+				 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ina209_data *data = ina209_update_device(dev);
+	const unsigned int mask = attr->index;
+	u16 status;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	status = data->regs[INA209_STATUS];
+
+	/*
+	 * All alarms are in the INA209_STATUS register. To avoid a long
+	 * switch statement, the mask is passed in attr->index
+	 */
+	return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
+}
+
+/* Shunt voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_SHUNT_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_SHUNT_VOLTAGE_POS_PEAK);
+static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_SHUNT_VOLTAGE_NEG_PEAK);
+static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL,
+			  ina209_reset_history, (1 << 0) | (1 << 1));
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN);
+static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_CRITICAL_DAC_POS);
+static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_CRITICAL_DAC_NEG);
+
+static SENSOR_DEVICE_ATTR(in0_min_alarm,  S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 11);
+static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 12);
+static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 6);
+static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 7);
+
+/* Bus voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_BUS_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_BUS_VOLTAGE_MAX_PEAK);
+static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL,
+			  INA209_BUS_VOLTAGE_MIN_PEAK);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+			  ina209_reset_history, (1 << 2) | (1 << 3));
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN);
+static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT);
+static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 14);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 15);
+static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 9);
+static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 10);
+
+/* Power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_POWER);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value,
+			  NULL, INA209_POWER_PEAK);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+			  ina209_reset_history, 1 << 4);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_POWER_WARN);
+static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value,
+			  ina209_set_value, INA209_POWER_OVER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 13);
+static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL,
+			  1 << 8);
+
+/* Current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL,
+			  INA209_CURRENT);
+
+static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+			  ina209_show_interval, ina209_set_interval, 0);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ina209_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_input_highest.dev_attr.attr,
+	&sensor_dev_attr_in0_input_lowest.dev_attr.attr,
+	&sensor_dev_attr_in0_reset_history.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_max.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input_highest.dev_attr.attr,
+	&sensor_dev_attr_in1_input_lowest.dev_attr.attr,
+	&sensor_dev_attr_in1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_max.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_power1_input.dev_attr.attr,
+	&sensor_dev_attr_power1_input_highest.dev_attr.attr,
+	&sensor_dev_attr_power1_reset_history.dev_attr.attr,
+	&sensor_dev_attr_power1_max.dev_attr.attr,
+	&sensor_dev_attr_power1_crit.dev_attr.attr,
+	&sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_power1_crit_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+
+	&sensor_dev_attr_update_interval.dev_attr.attr,
+
+	NULL,
+};
+
+static const struct attribute_group ina209_group = {
+	.attrs = ina209_attributes,
+};
+
+static void ina209_restore_conf(struct i2c_client *client,
+				struct ina209_data *data)
+{
+	/* Restore initial configuration */
+	i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+				     data->config_orig);
+	i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+				     data->calibration_orig);
+}
+
+static int ina209_init_client(struct i2c_client *client,
+			      struct ina209_data *data)
+{
+	struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
+	u32 shunt;
+	int reg;
+
+	reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION);
+	if (reg < 0)
+		return reg;
+	data->calibration_orig = reg;
+
+	reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION);
+	if (reg < 0)
+		return reg;
+	data->config_orig = reg;
+
+	if (pdata) {
+		if (pdata->shunt_uohms <= 0)
+			return -EINVAL;
+		shunt = pdata->shunt_uohms;
+	} else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor",
+					 &shunt)) {
+		if (shunt == 0)
+			return -EINVAL;
+	} else {
+		shunt = data->calibration_orig ?
+		  40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT;
+	}
+
+	i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+				     INA209_CONFIG_DEFAULT);
+	data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT);
+
+	/*
+	 * Calibrate current LSB to 1mA. Shunt is in uOhms.
+	 * See equation 13 in datasheet.
+	 */
+	i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+				     clamp_val(40960000 / shunt, 1, 65535));
+
+	/* Clear status register */
+	i2c_smbus_read_word_swapped(client, INA209_STATUS);
+
+	return 0;
+}
+
+static int ina209_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct ina209_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	ret = ina209_init_client(client, data);
+	if (ret)
+		return ret;
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&client->dev.kobj, &ina209_group);
+	if (ret)
+		goto out_restore_conf;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto out_hwmon_device_register;
+	}
+
+	return 0;
+
+out_hwmon_device_register:
+	sysfs_remove_group(&client->dev.kobj, &ina209_group);
+out_restore_conf:
+	ina209_restore_conf(client, data);
+	return ret;
+}
+
+static int ina209_remove(struct i2c_client *client)
+{
+	struct ina209_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &ina209_group);
+	ina209_restore_conf(client, data);
+
+	return 0;
+}
+
+static const struct i2c_device_id ina209_id[] = {
+	{ "ina209", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ina209_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ina209_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "ina209",
+	},
+	.probe		= ina209_probe,
+	.remove		= ina209_remove,
+	.id_table	= ina209_id,
+};
+
+module_i2c_driver(ina209_driver);
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("INA209 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 117d66f..37fc980 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -19,6 +19,8 @@
  *            IT8726F  Super I/O chip w/LPC interface
  *            IT8728F  Super I/O chip w/LPC interface
  *            IT8758E  Super I/O chip w/LPC interface
+ *            IT8771E  Super I/O chip w/LPC interface
+ *            IT8772E  Super I/O chip w/LPC interface
  *            IT8782F  Super I/O chip w/LPC interface
  *            IT8783E/F Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
@@ -61,8 +63,8 @@
 
 #define DRVNAME "it87"
 
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
-	     it8783 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771,
+	     it8772, it8782, it8783 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -140,6 +142,8 @@
 #define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
 #define IT8728F_DEVID 0x8728
+#define IT8771E_DEVID 0x8771
+#define IT8772E_DEVID 0x8772
 #define IT8782F_DEVID 0x8782
 #define IT8783E_DEVID 0x8783
 #define IT87_ACT_REG  0x30
@@ -281,6 +285,24 @@
 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
 		.peci_mask = 0x07,
 	},
+	[it8771] = {
+		.name = "it8771",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+					/* PECI: guesswork */
+					/* 12mV ADC (OHM) */
+					/* 16 bit fans (OHM) */
+		.peci_mask = 0x07,
+	},
+	[it8772] = {
+		.name = "it8772",
+		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+					/* PECI (coreboot) */
+					/* 12mV ADC (HWSensors4, OHM) */
+					/* 16 bit fans (HWSensors4, OHM) */
+		.peci_mask = 0x07,
+	},
 	[it8782] = {
 		.name = "it8782",
 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
@@ -384,7 +406,7 @@
 static u8 in_to_reg(const struct it87_data *data, int nr, long val)
 {
 	val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
-	return SENSORS_LIMIT(val, 0, 255);
+	return clamp_val(val, 0, 255);
 }
 
 static int in_from_reg(const struct it87_data *data, int nr, int val)
@@ -396,16 +418,15 @@
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-			     254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline u16 FAN16_TO_REG(long rpm)
 {
 	if (rpm == 0)
 		return 0xffff;
-	return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+	return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
 }
 
 #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
@@ -414,8 +435,8 @@
 #define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
 			     1350000 / ((val) * 2))
 
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (((val) - 500) / 1000) : \
-					((val) + 500) / 1000), -128, 127))
+#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \
+				    ((val) + 500) / 1000), -128, 127))
 #define TEMP_FROM_REG(val) ((val) * 1000)
 
 static u8 pwm_to_reg(const struct it87_data *data, long val)
@@ -1709,6 +1730,12 @@
 	case IT8728F_DEVID:
 		sio_data->type = it8728;
 		break;
+	case IT8771E_DEVID:
+		sio_data->type = it8771;
+		break;
+	case IT8772E_DEVID:
+		sio_data->type = it8772;
+		break;
 	case IT8782F_DEVID:
 		sio_data->type = it8782;
 		break;
@@ -1826,10 +1853,11 @@
 
 		reg = superio_inb(IT87_SIO_GPIO3_REG);
 		if (sio_data->type == it8721 || sio_data->type == it8728 ||
+		    sio_data->type == it8771 || sio_data->type == it8772 ||
 		    sio_data->type == it8782) {
 			/*
 			 * IT8721F/IT8758E, and IT8782F don't have VID pins
-			 * at all, not sure about the IT8728F.
+			 * at all, not sure about the IT8728F and compatibles.
 			 */
 			sio_data->skip_vid = 1;
 		} else {
@@ -1883,7 +1911,9 @@
 		if (reg & (1 << 0))
 			sio_data->internal |= (1 << 0);
 		if ((reg & (1 << 1)) || sio_data->type == it8721 ||
-		    sio_data->type == it8728)
+		    sio_data->type == it8728 ||
+		    sio_data->type == it8771 ||
+		    sio_data->type == it8772)
 			sio_data->internal |= (1 << 1);
 
 		/*
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index e21e43c..4a58f13 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -103,6 +103,9 @@
 #define MCP98243_DEVID		0x2100
 #define MCP98243_DEVID_MASK	0xfffc
 
+#define MCP98244_DEVID		0x2200
+#define MCP98244_DEVID_MASK	0xfffc
+
 #define MCP9843_DEVID		0x0000	/* Also matches mcp9805 */
 #define MCP9843_DEVID_MASK	0xfffe
 
@@ -147,6 +150,7 @@
 	{ MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
 	{ MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
 	{ MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
+	{ MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
 	{ MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
 	{ NXP_MANID, SE97_DEVID, SE97_DEVID_MASK },
 	{ ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK },
@@ -237,9 +241,9 @@
 
 static u16 jc42_temp_to_reg(int temp, bool extended)
 {
-	int ntemp = SENSORS_LIMIT(temp,
-				  extended ? JC42_TEMP_MIN_EXTENDED :
-				  JC42_TEMP_MIN, JC42_TEMP_MAX);
+	int ntemp = clamp_val(temp,
+			      extended ? JC42_TEMP_MIN_EXTENDED :
+			      JC42_TEMP_MIN, JC42_TEMP_MAX);
 
 	/* convert from 0.001 to 0.0625 resolution */
 	return (ntemp * 2 / 125) & 0x1fff;
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index eed4d94..f644a2e 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -209,9 +209,9 @@
 {
 	val -= data->temp2_offset;
 	if (data->lut_temp_highres)
-		return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
+		return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127500), 500);
 	else
-		return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
+		return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
 }
 
 /*
@@ -415,7 +415,7 @@
 		return err;
 
 	reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm1[nr] = data->pwm_highres ? val :
@@ -700,7 +700,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+	lm63_set_convrate(client, data, clamp_val(val, 0, 100000));
 	mutex_unlock(&data->update_lock);
 
 	return count;
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
index 7272176..9bde964 100644
--- a/drivers/hwmon/lm73.c
+++ b/drivers/hwmon/lm73.c
@@ -8,6 +8,7 @@
  * Guillaume Ligneul <guillaume.ligneul@gmail.com>
  * Adrien Demarez <adrien.demarez@bolloretelecom.eu>
  * Jeremy Laine <jeremy.laine@bolloretelecom.eu>
+ * Chris Verges <kg4ysn@gmail.com>
  *
  * This software program is licensed subject to the GNU General Public License
  * (GPL).Version 2,June 1991, available at
@@ -36,12 +37,31 @@
 
 #define LM73_ID			0x9001	/* 0x0190, byte-swapped */
 #define DRVNAME			"lm73"
-#define LM73_TEMP_MIN		(-40)
-#define LM73_TEMP_MAX		150
+#define LM73_TEMP_MIN		(-256000 / 250)
+#define LM73_TEMP_MAX		(255750 / 250)
+
+#define LM73_CTRL_RES_SHIFT	5
+#define LM73_CTRL_RES_MASK	(BIT(5) | BIT(6))
+#define LM73_CTRL_TO_MASK	BIT(7)
+
+#define LM73_CTRL_HI_SHIFT	2
+#define LM73_CTRL_LO_SHIFT	1
+
+static const unsigned short lm73_convrates[] = {
+	14,	/* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */
+	28,	/* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */
+	56,	/* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */
+	112,	/* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */
+};
+
+struct lm73_data {
+	struct device *hwmon_dev;
+	struct mutex lock;
+	u8 ctrl;			/* control register value */
+};
 
 /*-----------------------------------------------------------------------*/
 
-
 static ssize_t set_temp(struct device *dev, struct device_attribute *da,
 			const char *buf, size_t count)
 {
@@ -56,8 +76,7 @@
 		return status;
 
 	/* Write value */
-	value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4),
-		(LM73_TEMP_MAX*4)) << 5;
+	value = clamp_val(temp / 250, LM73_TEMP_MIN, LM73_TEMP_MAX) << 5;
 	err = i2c_smbus_write_word_swapped(client, attr->index, value);
 	return (err < 0) ? err : count;
 }
@@ -79,6 +98,73 @@
 	return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
 
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+			    const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm73_data *data = i2c_get_clientdata(client);
+	unsigned long convrate;
+	s32 err;
+	int res = 0;
+
+	err = kstrtoul(buf, 10, &convrate);
+	if (err < 0)
+		return err;
+
+	/*
+	 * Convert the desired conversion rate into register bits.
+	 * res is already initialized, and everything past the second-to-last
+	 * value in the array is treated as belonging to the last value
+	 * in the array.
+	 */
+	while (res < (ARRAY_SIZE(lm73_convrates) - 1) &&
+			convrate > lm73_convrates[res])
+		res++;
+
+	mutex_lock(&data->lock);
+	data->ctrl &= LM73_CTRL_TO_MASK;
+	data->ctrl |= res << LM73_CTRL_RES_SHIFT;
+	err = i2c_smbus_write_byte_data(client, LM73_REG_CTRL, data->ctrl);
+	mutex_unlock(&data->lock);
+
+	if (err < 0)
+		return err;
+
+	return count;
+}
+
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+			     char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm73_data *data = i2c_get_clientdata(client);
+	int res;
+
+	res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT;
+	return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]);
+}
+
+static ssize_t show_maxmin_alarm(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm73_data *data = i2c_get_clientdata(client);
+	s32 ctrl;
+
+	mutex_lock(&data->lock);
+	ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+	if (ctrl < 0)
+		goto abort;
+	data->ctrl = ctrl;
+	mutex_unlock(&data->lock);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1);
+
+abort:
+	mutex_unlock(&data->lock);
+	return ctrl;
+}
 
 /*-----------------------------------------------------------------------*/
 
@@ -90,13 +176,20 @@
 			show_temp, set_temp, LM73_REG_MIN);
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
 			show_temp, NULL, LM73_REG_INPUT);
-
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+			show_convrate, set_convrate, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+			show_maxmin_alarm, NULL, LM73_CTRL_HI_SHIFT);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+			show_maxmin_alarm, NULL, LM73_CTRL_LO_SHIFT);
 
 static struct attribute *lm73_attributes[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	&sensor_dev_attr_temp1_max.dev_attr.attr,
 	&sensor_dev_attr_temp1_min.dev_attr.attr,
-
+	&sensor_dev_attr_update_interval.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 	NULL
 };
 
@@ -111,23 +204,36 @@
 static int
 lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-	struct device *hwmon_dev;
 	int status;
+	struct lm73_data *data;
+	int ctrl;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct lm73_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->lock);
+
+	ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+	if (ctrl < 0)
+		return ctrl;
+	data->ctrl = ctrl;
 
 	/* Register sysfs hooks */
 	status = sysfs_create_group(&client->dev.kobj, &lm73_group);
 	if (status)
 		return status;
 
-	hwmon_dev = hwmon_device_register(&client->dev);
-	if (IS_ERR(hwmon_dev)) {
-		status = PTR_ERR(hwmon_dev);
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		status = PTR_ERR(data->hwmon_dev);
 		goto exit_remove;
 	}
-	i2c_set_clientdata(client, hwmon_dev);
 
 	dev_info(&client->dev, "%s: sensor '%s'\n",
-		 dev_name(hwmon_dev), client->name);
+		 dev_name(data->hwmon_dev), client->name);
 
 	return 0;
 
@@ -138,9 +244,9 @@
 
 static int lm73_remove(struct i2c_client *client)
 {
-	struct device *hwmon_dev = i2c_get_clientdata(client);
+	struct lm73_data *data = i2c_get_clientdata(client);
 
-	hwmon_device_unregister(hwmon_dev);
+	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm73_group);
 	return 0;
 }
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index 89aa909..668ff47 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -36,7 +36,7 @@
    REG: (0.5C/bit, two's complement) << 7 */
 static inline u16 LM75_TEMP_TO_REG(long temp)
 {
-	int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
+	int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
 	ntemp += (ntemp < 0 ? -250 : 250);
 	return (u16)((ntemp / 500) << 7);
 }
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index f82acf6..f17beb5 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -101,7 +101,7 @@
  */
 static inline s16 LM77_TEMP_TO_REG(int temp)
 {
-	int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
+	int ntemp = clamp_val(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
 	return (ntemp / 500) * 8;
 }
 
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 53d6ee8..483538f 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -85,7 +85,7 @@
  */
 static inline u8 IN_TO_REG(unsigned long val)
 {
-	unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+	unsigned long nval = clamp_val(val, 0, 4080);
 	return (nval + 8) / 16;
 }
 #define IN_FROM_REG(val) ((val) *  16)
@@ -94,7 +94,7 @@
 {
 	if (rpm <= 0)
 		return 255;
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline int FAN_FROM_REG(u8 val, int div)
@@ -108,7 +108,7 @@
  */
 static inline s8 TEMP_TO_REG(int val)
 {
-	int nval = SENSORS_LIMIT(val, -128000, 127000) ;
+	int nval = clamp_val(val, -128000, 127000) ;
 	return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000;
 }
 
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 28a8b71..357fbb9 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -72,15 +72,15 @@
  * Fixing this is just not worth it.
  */
 
-#define IN_TO_REG(val)		(SENSORS_LIMIT(((val) + 5) / 10, 0, 255))
+#define IN_TO_REG(val)		(clamp_val(((val) + 5) / 10, 0, 255))
 #define IN_FROM_REG(val)	((val) * 10)
 
 static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 #define FAN_FROM_REG(val, div)	((val) == 0 ? -1 : \
@@ -102,7 +102,7 @@
 #define TEMP_LIMIT_FROM_REG(val)	(((val) > 0x80 ? \
 	(val) - 0x100 : (val)) * 1000)
 
-#define TEMP_LIMIT_TO_REG(val)		SENSORS_LIMIT((val) < 0 ? \
+#define TEMP_LIMIT_TO_REG(val)		clamp_val((val) < 0 ? \
 	((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255)
 
 #define DIV_FROM_REG(val)		(1 << (val))
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 9f2dd77..47ade8b 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -139,7 +139,7 @@
 #define SCALE(val, from, to)	(((val) * (to) + ((from) / 2)) / (from))
 
 #define INS_TO_REG(n, val)	\
-		SENSORS_LIMIT(SCALE(val, lm85_scaling[n], 192), 0, 255)
+		clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255)
 
 #define INSEXT_FROM_REG(n, val, ext)	\
 		SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
@@ -151,19 +151,19 @@
 {
 	if (!val)
 		return 0xffff;
-	return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+	return clamp_val(5400000 / val, 1, 0xfffe);
 }
 #define FAN_FROM_REG(val)	((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
 				 5400000 / (val))
 
 /* Temperature is reported in .001 degC increments */
 #define TEMP_TO_REG(val)	\
-		SENSORS_LIMIT(SCALE(val, 1000, 1), -127, 127)
+		clamp_val(SCALE(val, 1000, 1), -127, 127)
 #define TEMPEXT_FROM_REG(val, ext)	\
 		SCALE(((val) << 4) + (ext), 16, 1000)
 #define TEMP_FROM_REG(val)	((val) * 1000)
 
-#define PWM_TO_REG(val)			SENSORS_LIMIT(val, 0, 255)
+#define PWM_TO_REG(val)			clamp_val(val, 0, 255)
 #define PWM_FROM_REG(val)		(val)
 
 
@@ -258,7 +258,7 @@
 	return i << 5;
 }
 
-#define HYST_TO_REG(val)	SENSORS_LIMIT(((val) + 500) / 1000, 0, 15)
+#define HYST_TO_REG(val)	clamp_val(((val) + 500) / 1000, 0, 15)
 #define HYST_FROM_REG(val)	((val) * 1000)
 
 /*
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 863412a..8eeb141 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -931,7 +931,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+	lm90_set_convrate(client, data, clamp_val(val, 0, 100000));
 	mutex_unlock(&data->update_lock);
 
 	return count;
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index 1a003f7..b40f34c 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -371,8 +371,8 @@
 static u8 LM93_IN_TO_REG(int nr, unsigned val)
 {
 	/* range limit */
-	const long mV = SENSORS_LIMIT(val,
-		lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+	const long mV = clamp_val(val,
+				  lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
 
 	/* try not to lose too much precision here */
 	const long uV = mV * 1000;
@@ -385,8 +385,8 @@
 	const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
 
 	u8 result = ((uV - intercept + (slope/2)) / slope);
-	result = SENSORS_LIMIT(result,
-			lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+	result = clamp_val(result,
+			   lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
 	return result;
 }
 
@@ -411,10 +411,10 @@
 {
 	long uV_offset = vid * 1000 - val * 10000;
 	if (upper) {
-		uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+		uV_offset = clamp_val(uV_offset, 12500, 200000);
 		return (u8)((uV_offset /  12500 - 1) << 4);
 	} else {
-		uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+		uV_offset = clamp_val(uV_offset, -400000, -25000);
 		return (u8)((uV_offset / -25000 - 1) << 0);
 	}
 }
@@ -437,7 +437,7 @@
  */
 static u8 LM93_TEMP_TO_REG(long temp)
 {
-	int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+	int ntemp = clamp_val(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
 	ntemp += (ntemp < 0 ? -500 : 500);
 	return (u8)(ntemp / 1000);
 }
@@ -472,7 +472,7 @@
 {
 	int factor = mode ? 5 : 10;
 
-	off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+	off = clamp_val(off, LM93_TEMP_OFFSET_MIN,
 		mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
 	return (u8)((off + factor/2) / factor);
 }
@@ -620,8 +620,8 @@
 	if (rpm == 0) {
 		count = 0x3fff;
 	} else {
-		rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-		count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+		rpm = clamp_val(rpm, 1, 1000000);
+		count = clamp_val((1350000 + rpm) / rpm, 1, 0x3ffe);
 	}
 
 	regs = count << 2;
@@ -692,7 +692,7 @@
  */
 static u8 LM93_RAMP_TO_REG(int ramp)
 {
-	ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+	ramp = clamp_val(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
 	return (u8)((ramp + 2) / 5);
 }
 
@@ -702,7 +702,7 @@
  */
 static u8 LM93_PROCHOT_TO_REG(long prochot)
 {
-	prochot = SENSORS_LIMIT(prochot, 0, 255);
+	prochot = clamp_val(prochot, 0, 255);
 	return (u8)prochot;
 }
 
@@ -2052,7 +2052,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+	data->block9[nr][LM93_PWM_CTL1] = clamp_val(val, 0, 255);
 	lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1),
 				data->block9[nr][LM93_PWM_CTL1]);
 	mutex_unlock(&data->update_lock);
@@ -2397,7 +2397,7 @@
 
 	mutex_lock(&data->update_lock);
 	data->prochot_override = (data->prochot_override & 0xf0) |
-					SENSORS_LIMIT(val, 0, 15);
+					clamp_val(val, 0, 15);
 	lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
 			data->prochot_override);
 	mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index 2915fd9..a6c85f0 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -259,7 +259,7 @@
 
 	val /= 1000;
 
-	val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255));
+	val = clamp_val(val, 0, (index == 6 ? 127 : 255));
 
 	mutex_lock(&data->update_lock);
 
@@ -284,7 +284,7 @@
 
 	val /= 1000;
 
-	val = SENSORS_LIMIT(val, 0, 31);
+	val = clamp_val(val, 0, 31);
 
 	mutex_lock(&data->update_lock);
 
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index e0019c6..2fa2c02 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -118,7 +118,7 @@
 
 static inline int MV_TO_LIMIT(int mv, int range)
 {
-	return SENSORS_LIMIT(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
+	return clamp_val(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
 }
 
 static inline int ADC_TO_CURR(int adc, int gain)
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
index 666d9f6..a762635 100644
--- a/drivers/hwmon/max1668.c
+++ b/drivers/hwmon/max1668.c
@@ -215,7 +215,7 @@
 		return ret;
 
 	mutex_lock(&data->update_lock);
-	data->temp_max[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+	data->temp_max[index] = clamp_val(temp/1000, -128, 127);
 	if (i2c_smbus_write_byte_data(client,
 					MAX1668_REG_LIMH_WR(index),
 					data->temp_max[index]))
@@ -240,7 +240,7 @@
 		return ret;
 
 	mutex_lock(&data->update_lock);
-	data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+	data->temp_min[index] = clamp_val(temp/1000, -128, 127);
 	if (i2c_smbus_write_byte_data(client,
 					MAX1668_REG_LIML_WR(index),
 					data->temp_max[index]))
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 6e60036..3e7b426 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -74,7 +74,7 @@
 
 #define FAN_FROM_REG(val, rpm_range)	((val) == 0 || (val) == 255 ? \
 				0 : (rpm_ranges[rpm_range] * 30) / (val))
-#define TEMP_LIMIT_TO_REG(val)	SENSORS_LIMIT((val) / 1000, 0, 255)
+#define TEMP_LIMIT_TO_REG(val)	clamp_val((val) / 1000, 0, 255)
 
 /*
  * Client data (each client gets its own)
@@ -312,7 +312,7 @@
 	if (res)
 		return res;
 
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm[attr->index] = (u8)(val * 120 / 255);
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
index 223461a..57d58cd 100644
--- a/drivers/hwmon/max6642.c
+++ b/drivers/hwmon/max6642.c
@@ -239,7 +239,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255);
+	data->temp_high[attr2->nr] = clamp_val(temp_to_reg(val), 0, 255);
 	i2c_smbus_write_byte_data(client, attr2->index,
 				  data->temp_high[attr2->nr]);
 	mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index f739f83..3c16cbd 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -245,7 +245,7 @@
 	if (err)
 		return err;
 
-	rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+	rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
 
 	/*
 	 * Divide the required speed by 60 to get from rpm to rps, then
@@ -313,7 +313,7 @@
 	if (err)
 		return err;
 
-	pwm = SENSORS_LIMIT(pwm, 0, 255);
+	pwm = clamp_val(pwm, 0, 255);
 
 	mutex_lock(&data->update_lock);
 
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
new file mode 100644
index 0000000..bf4aa37
--- /dev/null
+++ b/drivers/hwmon/max6697.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * based on max1668.c
+ * Copyright (c) 2011 David George <david.george@ska.ac.za>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+
+#include <linux/platform_data/max6697.h>
+
+enum chips { max6581, max6602, max6622, max6636, max6689, max6693, max6694,
+	     max6697, max6698, max6699 };
+
+/* Report local sensor as temp1 */
+
+static const u8 MAX6697_REG_TEMP[] = {
+			0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08 };
+static const u8 MAX6697_REG_TEMP_EXT[] = {
+			0x57, 0x09, 0x52, 0x53, 0x54, 0x55, 0x56, 0 };
+static const u8 MAX6697_REG_MAX[] = {
+			0x17, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18 };
+static const u8 MAX6697_REG_CRIT[] = {
+			0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 };
+
+/*
+ * Map device tree / platform data register bit map to chip bit map.
+ * Applies to alert register and over-temperature register.
+ */
+#define MAX6697_MAP_BITS(reg)	((((reg) & 0x7e) >> 1) | \
+				 (((reg) & 0x01) << 6) | ((reg) & 0x80))
+
+#define MAX6697_REG_STAT(n)		(0x44 + (n))
+
+#define MAX6697_REG_CONFIG		0x41
+#define MAX6581_CONF_EXTENDED		(1 << 1)
+#define MAX6693_CONF_BETA		(1 << 2)
+#define MAX6697_CONF_RESISTANCE		(1 << 3)
+#define MAX6697_CONF_TIMEOUT		(1 << 5)
+#define MAX6697_REG_ALERT_MASK		0x42
+#define MAX6697_REG_OVERT_MASK		0x43
+
+#define MAX6581_REG_RESISTANCE		0x4a
+#define MAX6581_REG_IDEALITY		0x4b
+#define MAX6581_REG_IDEALITY_SELECT	0x4c
+#define MAX6581_REG_OFFSET		0x4d
+#define MAX6581_REG_OFFSET_SELECT	0x4e
+
+#define MAX6697_CONV_TIME		156	/* ms per channel, worst case */
+
+struct max6697_chip_data {
+	int channels;
+	u32 have_ext;
+	u32 have_crit;
+	u32 have_fault;
+	u8 valid_conf;
+	const u8 *alarm_map;
+};
+
+struct max6697_data {
+	struct device *hwmon_dev;
+
+	enum chips type;
+	const struct max6697_chip_data *chip;
+
+	int update_interval;	/* in milli-seconds */
+	int temp_offset;	/* in degrees C */
+
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+	bool valid;		/* true if following fields are valid */
+
+	/* 1x local and up to 7x remote */
+	u8 temp[8][4];		/* [nr][0]=temp [1]=ext [2]=max [3]=crit */
+#define MAX6697_TEMP_INPUT	0
+#define MAX6697_TEMP_EXT	1
+#define MAX6697_TEMP_MAX	2
+#define MAX6697_TEMP_CRIT	3
+	u32 alarms;
+};
+
+/* Diode fault status bits on MAX6581 are right shifted by one bit */
+static const u8 max6581_alarm_map[] = {
+	 0, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23 };
+
+static const struct max6697_chip_data max6697_chip_data[] = {
+	[max6581] = {
+		.channels = 8,
+		.have_crit = 0xff,
+		.have_ext = 0x7f,
+		.have_fault = 0xfe,
+		.valid_conf = MAX6581_CONF_EXTENDED | MAX6697_CONF_TIMEOUT,
+		.alarm_map = max6581_alarm_map,
+	},
+	[max6602] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6622] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6636] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6689] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6693] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+		  MAX6697_CONF_TIMEOUT,
+	},
+	[max6694] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+		  MAX6697_CONF_TIMEOUT,
+	},
+	[max6697] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x7e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6698] = {
+		.channels = 7,
+		.have_crit = 0x72,
+		.have_ext = 0x02,
+		.have_fault = 0x0e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+	[max6699] = {
+		.channels = 5,
+		.have_crit = 0x12,
+		.have_ext = 0x02,
+		.have_fault = 0x1e,
+		.valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+	},
+};
+
+static struct max6697_data *max6697_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6697_data *data = i2c_get_clientdata(client);
+	struct max6697_data *ret = data;
+	int val;
+	int i;
+	u32 alarms;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->valid &&
+	    !time_after(jiffies, data->last_updated
+			+ msecs_to_jiffies(data->update_interval)))
+		goto abort;
+
+	for (i = 0; i < data->chip->channels; i++) {
+		if (data->chip->have_ext & (1 << i)) {
+			val = i2c_smbus_read_byte_data(client,
+						       MAX6697_REG_TEMP_EXT[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->temp[i][MAX6697_TEMP_EXT] = val;
+		}
+
+		val = i2c_smbus_read_byte_data(client, MAX6697_REG_TEMP[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp[i][MAX6697_TEMP_INPUT] = val;
+
+		val = i2c_smbus_read_byte_data(client, MAX6697_REG_MAX[i]);
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		data->temp[i][MAX6697_TEMP_MAX] = val;
+
+		if (data->chip->have_crit & (1 << i)) {
+			val = i2c_smbus_read_byte_data(client,
+						       MAX6697_REG_CRIT[i]);
+			if (unlikely(val < 0)) {
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->temp[i][MAX6697_TEMP_CRIT] = val;
+		}
+	}
+
+	alarms = 0;
+	for (i = 0; i < 3; i++) {
+		val = i2c_smbus_read_byte_data(client, MAX6697_REG_STAT(i));
+		if (unlikely(val < 0)) {
+			ret = ERR_PTR(val);
+			goto abort;
+		}
+		alarms = (alarms << 8) | val;
+	}
+	data->alarms = alarms;
+	data->last_updated = jiffies;
+	data->valid = true;
+abort:
+	mutex_unlock(&data->update_lock);
+
+	return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+			       struct device_attribute *devattr, char *buf)
+{
+	int index = to_sensor_dev_attr(devattr)->index;
+	struct max6697_data *data = max6697_update_device(dev);
+	int temp;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = (data->temp[index][MAX6697_TEMP_INPUT] - data->temp_offset) << 3;
+	temp |= data->temp[index][MAX6697_TEMP_EXT] >> 5;
+
+	return sprintf(buf, "%d\n", temp * 125);
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int index = to_sensor_dev_attr_2(devattr)->index;
+	struct max6697_data *data = max6697_update_device(dev);
+	int temp;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	temp = data->temp[nr][index];
+	temp -= data->temp_offset;
+
+	return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+	struct max6697_data *data = max6697_update_device(dev);
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	if (data->chip->alarm_map)
+		index = data->chip->alarm_map[index];
+
+	return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t set_temp(struct device *dev,
+			struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	int index = to_sensor_dev_attr_2(devattr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6697_data *data = i2c_get_clientdata(client);
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	temp = DIV_ROUND_CLOSEST(temp, 1000) + data->temp_offset;
+	temp = clamp_val(temp, 0, data->type == max6581 ? 255 : 127);
+	data->temp[nr][index] = temp;
+	ret = i2c_smbus_write_byte_data(client,
+					index == 2 ? MAX6697_REG_MAX[nr]
+						   : MAX6697_REG_CRIT[nr],
+					temp);
+	mutex_unlock(&data->update_lock);
+
+	return ret < 0 ? ret : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    0, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    1, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    2, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    3, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    3, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    4, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    4, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    5, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    5, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp_input, NULL, 6);
+static SENSOR_DEVICE_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    6, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    6, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp_input, NULL, 7);
+static SENSOR_DEVICE_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    7, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+			    7, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp7_max_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp8_max_alarm, S_IRUGO, show_alarm, NULL, 23);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp7_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp8_crit_alarm, S_IRUGO, show_alarm, NULL, 15);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
+
+static struct attribute *max6697_attributes[8][7] = {
+	{
+		&sensor_dev_attr_temp1_input.dev_attr.attr,
+		&sensor_dev_attr_temp1_max.dev_attr.attr,
+		&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp1_crit.dev_attr.attr,
+		&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp2_input.dev_attr.attr,
+		&sensor_dev_attr_temp2_max.dev_attr.attr,
+		&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp2_crit.dev_attr.attr,
+		&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp2_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp3_input.dev_attr.attr,
+		&sensor_dev_attr_temp3_max.dev_attr.attr,
+		&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp3_crit.dev_attr.attr,
+		&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp3_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp4_input.dev_attr.attr,
+		&sensor_dev_attr_temp4_max.dev_attr.attr,
+		&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp4_crit.dev_attr.attr,
+		&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp4_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp5_input.dev_attr.attr,
+		&sensor_dev_attr_temp5_max.dev_attr.attr,
+		&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp5_crit.dev_attr.attr,
+		&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp5_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp6_input.dev_attr.attr,
+		&sensor_dev_attr_temp6_max.dev_attr.attr,
+		&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp6_crit.dev_attr.attr,
+		&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp6_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp7_input.dev_attr.attr,
+		&sensor_dev_attr_temp7_max.dev_attr.attr,
+		&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp7_crit.dev_attr.attr,
+		&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp7_fault.dev_attr.attr,
+		NULL
+	}, {
+		&sensor_dev_attr_temp8_input.dev_attr.attr,
+		&sensor_dev_attr_temp8_max.dev_attr.attr,
+		&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp8_crit.dev_attr.attr,
+		&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+		&sensor_dev_attr_temp8_fault.dev_attr.attr,
+		NULL
+	}
+};
+
+static const struct attribute_group max6697_group[8] = {
+	{ .attrs = max6697_attributes[0] },
+	{ .attrs = max6697_attributes[1] },
+	{ .attrs = max6697_attributes[2] },
+	{ .attrs = max6697_attributes[3] },
+	{ .attrs = max6697_attributes[4] },
+	{ .attrs = max6697_attributes[5] },
+	{ .attrs = max6697_attributes[6] },
+	{ .attrs = max6697_attributes[7] },
+};
+
+static void max6697_get_config_of(struct device_node *node,
+				  struct max6697_platform_data *pdata)
+{
+	int len;
+	const __be32 *prop;
+
+	prop = of_get_property(node, "smbus-timeout-disable", &len);
+	if (prop)
+		pdata->smbus_timeout_disable = true;
+	prop = of_get_property(node, "extended-range-enable", &len);
+	if (prop)
+		pdata->extended_range_enable = true;
+	prop = of_get_property(node, "beta-compensation-enable", &len);
+	if (prop)
+		pdata->beta_compensation = true;
+	prop = of_get_property(node, "alert-mask", &len);
+	if (prop && len == sizeof(u32))
+		pdata->alert_mask = be32_to_cpu(prop[0]);
+	prop = of_get_property(node, "over-temperature-mask", &len);
+	if (prop && len == sizeof(u32))
+		pdata->over_temperature_mask = be32_to_cpu(prop[0]);
+	prop = of_get_property(node, "resistance-cancellation", &len);
+	if (prop) {
+		if (len == sizeof(u32))
+			pdata->resistance_cancellation = be32_to_cpu(prop[0]);
+		else
+			pdata->resistance_cancellation = 0xfe;
+	}
+	prop = of_get_property(node, "transistor-ideality", &len);
+	if (prop && len == 2 * sizeof(u32)) {
+			pdata->ideality_mask = be32_to_cpu(prop[0]);
+			pdata->ideality_value = be32_to_cpu(prop[1]);
+	}
+}
+
+static int max6697_init_chip(struct i2c_client *client)
+{
+	struct max6697_data *data = i2c_get_clientdata(client);
+	struct max6697_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct max6697_platform_data p;
+	const struct max6697_chip_data *chip = data->chip;
+	int factor = chip->channels;
+	int ret, reg;
+
+	/*
+	 * Don't touch configuration if neither platform data nor OF
+	 * configuration was specified. If that is the case, use the
+	 * current chip configuration.
+	 */
+	if (!pdata && !client->dev.of_node) {
+		reg = i2c_smbus_read_byte_data(client, MAX6697_REG_CONFIG);
+		if (reg < 0)
+			return reg;
+		if (data->type == max6581) {
+			if (reg & MAX6581_CONF_EXTENDED)
+				data->temp_offset = 64;
+			reg = i2c_smbus_read_byte_data(client,
+						       MAX6581_REG_RESISTANCE);
+			if (reg < 0)
+				return reg;
+			factor += hweight8(reg);
+		} else {
+			if (reg & MAX6697_CONF_RESISTANCE)
+				factor++;
+		}
+		goto done;
+	}
+
+	if (client->dev.of_node) {
+		memset(&p, 0, sizeof(p));
+		max6697_get_config_of(client->dev.of_node, &p);
+		pdata = &p;
+	}
+
+	reg = 0;
+	if (pdata->smbus_timeout_disable &&
+	    (chip->valid_conf & MAX6697_CONF_TIMEOUT)) {
+		reg |= MAX6697_CONF_TIMEOUT;
+	}
+	if (pdata->extended_range_enable &&
+	    (chip->valid_conf & MAX6581_CONF_EXTENDED)) {
+		reg |= MAX6581_CONF_EXTENDED;
+		data->temp_offset = 64;
+	}
+	if (pdata->resistance_cancellation &&
+	    (chip->valid_conf & MAX6697_CONF_RESISTANCE)) {
+		reg |= MAX6697_CONF_RESISTANCE;
+		factor++;
+	}
+	if (pdata->beta_compensation &&
+	    (chip->valid_conf & MAX6693_CONF_BETA)) {
+		reg |= MAX6693_CONF_BETA;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_CONFIG, reg);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_ALERT_MASK,
+					MAX6697_MAP_BITS(pdata->alert_mask));
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, MAX6697_REG_OVERT_MASK,
+				MAX6697_MAP_BITS(pdata->over_temperature_mask));
+	if (ret < 0)
+		return ret;
+
+	if (data->type == max6581) {
+		factor += hweight8(pdata->resistance_cancellation >> 1);
+		ret = i2c_smbus_write_byte_data(client, MAX6581_REG_RESISTANCE,
+					pdata->resistance_cancellation >> 1);
+		if (ret < 0)
+			return ret;
+		ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
+						pdata->ideality_mask >> 1);
+		if (ret < 0)
+			return ret;
+		ret = i2c_smbus_write_byte_data(client,
+						MAX6581_REG_IDEALITY_SELECT,
+						pdata->ideality_value);
+		if (ret < 0)
+			return ret;
+	}
+done:
+	data->update_interval = factor * MAX6697_CONV_TIME;
+	return 0;
+}
+
+static void max6697_remove_files(struct i2c_client *client)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
+		sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
+}
+
+static int max6697_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct device *dev = &client->dev;
+	struct max6697_data *data;
+	int i, err;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(struct max6697_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->type = id->driver_data;
+	data->chip = &max6697_chip_data[data->type];
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	err = max6697_init_chip(client);
+	if (err)
+		return err;
+
+	for (i = 0; i < data->chip->channels; i++) {
+		err = sysfs_create_file(&dev->kobj,
+					max6697_attributes[i][0]);
+		if (err)
+			goto error;
+		err = sysfs_create_file(&dev->kobj,
+					max6697_attributes[i][1]);
+		if (err)
+			goto error;
+		err = sysfs_create_file(&dev->kobj,
+					max6697_attributes[i][2]);
+		if (err)
+			goto error;
+
+		if (data->chip->have_crit & (1 << i)) {
+			err = sysfs_create_file(&dev->kobj,
+						max6697_attributes[i][3]);
+			if (err)
+				goto error;
+			err = sysfs_create_file(&dev->kobj,
+						max6697_attributes[i][4]);
+			if (err)
+				goto error;
+		}
+		if (data->chip->have_fault & (1 << i)) {
+			err = sysfs_create_file(&dev->kobj,
+						max6697_attributes[i][5]);
+			if (err)
+				goto error;
+		}
+	}
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	max6697_remove_files(client);
+	return err;
+}
+
+static int max6697_remove(struct i2c_client *client)
+{
+	struct max6697_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	max6697_remove_files(client);
+
+	return 0;
+}
+
+static const struct i2c_device_id max6697_id[] = {
+	{ "max6581", max6581 },
+	{ "max6602", max6602 },
+	{ "max6622", max6622 },
+	{ "max6636", max6636 },
+	{ "max6689", max6689 },
+	{ "max6693", max6693 },
+	{ "max6694", max6694 },
+	{ "max6697", max6697 },
+	{ "max6698", max6698 },
+	{ "max6699", max6699 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max6697_id);
+
+static struct i2c_driver max6697_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "max6697",
+	},
+	.probe = max6697_probe,
+	.remove	= max6697_remove,
+	.id_table = max6697_id,
+};
+
+module_i2c_driver(max6697_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("MAX6697 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index a87eb89..b5f63f9 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -43,7 +43,7 @@
  * The following compensation tables are from the specification of Murata NTC
  * Thermistors Datasheet
  */
-const struct ntc_compensation ncpXXwb473[] = {
+static const struct ntc_compensation ncpXXwb473[] = {
 	{ .temp_C	= -40, .ohm	= 1747920 },
 	{ .temp_C	= -35, .ohm	= 1245428 },
 	{ .temp_C	= -30, .ohm	= 898485 },
@@ -79,7 +79,7 @@
 	{ .temp_C	= 120, .ohm	= 1615 },
 	{ .temp_C	= 125, .ohm	= 1406 },
 };
-const struct ntc_compensation ncpXXwl333[] = {
+static const struct ntc_compensation ncpXXwl333[] = {
 	{ .temp_C	= -40, .ohm	= 1610154 },
 	{ .temp_C	= -35, .ohm	= 1130850 },
 	{ .temp_C	= -30, .ohm	= 802609 },
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 60745a5..4f9eb0a 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -72,7 +72,7 @@
 	default n
 	help
 	  If you say yes here you get hardware monitoring support for Maxim
-	  MAX34440, MAX34441, and MAX34446.
+	  MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461.
 
 	  This driver can also be built as a module. If so, the module will
 	  be called max34440.
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index 2ada7b0..7e930c3 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -2,6 +2,7 @@
  * Hardware monitoring driver for Maxim MAX34440/MAX34441
  *
  * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * 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
@@ -25,7 +26,7 @@
 #include <linux/i2c.h>
 #include "pmbus.h"
 
-enum chips { max34440, max34441, max34446 };
+enum chips { max34440, max34441, max34446, max34460, max34461 };
 
 #define MAX34440_MFR_VOUT_PEAK		0xd4
 #define MAX34440_MFR_IOUT_PEAK		0xd5
@@ -87,7 +88,8 @@
 					   MAX34446_MFR_POUT_PEAK);
 		break;
 	case PMBUS_VIRT_READ_TEMP_AVG:
-		if (data->id != max34446)
+		if (data->id != max34446 && data->id != max34460 &&
+		    data->id != max34461)
 			return -ENXIO;
 		ret = pmbus_read_word_data(client, page,
 					   MAX34446_MFR_TEMPERATURE_AVG);
@@ -322,6 +324,73 @@
 		.read_word_data = max34440_read_word_data,
 		.write_word_data = max34440_write_word_data,
 	},
+	[max34460] = {
+		.pages = 18,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[14] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
+	[max34461] = {
+		.pages = 23,
+		.format[PSC_VOLTAGE_OUT] = direct,
+		.format[PSC_TEMPERATURE] = direct,
+		.m[PSC_VOLTAGE_OUT] = 1,
+		.b[PSC_VOLTAGE_OUT] = 0,
+		.R[PSC_VOLTAGE_OUT] = 3,
+		.m[PSC_TEMPERATURE] = 1,
+		.b[PSC_TEMPERATURE] = 0,
+		.R[PSC_TEMPERATURE] = 2,
+		.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[12] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[13] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[14] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		.func[15] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+		/* page 16 is reserved */
+		.func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+		.read_byte_data = max34440_read_byte_data,
+		.read_word_data = max34440_read_word_data,
+		.write_word_data = max34440_write_word_data,
+	},
 };
 
 static int max34440_probe(struct i2c_client *client,
@@ -343,6 +412,8 @@
 	{"max34440", max34440},
 	{"max34441", max34441},
 	{"max34446", max34446},
+	{"max34460", max34460},
+	{"max34461", max34461},
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, max34440_id);
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 3fe03dc..fa9beb3 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -2,6 +2,7 @@
  * pmbus.h - Common defines and structures for PMBus devices
  *
  * Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * 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
@@ -177,6 +178,13 @@
 #define PMBUS_VIRT_READ_TEMP2_MAX	(PMBUS_VIRT_BASE + 28)
 #define PMBUS_VIRT_RESET_TEMP2_HISTORY	(PMBUS_VIRT_BASE + 29)
 
+#define PMBUS_VIRT_READ_VMON		(PMBUS_VIRT_BASE + 30)
+#define PMBUS_VIRT_VMON_UV_WARN_LIMIT	(PMBUS_VIRT_BASE + 31)
+#define PMBUS_VIRT_VMON_OV_WARN_LIMIT	(PMBUS_VIRT_BASE + 32)
+#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT	(PMBUS_VIRT_BASE + 33)
+#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT	(PMBUS_VIRT_BASE + 34)
+#define PMBUS_VIRT_STATUS_VMON		(PMBUS_VIRT_BASE + 35)
+
 /*
  * CAPABILITY
  */
@@ -317,6 +325,8 @@
 #define PMBUS_HAVE_STATUS_TEMP	(1 << 15)
 #define PMBUS_HAVE_STATUS_FAN12	(1 << 16)
 #define PMBUS_HAVE_STATUS_FAN34	(1 << 17)
+#define PMBUS_HAVE_VMON		(1 << 18)
+#define PMBUS_HAVE_STATUS_VMON	(1 << 19)
 
 enum pmbus_data_format { linear = 0, direct, vid };
 
@@ -359,6 +369,7 @@
 
 /* Function declarations */
 
+void pmbus_clear_cache(struct i2c_client *client);
 int pmbus_set_page(struct i2c_client *client, u8 page);
 int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
 int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 7d19b1b..80eef50 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -2,6 +2,7 @@
  * Hardware monitoring driver for PMBus devices
  *
  * Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * 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
@@ -31,45 +32,10 @@
 #include "pmbus.h"
 
 /*
- * Constants needed to determine number of sensors, booleans, and labels.
+ * Number of additional attribute pointers to allocate
+ * with each call to krealloc
  */
-#define PMBUS_MAX_INPUT_SENSORS		22	/* 10*volt, 7*curr, 5*power */
-#define PMBUS_VOUT_SENSORS_PER_PAGE	9	/* input, min, max, lcrit,
-						   crit, lowest, highest, avg,
-						   reset */
-#define PMBUS_IOUT_SENSORS_PER_PAGE	8	/* input, min, max, crit,
-						   lowest, highest, avg,
-						   reset */
-#define PMBUS_POUT_SENSORS_PER_PAGE	7	/* input, cap, max, crit,
-						 * highest, avg, reset
-						 */
-#define PMBUS_MAX_SENSORS_PER_FAN	1	/* input */
-#define PMBUS_MAX_SENSORS_PER_TEMP	9	/* input, min, max, lcrit,
-						 * crit, lowest, highest, avg,
-						 * reset
-						 */
-
-#define PMBUS_MAX_INPUT_BOOLEANS	7	/* v: min_alarm, max_alarm,
-						   lcrit_alarm, crit_alarm;
-						   c: alarm, crit_alarm;
-						   p: crit_alarm */
-#define PMBUS_VOUT_BOOLEANS_PER_PAGE	4	/* min_alarm, max_alarm,
-						   lcrit_alarm, crit_alarm */
-#define PMBUS_IOUT_BOOLEANS_PER_PAGE	3	/* alarm, lcrit_alarm,
-						   crit_alarm */
-#define PMBUS_POUT_BOOLEANS_PER_PAGE	3	/* cap_alarm, alarm, crit_alarm
-						 */
-#define PMBUS_MAX_BOOLEANS_PER_FAN	2	/* alarm, fault */
-#define PMBUS_MAX_BOOLEANS_PER_TEMP	4	/* min_alarm, max_alarm,
-						   lcrit_alarm, crit_alarm */
-
-#define PMBUS_MAX_INPUT_LABELS		4	/* vin, vcap, iin, pin */
-
-/*
- * status, status_vout, status_iout, status_fans, status_fan34, and status_temp
- * are paged. status_input is unpaged.
- */
-#define PB_NUM_STATUS_REG	(PMBUS_PAGES * 6 + 1)
+#define PMBUS_ATTR_ALLOC_SIZE	32
 
 /*
  * Index into status register array, per status register group
@@ -79,14 +45,18 @@
 #define PB_STATUS_IOUT_BASE	(PB_STATUS_VOUT_BASE + PMBUS_PAGES)
 #define PB_STATUS_FAN_BASE	(PB_STATUS_IOUT_BASE + PMBUS_PAGES)
 #define PB_STATUS_FAN34_BASE	(PB_STATUS_FAN_BASE + PMBUS_PAGES)
-#define PB_STATUS_INPUT_BASE	(PB_STATUS_FAN34_BASE + PMBUS_PAGES)
-#define PB_STATUS_TEMP_BASE	(PB_STATUS_INPUT_BASE + 1)
+#define PB_STATUS_TEMP_BASE	(PB_STATUS_FAN34_BASE + PMBUS_PAGES)
+#define PB_STATUS_INPUT_BASE	(PB_STATUS_TEMP_BASE + PMBUS_PAGES)
+#define PB_STATUS_VMON_BASE	(PB_STATUS_INPUT_BASE + 1)
+
+#define PB_NUM_STATUS_REG	(PB_STATUS_VMON_BASE + 1)
 
 #define PMBUS_NAME_SIZE		24
 
 struct pmbus_sensor {
+	struct pmbus_sensor *next;
 	char name[PMBUS_NAME_SIZE];	/* sysfs sensor name */
-	struct sensor_device_attribute attribute;
+	struct device_attribute attribute;
 	u8 page;		/* page number */
 	u16 reg;		/* register */
 	enum pmbus_sensor_classes class;	/* sensor class */
@@ -94,19 +64,28 @@
 	int data;		/* Sensor data.
 				   Negative if there was a read error */
 };
+#define to_pmbus_sensor(_attr) \
+	container_of(_attr, struct pmbus_sensor, attribute)
 
 struct pmbus_boolean {
 	char name[PMBUS_NAME_SIZE];	/* sysfs boolean name */
 	struct sensor_device_attribute attribute;
+	struct pmbus_sensor *s1;
+	struct pmbus_sensor *s2;
 };
+#define to_pmbus_boolean(_attr) \
+	container_of(_attr, struct pmbus_boolean, attribute)
 
 struct pmbus_label {
 	char name[PMBUS_NAME_SIZE];	/* sysfs label name */
-	struct sensor_device_attribute attribute;
+	struct device_attribute attribute;
 	char label[PMBUS_NAME_SIZE];	/* label */
 };
+#define to_pmbus_label(_attr) \
+	container_of(_attr, struct pmbus_label, attribute)
 
 struct pmbus_data {
+	struct device *dev;
 	struct device *hwmon_dev;
 
 	u32 flags;		/* from platform data */
@@ -117,29 +96,9 @@
 
 	int max_attributes;
 	int num_attributes;
-	struct attribute **attributes;
 	struct attribute_group group;
 
-	/*
-	 * Sensors cover both sensor and limit registers.
-	 */
-	int max_sensors;
-	int num_sensors;
 	struct pmbus_sensor *sensors;
-	/*
-	 * Booleans are used for alarms.
-	 * Values are determined from status registers.
-	 */
-	int max_booleans;
-	int num_booleans;
-	struct pmbus_boolean *booleans;
-	/*
-	 * Labels are used to map generic names (e.g., "in1")
-	 * to PMBus specific names (e.g., "vin" or "vout1").
-	 */
-	int max_labels;
-	int num_labels;
-	struct pmbus_label *labels;
 
 	struct mutex update_lock;
 	bool valid;
@@ -150,10 +109,19 @@
 	 * so we keep them all together.
 	 */
 	u8 status[PB_NUM_STATUS_REG];
+	u8 status_register;
 
 	u8 currpage;
 };
 
+void pmbus_clear_cache(struct i2c_client *client)
+{
+	struct pmbus_data *data = i2c_get_clientdata(client);
+
+	data->valid = false;
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_cache);
+
 int pmbus_set_page(struct i2c_client *client, u8 page)
 {
 	struct pmbus_data *data = i2c_get_clientdata(client);
@@ -318,9 +286,10 @@
 
 static int pmbus_check_status_cml(struct i2c_client *client)
 {
+	struct pmbus_data *data = i2c_get_clientdata(client);
 	int status, status2;
 
-	status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
+	status = _pmbus_read_byte_data(client, -1, data->status_register);
 	if (status < 0 || (status & PB_STATUS_CML)) {
 		status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
 		if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
@@ -329,29 +298,30 @@
 	return 0;
 }
 
-bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+static bool pmbus_check_register(struct i2c_client *client,
+				 int (*func)(struct i2c_client *client,
+					     int page, int reg),
+				 int page, int reg)
 {
 	int rv;
 	struct pmbus_data *data = i2c_get_clientdata(client);
 
-	rv = _pmbus_read_byte_data(client, page, reg);
+	rv = func(client, page, reg);
 	if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
 		rv = pmbus_check_status_cml(client);
 	pmbus_clear_fault_page(client, -1);
 	return rv >= 0;
 }
+
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+{
+	return pmbus_check_register(client, _pmbus_read_byte_data, page, reg);
+}
 EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
 
 bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
 {
-	int rv;
-	struct pmbus_data *data = i2c_get_clientdata(client);
-
-	rv = _pmbus_read_word_data(client, page, reg);
-	if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
-		rv = pmbus_check_status_cml(client);
-	pmbus_clear_fault_page(client, -1);
-	return rv >= 0;
+	return pmbus_check_register(client, _pmbus_read_word_data, page, reg);
 }
 EXPORT_SYMBOL_GPL(pmbus_check_word_register);
 
@@ -363,53 +333,43 @@
 }
 EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
 
+static struct _pmbus_status {
+	u32 func;
+	u16 base;
+	u16 reg;
+} pmbus_status[] = {
+	{ PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT },
+	{ PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT },
+	{ PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE,
+	  PMBUS_STATUS_TEMPERATURE },
+	{ PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 },
+	{ PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 },
+};
+
 static struct pmbus_data *pmbus_update_device(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct pmbus_data *data = i2c_get_clientdata(client);
 	const struct pmbus_driver_info *info = data->info;
+	struct pmbus_sensor *sensor;
 
 	mutex_lock(&data->update_lock);
 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-		int i;
+		int i, j;
 
-		for (i = 0; i < info->pages; i++)
+		for (i = 0; i < info->pages; i++) {
 			data->status[PB_STATUS_BASE + i]
 			    = _pmbus_read_byte_data(client, i,
-						    PMBUS_STATUS_BYTE);
-		for (i = 0; i < info->pages; i++) {
-			if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
-				continue;
-			data->status[PB_STATUS_VOUT_BASE + i]
-			  = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT);
-		}
-		for (i = 0; i < info->pages; i++) {
-			if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT))
-				continue;
-			data->status[PB_STATUS_IOUT_BASE + i]
-			  = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT);
-		}
-		for (i = 0; i < info->pages; i++) {
-			if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP))
-				continue;
-			data->status[PB_STATUS_TEMP_BASE + i]
-			  = _pmbus_read_byte_data(client, i,
-						  PMBUS_STATUS_TEMPERATURE);
-		}
-		for (i = 0; i < info->pages; i++) {
-			if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12))
-				continue;
-			data->status[PB_STATUS_FAN_BASE + i]
-			  = _pmbus_read_byte_data(client, i,
-						  PMBUS_STATUS_FAN_12);
-		}
+						    data->status_register);
+			for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) {
+				struct _pmbus_status *s = &pmbus_status[j];
 
-		for (i = 0; i < info->pages; i++) {
-			if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34))
-				continue;
-			data->status[PB_STATUS_FAN34_BASE + i]
-			  = _pmbus_read_byte_data(client, i,
-						  PMBUS_STATUS_FAN_34);
+				if (!(info->func[i] & s->func))
+					continue;
+				data->status[s->base + i]
+					= _pmbus_read_byte_data(client, i,
+								s->reg);
+			}
 		}
 
 		if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
@@ -417,9 +377,12 @@
 			  = _pmbus_read_byte_data(client, 0,
 						  PMBUS_STATUS_INPUT);
 
-		for (i = 0; i < data->num_sensors; i++) {
-			struct pmbus_sensor *sensor = &data->sensors[i];
+		if (info->func[0] & PMBUS_HAVE_STATUS_VMON)
+			data->status[PB_STATUS_VMON_BASE]
+			  = _pmbus_read_byte_data(client, 0,
+						  PMBUS_VIRT_STATUS_VMON);
 
+		for (sensor = data->sensors; sensor; sensor = sensor->next) {
 			if (!data->valid || sensor->update)
 				sensor->data
 				    = _pmbus_read_word_data(client,
@@ -657,7 +620,7 @@
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
 			      enum pmbus_sensor_classes class, long val)
 {
-	val = SENSORS_LIMIT(val, 500, 1600);
+	val = clamp_val(val, 500, 1600);
 
 	return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
 }
@@ -684,25 +647,20 @@
 
 /*
  * Return boolean calculated from converted data.
- * <index> defines a status register index and mask, and optionally
- * two sensor indexes.
- * The upper half-word references the two sensors,
- * two sensor indices.
- * The upper half-word references the two optional sensors,
- * the lower half word references status register and mask.
- * The function returns true if (status[reg] & mask) is true and,
- * if specified, if v1 >= v2.
- * To determine if an object exceeds upper limits, specify <v, limit>.
- * To determine if an object exceeds lower limits, specify <limit, v>.
+ * <index> defines a status register index and mask.
+ * The mask is in the lower 8 bits, the register index is in bits 8..23.
  *
- * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of
- * index are set. s1 and s2 (the sensor index values) are zero in this case.
- * The function returns true if (status[reg] & mask) is true.
+ * The associated pmbus_boolean structure contains optional pointers to two
+ * sensor attributes. If specified, those attributes are compared against each
+ * other to determine if a limit has been exceeded.
  *
- * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against
- * a specified limit has to be performed to determine the boolean result.
+ * If the sensor attribute pointers are NULL, the function returns true if
+ * (status[reg] & mask) is true.
+ *
+ * If sensor attribute pointers are provided, a comparison against a specified
+ * limit has to be performed to determine the boolean result.
  * In this case, the function returns true if v1 >= v2 (where v1 and v2 are
- * sensor values referenced by sensor indices s1 and s2).
+ * sensor values referenced by sensor attribute pointers s1 and s2).
  *
  * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
  * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
@@ -710,11 +668,12 @@
  * If a negative value is stored in any of the referenced registers, this value
  * reflects an error code which will be returned.
  */
-static int pmbus_get_boolean(struct pmbus_data *data, int index)
+static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b,
+			     int index)
 {
-	u8 s1 = (index >> 24) & 0xff;
-	u8 s2 = (index >> 16) & 0xff;
-	u8 reg = (index >> 8) & 0xff;
+	struct pmbus_sensor *s1 = b->s1;
+	struct pmbus_sensor *s2 = b->s2;
+	u16 reg = (index >> 8) & 0xffff;
 	u8 mask = index & 0xff;
 	int ret, status;
 	u8 regval;
@@ -724,21 +683,21 @@
 		return status;
 
 	regval = status & mask;
-	if (!s1 && !s2)
+	if (!s1 && !s2) {
 		ret = !!regval;
-	else {
+	} else if (!s1 || !s2) {
+		BUG();
+		return 0;
+	} else {
 		long v1, v2;
-		struct pmbus_sensor *sensor1, *sensor2;
 
-		sensor1 = &data->sensors[s1];
-		if (sensor1->data < 0)
-			return sensor1->data;
-		sensor2 = &data->sensors[s2];
-		if (sensor2->data < 0)
-			return sensor2->data;
+		if (s1->data < 0)
+			return s1->data;
+		if (s2->data < 0)
+			return s2->data;
 
-		v1 = pmbus_reg2data(data, sensor1);
-		v2 = pmbus_reg2data(data, sensor2);
+		v1 = pmbus_reg2data(data, s1);
+		v2 = pmbus_reg2data(data, s2);
 		ret = !!(regval && v1 >= v2);
 	}
 	return ret;
@@ -748,23 +707,22 @@
 				  struct device_attribute *da, char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pmbus_boolean *boolean = to_pmbus_boolean(attr);
 	struct pmbus_data *data = pmbus_update_device(dev);
 	int val;
 
-	val = pmbus_get_boolean(data, attr->index);
+	val = pmbus_get_boolean(data, boolean, attr->index);
 	if (val < 0)
 		return val;
 	return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
 static ssize_t pmbus_show_sensor(struct device *dev,
-				 struct device_attribute *da, char *buf)
+				 struct device_attribute *devattr, char *buf)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct pmbus_data *data = pmbus_update_device(dev);
-	struct pmbus_sensor *sensor;
+	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
 
-	sensor = &data->sensors[attr->index];
 	if (sensor->data < 0)
 		return sensor->data;
 
@@ -775,10 +733,9 @@
 				struct device_attribute *devattr,
 				const char *buf, size_t count)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct i2c_client *client = to_i2c_client(dev);
 	struct pmbus_data *data = i2c_get_clientdata(client);
-	struct pmbus_sensor *sensor = &data->sensors[attr->index];
+	struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
 	ssize_t rv = count;
 	long val = 0;
 	int ret;
@@ -793,7 +750,7 @@
 	if (ret < 0)
 		rv = ret;
 	else
-		data->sensors[attr->index].data = regval;
+		sensor->data = regval;
 	mutex_unlock(&data->update_lock);
 	return rv;
 }
@@ -801,102 +758,130 @@
 static ssize_t pmbus_show_label(struct device *dev,
 				struct device_attribute *da, char *buf)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pmbus_data *data = i2c_get_clientdata(client);
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct pmbus_label *label = to_pmbus_label(da);
 
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-			data->labels[attr->index].label);
+	return snprintf(buf, PAGE_SIZE, "%s\n", label->label);
 }
 
-#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set)	\
-do {									\
-	struct sensor_device_attribute *a				\
-	    = &data->_type##s[data->num_##_type##s].attribute;		\
-	BUG_ON(data->num_attributes >= data->max_attributes);		\
-	sysfs_attr_init(&a->dev_attr.attr);				\
-	a->dev_attr.attr.name = _name;					\
-	a->dev_attr.attr.mode = _mode;					\
-	a->dev_attr.show = _show;					\
-	a->dev_attr.store = _set;					\
-	a->index = _idx;						\
-	data->attributes[data->num_attributes] = &a->dev_attr.attr;	\
-	data->num_attributes++;						\
-} while (0)
+static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
+{
+	if (data->num_attributes >= data->max_attributes - 1) {
+		data->max_attributes += PMBUS_ATTR_ALLOC_SIZE;
+		data->group.attrs = krealloc(data->group.attrs,
+					     sizeof(struct attribute *) *
+					     data->max_attributes, GFP_KERNEL);
+		if (data->group.attrs == NULL)
+			return -ENOMEM;
+	}
 
-#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx)			\
-	PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type,		\
-		       pmbus_show_##_type,  NULL)
+	data->group.attrs[data->num_attributes++] = attr;
+	data->group.attrs[data->num_attributes] = NULL;
+	return 0;
+}
 
-#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx)			\
-	PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type,	\
-		       pmbus_show_##_type, pmbus_set_##_type)
+static void pmbus_dev_attr_init(struct device_attribute *dev_attr,
+				const char *name,
+				umode_t mode,
+				ssize_t (*show)(struct device *dev,
+						struct device_attribute *attr,
+						char *buf),
+				ssize_t (*store)(struct device *dev,
+						 struct device_attribute *attr,
+						 const char *buf, size_t count))
+{
+	sysfs_attr_init(&dev_attr->attr);
+	dev_attr->attr.name = name;
+	dev_attr->attr.mode = mode;
+	dev_attr->show = show;
+	dev_attr->store = store;
+}
 
-static void pmbus_add_boolean(struct pmbus_data *data,
-			      const char *name, const char *type, int seq,
-			      int idx)
+static void pmbus_attr_init(struct sensor_device_attribute *a,
+			    const char *name,
+			    umode_t mode,
+			    ssize_t (*show)(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf),
+			    ssize_t (*store)(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count),
+			    int idx)
+{
+	pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store);
+	a->index = idx;
+}
+
+static int pmbus_add_boolean(struct pmbus_data *data,
+			     const char *name, const char *type, int seq,
+			     struct pmbus_sensor *s1,
+			     struct pmbus_sensor *s2,
+			     u16 reg, u8 mask)
 {
 	struct pmbus_boolean *boolean;
+	struct sensor_device_attribute *a;
 
-	BUG_ON(data->num_booleans >= data->max_booleans);
+	boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL);
+	if (!boolean)
+		return -ENOMEM;
 
-	boolean = &data->booleans[data->num_booleans];
+	a = &boolean->attribute;
 
 	snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
 		 name, seq, type);
-	PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx);
-	data->num_booleans++;
+	boolean->s1 = s1;
+	boolean->s2 = s2;
+	pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL,
+			(reg << 8) | mask);
+
+	return pmbus_add_attribute(data, &a->dev_attr.attr);
 }
 
-static void pmbus_add_boolean_reg(struct pmbus_data *data,
-				  const char *name, const char *type,
-				  int seq, int reg, int bit)
-{
-	pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
-}
-
-static void pmbus_add_boolean_cmp(struct pmbus_data *data,
-				  const char *name, const char *type,
-				  int seq, int i1, int i2, int reg, int mask)
-{
-	pmbus_add_boolean(data, name, type, seq,
-			  (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
-}
-
-static void pmbus_add_sensor(struct pmbus_data *data,
-			     const char *name, const char *type, int seq,
-			     int page, int reg, enum pmbus_sensor_classes class,
-			     bool update, bool readonly)
+static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+					     const char *name, const char *type,
+					     int seq, int page, int reg,
+					     enum pmbus_sensor_classes class,
+					     bool update, bool readonly)
 {
 	struct pmbus_sensor *sensor;
+	struct device_attribute *a;
 
-	BUG_ON(data->num_sensors >= data->max_sensors);
+	sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return NULL;
+	a = &sensor->attribute;
 
-	sensor = &data->sensors[data->num_sensors];
 	snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
 		 name, seq, type);
 	sensor->page = page;
 	sensor->reg = reg;
 	sensor->class = class;
 	sensor->update = update;
-	if (readonly)
-		PMBUS_ADD_GET_ATTR(data, sensor->name, sensor,
-				   data->num_sensors);
-	else
-		PMBUS_ADD_SET_ATTR(data, sensor->name, sensor,
-				   data->num_sensors);
-	data->num_sensors++;
+	pmbus_dev_attr_init(a, sensor->name,
+			    readonly ? S_IRUGO : S_IRUGO | S_IWUSR,
+			    pmbus_show_sensor, pmbus_set_sensor);
+
+	if (pmbus_add_attribute(data, &a->attr))
+		return NULL;
+
+	sensor->next = data->sensors;
+	data->sensors = sensor;
+
+	return sensor;
 }
 
-static void pmbus_add_label(struct pmbus_data *data,
-			    const char *name, int seq,
-			    const char *lstring, int index)
+static int pmbus_add_label(struct pmbus_data *data,
+			   const char *name, int seq,
+			   const char *lstring, int index)
 {
 	struct pmbus_label *label;
+	struct device_attribute *a;
 
-	BUG_ON(data->num_labels >= data->max_labels);
+	label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+	if (!label)
+		return -ENOMEM;
 
-	label = &data->labels[data->num_labels];
+	a = &label->attribute;
+
 	snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
 	if (!index)
 		strncpy(label->label, lstring, sizeof(label->label) - 1);
@@ -904,65 +889,8 @@
 		snprintf(label->label, sizeof(label->label), "%s%d", lstring,
 			 index);
 
-	PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels);
-	data->num_labels++;
-}
-
-/*
- * Determine maximum number of sensors, booleans, and labels.
- * To keep things simple, only make a rough high estimate.
- */
-static void pmbus_find_max_attr(struct i2c_client *client,
-				struct pmbus_data *data)
-{
-	const struct pmbus_driver_info *info = data->info;
-	int page, max_sensors, max_booleans, max_labels;
-
-	max_sensors = PMBUS_MAX_INPUT_SENSORS;
-	max_booleans = PMBUS_MAX_INPUT_BOOLEANS;
-	max_labels = PMBUS_MAX_INPUT_LABELS;
-
-	for (page = 0; page < info->pages; page++) {
-		if (info->func[page] & PMBUS_HAVE_VOUT) {
-			max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE;
-			max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE;
-			max_labels++;
-		}
-		if (info->func[page] & PMBUS_HAVE_IOUT) {
-			max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE;
-			max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE;
-			max_labels++;
-		}
-		if (info->func[page] & PMBUS_HAVE_POUT) {
-			max_sensors += PMBUS_POUT_SENSORS_PER_PAGE;
-			max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE;
-			max_labels++;
-		}
-		if (info->func[page] & PMBUS_HAVE_FAN12) {
-			max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
-			max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
-		}
-		if (info->func[page] & PMBUS_HAVE_FAN34) {
-			max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
-			max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
-		}
-		if (info->func[page] & PMBUS_HAVE_TEMP) {
-			max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-			max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-		}
-		if (info->func[page] & PMBUS_HAVE_TEMP2) {
-			max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-			max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-		}
-		if (info->func[page] & PMBUS_HAVE_TEMP3) {
-			max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-			max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-		}
-	}
-	data->max_sensors = max_sensors;
-	data->max_booleans = max_booleans;
-	data->max_labels = max_labels;
-	data->max_attributes = max_sensors + max_booleans + max_labels;
+	pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL);
+	return pmbus_add_attribute(data, &a->attr);
 }
 
 /*
@@ -975,12 +903,12 @@
  */
 struct pmbus_limit_attr {
 	u16 reg;		/* Limit register */
+	u16 sbit;		/* Alarm attribute status bit */
 	bool update;		/* True if register needs updates */
 	bool low;		/* True if low limit; for limits with compare
 				   functions only */
 	const char *attr;	/* Attribute name */
 	const char *alarm;	/* Alarm attribute name */
-	u32 sbit;		/* Alarm attribute status bit */
 };
 
 /*
@@ -988,7 +916,9 @@
  * description includes a reference to the associated limit attributes.
  */
 struct pmbus_sensor_attr {
-	u8 reg;				/* sensor register */
+	u16 reg;			/* sensor register */
+	u8 gbit;			/* generic status bit */
+	u8 nlimit;			/* # of limit registers */
 	enum pmbus_sensor_classes class;/* sensor class */
 	const char *label;		/* sensor label */
 	bool paged;			/* true if paged sensor */
@@ -997,47 +927,47 @@
 	u32 func;			/* sensor mask */
 	u32 sfunc;			/* sensor status mask */
 	int sbase;			/* status base register */
-	u32 gbit;			/* generic status bit */
 	const struct pmbus_limit_attr *limit;/* limit registers */
-	int nlimit;			/* # of limit registers */
 };
 
 /*
  * Add a set of limit attributes and, if supported, the associated
  * alarm attributes.
+ * returns 0 if no alarm register found, 1 if an alarm register was found,
+ * < 0 on errors.
  */
-static bool pmbus_add_limit_attrs(struct i2c_client *client,
-				  struct pmbus_data *data,
-				  const struct pmbus_driver_info *info,
-				  const char *name, int index, int page,
-				  int cbase,
-				  const struct pmbus_sensor_attr *attr)
+static int pmbus_add_limit_attrs(struct i2c_client *client,
+				 struct pmbus_data *data,
+				 const struct pmbus_driver_info *info,
+				 const char *name, int index, int page,
+				 struct pmbus_sensor *base,
+				 const struct pmbus_sensor_attr *attr)
 {
 	const struct pmbus_limit_attr *l = attr->limit;
 	int nlimit = attr->nlimit;
-	bool have_alarm = false;
-	int i, cindex;
+	int have_alarm = 0;
+	int i, ret;
+	struct pmbus_sensor *curr;
 
 	for (i = 0; i < nlimit; i++) {
 		if (pmbus_check_word_register(client, page, l->reg)) {
-			cindex = data->num_sensors;
-			pmbus_add_sensor(data, name, l->attr, index, page,
-					 l->reg, attr->class,
-					 attr->update || l->update,
-					 false);
+			curr = pmbus_add_sensor(data, name, l->attr, index,
+						page, l->reg, attr->class,
+						attr->update || l->update,
+						false);
+			if (!curr)
+				return -ENOMEM;
 			if (l->sbit && (info->func[page] & attr->sfunc)) {
-				if (attr->compare) {
-					pmbus_add_boolean_cmp(data, name,
-						l->alarm, index,
-						l->low ? cindex : cbase,
-						l->low ? cbase : cindex,
-						attr->sbase + page, l->sbit);
-				} else {
-					pmbus_add_boolean_reg(data, name,
-						l->alarm, index,
-						attr->sbase + page, l->sbit);
-				}
-				have_alarm = true;
+				ret = pmbus_add_boolean(data, name,
+					l->alarm, index,
+					attr->compare ?  l->low ? curr : base
+						      : NULL,
+					attr->compare ? l->low ? base : curr
+						      : NULL,
+					attr->sbase + page, l->sbit);
+				if (ret)
+					return ret;
+				have_alarm = 1;
 			}
 		}
 		l++;
@@ -1045,45 +975,59 @@
 	return have_alarm;
 }
 
-static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
-				       struct pmbus_data *data,
-				       const struct pmbus_driver_info *info,
-				       const char *name,
-				       int index, int page,
-				       const struct pmbus_sensor_attr *attr)
+static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
+				      struct pmbus_data *data,
+				      const struct pmbus_driver_info *info,
+				      const char *name,
+				      int index, int page,
+				      const struct pmbus_sensor_attr *attr)
 {
-	bool have_alarm;
-	int cbase = data->num_sensors;
+	struct pmbus_sensor *base;
+	int ret;
 
-	if (attr->label)
-		pmbus_add_label(data, name, index, attr->label,
-				attr->paged ? page + 1 : 0);
-	pmbus_add_sensor(data, name, "input", index, page, attr->reg,
-			 attr->class, true, true);
+	if (attr->label) {
+		ret = pmbus_add_label(data, name, index, attr->label,
+				      attr->paged ? page + 1 : 0);
+		if (ret)
+			return ret;
+	}
+	base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
+				attr->class, true, true);
+	if (!base)
+		return -ENOMEM;
 	if (attr->sfunc) {
-		have_alarm = pmbus_add_limit_attrs(client, data, info, name,
-						   index, page, cbase, attr);
+		ret = pmbus_add_limit_attrs(client, data, info, name,
+					    index, page, base, attr);
+		if (ret < 0)
+			return ret;
 		/*
 		 * Add generic alarm attribute only if there are no individual
 		 * alarm attributes, if there is a global alarm bit, and if
 		 * the generic status register for this page is accessible.
 		 */
-		if (!have_alarm && attr->gbit &&
-		    pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
-			pmbus_add_boolean_reg(data, name, "alarm", index,
-					      PB_STATUS_BASE + page,
-					      attr->gbit);
+		if (!ret && attr->gbit &&
+		    pmbus_check_byte_register(client, page,
+					      data->status_register)) {
+			ret = pmbus_add_boolean(data, name, "alarm", index,
+						NULL, NULL,
+						PB_STATUS_BASE + page,
+						attr->gbit);
+			if (ret)
+				return ret;
+		}
 	}
+	return 0;
 }
 
-static void pmbus_add_sensor_attrs(struct i2c_client *client,
-				   struct pmbus_data *data,
-				   const char *name,
-				   const struct pmbus_sensor_attr *attrs,
-				   int nattrs)
+static int pmbus_add_sensor_attrs(struct i2c_client *client,
+				  struct pmbus_data *data,
+				  const char *name,
+				  const struct pmbus_sensor_attr *attrs,
+				  int nattrs)
 {
 	const struct pmbus_driver_info *info = data->info;
 	int index, i;
+	int ret;
 
 	index = 1;
 	for (i = 0; i < nattrs; i++) {
@@ -1093,12 +1037,16 @@
 		for (page = 0; page < pages; page++) {
 			if (!(info->func[page] & attrs->func))
 				continue;
-			pmbus_add_sensor_attrs_one(client, data, info, name,
-						   index, page, attrs);
+			ret = pmbus_add_sensor_attrs_one(client, data, info,
+							 name, index, page,
+							 attrs);
+			if (ret)
+				return ret;
 			index++;
 		}
 		attrs++;
 	}
+	return 0;
 }
 
 static const struct pmbus_limit_attr vin_limit_attrs[] = {
@@ -1140,6 +1088,30 @@
 	},
 };
 
+static const struct pmbus_limit_attr vmon_limit_attrs[] = {
+	{
+		.reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT,
+		.attr = "min",
+		.alarm = "min_alarm",
+		.sbit = PB_VOLTAGE_UV_WARNING,
+	}, {
+		.reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
+		.attr = "lcrit",
+		.alarm = "lcrit_alarm",
+		.sbit = PB_VOLTAGE_UV_FAULT,
+	}, {
+		.reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT,
+		.attr = "max",
+		.alarm = "max_alarm",
+		.sbit = PB_VOLTAGE_OV_WARNING,
+	}, {
+		.reg = PMBUS_VIRT_VMON_OV_FAULT_LIMIT,
+		.attr = "crit",
+		.alarm = "crit_alarm",
+		.sbit = PB_VOLTAGE_OV_FAULT,
+	}
+};
+
 static const struct pmbus_limit_attr vout_limit_attrs[] = {
 	{
 		.reg = PMBUS_VOUT_UV_WARN_LIMIT,
@@ -1191,6 +1163,15 @@
 		.limit = vin_limit_attrs,
 		.nlimit = ARRAY_SIZE(vin_limit_attrs),
 	}, {
+		.reg = PMBUS_VIRT_READ_VMON,
+		.class = PSC_VOLTAGE_IN,
+		.label = "vmon",
+		.func = PMBUS_HAVE_VMON,
+		.sfunc = PMBUS_HAVE_STATUS_VMON,
+		.sbase = PB_STATUS_VMON_BASE,
+		.limit = vmon_limit_attrs,
+		.nlimit = ARRAY_SIZE(vmon_limit_attrs),
+	}, {
 		.reg = PMBUS_READ_VCAP,
 		.class = PSC_VOLTAGE_IN,
 		.label = "vcap",
@@ -1553,12 +1534,13 @@
 };
 
 /* Fans */
-static void pmbus_add_fan_attributes(struct i2c_client *client,
-				     struct pmbus_data *data)
+static int pmbus_add_fan_attributes(struct i2c_client *client,
+				    struct pmbus_data *data)
 {
 	const struct pmbus_driver_info *info = data->info;
 	int index = 1;
 	int page;
+	int ret;
 
 	for (page = 0; page < info->pages; page++) {
 		int f;
@@ -1584,9 +1566,10 @@
 			    (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
 				continue;
 
-			pmbus_add_sensor(data, "fan", "input", index, page,
-					 pmbus_fan_registers[f], PSC_FAN, true,
-					 true);
+			if (pmbus_add_sensor(data, "fan", "input", index,
+					     page, pmbus_fan_registers[f],
+					     PSC_FAN, true, true) == NULL)
+				return -ENOMEM;
 
 			/*
 			 * Each fan status register covers multiple fans,
@@ -1601,39 +1584,55 @@
 					base = PB_STATUS_FAN34_BASE + page;
 				else
 					base = PB_STATUS_FAN_BASE + page;
-				pmbus_add_boolean_reg(data, "fan", "alarm",
-					index, base,
+				ret = pmbus_add_boolean(data, "fan",
+					"alarm", index, NULL, NULL, base,
 					PB_FAN_FAN1_WARNING >> (f & 1));
-				pmbus_add_boolean_reg(data, "fan", "fault",
-					index, base,
+				if (ret)
+					return ret;
+				ret = pmbus_add_boolean(data, "fan",
+					"fault", index, NULL, NULL, base,
 					PB_FAN_FAN1_FAULT >> (f & 1));
+				if (ret)
+					return ret;
 			}
 			index++;
 		}
 	}
+	return 0;
 }
 
-static void pmbus_find_attributes(struct i2c_client *client,
-				  struct pmbus_data *data)
+static int pmbus_find_attributes(struct i2c_client *client,
+				 struct pmbus_data *data)
 {
+	int ret;
+
 	/* Voltage sensors */
-	pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
-			       ARRAY_SIZE(voltage_attributes));
+	ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+				     ARRAY_SIZE(voltage_attributes));
+	if (ret)
+		return ret;
 
 	/* Current sensors */
-	pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
-			       ARRAY_SIZE(current_attributes));
+	ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+				     ARRAY_SIZE(current_attributes));
+	if (ret)
+		return ret;
 
 	/* Power sensors */
-	pmbus_add_sensor_attrs(client, data, "power", power_attributes,
-			       ARRAY_SIZE(power_attributes));
+	ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+				     ARRAY_SIZE(power_attributes));
+	if (ret)
+		return ret;
 
 	/* Temperature sensors */
-	pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
-			       ARRAY_SIZE(temp_attributes));
+	ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+				     ARRAY_SIZE(temp_attributes));
+	if (ret)
+		return ret;
 
 	/* Fans */
-	pmbus_add_fan_attributes(client, data);
+	ret = pmbus_add_fan_attributes(client, data);
+	return ret;
 }
 
 /*
@@ -1672,127 +1671,119 @@
 		}
 	}
 
-	/* Determine maximum number of sensors, booleans, and labels */
-	pmbus_find_max_attr(client, data);
 	pmbus_clear_fault_page(client, 0);
 	return 0;
 }
 
-int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
-		   struct pmbus_driver_info *info)
+static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
+			     struct pmbus_driver_info *info)
 {
-	const struct pmbus_platform_data *pdata = client->dev.platform_data;
-	struct pmbus_data *data;
+	struct device *dev = &client->dev;
 	int ret;
 
-	if (!info) {
-		dev_err(&client->dev, "Missing chip information");
-		return -ENODEV;
+	/*
+	 * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try
+	 * to use PMBUS_STATUS_WORD instead if that is the case.
+	 * Bail out if both registers are not supported.
+	 */
+	data->status_register = PMBUS_STATUS_BYTE;
+	ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE);
+	if (ret < 0 || ret == 0xff) {
+		data->status_register = PMBUS_STATUS_WORD;
+		ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD);
+		if (ret < 0 || ret == 0xffff) {
+			dev_err(dev, "PMBus status register not found\n");
+			return -ENODEV;
+		}
 	}
 
-	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
-				     | I2C_FUNC_SMBUS_BYTE_DATA
-				     | I2C_FUNC_SMBUS_WORD_DATA))
-		return -ENODEV;
-
-	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		dev_err(&client->dev, "No memory to allocate driver data\n");
-		return -ENOMEM;
-	}
-
-	i2c_set_clientdata(client, data);
-	mutex_init(&data->update_lock);
-
-	/* Bail out if PMBus status register does not exist. */
-	if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
-		dev_err(&client->dev, "PMBus status register not found\n");
-		return -ENODEV;
-	}
-
-	if (pdata)
-		data->flags = pdata->flags;
-	data->info = info;
-
 	pmbus_clear_faults(client);
 
 	if (info->identify) {
 		ret = (*info->identify)(client, info);
 		if (ret < 0) {
-			dev_err(&client->dev, "Chip identification failed\n");
+			dev_err(dev, "Chip identification failed\n");
 			return ret;
 		}
 	}
 
 	if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
-		dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
-			info->pages);
+		dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages);
 		return -ENODEV;
 	}
 
 	ret = pmbus_identify_common(client, data);
 	if (ret < 0) {
-		dev_err(&client->dev, "Failed to identify chip capabilities\n");
+		dev_err(dev, "Failed to identify chip capabilities\n");
 		return ret;
 	}
+	return 0;
+}
 
-	ret = -ENOMEM;
-	data->sensors = devm_kzalloc(&client->dev, sizeof(struct pmbus_sensor)
-				     * data->max_sensors, GFP_KERNEL);
-	if (!data->sensors) {
-		dev_err(&client->dev, "No memory to allocate sensor data\n");
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+		   struct pmbus_driver_info *info)
+{
+	struct device *dev = &client->dev;
+	const struct pmbus_platform_data *pdata = dev->platform_data;
+	struct pmbus_data *data;
+	int ret;
+
+	if (!info)
+		return -ENODEV;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+				     | I2C_FUNC_SMBUS_BYTE_DATA
+				     | I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
 		return -ENOMEM;
-	}
 
-	data->booleans = devm_kzalloc(&client->dev, sizeof(struct pmbus_boolean)
-				 * data->max_booleans, GFP_KERNEL);
-	if (!data->booleans) {
-		dev_err(&client->dev, "No memory to allocate boolean data\n");
-		return -ENOMEM;
-	}
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+	data->dev = dev;
 
-	data->labels = devm_kzalloc(&client->dev, sizeof(struct pmbus_label)
-				    * data->max_labels, GFP_KERNEL);
-	if (!data->labels) {
-		dev_err(&client->dev, "No memory to allocate label data\n");
-		return -ENOMEM;
-	}
+	if (pdata)
+		data->flags = pdata->flags;
+	data->info = info;
 
-	data->attributes = devm_kzalloc(&client->dev, sizeof(struct attribute *)
-					* data->max_attributes, GFP_KERNEL);
-	if (!data->attributes) {
-		dev_err(&client->dev, "No memory to allocate attribute data\n");
-		return -ENOMEM;
-	}
+	ret = pmbus_init_common(client, data, info);
+	if (ret < 0)
+		return ret;
 
-	pmbus_find_attributes(client, data);
+	ret = pmbus_find_attributes(client, data);
+	if (ret)
+		goto out_kfree;
 
 	/*
 	 * If there are no attributes, something is wrong.
 	 * Bail out instead of trying to register nothing.
 	 */
 	if (!data->num_attributes) {
-		dev_err(&client->dev, "No attributes found\n");
-		return -ENODEV;
+		dev_err(dev, "No attributes found\n");
+		ret = -ENODEV;
+		goto out_kfree;
 	}
 
 	/* Register sysfs hooks */
-	data->group.attrs = data->attributes;
-	ret = sysfs_create_group(&client->dev.kobj, &data->group);
+	ret = sysfs_create_group(&dev->kobj, &data->group);
 	if (ret) {
-		dev_err(&client->dev, "Failed to create sysfs entries\n");
-		return ret;
+		dev_err(dev, "Failed to create sysfs entries\n");
+		goto out_kfree;
 	}
-	data->hwmon_dev = hwmon_device_register(&client->dev);
+	data->hwmon_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->hwmon_dev)) {
 		ret = PTR_ERR(data->hwmon_dev);
-		dev_err(&client->dev, "Failed to register hwmon device\n");
+		dev_err(dev, "Failed to register hwmon device\n");
 		goto out_hwmon_device_register;
 	}
 	return 0;
 
 out_hwmon_device_register:
-	sysfs_remove_group(&client->dev.kobj, &data->group);
+	sysfs_remove_group(&dev->kobj, &data->group);
+out_kfree:
+	kfree(data->group.attrs);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pmbus_do_probe);
@@ -1802,6 +1793,7 @@
 	struct pmbus_data *data = i2c_get_clientdata(client);
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &data->group);
+	kfree(data->group.attrs);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pmbus_do_remove);
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
index fc5eed8..8196441 100644
--- a/drivers/hwmon/pmbus/zl6100.c
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -2,6 +2,7 @@
  * Hardware monitoring driver for ZL6100 and compatibles
  *
  * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
  *
  * 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
@@ -45,12 +46,87 @@
 
 #define ZL6100_MFR_XTEMP_ENABLE		(1 << 7)
 
+#define MFR_VMON_OV_FAULT_LIMIT		0xf5
+#define MFR_VMON_UV_FAULT_LIMIT		0xf6
+#define MFR_READ_VMON			0xf7
+
+#define VMON_UV_WARNING			(1 << 5)
+#define VMON_OV_WARNING			(1 << 4)
+#define VMON_UV_FAULT			(1 << 1)
+#define VMON_OV_FAULT			(1 << 0)
+
 #define ZL6100_WAIT_TIME		1000	/* uS	*/
 
 static ushort delay = ZL6100_WAIT_TIME;
 module_param(delay, ushort, 0644);
 MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
 
+/* Convert linear sensor value to milli-units */
+static long zl6100_l2d(s16 l)
+{
+	s16 exponent;
+	s32 mantissa;
+	long val;
+
+	exponent = l >> 11;
+	mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;
+
+	val = mantissa;
+
+	/* scale result to milli-units */
+	val = val * 1000L;
+
+	if (exponent >= 0)
+		val <<= exponent;
+	else
+		val >>= -exponent;
+
+	return val;
+}
+
+#define MAX_MANTISSA	(1023 * 1000)
+#define MIN_MANTISSA	(511 * 1000)
+
+static u16 zl6100_d2l(long val)
+{
+	s16 exponent = 0, mantissa;
+	bool negative = false;
+
+	/* simple case */
+	if (val == 0)
+		return 0;
+
+	if (val < 0) {
+		negative = true;
+		val = -val;
+	}
+
+	/* Reduce large mantissa until it fits into 10 bit */
+	while (val >= MAX_MANTISSA && exponent < 15) {
+		exponent++;
+		val >>= 1;
+	}
+	/* Increase small mantissa to improve precision */
+	while (val < MIN_MANTISSA && exponent > -15) {
+		exponent--;
+		val <<= 1;
+	}
+
+	/* Convert mantissa from milli-units to units */
+	mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+	/* Ensure that resulting number is within range */
+	if (mantissa > 0x3ff)
+		mantissa = 0x3ff;
+
+	/* restore sign */
+	if (negative)
+		mantissa = -mantissa;
+
+	/* Convert to 5 bit exponent, 11 bit mantissa */
+	return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
 /* Some chips need a delay between accesses */
 static inline void zl6100_wait(const struct zl6100_data *data)
 {
@@ -65,9 +141,9 @@
 {
 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 	struct zl6100_data *data = to_zl6100_data(info);
-	int ret;
+	int ret, vreg;
 
-	if (page || reg >= PMBUS_VIRT_BASE)
+	if (page > 0)
 		return -ENXIO;
 
 	if (data->id == zl2005) {
@@ -83,9 +159,39 @@
 		}
 	}
 
+	switch (reg) {
+	case PMBUS_VIRT_READ_VMON:
+		vreg = MFR_READ_VMON;
+		break;
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+	case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+		vreg = MFR_VMON_OV_FAULT_LIMIT;
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+	case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+		vreg = MFR_VMON_UV_FAULT_LIMIT;
+		break;
+	default:
+		if (reg >= PMBUS_VIRT_BASE)
+			return -ENXIO;
+		vreg = reg;
+		break;
+	}
+
 	zl6100_wait(data);
-	ret = pmbus_read_word_data(client, page, reg);
+	ret = pmbus_read_word_data(client, page, vreg);
 	data->access = ktime_get();
+	if (ret < 0)
+		return ret;
+
+	switch (reg) {
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+		ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+		ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));
+		break;
+	}
 
 	return ret;
 }
@@ -94,13 +200,35 @@
 {
 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 	struct zl6100_data *data = to_zl6100_data(info);
-	int ret;
+	int ret, status;
 
 	if (page > 0)
 		return -ENXIO;
 
 	zl6100_wait(data);
-	ret = pmbus_read_byte_data(client, page, reg);
+
+	switch (reg) {
+	case PMBUS_VIRT_STATUS_VMON:
+		ret = pmbus_read_byte_data(client, 0,
+					   PMBUS_STATUS_MFR_SPECIFIC);
+		if (ret < 0)
+			break;
+
+		status = 0;
+		if (ret & VMON_UV_WARNING)
+			status |= PB_VOLTAGE_UV_WARNING;
+		if (ret & VMON_OV_WARNING)
+			status |= PB_VOLTAGE_OV_WARNING;
+		if (ret & VMON_UV_FAULT)
+			status |= PB_VOLTAGE_UV_FAULT;
+		if (ret & VMON_OV_FAULT)
+			status |= PB_VOLTAGE_OV_FAULT;
+		ret = status;
+		break;
+	default:
+		ret = pmbus_read_byte_data(client, page, reg);
+		break;
+	}
 	data->access = ktime_get();
 
 	return ret;
@@ -111,13 +239,38 @@
 {
 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
 	struct zl6100_data *data = to_zl6100_data(info);
-	int ret;
+	int ret, vreg;
 
-	if (page || reg >= PMBUS_VIRT_BASE)
+	if (page > 0)
 		return -ENXIO;
 
+	switch (reg) {
+	case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+		word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));
+		vreg = MFR_VMON_OV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+		vreg = MFR_VMON_OV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+		word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));
+		vreg = MFR_VMON_UV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+		vreg = MFR_VMON_UV_FAULT_LIMIT;
+		pmbus_clear_cache(client);
+		break;
+	default:
+		if (reg >= PMBUS_VIRT_BASE)
+			return -ENXIO;
+		vreg = reg;
+	}
+
 	zl6100_wait(data);
-	ret = pmbus_write_word_data(client, page, reg, word);
+	ret = pmbus_write_word_data(client, page, vreg, word);
 	data->access = ktime_get();
 
 	return ret;
@@ -225,6 +378,13 @@
 	  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
 	  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
+	/*
+	 * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
+	 * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
+	 */
+	if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
+		info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
+
 	ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 1c85d39..bfe326e 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -139,12 +139,12 @@
  * @reg:		associated regulator (if specified).
  * @nb:			notifier block to handle notifications of voltage
  *                      changes.
- * @supply_uV:		local copy of supply voltage used to allow use of
+ * @supply_uv:		local copy of supply voltage used to allow use of
  *                      regulator consumer if available.
- * @supply_uV_valid:	indicates that an updated value has not yet been
+ * @supply_uv_valid:	indicates that an updated value has not yet been
  *			obtained from the regulator and so any calculations
  *			based upon it will be invalid.
- * @update_supply_work:	work struct that is used to update the supply_uV.
+ * @update_supply_work:	work struct that is used to update the supply_uv.
  * @interrupt_handled:	flag used to indicate a handler has been scheduled.
  */
 struct sht15_data {
@@ -166,8 +166,8 @@
 	struct device			*hwmon_dev;
 	struct regulator		*reg;
 	struct notifier_block		nb;
-	int				supply_uV;
-	bool				supply_uV_valid;
+	int				supply_uv;
+	bool				supply_uv_valid;
 	struct work_struct		update_supply_work;
 	atomic_t			interrupt_handled;
 };
@@ -212,11 +212,13 @@
  *
  * This implements section 3.4 of the data sheet
  */
-static void sht15_connection_reset(struct sht15_data *data)
+static int sht15_connection_reset(struct sht15_data *data)
 {
-	int i;
+	int i, err;
 
-	gpio_direction_output(data->pdata->gpio_data, 1);
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
 	ndelay(SHT15_TSCKL);
 	gpio_set_value(data->pdata->gpio_sck, 0);
 	ndelay(SHT15_TSCKL);
@@ -226,6 +228,7 @@
 		gpio_set_value(data->pdata->gpio_sck, 0);
 		ndelay(SHT15_TSCKL);
 	}
+	return 0;
 }
 
 /**
@@ -251,10 +254,14 @@
  * conservative ones used in implementation. This implements
  * figure 12 on the data sheet.
  */
-static void sht15_transmission_start(struct sht15_data *data)
+static int sht15_transmission_start(struct sht15_data *data)
 {
+	int err;
+
 	/* ensure data is high and output */
-	gpio_direction_output(data->pdata->gpio_data, 1);
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
 	ndelay(SHT15_TSU);
 	gpio_set_value(data->pdata->gpio_sck, 0);
 	ndelay(SHT15_TSCKL);
@@ -270,6 +277,7 @@
 	ndelay(SHT15_TSU);
 	gpio_set_value(data->pdata->gpio_sck, 0);
 	ndelay(SHT15_TSCKL);
+	return 0;
 }
 
 /**
@@ -293,13 +301,19 @@
  */
 static int sht15_wait_for_response(struct sht15_data *data)
 {
-	gpio_direction_input(data->pdata->gpio_data);
+	int err;
+
+	err = gpio_direction_input(data->pdata->gpio_data);
+	if (err)
+		return err;
 	gpio_set_value(data->pdata->gpio_sck, 1);
 	ndelay(SHT15_TSCKH);
 	if (gpio_get_value(data->pdata->gpio_data)) {
 		gpio_set_value(data->pdata->gpio_sck, 0);
 		dev_err(data->dev, "Command not acknowledged\n");
-		sht15_connection_reset(data);
+		err = sht15_connection_reset(data);
+		if (err)
+			return err;
 		return -EIO;
 	}
 	gpio_set_value(data->pdata->gpio_sck, 0);
@@ -317,12 +331,13 @@
  */
 static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
 {
-	int ret = 0;
+	int err;
 
-	sht15_transmission_start(data);
+	err = sht15_transmission_start(data);
+	if (err)
+		return err;
 	sht15_send_byte(data, cmd);
-	ret = sht15_wait_for_response(data);
-	return ret;
+	return sht15_wait_for_response(data);
 }
 
 /**
@@ -352,9 +367,13 @@
  * Each byte of data is acknowledged by pulling the data line
  * low for one clock pulse.
  */
-static void sht15_ack(struct sht15_data *data)
+static int sht15_ack(struct sht15_data *data)
 {
-	gpio_direction_output(data->pdata->gpio_data, 0);
+	int err;
+
+	err = gpio_direction_output(data->pdata->gpio_data, 0);
+	if (err)
+		return err;
 	ndelay(SHT15_TSU);
 	gpio_set_value(data->pdata->gpio_sck, 1);
 	ndelay(SHT15_TSU);
@@ -362,7 +381,7 @@
 	ndelay(SHT15_TSU);
 	gpio_set_value(data->pdata->gpio_data, 1);
 
-	gpio_direction_input(data->pdata->gpio_data);
+	return gpio_direction_input(data->pdata->gpio_data);
 }
 
 /**
@@ -371,14 +390,19 @@
  *
  * This is basically a NAK (single clock pulse, data high).
  */
-static void sht15_end_transmission(struct sht15_data *data)
+static int sht15_end_transmission(struct sht15_data *data)
 {
-	gpio_direction_output(data->pdata->gpio_data, 1);
+	int err;
+
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
 	ndelay(SHT15_TSU);
 	gpio_set_value(data->pdata->gpio_sck, 1);
 	ndelay(SHT15_TSCKH);
 	gpio_set_value(data->pdata->gpio_sck, 0);
 	ndelay(SHT15_TSCKL);
+	return 0;
 }
 
 /**
@@ -410,17 +434,19 @@
  */
 static int sht15_send_status(struct sht15_data *data, u8 status)
 {
-	int ret;
+	int err;
 
-	ret = sht15_send_cmd(data, SHT15_WRITE_STATUS);
-	if (ret)
-		return ret;
-	gpio_direction_output(data->pdata->gpio_data, 1);
+	err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
+	if (err)
+		return err;
+	err = gpio_direction_output(data->pdata->gpio_data, 1);
+	if (err)
+		return err;
 	ndelay(SHT15_TSU);
 	sht15_send_byte(data, status);
-	ret = sht15_wait_for_response(data);
-	if (ret)
-		return ret;
+	err = sht15_wait_for_response(data);
+	if (err)
+		return err;
 
 	data->val_status = status;
 	return 0;
@@ -446,7 +472,7 @@
 			|| !data->status_valid) {
 		ret = sht15_send_cmd(data, SHT15_READ_STATUS);
 		if (ret)
-			goto error_ret;
+			goto unlock;
 		status = sht15_read_byte(data);
 
 		if (data->checksumming) {
@@ -458,7 +484,9 @@
 					== dev_checksum);
 		}
 
-		sht15_end_transmission(data);
+		ret = sht15_end_transmission(data);
+		if (ret)
+			goto unlock;
 
 		/*
 		 * Perform checksum validation on the received data.
@@ -469,27 +497,27 @@
 			previous_config = data->val_status & 0x07;
 			ret = sht15_soft_reset(data);
 			if (ret)
-				goto error_ret;
+				goto unlock;
 			if (previous_config) {
 				ret = sht15_send_status(data, previous_config);
 				if (ret) {
 					dev_err(data->dev,
 						"CRC validation failed, unable "
 						"to restore device settings\n");
-					goto error_ret;
+					goto unlock;
 				}
 			}
 			ret = -EAGAIN;
-			goto error_ret;
+			goto unlock;
 		}
 
 		data->val_status = status;
 		data->status_valid = true;
 		data->last_status = jiffies;
 	}
-error_ret:
-	mutex_unlock(&data->read_lock);
 
+unlock:
+	mutex_unlock(&data->read_lock);
 	return ret;
 }
 
@@ -511,7 +539,9 @@
 	if (ret)
 		return ret;
 
-	gpio_direction_input(data->pdata->gpio_data);
+	ret = gpio_direction_input(data->pdata->gpio_data);
+	if (ret)
+		return ret;
 	atomic_set(&data->interrupt_handled, 0);
 
 	enable_irq(gpio_to_irq(data->pdata->gpio_data));
@@ -524,9 +554,14 @@
 	ret = wait_event_timeout(data->wait_queue,
 				 (data->state == SHT15_READING_NOTHING),
 				 msecs_to_jiffies(timeout_msecs));
-	if (ret == 0) {/* timeout occurred */
+	if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */
+		data->state = SHT15_READING_NOTHING;
+		return -EIO;
+	} else if (ret == 0) { /* timeout occurred */
 		disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
-		sht15_connection_reset(data);
+		ret = sht15_connection_reset(data);
+		if (ret)
+			return ret;
 		return -ETIME;
 	}
 
@@ -570,17 +605,17 @@
 		data->state = SHT15_READING_HUMID;
 		ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
 		if (ret)
-			goto error_ret;
+			goto unlock;
 		data->state = SHT15_READING_TEMP;
 		ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
 		if (ret)
-			goto error_ret;
+			goto unlock;
 		data->measurements_valid = true;
 		data->last_measurement = jiffies;
 	}
-error_ret:
-	mutex_unlock(&data->read_lock);
 
+unlock:
+	mutex_unlock(&data->read_lock);
 	return ret;
 }
 
@@ -598,8 +633,8 @@
 
 	for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
 		/* Find pointer to interpolate */
-		if (data->supply_uV > temppoints[i - 1].vdd) {
-			d1 = (data->supply_uV - temppoints[i - 1].vdd)
+		if (data->supply_uv > temppoints[i - 1].vdd) {
+			d1 = (data->supply_uv - temppoints[i - 1].vdd)
 				* (temppoints[i].d1 - temppoints[i - 1].d1)
 				/ (temppoints[i].vdd - temppoints[i - 1].vdd)
 				+ temppoints[i - 1].d1;
@@ -818,7 +853,8 @@
 	/* Read the data back from the device */
 	val = sht15_read_byte(data);
 	val <<= 8;
-	sht15_ack(data);
+	if (sht15_ack(data))
+		goto wakeup;
 	val |= sht15_read_byte(data);
 
 	if (data->checksumming) {
@@ -826,7 +862,8 @@
 		 * Ask the device for a checksum and read it back.
 		 * Note: the device sends the checksum byte reversed.
 		 */
-		sht15_ack(data);
+		if (sht15_ack(data))
+			goto wakeup;
 		dev_checksum = sht15_reverse(sht15_read_byte(data));
 		checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
 			SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
@@ -837,7 +874,8 @@
 	}
 
 	/* Tell the device we are done */
-	sht15_end_transmission(data);
+	if (sht15_end_transmission(data))
+		goto wakeup;
 
 	switch (data->state) {
 	case SHT15_READING_TEMP:
@@ -851,6 +889,7 @@
 	}
 
 	data->state = SHT15_READING_NOTHING;
+wakeup:
 	wake_up(&data->wait_queue);
 }
 
@@ -859,7 +898,7 @@
 	struct sht15_data *data
 		= container_of(work_s, struct sht15_data,
 			       update_supply_work);
-	data->supply_uV = regulator_get_voltage(data->reg);
+	data->supply_uv = regulator_get_voltage(data->reg);
 }
 
 /**
@@ -878,7 +917,7 @@
 	struct sht15_data *data = container_of(nb, struct sht15_data, nb);
 
 	if (event == REGULATOR_EVENT_VOLTAGE_CHANGE)
-		data->supply_uV_valid = false;
+		data->supply_uv_valid = false;
 	schedule_work(&data->update_supply_work);
 
 	return NOTIFY_OK;
@@ -906,7 +945,7 @@
 		return -EINVAL;
 	}
 	data->pdata = pdev->dev.platform_data;
-	data->supply_uV = data->pdata->supply_mv * 1000;
+	data->supply_uv = data->pdata->supply_mv * 1000;
 	if (data->pdata->checksum)
 		data->checksumming = true;
 	if (data->pdata->no_otp_reload)
@@ -924,7 +963,7 @@
 
 		voltage = regulator_get_voltage(data->reg);
 		if (voltage)
-			data->supply_uV = voltage;
+			data->supply_uv = voltage;
 
 		regulator_enable(data->reg);
 		/*
@@ -942,17 +981,17 @@
 	}
 
 	/* Try requesting the GPIOs */
-	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
+	ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck,
+			GPIOF_OUT_INIT_LOW, "SHT15 sck");
 	if (ret) {
-		dev_err(&pdev->dev, "gpio request failed\n");
+		dev_err(&pdev->dev, "clock line GPIO request failed\n");
 		goto err_release_reg;
 	}
-	gpio_direction_output(data->pdata->gpio_sck, 0);
 
 	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
 				"SHT15 data");
 	if (ret) {
-		dev_err(&pdev->dev, "gpio request failed\n");
+		dev_err(&pdev->dev, "data line GPIO request failed\n");
 		goto err_release_reg;
 	}
 
@@ -966,7 +1005,9 @@
 		goto err_release_reg;
 	}
 	disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
-	sht15_connection_reset(data);
+	ret = sht15_connection_reset(data);
+	if (ret)
+		goto err_release_reg;
 	ret = sht15_soft_reset(data);
 	if (ret)
 		goto err_release_reg;
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 06ce3c9..c35847a 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -132,7 +132,7 @@
  */
 static inline u8 IN_TO_REG(unsigned long val)
 {
-	unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+	unsigned long nval = clamp_val(val, 0, 4080);
 	return (nval + 8) / 16;
 }
 #define IN_FROM_REG(val) ((val) *  16)
@@ -141,7 +141,7 @@
 {
 	if (rpm <= 0)
 		return 255;
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline int FAN_FROM_REG(u8 val, int div)
@@ -159,7 +159,7 @@
 }
 static inline s8 TEMP_TO_REG(int val)
 {
-	int nval = SENSORS_LIMIT(val, -54120, 157530) ;
+	int nval = clamp_val(val, -54120, 157530) ;
 	return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
 }
 
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index dba0c56..6d8255c 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -326,7 +326,7 @@
 	/* Preserve fan min */
 	tmp = 192 - (old_div * (192 - data->fan_preload[nr])
 		     + new_div / 2) / new_div;
-	data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
+	data->fan_preload[nr] = clamp_val(tmp, 0, 191);
 	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
 			     data->fan_preload[nr]);
 	mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index 36a3478..efee4c5 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -77,7 +77,7 @@
 
 static inline u8 IN_TO_REG(unsigned long val, int n)
 {
-	return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+	return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
 }
 
 /*
@@ -86,7 +86,7 @@
  */
 static inline s8 TEMP_TO_REG(int val)
 {
-	return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
+	return clamp_val(SCALE(val, 1, 1000), -128000, 127000);
 }
 
 static inline int TEMP_FROM_REG(s8 val)
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 3c2c48d..4b59eb5 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -134,7 +134,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
+	data->analog_out = clamp_val(tmp, 0, 255);
 	i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
 				  data->analog_out);
 
@@ -187,7 +187,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+	data->temp_min[nr] = clamp_val(val / 1000, -128, 127);
 	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
 				  data->temp_min[nr]);
 	mutex_unlock(&data->update_lock);
@@ -216,7 +216,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+	data->temp_max[nr] = clamp_val(val / 1000, -128, 127);
 	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
 				  data->temp_max[nr]);
 	mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index b10c3d3..523dd89 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -115,7 +115,7 @@
 
 	if (kstrtol(buf, 10, &val) < 0)
 		return -EINVAL;
-	val = SENSORS_LIMIT(val, -256000, 255000);
+	val = clamp_val(val, -256000, 255000);
 
 	mutex_lock(&tmp102->lock);
 	tmp102->temp[sda->index] = val;
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index e620548..c85f696 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -142,10 +142,10 @@
 static u16 tmp401_temp_to_register(long temp, u8 config)
 {
 	if (config & TMP401_CONFIG_RANGE) {
-		temp = SENSORS_LIMIT(temp, -64000, 191000);
+		temp = clamp_val(temp, -64000, 191000);
 		temp += 64000;
 	} else
-		temp = SENSORS_LIMIT(temp, 0, 127000);
+		temp = clamp_val(temp, 0, 127000);
 
 	return (temp * 160 + 312) / 625;
 }
@@ -163,10 +163,10 @@
 static u8 tmp401_crit_temp_to_register(long temp, u8 config)
 {
 	if (config & TMP401_CONFIG_RANGE) {
-		temp = SENSORS_LIMIT(temp, -64000, 191000);
+		temp = clamp_val(temp, -64000, 191000);
 		temp += 64000;
 	} else
-		temp = SENSORS_LIMIT(temp, 0, 127000);
+		temp = clamp_val(temp, 0, 127000);
 
 	return (temp + 500) / 1000;
 }
@@ -417,14 +417,14 @@
 		return -EINVAL;
 
 	if (data->config & TMP401_CONFIG_RANGE)
-		val = SENSORS_LIMIT(val, -64000, 191000);
+		val = clamp_val(val, -64000, 191000);
 	else
-		val = SENSORS_LIMIT(val, 0, 127000);
+		val = clamp_val(val, 0, 127000);
 
 	mutex_lock(&data->update_lock);
 	temp = tmp401_crit_register_to_temp(data->temp_crit[index],
 						data->config);
-	val = SENSORS_LIMIT(val, temp - 255000, temp);
+	val = clamp_val(val, temp - 255000, temp);
 	reg = ((temp - val) + 500) / 1000;
 
 	i2c_smbus_write_byte_data(to_i2c_client(dev),
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index e0e14a9..3123b30 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -135,17 +135,14 @@
 	 * for the constants.
 	 */
 	if (inNum <= 1)
-		return (u8)
-		    SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255);
+		return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
 	else if (inNum == 2)
-		return (u8)
-		    SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255);
+		return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
 	else if (inNum == 3)
-		return (u8)
-		    SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255);
+		return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
 	else
-		return (u8)
-		    SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255);
+		return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
+				      255);
 }
 
 static inline long IN_FROM_REG(u8 val, int inNum)
@@ -175,8 +172,8 @@
 {
 	if (rpm == 0)
 		return 0;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
 }
 
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 7517030..dcc62f8 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -158,7 +158,7 @@
 #define IN_FROM_REG(ix, reg)	((reg) < 3 ? 0 : (ix) == 5 ? \
 				 (((reg) - 3) * 15882 + 479) / 958 : \
 				 (((reg) - 3) * 10000 + 479) / 958)
-#define IN_TO_REG(ix, val)	(SENSORS_LIMIT((ix) == 5 ? \
+#define IN_TO_REG(ix, val)	(clamp_val((ix) == 5 ? \
 				 ((val) * 958 + 7941) / 15882 + 3 : \
 				 ((val) * 958 + 5000) / 10000 + 3, 0, 255))
 
@@ -173,7 +173,7 @@
 				 (ix) == 1 ? (reg) < 51 ? 0 : \
 				 ((reg) - 51) * 1000 : \
 				 ((253 - (reg)) * 2200 + 105) / 210)
-#define TEMP_TO_REG(ix, val)	SENSORS_LIMIT( \
+#define TEMP_TO_REG(ix, val)	clamp_val( \
 				 ((ix) == 0 ? ((val) + 500) / 1000 : \
 				  (ix) == 1 ? ((val) + 500) / 1000 + 51 : \
 				  253 - ((val) * 210 + 1100) / 2200), 0, 255)
@@ -183,7 +183,7 @@
 #define RPM_FROM_REG(reg, div)	(((reg) == 0) || ((reg) == 255) ? 0 : \
 				 1310720 / (reg) / DIV_FROM_REG(div))
 #define RPM_TO_REG(val, div)	((val) == 0 ? 255 : \
-				 SENSORS_LIMIT((1310720 / (val) / \
+				 clamp_val((1310720 / (val) / \
 				 DIV_FROM_REG(div)), 1, 254))
 
 /* ---------------------------------------------------------------------
@@ -687,7 +687,7 @@
 				data->fan_ctl));
 		break;
 	case SHOW_SET_PWM_FREQ:
-		val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000);
+		val = 135000 / clamp_val(val, 135000 >> 7, 135000);
 		/* calculate tmp = log2(val) */
 		tmp = 0;
 		for (val >>= 1; val > 0; val >>= 1)
@@ -845,7 +845,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->pwm_auto_pwm[ix][ap] = SENSORS_LIMIT(val, 0, 255);
+	data->pwm_auto_pwm[ix][ap] = clamp_val(val, 0, 255);
 	vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
 		      data->pwm_auto_pwm[ix][ap]);
 	mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index a56355c..988a2a7 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -147,7 +147,7 @@
 {
 	if (rpm == 0)
 		return 0;
-	return SENSORS_LIMIT(1310720 / (rpm * div), 1, 255);
+	return clamp_val(1310720 / (rpm * div), 1, 255);
 }
 
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
@@ -236,7 +236,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
+	data->in_min[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255);
 	vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -256,7 +256,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
+	data->in_max[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255);
 	vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -302,8 +302,8 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
-					0, 255);
+	data->in_min[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3,
+				    0, 255);
 	vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -321,8 +321,8 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
-					0, 255);
+	data->in_max[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3,
+				    0, 255);
 	vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -380,7 +380,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
+	data->temp_max[0] = clamp_val((val + 500) / 1000, 0, 255);
 	vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -397,7 +397,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
+	data->temp_min[0] = clamp_val((val + 500) / 1000, 0, 255);
 	vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -444,7 +444,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
+	data->temp_max[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255);
 	vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -463,7 +463,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
+	data->temp_min[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255);
 	vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 0e8ffd6..0a89211 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -354,8 +354,8 @@
 
 static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
 {
-	return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
-						(msec + 200) / 400), 1, 255);
+	return clamp_val((mode ? (msec + 50) / 100 : (msec + 200) / 400),
+			 1, 255);
 }
 
 static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
@@ -414,8 +414,7 @@
 
 static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in)
 {
-	return SENSORS_LIMIT(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0,
-			     255);
+	return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
 }
 
 /*
@@ -1267,7 +1266,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
 
 	mutex_lock(&data->update_lock);
 	data->temp_offset[nr] = val;
@@ -1435,7 +1434,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
@@ -1514,7 +1513,7 @@
 	if (err < 0)
 		return err;
 
-	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
@@ -1540,7 +1539,7 @@
 		return err;
 
 	/* Limit the temp to 0C - 15C */
-	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
+	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
 
 	mutex_lock(&data->update_lock);
 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
@@ -1639,7 +1638,7 @@
 	err = kstrtoul(buf, 10, &val); \
 	if (err < 0) \
 		return err; \
-	val = SENSORS_LIMIT(val, 1, 255); \
+	val = clamp_val(val, 1, 255); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
 	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 81f4865..3b9ef2d 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -254,16 +254,15 @@
  * these macros are called: arguments may be evaluated more than once.
  * Fixing this is just not worth it.
  */
-#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
+#define IN_TO_REG(val)  (clamp_val((((val) + 8) / 16), 0, 255))
 #define IN_FROM_REG(val) ((val) * 16)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-			     254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 #define TEMP_MIN (-128000)
@@ -275,9 +274,9 @@
  */
 static u8 TEMP_TO_REG(long temp)
 {
-        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
-        ntemp += (ntemp<0 ? -500 : 500);
-        return (u8)(ntemp / 1000);
+	int ntemp = clamp_val(temp, TEMP_MIN, TEMP_MAX);
+	ntemp += (ntemp < 0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
 }
 
 static int TEMP_FROM_REG(u8 reg)
@@ -287,7 +286,7 @@
 
 #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
 
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+#define PWM_TO_REG(val) (clamp_val((val), 0, 255))
 
 static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
 {
@@ -342,7 +341,7 @@
 static inline u8 DIV_TO_REG(long val)
 {
 	int i;
-	val = SENSORS_LIMIT(val, 1, 128) >> 1;
+	val = clamp_val(val, 1, 128) >> 1;
 	for (i = 0; i < 7; i++) {
 		if (val == 0)
 			break;
@@ -614,8 +613,7 @@
 
 		/* use VRM9 calculation */
 		data->in_min[0] =
-			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
-					255);
+			clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255);
 	else
 		/* use VRM8 (standard) calculation */
 		data->in_min[0] = IN_TO_REG(val);
@@ -644,8 +642,7 @@
 		
 		/* use VRM9 calculation */
 		data->in_max[0] =
-			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
-					255);
+			clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255);
 	else
 		/* use VRM8 (standard) calculation */
 		data->in_max[0] = IN_TO_REG(val);
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 93bd286..aeec5b1 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -159,7 +159,7 @@
 #define W83781D_DEFAULT_BETA		3435
 
 /* Conversions */
-#define IN_TO_REG(val)			SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
+#define IN_TO_REG(val)			clamp_val(((val) + 8) / 16, 0, 255)
 #define IN_FROM_REG(val)		((val) * 16)
 
 static inline u8
@@ -167,8 +167,8 @@
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 static inline long
@@ -181,7 +181,7 @@
 	return 1350000 / (val * div);
 }
 
-#define TEMP_TO_REG(val)		SENSORS_LIMIT((val) / 1000, -127, 128)
+#define TEMP_TO_REG(val)		clamp_val((val) / 1000, -127, 128)
 #define TEMP_FROM_REG(val)		((val) * 1000)
 
 #define BEEP_MASK_FROM_REG(val, type)	((type) == as99127f ? \
@@ -195,9 +195,8 @@
 DIV_TO_REG(long val, enum chips type)
 {
 	int i;
-	val = SENSORS_LIMIT(val, 1,
-			    ((type == w83781d
-			      || type == as99127f) ? 8 : 128)) >> 1;
+	val = clamp_val(val, 1,
+			((type == w83781d || type == as99127f) ? 8 : 128)) >> 1;
 	for (i = 0; i < 7; i++) {
 		if (val == 0)
 			break;
@@ -443,7 +442,7 @@
 	err = kstrtoul(buf, 10, &val);
 	if (err)
 		return err;
-	data->vrm = SENSORS_LIMIT(val, 0, 255);
+	data->vrm = clamp_val(val, 0, 255);
 
 	return count;
 }
@@ -730,7 +729,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+	data->pwm[nr] = clamp_val(val, 0, 255);
 	w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index ed397c6..38ddddd 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -220,15 +220,15 @@
  * in mV as would be measured on the chip input pin, need to just
  * multiply/divide by 16 to translate from/to register values.
  */
-#define IN_TO_REG(val)		(SENSORS_LIMIT((((val) + 8) / 16), 0, 255))
+#define IN_TO_REG(val)		(clamp_val((((val) + 8) / 16), 0, 255))
 #define IN_FROM_REG(val)	((val) * 16)
 
 static u8 fan_to_reg(long rpm, int div)
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 #define FAN_FROM_REG(val, div)	((val) == 0 ? -1 : \
@@ -273,7 +273,7 @@
 	int i;
 
 	/* fan divisors max out at 128 */
-	val = SENSORS_LIMIT(val, 1, 128) >> 1;
+	val = clamp_val(val, 1, 128) >> 1;
 	for (i = 0; i < 7; i++) {
 		if (val == 0)
 			break;
@@ -747,7 +747,7 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+	data->pwm[nr] = clamp_val(val, 0, 255);
 	w83791d_write(client, W83791D_REG_PWM[nr], data->pwm[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 301942d..5cb83dd 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -235,8 +235,8 @@
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 #define FAN_FROM_REG(val, div)	((val) == 0   ? -1 : \
@@ -244,16 +244,15 @@
 						1350000 / ((val) * (div))))
 
 /* for temp1 */
-#define TEMP1_TO_REG(val)	(SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
-					: (val)) / 1000, 0, 0xff))
+#define TEMP1_TO_REG(val)	(clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \
+						      : (val)) / 1000, 0, 0xff))
 #define TEMP1_FROM_REG(val)	(((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
 /* for temp2 and temp3, because they need additional resolution */
 #define TEMP_ADD_FROM_REG(val1, val2) \
 	((((val1) & 0x80 ? (val1)-0x100 \
 		: (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
 #define TEMP_ADD_TO_REG_HIGH(val) \
-	(SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
-			: (val)) / 1000, 0, 0xff))
+	(clamp_val(((val) < 0 ? (val) + 0x100 * 1000 : (val)) / 1000, 0, 0xff))
 #define TEMP_ADD_TO_REG_LOW(val)	((val%1000) ? 0x80 : 0x00)
 
 #define DIV_FROM_REG(val)		(1 << (val))
@@ -262,7 +261,7 @@
 DIV_TO_REG(long val)
 {
 	int i;
-	val = SENSORS_LIMIT(val, 1, 128) >> 1;
+	val = clamp_val(val, 1, 128) >> 1;
 	for (i = 0; i < 7; i++) {
 		if (val == 0)
 			break;
@@ -397,7 +396,7 @@
 	if (err) \
 		return err; \
 	mutex_lock(&data->update_lock); \
-	data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val) / 4, 0, 255); \
+	data->in_##reg[nr] = clamp_val(IN_TO_REG(nr, val) / 4, 0, 255); \
 	w83792d_write_value(client, W83792D_REG_IN_##REG[nr], \
 			    data->in_##reg[nr]); \
 	mutex_unlock(&data->update_lock); \
@@ -645,7 +644,7 @@
 	err = kstrtoul(buf, 10, &val);
 	if (err)
 		return err;
-	val = SENSORS_LIMIT(val, 0, 255) >> 4;
+	val = clamp_val(val, 0, 255) >> 4;
 
 	mutex_lock(&data->update_lock);
 	val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0;
@@ -799,7 +798,7 @@
 	mutex_lock(&data->update_lock);
 	target_mask = w83792d_read_value(client,
 					 W83792D_REG_THERMAL[nr]) & 0x80;
-	data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
+	data->thermal_cruise[nr] = clamp_val(target_tmp, 0, 255);
 	w83792d_write_value(client, W83792D_REG_THERMAL[nr],
 		(data->thermal_cruise[nr]) | target_mask);
 	mutex_unlock(&data->update_lock);
@@ -837,7 +836,7 @@
 	mutex_lock(&data->update_lock);
 	tol_mask = w83792d_read_value(client,
 		W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
-	tol_tmp = SENSORS_LIMIT(val, 0, 15);
+	tol_tmp = clamp_val(val, 0, 15);
 	tol_tmp &= 0x0f;
 	data->tolerance[nr] = tol_tmp;
 	if (nr == 1)
@@ -881,7 +880,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
+	data->sf2_points[index][nr] = clamp_val(val, 0, 127);
 	mask_tmp = w83792d_read_value(client,
 					W83792D_REG_POINTS[index][nr]) & 0x80;
 	w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
@@ -923,7 +922,7 @@
 		return err;
 
 	mutex_lock(&data->update_lock);
-	data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
+	data->sf2_levels[index][nr] = clamp_val((val * 15) / 100, 0, 15);
 	mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
 		& ((nr == 3) ? 0xf0 : 0x0f);
 	if (nr == 3)
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 99799fd..6604275 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -191,7 +191,7 @@
 {
 	if (rpm <= 0)
 		return 0x0fff;
-	return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+	return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
 }
 
 static inline unsigned long TIME_FROM_REG(u8 reg)
@@ -201,7 +201,7 @@
 
 static inline u8 TIME_TO_REG(unsigned long val)
 {
-	return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
+	return clamp_val((val + 50) / 100, 0, 0xff);
 }
 
 static inline long TEMP_FROM_REG(s8 reg)
@@ -211,7 +211,7 @@
 
 static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
 {
-	return SENSORS_LIMIT((val + (val < 0 ? -500 : 500)) / 1000, min, max);
+	return clamp_val((val + (val < 0 ? -500 : 500)) / 1000, min, max);
 }
 
 struct w83793_data {
@@ -558,7 +558,7 @@
 		w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index),
 				   val);
 	} else {
-		val = SENSORS_LIMIT(val, 0, 0xff) >> 2;
+		val = clamp_val(val, 0, 0xff) >> 2;
 		data->pwm[index][nr] =
 		    w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0;
 		data->pwm[index][nr] |= val;
@@ -739,7 +739,7 @@
 	if (nr == SETUP_PWM_DEFAULT) {
 		data->pwm_default =
 		    w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0;
-		data->pwm_default |= SENSORS_LIMIT(val, 0, 0xff) >> 2;
+		data->pwm_default |= clamp_val(val, 0, 0xff) >> 2;
 		w83793_write_value(client, W83793_REG_PWM_DEFAULT,
 							data->pwm_default);
 	} else if (nr == SETUP_PWM_UPTIME) {
@@ -838,7 +838,7 @@
 
 	mutex_lock(&data->update_lock);
 	if (nr == TEMP_FAN_MAP) {
-		val = SENSORS_LIMIT(val, 0, 255);
+		val = clamp_val(val, 0, 255);
 		w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val);
 		data->temp_fan_map[index] = val;
 	} else if (nr == TEMP_PWM_ENABLE) {
@@ -907,7 +907,7 @@
 	err = kstrtoul(buf, 10, &val);
 	if (err)
 		return err;
-	val = SENSORS_LIMIT(val, 0, 0xff) >> 2;
+	val = clamp_val(val, 0, 0xff) >> 2;
 
 	mutex_lock(&data->update_lock);
 	data->sf2_pwm[index][nr] =
@@ -1003,9 +1003,9 @@
 		/* fix the limit values of 5VDD and 5VSB to ALARM mechanism */
 		if (nr == 1 || nr == 2)
 			val -= scale_in_add[index] / scale_in[index];
-		val = SENSORS_LIMIT(val, 0, 255);
+		val = clamp_val(val, 0, 255);
 	} else {
-		val = SENSORS_LIMIT(val, 0, 0x3FF);
+		val = clamp_val(val, 0, 0x3FF);
 		data->in_low_bits[nr] =
 		    w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]);
 		data->in_low_bits[nr] &= ~(0x03 << (2 * index));
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index 55a4f48..e226096 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -262,7 +262,7 @@
 {
 	if (rpm <= 0)
 		return 0x0fff;
-	return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+	return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
 }
 
 static inline unsigned long time_from_reg(u8 reg)
@@ -272,7 +272,7 @@
 
 static inline u8 time_to_reg(unsigned long val)
 {
-	return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
+	return clamp_val((val + 50) / 100, 0, 0xff);
 }
 
 static inline long temp_from_reg(s8 reg)
@@ -282,7 +282,7 @@
 
 static inline s8 temp_to_reg(long val, s8 min, s8 max)
 {
-	return SENSORS_LIMIT(val / 1000, min, max);
+	return clamp_val(val / 1000, min, max);
 }
 
 static const u16 pwm_freq_cksel0[16] = {
@@ -319,7 +319,7 @@
 
 	/* Best fit for cksel = 1 */
 	base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
-	reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
+	reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
 	best1 = base_clock / reg1;
 	reg1 = 0x80 | (reg1 - 1);
 
@@ -889,7 +889,7 @@
 		val = pwm_freq_to_reg(val, data->clkin);
 		break;
 	default:
-		val = SENSORS_LIMIT(val, 0, 0xff);
+		val = clamp_val(val, 0, 0xff);
 		break;
 	}
 	w83795_write(client, W83795_REG_PWM(index, nr), val);
@@ -1126,7 +1126,7 @@
 		break;
 	case TEMP_PWM_FAN_MAP:
 		mutex_lock(&data->update_lock);
-		tmp = SENSORS_LIMIT(tmp, 0, 0xff);
+		tmp = clamp_val(tmp, 0, 0xff);
 		w83795_write(client, W83795_REG_TFMR(index), tmp);
 		data->pwm_tfmr[index] = tmp;
 		mutex_unlock(&data->update_lock);
@@ -1177,13 +1177,13 @@
 	mutex_lock(&data->update_lock);
 	switch (nr) {
 	case FANIN_TARGET:
-		val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff));
+		val = fan_to_reg(clamp_val(val, 0, 0xfff));
 		w83795_write(client, W83795_REG_FTSH(index), val >> 4);
 		w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0);
 		data->target_speed[index] = val;
 		break;
 	case FANIN_TOL:
-		val = SENSORS_LIMIT(val, 0, 0x3f);
+		val = clamp_val(val, 0, 0x3f);
 		w83795_write(client, W83795_REG_TFTS, val);
 		data->tol_speed = val;
 		break;
@@ -1227,22 +1227,22 @@
 	mutex_lock(&data->update_lock);
 	switch (nr) {
 	case TEMP_PWM_TTTI:
-		val = SENSORS_LIMIT(val, 0, 0x7f);
+		val = clamp_val(val, 0, 0x7f);
 		w83795_write(client, W83795_REG_TTTI(index), val);
 		break;
 	case TEMP_PWM_CTFS:
-		val = SENSORS_LIMIT(val, 0, 0x7f);
+		val = clamp_val(val, 0, 0x7f);
 		w83795_write(client, W83795_REG_CTFS(index), val);
 		break;
 	case TEMP_PWM_HCT:
-		val = SENSORS_LIMIT(val, 0, 0x0f);
+		val = clamp_val(val, 0, 0x0f);
 		tmp = w83795_read(client, W83795_REG_HT(index));
 		tmp &= 0x0f;
 		tmp |= (val << 4) & 0xf0;
 		w83795_write(client, W83795_REG_HT(index), tmp);
 		break;
 	case TEMP_PWM_HOT:
-		val = SENSORS_LIMIT(val, 0, 0x0f);
+		val = clamp_val(val, 0, 0x0f);
 		tmp = w83795_read(client, W83795_REG_HT(index));
 		tmp &= 0xf0;
 		tmp |= val & 0x0f;
@@ -1541,7 +1541,7 @@
 	if ((index >= 17) &&
 	    !((data->has_gain >> (index - 17)) & 1))
 		val /= 8;
-	val = SENSORS_LIMIT(val, 0, 0x3FF);
+	val = clamp_val(val, 0, 0x3FF);
 	mutex_lock(&data->update_lock);
 
 	lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
@@ -1596,7 +1596,7 @@
 
 	switch (nr) {
 	case SETUP_PWM_DEFAULT:
-		val = SENSORS_LIMIT(val, 0, 0xff);
+		val = clamp_val(val, 0, 0xff);
 		break;
 	case SETUP_PWM_UPTIME:
 	case SETUP_PWM_DOWNTIME:
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index 79710bc..edb06cd 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -86,8 +86,8 @@
 {
 	if (rpm == 0)
 		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+	rpm = clamp_val(rpm, 1, 1000000);
+	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
 #define FAN_FROM_REG(val, div)	((val) == 0   ? -1 : \
@@ -95,9 +95,8 @@
 				1350000 / ((val) * (div))))
 
 /* for temp */
-#define TEMP_TO_REG(val)	(SENSORS_LIMIT(((val) < 0 ? \
-						(val) + 0x100 * 1000 \
-						: (val)) / 1000, 0, 0xff))
+#define TEMP_TO_REG(val)	(clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \
+						      : (val)) / 1000, 0, 0xff))
 #define TEMP_FROM_REG(val)	(((val) & 0x80 ? \
 				  (val) - 0x100 : (val)) * 1000)
 
@@ -106,7 +105,7 @@
  * in mV as would be measured on the chip input pin, need to just
  * multiply/divide by 8 to translate from/to register values.
  */
-#define IN_TO_REG(val)		(SENSORS_LIMIT((((val) + 4) / 8), 0, 255))
+#define IN_TO_REG(val)		(clamp_val((((val) + 4) / 8), 0, 255))
 #define IN_FROM_REG(val)	((val) * 8)
 
 #define DIV_FROM_REG(val)	(1 << (val))
@@ -115,7 +114,7 @@
 DIV_TO_REG(long val)
 {
 	int i;
-	val = SENSORS_LIMIT(val, 1, 128) >> 1;
+	val = clamp_val(val, 1, 128) >> 1;
 	for (i = 0; i < 7; i++) {
 		if (val == 0)
 			break;
@@ -481,7 +480,7 @@
 	err = kstrtoul(buf, 10, &val);
 	if (err)
 		return err;
-	val = SENSORS_LIMIT(val, 0, 255);
+	val = clamp_val(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
@@ -564,7 +563,7 @@
 	mutex_lock(&data->update_lock);
 	tol_mask = w83l786ng_read_value(client,
 	    W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0);
-	tol_tmp = SENSORS_LIMIT(val, 0, 15);
+	tol_tmp = clamp_val(val, 0, 15);
 	tol_tmp &= 0x0f;
 	data->tolerance[nr] = tol_tmp;
 	if (nr == 1)
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index 6aafa3d..c447e8d 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -406,7 +406,7 @@
 	return -EIO;
 }
 
-static int acpi_smbus_cmi_remove(struct acpi_device *device, int type)
+static int acpi_smbus_cmi_remove(struct acpi_device *device)
 {
 	struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
 
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 2df9414..5d66750 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -74,7 +74,7 @@
 	.en_core_tk_irqen = 1,
 };
 /* intel_idle.max_cstate=0 disables driver */
-static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
+static int max_cstate = CPUIDLE_STATE_MAX - 1;
 
 static unsigned int mwait_substates;
 
@@ -90,6 +90,7 @@
 	 * Indicate which enable bits to clear here.
 	 */
 	unsigned long auto_demotion_disable_flags;
+	bool disable_promotion_to_c1e;
 };
 
 static const struct idle_cpu *icpu;
@@ -109,162 +110,206 @@
 #define CPUIDLE_FLAG_TLB_FLUSHED	0x10000
 
 /*
+ * MWAIT takes an 8-bit "hint" in EAX "suggesting"
+ * the C-state (top nibble) and sub-state (bottom nibble)
+ * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
+ *
+ * We store the hint at the top of our "flags" for each state.
+ */
+#define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
+#define MWAIT2flg(eax) ((eax & 0xFF) << 24)
+
+/*
  * States are indexed by the cstate number,
  * which is also the index into the MWAIT hint array.
  * Thus C0 is a dummy.
  */
-static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
-	{ /* MWAIT C0 */ },
-	{ /* MWAIT C1 */
+static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = {
+	{
 		.name = "C1-NHM",
 		.desc = "MWAIT 0x00",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 3,
 		.target_residency = 6,
 		.enter = &intel_idle },
-	{ /* MWAIT C2 */
+	{
+		.name = "C1E-NHM",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle },
+	{
 		.name = "C3-NHM",
 		.desc = "MWAIT 0x10",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 20,
 		.target_residency = 80,
 		.enter = &intel_idle },
-	{ /* MWAIT C3 */
+	{
 		.name = "C6-NHM",
 		.desc = "MWAIT 0x20",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 200,
 		.target_residency = 800,
 		.enter = &intel_idle },
+	{
+		.enter = NULL }
 };
 
-static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
-	{ /* MWAIT C0 */ },
-	{ /* MWAIT C1 */
+static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = {
+	{
 		.name = "C1-SNB",
 		.desc = "MWAIT 0x00",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 1,
-		.target_residency = 1,
+		.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 2,
+		.target_residency = 2,
 		.enter = &intel_idle },
-	{ /* MWAIT C2 */
+	{
+		.name = "C1E-SNB",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle },
+	{
 		.name = "C3-SNB",
 		.desc = "MWAIT 0x10",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 80,
 		.target_residency = 211,
 		.enter = &intel_idle },
-	{ /* MWAIT C3 */
+	{
 		.name = "C6-SNB",
 		.desc = "MWAIT 0x20",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 104,
 		.target_residency = 345,
 		.enter = &intel_idle },
-	{ /* MWAIT C4 */
+	{
 		.name = "C7-SNB",
 		.desc = "MWAIT 0x30",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 109,
 		.target_residency = 345,
 		.enter = &intel_idle },
+	{
+		.enter = NULL }
 };
 
-static struct cpuidle_state ivb_cstates[MWAIT_MAX_NUM_CSTATES] = {
-	{ /* MWAIT C0 */ },
-	{ /* MWAIT C1 */
+static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = {
+	{
 		.name = "C1-IVB",
 		.desc = "MWAIT 0x00",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
 		.target_residency = 1,
 		.enter = &intel_idle },
-	{ /* MWAIT C2 */
+	{
+		.name = "C1E-IVB",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle },
+	{
 		.name = "C3-IVB",
 		.desc = "MWAIT 0x10",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 59,
 		.target_residency = 156,
 		.enter = &intel_idle },
-	{ /* MWAIT C3 */
+	{
 		.name = "C6-IVB",
 		.desc = "MWAIT 0x20",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 80,
 		.target_residency = 300,
 		.enter = &intel_idle },
-	{ /* MWAIT C4 */
+	{
 		.name = "C7-IVB",
 		.desc = "MWAIT 0x30",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 87,
 		.target_residency = 300,
 		.enter = &intel_idle },
+	{
+		.enter = NULL }
 };
 
-static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
-	{ /* MWAIT C0 */ },
-	{ /* MWAIT C1 */
-		.name = "C1-ATM",
+static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = {
+	{
+		.name = "C1-HSW",
 		.desc = "MWAIT 0x00",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
-		.exit_latency = 1,
-		.target_residency = 4,
+		.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 2,
+		.target_residency = 2,
 		.enter = &intel_idle },
-	{ /* MWAIT C2 */
+	{
+		.name = "C1E-HSW",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle },
+	{
+		.name = "C3-HSW",
+		.desc = "MWAIT 0x10",
+		.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 33,
+		.target_residency = 100,
+		.enter = &intel_idle },
+	{
+		.name = "C6-HSW",
+		.desc = "MWAIT 0x20",
+		.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 133,
+		.target_residency = 400,
+		.enter = &intel_idle },
+	{
+		.name = "C7s-HSW",
+		.desc = "MWAIT 0x32",
+		.flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 166,
+		.target_residency = 500,
+		.enter = &intel_idle },
+	{
+		.enter = NULL }
+};
+
+static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = {
+	{
+		.name = "C1E-ATM",
+		.desc = "MWAIT 0x00",
+		.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 10,
+		.target_residency = 20,
+		.enter = &intel_idle },
+	{
 		.name = "C2-ATM",
 		.desc = "MWAIT 0x10",
-		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 20,
 		.target_residency = 80,
 		.enter = &intel_idle },
-	{ /* MWAIT C3 */ },
-	{ /* MWAIT C4 */
+	{
 		.name = "C4-ATM",
 		.desc = "MWAIT 0x30",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 100,
 		.target_residency = 400,
 		.enter = &intel_idle },
-	{ /* MWAIT C5 */ },
-	{ /* MWAIT C6 */
+	{
 		.name = "C6-ATM",
 		.desc = "MWAIT 0x52",
-		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 140,
 		.target_residency = 560,
 		.enter = &intel_idle },
+	{
+		.enter = NULL }
 };
 
-static long get_driver_data(int cstate)
-{
-	int driver_data;
-	switch (cstate) {
-
-	case 1:	/* MWAIT C1 */
-		driver_data = 0x00;
-		break;
-	case 2:	/* MWAIT C2 */
-		driver_data = 0x10;
-		break;
-	case 3:	/* MWAIT C3 */
-		driver_data = 0x20;
-		break;
-	case 4:	/* MWAIT C4 */
-		driver_data = 0x30;
-		break;
-	case 5:	/* MWAIT C5 */
-		driver_data = 0x40;
-		break;
-	case 6:	/* MWAIT C6 */
-		driver_data = 0x52;
-		break;
-	default:
-		driver_data = 0x00;
-	}
-	return driver_data;
-}
-
 /**
  * intel_idle
  * @dev: cpuidle_device
@@ -278,8 +323,7 @@
 {
 	unsigned long ecx = 1; /* break on interrupt flag */
 	struct cpuidle_state *state = &drv->states[index];
-	struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
-	unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
+	unsigned long eax = flg2MWAIT(state->flags);
 	unsigned int cstate;
 	int cpu = smp_processor_id();
 
@@ -362,10 +406,19 @@
 	msr_bits &= ~(icpu->auto_demotion_disable_flags);
 	wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
 }
+static void c1e_promotion_disable(void *dummy)
+{
+	unsigned long long msr_bits;
+
+	rdmsrl(MSR_IA32_POWER_CTL, msr_bits);
+	msr_bits &= ~0x2;
+	wrmsrl(MSR_IA32_POWER_CTL, msr_bits);
+}
 
 static const struct idle_cpu idle_cpu_nehalem = {
 	.state_table = nehalem_cstates,
 	.auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
+	.disable_promotion_to_c1e = true,
 };
 
 static const struct idle_cpu idle_cpu_atom = {
@@ -379,10 +432,17 @@
 
 static const struct idle_cpu idle_cpu_snb = {
 	.state_table = snb_cstates,
+	.disable_promotion_to_c1e = true,
 };
 
 static const struct idle_cpu idle_cpu_ivb = {
 	.state_table = ivb_cstates,
+	.disable_promotion_to_c1e = true,
+};
+
+static const struct idle_cpu idle_cpu_hsw = {
+	.state_table = hsw_cstates,
+	.disable_promotion_to_c1e = true,
 };
 
 #define ICPU(model, cpu) \
@@ -402,6 +462,9 @@
 	ICPU(0x2d, idle_cpu_snb),
 	ICPU(0x3a, idle_cpu_ivb),
 	ICPU(0x3e, idle_cpu_ivb),
+	ICPU(0x3c, idle_cpu_hsw),
+	ICPU(0x3f, idle_cpu_hsw),
+	ICPU(0x45, idle_cpu_hsw),
 	{}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
@@ -484,32 +547,31 @@
 
 	drv->state_count = 1;
 
-	for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
-		int num_substates;
+	for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
+		int num_substates, mwait_hint, mwait_cstate, mwait_substate;
 
-		if (cstate > max_cstate) {
+		if (cpuidle_state_table[cstate].enter == NULL)
+			break;
+
+		if (cstate + 1 > max_cstate) {
 			printk(PREFIX "max_cstate %d reached\n",
 				max_cstate);
 			break;
 		}
 
-		/* does the state exist in CPUID.MWAIT? */
-		num_substates = (mwait_substates >> ((cstate) * 4))
-					& MWAIT_SUBSTATE_MASK;
-		if (num_substates == 0)
-			continue;
-		/* is the state not enabled? */
-		if (cpuidle_state_table[cstate].enter == NULL) {
-			/* does the driver not know about the state? */
-			if (*cpuidle_state_table[cstate].name == '\0')
-				pr_debug(PREFIX "unaware of model 0x%x"
-					" MWAIT %d please"
-					" contact lenb@kernel.org\n",
-				boot_cpu_data.x86_model, cstate);
-			continue;
-		}
+		mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags);
+		mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint);
+		mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint);
 
-		if ((cstate > 2) &&
+		/* does the state exist in CPUID.MWAIT? */
+		num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
+					& MWAIT_SUBSTATE_MASK;
+
+		/* if sub-state in table is not enumerated by CPUID */
+		if ((mwait_substate + 1) > num_substates)
+			continue;
+
+		if (((mwait_cstate + 1) > 2) &&
 			!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
 			mark_tsc_unstable("TSC halts in idle"
 					" states deeper than C2");
@@ -523,6 +585,9 @@
 	if (icpu->auto_demotion_disable_flags)
 		on_each_cpu(auto_demotion_disable, NULL, 1);
 
+	if (icpu->disable_promotion_to_c1e)	/* each-cpu is redundant */
+		on_each_cpu(c1e_promotion_disable, NULL, 1);
+
 	return 0;
 }
 
@@ -541,25 +606,28 @@
 
 	dev->state_count = 1;
 
-	for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
-		int num_substates;
+	for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
+		int num_substates, mwait_hint, mwait_cstate, mwait_substate;
 
-		if (cstate > max_cstate) {
+		if (cpuidle_state_table[cstate].enter == NULL)
+			continue;
+
+		if (cstate + 1 > max_cstate) {
 			printk(PREFIX "max_cstate %d reached\n", max_cstate);
 			break;
 		}
 
-		/* does the state exist in CPUID.MWAIT? */
-		num_substates = (mwait_substates >> ((cstate) * 4))
-			& MWAIT_SUBSTATE_MASK;
-		if (num_substates == 0)
-			continue;
-		/* is the state not enabled? */
-		if (cpuidle_state_table[cstate].enter == NULL)
-			continue;
+		mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags);
+		mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint);
+		mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint);
 
-		dev->states_usage[dev->state_count].driver_data =
-			(void *)get_driver_data(cstate);
+		/* does the state exist in CPUID.MWAIT? */
+		num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
+					& MWAIT_SUBSTATE_MASK;
+
+		/* if sub-state in table is not enumerated by CPUID */
+		if ((mwait_substate + 1) > num_substates)
+			continue;
 
 		dev->state_count += 1;
 	}
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 5b152a3..4291410 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -135,6 +135,7 @@
 	struct net_device *event_netdev = ifa->ifa_dev->dev;
 	struct nes_device *nesdev;
 	struct net_device *netdev;
+	struct net_device *upper_dev;
 	struct nes_vnic *nesvnic;
 	unsigned int is_bonded;
 
@@ -145,8 +146,9 @@
 				nesdev, nesdev->netdev[0]->name);
 		netdev = nesdev->netdev[0];
 		nesvnic = netdev_priv(netdev);
+		upper_dev = netdev_master_upper_dev_get(netdev);
 		is_bonded = netif_is_bond_slave(netdev) &&
-			    (netdev->master == event_netdev);
+			    (upper_dev == event_netdev);
 		if ((netdev == event_netdev) || is_bonded) {
 			if (nesvnic->rdma_enabled == 0) {
 				nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
@@ -179,9 +181,9 @@
 					/* fall through */
 				case NETDEV_CHANGEADDR:
 					/* Add the address to the IP table */
-					if (netdev->master)
+					if (upper_dev)
 						nesvnic->local_ipaddr =
-							((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address;
+							((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address;
 					else
 						nesvnic->local_ipaddr = ifa->ifa_address;
 
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 22ea67e..24b9f1a 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1340,7 +1340,7 @@
 	}
 
 	if (netif_is_bond_slave(nesvnic->netdev))
-		netdev = nesvnic->netdev->master;
+		netdev = netdev_master_upper_dev_get(nesvnic->netdev);
 	else
 		netdev = nesvnic->netdev;
 
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 9542e16..85cf4d1 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1317,11 +1317,13 @@
 	struct nes_vnic *nesvnic = netdev_priv(netdev);
 	struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
 
-	strcpy(drvinfo->driver, DRV_NAME);
-	strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
-	sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
-				nesadapter->firmware_version & 0x000000ff);
-	strcpy(drvinfo->version, DRV_VERSION);
+	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev),
+		sizeof(drvinfo->bus_info));
+	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+		 "%u.%u", nesadapter->firmware_version >> 16,
+		 nesadapter->firmware_version & 0x000000ff);
+	strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
 	drvinfo->testinfo_len = 0;
 	drvinfo->eedump_len = 0;
 	drvinfo->regdump_len = 0;
@@ -1703,7 +1705,6 @@
 	netdev->dev_addr[3] = (u8)(u64temp>>16);
 	netdev->dev_addr[4] = (u8)(u64temp>>8);
 	netdev->dev_addr[5] = (u8)u64temp;
-	memcpy(netdev->perm_addr, netdev->dev_addr, 6);
 
 	netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX;
 	if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 29bc7b5..ca13133 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -39,7 +39,7 @@
 static void ipoib_get_drvinfo(struct net_device *netdev,
 			      struct ethtool_drvinfo *drvinfo)
 {
-	strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1);
+	strlcpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver));
 }
 
 static int ipoib_get_coalesce(struct net_device *dev,
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 55f7e57..38b523a 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -3,7 +3,7 @@
 #
 
 menu "Input device support"
-	depends on !S390 && !UML
+	depends on !UML
 
 config INPUT
 	tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 47a6009..71db193 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -18,6 +18,7 @@
 {
 	if (dev->absinfo && test_bit(src, dev->absbit)) {
 		dev->absinfo[dst] = dev->absinfo[src];
+		dev->absinfo[dst].fuzz = 0;
 		dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
 	}
 }
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ce01332f..c044699 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1785,12 +1785,13 @@
  * its driver (or binding fails). Once managed input device is allocated,
  * it is ready to be set up and registered in the same fashion as regular
  * input device. There are no special devm_input_device_[un]register()
- * variants, regular ones work with both managed and unmanaged devices.
+ * variants, regular ones work with both managed and unmanaged devices,
+ * should you need them. In most cases however, managed input device need
+ * not be explicitly unregistered or freed.
  *
  * NOTE: the owner device is set up as parent of input device and users
  * should not override it.
  */
-
 struct input_dev *devm_input_allocate_device(struct device *dev)
 {
 	struct input_dev *input;
@@ -2004,6 +2005,17 @@
  * Once device has been successfully registered it can be unregistered
  * with input_unregister_device(); input_free_device() should not be
  * called in this case.
+ *
+ * Note that this function is also used to register managed input devices
+ * (ones allocated with devm_input_allocate_device()). Such managed input
+ * devices need not be explicitly unregistered or freed, their tear down
+ * is controlled by the devres infrastructure. It is also worth noting
+ * that tear down of managed input devices is internally a 2-step process:
+ * registered managed input device is first unregistered, but stays in
+ * memory and can still handle input_event() calls (although events will
+ * not be delivered anywhere). The freeing of managed input device will
+ * happen later, when devres stack is unwound to the point where device
+ * allocation was made.
  */
 int input_register_device(struct input_dev *dev)
 {
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 358cd7e..7cd74e2 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -162,7 +162,7 @@
 #define GET_TIME(x)	do { x = get_cycles(); } while (0)
 #define DELTA(x,y)	((y)-(x))
 #define TIME_NAME	"PCC"
-#elif defined(CONFIG_MN10300)
+#elif defined(CONFIG_MN10300) || defined(CONFIG_TILE)
 #define GET_TIME(x)	do { x = get_cycles(); } while (0)
 #define DELTA(x, y)	((x) - (y))
 #define TIME_NAME	"TSC"
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index f8f892b..b76ac58 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -12,7 +12,7 @@
  * the Free Software Foundation.
 */
 
-/* #define WK0701_DEBUG */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #define RESERVE 20000
 #define SYNC_PULSE 1306000
@@ -67,6 +67,7 @@
 {
 	int i;
 	int val1, val2, val3, val4, val5, val6, val7, val8;
+	int magic, magic_bit;
 	int crc1, crc2;
 
 	for (crc1 = crc2 = i = 0; i < 10; i++) {
@@ -102,17 +103,12 @@
 	val8 = (w->buf[18] & 1) << 8 | (w->buf[19] << 4) | w->buf[20];
 	val8 *= (w->buf[18] & 2) - 1;	/*sign */
 
-#ifdef WK0701_DEBUG
-	{
-		int magic, magic_bit;
-		magic = (w->buf[21] << 4) | w->buf[22];
-		magic_bit = (w->buf[24] & 8) >> 3;
-		printk(KERN_DEBUG
-		       "walkera0701: %4d %4d %4d %4d  %4d %4d %4d %4d (magic %2x %d)\n",
-		       val1, val2, val3, val4, val5, val6, val7, val8, magic,
-		       magic_bit);
-	}
-#endif
+	magic = (w->buf[21] << 4) | w->buf[22];
+	magic_bit = (w->buf[24] & 8) >> 3;
+	pr_debug("%4d %4d %4d %4d  %4d %4d %4d %4d (magic %2x %d)\n",
+		 val1, val2, val3, val4, val5, val6, val7, val8,
+		 magic, magic_bit);
+
 	input_report_abs(w->input_dev, ABS_X, val2);
 	input_report_abs(w->input_dev, ABS_Y, val1);
 	input_report_abs(w->input_dev, ABS_Z, val6);
@@ -187,6 +183,9 @@
 {
 	struct walkera_dev *w = input_get_drvdata(dev);
 
+	if (parport_claim(w->pardevice))
+		return -EBUSY;
+
 	parport_enable_irq(w->parport);
 	return 0;
 }
@@ -197,40 +196,51 @@
 
 	parport_disable_irq(w->parport);
 	hrtimer_cancel(&w->timer);
+
+	parport_release(w->pardevice);
 }
 
 static int walkera0701_connect(struct walkera_dev *w, int parport)
 {
-	int err = -ENODEV;
+	int error;
 
 	w->parport = parport_find_number(parport);
-	if (w->parport == NULL)
+	if (!w->parport) {
+		pr_err("parport %d does not exist\n", parport);
 		return -ENODEV;
-
-	if (w->parport->irq == -1) {
-		printk(KERN_ERR "walkera0701: parport without interrupt\n");
-		goto init_err;
 	}
 
-	err = -EBUSY;
+	if (w->parport->irq == -1) {
+		pr_err("parport %d does not have interrupt assigned\n",
+			parport);
+		error = -EINVAL;
+		goto err_put_parport;
+	}
+
 	w->pardevice = parport_register_device(w->parport, "walkera0701",
 				    NULL, NULL, walkera0701_irq_handler,
 				    PARPORT_DEV_EXCL, w);
-	if (!w->pardevice)
-		goto init_err;
+	if (!w->pardevice) {
+		pr_err("failed to register parport device\n");
+		error = -EIO;
+		goto err_put_parport;
+	}
 
-	if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT))
-		goto init_err1;
-
-	if (parport_claim(w->pardevice))
-		goto init_err1;
+	if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) {
+		pr_err("failed to negotiate parport mode\n");
+		error = -EIO;
+		goto err_unregister_device;
+	}
 
 	hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	w->timer.function = timer_handler;
 
 	w->input_dev = input_allocate_device();
-	if (!w->input_dev)
-		goto init_err2;
+	if (!w->input_dev) {
+		pr_err("failed to allocate input device\n");
+		error = -ENOMEM;
+		goto err_unregister_device;
+	}
 
 	input_set_drvdata(w->input_dev, w);
 	w->input_dev->name = "Walkera WK-0701 TX";
@@ -241,6 +251,7 @@
 	w->input_dev->id.vendor = 0x0001;
 	w->input_dev->id.product = 0x0001;
 	w->input_dev->id.version = 0x0100;
+	w->input_dev->dev.parent = w->parport->dev;
 	w->input_dev->open = walkera0701_open;
 	w->input_dev->close = walkera0701_close;
 
@@ -254,27 +265,26 @@
 	input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
 	input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
 
-	err = input_register_device(w->input_dev);
-	if (err)
-		goto init_err3;
+	error = input_register_device(w->input_dev);
+	if (error) {
+		pr_err("failed to register input device\n");
+		goto err_free_input_dev;
+	}
 
 	return 0;
 
- init_err3:
+err_free_input_dev:
 	input_free_device(w->input_dev);
- init_err2:
-	parport_release(w->pardevice);
- init_err1:
+err_unregister_device:
 	parport_unregister_device(w->pardevice);
- init_err:
+err_put_parport:
 	parport_put_port(w->parport);
-	return err;
+	return error;
 }
 
 static void walkera0701_disconnect(struct walkera_dev *w)
 {
 	input_unregister_device(w->input_dev);
-	parport_release(w->pardevice);
 	parport_unregister_device(w->pardevice);
 	parport_put_port(w->parport);
 }
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 5a240c6..ac05006 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -224,7 +224,7 @@
 
 config KEYBOARD_TCA8418
 	tristate "TCA8418 Keypad Support"
-	depends on I2C
+	depends on I2C && GENERIC_HARDIRQS
 	select INPUT_MATRIXKMAP
 	help
 	  This driver implements basic keypad functionality
@@ -303,7 +303,7 @@
 
 config KEYBOARD_LM8323
 	tristate "LM8323 keypad chip"
-	depends on I2C
+	depends on I2C && GENERIC_HARDIRQS
 	depends on LEDS_CLASS
 	help
 	  If you say yes here you get support for the National Semiconductor
@@ -420,7 +420,7 @@
 
 config KEYBOARD_TEGRA
 	tristate "NVIDIA Tegra internal matrix keyboard controller support"
-	depends on ARCH_TEGRA
+	depends on ARCH_TEGRA && OF
 	select INPUT_MATRIXKMAP
 	help
 	  Say Y here if you want to use a matrix keyboard connected directly
@@ -479,6 +479,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called samsung-keypad.
 
+config KEYBOARD_GOLDFISH_EVENTS
+	depends on GOLDFISH
+	tristate "Generic Input Event device for Goldfish"
+	help
+	  Say Y here to get an input event device for the Goldfish virtual
+	  device emulator.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called goldfish-events.
+
 config KEYBOARD_STOWAWAY
 	tristate "Stowaway keyboard"
 	select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 44e7600..49b1645 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 obj-$(CONFIG_KEYBOARD_DAVINCI)		+= davinci_keyscan.o
 obj-$(CONFIG_KEYBOARD_EP93XX)		+= ep93xx_keypad.o
+obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS)	+= goldfish_events.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
 obj-$(CONFIG_KEYBOARD_GPIO_POLLED)	+= gpio_keys_polled.o
 obj-$(CONFIG_KEYBOARD_TCA6416)		+= tca6416-keypad.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index add5ffd..2626773 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -676,6 +676,39 @@
 	serio_continue_rx(atkbd->ps2dev.serio);
 }
 
+static int atkbd_activate(struct atkbd *atkbd)
+{
+	struct ps2dev *ps2dev = &atkbd->ps2dev;
+
+/*
+ * Enable the keyboard to receive keystrokes.
+ */
+
+	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
+		dev_err(&ps2dev->serio->dev,
+			"Failed to enable keyboard on %s\n",
+			ps2dev->serio->phys);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * atkbd_deactivate() resets and disables the keyboard from sending
+ * keystrokes.
+ */
+
+static void atkbd_deactivate(struct atkbd *atkbd)
+{
+	struct ps2dev *ps2dev = &atkbd->ps2dev;
+
+	if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
+		dev_err(&ps2dev->serio->dev,
+			"Failed to deactivate keyboard on %s\n",
+			ps2dev->serio->phys);
+}
+
 /*
  * atkbd_probe() probes for an AT keyboard on a serio port.
  */
@@ -726,11 +759,17 @@
 
 	if (atkbd->id == 0xaca1 && atkbd->translated) {
 		dev_err(&ps2dev->serio->dev,
-			"NCD terminal keyboards are only supported on non-translating controlelrs. "
+			"NCD terminal keyboards are only supported on non-translating controllers. "
 			"Use i8042.direct=1 to disable translation.\n");
 		return -1;
 	}
 
+/*
+ * Make sure nothing is coming from the keyboard and disturbs our
+ * internal state.
+ */
+	atkbd_deactivate(atkbd);
+
 	return 0;
 }
 
@@ -825,24 +864,6 @@
 	return 0;
 }
 
-static int atkbd_activate(struct atkbd *atkbd)
-{
-	struct ps2dev *ps2dev = &atkbd->ps2dev;
-
-/*
- * Enable the keyboard to receive keystrokes.
- */
-
-	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
-		dev_err(&ps2dev->serio->dev,
-			"Failed to enable keyboard on %s\n",
-			ps2dev->serio->phys);
-		return -1;
-	}
-
-	return 0;
-}
-
 /*
  * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
  * reboot.
@@ -1150,7 +1171,6 @@
 
 		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
 		atkbd_reset_state(atkbd);
-		atkbd_activate(atkbd);
 
 	} else {
 		atkbd->set = 2;
@@ -1165,6 +1185,8 @@
 		goto fail3;
 
 	atkbd_enable(atkbd);
+	if (serio->write)
+		atkbd_activate(atkbd);
 
 	err = input_register_device(atkbd->dev);
 	if (err)
@@ -1208,8 +1230,6 @@
 		if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
 			goto out;
 
-		atkbd_activate(atkbd);
-
 		/*
 		 * Restore LED state and repeat rate. While input core
 		 * will do this for us at resume time reconnect may happen
@@ -1223,7 +1243,17 @@
 
 	}
 
+	/*
+	 * Reset our state machine in case reconnect happened in the middle
+	 * of multi-byte scancode.
+	 */
+	atkbd->xl_bit = 0;
+	atkbd->emul = 0;
+
 	atkbd_enable(atkbd);
+	if (atkbd->write)
+		atkbd_activate(atkbd);
+
 	retval = 0;
 
  out:
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
new file mode 100644
index 0000000..9f60a2e
--- /dev/null
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+enum {
+	REG_READ        = 0x00,
+	REG_SET_PAGE    = 0x00,
+	REG_LEN         = 0x04,
+	REG_DATA        = 0x08,
+
+	PAGE_NAME       = 0x00000,
+	PAGE_EVBITS     = 0x10000,
+	PAGE_ABSDATA    = 0x20000 | EV_ABS,
+};
+
+struct event_dev {
+	struct input_dev *input;
+	int irq;
+	void __iomem *addr;
+	char name[0];
+};
+
+static irqreturn_t events_interrupt(int irq, void *dev_id)
+{
+	struct event_dev *edev = dev_id;
+	unsigned type, code, value;
+
+	type = __raw_readl(edev->addr + REG_READ);
+	code = __raw_readl(edev->addr + REG_READ);
+	value = __raw_readl(edev->addr + REG_READ);
+
+	input_event(edev->input, type, code, value);
+	input_sync(edev->input);
+	return IRQ_HANDLED;
+}
+
+static void events_import_bits(struct event_dev *edev,
+			unsigned long bits[], unsigned type, size_t count)
+{
+	void __iomem *addr = edev->addr;
+	int i, j;
+	size_t size;
+	uint8_t val;
+
+	__raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE);
+
+	size = __raw_readl(addr + REG_LEN) * 8;
+	if (size < count)
+		count = size;
+
+	addr += REG_DATA;
+	for (i = 0; i < count; i += 8) {
+		val = __raw_readb(addr++);
+		for (j = 0; j < 8; j++)
+			if (val & 1 << j)
+				set_bit(i + j, bits);
+	}
+}
+
+static void events_import_abs_params(struct event_dev *edev)
+{
+	struct input_dev *input_dev = edev->input;
+	void __iomem *addr = edev->addr;
+	u32 val[4];
+	int count;
+	int i, j;
+
+	__raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
+
+	count = __raw_readl(addr + REG_LEN) / sizeof(val);
+	if (count > ABS_MAX)
+		count = ABS_MAX;
+
+	for (i = 0; i < count; i++) {
+		if (!test_bit(i, input_dev->absbit))
+			continue;
+
+		for (j = 0; j < ARRAY_SIZE(val); j++) {
+			int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32);
+			val[j] = __raw_readl(edev->addr + REG_DATA + offset);
+		}
+
+		input_set_abs_params(input_dev, i,
+				     val[0], val[1], val[2], val[3]);
+	}
+}
+
+static int events_probe(struct platform_device *pdev)
+{
+	struct input_dev *input_dev;
+	struct event_dev *edev;
+	struct resource *res;
+	unsigned keymapnamelen;
+	void __iomem *addr;
+	int irq;
+	int i;
+	int error;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	addr = devm_ioremap(&pdev->dev, res->start, 4096);
+	if (!addr)
+		return -ENOMEM;
+
+	__raw_writel(PAGE_NAME, addr + REG_SET_PAGE);
+	keymapnamelen = __raw_readl(addr + REG_LEN);
+
+	edev = devm_kzalloc(&pdev->dev,
+			    sizeof(struct event_dev) + keymapnamelen + 1,
+			    GFP_KERNEL);
+	if (!edev)
+		return -ENOMEM;
+
+	input_dev = devm_input_allocate_device(&pdev->dev);
+	if (!input_dev)
+		return -ENOMEM;
+
+	edev->input = input_dev;
+	edev->addr = addr;
+	edev->irq = irq;
+
+	for (i = 0; i < keymapnamelen; i++)
+		edev->name[i] = __raw_readb(edev->addr + REG_DATA + i);
+
+	pr_debug("events_probe() keymap=%s\n", edev->name);
+
+	input_dev->name = edev->name;
+	input_dev->id.bustype = BUS_HOST;
+
+	events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
+	events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
+	events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
+	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
+	events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
+	events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
+	events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
+	events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX);
+	events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX);
+
+	events_import_abs_params(edev);
+
+	error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0,
+				 "goldfish-events-keypad", edev);
+	if (error)
+		return error;
+
+	error = input_register_device(input_dev);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static struct platform_driver events_driver = {
+	.probe	= events_probe,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "goldfish_events",
+	},
+};
+
+module_platform_driver(events_driver);
+
+MODULE_AUTHOR("Brian Swetland");
+MODULE_DESCRIPTION("Goldfish Event Device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 6d150e3..98f9113 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -20,6 +20,7 @@
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
@@ -414,15 +415,23 @@
 	return -EIO;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id imx_keypad_of_match[] = {
+	{ .compatible = "fsl,imx21-kpp", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_keypad_of_match);
+#endif
+
 static int imx_keypad_probe(struct platform_device *pdev)
 {
 	const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
 	struct imx_keypad *keypad;
 	struct input_dev *input_dev;
 	struct resource *res;
-	int irq, error, i;
+	int irq, error, i, row, col;
 
-	if (keymap_data == NULL) {
+	if (!keymap_data && !pdev->dev.of_node) {
 		dev_err(&pdev->dev, "no keymap defined\n");
 		return -EINVAL;
 	}
@@ -480,22 +489,6 @@
 		goto failed_unmap;
 	}
 
-	/* Search for rows and cols enabled */
-	for (i = 0; i < keymap_data->keymap_size; i++) {
-		keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
-		keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
-	}
-
-	if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
-	    keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
-		dev_err(&pdev->dev,
-			"invalid key data (too many rows or colums)\n");
-		error = -EINVAL;
-		goto failed_clock_put;
-	}
-	dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
-	dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
-
 	/* Init the Input device */
 	input_dev->name = pdev->name;
 	input_dev->id.bustype = BUS_HOST;
@@ -512,6 +505,19 @@
 		goto failed_clock_put;
 	}
 
+	/* Search for rows and cols enabled */
+	for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
+		for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+			i = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+			if (keypad->keycodes[i] != KEY_RESERVED) {
+				keypad->rows_en_mask |= 1 << row;
+				keypad->cols_en_mask |= 1 << col;
+			}
+		}
+	}
+	dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
+	dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
+
 	__set_bit(EV_REP, input_dev->evbit);
 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 	input_set_drvdata(input_dev, keypad);
@@ -631,6 +637,7 @@
 		.name	= "imx-keypad",
 		.owner	= THIS_MODULE,
 		.pm	= &imx_kbd_pm_ops,
+		.of_match_table = of_match_ptr(imx_keypad_of_match),
 	},
 	.probe		= imx_keypad_probe,
 	.remove		= imx_keypad_remove,
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 93c8126..0de23f4 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -398,7 +398,7 @@
 			lm8323_configure(lm);
 		}
 		for (i = 0; i < LM8323_NUM_PWMS; i++) {
-			if (ints & (1 << (INT_PWM1 + i))) {
+			if (ints & (INT_PWM1 << i)) {
 				dev_vdbg(&lm->client->dev,
 					 "pwm%d engine completed\n", i);
 				pwm_done(&lm->pwm[i]);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index f4ff0dd..71d7719 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -403,7 +403,7 @@
 	struct matrix_keypad_platform_data *pdata;
 	struct device_node *np = dev->of_node;
 	unsigned int *gpios;
-	int i;
+	int i, nrow, ncol;
 
 	if (!np) {
 		dev_err(dev, "device lacks DT data\n");
@@ -416,9 +416,9 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios");
-	pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios");
-	if (!pdata->num_row_gpios || !pdata->num_col_gpios) {
+	pdata->num_row_gpios = nrow = of_gpio_named_count(np, "row-gpios");
+	pdata->num_col_gpios = ncol = of_gpio_named_count(np, "col-gpios");
+	if (nrow <= 0 || ncol <= 0) {
 		dev_err(dev, "number of keypad rows/columns not specified\n");
 		return ERR_PTR(-EINVAL);
 	}
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 3dc2b0f..1c0ddad 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -39,6 +40,11 @@
 #define QT2160_CMD_GPIOS      6
 #define QT2160_CMD_SUBVER     7
 #define QT2160_CMD_CALIBRATE  10
+#define QT2160_CMD_DRIVE_X    70
+#define QT2160_CMD_PWMEN_X    74
+#define QT2160_CMD_PWM_DUTY   76
+
+#define QT2160_NUM_LEDS_X	8
 
 #define QT2160_CYCLE_INTERVAL	(2*HZ)
 
@@ -49,6 +55,17 @@
 	KEY_C, KEY_D, KEY_E, KEY_F,
 };
 
+#ifdef CONFIG_LEDS_CLASS
+struct qt2160_led {
+	struct qt2160_data *qt2160;
+	struct led_classdev cdev;
+	struct work_struct work;
+	char name[32];
+	int id;
+	enum led_brightness new_brightness;
+};
+#endif
+
 struct qt2160_data {
 	struct i2c_client *client;
 	struct input_dev *input;
@@ -56,8 +73,61 @@
 	spinlock_t lock;        /* Protects canceling/rescheduling of dwork */
 	unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
 	u16 key_matrix;
+#ifdef CONFIG_LEDS_CLASS
+	struct qt2160_led leds[QT2160_NUM_LEDS_X];
+	struct mutex led_lock;
+#endif
 };
 
+static int qt2160_read(struct i2c_client *client, u8 reg);
+static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
+
+#ifdef CONFIG_LEDS_CLASS
+
+static void qt2160_led_work(struct work_struct *work)
+{
+	struct qt2160_led *led = container_of(work, struct qt2160_led, work);
+	struct qt2160_data *qt2160 = led->qt2160;
+	struct i2c_client *client = qt2160->client;
+	int value = led->new_brightness;
+	u32 drive, pwmen;
+
+	mutex_lock(&qt2160->led_lock);
+
+	drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
+	pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
+	if (value != LED_OFF) {
+		drive |= (1 << led->id);
+		pwmen |= (1 << led->id);
+
+	} else {
+		drive &= ~(1 << led->id);
+		pwmen &= ~(1 << led->id);
+	}
+	qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
+	qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
+
+	/*
+	 * Changing this register will change the brightness
+	 * of every LED in the qt2160. It's a HW limitation.
+	 */
+	if (value != LED_OFF)
+		qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
+
+	mutex_unlock(&qt2160->led_lock);
+}
+
+static void qt2160_led_set(struct led_classdev *cdev,
+			   enum led_brightness value)
+{
+	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
+
+	led->new_brightness = value;
+	schedule_work(&led->work);
+}
+
+#endif /* CONFIG_LEDS_CLASS */
+
 static int qt2160_read_block(struct i2c_client *client,
 			     u8 inireg, u8 *buffer, unsigned int count)
 {
@@ -216,6 +286,63 @@
 	return ret;
 }
 
+#ifdef CONFIG_LEDS_CLASS
+
+static int qt2160_register_leds(struct qt2160_data *qt2160)
+{
+	struct i2c_client *client = qt2160->client;
+	int ret;
+	int i;
+
+	mutex_init(&qt2160->led_lock);
+
+	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+		struct qt2160_led *led = &qt2160->leds[i];
+
+		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
+		led->cdev.name = led->name;
+		led->cdev.brightness_set = qt2160_led_set;
+		led->cdev.brightness = LED_OFF;
+		led->id = i;
+		led->qt2160 = qt2160;
+
+		INIT_WORK(&led->work, qt2160_led_work);
+
+		ret = led_classdev_register(&client->dev, &led->cdev);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Tur off LEDs */
+	qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
+	qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
+	qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
+
+	return 0;
+}
+
+static void qt2160_unregister_leds(struct qt2160_data *qt2160)
+{
+	int i;
+
+	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+		led_classdev_unregister(&qt2160->leds[i].cdev);
+		cancel_work_sync(&qt2160->leds[i].work);
+	}
+}
+
+#else
+
+static inline int qt2160_register_leds(struct qt2160_data *qt2160)
+{
+	return 0;
+}
+
+static inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
+{
+}
+
+#endif
 
 static bool qt2160_identify(struct i2c_client *client)
 {
@@ -249,7 +376,7 @@
 }
 
 static int qt2160_probe(struct i2c_client *client,
-				  const struct i2c_device_id *id)
+			const struct i2c_device_id *id)
 {
 	struct qt2160_data *qt2160;
 	struct input_dev *input;
@@ -314,11 +441,17 @@
 		}
 	}
 
+	error = qt2160_register_leds(qt2160);
+	if (error) {
+		dev_err(&client->dev, "Failed to register leds\n");
+		goto err_free_irq;
+	}
+
 	error = input_register_device(qt2160->input);
 	if (error) {
 		dev_err(&client->dev,
 			"Failed to register input device\n");
-		goto err_free_irq;
+		goto err_unregister_leds;
 	}
 
 	i2c_set_clientdata(client, qt2160);
@@ -326,6 +459,8 @@
 
 	return 0;
 
+err_unregister_leds:
+	qt2160_unregister_leds(qt2160);
 err_free_irq:
 	if (client->irq)
 		free_irq(client->irq, qt2160);
@@ -339,6 +474,8 @@
 {
 	struct qt2160_data *qt2160 = i2c_get_clientdata(client);
 
+	qt2160_unregister_leds(qt2160);
+
 	/* Release IRQ so no queue will be scheduled */
 	if (client->irq)
 		free_irq(client->irq, qt2160);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index c76f968..d89e7d39 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -29,9 +29,16 @@
 #include <linux/of.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
-#include <linux/input/tegra_kbc.h>
+#include <linux/input/matrix_keypad.h>
 #include <mach/clk.h>
 
+#define KBC_MAX_GPIO	24
+#define KBC_MAX_KPENT	8
+
+#define KBC_MAX_ROW	16
+#define KBC_MAX_COL	8
+#define KBC_MAX_KEY	(KBC_MAX_ROW * KBC_MAX_COL)
+
 #define KBC_MAX_DEBOUNCE_CNT	0x3ffu
 
 /* KBC row scan time and delay for beginning the row scan. */
@@ -67,10 +74,27 @@
 
 #define KBC_ROW_SHIFT	3
 
+enum tegra_pin_type {
+	PIN_CFG_IGNORE,
+	PIN_CFG_COL,
+	PIN_CFG_ROW,
+};
+
+struct tegra_kbc_pin_cfg {
+	enum tegra_pin_type type;
+	unsigned char num;
+};
+
 struct tegra_kbc {
+	struct device *dev;
+	unsigned int debounce_cnt;
+	unsigned int repeat_cnt;
+	struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
+	const struct matrix_keymap_data *keymap_data;
+	bool wakeup;
 	void __iomem *mmio;
 	struct input_dev *idev;
-	unsigned int irq;
+	int irq;
 	spinlock_t lock;
 	unsigned int repoll_dly;
 	unsigned long cp_dly_jiffies;
@@ -78,7 +102,6 @@
 	bool use_fn_map;
 	bool use_ghost_filter;
 	bool keypress_caused_wake;
-	const struct tegra_kbc_platform_data *pdata;
 	unsigned short keycode[KBC_MAX_KEY * 2];
 	unsigned short current_keys[KBC_MAX_KPENT];
 	unsigned int num_pressed_keys;
@@ -87,147 +110,6 @@
 	struct clk *clk;
 };
 
-static const u32 tegra_kbc_default_keymap[] = {
-	KEY(0, 2, KEY_W),
-	KEY(0, 3, KEY_S),
-	KEY(0, 4, KEY_A),
-	KEY(0, 5, KEY_Z),
-	KEY(0, 7, KEY_FN),
-
-	KEY(1, 7, KEY_LEFTMETA),
-
-	KEY(2, 6, KEY_RIGHTALT),
-	KEY(2, 7, KEY_LEFTALT),
-
-	KEY(3, 0, KEY_5),
-	KEY(3, 1, KEY_4),
-	KEY(3, 2, KEY_R),
-	KEY(3, 3, KEY_E),
-	KEY(3, 4, KEY_F),
-	KEY(3, 5, KEY_D),
-	KEY(3, 6, KEY_X),
-
-	KEY(4, 0, KEY_7),
-	KEY(4, 1, KEY_6),
-	KEY(4, 2, KEY_T),
-	KEY(4, 3, KEY_H),
-	KEY(4, 4, KEY_G),
-	KEY(4, 5, KEY_V),
-	KEY(4, 6, KEY_C),
-	KEY(4, 7, KEY_SPACE),
-
-	KEY(5, 0, KEY_9),
-	KEY(5, 1, KEY_8),
-	KEY(5, 2, KEY_U),
-	KEY(5, 3, KEY_Y),
-	KEY(5, 4, KEY_J),
-	KEY(5, 5, KEY_N),
-	KEY(5, 6, KEY_B),
-	KEY(5, 7, KEY_BACKSLASH),
-
-	KEY(6, 0, KEY_MINUS),
-	KEY(6, 1, KEY_0),
-	KEY(6, 2, KEY_O),
-	KEY(6, 3, KEY_I),
-	KEY(6, 4, KEY_L),
-	KEY(6, 5, KEY_K),
-	KEY(6, 6, KEY_COMMA),
-	KEY(6, 7, KEY_M),
-
-	KEY(7, 1, KEY_EQUAL),
-	KEY(7, 2, KEY_RIGHTBRACE),
-	KEY(7, 3, KEY_ENTER),
-	KEY(7, 7, KEY_MENU),
-
-	KEY(8, 4, KEY_RIGHTSHIFT),
-	KEY(8, 5, KEY_LEFTSHIFT),
-
-	KEY(9, 5, KEY_RIGHTCTRL),
-	KEY(9, 7, KEY_LEFTCTRL),
-
-	KEY(11, 0, KEY_LEFTBRACE),
-	KEY(11, 1, KEY_P),
-	KEY(11, 2, KEY_APOSTROPHE),
-	KEY(11, 3, KEY_SEMICOLON),
-	KEY(11, 4, KEY_SLASH),
-	KEY(11, 5, KEY_DOT),
-
-	KEY(12, 0, KEY_F10),
-	KEY(12, 1, KEY_F9),
-	KEY(12, 2, KEY_BACKSPACE),
-	KEY(12, 3, KEY_3),
-	KEY(12, 4, KEY_2),
-	KEY(12, 5, KEY_UP),
-	KEY(12, 6, KEY_PRINT),
-	KEY(12, 7, KEY_PAUSE),
-
-	KEY(13, 0, KEY_INSERT),
-	KEY(13, 1, KEY_DELETE),
-	KEY(13, 3, KEY_PAGEUP),
-	KEY(13, 4, KEY_PAGEDOWN),
-	KEY(13, 5, KEY_RIGHT),
-	KEY(13, 6, KEY_DOWN),
-	KEY(13, 7, KEY_LEFT),
-
-	KEY(14, 0, KEY_F11),
-	KEY(14, 1, KEY_F12),
-	KEY(14, 2, KEY_F8),
-	KEY(14, 3, KEY_Q),
-	KEY(14, 4, KEY_F4),
-	KEY(14, 5, KEY_F3),
-	KEY(14, 6, KEY_1),
-	KEY(14, 7, KEY_F7),
-
-	KEY(15, 0, KEY_ESC),
-	KEY(15, 1, KEY_GRAVE),
-	KEY(15, 2, KEY_F5),
-	KEY(15, 3, KEY_TAB),
-	KEY(15, 4, KEY_F1),
-	KEY(15, 5, KEY_F2),
-	KEY(15, 6, KEY_CAPSLOCK),
-	KEY(15, 7, KEY_F6),
-
-	/* Software Handled Function Keys */
-	KEY(20, 0, KEY_KP7),
-
-	KEY(21, 0, KEY_KP9),
-	KEY(21, 1, KEY_KP8),
-	KEY(21, 2, KEY_KP4),
-	KEY(21, 4, KEY_KP1),
-
-	KEY(22, 1, KEY_KPSLASH),
-	KEY(22, 2, KEY_KP6),
-	KEY(22, 3, KEY_KP5),
-	KEY(22, 4, KEY_KP3),
-	KEY(22, 5, KEY_KP2),
-	KEY(22, 7, KEY_KP0),
-
-	KEY(27, 1, KEY_KPASTERISK),
-	KEY(27, 3, KEY_KPMINUS),
-	KEY(27, 4, KEY_KPPLUS),
-	KEY(27, 5, KEY_KPDOT),
-
-	KEY(28, 5, KEY_VOLUMEUP),
-
-	KEY(29, 3, KEY_HOME),
-	KEY(29, 4, KEY_END),
-	KEY(29, 5, KEY_BRIGHTNESSDOWN),
-	KEY(29, 6, KEY_VOLUMEDOWN),
-	KEY(29, 7, KEY_BRIGHTNESSUP),
-
-	KEY(30, 0, KEY_NUMLOCK),
-	KEY(30, 1, KEY_SCROLLLOCK),
-	KEY(30, 2, KEY_MUTE),
-
-	KEY(31, 4, KEY_HELP),
-};
-
-static const
-struct matrix_keymap_data tegra_kbc_default_keymap_data = {
-	.keymap		= tegra_kbc_default_keymap,
-	.keymap_size	= ARRAY_SIZE(tegra_kbc_default_keymap),
-};
-
 static void tegra_kbc_report_released_keys(struct input_dev *input,
 					   unsigned short old_keycodes[],
 					   unsigned int old_num_keys,
@@ -357,18 +239,6 @@
 	writel(val, kbc->mmio + KBC_CONTROL_0);
 }
 
-static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
-{
-	u32 val;
-
-	val = readl(kbc->mmio + KBC_CONTROL_0);
-	if (enable)
-		val |= KBC_CONTROL_KEYPRESS_INT_EN;
-	else
-		val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
-	writel(val, kbc->mmio + KBC_CONTROL_0);
-}
-
 static void tegra_kbc_keypress_timer(unsigned long data)
 {
 	struct tegra_kbc *kbc = (struct tegra_kbc *)data;
@@ -439,12 +309,11 @@
 
 static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
 {
-	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 	int i;
 	unsigned int rst_val;
 
 	/* Either mask all keys or none. */
-	rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
+	rst_val = (filter && !kbc->wakeup) ? ~0 : 0;
 
 	for (i = 0; i < KBC_MAX_ROW; i++)
 		writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
@@ -452,7 +321,6 @@
 
 static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
 {
-	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 	int i;
 
 	for (i = 0; i < KBC_MAX_GPIO; i++) {
@@ -468,13 +336,13 @@
 		row_cfg &= ~r_mask;
 		col_cfg &= ~c_mask;
 
-		switch (pdata->pin_cfg[i].type) {
+		switch (kbc->pin_cfg[i].type) {
 		case PIN_CFG_ROW:
-			row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
+			row_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << r_shft;
 			break;
 
 		case PIN_CFG_COL:
-			col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+			col_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << c_shft;
 			break;
 
 		case PIN_CFG_IGNORE:
@@ -488,7 +356,6 @@
 
 static int tegra_kbc_start(struct tegra_kbc *kbc)
 {
-	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 	unsigned int debounce_cnt;
 	u32 val = 0;
 
@@ -503,10 +370,10 @@
 	tegra_kbc_config_pins(kbc);
 	tegra_kbc_setup_wakekeys(kbc, false);
 
-	writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
+	writel(kbc->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
 
 	/* Keyboard debounce count is maximum of 12 bits. */
-	debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+	debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
 	val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt);
 	val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */
 	val |= KBC_CONTROL_FIFO_CNT_INT_EN;  /* interrupt on FIFO threshold */
@@ -573,21 +440,20 @@
 	return tegra_kbc_stop(kbc);
 }
 
-static bool
-tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
-			struct device *dev, unsigned int *num_rows)
+static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,
+					unsigned int *num_rows)
 {
 	int i;
 
 	*num_rows = 0;
 
 	for (i = 0; i < KBC_MAX_GPIO; i++) {
-		const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
+		const struct tegra_kbc_pin_cfg *pin_cfg = &kbc->pin_cfg[i];
 
 		switch (pin_cfg->type) {
 		case PIN_CFG_ROW:
 			if (pin_cfg->num >= KBC_MAX_ROW) {
-				dev_err(dev,
+				dev_err(kbc->dev,
 					"pin_cfg[%d]: invalid row number %d\n",
 					i, pin_cfg->num);
 				return false;
@@ -597,7 +463,7 @@
 
 		case PIN_CFG_COL:
 			if (pin_cfg->num >= KBC_MAX_COL) {
-				dev_err(dev,
+				dev_err(kbc->dev,
 					"pin_cfg[%d]: invalid column number %d\n",
 					i, pin_cfg->num);
 				return false;
@@ -608,7 +474,7 @@
 			break;
 
 		default:
-			dev_err(dev,
+			dev_err(kbc->dev,
 				"pin_cfg[%d]: invalid entry type %d\n",
 				pin_cfg->type, pin_cfg->num);
 			return false;
@@ -618,154 +484,140 @@
 	return true;
 }
 
-#ifdef CONFIG_OF
-static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
-	struct platform_device *pdev)
+static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
 {
-	struct tegra_kbc_platform_data *pdata;
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = kbc->dev->of_node;
 	u32 prop;
 	int i;
-
-	if (!np)
-		return NULL;
-
-	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return NULL;
+	u32 num_rows = 0;
+	u32 num_cols = 0;
+	u32 cols_cfg[KBC_MAX_GPIO];
+	u32 rows_cfg[KBC_MAX_GPIO];
+	int proplen;
+	int ret;
 
 	if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
-		pdata->debounce_cnt = prop;
+		kbc->debounce_cnt = prop;
 
 	if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop))
-		pdata->repeat_cnt = prop;
+		kbc->repeat_cnt = prop;
 
 	if (of_find_property(np, "nvidia,needs-ghost-filter", NULL))
-		pdata->use_ghost_filter = true;
+		kbc->use_ghost_filter = true;
 
 	if (of_find_property(np, "nvidia,wakeup-source", NULL))
-		pdata->wakeup = true;
+		kbc->wakeup = true;
 
-	/*
-	 * All currently known keymaps with device tree support use the same
-	 * pin_cfg, so set it up here.
-	 */
-	for (i = 0; i < KBC_MAX_ROW; i++) {
-		pdata->pin_cfg[i].num = i;
-		pdata->pin_cfg[i].type = PIN_CFG_ROW;
+	if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) {
+		dev_err(kbc->dev, "property nvidia,kbc-row-pins not found\n");
+		return -ENOENT;
+	}
+	num_rows = proplen / sizeof(u32);
+
+	if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) {
+		dev_err(kbc->dev, "property nvidia,kbc-col-pins not found\n");
+		return -ENOENT;
+	}
+	num_cols = proplen / sizeof(u32);
+
+	if (!of_get_property(np, "linux,keymap", &proplen)) {
+		dev_err(kbc->dev, "property linux,keymap not found\n");
+		return -ENOENT;
 	}
 
-	for (i = 0; i < KBC_MAX_COL; i++) {
-		pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
-		pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
+	if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
+		dev_err(kbc->dev,
+			"keypad rows/columns not porperly specified\n");
+		return -EINVAL;
 	}
 
-	return pdata;
-}
-#else
-static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
-	struct platform_device *pdev)
-{
-	return NULL;
-}
-#endif
+	/* Set all pins as non-configured */
+	for (i = 0; i < KBC_MAX_GPIO; i++)
+		kbc->pin_cfg[i].type = PIN_CFG_IGNORE;
 
-static int tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
-{
-	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
-	const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
-	unsigned int keymap_rows = KBC_MAX_KEY;
-	int retval;
-
-	if (keymap_data && pdata->use_fn_map)
-		keymap_rows *= 2;
-
-	retval = matrix_keypad_build_keymap(keymap_data, NULL,
-					    keymap_rows, KBC_MAX_COL,
-					    kbc->keycode, kbc->idev);
-	if (retval == -ENOSYS || retval == -ENOENT) {
-		/*
-		 * If there is no OF support in kernel or keymap
-		 * property is missing, use default keymap.
-		 */
-		retval = matrix_keypad_build_keymap(
-					&tegra_kbc_default_keymap_data, NULL,
-					keymap_rows, KBC_MAX_COL,
-					kbc->keycode, kbc->idev);
+	ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
+				rows_cfg, num_rows);
+	if (ret < 0) {
+		dev_err(kbc->dev, "Rows configurations are not proper\n");
+		return -EINVAL;
 	}
 
-	return retval;
+	ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins",
+				cols_cfg, num_cols);
+	if (ret < 0) {
+		dev_err(kbc->dev, "Cols configurations are not proper\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_rows; i++) {
+		kbc->pin_cfg[rows_cfg[i]].type = PIN_CFG_ROW;
+		kbc->pin_cfg[rows_cfg[i]].num = i;
+	}
+
+	for (i = 0; i < num_cols; i++) {
+		kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL;
+		kbc->pin_cfg[cols_cfg[i]].num = i;
+	}
+
+	return 0;
 }
 
 static int tegra_kbc_probe(struct platform_device *pdev)
 {
-	const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
 	struct tegra_kbc *kbc;
-	struct input_dev *input_dev;
 	struct resource *res;
-	int irq;
 	int err;
 	int num_rows = 0;
 	unsigned int debounce_cnt;
 	unsigned int scan_time_rows;
+	unsigned int keymap_rows = KBC_MAX_KEY;
 
-	if (!pdata)
-		pdata = tegra_kbc_dt_parse_pdata(pdev);
-
-	if (!pdata)
-		return -EINVAL;
-
-	if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) {
-		err = -EINVAL;
-		goto err_free_pdata;
+	kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL);
+	if (!kbc) {
+		dev_err(&pdev->dev, "failed to alloc memory for kbc\n");
+		return -ENOMEM;
 	}
 
+	kbc->dev = &pdev->dev;
+	spin_lock_init(&kbc->lock);
+
+	err = tegra_kbc_parse_dt(kbc);
+	if (err)
+		return err;
+
+	if (!tegra_kbc_check_pin_cfg(kbc, &num_rows))
+		return -EINVAL;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "failed to get I/O memory\n");
-		err = -ENXIO;
-		goto err_free_pdata;
+		return -ENXIO;
 	}
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
+	kbc->irq = platform_get_irq(pdev, 0);
+	if (kbc->irq < 0) {
 		dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
-		err = -ENXIO;
-		goto err_free_pdata;
+		return -ENXIO;
 	}
 
-	kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!kbc || !input_dev) {
-		err = -ENOMEM;
-		goto err_free_mem;
+	kbc->idev = devm_input_allocate_device(&pdev->dev);
+	if (!kbc->idev) {
+		dev_err(&pdev->dev, "failed to allocate input device\n");
+		return -ENOMEM;
 	}
 
-	kbc->pdata = pdata;
-	kbc->idev = input_dev;
-	kbc->irq = irq;
-	spin_lock_init(&kbc->lock);
 	setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
 
-	res = request_mem_region(res->start, resource_size(res), pdev->name);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to request I/O memory\n");
-		err = -EBUSY;
-		goto err_free_mem;
-	}
-
-	kbc->mmio = ioremap(res->start, resource_size(res));
+	kbc->mmio = devm_request_and_ioremap(&pdev->dev, res);
 	if (!kbc->mmio) {
-		dev_err(&pdev->dev, "failed to remap I/O memory\n");
-		err = -ENXIO;
-		goto err_free_mem_region;
+		dev_err(&pdev->dev, "Cannot request memregion/iomap address\n");
+		return -EBUSY;
 	}
 
-	kbc->clk = clk_get(&pdev->dev, NULL);
+	kbc->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(kbc->clk)) {
 		dev_err(&pdev->dev, "failed to get keyboard clock\n");
-		err = PTR_ERR(kbc->clk);
-		goto err_iounmap;
+		return PTR_ERR(kbc->clk);
 	}
 
 	/*
@@ -774,37 +626,38 @@
 	 * the rows. There is an additional delay before the row scanning
 	 * starts. The repoll delay is computed in milliseconds.
 	 */
-	debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+	debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
 	scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
-	kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
+	kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + kbc->repeat_cnt;
 	kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
 
-	kbc->wakeup_key = pdata->wakeup_key;
-	kbc->use_fn_map = pdata->use_fn_map;
-	kbc->use_ghost_filter = pdata->use_ghost_filter;
+	kbc->idev->name = pdev->name;
+	kbc->idev->id.bustype = BUS_HOST;
+	kbc->idev->dev.parent = &pdev->dev;
+	kbc->idev->open = tegra_kbc_open;
+	kbc->idev->close = tegra_kbc_close;
 
-	input_dev->name = pdev->name;
-	input_dev->id.bustype = BUS_HOST;
-	input_dev->dev.parent = &pdev->dev;
-	input_dev->open = tegra_kbc_open;
-	input_dev->close = tegra_kbc_close;
+	if (kbc->keymap_data && kbc->use_fn_map)
+		keymap_rows *= 2;
 
-	err = tegra_kbd_setup_keymap(kbc);
+	err = matrix_keypad_build_keymap(kbc->keymap_data, NULL,
+					 keymap_rows, KBC_MAX_COL,
+					 kbc->keycode, kbc->idev);
 	if (err) {
 		dev_err(&pdev->dev, "failed to setup keymap\n");
-		goto err_put_clk;
+		return err;
 	}
 
-	__set_bit(EV_REP, input_dev->evbit);
-	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	__set_bit(EV_REP, kbc->idev->evbit);
+	input_set_capability(kbc->idev, EV_MSC, MSC_SCAN);
 
-	input_set_drvdata(input_dev, kbc);
+	input_set_drvdata(kbc->idev, kbc);
 
-	err = request_irq(kbc->irq, tegra_kbc_isr,
+	err = devm_request_irq(&pdev->dev, kbc->irq, tegra_kbc_isr,
 			  IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
 	if (err) {
 		dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
-		goto err_put_clk;
+		return err;
 	}
 
 	disable_irq(kbc->irq);
@@ -812,60 +665,28 @@
 	err = input_register_device(kbc->idev);
 	if (err) {
 		dev_err(&pdev->dev, "failed to register input device\n");
-		goto err_free_irq;
+		return err;
 	}
 
 	platform_set_drvdata(pdev, kbc);
-	device_init_wakeup(&pdev->dev, pdata->wakeup);
-
-	return 0;
-
-err_free_irq:
-	free_irq(kbc->irq, pdev);
-err_put_clk:
-	clk_put(kbc->clk);
-err_iounmap:
-	iounmap(kbc->mmio);
-err_free_mem_region:
-	release_mem_region(res->start, resource_size(res));
-err_free_mem:
-	input_free_device(input_dev);
-	kfree(kbc);
-err_free_pdata:
-	if (!pdev->dev.platform_data)
-		kfree(pdata);
-
-	return err;
-}
-
-static int tegra_kbc_remove(struct platform_device *pdev)
-{
-	struct tegra_kbc *kbc = platform_get_drvdata(pdev);
-	struct resource *res;
-
-	platform_set_drvdata(pdev, NULL);
-
-	free_irq(kbc->irq, pdev);
-	clk_put(kbc->clk);
-
-	input_unregister_device(kbc->idev);
-	iounmap(kbc->mmio);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	/*
-	 * If we do not have platform data attached to the device we
-	 * allocated it ourselves and thus need to free it.
-	 */
-	if (!pdev->dev.platform_data)
-		kfree(kbc->pdata);
-
-	kfree(kbc);
+	device_init_wakeup(&pdev->dev, kbc->wakeup);
 
 	return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
+static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
+{
+	u32 val;
+
+	val = readl(kbc->mmio + KBC_CONTROL_0);
+	if (enable)
+		val |= KBC_CONTROL_KEYPRESS_INT_EN;
+	else
+		val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
+	writel(val, kbc->mmio + KBC_CONTROL_0);
+}
+
 static int tegra_kbc_suspend(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -954,7 +775,6 @@
 
 static struct platform_driver tegra_kbc_driver = {
 	.probe		= tegra_kbc_probe,
-	.remove		= tegra_kbc_remove,
 	.driver	= {
 		.name	= "tegra-kbc",
 		.owner  = THIS_MODULE,
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
index 1cf72fe..0735de3 100644
--- a/drivers/input/misc/adxl34x.c
+++ b/drivers/input/misc/adxl34x.c
@@ -232,7 +232,7 @@
 
 	.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
 	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
-	.fifo_mode = FIFO_STREAM,
+	.fifo_mode = ADXL_FIFO_STREAM,
 	.watermark = 0,
 };
 
@@ -732,7 +732,7 @@
 	mutex_init(&ac->mutex);
 
 	input_dev->name = "ADXL34x accelerometer";
-	revid = ac->bops->read(dev, DEVID);
+	revid = AC_READ(ac, DEVID);
 
 	switch (revid) {
 	case ID_ADXL345:
@@ -809,7 +809,7 @@
 	if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
 		ac->fifo_delay = false;
 
-	ac->bops->write(dev, POWER_CTL, 0);
+	AC_WRITE(ac, POWER_CTL, 0);
 
 	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
 				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
@@ -827,7 +827,6 @@
 	if (err)
 		goto err_remove_attr;
 
-	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
 	AC_WRITE(ac, OFSX, pdata->x_axis_offset);
 	ac->hwcal.x = pdata->x_axis_offset;
 	AC_WRITE(ac, OFSY, pdata->y_axis_offset);
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 26f1313..5d44023 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -121,7 +121,7 @@
 	return err;
 }
 
-static int atlas_acpi_button_remove(struct acpi_device *device, int type)
+static int atlas_acpi_button_remove(struct acpi_device *device)
 {
 	acpi_status status;
 
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index 08ffcab..865c2f9 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -46,18 +46,6 @@
 #define BMA150_POLL_MAX		200
 #define BMA150_POLL_MIN		0
 
-#define BMA150_BW_25HZ		0
-#define BMA150_BW_50HZ		1
-#define BMA150_BW_100HZ		2
-#define BMA150_BW_190HZ		3
-#define BMA150_BW_375HZ		4
-#define BMA150_BW_750HZ		5
-#define BMA150_BW_1500HZ	6
-
-#define BMA150_RANGE_2G		0
-#define BMA150_RANGE_4G		1
-#define BMA150_RANGE_8G		2
-
 #define BMA150_MODE_NORMAL	0
 #define BMA150_MODE_SLEEP	2
 #define BMA150_MODE_WAKE_UP	3
@@ -372,7 +360,7 @@
 	int error;
 
 	error = pm_runtime_get_sync(&bma150->client->dev);
-	if (error && error != -ENOSYS)
+	if (error < 0 && error != -ENOSYS)
 		return error;
 
 	/*
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 78eb6b3..68a5f33 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -43,7 +43,6 @@
 	struct device		*dev;
 	struct input_dev	*input_dev;
 
-	struct workqueue_struct *workqueue;
 	struct work_struct	play_work;
 
 	bool			enabled;
@@ -143,19 +142,7 @@
 	if (!info->speed)
 		info->speed = effect->u.rumble.weak_magnitude >> 9;
 	info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
-	queue_work(info->workqueue, &info->play_work);
-	return 0;
-}
-
-static int twl4030_vibra_open(struct input_dev *input)
-{
-	struct vibra_info *info = input_get_drvdata(input);
-
-	info->workqueue = create_singlethread_workqueue("vibra");
-	if (info->workqueue == NULL) {
-		dev_err(&input->dev, "couldn't create workqueue\n");
-		return -ENOMEM;
-	}
+	schedule_work(&info->play_work);
 	return 0;
 }
 
@@ -164,9 +151,6 @@
 	struct vibra_info *info = input_get_drvdata(input);
 
 	cancel_work_sync(&info->play_work);
-	INIT_WORK(&info->play_work, vibra_play_work); /* cleanup */
-	destroy_workqueue(info->workqueue);
-	info->workqueue = NULL;
 
 	if (info->enabled)
 		vibra_disable(info);
@@ -219,7 +203,7 @@
 		return -EINVAL;
 	}
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
@@ -227,11 +211,10 @@
 	info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
 	INIT_WORK(&info->play_work, vibra_play_work);
 
-	info->input_dev = input_allocate_device();
+	info->input_dev = devm_input_allocate_device(&pdev->dev);
 	if (info->input_dev == NULL) {
 		dev_err(&pdev->dev, "couldn't allocate input device\n");
-		ret = -ENOMEM;
-		goto err_kzalloc;
+		return -ENOMEM;
 	}
 
 	input_set_drvdata(info->input_dev, info);
@@ -239,14 +222,13 @@
 	info->input_dev->name = "twl4030:vibrator";
 	info->input_dev->id.version = 1;
 	info->input_dev->dev.parent = pdev->dev.parent;
-	info->input_dev->open = twl4030_vibra_open;
 	info->input_dev->close = twl4030_vibra_close;
 	__set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
 	ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
 	if (ret < 0) {
 		dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
-		goto err_ialloc;
+		return ret;
 	}
 
 	ret = input_register_device(info->input_dev);
@@ -262,28 +244,11 @@
 
 err_iff:
 	input_ff_destroy(info->input_dev);
-err_ialloc:
-	input_free_device(info->input_dev);
-err_kzalloc:
-	kfree(info);
 	return ret;
 }
 
-static int twl4030_vibra_remove(struct platform_device *pdev)
-{
-	struct vibra_info *info = platform_get_drvdata(pdev);
-
-	/* this also free ff-memless and calls close if needed */
-	input_unregister_device(info->input_dev);
-	kfree(info);
-	platform_set_drvdata(pdev, NULL);
-
-	return 0;
-}
-
 static struct platform_driver twl4030_vibra_driver = {
 	.probe		= twl4030_vibra_probe,
-	.remove		= twl4030_vibra_remove,
 	.driver		= {
 		.name	= "twl4030-vibra",
 		.owner	= THIS_MODULE,
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 71a28ee..0c2dfc8 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -275,7 +275,7 @@
 		return -EINVAL;
 	}
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 	if (!info) {
 		dev_err(&pdev->dev, "couldn't allocate memory\n");
 		return -ENOMEM;
@@ -309,24 +309,65 @@
 	if ((!info->vibldrv_res && !info->viblmotor_res) ||
 	    (!info->vibrdrv_res && !info->vibrmotor_res)) {
 		dev_err(info->dev, "invalid vibra driver/motor resistance\n");
-		ret = -EINVAL;
-		goto err_kzalloc;
+		return -EINVAL;
 	}
 
 	info->irq = platform_get_irq(pdev, 0);
 	if (info->irq < 0) {
 		dev_err(info->dev, "invalid irq\n");
-		ret = -EINVAL;
-		goto err_kzalloc;
+		return -EINVAL;
 	}
 
 	mutex_init(&info->mutex);
 
+	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+					twl6040_vib_irq_handler, 0,
+					"twl6040_irq_vib", info);
+	if (ret) {
+		dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
+		return ret;
+	}
+
+	info->supplies[0].supply = "vddvibl";
+	info->supplies[1].supply = "vddvibr";
+	/*
+	 * When booted with Device tree the regulators are attached to the
+	 * parent device (twl6040 MFD core)
+	 */
+	ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev,
+				 ARRAY_SIZE(info->supplies), info->supplies);
+	if (ret) {
+		dev_err(info->dev, "couldn't get regulators %d\n", ret);
+		return ret;
+	}
+
+	if (vddvibl_uV) {
+		ret = regulator_set_voltage(info->supplies[0].consumer,
+					    vddvibl_uV, vddvibl_uV);
+		if (ret) {
+			dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
+				ret);
+			goto err_regulator;
+		}
+	}
+
+	if (vddvibr_uV) {
+		ret = regulator_set_voltage(info->supplies[1].consumer,
+					    vddvibr_uV, vddvibr_uV);
+		if (ret) {
+			dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
+				ret);
+			goto err_regulator;
+		}
+	}
+
+	INIT_WORK(&info->play_work, vibra_play_work);
+
 	info->input_dev = input_allocate_device();
 	if (info->input_dev == NULL) {
 		dev_err(info->dev, "couldn't allocate input device\n");
 		ret = -ENOMEM;
-		goto err_kzalloc;
+		goto err_regulator;
 	}
 
 	input_set_drvdata(info->input_dev, info);
@@ -351,70 +392,14 @@
 
 	platform_set_drvdata(pdev, info);
 
-	ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0,
-				   "twl6040_irq_vib", info);
-	if (ret) {
-		dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
-		goto err_irq;
-	}
-
-	info->supplies[0].supply = "vddvibl";
-	info->supplies[1].supply = "vddvibr";
-	/*
-	 * When booted with Device tree the regulators are attached to the
-	 * parent device (twl6040 MFD core)
-	 */
-	ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev,
-				 ARRAY_SIZE(info->supplies), info->supplies);
-	if (ret) {
-		dev_err(info->dev, "couldn't get regulators %d\n", ret);
-		goto err_regulator;
-	}
-
-	if (vddvibl_uV) {
-		ret = regulator_set_voltage(info->supplies[0].consumer,
-					    vddvibl_uV, vddvibl_uV);
-		if (ret) {
-			dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
-				ret);
-			goto err_voltage;
-		}
-	}
-
-	if (vddvibr_uV) {
-		ret = regulator_set_voltage(info->supplies[1].consumer,
-					    vddvibr_uV, vddvibr_uV);
-		if (ret) {
-			dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
-				ret);
-			goto err_voltage;
-		}
-	}
-
-	info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0);
-	if (info->workqueue == NULL) {
-		dev_err(info->dev, "couldn't create workqueue\n");
-		ret = -ENOMEM;
-		goto err_voltage;
-	}
-	INIT_WORK(&info->play_work, vibra_play_work);
-
 	return 0;
 
-err_voltage:
-	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-err_regulator:
-	free_irq(info->irq, info);
-err_irq:
-	input_unregister_device(info->input_dev);
-	info->input_dev = NULL;
 err_iff:
-	if (info->input_dev)
-		input_ff_destroy(info->input_dev);
+	input_ff_destroy(info->input_dev);
 err_ialloc:
 	input_free_device(info->input_dev);
-err_kzalloc:
-	kfree(info);
+err_regulator:
+	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
 	return ret;
 }
 
@@ -423,10 +408,7 @@
 	struct vibra_info *info = platform_get_drvdata(pdev);
 
 	input_unregister_device(info->input_dev);
-	free_irq(info->irq, info);
 	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-	destroy_workqueue(info->workqueue);
-	kfree(info);
 
 	return 0;
 }
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index 558767d..caa2c406 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -86,7 +86,7 @@
 	wm831x_on->wm831x = wm831x;
 	INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on);
 
-	wm831x_on->dev = input_allocate_device();
+	wm831x_on->dev = devm_input_allocate_device(&pdev->dev);
 	if (!wm831x_on->dev) {
 		dev_err(&pdev->dev, "Can't allocate input dev\n");
 		ret = -ENOMEM;
@@ -119,7 +119,6 @@
 err_irq:
 	free_irq(irq, wm831x_on);
 err_input_dev:
-	input_free_device(wm831x_on->dev);
 err:
 	return ret;
 }
@@ -131,7 +130,6 @@
 
 	free_irq(irq, wm831x_on);
 	cancel_delayed_work_sync(&wm831x_on->work);
-	input_unregister_device(wm831x_on->dev);
 
 	return 0;
 }
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index cd6268c..802bd6a 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -68,6 +68,16 @@
 
 	  If unsure, say Y.
 
+config MOUSE_PS2_CYPRESS
+       bool "Cypress PS/2 mouse protocol extension" if EXPERT
+       default y
+       depends on MOUSE_PS2
+       help
+         Say Y here if you have a Cypress PS/2 Trackpad connected to
+         your system.
+
+         If unsure, say Y.
+
 config MOUSE_PS2_LIFEBOOK
 	bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT
 	default y
@@ -193,6 +203,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called bcm5974.
 
+config MOUSE_CYAPA
+	tristate "Cypress APA I2C Trackpad support"
+	depends on I2C
+	help
+	  This driver adds support for Cypress All Points Addressable (APA)
+	  I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
+
+	  Say Y here if you have a Cypress APA I2C Trackpad.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called cyapa.
+
 config MOUSE_INPORT
 	tristate "InPort/MS/ATIXL busmouse"
 	depends on ISA
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 46ba755..c25efdb 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_MOUSE_APPLETOUCH)		+= appletouch.o
 obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
+obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
 obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
@@ -32,3 +33,4 @@
 psmouse-$(CONFIG_MOUSE_PS2_SENTELIC)	+= sentelic.o
 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT)	+= trackpoint.o
 psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT)	+= touchkit_ps2.o
+psmouse-$(CONFIG_MOUSE_PS2_CYPRESS)	+= cypress_ps2.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index e229fa3..7b99fc7 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -27,14 +27,11 @@
 /*
  * Definitions for ALPS version 3 and 4 command mode protocol
  */
-#define ALPS_V3_X_MAX	2000
-#define ALPS_V3_Y_MAX	1400
-
-#define ALPS_BITMAP_X_BITS	15
-#define ALPS_BITMAP_Y_BITS	11
-
 #define ALPS_CMD_NIBBLE_10	0x01f2
 
+#define ALPS_REG_BASE_RUSHMORE	0xc2c0
+#define ALPS_REG_BASE_PINNACLE	0x0000
+
 static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
 	{ PSMOUSE_CMD_SETPOLL,		0x00 }, /* 0 */
 	{ PSMOUSE_CMD_RESET_DIS,	0x00 }, /* 1 */
@@ -109,11 +106,14 @@
 	{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },		/* Dell Vostro 1400 */
 	{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
 		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },				/* Toshiba Tecra A11-11L */
-	{ { 0x73, 0x02, 0x64 },	0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
-	{ { 0x73, 0x02, 0x64 },	0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
 	{ { 0x73, 0x02, 0x64 },	0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
 };
 
+static void alps_set_abs_params_st(struct alps_data *priv,
+				   struct input_dev *dev1);
+static void alps_set_abs_params_mt(struct alps_data *priv,
+				   struct input_dev *dev1);
+
 /*
  * XXX - this entry is suspicious. First byte has zero lower nibble,
  * which is what a normal mouse would report. Also, the value 0x0e
@@ -122,10 +122,10 @@
 
 /* Packet formats are described in Documentation/input/alps.txt */
 
-static bool alps_is_valid_first_byte(const struct alps_model_info *model,
+static bool alps_is_valid_first_byte(struct alps_data *priv,
 				     unsigned char data)
 {
-	return (data & model->mask0) == model->byte0;
+	return (data & priv->mask0) == priv->byte0;
 }
 
 static void alps_report_buttons(struct psmouse *psmouse,
@@ -158,14 +158,13 @@
 static void alps_process_packet_v1_v2(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
-	const struct alps_model_info *model = priv->i;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = psmouse->dev;
 	struct input_dev *dev2 = priv->dev2;
 	int x, y, z, ges, fin, left, right, middle;
 	int back = 0, forward = 0;
 
-	if (model->proto_version == ALPS_PROTO_V1) {
+	if (priv->proto_version == ALPS_PROTO_V1) {
 		left = packet[2] & 0x10;
 		right = packet[2] & 0x08;
 		middle = 0;
@@ -181,12 +180,12 @@
 		z = packet[5];
 	}
 
-	if (model->flags & ALPS_FW_BK_1) {
+	if (priv->flags & ALPS_FW_BK_1) {
 		back = packet[0] & 0x10;
 		forward = packet[2] & 4;
 	}
 
-	if (model->flags & ALPS_FW_BK_2) {
+	if (priv->flags & ALPS_FW_BK_2) {
 		back = packet[3] & 4;
 		forward = packet[2] & 4;
 		if ((middle = forward && back))
@@ -196,7 +195,7 @@
 	ges = packet[2] & 1;
 	fin = packet[2] & 2;
 
-	if ((model->flags & ALPS_DUALPOINT) && z == 127) {
+	if ((priv->flags & ALPS_DUALPOINT) && z == 127) {
 		input_report_rel(dev2, REL_X,  (x > 383 ? (x - 768) : x));
 		input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
 
@@ -239,15 +238,15 @@
 	input_report_abs(dev, ABS_PRESSURE, z);
 	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 
-	if (model->flags & ALPS_WHEEL)
+	if (priv->flags & ALPS_WHEEL)
 		input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07));
 
-	if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+	if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 		input_report_key(dev, BTN_FORWARD, forward);
 		input_report_key(dev, BTN_BACK, back);
 	}
 
-	if (model->flags & ALPS_FOUR_BUTTONS) {
+	if (priv->flags & ALPS_FOUR_BUTTONS) {
 		input_report_key(dev, BTN_0, packet[2] & 4);
 		input_report_key(dev, BTN_1, packet[0] & 0x10);
 		input_report_key(dev, BTN_2, packet[3] & 4);
@@ -267,7 +266,8 @@
  * These points are returned in x1, y1, x2, and y2 when the return value
  * is greater than 0.
  */
-static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
+static int alps_process_bitmap(struct alps_data *priv,
+			       unsigned int x_map, unsigned int y_map,
 			       int *x1, int *y1, int *x2, int *y2)
 {
 	struct alps_bitmap_point {
@@ -309,7 +309,7 @@
 	 * y bitmap is reversed for what we need (lower positions are in
 	 * higher bits), so we process from the top end.
 	 */
-	y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS);
+	y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
 	prev_bit = 0;
 	point = &y_low;
 	for (i = 0; y_map != 0; i++, y_map <<= 1) {
@@ -355,16 +355,18 @@
 		}
 	}
 
-	*x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) /
-	      (2 * (ALPS_BITMAP_X_BITS - 1));
-	*y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) /
-	      (2 * (ALPS_BITMAP_Y_BITS - 1));
+	*x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+	      (2 * (priv->x_bits - 1));
+	*y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+	      (2 * (priv->y_bits - 1));
 
 	if (fingers > 1) {
-		*x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) /
-		      (2 * (ALPS_BITMAP_X_BITS - 1));
-		*y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) /
-		      (2 * (ALPS_BITMAP_Y_BITS - 1));
+		*x2 = (priv->x_max *
+		       (2 * x_high.start_bit + x_high.num_bits - 1)) /
+		      (2 * (priv->x_bits - 1));
+		*y2 = (priv->y_max *
+		       (2 * y_high.start_bit + y_high.num_bits - 1)) /
+		      (2 * (priv->y_bits - 1));
 	}
 
 	return fingers;
@@ -448,17 +450,57 @@
 	return;
 }
 
+static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
+{
+	f->left = !!(p[3] & 0x01);
+	f->right = !!(p[3] & 0x02);
+	f->middle = !!(p[3] & 0x04);
+
+	f->ts_left = !!(p[3] & 0x10);
+	f->ts_right = !!(p[3] & 0x20);
+	f->ts_middle = !!(p[3] & 0x40);
+}
+
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+{
+	f->first_mp = !!(p[4] & 0x40);
+	f->is_mp = !!(p[0] & 0x40);
+
+	f->fingers = (p[5] & 0x3) + 1;
+	f->x_map = ((p[4] & 0x7e) << 8) |
+		   ((p[1] & 0x7f) << 2) |
+		   ((p[0] & 0x30) >> 4);
+	f->y_map = ((p[3] & 0x70) << 4) |
+		   ((p[2] & 0x7f) << 1) |
+		   (p[4] & 0x01);
+
+	f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+	       ((p[0] & 0x30) >> 4);
+	f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+	f->z = p[5] & 0x7f;
+
+	alps_decode_buttons_v3(f, p);
+}
+
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+{
+	alps_decode_pinnacle(f, p);
+
+	f->x_map |= (p[5] & 0x10) << 11;
+	f->y_map |= (p[5] & 0x20) << 6;
+}
+
 static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	struct input_dev *dev = psmouse->dev;
 	struct input_dev *dev2 = priv->dev2;
-	int x, y, z;
-	int left, right, middle;
 	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
 	int fingers = 0, bmap_fingers;
-	unsigned int x_bitmap, y_bitmap;
+	struct alps_fields f;
+
+	priv->decode_fields(&f, packet);
 
 	/*
 	 * There's no single feature of touchpad position and bitmap packets
@@ -473,16 +515,10 @@
 		 * packet. Check for this, and when it happens process the
 		 * position packet as usual.
 		 */
-		if (packet[0] & 0x40) {
-			fingers = (packet[5] & 0x3) + 1;
-			x_bitmap = ((packet[4] & 0x7e) << 8) |
-				   ((packet[1] & 0x7f) << 2) |
-				   ((packet[0] & 0x30) >> 4);
-			y_bitmap = ((packet[3] & 0x70) << 4) |
-				   ((packet[2] & 0x7f) << 1) |
-				   (packet[4] & 0x01);
-
-			bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+		if (f.is_mp) {
+			fingers = f.fingers;
+			bmap_fingers = alps_process_bitmap(priv,
+							   f.x_map, f.y_map,
 							   &x1, &y1, &x2, &y2);
 
 			/*
@@ -493,7 +529,7 @@
 				fingers = bmap_fingers;
 
 			/* Now process position packet */
-			packet = priv->multi_data;
+			priv->decode_fields(&f, priv->multi_data);
 		} else {
 			priv->multi_packet = 0;
 		}
@@ -507,10 +543,10 @@
 	 * out misidentified bitmap packets, we reject anything with this
 	 * bit set.
 	 */
-	if (packet[0] & 0x40)
+	if (f.is_mp)
 		return;
 
-	if (!priv->multi_packet && (packet[4] & 0x40)) {
+	if (!priv->multi_packet && f.first_mp) {
 		priv->multi_packet = 1;
 		memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
 		return;
@@ -518,22 +554,13 @@
 
 	priv->multi_packet = 0;
 
-	left = packet[3] & 0x01;
-	right = packet[3] & 0x02;
-	middle = packet[3] & 0x04;
-
-	x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
-	    ((packet[0] & 0x30) >> 4);
-	y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
-	z = packet[5] & 0x7f;
-
 	/*
 	 * Sometimes the hardware sends a single packet with z = 0
 	 * in the middle of a stream. Real releases generate packets
 	 * with x, y, and z all zero, so these seem to be flukes.
 	 * Ignore them.
 	 */
-	if (x && y && !z)
+	if (f.x && f.y && !f.z)
 		return;
 
 	/*
@@ -541,12 +568,12 @@
 	 * to rely on ST data.
 	 */
 	if (!fingers) {
-		x1 = x;
-		y1 = y;
-		fingers = z > 0 ? 1 : 0;
+		x1 = f.x;
+		y1 = f.y;
+		fingers = f.z > 0 ? 1 : 0;
 	}
 
-	if (z >= 64)
+	if (f.z >= 64)
 		input_report_key(dev, BTN_TOUCH, 1);
 	else
 		input_report_key(dev, BTN_TOUCH, 0);
@@ -555,26 +582,22 @@
 
 	input_mt_report_finger_count(dev, fingers);
 
-	input_report_key(dev, BTN_LEFT, left);
-	input_report_key(dev, BTN_RIGHT, right);
-	input_report_key(dev, BTN_MIDDLE, middle);
+	input_report_key(dev, BTN_LEFT, f.left);
+	input_report_key(dev, BTN_RIGHT, f.right);
+	input_report_key(dev, BTN_MIDDLE, f.middle);
 
-	if (z > 0) {
-		input_report_abs(dev, ABS_X, x);
-		input_report_abs(dev, ABS_Y, y);
+	if (f.z > 0) {
+		input_report_abs(dev, ABS_X, f.x);
+		input_report_abs(dev, ABS_Y, f.y);
 	}
-	input_report_abs(dev, ABS_PRESSURE, z);
+	input_report_abs(dev, ABS_PRESSURE, f.z);
 
 	input_sync(dev);
 
 	if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
-		left = packet[3] & 0x10;
-		right = packet[3] & 0x20;
-		middle = packet[3] & 0x40;
-
-		input_report_key(dev2, BTN_LEFT, left);
-		input_report_key(dev2, BTN_RIGHT, right);
-		input_report_key(dev2, BTN_MIDDLE, middle);
+		input_report_key(dev2, BTN_LEFT, f.ts_left);
+		input_report_key(dev2, BTN_RIGHT, f.ts_right);
+		input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
 		input_sync(dev2);
 	}
 }
@@ -639,7 +662,7 @@
 			   ((priv->multi_data[3] & 0x1f) << 5) |
 			    (priv->multi_data[1] & 0x1f);
 
-		fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+		fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
 					      &x1, &y1, &x2, &y2);
 
 		/* Store MT data.*/
@@ -696,25 +719,6 @@
 	input_sync(dev);
 }
 
-static void alps_process_packet(struct psmouse *psmouse)
-{
-	struct alps_data *priv = psmouse->private;
-	const struct alps_model_info *model = priv->i;
-
-	switch (model->proto_version) {
-	case ALPS_PROTO_V1:
-	case ALPS_PROTO_V2:
-		alps_process_packet_v1_v2(psmouse);
-		break;
-	case ALPS_PROTO_V3:
-		alps_process_packet_v3(psmouse);
-		break;
-	case ALPS_PROTO_V4:
-		alps_process_packet_v4(psmouse);
-		break;
-	}
-}
-
 static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 					unsigned char packet[],
 					bool report_buttons)
@@ -765,14 +769,14 @@
 		if (((psmouse->packet[3] |
 		      psmouse->packet[4] |
 		      psmouse->packet[5]) & 0x80) ||
-		    (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
+		    (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) {
 			psmouse_dbg(psmouse,
 				    "refusing packet %4ph (suspected interleaved ps/2)\n",
 				    psmouse->packet + 3);
 			return PSMOUSE_BAD_DATA;
 		}
 
-		alps_process_packet(psmouse);
+		priv->process_packet(psmouse);
 
 		/* Continue with the next packet */
 		psmouse->packet[0] = psmouse->packet[6];
@@ -816,6 +820,7 @@
 static void alps_flush_packet(unsigned long data)
 {
 	struct psmouse *psmouse = (struct psmouse *)data;
+	struct alps_data *priv = psmouse->private;
 
 	serio_pause_rx(psmouse->ps2dev.serio);
 
@@ -833,7 +838,7 @@
 				    "refusing packet %3ph (suspected interleaved ps/2)\n",
 				    psmouse->packet + 3);
 		} else {
-			alps_process_packet(psmouse);
+			priv->process_packet(psmouse);
 		}
 		psmouse->pktcnt = 0;
 	}
@@ -844,7 +849,6 @@
 static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
-	const struct alps_model_info *model = priv->i;
 
 	if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
 		if (psmouse->pktcnt == 3) {
@@ -857,15 +861,15 @@
 
 	/* Check for PS/2 packet stuffed in the middle of ALPS packet. */
 
-	if ((model->flags & ALPS_PS2_INTERLEAVED) &&
+	if ((priv->flags & ALPS_PS2_INTERLEAVED) &&
 	    psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) {
 		return alps_handle_interleaved_ps2(psmouse);
 	}
 
-	if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
+	if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) {
 		psmouse_dbg(psmouse,
 			    "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
-			    psmouse->packet[0], model->mask0, model->byte0);
+			    psmouse->packet[0], priv->mask0, priv->byte0);
 		return PSMOUSE_BAD_DATA;
 	}
 
@@ -879,7 +883,7 @@
 	}
 
 	if (psmouse->pktcnt == psmouse->pktsize) {
-		alps_process_packet(psmouse);
+		priv->process_packet(psmouse);
 		return PSMOUSE_FULL_PACKET;
 	}
 
@@ -967,24 +971,42 @@
 	return __alps_command_mode_write_reg(psmouse, value);
 }
 
+static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
+			int repeated_command, unsigned char *param)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+	param[0] = 0;
+	if (init_command && ps2_command(ps2dev, param, init_command))
+		return -EIO;
+
+	if (ps2_command(ps2dev,  NULL, repeated_command) ||
+	    ps2_command(ps2dev,  NULL, repeated_command) ||
+	    ps2_command(ps2dev,  NULL, repeated_command))
+		return -EIO;
+
+	param[0] = param[1] = param[2] = 0xff;
+	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+		return -EIO;
+
+	psmouse_dbg(psmouse, "%2.2X report: %2.2x %2.2x %2.2x\n",
+		    repeated_command, param[0], param[1], param[2]);
+	return 0;
+}
+
 static int alps_enter_command_mode(struct psmouse *psmouse,
 				   unsigned char *resp)
 {
 	unsigned char param[4];
-	struct ps2dev *ps2dev = &psmouse->ps2dev;
 
-	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
-	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
-	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
-	    ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
+	if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) {
 		psmouse_err(psmouse, "failed to enter command mode\n");
 		return -1;
 	}
 
-	if (param[0] != 0x88 && param[1] != 0x07) {
+	if (param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) {
 		psmouse_dbg(psmouse,
-			    "unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
-			    param[0], param[1], param[2]);
+			    "unknown response while entering command mode\n");
 		return -1;
 	}
 
@@ -1001,99 +1023,6 @@
 	return 0;
 }
 
-static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
-{
-	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
-	unsigned char param[4];
-	const struct alps_model_info *model = NULL;
-	int i;
-
-	/*
-	 * First try "E6 report".
-	 * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
-	 * The bits 0-2 of the first byte will be 1s if some buttons are
-	 * pressed.
-	 */
-	param[0] = 0;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
-	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
-	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
-	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11))
-		return NULL;
-
-	param[0] = param[1] = param[2] = 0xff;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return NULL;
-
-	psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
-		    param[0], param[1], param[2]);
-
-	if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
-	    (param[2] != 10 && param[2] != 100))
-		return NULL;
-
-	/*
-	 * Now try "E7 report". Allowed responses are in
-	 * alps_model_data[].signature
-	 */
-	param[0] = 0;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
-	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
-	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
-	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21))
-		return NULL;
-
-	param[0] = param[1] = param[2] = 0xff;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return NULL;
-
-	psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
-		    param[0], param[1], param[2]);
-
-	if (version) {
-		for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
-			/* empty */;
-		*version = (param[0] << 8) | (param[1] << 4) | i;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
-		if (!memcmp(param, alps_model_data[i].signature,
-			    sizeof(alps_model_data[i].signature))) {
-			model = alps_model_data + i;
-			break;
-		}
-	}
-
-	if (model && model->proto_version > ALPS_PROTO_V2) {
-		/*
-		 * Need to check command mode response to identify
-		 * model
-		 */
-		model = NULL;
-		if (alps_enter_command_mode(psmouse, param)) {
-			psmouse_warn(psmouse,
-				     "touchpad failed to enter command mode\n");
-		} else {
-			for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
-				if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
-				    alps_model_data[i].command_mode_resp == param[0]) {
-					model = alps_model_data + i;
-					break;
-				}
-			}
-			alps_exit_command_mode(psmouse);
-
-			if (!model)
-				psmouse_dbg(psmouse,
-					    "Unknown command mode response %2.2x\n",
-					    param[0]);
-		}
-	}
-
-	return model;
-}
-
 /*
  * For DualPoint devices select the device that should respond to
  * subsequent commands. It looks like glidepad is behind stickpointer,
@@ -1137,18 +1066,10 @@
 
 static int alps_get_status(struct psmouse *psmouse, char *param)
 {
-	struct ps2dev *ps2dev = &psmouse->ps2dev;
-
 	/* Get status: 0xF5 0xF5 0xF5 0xE9 */
-	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
-	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
-	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
-	    ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+	if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param))
 		return -1;
 
-	psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x",
-		    param[0], param[1], param[2]);
-
 	return 0;
 }
 
@@ -1190,16 +1111,16 @@
 	unsigned char buf[sizeof(psmouse->packet)];
 	bool poll_failed;
 
-	if (priv->i->flags & ALPS_PASS)
+	if (priv->flags & ALPS_PASS)
 		alps_passthrough_mode_v2(psmouse, true);
 
 	poll_failed = ps2_command(&psmouse->ps2dev, buf,
 				  PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
 
-	if (priv->i->flags & ALPS_PASS)
+	if (priv->flags & ALPS_PASS)
 		alps_passthrough_mode_v2(psmouse, false);
 
-	if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
+	if (poll_failed || (buf[0] & priv->mask0) != priv->byte0)
 		return -1;
 
 	if ((psmouse->badbyte & 0xc8) == 0x08) {
@@ -1217,9 +1138,8 @@
 static int alps_hw_init_v1_v2(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
-	const struct alps_model_info *model = priv->i;
 
-	if ((model->flags & ALPS_PASS) &&
+	if ((priv->flags & ALPS_PASS) &&
 	    alps_passthrough_mode_v2(psmouse, true)) {
 		return -1;
 	}
@@ -1234,7 +1154,7 @@
 		return -1;
 	}
 
-	if ((model->flags & ALPS_PASS) &&
+	if ((priv->flags & ALPS_PASS) &&
 	    alps_passthrough_mode_v2(psmouse, false)) {
 		return -1;
 	}
@@ -1249,26 +1169,31 @@
 }
 
 /*
- * Enable or disable passthrough mode to the trackstick. Must be in
- * command mode when calling this function.
+ * Enable or disable passthrough mode to the trackstick.
  */
-static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
+static int alps_passthrough_mode_v3(struct psmouse *psmouse,
+				    int reg_base, bool enable)
 {
-	int reg_val;
+	int reg_val, ret = -1;
 
-	reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
-	if (reg_val == -1)
+	if (alps_enter_command_mode(psmouse, NULL))
 		return -1;
 
+	reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008);
+	if (reg_val == -1)
+		goto error;
+
 	if (enable)
 		reg_val |= 0x01;
 	else
 		reg_val &= ~0x01;
 
-	if (__alps_command_mode_write_reg(psmouse, reg_val))
-		return -1;
+	ret = __alps_command_mode_write_reg(psmouse, reg_val);
 
-	return 0;
+error:
+	if (alps_exit_command_mode(psmouse))
+		ret = -1;
+	return ret;
 }
 
 /* Must be in command mode when calling this function */
@@ -1287,73 +1212,102 @@
 	return 0;
 }
 
-static int alps_hw_init_v3(struct psmouse *psmouse)
+static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base)
 {
-	struct alps_data *priv = psmouse->private;
-	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	int reg_val;
-	unsigned char param[4];
-
-	priv->nibble_commands = alps_v3_nibble_commands;
-	priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+	int ret = -EIO, reg_val;
 
 	if (alps_enter_command_mode(psmouse, NULL))
 		goto error;
 
-	/* Check for trackstick */
-	reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
+	reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08);
 	if (reg_val == -1)
 		goto error;
-	if (reg_val & 0x80) {
-		if (alps_passthrough_mode_v3(psmouse, true))
-			goto error;
-		if (alps_exit_command_mode(psmouse))
-			goto error;
+
+	/* bit 7: trackstick is present */
+	ret = reg_val & 0x80 ? 0 : -ENODEV;
+
+error:
+	alps_exit_command_mode(psmouse);
+	return ret;
+}
+
+static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int ret = 0;
+	unsigned char param[4];
+
+	if (alps_passthrough_mode_v3(psmouse, reg_base, true))
+		return -EIO;
+
+	/*
+	 * E7 report for the trackstick
+	 *
+	 * There have been reports of failures to seem to trace back
+	 * to the above trackstick check failing. When these occur
+	 * this E7 report fails, so when that happens we continue
+	 * with the assumption that there isn't a trackstick after
+	 * all.
+	 */
+	if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
+		psmouse_warn(psmouse, "trackstick E7 report failed\n");
+		ret = -ENODEV;
+	} else {
+		psmouse_dbg(psmouse,
+			    "trackstick E7 report: %2.2x %2.2x %2.2x\n",
+			    param[0], param[1], param[2]);
 
 		/*
-		 * E7 report for the trackstick
-		 *
-		 * There have been reports of failures to seem to trace back
-		 * to the above trackstick check failing. When these occur
-		 * this E7 report fails, so when that happens we continue
-		 * with the assumption that there isn't a trackstick after
-		 * all.
+		 * Not sure what this does, but it is absolutely
+		 * essential. Without it, the touchpad does not
+		 * work at all and the trackstick just emits normal
+		 * PS/2 packets.
 		 */
-		param[0] = 0x64;
-		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
-		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
-		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
-		    ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
-			psmouse_warn(psmouse, "trackstick E7 report failed\n");
-		} else {
-			psmouse_dbg(psmouse,
-				    "trackstick E7 report: %2.2x %2.2x %2.2x\n",
-				    param[0], param[1], param[2]);
-
-			/*
-			 * Not sure what this does, but it is absolutely
-			 * essential. Without it, the touchpad does not
-			 * work at all and the trackstick just emits normal
-			 * PS/2 packets.
-			 */
-			if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
-			    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
-			    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
-			    alps_command_mode_send_nibble(psmouse, 0x9) ||
-			    alps_command_mode_send_nibble(psmouse, 0x4)) {
-				psmouse_err(psmouse,
-					    "Error sending magic E6 sequence\n");
-				goto error_passthrough;
-			}
+		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+		    alps_command_mode_send_nibble(psmouse, 0x9) ||
+		    alps_command_mode_send_nibble(psmouse, 0x4)) {
+			psmouse_err(psmouse,
+				    "Error sending magic E6 sequence\n");
+			ret = -EIO;
+			goto error;
 		}
 
-		if (alps_enter_command_mode(psmouse, NULL))
-			goto error_passthrough;
-		if (alps_passthrough_mode_v3(psmouse, false))
-			goto error;
+		/*
+		 * This ensures the trackstick packets are in the format
+		 * supported by this driver. If bit 1 isn't set the packet
+		 * format is different.
+		 */
+		if (alps_enter_command_mode(psmouse, NULL) ||
+		    alps_command_mode_write_reg(psmouse,
+						reg_base + 0x08, 0x82) ||
+		    alps_exit_command_mode(psmouse))
+			ret = -EIO;
 	}
 
-	if (alps_absolute_mode_v3(psmouse)) {
+error:
+	if (alps_passthrough_mode_v3(psmouse, reg_base, false))
+		ret = -EIO;
+
+	return ret;
+}
+
+static int alps_hw_init_v3(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int reg_val;
+	unsigned char param[4];
+
+	reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
+	if (reg_val == -EIO)
+		goto error;
+	if (reg_val == 0 &&
+	    alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
+		goto error;
+
+	if (alps_enter_command_mode(psmouse, NULL) ||
+	    alps_absolute_mode_v3(psmouse)) {
 		psmouse_err(psmouse, "Failed to enter absolute mode\n");
 		goto error;
 	}
@@ -1390,14 +1344,6 @@
 	if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
 		goto error;
 
-	/*
-	 * This ensures the trackstick packets are in the format
-	 * supported by this driver. If bit 1 isn't set the packet
-	 * format is different.
-	 */
-	if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
-		goto error;
-
 	alps_exit_command_mode(psmouse);
 
 	/* Set rate and enable data reporting */
@@ -1410,10 +1356,6 @@
 
 	return 0;
 
-error_passthrough:
-	/* Something failed while in passthrough mode, so try to get out */
-	if (!alps_enter_command_mode(psmouse, NULL))
-		alps_passthrough_mode_v3(psmouse, false);
 error:
 	/*
 	 * Leaving the touchpad in command mode will essentially render
@@ -1424,6 +1366,50 @@
 	return -1;
 }
 
+static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int reg_val, ret = -1;
+
+	if (priv->flags & ALPS_DUALPOINT) {
+		reg_val = alps_setup_trackstick_v3(psmouse,
+						   ALPS_REG_BASE_RUSHMORE);
+		if (reg_val == -EIO)
+			goto error;
+		if (reg_val == -ENODEV)
+			priv->flags &= ~ALPS_DUALPOINT;
+	}
+
+	if (alps_enter_command_mode(psmouse, NULL) ||
+	    alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
+	    alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
+		goto error;
+
+	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
+	if (reg_val == -1)
+		goto error;
+	if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd))
+		goto error;
+
+	if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
+		goto error;
+
+	/* enter absolute mode */
+	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
+	if (reg_val == -1)
+		goto error;
+	if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
+		goto error;
+
+	alps_exit_command_mode(psmouse);
+	return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+error:
+	alps_exit_command_mode(psmouse);
+	return ret;
+}
+
 /* Must be in command mode when calling this function */
 static int alps_absolute_mode_v4(struct psmouse *psmouse)
 {
@@ -1442,13 +1428,9 @@
 
 static int alps_hw_init_v4(struct psmouse *psmouse)
 {
-	struct alps_data *priv = psmouse->private;
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
 	unsigned char param[4];
 
-	priv->nibble_commands = alps_v4_nibble_commands;
-	priv->addr_command = PSMOUSE_CMD_DISABLE;
-
 	if (alps_enter_command_mode(psmouse, NULL))
 		goto error;
 
@@ -1517,39 +1499,140 @@
 	return -1;
 }
 
-static int alps_hw_init(struct psmouse *psmouse)
+static void alps_set_defaults(struct alps_data *priv)
 {
-	struct alps_data *priv = psmouse->private;
-	const struct alps_model_info *model = priv->i;
-	int ret = -1;
+	priv->byte0 = 0x8f;
+	priv->mask0 = 0x8f;
+	priv->flags = ALPS_DUALPOINT;
 
-	switch (model->proto_version) {
+	priv->x_max = 2000;
+	priv->y_max = 1400;
+	priv->x_bits = 15;
+	priv->y_bits = 11;
+
+	switch (priv->proto_version) {
 	case ALPS_PROTO_V1:
 	case ALPS_PROTO_V2:
-		ret = alps_hw_init_v1_v2(psmouse);
+		priv->hw_init = alps_hw_init_v1_v2;
+		priv->process_packet = alps_process_packet_v1_v2;
+		priv->set_abs_params = alps_set_abs_params_st;
 		break;
 	case ALPS_PROTO_V3:
-		ret = alps_hw_init_v3(psmouse);
+		priv->hw_init = alps_hw_init_v3;
+		priv->process_packet = alps_process_packet_v3;
+		priv->set_abs_params = alps_set_abs_params_mt;
+		priv->decode_fields = alps_decode_pinnacle;
+		priv->nibble_commands = alps_v3_nibble_commands;
+		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
 		break;
 	case ALPS_PROTO_V4:
-		ret = alps_hw_init_v4(psmouse);
+		priv->hw_init = alps_hw_init_v4;
+		priv->process_packet = alps_process_packet_v4;
+		priv->set_abs_params = alps_set_abs_params_mt;
+		priv->nibble_commands = alps_v4_nibble_commands;
+		priv->addr_command = PSMOUSE_CMD_DISABLE;
 		break;
 	}
+}
 
-	return ret;
+static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
+			    unsigned char *e7, unsigned char *ec)
+{
+	const struct alps_model_info *model;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+		model = &alps_model_data[i];
+
+		if (!memcmp(e7, model->signature, sizeof(model->signature)) &&
+		    (!model->command_mode_resp ||
+		     model->command_mode_resp == ec[2])) {
+
+			priv->proto_version = model->proto_version;
+			alps_set_defaults(priv);
+
+			priv->flags = model->flags;
+			priv->byte0 = model->byte0;
+			priv->mask0 = model->mask0;
+
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
+{
+	unsigned char e6[4], e7[4], ec[4];
+
+	/*
+	 * First try "E6 report".
+	 * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+	 * The bits 0-2 of the first byte will be 1s if some buttons are
+	 * pressed.
+	 */
+	if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+			 PSMOUSE_CMD_SETSCALE11, e6))
+		return -EIO;
+
+	if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100))
+		return -EINVAL;
+
+	/*
+	 * Now get the "E7" and "EC" reports.  These will uniquely identify
+	 * most ALPS touchpads.
+	 */
+	if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+			 PSMOUSE_CMD_SETSCALE21, e7) ||
+	    alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+			 PSMOUSE_CMD_RESET_WRAP, ec) ||
+	    alps_exit_command_mode(psmouse))
+		return -EIO;
+
+	if (alps_match_table(psmouse, priv, e7, ec) == 0) {
+		return 0;
+	} else if (ec[0] == 0x88 && ec[1] == 0x08) {
+		priv->proto_version = ALPS_PROTO_V3;
+		alps_set_defaults(priv);
+
+		priv->hw_init = alps_hw_init_rushmore_v3;
+		priv->decode_fields = alps_decode_rushmore;
+		priv->x_bits = 16;
+		priv->y_bits = 12;
+
+		/* hack to make addr_command, nibble_command available */
+		psmouse->private = priv;
+
+		if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE))
+			priv->flags &= ~ALPS_DUALPOINT;
+
+		return 0;
+	} else if (ec[0] == 0x88 && ec[1] == 0x07 &&
+		   ec[2] >= 0x90 && ec[2] <= 0x9d) {
+		priv->proto_version = ALPS_PROTO_V3;
+		alps_set_defaults(priv);
+
+		return 0;
+	}
+
+	psmouse_info(psmouse,
+		"Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n",
+		e7[0], e7[1], e7[2], ec[0], ec[1], ec[2]);
+
+	return -EINVAL;
 }
 
 static int alps_reconnect(struct psmouse *psmouse)
 {
-	const struct alps_model_info *model;
+	struct alps_data *priv = psmouse->private;
 
 	psmouse_reset(psmouse);
 
-	model = alps_get_model(psmouse, NULL);
-	if (!model)
+	if (alps_identify(psmouse, priv) < 0)
 		return -1;
 
-	return alps_hw_init(psmouse);
+	return priv->hw_init(psmouse);
 }
 
 static void alps_disconnect(struct psmouse *psmouse)
@@ -1562,12 +1645,33 @@
 	kfree(priv);
 }
 
+static void alps_set_abs_params_st(struct alps_data *priv,
+				   struct input_dev *dev1)
+{
+	input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
+	input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+}
+
+static void alps_set_abs_params_mt(struct alps_data *priv,
+				   struct input_dev *dev1)
+{
+	set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+	input_mt_init_slots(dev1, 2, 0);
+	input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
+	input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+
+	set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
+	set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
+	set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
+
+	input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
+	input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
+}
+
 int alps_init(struct psmouse *psmouse)
 {
 	struct alps_data *priv;
-	const struct alps_model_info *model;
 	struct input_dev *dev1 = psmouse->dev, *dev2;
-	int version;
 
 	priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
 	dev2 = input_allocate_device();
@@ -1581,13 +1685,10 @@
 
 	psmouse_reset(psmouse);
 
-	model = alps_get_model(psmouse, &version);
-	if (!model)
+	if (alps_identify(psmouse, priv) < 0)
 		goto init_fail;
 
-	priv->i = model;
-
-	if (alps_hw_init(psmouse))
+	if (priv->hw_init(psmouse))
 		goto init_fail;
 
 	/*
@@ -1609,41 +1710,20 @@
 
 	dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
 
-	switch (model->proto_version) {
-	case ALPS_PROTO_V1:
-	case ALPS_PROTO_V2:
-		input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
-		input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
-		break;
-	case ALPS_PROTO_V3:
-	case ALPS_PROTO_V4:
-		set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
-		input_mt_init_slots(dev1, 2, 0);
-		input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
-		input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
-
-		set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
-		set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
-		set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
-
-		input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
-		input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
-		break;
-	}
-
+	priv->set_abs_params(priv, dev1);
 	input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
 
-	if (model->flags & ALPS_WHEEL) {
+	if (priv->flags & ALPS_WHEEL) {
 		dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
 		dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL);
 	}
 
-	if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+	if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 		dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD);
 		dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK);
 	}
 
-	if (model->flags & ALPS_FOUR_BUTTONS) {
+	if (priv->flags & ALPS_FOUR_BUTTONS) {
 		dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0);
 		dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
 		dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
@@ -1654,7 +1734,8 @@
 
 	snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
 	dev2->phys = priv->phys;
-	dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
+	dev2->name = (priv->flags & ALPS_DUALPOINT) ?
+		     "DualPoint Stick" : "PS/2 Mouse";
 	dev2->id.bustype = BUS_I8042;
 	dev2->id.vendor  = 0x0002;
 	dev2->id.product = PSMOUSE_ALPS;
@@ -1673,7 +1754,7 @@
 	psmouse->poll = alps_poll;
 	psmouse->disconnect = alps_disconnect;
 	psmouse->reconnect = alps_reconnect;
-	psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
+	psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
 
 	/* We are having trouble resyncing ALPS touchpads so disable it for now */
 	psmouse->resync_time = 0;
@@ -1690,18 +1771,16 @@
 
 int alps_detect(struct psmouse *psmouse, bool set_properties)
 {
-	int version;
-	const struct alps_model_info *model;
+	struct alps_data dummy;
 
-	model = alps_get_model(psmouse, &version);
-	if (!model)
+	if (alps_identify(psmouse, &dummy) < 0)
 		return -1;
 
 	if (set_properties) {
 		psmouse->vendor = "ALPS";
-		psmouse->name = model->flags & ALPS_DUALPOINT ?
+		psmouse->name = dummy.flags & ALPS_DUALPOINT ?
 				"DualPoint TouchPad" : "GlidePoint";
-		psmouse->model = version;
+		psmouse->model = dummy.proto_version << 8;
 	}
 	return 0;
 }
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index ae1ac35..9704805 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,35 +12,146 @@
 #ifndef _ALPS_H
 #define _ALPS_H
 
-#define ALPS_PROTO_V1	0
-#define ALPS_PROTO_V2	1
-#define ALPS_PROTO_V3	2
-#define ALPS_PROTO_V4	3
+#define ALPS_PROTO_V1	1
+#define ALPS_PROTO_V2	2
+#define ALPS_PROTO_V3	3
+#define ALPS_PROTO_V4	4
 
+/**
+ * struct alps_model_info - touchpad ID table
+ * @signature: E7 response string to match.
+ * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response
+ *   (aka command mode response) identifies the firmware minor version.  This
+ *   can be used to distinguish different hardware models which are not
+ *   uniquely identifiable through their E7 responses.
+ * @proto_version: Indicates V1/V2/V3/...
+ * @byte0: Helps figure out whether a position report packet matches the
+ *   known format for this model.  The first byte of the report, ANDed with
+ *   mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ *
+ * Many (but not all) ALPS touchpads can be identified by looking at the
+ * values returned in the "E7 report" and/or the "EC report."  This table
+ * lists a number of such touchpads.
+ */
 struct alps_model_info {
-        unsigned char signature[3];
-	unsigned char command_mode_resp; /* v3/v4 only */
+	unsigned char signature[3];
+	unsigned char command_mode_resp;
 	unsigned char proto_version;
-        unsigned char byte0, mask0;
-        unsigned char flags;
+	unsigned char byte0, mask0;
+	unsigned char flags;
 };
 
+/**
+ * struct alps_nibble_commands - encodings for register accesses
+ * @command: PS/2 command used for the nibble
+ * @data: Data supplied as an argument to the PS/2 command, if applicable
+ *
+ * The ALPS protocol uses magic sequences to transmit binary data to the
+ * touchpad, as it is generally not OK to send arbitrary bytes out the
+ * PS/2 port.  Each of the sequences in this table sends one nibble of the
+ * register address or (write) data.  Different versions of the ALPS protocol
+ * use slightly different encodings.
+ */
 struct alps_nibble_commands {
 	int command;
 	unsigned char data;
 };
 
+/**
+ * struct alps_fields - decoded version of the report packet
+ * @x_map: Bitmap of active X positions for MT.
+ * @y_map: Bitmap of active Y positions for MT.
+ * @fingers: Number of fingers for MT.
+ * @x: X position for ST.
+ * @y: Y position for ST.
+ * @z: Z position for ST.
+ * @first_mp: Packet is the first of a multi-packet report.
+ * @is_mp: Packet is part of a multi-packet report.
+ * @left: Left touchpad button is active.
+ * @right: Right touchpad button is active.
+ * @middle: Middle touchpad button is active.
+ * @ts_left: Left trackstick button is active.
+ * @ts_right: Right trackstick button is active.
+ * @ts_middle: Middle trackstick button is active.
+ */
+struct alps_fields {
+	unsigned int x_map;
+	unsigned int y_map;
+	unsigned int fingers;
+	unsigned int x;
+	unsigned int y;
+	unsigned int z;
+	unsigned int first_mp:1;
+	unsigned int is_mp:1;
+
+	unsigned int left:1;
+	unsigned int right:1;
+	unsigned int middle:1;
+
+	unsigned int ts_left:1;
+	unsigned int ts_right:1;
+	unsigned int ts_middle:1;
+};
+
+/**
+ * struct alps_data - private data structure for the ALPS driver
+ * @dev2: "Relative" device used to report trackstick or mouse activity.
+ * @phys: Physical path for the relative device.
+ * @nibble_commands: Command mapping used for touchpad register accesses.
+ * @addr_command: Command used to tell the touchpad that a register address
+ *   follows.
+ * @proto_version: Indicates V1/V2/V3/...
+ * @byte0: Helps figure out whether a position report packet matches the
+ *   known format for this model.  The first byte of the report, ANDed with
+ *   mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ * @x_max: Largest possible X position value.
+ * @y_max: Largest possible Y position value.
+ * @x_bits: Number of X bits in the MT bitmap.
+ * @y_bits: Number of Y bits in the MT bitmap.
+ * @hw_init: Protocol-specific hardware init function.
+ * @process_packet: Protocol-specific function to process a report packet.
+ * @decode_fields: Protocol-specific function to read packet bitfields.
+ * @set_abs_params: Protocol-specific function to configure the input_dev.
+ * @prev_fin: Finger bit from previous packet.
+ * @multi_packet: Multi-packet data in progress.
+ * @multi_data: Saved multi-packet data.
+ * @x1: First X coordinate from last MT report.
+ * @x2: Second X coordinate from last MT report.
+ * @y1: First Y coordinate from last MT report.
+ * @y2: Second Y coordinate from last MT report.
+ * @fingers: Number of fingers from last MT report.
+ * @quirks: Bitmap of ALPS_QUIRK_*.
+ * @timer: Timer for flushing out the final report packet in the stream.
+ */
 struct alps_data {
-	struct input_dev *dev2;		/* Relative device */
-	char phys[32];			/* Phys */
-	const struct alps_model_info *i;/* Info */
+	struct input_dev *dev2;
+	char phys[32];
+
+	/* these are autodetected when the device is identified */
 	const struct alps_nibble_commands *nibble_commands;
-	int addr_command;		/* Command to set register address */
-	int prev_fin;			/* Finger bit from previous packet */
-	int multi_packet;		/* Multi-packet data in progress */
-	unsigned char multi_data[6];	/* Saved multi-packet data */
-	int x1, x2, y1, y2;		/* Coordinates from last MT report */
-	int fingers;			/* Number of fingers from MT report */
+	int addr_command;
+	unsigned char proto_version;
+	unsigned char byte0, mask0;
+	unsigned char flags;
+	int x_max;
+	int y_max;
+	int x_bits;
+	int y_bits;
+
+	int (*hw_init)(struct psmouse *psmouse);
+	void (*process_packet)(struct psmouse *psmouse);
+	void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
+
+	int prev_fin;
+	int multi_packet;
+	unsigned char multi_data[6];
+	int x1, x2, y1, y2;
+	int fingers;
 	u8 quirks;
 	struct timer_list timer;
 };
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
new file mode 100644
index 0000000..b409c3d
--- /dev/null
+++ b/drivers/input/mouse/cyapa.c
@@ -0,0 +1,973 @@
+/*
+ * Cypress APA trackpad with I2C interface
+ *
+ * Author: Dudley Du <dudl@cypress.com>
+ * Further cleanup and restructuring by:
+ *   Daniel Kurtz <djkurtz@chromium.org>
+ *   Benson Leung <bleung@chromium.org>
+ *
+ * Copyright (C) 2011-2012 Cypress Semiconductor, Inc.
+ * Copyright (C) 2011-2012 Google, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/* APA trackpad firmware generation */
+#define CYAPA_GEN3   0x03   /* support MT-protocol B with tracking ID. */
+
+#define CYAPA_NAME   "Cypress APA Trackpad (cyapa)"
+
+/* commands for read/write registers of Cypress trackpad */
+#define CYAPA_CMD_SOFT_RESET       0x00
+#define CYAPA_CMD_POWER_MODE       0x01
+#define CYAPA_CMD_DEV_STATUS       0x02
+#define CYAPA_CMD_GROUP_DATA       0x03
+#define CYAPA_CMD_GROUP_CMD        0x04
+#define CYAPA_CMD_GROUP_QUERY      0x05
+#define CYAPA_CMD_BL_STATUS        0x06
+#define CYAPA_CMD_BL_HEAD          0x07
+#define CYAPA_CMD_BL_CMD           0x08
+#define CYAPA_CMD_BL_DATA          0x09
+#define CYAPA_CMD_BL_ALL           0x0a
+#define CYAPA_CMD_BLK_PRODUCT_ID   0x0b
+#define CYAPA_CMD_BLK_HEAD         0x0c
+
+/* report data start reg offset address. */
+#define DATA_REG_START_OFFSET  0x0000
+
+#define BL_HEAD_OFFSET 0x00
+#define BL_DATA_OFFSET 0x10
+
+/*
+ * Operational Device Status Register
+ *
+ * bit 7: Valid interrupt source
+ * bit 6 - 4: Reserved
+ * bit 3 - 2: Power status
+ * bit 1 - 0: Device status
+ */
+#define REG_OP_STATUS     0x00
+#define OP_STATUS_SRC     0x80
+#define OP_STATUS_POWER   0x0c
+#define OP_STATUS_DEV     0x03
+#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
+
+/*
+ * Operational Finger Count/Button Flags Register
+ *
+ * bit 7 - 4: Number of touched finger
+ * bit 3: Valid data
+ * bit 2: Middle Physical Button
+ * bit 1: Right Physical Button
+ * bit 0: Left physical Button
+ */
+#define REG_OP_DATA1       0x01
+#define OP_DATA_VALID      0x08
+#define OP_DATA_MIDDLE_BTN 0x04
+#define OP_DATA_RIGHT_BTN  0x02
+#define OP_DATA_LEFT_BTN   0x01
+#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
+			  OP_DATA_LEFT_BTN)
+
+/*
+ * Bootloader Status Register
+ *
+ * bit 7: Busy
+ * bit 6 - 5: Reserved
+ * bit 4: Bootloader running
+ * bit 3 - 1: Reserved
+ * bit 0: Checksum valid
+ */
+#define REG_BL_STATUS        0x01
+#define BL_STATUS_BUSY       0x80
+#define BL_STATUS_RUNNING    0x10
+#define BL_STATUS_DATA_VALID 0x08
+#define BL_STATUS_CSUM_VALID 0x01
+
+/*
+ * Bootloader Error Register
+ *
+ * bit 7: Invalid
+ * bit 6: Invalid security key
+ * bit 5: Bootloading
+ * bit 4: Command checksum
+ * bit 3: Flash protection error
+ * bit 2: Flash checksum error
+ * bit 1 - 0: Reserved
+ */
+#define REG_BL_ERROR         0x02
+#define BL_ERROR_INVALID     0x80
+#define BL_ERROR_INVALID_KEY 0x40
+#define BL_ERROR_BOOTLOADING 0x20
+#define BL_ERROR_CMD_CSUM    0x10
+#define BL_ERROR_FLASH_PROT  0x08
+#define BL_ERROR_FLASH_CSUM  0x04
+
+#define BL_STATUS_SIZE  3  /* length of bootloader status registers */
+#define BLK_HEAD_BYTES 32
+
+#define PRODUCT_ID_SIZE  16
+#define QUERY_DATA_SIZE  27
+#define REG_PROTOCOL_GEN_QUERY_OFFSET  20
+
+#define REG_OFFSET_DATA_BASE     0x0000
+#define REG_OFFSET_COMMAND_BASE  0x0028
+#define REG_OFFSET_QUERY_BASE    0x002a
+
+#define CAPABILITY_LEFT_BTN_MASK	(0x01 << 3)
+#define CAPABILITY_RIGHT_BTN_MASK	(0x01 << 4)
+#define CAPABILITY_MIDDLE_BTN_MASK	(0x01 << 5)
+#define CAPABILITY_BTN_MASK  (CAPABILITY_LEFT_BTN_MASK | \
+			      CAPABILITY_RIGHT_BTN_MASK | \
+			      CAPABILITY_MIDDLE_BTN_MASK)
+
+#define CYAPA_OFFSET_SOFT_RESET  REG_OFFSET_COMMAND_BASE
+
+#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1)
+
+#define PWR_MODE_MASK   0xfc
+#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
+#define PWR_MODE_IDLE        (0x05 << 2) /* default sleep time is 50 ms. */
+#define PWR_MODE_OFF         (0x00 << 2)
+
+#define PWR_STATUS_MASK      0x0c
+#define PWR_STATUS_ACTIVE    (0x03 << 2)
+#define PWR_STATUS_IDLE      (0x02 << 2)
+#define PWR_STATUS_OFF       (0x00 << 2)
+
+/*
+ * CYAPA trackpad device states.
+ * Used in register 0x00, bit1-0, DeviceStatus field.
+ * Other values indicate device is in an abnormal state and must be reset.
+ */
+#define CYAPA_DEV_NORMAL  0x03
+#define CYAPA_DEV_BUSY    0x01
+
+enum cyapa_state {
+	CYAPA_STATE_OP,
+	CYAPA_STATE_BL_IDLE,
+	CYAPA_STATE_BL_ACTIVE,
+	CYAPA_STATE_BL_BUSY,
+	CYAPA_STATE_NO_DEVICE,
+};
+
+
+struct cyapa_touch {
+	/*
+	 * high bits or x/y position value
+	 * bit 7 - 4: high 4 bits of x position value
+	 * bit 3 - 0: high 4 bits of y position value
+	 */
+	u8 xy_hi;
+	u8 x_lo;  /* low 8 bits of x position value. */
+	u8 y_lo;  /* low 8 bits of y position value. */
+	u8 pressure;
+	/* id range is 1 - 15.  It is incremented with every new touch. */
+	u8 id;
+} __packed;
+
+/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
+#define CYAPA_MAX_MT_SLOTS  15
+
+struct cyapa_reg_data {
+	/*
+	 * bit 0 - 1: device status
+	 * bit 3 - 2: power mode
+	 * bit 6 - 4: reserved
+	 * bit 7: interrupt valid bit
+	 */
+	u8 device_status;
+	/*
+	 * bit 7 - 4: number of fingers currently touching pad
+	 * bit 3: valid data check bit
+	 * bit 2: middle mechanism button state if exists
+	 * bit 1: right mechanism button state if exists
+	 * bit 0: left mechanism button state if exists
+	 */
+	u8 finger_btn;
+	/* CYAPA reports up to 5 touches per packet. */
+	struct cyapa_touch touches[5];
+} __packed;
+
+/* The main device structure */
+struct cyapa {
+	enum cyapa_state state;
+
+	struct i2c_client *client;
+	struct input_dev *input;
+	char phys[32];	/* device physical location */
+	int irq;
+	bool irq_wake;  /* irq wake is enabled */
+	bool smbus;
+
+	/* read from query data region. */
+	char product_id[16];
+	u8 btn_capability;
+	u8 gen;
+	int max_abs_x;
+	int max_abs_y;
+	int physical_size_x;
+	int physical_size_y;
+};
+
+static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03,
+		0x04, 0x05, 0x06, 0x07 };
+static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
+		0x05, 0x06, 0x07 };
+
+struct cyapa_cmd_len {
+	u8 cmd;
+	u8 len;
+};
+
+#define CYAPA_ADAPTER_FUNC_NONE   0
+#define CYAPA_ADAPTER_FUNC_I2C    1
+#define CYAPA_ADAPTER_FUNC_SMBUS  2
+#define CYAPA_ADAPTER_FUNC_BOTH   3
+
+/*
+ * macros for SMBus communication
+ */
+#define SMBUS_READ   0x01
+#define SMBUS_WRITE 0x00
+#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
+#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
+#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
+#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
+
+ /* for byte read/write command */
+#define CMD_RESET 0
+#define CMD_POWER_MODE 1
+#define CMD_DEV_STATUS 2
+#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
+#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
+#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
+#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
+
+ /* for group registers read/write command */
+#define REG_GROUP_DATA 0
+#define REG_GROUP_CMD 2
+#define REG_GROUP_QUERY 3
+#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
+#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
+#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
+#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
+
+ /* for register block read/write command */
+#define CMD_BL_STATUS 0
+#define CMD_BL_HEAD 1
+#define CMD_BL_CMD 2
+#define CMD_BL_DATA 3
+#define CMD_BL_ALL 4
+#define CMD_BLK_PRODUCT_ID 5
+#define CMD_BLK_HEAD 6
+#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
+
+/* register block read/write command in bootloader mode */
+#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
+#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
+#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
+#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
+#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
+
+/* register block read/write command in operational mode */
+#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
+#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
+
+static const struct cyapa_cmd_len cyapa_i2c_cmds[] = {
+	{ CYAPA_OFFSET_SOFT_RESET, 1 },
+	{ REG_OFFSET_COMMAND_BASE + 1, 1 },
+	{ REG_OFFSET_DATA_BASE, 1 },
+	{ REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) },
+	{ REG_OFFSET_COMMAND_BASE, 0 },
+	{ REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE },
+	{ BL_HEAD_OFFSET, 3 },
+	{ BL_HEAD_OFFSET, 16 },
+	{ BL_HEAD_OFFSET, 16 },
+	{ BL_DATA_OFFSET, 16 },
+	{ BL_HEAD_OFFSET, 32 },
+	{ REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE },
+	{ REG_OFFSET_DATA_BASE, 32 }
+};
+
+static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
+	{ CYAPA_SMBUS_RESET, 1 },
+	{ CYAPA_SMBUS_POWER_MODE, 1 },
+	{ CYAPA_SMBUS_DEV_STATUS, 1 },
+	{ CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) },
+	{ CYAPA_SMBUS_GROUP_CMD, 2 },
+	{ CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE },
+	{ CYAPA_SMBUS_BL_STATUS, 3 },
+	{ CYAPA_SMBUS_BL_HEAD, 16 },
+	{ CYAPA_SMBUS_BL_CMD, 16 },
+	{ CYAPA_SMBUS_BL_DATA, 16 },
+	{ CYAPA_SMBUS_BL_ALL, 32 },
+	{ CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE },
+	{ CYAPA_SMBUS_BLK_HEAD, 16 },
+};
+
+static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
+					u8 *values)
+{
+	return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values);
+}
+
+static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
+					 size_t len, const u8 *values)
+{
+	return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values);
+}
+
+/*
+ * cyapa_smbus_read_block - perform smbus block read command
+ * @cyapa  - private data structure of the driver
+ * @cmd    - the properly encoded smbus command
+ * @len    - expected length of smbus command result
+ * @values - buffer to store smbus command result
+ *
+ * Returns negative errno, else the number of bytes written.
+ *
+ * Note:
+ * In trackpad device, the memory block allocated for I2C register map
+ * is 256 bytes, so the max read block for I2C bus is 256 bytes.
+ */
+static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
+				      u8 *values)
+{
+	ssize_t ret;
+	u8 index;
+	u8 smbus_cmd;
+	u8 *buf;
+	struct i2c_client *client = cyapa->client;
+
+	if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd))
+		return -EINVAL;
+
+	if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) {
+		/* read specific block registers command. */
+		smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
+		ret = i2c_smbus_read_block_data(client, smbus_cmd, values);
+		goto out;
+	}
+
+	ret = 0;
+	for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
+		smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
+		smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
+		buf = values + I2C_SMBUS_BLOCK_MAX * index;
+		ret = i2c_smbus_read_block_data(client, smbus_cmd, buf);
+		if (ret < 0)
+			goto out;
+	}
+
+out:
+	return ret > 0 ? len : ret;
+}
+
+static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx)
+{
+	u8 cmd;
+
+	if (cyapa->smbus) {
+		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+		cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
+	} else {
+		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+	}
+	return i2c_smbus_read_byte_data(cyapa->client, cmd);
+}
+
+static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value)
+{
+	u8 cmd;
+
+	if (cyapa->smbus) {
+		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+		cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE);
+	} else {
+		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+	}
+	return i2c_smbus_write_byte_data(cyapa->client, cmd, value);
+}
+
+static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
+{
+	u8 cmd;
+	size_t len;
+
+	if (cyapa->smbus) {
+		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+		len = cyapa_smbus_cmds[cmd_idx].len;
+		return cyapa_smbus_read_block(cyapa, cmd, len, values);
+	} else {
+		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+		len = cyapa_i2c_cmds[cmd_idx].len;
+		return cyapa_i2c_reg_read_block(cyapa, cmd, len, values);
+	}
+}
+
+/*
+ * Query device for its current operating state.
+ *
+ */
+static int cyapa_get_state(struct cyapa *cyapa)
+{
+	int ret;
+	u8 status[BL_STATUS_SIZE];
+
+	cyapa->state = CYAPA_STATE_NO_DEVICE;
+
+	/*
+	 * Get trackpad status by reading 3 registers starting from 0.
+	 * If the device is in the bootloader, this will be BL_HEAD.
+	 * If the device is in operation mode, this will be the DATA regs.
+	 *
+	 */
+	ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
+				       status);
+
+	/*
+	 * On smbus systems in OP mode, the i2c_reg_read will fail with
+	 * -ETIMEDOUT.  In this case, try again using the smbus equivalent
+	 * command.  This should return a BL_HEAD indicating CYAPA_STATE_OP.
+	 */
+	if (cyapa->smbus && (ret == -ETIMEDOUT || ret == -ENXIO))
+		ret = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status);
+
+	if (ret != BL_STATUS_SIZE)
+		goto error;
+
+	if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) {
+		switch (status[REG_OP_STATUS] & OP_STATUS_DEV) {
+		case CYAPA_DEV_NORMAL:
+		case CYAPA_DEV_BUSY:
+			cyapa->state = CYAPA_STATE_OP;
+			break;
+		default:
+			ret = -EAGAIN;
+			goto error;
+		}
+	} else {
+		if (status[REG_BL_STATUS] & BL_STATUS_BUSY)
+			cyapa->state = CYAPA_STATE_BL_BUSY;
+		else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING)
+			cyapa->state = CYAPA_STATE_BL_ACTIVE;
+		else
+			cyapa->state = CYAPA_STATE_BL_IDLE;
+	}
+
+	return 0;
+error:
+	return (ret < 0) ? ret : -EAGAIN;
+}
+
+/*
+ * Poll device for its status in a loop, waiting up to timeout for a response.
+ *
+ * When the device switches state, it usually takes ~300 ms.
+ * However, when running a new firmware image, the device must calibrate its
+ * sensors, which can take as long as 2 seconds.
+ *
+ * Note: The timeout has granularity of the polling rate, which is 100 ms.
+ *
+ * Returns:
+ *   0 when the device eventually responds with a valid non-busy state.
+ *   -ETIMEDOUT if device never responds (too many -EAGAIN)
+ *   < 0    other errors
+ */
+static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
+{
+	int ret;
+	int tries = timeout / 100;
+
+	ret = cyapa_get_state(cyapa);
+	while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
+		msleep(100);
+		ret = cyapa_get_state(cyapa);
+	}
+	return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret;
+}
+
+static int cyapa_bl_deactivate(struct cyapa *cyapa)
+{
+	int ret;
+
+	ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
+					bl_deactivate);
+	if (ret < 0)
+		return ret;
+
+	/* wait for bootloader to switch to idle state; should take < 100ms */
+	msleep(100);
+	ret = cyapa_poll_state(cyapa, 500);
+	if (ret < 0)
+		return ret;
+	if (cyapa->state != CYAPA_STATE_BL_IDLE)
+		return -EAGAIN;
+	return 0;
+}
+
+/*
+ * Exit bootloader
+ *
+ * Send bl_exit command, then wait 50 - 100 ms to let device transition to
+ * operational mode.  If this is the first time the device's firmware is
+ * running, it can take up to 2 seconds to calibrate its sensors.  So, poll
+ * the device's new state for up to 2 seconds.
+ *
+ * Returns:
+ *   -EIO    failure while reading from device
+ *   -EAGAIN device is stuck in bootloader, b/c it has invalid firmware
+ *   0       device is supported and in operational mode
+ */
+static int cyapa_bl_exit(struct cyapa *cyapa)
+{
+	int ret;
+
+	ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Wait for bootloader to exit, and operation mode to start.
+	 * Normally, this takes at least 50 ms.
+	 */
+	usleep_range(50000, 100000);
+	/*
+	 * In addition, when a device boots for the first time after being
+	 * updated to new firmware, it must first calibrate its sensors, which
+	 * can take up to an additional 2 seconds.
+	 */
+	ret = cyapa_poll_state(cyapa, 2000);
+	if (ret < 0)
+		return ret;
+	if (cyapa->state != CYAPA_STATE_OP)
+		return -EAGAIN;
+
+	return 0;
+}
+
+/*
+ * Set device power mode
+ *
+ */
+static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
+{
+	struct device *dev = &cyapa->client->dev;
+	int ret;
+	u8 power;
+
+	if (cyapa->state != CYAPA_STATE_OP)
+		return 0;
+
+	ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE);
+	if (ret < 0)
+		return ret;
+
+	power = ret & ~PWR_MODE_MASK;
+	power |= power_mode & PWR_MODE_MASK;
+	ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
+	if (ret < 0)
+		dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
+			power_mode, ret);
+	return ret;
+}
+
+static int cyapa_get_query_data(struct cyapa *cyapa)
+{
+	u8 query_data[QUERY_DATA_SIZE];
+	int ret;
+
+	if (cyapa->state != CYAPA_STATE_OP)
+		return -EBUSY;
+
+	ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data);
+	if (ret < 0)
+		return ret;
+	if (ret != QUERY_DATA_SIZE)
+		return -EIO;
+
+	memcpy(&cyapa->product_id[0], &query_data[0], 5);
+	cyapa->product_id[5] = '-';
+	memcpy(&cyapa->product_id[6], &query_data[5], 6);
+	cyapa->product_id[12] = '-';
+	memcpy(&cyapa->product_id[13], &query_data[11], 2);
+	cyapa->product_id[15] = '\0';
+
+	cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK;
+
+	cyapa->gen = query_data[20] & 0x0f;
+
+	cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22];
+	cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23];
+
+	cyapa->physical_size_x =
+		((query_data[24] & 0xf0) << 4) | query_data[25];
+	cyapa->physical_size_y =
+		((query_data[24] & 0x0f) << 8) | query_data[26];
+
+	return 0;
+}
+
+/*
+ * Check if device is operational.
+ *
+ * An operational device is responding, has exited bootloader, and has
+ * firmware supported by this driver.
+ *
+ * Returns:
+ *   -EBUSY  no device or in bootloader
+ *   -EIO    failure while reading from device
+ *   -EAGAIN device is still in bootloader
+ *           if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
+ *   -EINVAL device is in operational mode, but not supported by this driver
+ *   0       device is supported
+ */
+static int cyapa_check_is_operational(struct cyapa *cyapa)
+{
+	struct device *dev = &cyapa->client->dev;
+	static const char unique_str[] = "CYTRA";
+	int ret;
+
+	ret = cyapa_poll_state(cyapa, 2000);
+	if (ret < 0)
+		return ret;
+	switch (cyapa->state) {
+	case CYAPA_STATE_BL_ACTIVE:
+		ret = cyapa_bl_deactivate(cyapa);
+		if (ret)
+			return ret;
+
+	/* Fallthrough state */
+	case CYAPA_STATE_BL_IDLE:
+		ret = cyapa_bl_exit(cyapa);
+		if (ret)
+			return ret;
+
+	/* Fallthrough state */
+	case CYAPA_STATE_OP:
+		ret = cyapa_get_query_data(cyapa);
+		if (ret < 0)
+			return ret;
+
+		/* only support firmware protocol gen3 */
+		if (cyapa->gen != CYAPA_GEN3) {
+			dev_err(dev, "unsupported protocol version (%d)",
+				cyapa->gen);
+			return -EINVAL;
+		}
+
+		/* only support product ID starting with CYTRA */
+		if (memcmp(cyapa->product_id, unique_str,
+			   sizeof(unique_str) - 1) != 0) {
+			dev_err(dev, "unsupported product ID (%s)\n",
+				cyapa->product_id);
+			return -EINVAL;
+		}
+		return 0;
+
+	default:
+		return -EIO;
+	}
+	return 0;
+}
+
+static irqreturn_t cyapa_irq(int irq, void *dev_id)
+{
+	struct cyapa *cyapa = dev_id;
+	struct device *dev = &cyapa->client->dev;
+	struct input_dev *input = cyapa->input;
+	struct cyapa_reg_data data;
+	int i;
+	int ret;
+	int num_fingers;
+
+	if (device_may_wakeup(dev))
+		pm_wakeup_event(dev, 0);
+
+	ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
+	if (ret != sizeof(data))
+		goto out;
+
+	if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
+	    (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
+	    (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
+		goto out;
+	}
+
+	num_fingers = (data.finger_btn >> 4) & 0x0f;
+	for (i = 0; i < num_fingers; i++) {
+		const struct cyapa_touch *touch = &data.touches[i];
+		/* Note: touch->id range is 1 to 15; slots are 0 to 14. */
+		int slot = touch->id - 1;
+
+		input_mt_slot(input, slot);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+		input_report_abs(input, ABS_MT_POSITION_X,
+				 ((touch->xy_hi & 0xf0) << 4) | touch->x_lo);
+		input_report_abs(input, ABS_MT_POSITION_Y,
+				 ((touch->xy_hi & 0x0f) << 8) | touch->y_lo);
+		input_report_abs(input, ABS_MT_PRESSURE, touch->pressure);
+	}
+
+	input_mt_sync_frame(input);
+
+	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
+		input_report_key(input, BTN_LEFT,
+				 data.finger_btn & OP_DATA_LEFT_BTN);
+
+	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
+		input_report_key(input, BTN_MIDDLE,
+				 data.finger_btn & OP_DATA_MIDDLE_BTN);
+
+	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
+		input_report_key(input, BTN_RIGHT,
+				 data.finger_btn & OP_DATA_RIGHT_BTN);
+
+	input_sync(input);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
+{
+	u8 ret = CYAPA_ADAPTER_FUNC_NONE;
+
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		ret |= CYAPA_ADAPTER_FUNC_I2C;
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_BLOCK_DATA |
+				     I2C_FUNC_SMBUS_I2C_BLOCK))
+		ret |= CYAPA_ADAPTER_FUNC_SMBUS;
+	return ret;
+}
+
+static int cyapa_create_input_dev(struct cyapa *cyapa)
+{
+	struct device *dev = &cyapa->client->dev;
+	int ret;
+	struct input_dev *input;
+
+	if (!cyapa->physical_size_x || !cyapa->physical_size_y)
+		return -EINVAL;
+
+	input = cyapa->input = input_allocate_device();
+	if (!input) {
+		dev_err(dev, "allocate memory for input device failed\n");
+		return -ENOMEM;
+	}
+
+	input->name = CYAPA_NAME;
+	input->phys = cyapa->phys;
+	input->id.bustype = BUS_I2C;
+	input->id.version = 1;
+	input->id.product = 0;  /* means any product in eventcomm. */
+	input->dev.parent = &cyapa->client->dev;
+
+	input_set_drvdata(input, cyapa);
+
+	__set_bit(EV_ABS, input->evbit);
+
+	/* finger position */
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
+			     0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
+			     0);
+	input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+	input_abs_set_res(input, ABS_MT_POSITION_X,
+			  cyapa->max_abs_x / cyapa->physical_size_x);
+	input_abs_set_res(input, ABS_MT_POSITION_Y,
+			  cyapa->max_abs_y / cyapa->physical_size_y);
+
+	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
+		__set_bit(BTN_LEFT, input->keybit);
+	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
+		__set_bit(BTN_MIDDLE, input->keybit);
+	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
+		__set_bit(BTN_RIGHT, input->keybit);
+
+	if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
+		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+	/* handle pointer emulation and unused slots in core */
+	ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
+				  INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
+	if (ret) {
+		dev_err(dev, "allocate memory for MT slots failed, %d\n", ret);
+		goto err_free_device;
+	}
+
+	/* Register the device in input subsystem */
+	ret = input_register_device(input);
+	if (ret) {
+		dev_err(dev, "input device register failed, %d\n", ret);
+		goto err_free_device;
+	}
+	return 0;
+
+err_free_device:
+	input_free_device(input);
+	cyapa->input = NULL;
+	return ret;
+}
+
+static int cyapa_probe(struct i2c_client *client,
+		       const struct i2c_device_id *dev_id)
+{
+	int ret;
+	u8 adapter_func;
+	struct cyapa *cyapa;
+	struct device *dev = &client->dev;
+
+	adapter_func = cyapa_check_adapter_functionality(client);
+	if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
+		dev_err(dev, "not a supported I2C/SMBus adapter\n");
+		return -EIO;
+	}
+
+	cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL);
+	if (!cyapa) {
+		dev_err(dev, "allocate memory for cyapa failed\n");
+		return -ENOMEM;
+	}
+
+	cyapa->gen = CYAPA_GEN3;
+	cyapa->client = client;
+	i2c_set_clientdata(client, cyapa);
+	sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
+		client->addr);
+
+	/* i2c isn't supported, use smbus */
+	if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
+		cyapa->smbus = true;
+	cyapa->state = CYAPA_STATE_NO_DEVICE;
+	ret = cyapa_check_is_operational(cyapa);
+	if (ret) {
+		dev_err(dev, "device not operational, %d\n", ret);
+		goto err_mem_free;
+	}
+
+	ret = cyapa_create_input_dev(cyapa);
+	if (ret) {
+		dev_err(dev, "create input_dev instance failed, %d\n", ret);
+		goto err_mem_free;
+	}
+
+	ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
+	if (ret) {
+		dev_err(dev, "set active power failed, %d\n", ret);
+		goto err_unregister_device;
+	}
+
+	cyapa->irq = client->irq;
+	ret = request_threaded_irq(cyapa->irq,
+				   NULL,
+				   cyapa_irq,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   "cyapa",
+				   cyapa);
+	if (ret) {
+		dev_err(dev, "IRQ request failed: %d\n, ", ret);
+		goto err_unregister_device;
+	}
+
+	return 0;
+
+err_unregister_device:
+	input_unregister_device(cyapa->input);
+err_mem_free:
+	kfree(cyapa);
+
+	return ret;
+}
+
+static int cyapa_remove(struct i2c_client *client)
+{
+	struct cyapa *cyapa = i2c_get_clientdata(client);
+
+	free_irq(cyapa->irq, cyapa);
+	input_unregister_device(cyapa->input);
+	cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
+	kfree(cyapa);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cyapa_suspend(struct device *dev)
+{
+	int ret;
+	u8 power_mode;
+	struct cyapa *cyapa = dev_get_drvdata(dev);
+
+	disable_irq(cyapa->irq);
+
+	/*
+	 * Set trackpad device to idle mode if wakeup is allowed,
+	 * otherwise turn off.
+	 */
+	power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE
+					    : PWR_MODE_OFF;
+	ret = cyapa_set_power_mode(cyapa, power_mode);
+	if (ret < 0)
+		dev_err(dev, "set power mode failed, %d\n", ret);
+
+	if (device_may_wakeup(dev))
+		cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0);
+	return 0;
+}
+
+static int cyapa_resume(struct device *dev)
+{
+	int ret;
+	struct cyapa *cyapa = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev) && cyapa->irq_wake)
+		disable_irq_wake(cyapa->irq);
+
+	ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
+	if (ret)
+		dev_warn(dev, "resume active power failed, %d\n", ret);
+
+	enable_irq(cyapa->irq);
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume);
+
+static const struct i2c_device_id cyapa_id_table[] = {
+	{ "cyapa", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+
+static struct i2c_driver cyapa_driver = {
+	.driver = {
+		.name = "cyapa",
+		.owner = THIS_MODULE,
+		.pm = &cyapa_pm_ops,
+	},
+
+	.probe = cyapa_probe,
+	.remove = cyapa_remove,
+	.id_table = cyapa_id_table,
+};
+
+module_i2c_driver(cyapa_driver);
+
+MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver");
+MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
new file mode 100644
index 0000000..1673dc6
--- /dev/null
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -0,0 +1,725 @@
+/*
+ * Cypress Trackpad PS/2 mouse driver
+ *
+ * Copyright (c) 2012 Cypress Semiconductor Corporation.
+ *
+ * Author:
+ *   Dudley Du <dudl@cypress.com>
+ *
+ * Additional contributors include:
+ *   Kamal Mostafa <kamal@canonical.com>
+ *   Kyle Fazzari <git@status.e4ward.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "cypress_ps2.h"
+
+#undef CYTP_DEBUG_VERBOSE  /* define this and DEBUG for more verbose dump */
+
+static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
+{
+	struct cytp_data *cytp = psmouse->private;
+	cytp->pkt_size = n;
+}
+
+static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
+static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
+
+static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+	if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
+		psmouse_dbg(psmouse,
+				"sending command 0x%02x failed, resp 0x%02x\n",
+				value & 0xff, ps2dev->nak);
+		if (ps2dev->nak == CYTP_PS2_RETRY)
+			return CYTP_PS2_RETRY;
+		else
+			return CYTP_PS2_ERROR;
+	}
+
+#ifdef CYTP_DEBUG_VERBOSE
+	psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
+			value & 0xff);
+#endif
+
+	return 0;
+}
+
+static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
+			       unsigned char data)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int tries = CYTP_PS2_CMD_TRIES;
+	int rc;
+
+	ps2_begin_command(ps2dev);
+
+	do {
+		/*
+		 * Send extension command byte (0xE8 or 0xF3).
+		 * If sending the command fails, send recovery command
+		 * to make the device return to the ready state.
+		 */
+		rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
+		if (rc == CYTP_PS2_RETRY) {
+			rc = cypress_ps2_sendbyte(psmouse, 0x00);
+			if (rc == CYTP_PS2_RETRY)
+				rc = cypress_ps2_sendbyte(psmouse, 0x0a);
+		}
+		if (rc == CYTP_PS2_ERROR)
+			continue;
+
+		rc = cypress_ps2_sendbyte(psmouse, data);
+		if (rc == CYTP_PS2_RETRY)
+			rc = cypress_ps2_sendbyte(psmouse, data);
+		if (rc == CYTP_PS2_ERROR)
+			continue;
+		else
+			break;
+	} while (--tries > 0);
+
+	ps2_end_command(ps2dev);
+
+	return rc;
+}
+
+static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
+				       unsigned char cmd,
+				       unsigned char *param)
+{
+	int rc;
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	enum psmouse_state old_state;
+	int pktsize;
+
+	ps2_begin_command(&psmouse->ps2dev);
+
+	old_state = psmouse->state;
+	psmouse->state = PSMOUSE_CMD_MODE;
+	psmouse->pktcnt = 0;
+
+	pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
+	memset(param, 0, pktsize);
+
+	rc = cypress_ps2_sendbyte(psmouse, 0xe9);
+	if (rc < 0)
+		goto out;
+
+	wait_event_timeout(ps2dev->wait,
+			(psmouse->pktcnt >= pktsize),
+			msecs_to_jiffies(CYTP_CMD_TIMEOUT));
+
+	memcpy(param, psmouse->packet, pktsize);
+
+	psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
+			cmd, pktsize, param);
+
+out:
+	psmouse->state = old_state;
+	psmouse->pktcnt = 0;
+
+	ps2_end_command(&psmouse->ps2dev);
+
+	return rc;
+}
+
+static bool cypress_verify_cmd_state(struct psmouse *psmouse,
+				     unsigned char cmd, unsigned char *param)
+{
+	bool rate_match = false;
+	bool resolution_match = false;
+	int i;
+
+	/* callers will do further checking. */
+	if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
+	    cmd == CYTP_CMD_STANDARD_MODE ||
+	    cmd == CYTP_CMD_READ_TP_METRICS)
+		return true;
+
+	if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
+	    (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
+		for (i = 0; i < sizeof(cytp_resolution); i++)
+			if (cytp_resolution[i] == param[1])
+				resolution_match = true;
+
+		for (i = 0; i < sizeof(cytp_rate); i++)
+			if (cytp_rate[i] == param[2])
+				rate_match = true;
+
+		if (resolution_match && rate_match)
+			return true;
+	}
+
+	psmouse_dbg(psmouse, "verify cmd state failed.\n");
+	return false;
+}
+
+static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
+				unsigned char *param)
+{
+	int tries = CYTP_PS2_CMD_TRIES;
+	int rc;
+
+	psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
+		 cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
+		 DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
+
+	do {
+		cypress_ps2_ext_cmd(psmouse,
+				    PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
+		cypress_ps2_ext_cmd(psmouse,
+				    PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
+		cypress_ps2_ext_cmd(psmouse,
+				    PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
+		cypress_ps2_ext_cmd(psmouse,
+				    PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
+
+		rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
+		if (rc)
+			continue;
+
+		if (cypress_verify_cmd_state(psmouse, cmd, param))
+			return 0;
+
+	} while (--tries > 0);
+
+	return -EIO;
+}
+
+int cypress_detect(struct psmouse *psmouse, bool set_properties)
+{
+	unsigned char param[3];
+
+	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
+		return -ENODEV;
+
+	/* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
+	if (param[0] != 0x33 || param[1] != 0xCC)
+		return -ENODEV;
+
+	if (set_properties) {
+		psmouse->vendor = "Cypress";
+		psmouse->name = "Trackpad";
+	}
+
+	return 0;
+}
+
+static int cypress_read_fw_version(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp = psmouse->private;
+	unsigned char param[3];
+
+	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
+		return -ENODEV;
+
+	/* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
+	if (param[0] != 0x33 || param[1] != 0xCC)
+		return -ENODEV;
+
+	cytp->fw_version = param[2] & FW_VERSION_MASX;
+	cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0;
+
+	psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version);
+	psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n",
+		 cytp->tp_metrics_supported);
+
+	return 0;
+}
+
+static int cypress_read_tp_metrics(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp = psmouse->private;
+	unsigned char param[8];
+
+	/* set default values for tp metrics. */
+	cytp->tp_width = CYTP_DEFAULT_WIDTH;
+	cytp->tp_high = CYTP_DEFAULT_HIGH;
+	cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
+	cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
+	cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
+	cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
+	cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
+	cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
+
+	memset(param, 0, sizeof(param));
+	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
+		/* Update trackpad parameters. */
+		cytp->tp_max_abs_x = (param[1] << 8) | param[0];
+		cytp->tp_max_abs_y = (param[3] << 8) | param[2];
+		cytp->tp_min_pressure = param[4];
+		cytp->tp_max_pressure = param[5];
+	}
+
+	if (!cytp->tp_max_pressure ||
+	    cytp->tp_max_pressure < cytp->tp_min_pressure ||
+	    !cytp->tp_width || !cytp->tp_high ||
+	    !cytp->tp_max_abs_x ||
+	    cytp->tp_max_abs_x < cytp->tp_width ||
+	    !cytp->tp_max_abs_y ||
+	    cytp->tp_max_abs_y < cytp->tp_high)
+		return -EINVAL;
+
+	cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
+	cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
+
+#ifdef CYTP_DEBUG_VERBOSE
+	psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n");
+	psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width);
+	psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high);
+	psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x);
+	psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y);
+	psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure);
+	psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure);
+	psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x);
+	psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y);
+
+	psmouse_dbg(psmouse, "tp_type_APA = %d\n",
+			(param[6] & TP_METRICS_BIT_APA) ? 1 : 0);
+	psmouse_dbg(psmouse, "tp_type_MTG = %d\n",
+			(param[6] & TP_METRICS_BIT_MTG) ? 1 : 0);
+	psmouse_dbg(psmouse, "tp_palm = %d\n",
+			(param[6] & TP_METRICS_BIT_PALM) ? 1 : 0);
+	psmouse_dbg(psmouse, "tp_stubborn = %d\n",
+			(param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0);
+	psmouse_dbg(psmouse, "tp_1f_jitter = %d\n",
+			(param[6] & TP_METRICS_BIT_1F_JITTER) >> 2);
+	psmouse_dbg(psmouse, "tp_2f_jitter = %d\n",
+			(param[6] & TP_METRICS_BIT_2F_JITTER) >> 4);
+	psmouse_dbg(psmouse, "tp_1f_spike = %d\n",
+			param[7] & TP_METRICS_BIT_1F_SPIKE);
+	psmouse_dbg(psmouse, "tp_2f_spike = %d\n",
+			(param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2);
+	psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n",
+			(param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4);
+#endif
+
+	return 0;
+}
+
+static int cypress_query_hardware(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp = psmouse->private;
+	int ret;
+
+	ret = cypress_read_fw_version(psmouse);
+	if (ret)
+		return ret;
+
+	if (cytp->tp_metrics_supported) {
+		ret = cypress_read_tp_metrics(psmouse);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int cypress_set_absolute_mode(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp = psmouse->private;
+	unsigned char param[3];
+
+	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
+		return -1;
+
+	cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
+			| CYTP_BIT_ABS_PRESSURE;
+	cypress_set_packet_size(psmouse, 5);
+
+	return 0;
+}
+
+/*
+ * Reset trackpad device.
+ * This is also the default mode when trackpad powered on.
+ */
+static void cypress_reset(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp = psmouse->private;
+
+	cytp->mode = 0;
+
+	psmouse_reset(psmouse);
+}
+
+static int cypress_set_input_params(struct input_dev *input,
+				    struct cytp_data *cytp)
+{
+	int ret;
+
+	if (!cytp->tp_res_x || !cytp->tp_res_y)
+		return -EINVAL;
+
+	__set_bit(EV_ABS, input->evbit);
+	input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE,
+			     cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
+	input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
+
+	/* finger position */
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
+	input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+	ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
+			INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
+	if (ret < 0)
+		return ret;
+
+	__set_bit(INPUT_PROP_SEMI_MT, input->propbit);
+
+	input_abs_set_res(input, ABS_X, cytp->tp_res_x);
+	input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
+
+	input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
+	input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
+
+	__set_bit(BTN_TOUCH, input->keybit);
+	__set_bit(BTN_TOOL_FINGER, input->keybit);
+	__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+	__set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+	__set_bit(BTN_TOOL_QUADTAP, input->keybit);
+	__set_bit(BTN_TOOL_QUINTTAP, input->keybit);
+
+	__clear_bit(EV_REL, input->evbit);
+	__clear_bit(REL_X, input->relbit);
+	__clear_bit(REL_Y, input->relbit);
+
+	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_LEFT, input->keybit);
+	__set_bit(BTN_RIGHT, input->keybit);
+	__set_bit(BTN_MIDDLE, input->keybit);
+
+	input_set_drvdata(input, cytp);
+
+	return 0;
+}
+
+static int cypress_get_finger_count(unsigned char header_byte)
+{
+	unsigned char bits6_7;
+	int finger_count;
+
+	bits6_7 = header_byte >> 6;
+	finger_count = bits6_7 & 0x03;
+
+	if (finger_count == 1)
+		return 1;
+
+	if (header_byte & ABS_HSCROLL_BIT) {
+		/* HSCROLL gets added on to 0 finger count. */
+		switch (finger_count) {
+			case 0:	return 4;
+			case 2: return 5;
+			default:
+				/* Invalid contact (e.g. palm). Ignore it. */
+				return -1;
+		}
+	}
+
+	return finger_count;
+}
+
+
+static int cypress_parse_packet(struct psmouse *psmouse,
+				struct cytp_data *cytp, struct cytp_report_data *report_data)
+{
+	unsigned char *packet = psmouse->packet;
+	unsigned char header_byte = packet[0];
+	int contact_cnt;
+
+	memset(report_data, 0, sizeof(struct cytp_report_data));
+
+	contact_cnt = cypress_get_finger_count(header_byte);
+
+	if (contact_cnt < 0) /* e.g. palm detect */
+		return -EINVAL;
+
+	report_data->contact_cnt = contact_cnt;
+
+	report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
+
+	if (report_data->contact_cnt == 1) {
+		report_data->contacts[0].x =
+			((packet[1] & 0x70) << 4) | packet[2];
+		report_data->contacts[0].y =
+			((packet[1] & 0x07) << 8) | packet[3];
+		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+			report_data->contacts[0].z = packet[4];
+
+	} else if (report_data->contact_cnt >= 2) {
+		report_data->contacts[0].x =
+			((packet[1] & 0x70) << 4) | packet[2];
+		report_data->contacts[0].y =
+			((packet[1] & 0x07) << 8) | packet[3];
+		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+			report_data->contacts[0].z = packet[4];
+
+		report_data->contacts[1].x =
+			((packet[5] & 0xf0) << 4) | packet[6];
+		report_data->contacts[1].y =
+			((packet[5] & 0x0f) << 8) | packet[7];
+		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+			report_data->contacts[1].z = report_data->contacts[0].z;
+	}
+
+	report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
+	report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0;
+
+	/*
+	 * This is only true if one of the mouse buttons were tapped.  Make
+	 * sure it doesn't turn into a click. The regular tap-to-click
+	 * functionality will handle that on its own. If we don't do this,
+	 * disabling tap-to-click won't affect the mouse button zones.
+	 */
+	if (report_data->tap)
+		report_data->left = 0;
+
+#ifdef CYTP_DEBUG_VERBOSE
+	{
+		int i;
+		int n = report_data->contact_cnt;
+		psmouse_dbg(psmouse, "Dump parsed report data as below:\n");
+		psmouse_dbg(psmouse, "contact_cnt = %d\n",
+			report_data->contact_cnt);
+		if (n > CYTP_MAX_MT_SLOTS)
+		    n = CYTP_MAX_MT_SLOTS;
+		for (i = 0; i < n; i++)
+			psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i,
+					report_data->contacts[i].x,
+					report_data->contacts[i].y,
+					report_data->contacts[i].z);
+		psmouse_dbg(psmouse, "left = %d\n", report_data->left);
+		psmouse_dbg(psmouse, "right = %d\n", report_data->right);
+		psmouse_dbg(psmouse, "middle = %d\n", report_data->middle);
+	}
+#endif
+
+	return 0;
+}
+
+static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
+{
+	int i;
+	struct input_dev *input = psmouse->dev;
+	struct cytp_data *cytp = psmouse->private;
+	struct cytp_report_data report_data;
+	struct cytp_contact *contact;
+	struct input_mt_pos pos[CYTP_MAX_MT_SLOTS];
+	int slots[CYTP_MAX_MT_SLOTS];
+	int n;
+
+	if (cypress_parse_packet(psmouse, cytp, &report_data))
+		return;
+
+	n = report_data.contact_cnt;
+
+	if (n > CYTP_MAX_MT_SLOTS)
+		n = CYTP_MAX_MT_SLOTS;
+
+	for (i = 0; i < n; i++) {
+		contact = &report_data.contacts[i];
+		pos[i].x = contact->x;
+		pos[i].y = contact->y;
+	}
+
+	input_mt_assign_slots(input, slots, pos, n);
+
+	for (i = 0; i < n; i++) {
+		contact = &report_data.contacts[i];
+		input_mt_slot(input, slots[i]);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+		input_report_abs(input, ABS_MT_POSITION_X, contact->x);
+		input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
+		input_report_abs(input, ABS_MT_PRESSURE, contact->z);
+	}
+
+	input_mt_sync_frame(input);
+
+	input_mt_report_finger_count(input, report_data.contact_cnt);
+
+	input_report_key(input, BTN_LEFT, report_data.left);
+	input_report_key(input, BTN_RIGHT, report_data.right);
+	input_report_key(input, BTN_MIDDLE, report_data.middle);
+
+	input_sync(input);
+}
+
+static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
+{
+	int contact_cnt;
+	int index = psmouse->pktcnt - 1;
+	unsigned char *packet = psmouse->packet;
+	struct cytp_data *cytp = psmouse->private;
+
+	if (index < 0 || index > cytp->pkt_size)
+		return PSMOUSE_BAD_DATA;
+
+	if (index == 0 && (packet[0] & 0xfc) == 0) {
+		/* call packet process for reporting finger leave. */
+		cypress_process_packet(psmouse, 1);
+		return PSMOUSE_FULL_PACKET;
+	}
+
+	/*
+	 * Perform validation (and adjust packet size) based only on the
+	 * first byte; allow all further bytes through.
+	 */
+	if (index != 0)
+		return PSMOUSE_GOOD_DATA;
+
+	/*
+	 * If absolute/relative mode bit has not been set yet, just pass
+	 * the byte through.
+	 */
+	if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
+		return PSMOUSE_GOOD_DATA;
+
+	if ((packet[0] & 0x08) == 0x08)
+		return PSMOUSE_BAD_DATA;
+
+	contact_cnt = cypress_get_finger_count(packet[0]);
+
+	if (contact_cnt < 0)
+		return PSMOUSE_BAD_DATA;
+
+	if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
+		cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
+	else
+		cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
+
+	return PSMOUSE_GOOD_DATA;
+}
+
+static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp = psmouse->private;
+
+	if (psmouse->pktcnt >= cytp->pkt_size) {
+		cypress_process_packet(psmouse, 0);
+		return PSMOUSE_FULL_PACKET;
+	}
+
+	return cypress_validate_byte(psmouse);
+}
+
+static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+	struct cytp_data *cytp = psmouse->private;
+
+	if (rate >= 80) {
+		psmouse->rate = 80;
+		cytp->mode |= CYTP_BIT_HIGH_RATE;
+	} else {
+		psmouse->rate = 40;
+		cytp->mode &= ~CYTP_BIT_HIGH_RATE;
+	}
+
+	ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
+		    PSMOUSE_CMD_SETRATE);
+}
+
+static void cypress_disconnect(struct psmouse *psmouse)
+{
+	cypress_reset(psmouse);
+	kfree(psmouse->private);
+	psmouse->private = NULL;
+}
+
+static int cypress_reconnect(struct psmouse *psmouse)
+{
+	int tries = CYTP_PS2_CMD_TRIES;
+	int rc;
+
+	do {
+		cypress_reset(psmouse);
+		rc = cypress_detect(psmouse, false);
+	} while (rc && (--tries > 0));
+
+	if (rc) {
+		psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
+		return -1;
+	}
+
+	if (cypress_set_absolute_mode(psmouse)) {
+		psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int cypress_init(struct psmouse *psmouse)
+{
+	struct cytp_data *cytp;
+
+	cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
+	psmouse->private = (void *)cytp;
+	if (cytp == NULL)
+		return -ENOMEM;
+
+	cypress_reset(psmouse);
+
+	psmouse->pktsize = 8;
+
+	if (cypress_query_hardware(psmouse)) {
+		psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
+		goto err_exit;
+	}
+
+	if (cypress_set_absolute_mode(psmouse)) {
+		psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
+		goto err_exit;
+	}
+
+	if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
+		psmouse_err(psmouse, "init: Unable to set input params.\n");
+		goto err_exit;
+	}
+
+	psmouse->model = 1;
+	psmouse->protocol_handler = cypress_protocol_handler;
+	psmouse->set_rate = cypress_set_rate;
+	psmouse->disconnect = cypress_disconnect;
+	psmouse->reconnect = cypress_reconnect;
+	psmouse->cleanup = cypress_reset;
+	psmouse->resync_time = 0;
+
+	return 0;
+
+err_exit:
+	/*
+	 * Reset Cypress Trackpad as a standard mouse. Then
+	 * let psmouse driver commmunicating with it as default PS2 mouse.
+	 */
+	cypress_reset(psmouse);
+
+	psmouse->private = NULL;
+	kfree(cytp);
+
+	return -1;
+}
+
+bool cypress_supported(void)
+{
+	return true;
+}
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h
new file mode 100644
index 0000000..4720f21
--- /dev/null
+++ b/drivers/input/mouse/cypress_ps2.h
@@ -0,0 +1,191 @@
+#ifndef _CYPRESS_PS2_H
+#define _CYPRESS_PS2_H
+
+#include "psmouse.h"
+
+#define CMD_BITS_MASK 0x03
+#define COMPOSIT(x, s) (((x) & CMD_BITS_MASK) << (s))
+
+#define ENCODE_CMD(aa, bb, cc, dd) \
+	(COMPOSIT((aa), 6) | COMPOSIT((bb), 4) | COMPOSIT((cc), 2) | COMPOSIT((dd), 0))
+#define CYTP_CMD_ABS_NO_PRESSURE_MODE       ENCODE_CMD(0, 1, 0, 0)
+#define CYTP_CMD_ABS_WITH_PRESSURE_MODE     ENCODE_CMD(0, 1, 0, 1)
+#define CYTP_CMD_SMBUS_MODE                 ENCODE_CMD(0, 1, 1, 0)
+#define CYTP_CMD_STANDARD_MODE              ENCODE_CMD(0, 2, 0, 0)  /* not implemented yet. */
+#define CYTP_CMD_CYPRESS_REL_MODE           ENCODE_CMD(1, 1, 1, 1)  /* not implemented yet. */
+#define CYTP_CMD_READ_CYPRESS_ID            ENCODE_CMD(0, 0, 0, 0)
+#define CYTP_CMD_READ_TP_METRICS            ENCODE_CMD(0, 0, 0, 1)
+#define CYTP_CMD_SET_HSCROLL_WIDTH(w)       ENCODE_CMD(1, 1, 0, (w))
+#define     CYTP_CMD_SET_HSCROLL_MASK       ENCODE_CMD(1, 1, 0, 0)
+#define CYTP_CMD_SET_VSCROLL_WIDTH(w)       ENCODE_CMD(1, 2, 0, (w))
+#define     CYTP_CMD_SET_VSCROLL_MASK       ENCODE_CMD(1, 2, 0, 0)
+#define CYTP_CMD_SET_PALM_GEOMETRY(e)       ENCODE_CMD(1, 2, 1, (e))
+#define     CYTP_CMD_PALM_GEMMETRY_MASK     ENCODE_CMD(1, 2, 1, 0)
+#define CYTP_CMD_SET_PALM_SENSITIVITY(s)    ENCODE_CMD(1, 2, 2, (s))
+#define     CYTP_CMD_PALM_SENSITIVITY_MASK  ENCODE_CMD(1, 2, 2, 0)
+#define CYTP_CMD_SET_MOUSE_SENSITIVITY(s)   ENCODE_CMD(1, 3, ((s) >> 2), (s))
+#define     CYTP_CMD_MOUSE_SENSITIVITY_MASK ENCODE_CMD(1, 3, 0, 0)
+#define CYTP_CMD_REQUEST_BASELINE_STATUS    ENCODE_CMD(2, 0, 0, 1)
+#define CYTP_CMD_REQUEST_RECALIBRATION      ENCODE_CMD(2, 0, 0, 3)
+
+#define DECODE_CMD_AA(x) (((x) >> 6) & CMD_BITS_MASK)
+#define DECODE_CMD_BB(x) (((x) >> 4) & CMD_BITS_MASK)
+#define DECODE_CMD_CC(x) (((x) >> 2) & CMD_BITS_MASK)
+#define DECODE_CMD_DD(x) ((x) & CMD_BITS_MASK)
+
+/* Cypress trackpad working mode. */
+#define CYTP_BIT_ABS_PRESSURE    (1 << 3)
+#define CYTP_BIT_ABS_NO_PRESSURE (1 << 2)
+#define CYTP_BIT_CYPRESS_REL     (1 << 1)
+#define CYTP_BIT_STANDARD_REL    (1 << 0)
+#define CYTP_BIT_REL_MASK (CYTP_BIT_CYPRESS_REL | CYTP_BIT_STANDARD_REL)
+#define CYTP_BIT_ABS_MASK (CYTP_BIT_ABS_PRESSURE | CYTP_BIT_ABS_NO_PRESSURE)
+#define CYTP_BIT_ABS_REL_MASK (CYTP_BIT_ABS_MASK | CYTP_BIT_REL_MASK)
+
+#define CYTP_BIT_HIGH_RATE       (1 << 4)
+/*
+ * report mode bit is set, firmware working in Remote Mode.
+ * report mode bit is cleared, firmware working in Stream Mode.
+ */
+#define CYTP_BIT_REPORT_MODE     (1 << 5)
+
+/* scrolling width values for set HSCROLL and VSCROLL width command. */
+#define SCROLL_WIDTH_NARROW 1
+#define SCROLL_WIDTH_NORMAL 2
+#define SCROLL_WIDTH_WIDE   3
+
+#define PALM_GEOMETRY_ENABLE  1
+#define PALM_GEOMETRY_DISABLE 0
+
+#define TP_METRICS_MASK  0x80
+#define FW_VERSION_MASX    0x7f
+#define FW_VER_HIGH_MASK 0x70
+#define FW_VER_LOW_MASK  0x0f
+
+/* Times to retry a ps2_command and millisecond delay between tries. */
+#define CYTP_PS2_CMD_TRIES 3
+#define CYTP_PS2_CMD_DELAY 500
+
+/* time out for PS/2 command only in milliseconds. */
+#define CYTP_CMD_TIMEOUT  200
+#define CYTP_DATA_TIMEOUT 30
+
+#define CYTP_EXT_CMD   0xe8
+#define CYTP_PS2_RETRY 0xfe
+#define CYTP_PS2_ERROR 0xfc
+
+#define CYTP_RESP_RETRY 0x01
+#define CYTP_RESP_ERROR 0xfe
+
+
+#define CYTP_105001_WIDTH  97   /* Dell XPS 13 */
+#define CYTP_105001_HIGH   59
+#define CYTP_DEFAULT_WIDTH (CYTP_105001_WIDTH)
+#define CYTP_DEFAULT_HIGH  (CYTP_105001_HIGH)
+
+#define CYTP_ABS_MAX_X     1600
+#define CYTP_ABS_MAX_Y     900
+#define CYTP_MAX_PRESSURE  255
+#define CYTP_MIN_PRESSURE  0
+
+/* header byte bits of relative package. */
+#define BTN_LEFT_BIT   0x01
+#define BTN_RIGHT_BIT  0x02
+#define BTN_MIDDLE_BIT 0x04
+#define REL_X_SIGN_BIT 0x10
+#define REL_Y_SIGN_BIT 0x20
+
+/* header byte bits of absolute package. */
+#define ABS_VSCROLL_BIT 0x10
+#define ABS_HSCROLL_BIT 0x20
+#define ABS_MULTIFINGER_TAP 0x04
+#define ABS_EDGE_MOTION_MASK 0x80
+
+#define DFLT_RESP_BITS_VALID     0x88  /* SMBus bit should not be set. */
+#define DFLT_RESP_SMBUS_BIT      0x80
+#define   DFLT_SMBUS_MODE        0x80
+#define   DFLT_PS2_MODE          0x00
+#define DFLT_RESP_BIT_MODE       0x40
+#define   DFLT_RESP_REMOTE_MODE  0x40
+#define   DFLT_RESP_STREAM_MODE  0x00
+#define DFLT_RESP_BIT_REPORTING  0x20
+#define DFLT_RESP_BIT_SCALING    0x10
+
+#define TP_METRICS_BIT_PALM               0x80
+#define TP_METRICS_BIT_STUBBORN           0x40
+#define TP_METRICS_BIT_2F_JITTER          0x30
+#define TP_METRICS_BIT_1F_JITTER          0x0c
+#define TP_METRICS_BIT_APA                0x02
+#define TP_METRICS_BIT_MTG                0x01
+#define TP_METRICS_BIT_ABS_PKT_FORMAT_SET 0xf0
+#define TP_METRICS_BIT_2F_SPIKE           0x0c
+#define TP_METRICS_BIT_1F_SPIKE           0x03
+
+/* bits of first byte response of E9h-Status Request command. */
+#define RESP_BTN_RIGHT_BIT  0x01
+#define RESP_BTN_MIDDLE_BIT 0x02
+#define RESP_BTN_LEFT_BIT   0x04
+#define RESP_SCALING_BIT    0x10
+#define RESP_ENABLE_BIT     0x20
+#define RESP_REMOTE_BIT     0x40
+#define RESP_SMBUS_BIT      0x80
+
+#define CYTP_MAX_MT_SLOTS 2
+
+struct cytp_contact {
+	int x;
+	int y;
+	int z;  /* also named as touch pressure. */
+};
+
+/* The structure of Cypress Trackpad event data. */
+struct cytp_report_data {
+	int contact_cnt;
+	struct cytp_contact contacts[CYTP_MAX_MT_SLOTS];
+	unsigned int left:1;
+	unsigned int right:1;
+	unsigned int middle:1;
+	unsigned int tap:1;  /* multi-finger tap detected. */
+};
+
+/* The structure of Cypress Trackpad device private data. */
+struct cytp_data {
+	int fw_version;
+
+	int pkt_size;
+	int mode;
+
+	int tp_min_pressure;
+	int tp_max_pressure;
+	int tp_width;  /* X direction physical size in mm. */
+	int tp_high;  /* Y direction physical size in mm. */
+	int tp_max_abs_x;  /* Max X absolute units that can be reported. */
+	int tp_max_abs_y;  /* Max Y absolute units that can be reported. */
+
+	int tp_res_x;  /* X resolution in units/mm. */
+	int tp_res_y;  /* Y resolution in units/mm. */
+
+	int tp_metrics_supported;
+};
+
+
+#ifdef CONFIG_MOUSE_PS2_CYPRESS
+int cypress_detect(struct psmouse *psmouse, bool set_properties);
+int cypress_init(struct psmouse *psmouse);
+bool cypress_supported(void);
+#else
+inline int cypress_detect(struct psmouse *psmouse, bool set_properties)
+{
+	return -ENOSYS;
+}
+inline int cypress_init(struct psmouse *psmouse)
+{
+	return -ENOSYS;
+}
+inline bool cypress_supported(void)
+{
+	return 0;
+}
+#endif /* CONFIG_MOUSE_PS2_CYPRESS */
+
+#endif  /* _CYPRESS_PS2_H */
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 22fe254..cff065f 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -34,6 +34,7 @@
 #include "touchkit_ps2.h"
 #include "elantech.h"
 #include "sentelic.h"
+#include "cypress_ps2.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -759,6 +760,28 @@
 	}
 
 /*
+ * Try Cypress Trackpad.
+ * Must try it before Finger Sensing Pad because Finger Sensing Pad probe
+ * upsets some modules of Cypress Trackpads.
+ */
+	if (max_proto > PSMOUSE_IMEX &&
+			cypress_detect(psmouse, set_properties) == 0) {
+		if (cypress_supported()) {
+			if (cypress_init(psmouse) == 0)
+				return PSMOUSE_CYPRESS;
+
+			/*
+			 * Finger Sensing Pad probe upsets some modules of
+			 * Cypress Trackpad, must avoid Finger Sensing Pad
+			 * probe if Cypress Trackpad device detected.
+			 */
+			return PSMOUSE_PS2;
+		}
+
+		max_proto = PSMOUSE_IMEX;
+	}
+
+/*
  * Try ALPS TouchPad
  */
 	if (max_proto > PSMOUSE_IMEX) {
@@ -896,6 +919,15 @@
 		.alias		= "thinkps",
 		.detect		= thinking_detect,
 	},
+#ifdef CONFIG_MOUSE_PS2_CYPRESS
+	{
+		.type		= PSMOUSE_CYPRESS,
+		.name		= "CyPS/2",
+		.alias		= "cypress",
+		.detect		= cypress_detect,
+		.init		= cypress_init,
+	},
+#endif
 	{
 		.type		= PSMOUSE_GENPS,
 		.name		= "GenPS/2",
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index fe1df23..2f0b39d 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -95,6 +95,7 @@
 	PSMOUSE_ELANTECH,
 	PSMOUSE_FSP,
 	PSMOUSE_SYNAPTICS_RELATIVE,
+	PSMOUSE_CYPRESS,
 	PSMOUSE_AUTO		/* This one should always be last */
 };
 
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 12d12ca..2f78538 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -722,11 +722,13 @@
 	default:
 		/*
 		 * If the finger slot contained in SGM is valid, and either
-		 * hasn't changed, or is new, then report SGM in MTB slot 0.
+		 * hasn't changed, or is new, or the old SGM has now moved to
+		 * AGM, then report SGM in MTB slot 0.
 		 * Otherwise, empty MTB slot 0.
 		 */
 		if (mt_state->sgm != -1 &&
-		    (mt_state->sgm == old->sgm || old->sgm == -1))
+		    (mt_state->sgm == old->sgm ||
+		     old->sgm == -1 || mt_state->agm == old->sgm))
 			synaptics_report_slot(dev, 0, sgm);
 		else
 			synaptics_report_slot(dev, 0, NULL);
@@ -735,9 +737,31 @@
 		 * If the finger slot contained in AGM is valid, and either
 		 * hasn't changed, or is new, then report AGM in MTB slot 1.
 		 * Otherwise, empty MTB slot 1.
+		 *
+		 * However, in the case where the AGM is new, make sure that
+		 * that it is either the same as the old SGM, or there was no
+		 * SGM.
+		 *
+		 * Otherwise, if the SGM was just 1, and the new AGM is 2, then
+		 * the new AGM will keep the old SGM's tracking ID, which can
+		 * cause apparent drumroll.  This happens if in the following
+		 * valid finger sequence:
+		 *
+		 *  Action                 SGM  AGM (MTB slot:Contact)
+		 *  1. Touch contact 0    (0:0)
+		 *  2. Touch contact 1    (0:0, 1:1)
+		 *  3. Lift  contact 0    (1:1)
+		 *  4. Touch contacts 2,3 (0:2, 1:3)
+		 *
+		 * In step 4, contact 3, in AGM must not be given the same
+		 * tracking ID as contact 1 had in step 3.  To avoid this,
+		 * the first agm with contact 3 is dropped and slot 1 is
+		 * invalidated (tracking ID = -1).
 		 */
 		if (mt_state->agm != -1 &&
-		    (mt_state->agm == old->agm || old->agm == -1))
+		    (mt_state->agm == old->agm ||
+		     (old->agm == -1 &&
+		      (old->sgm == -1 || mt_state->agm == old->sgm))))
 			synaptics_report_slot(dev, 1, agm);
 		else
 			synaptics_report_slot(dev, 1, NULL);
@@ -1247,11 +1271,11 @@
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
 	if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
-		input_mt_init_slots(dev, 2, 0);
 		set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
 					ABS_MT_POSITION_Y);
 		/* Image sensors can report per-contact pressure */
 		input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+		input_mt_init_slots(dev, 2, INPUT_MT_POINTER);
 
 		/* Image sensors can signal 4 and 5 finger clicks */
 		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 4a4e182..560c243 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -236,6 +236,7 @@
 
 config SERIO_ARC_PS2
 	tristate "ARC PS/2 support"
+	depends on GENERIC_HARDIRQS
 	help
 	  Say Y here if you have an ARC FPGA platform with a PS/2
 	  controller in it.
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index f92d34f..aaf23ae 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -553,10 +553,10 @@
 	if (!rep_data)
 		return error;
 
-	rep_data[0] = report_id;
-	rep_data[1] = mode;
-
 	do {
+		rep_data[0] = report_id;
+		rep_data[1] = mode;
+
 		error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
 		                         report_id, rep_data, length, 1);
 		if (error >= 0)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 264138f..41b6fbf 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -359,6 +359,7 @@
 		case 0x802: /* Intuos4 General Pen */
 		case 0x804: /* Intuos4 Marker Pen */
 		case 0x40802: /* Intuos4 Classic Pen */
+		case 0x18803: /* DTH2242 Grip Pen */
 		case 0x022:
 			wacom->tool[idx] = BTN_TOOL_PEN;
 			break;
@@ -538,6 +539,13 @@
 				input_report_key(input, wacom->tool[1], 0);
 				input_report_abs(input, ABS_MISC, 0);
 			}
+		} else if (features->type == DTK) {
+			input_report_key(input, BTN_0, (data[6] & 0x01));
+			input_report_key(input, BTN_1, (data[6] & 0x02));
+			input_report_key(input, BTN_2, (data[6] & 0x04));
+			input_report_key(input, BTN_3, (data[6] & 0x08));
+			input_report_key(input, BTN_4, (data[6] & 0x10));
+			input_report_key(input, BTN_5, (data[6] & 0x20));
 		} else if (features->type == WACOM_24HD) {
 			input_report_key(input, BTN_0, (data[6] & 0x01));
 			input_report_key(input, BTN_1, (data[6] & 0x02));
@@ -785,25 +793,6 @@
 	return 1;
 }
 
-static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
-{
-	int touch_max = wacom->features.touch_max;
-	int i;
-
-	if (!wacom->slots)
-		return -1;
-
-	for (i = 0; i < touch_max; ++i) {
-		if (wacom->slots[i] == contactid)
-			return i;
-	}
-	for (i = 0; i < touch_max; ++i) {
-		if (wacom->slots[i] == -1)
-			return i;
-	}
-	return -1;
-}
-
 static int int_dist(int x1, int y1, int x2, int y2)
 {
 	int x = x2 - x1;
@@ -833,8 +822,7 @@
 	for (i = 0; i < contacts_to_send; i++) {
 		int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
 		bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
-		int id = data[offset + 1];
-		int slot = find_slot_from_contactid(wacom, id);
+		int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
 
 		if (slot < 0)
 			continue;
@@ -856,9 +844,7 @@
 			input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
 			input_report_abs(input, ABS_MT_ORIENTATION, w > h);
 		}
-		wacom->slots[slot] = touch ? id : -1;
 	}
-
 	input_mt_report_pointer_emulation(input, true);
 
 	wacom->num_contacts_left -= contacts_to_send;
@@ -895,7 +881,7 @@
 		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
 		bool touch = data[offset] & 0x1;
 		int id = le16_to_cpup((__le16 *)&data[offset + 1]);
-		int slot = find_slot_from_contactid(wacom, id);
+		int slot = input_mt_get_slot_by_key(input, id);
 
 		if (slot < 0)
 			continue;
@@ -908,9 +894,7 @@
 			input_report_abs(input, ABS_MT_POSITION_X, x);
 			input_report_abs(input, ABS_MT_POSITION_Y, y);
 		}
-		wacom->slots[slot] = touch ? id : -1;
 	}
-
 	input_mt_report_pointer_emulation(input, true);
 
 	wacom->num_contacts_left -= contacts_to_send;
@@ -942,12 +926,11 @@
 			contact_with_no_pen_down_count++;
 		}
 	}
+	input_mt_report_pointer_emulation(input, true);
 
 	/* keep touch state for pen event */
 	wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
-	input_mt_report_pointer_emulation(input, true);
-
 	return 1;
 }
 
@@ -1104,12 +1087,15 @@
 static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
 {
 	struct input_dev *input = wacom->input;
-	int slot_id = data[0] - 2;  /* data[0] is between 2 and 17 */
 	bool touch = data[1] & 0x80;
+	int slot = input_mt_get_slot_by_key(input, data[0]);
+
+	if (slot < 0)
+		return;
 
 	touch = touch && !wacom->shared->stylus_in_proximity;
 
-	input_mt_slot(input, slot_id);
+	input_mt_slot(input, slot);
 	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
 
 	if (touch) {
@@ -1162,7 +1148,6 @@
 			wacom_bpt3_button_msg(wacom, data + offset);
 
 	}
-
 	input_mt_report_pointer_emulation(input, true);
 
 	input_sync(input);
@@ -1319,6 +1304,7 @@
 	case WACOM_21UX2:
 	case WACOM_22HD:
 	case WACOM_24HD:
+	case DTK:
 		sync = wacom_intuos_irq(wacom_wac);
 		break;
 
@@ -1444,6 +1430,51 @@
        return (logical_max * 100) / physical_max;
 }
 
+static void wacom_abs_set_axis(struct input_dev *input_dev,
+			       struct wacom_wac *wacom_wac)
+{
+	struct wacom_features *features = &wacom_wac->features;
+
+	if (features->device_type == BTN_TOOL_PEN) {
+		input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
+				     features->x_fuzz, 0);
+		input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
+				     features->y_fuzz, 0);
+		input_set_abs_params(input_dev, ABS_PRESSURE, 0,
+			features->pressure_max, features->pressure_fuzz, 0);
+
+		/* penabled devices have fixed resolution for each model */
+		input_abs_set_res(input_dev, ABS_X, features->x_resolution);
+		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
+	} else {
+		if (features->touch_max <= 2) {
+			input_set_abs_params(input_dev, ABS_X, 0,
+				features->x_max, features->x_fuzz, 0);
+			input_set_abs_params(input_dev, ABS_Y, 0,
+				features->y_max, features->y_fuzz, 0);
+			input_abs_set_res(input_dev, ABS_X,
+				wacom_calculate_touch_res(features->x_max,
+							features->x_phy));
+			input_abs_set_res(input_dev, ABS_Y,
+				wacom_calculate_touch_res(features->y_max,
+							features->y_phy));
+		}
+
+		if (features->touch_max > 1) {
+			input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+				features->x_max, features->x_fuzz, 0);
+			input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+				features->y_max, features->y_fuzz, 0);
+			input_abs_set_res(input_dev, ABS_MT_POSITION_X,
+				wacom_calculate_touch_res(features->x_max,
+							features->x_phy));
+			input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
+				wacom_calculate_touch_res(features->y_max,
+							features->y_phy));
+		}
+	}
+}
+
 int wacom_setup_input_capabilities(struct input_dev *input_dev,
 				   struct wacom_wac *wacom_wac)
 {
@@ -1453,30 +1484,10 @@
 	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 
 	__set_bit(BTN_TOUCH, input_dev->keybit);
-
-	input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
-			     features->x_fuzz, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
-			     features->y_fuzz, 0);
-
-	if (features->device_type == BTN_TOOL_PEN) {
-		input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
-			     features->pressure_fuzz, 0);
-
-		/* penabled devices have fixed resolution for each model */
-		input_abs_set_res(input_dev, ABS_X, features->x_resolution);
-		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
-	} else {
-		input_abs_set_res(input_dev, ABS_X,
-			wacom_calculate_touch_res(features->x_max,
-						features->x_phy));
-		input_abs_set_res(input_dev, ABS_Y,
-			wacom_calculate_touch_res(features->y_max,
-						features->y_phy));
-	}
-
 	__set_bit(ABS_MISC, input_dev->absbit);
 
+	wacom_abs_set_axis(input_dev, wacom_wac);
+
 	switch (wacom_wac->features.type) {
 	case WACOM_MO:
 		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
@@ -1513,12 +1524,17 @@
 		__set_bit(BTN_Y, input_dev->keybit);
 		__set_bit(BTN_Z, input_dev->keybit);
 
-		for (i = 0; i < 10; i++)
+		for (i = 6; i < 10; i++)
 			__set_bit(BTN_0 + i, input_dev->keybit);
 
 		__set_bit(KEY_PROG1, input_dev->keybit);
 		__set_bit(KEY_PROG2, input_dev->keybit);
 		__set_bit(KEY_PROG3, input_dev->keybit);
+		/* fall through */
+
+	case DTK:
+		for (i = 0; i < 6; i++)
+			__set_bit(BTN_0 + i, input_dev->keybit);
 
 		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
 		input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
@@ -1614,24 +1630,11 @@
 		} else if (features->device_type == BTN_TOOL_FINGER) {
 			__clear_bit(ABS_MISC, input_dev->absbit);
 
-			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-			__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-			__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
-
-			input_mt_init_slots(input_dev, features->touch_max, 0);
-
 			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 			                     0, features->x_max, 0, 0);
 			input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
 			                     0, features->y_max, 0, 0);
-
-			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-					     0, features->x_max,
-					     features->x_fuzz, 0);
-			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-					     0, features->y_max,
-					     features->y_fuzz, 0);
+			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
 		}
 		break;
 
@@ -1662,27 +1665,14 @@
 
 	case MTSCREEN:
 	case MTTPC:
-		if (features->device_type == BTN_TOOL_FINGER) {
-			wacom_wac->slots = kmalloc(features->touch_max *
-							sizeof(int),
-						   GFP_KERNEL);
-			if (!wacom_wac->slots)
-				return -ENOMEM;
-
-			for (i = 0; i < features->touch_max; i++)
-				wacom_wac->slots[i] = -1;
-		}
-		/* fall through */
-
 	case TABLETPC2FG:
 		if (features->device_type == BTN_TOOL_FINGER) {
-			input_mt_init_slots(input_dev, features->touch_max, 0);
-			input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
-					0, MT_TOOL_MAX, 0, 0);
-			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-					0, features->x_max, 0, 0);
-			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-					0, features->y_max, 0, 0);
+			unsigned int flags = INPUT_MT_DIRECT;
+
+			if (wacom_wac->features.type == TABLETPC2FG)
+				flags = 0;
+
+			input_mt_init_slots(input_dev, features->touch_max, flags);
 		}
 		/* fall through */
 
@@ -1725,35 +1715,26 @@
 		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 
 		if (features->device_type == BTN_TOOL_FINGER) {
+			unsigned int flags = INPUT_MT_POINTER;
+
 			__set_bit(BTN_LEFT, input_dev->keybit);
 			__set_bit(BTN_FORWARD, input_dev->keybit);
 			__set_bit(BTN_BACK, input_dev->keybit);
 			__set_bit(BTN_RIGHT, input_dev->keybit);
 
-			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-			input_mt_init_slots(input_dev, features->touch_max, 0);
-
 			if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
-				__set_bit(BTN_TOOL_TRIPLETAP,
-					  input_dev->keybit);
-				__set_bit(BTN_TOOL_QUADTAP,
-					  input_dev->keybit);
-
 				input_set_abs_params(input_dev,
 						     ABS_MT_TOUCH_MAJOR,
 						     0, features->x_max, 0, 0);
 				input_set_abs_params(input_dev,
 						     ABS_MT_TOUCH_MINOR,
 						     0, features->y_max, 0, 0);
+			} else {
+				__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+				__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+				flags = 0;
 			}
-
-			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-					     0, features->x_max,
-					     features->x_fuzz, 0);
-			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-					     0, features->y_max,
-					     features->y_fuzz, 0);
+			input_mt_init_slots(input_dev, features->touch_max, flags);
 		} else if (features->device_type == BTN_TOOL_PEN) {
 			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
 			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -1978,6 +1959,13 @@
 static const struct wacom_features wacom_features_0xF0 =
 	{ "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,
 	  0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x59 = /* Pen */
+	{ "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
+	  63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
+static const struct wacom_features wacom_features_0x5D = /* Touch */
+	{ "Wacom DTH2242",       .type = WACOM_24HDT,
+	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
 static const struct wacom_features wacom_features_0xCC =
 	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047,
 	  63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@@ -2152,6 +2140,8 @@
 	{ USB_DEVICE_WACOM(0x43) },
 	{ USB_DEVICE_WACOM(0x44) },
 	{ USB_DEVICE_WACOM(0x45) },
+	{ USB_DEVICE_WACOM(0x59) },
+	{ USB_DEVICE_WACOM(0x5D) },
 	{ USB_DEVICE_WACOM(0xB0) },
 	{ USB_DEVICE_WACOM(0xB1) },
 	{ USB_DEVICE_WACOM(0xB2) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 9396d77..5f9a772 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -78,6 +78,7 @@
 	INTUOS5L,
 	WACOM_21UX2,
 	WACOM_22HD,
+	DTK,
 	WACOM_24HD,
 	CINTIQ,
 	WACOM_BEE,
@@ -135,7 +136,6 @@
 	int pid;
 	int battery_capacity;
 	int num_contacts_left;
-	int *slots;
 };
 
 #endif
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 515cfe7..f9a5fd8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -359,7 +359,7 @@
 
 config TOUCHSCREEN_MMS114
 	tristate "MELFAS MMS114 touchscreen"
-	depends on I2C
+	depends on I2C && GENERIC_HARDIRQS
 	help
 	  Say Y here if you have the MELFAS MMS114 touchscreen controller
 	  chip in your system.
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 638e203..861b7f7 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -193,7 +193,6 @@
 
 module_spi_driver(cyttsp_spi_driver);
 
-MODULE_ALIAS("spi:cyttsp");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
 MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index 98841d8..4a29ddf 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -429,12 +429,12 @@
 		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct mms114_data), GFP_KERNEL);
-	input_dev = input_allocate_device();
+	data = devm_kzalloc(&client->dev, sizeof(struct mms114_data),
+			    GFP_KERNEL);
+	input_dev = devm_input_allocate_device(&client->dev);
 	if (!data || !input_dev) {
 		dev_err(&client->dev, "Failed to allocate memory\n");
-		error = -ENOMEM;
-		goto err_free_mem;
+		return -ENOMEM;
 	}
 
 	data->client = client;
@@ -466,57 +466,36 @@
 	input_set_drvdata(input_dev, data);
 	i2c_set_clientdata(client, data);
 
-	data->core_reg = regulator_get(&client->dev, "avdd");
+	data->core_reg = devm_regulator_get(&client->dev, "avdd");
 	if (IS_ERR(data->core_reg)) {
 		error = PTR_ERR(data->core_reg);
 		dev_err(&client->dev,
 			"Unable to get the Core regulator (%d)\n", error);
-		goto err_free_mem;
+		return error;
 	}
 
-	data->io_reg = regulator_get(&client->dev, "vdd");
+	data->io_reg = devm_regulator_get(&client->dev, "vdd");
 	if (IS_ERR(data->io_reg)) {
 		error = PTR_ERR(data->io_reg);
 		dev_err(&client->dev,
 			"Unable to get the IO regulator (%d)\n", error);
-		goto err_core_reg;
+		return error;
 	}
 
-	error = request_threaded_irq(client->irq, NULL, mms114_interrupt,
-			IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mms114", data);
+	error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+			mms114_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+			dev_name(&client->dev), data);
 	if (error) {
 		dev_err(&client->dev, "Failed to register interrupt\n");
-		goto err_io_reg;
+		return error;
 	}
 	disable_irq(client->irq);
 
 	error = input_register_device(data->input_dev);
-	if (error)
-		goto err_free_irq;
-
-	return 0;
-
-err_free_irq:
-	free_irq(client->irq, data);
-err_io_reg:
-	regulator_put(data->io_reg);
-err_core_reg:
-	regulator_put(data->core_reg);
-err_free_mem:
-	input_free_device(input_dev);
-	kfree(data);
-	return error;
-}
-
-static int mms114_remove(struct i2c_client *client)
-{
-	struct mms114_data *data = i2c_get_clientdata(client);
-
-	free_irq(client->irq, data);
-	regulator_put(data->io_reg);
-	regulator_put(data->core_reg);
-	input_unregister_device(data->input_dev);
-	kfree(data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register input device\n");
+		return error;
+	}
 
 	return 0;
 }
@@ -590,7 +569,6 @@
 		.of_match_table = of_match_ptr(mms114_dt_match),
 	},
 	.probe		= mms114_probe,
-	.remove		= mms114_remove,
 	.id_table	= mms114_id,
 };
 
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 84d884b..59e81b0 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -120,6 +120,7 @@
 	__stmpe_reset_fifo(ts->stmpe);
 
 	input_report_abs(ts->idev, ABS_PRESSURE, 0);
+	input_report_key(ts->idev, BTN_TOUCH, 0);
 	input_sync(ts->idev);
 }
 
@@ -153,6 +154,7 @@
 	input_report_abs(ts->idev, ABS_X, x);
 	input_report_abs(ts->idev, ABS_Y, y);
 	input_report_abs(ts->idev, ABS_PRESSURE, z);
+	input_report_key(ts->idev, BTN_TOUCH, 1);
 	input_sync(ts->idev);
 
        /* flush the FIFO after we have read out our values. */
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 9c0cdc7..7213e8b 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -753,3 +753,4 @@
 MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
 MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:tsc2005");
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index f88fab5..6be2eb6 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -247,7 +247,7 @@
 
 	wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts),
 				 GFP_KERNEL);
-	input_dev = input_allocate_device();
+	input_dev = devm_input_allocate_device(&pdev->dev);
 	if (!wm831x_ts || !input_dev) {
 		error = -ENOMEM;
 		goto err_alloc;
@@ -376,7 +376,6 @@
 err_data_irq:
 	free_irq(wm831x_ts->data_irq, wm831x_ts);
 err_alloc:
-	input_free_device(input_dev);
 
 	return error;
 }
@@ -387,7 +386,6 @@
 
 	free_irq(wm831x_ts->pd_irq, wm831x_ts);
 	free_irq(wm831x_ts->data_irq, wm831x_ts);
-	input_unregister_device(wm831x_ts->input_dev);
 
 	return 0;
 }
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index c1c74e0..d33eaaf 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4017,10 +4017,10 @@
 
 			index -= count - 1;
 
+			cfg->remapped	      = 1;
 			irte_info             = &cfg->irq_2_iommu;
 			irte_info->sub_handle = devid;
 			irte_info->irte_index = index;
-			irte_info->iommu      = (void *)cfg;
 
 			goto out;
 		}
@@ -4127,9 +4127,9 @@
 	index = attr->ioapic_pin;
 
 	/* Setup IRQ remapping info */
+	cfg->remapped	      = 1;
 	irte_info->sub_handle = devid;
 	irte_info->irte_index = index;
-	irte_info->iommu      = (void *)cfg;
 
 	/* Setup IRTE for IOMMU */
 	irte.val		= 0;
@@ -4288,9 +4288,9 @@
 	devid		= get_device_id(&pdev->dev);
 	irte_info	= &cfg->irq_2_iommu;
 
+	cfg->remapped	      = 1;
 	irte_info->sub_handle = devid;
 	irte_info->irte_index = index + offset;
-	irte_info->iommu      = (void *)cfg;
 
 	return 0;
 }
@@ -4314,9 +4314,9 @@
 	if (index < 0)
 		return index;
 
+	cfg->remapped	      = 1;
 	irte_info->sub_handle = devid;
 	irte_info->irte_index = index;
-	irte_info->iommu      = (void *)cfg;
 
 	return 0;
 }
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 86e2f4a..174bb65 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -41,6 +41,8 @@
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
+#include "irq_remapping.h"
+
 /* No locks are needed as DMA remapping hardware unit
  * list is constructed at boot time and hotplug of
  * these units are not supported by the architecture.
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index eca2801..43d5c8b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -46,6 +46,8 @@
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
 
+#include "irq_remapping.h"
+
 #define ROOT_SIZE		VTD_PAGE_SIZE
 #define CONTEXT_SIZE		VTD_PAGE_SIZE
 
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index af8904d..f3b8f23 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -68,6 +68,7 @@
 {
 	struct ir_table *table = iommu->ir_table;
 	struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+	struct irq_cfg *cfg = irq_get_chip_data(irq);
 	u16 index, start_index;
 	unsigned int mask = 0;
 	unsigned long flags;
@@ -115,6 +116,7 @@
 	for (i = index; i < index + count; i++)
 		table->base[i].present = 1;
 
+	cfg->remapped = 1;
 	irq_iommu->iommu = iommu;
 	irq_iommu->irte_index =  index;
 	irq_iommu->sub_handle = 0;
@@ -155,6 +157,7 @@
 static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 {
 	struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+	struct irq_cfg *cfg = irq_get_chip_data(irq);
 	unsigned long flags;
 
 	if (!irq_iommu)
@@ -162,6 +165,7 @@
 
 	raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 
+	cfg->remapped = 1;
 	irq_iommu->iommu = iommu;
 	irq_iommu->irte_index = index;
 	irq_iommu->sub_handle = subhandle;
@@ -425,11 +429,22 @@
 
 	/* Enable interrupt-remapping */
 	iommu->gcmd |= DMA_GCMD_IRE;
+	iommu->gcmd &= ~DMA_GCMD_CFI;  /* Block compatibility-format MSIs */
 	writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
 
 	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
 		      readl, (sts & DMA_GSTS_IRES), sts);
 
+	/*
+	 * With CFI clear in the Global Command register, we should be
+	 * protected from dangerous (i.e. compatibility) interrupts
+	 * regardless of x2apic status.  Check just to be sure.
+	 */
+	if (sts & DMA_GSTS_CFIS)
+		WARN(1, KERN_WARNING
+			"Compatibility-format IRQs enabled despite intr remapping;\n"
+			"you are vulnerable to IRQ injection.\n");
+
 	raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
@@ -526,20 +541,24 @@
 static int __init intel_enable_irq_remapping(void)
 {
 	struct dmar_drhd_unit *drhd;
+	bool x2apic_present;
 	int setup = 0;
 	int eim = 0;
 
+	x2apic_present = x2apic_supported();
+
 	if (parse_ioapics_under_ir() != 1) {
 		printk(KERN_INFO "Not enable interrupt remapping\n");
-		return -1;
+		goto error;
 	}
 
-	if (x2apic_supported()) {
+	if (x2apic_present) {
 		eim = !dmar_x2apic_optout();
-		WARN(!eim, KERN_WARNING
-			   "Your BIOS is broken and requested that x2apic be disabled\n"
-			   "This will leave your machine vulnerable to irq-injection attacks\n"
-			   "Use 'intremap=no_x2apic_optout' to override BIOS request\n");
+		if (!eim)
+			printk(KERN_WARNING
+				"Your BIOS is broken and requested that x2apic be disabled.\n"
+				"This will slightly decrease performance.\n"
+				"Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
 	}
 
 	for_each_drhd_unit(drhd) {
@@ -578,7 +597,7 @@
 		if (eim && !ecap_eim_support(iommu->ecap)) {
 			printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
 			       " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
-			return -1;
+			goto error;
 		}
 	}
 
@@ -594,7 +613,7 @@
 			printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
 			       " invalidation, ecap %Lx, ret %d\n",
 			       drhd->reg_base_addr, iommu->ecap, ret);
-			return -1;
+			goto error;
 		}
 	}
 
@@ -617,6 +636,14 @@
 		goto error;
 
 	irq_remapping_enabled = 1;
+
+	/*
+	 * VT-d has a different layout for IO-APIC entries when
+	 * interrupt remapping is enabled. So it needs a special routine
+	 * to print IO-APIC entries for debugging purposes too.
+	 */
+	x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries;
+
 	pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
 
 	return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
@@ -625,6 +652,11 @@
 	/*
 	 * handle error condition gracefully here!
 	 */
+
+	if (x2apic_present)
+		WARN(1, KERN_WARNING
+			"Failed to enable irq remapping.  You are vulnerable to irq-injection attacks.\n");
+
 	return -1;
 }
 
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index faf85d6..d56f8c1 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -1,11 +1,18 @@
+#include <linux/seq_file.h>
+#include <linux/cpumask.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/msi.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
 
 #include <asm/hw_irq.h>
 #include <asm/irq_remapping.h>
+#include <asm/processor.h>
+#include <asm/x86_init.h>
+#include <asm/apic.h>
 
 #include "irq_remapping.h"
 
@@ -17,6 +24,152 @@
 
 static struct irq_remap_ops *remap_ops;
 
+static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
+static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+				  int index, int sub_handle);
+static int set_remapped_irq_affinity(struct irq_data *data,
+				     const struct cpumask *mask,
+				     bool force);
+
+static bool irq_remapped(struct irq_cfg *cfg)
+{
+	return (cfg->remapped == 1);
+}
+
+static void irq_remapping_disable_io_apic(void)
+{
+	/*
+	 * With interrupt-remapping, for now we will use virtual wire A
+	 * mode, as virtual wire B is little complex (need to configure
+	 * both IOAPIC RTE as well as interrupt-remapping table entry).
+	 * As this gets called during crash dump, keep this simple for
+	 * now.
+	 */
+	if (cpu_has_apic || apic_from_smp_config())
+		disconnect_bsp_APIC(0);
+}
+
+static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
+{
+	int node, ret, sub_handle, index = 0;
+	unsigned int irq;
+	struct msi_desc *msidesc;
+
+	nvec = __roundup_pow_of_two(nvec);
+
+	WARN_ON(!list_is_singular(&dev->msi_list));
+	msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
+	WARN_ON(msidesc->irq);
+	WARN_ON(msidesc->msi_attrib.multiple);
+
+	node = dev_to_node(&dev->dev);
+	irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
+	if (irq == 0)
+		return -ENOSPC;
+
+	msidesc->msi_attrib.multiple = ilog2(nvec);
+	for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
+		if (!sub_handle) {
+			index = msi_alloc_remapped_irq(dev, irq, nvec);
+			if (index < 0) {
+				ret = index;
+				goto error;
+			}
+		} else {
+			ret = msi_setup_remapped_irq(dev, irq + sub_handle,
+						     index, sub_handle);
+			if (ret < 0)
+				goto error;
+		}
+		ret = setup_msi_irq(dev, msidesc, irq, sub_handle);
+		if (ret < 0)
+			goto error;
+	}
+	return 0;
+
+error:
+	destroy_irqs(irq, nvec);
+
+	/*
+	 * Restore altered MSI descriptor fields and prevent just destroyed
+	 * IRQs from tearing down again in default_teardown_msi_irqs()
+	 */
+	msidesc->irq = 0;
+	msidesc->msi_attrib.multiple = 0;
+
+	return ret;
+}
+
+static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
+{
+	int node, ret, sub_handle, index = 0;
+	struct msi_desc *msidesc;
+	unsigned int irq;
+
+	node		= dev_to_node(&dev->dev);
+	irq		= get_nr_irqs_gsi();
+	sub_handle	= 0;
+
+	list_for_each_entry(msidesc, &dev->msi_list, list) {
+
+		irq = create_irq_nr(irq, node);
+		if (irq == 0)
+			return -1;
+
+		if (sub_handle == 0)
+			ret = index = msi_alloc_remapped_irq(dev, irq, nvec);
+		else
+			ret = msi_setup_remapped_irq(dev, irq, index, sub_handle);
+
+		if (ret < 0)
+			goto error;
+
+		ret = setup_msi_irq(dev, msidesc, irq, 0);
+		if (ret < 0)
+			goto error;
+
+		sub_handle += 1;
+		irq        += 1;
+	}
+
+	return 0;
+
+error:
+	destroy_irq(irq);
+	return ret;
+}
+
+static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
+					int nvec, int type)
+{
+	if (type == PCI_CAP_ID_MSI)
+		return do_setup_msi_irqs(dev, nvec);
+	else
+		return do_setup_msix_irqs(dev, nvec);
+}
+
+void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
+{
+	/*
+	 * Intr-remapping uses pin number as the virtual vector
+	 * in the RTE. Actual vector is programmed in
+	 * intr-remapping table entry. Hence for the io-apic
+	 * EOI we use the pin number.
+	 */
+	io_apic_eoi(apic, pin);
+}
+
+static void __init irq_remapping_modify_x86_ops(void)
+{
+	x86_io_apic_ops.disable		= irq_remapping_disable_io_apic;
+	x86_io_apic_ops.set_affinity	= set_remapped_irq_affinity;
+	x86_io_apic_ops.setup_entry	= setup_ioapic_remapped_entry;
+	x86_io_apic_ops.eoi_ioapic_pin	= eoi_ioapic_pin_remapped;
+	x86_msi.setup_msi_irqs		= irq_remapping_setup_msi_irqs;
+	x86_msi.setup_hpet_msi		= setup_hpet_msi_remapped;
+	x86_msi.compose_msi_msg		= compose_remapped_msi_msg;
+}
+
 static __init int setup_nointremap(char *str)
 {
 	disable_irq_remap = 1;
@@ -79,15 +232,24 @@
 
 int __init irq_remapping_enable(void)
 {
+	int ret;
+
 	if (!remap_ops || !remap_ops->enable)
 		return -ENODEV;
 
-	return remap_ops->enable();
+	ret = remap_ops->enable();
+
+	if (irq_remapping_enabled)
+		irq_remapping_modify_x86_ops();
+
+	return ret;
 }
 
 void irq_remapping_disable(void)
 {
-	if (!remap_ops || !remap_ops->disable)
+	if (!irq_remapping_enabled ||
+	    !remap_ops ||
+	    !remap_ops->disable)
 		return;
 
 	remap_ops->disable();
@@ -95,7 +257,9 @@
 
 int irq_remapping_reenable(int mode)
 {
-	if (!remap_ops || !remap_ops->reenable)
+	if (!irq_remapping_enabled ||
+	    !remap_ops ||
+	    !remap_ops->reenable)
 		return 0;
 
 	return remap_ops->reenable(mode);
@@ -103,6 +267,9 @@
 
 int __init irq_remap_enable_fault_handling(void)
 {
+	if (!irq_remapping_enabled)
+		return 0;
+
 	if (!remap_ops || !remap_ops->enable_faulting)
 		return -ENODEV;
 
@@ -133,23 +300,28 @@
 
 void free_remapped_irq(int irq)
 {
+	struct irq_cfg *cfg = irq_get_chip_data(irq);
+
 	if (!remap_ops || !remap_ops->free_irq)
 		return;
 
-	remap_ops->free_irq(irq);
+	if (irq_remapped(cfg))
+		remap_ops->free_irq(irq);
 }
 
 void compose_remapped_msi_msg(struct pci_dev *pdev,
 			      unsigned int irq, unsigned int dest,
 			      struct msi_msg *msg, u8 hpet_id)
 {
-	if (!remap_ops || !remap_ops->compose_msi_msg)
-		return;
+	struct irq_cfg *cfg = irq_get_chip_data(irq);
 
-	remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+	if (!irq_remapped(cfg))
+		native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+	else if (remap_ops && remap_ops->compose_msi_msg)
+		remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
 }
 
-int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
+static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
 {
 	if (!remap_ops || !remap_ops->msi_alloc_irq)
 		return -ENODEV;
@@ -157,8 +329,8 @@
 	return remap_ops->msi_alloc_irq(pdev, irq, nvec);
 }
 
-int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
-			   int index, int sub_handle)
+static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+				  int index, int sub_handle)
 {
 	if (!remap_ops || !remap_ops->msi_setup_irq)
 		return -ENODEV;
@@ -173,3 +345,42 @@
 
 	return remap_ops->setup_hpet_msi(irq, id);
 }
+
+void panic_if_irq_remap(const char *msg)
+{
+	if (irq_remapping_enabled)
+		panic(msg);
+}
+
+static void ir_ack_apic_edge(struct irq_data *data)
+{
+	ack_APIC_irq();
+}
+
+static void ir_ack_apic_level(struct irq_data *data)
+{
+	ack_APIC_irq();
+	eoi_ioapic_irq(data->irq, data->chip_data);
+}
+
+static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
+{
+	seq_printf(p, " IR-%s", data->chip->name);
+}
+
+void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+{
+	chip->irq_print_chip = ir_print_prefix;
+	chip->irq_ack = ir_ack_apic_edge;
+	chip->irq_eoi = ir_ack_apic_level;
+	chip->irq_set_affinity = x86_io_apic_ops.set_affinity;
+}
+
+bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip)
+{
+	if (!irq_remapped(cfg))
+		return false;
+	irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
+	irq_remap_modify_chip_defaults(chip);
+	return true;
+}
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index 95363ac..ecb6376 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -34,6 +34,7 @@
 extern int disable_irq_remap;
 extern int disable_sourceid_checking;
 extern int no_x2apic_optout;
+extern int irq_remapping_enabled;
 
 struct irq_remap_ops {
 	/* Check whether Interrupt Remapping is supported */
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
index 5374c25..267dede 100644
--- a/drivers/isdn/divert/divert_init.c
+++ b/drivers/isdn/divert/divert_init.c
@@ -22,13 +22,13 @@
 /****************************************/
 /* structure containing interface to hl */
 /****************************************/
-isdn_divert_if divert_if =
-{ DIVERT_IF_MAGIC,  /* magic value */
-  DIVERT_CMD_REG,   /* register cmd */
-  ll_callback,      /* callback routine from ll */
-  NULL,             /* command still not specified */
-  NULL,             /* drv_to_name */
-  NULL,             /* name_to_drv */
+isdn_divert_if divert_if = {
+	DIVERT_IF_MAGIC,	/* magic value */
+	DIVERT_CMD_REG,		/* register cmd */
+	ll_callback,		/* callback routine from ll */
+	NULL,			/* command still not specified */
+	NULL,			/* drv_to_name */
+	NULL,			/* name_to_drv */
 };
 
 /*************************/
@@ -36,14 +36,15 @@
 /* no cmd line parms     */
 /*************************/
 static int __init divert_init(void)
-{ int i;
+{
+	int i;
 
-	if (divert_dev_init())
-	{ printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
+	if (divert_dev_init()) {
+		printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
 		return (-EIO);
 	}
-	if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
-	{ divert_dev_deinit();
+	if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
+		divert_dev_deinit();
 		printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
 		return (-EIO);
 	}
@@ -61,13 +62,13 @@
 
 	spin_lock_irqsave(&divert_lock, flags);
 	divert_if.cmd = DIVERT_CMD_REL; /* release */
-	if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
-	{ printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
+	if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
+		printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
 		spin_unlock_irqrestore(&divert_lock, flags);
 		return;
 	}
-	if (divert_dev_deinit())
-	{ printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
+	if (divert_dev_deinit()) {
+		printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
 		spin_unlock_irqrestore(&divert_lock, flags);
 		return;
 	}
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index e61e55f..db432e6 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -19,8 +19,8 @@
 /**********************************/
 /* structure keeping calling info */
 /**********************************/
-struct call_struc
-{ isdn_ctrl ics; /* delivered setup + driver parameters */
+struct call_struc {
+	isdn_ctrl ics; /* delivered setup + driver parameters */
 	ulong divert_id; /* Id delivered to user */
 	unsigned char akt_state; /* actual state */
 	char deflect_dest[35]; /* deflection destination */
@@ -34,8 +34,8 @@
 /********************************************/
 /* structure keeping deflection table entry */
 /********************************************/
-struct deflect_struc
-{ struct deflect_struc *next, *prev;
+struct deflect_struc {
+	struct deflect_struc *next, *prev;
 	divert_rule rule; /* used rule */
 };
 
@@ -64,16 +64,16 @@
 	del_timer(&cs->timer); /* delete active timer */
 	spin_unlock_irqrestore(&divert_lock, flags);
 
-	switch (cs->akt_state)
-	{ case DEFLECT_PROCEED:
-			cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
-			divert_if.ll_cmd(&cs->ics);
-			spin_lock_irqsave(&divert_lock, flags);
-			cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
-			cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
-			add_timer(&cs->timer);
-			spin_unlock_irqrestore(&divert_lock, flags);
-			break;
+	switch (cs->akt_state) {
+	case DEFLECT_PROCEED:
+		cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
+		divert_if.ll_cmd(&cs->ics);
+		spin_lock_irqsave(&divert_lock, flags);
+		cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+		cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+		add_timer(&cs->timer);
+		spin_unlock_irqrestore(&divert_lock, flags);
+		break;
 
 	case DEFLECT_ALERT:
 		cs->ics.command = ISDN_CMD_REDIR; /* protocol */
@@ -111,7 +111,8 @@
 int cf_command(int drvid, int mode,
 	       u_char proc, char *msn,
 	       u_char service, char *fwd_nr, ulong *procid)
-{ unsigned long flags;
+{
+	unsigned long flags;
 	int retval, msnlen;
 	int fwd_len;
 	char *p, *ielenp, tmp[60];
@@ -130,8 +131,8 @@
 	*p++ = 1;   /* length */
 	*p++ = service; /* service to handle */
 
-	if (mode == 1)
-	{ if (!*fwd_nr) return (-EINVAL); /* destination missing */
+	if (mode == 1) {
+		if (!*fwd_nr) return (-EINVAL); /* destination missing */
 		if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
 		fwd_len = strlen(fwd_nr);
 		*p++ = 0x30; /* number enumeration */
@@ -144,12 +145,12 @@
 
 	msnlen = strlen(msn);
 	*p++ = 0x80; /* msn number */
-	if (msnlen > 1)
-	{ *p++ = msnlen; /* length */
+	if (msnlen > 1) {
+		*p++ = msnlen; /* length */
 		strcpy(p, msn);
 		p += msnlen;
-	}
-	else *p++ = 0;
+	} else
+		*p++ = 0;
 
 	*ielenp = p - ielenp - 1; /* set total IE length */
 
@@ -186,14 +187,13 @@
 
 	retval = divert_if.ll_cmd(&cs->ics); /* execute command */
 
-	if (!retval)
-	{ cs->prev = NULL;
+	if (!retval) {
+		cs->prev = NULL;
 		spin_lock_irqsave(&divert_lock, flags);
 		cs->next = divert_head;
 		divert_head = cs;
 		spin_unlock_irqrestore(&divert_lock, flags);
-	}
-	else
+	} else
 		kfree(cs);
 	return (retval);
 } /* cf_command */
@@ -203,15 +203,16 @@
 /* handle a external deflection command */
 /****************************************/
 int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
-{ struct call_struc *cs;
+{
+	struct call_struc *cs;
 	isdn_ctrl ic;
 	unsigned long flags;
 	int i;
 
 	if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
 	cs = divert_head; /* start of parameter list */
-	while (cs)
-	{ if (cs->divert_id == callid) break; /* found */
+	while (cs) {
+		if (cs->divert_id == callid) break; /* found */
 		cs = cs->next;
 	} /* search entry */
 	if (!cs) return (-EINVAL); /* invalid callid */
@@ -220,32 +221,30 @@
 	ic.arg = cs->ics.arg;
 	i = -EINVAL;
 	if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
-	switch (cmd & 0x7F)
-	{ case 0: /* hangup */
-			del_timer(&cs->timer);
-			ic.command = ISDN_CMD_HANGUP;
-			i = divert_if.ll_cmd(&ic);
-			spin_lock_irqsave(&divert_lock, flags);
-			cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
-			cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
-			add_timer(&cs->timer);
-			spin_unlock_irqrestore(&divert_lock, flags);
-			break;
+	switch (cmd & 0x7F) {
+	case 0: /* hangup */
+		del_timer(&cs->timer);
+		ic.command = ISDN_CMD_HANGUP;
+		i = divert_if.ll_cmd(&ic);
+		spin_lock_irqsave(&divert_lock, flags);
+		cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+		cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+		add_timer(&cs->timer);
+		spin_unlock_irqrestore(&divert_lock, flags);
+		break;
 
 	case 1: /* alert */
 		if (cs->akt_state == DEFLECT_ALERT) return (0);
 		cmd &= 0x7F; /* never wait */
 		del_timer(&cs->timer);
 		ic.command = ISDN_CMD_ALERT;
-		if ((i = divert_if.ll_cmd(&ic)))
-		{
+		if ((i = divert_if.ll_cmd(&ic))) {
 			spin_lock_irqsave(&divert_lock, flags);
 			cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
 			cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
 			add_timer(&cs->timer);
 			spin_unlock_irqrestore(&divert_lock, flags);
-		}
-		else
+		} else
 			cs->akt_state = DEFLECT_ALERT;
 		break;
 
@@ -254,15 +253,13 @@
 		strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
 		strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
 		ic.command = ISDN_CMD_REDIR;
-		if ((i = divert_if.ll_cmd(&ic)))
-		{
+		if ((i = divert_if.ll_cmd(&ic))) {
 			spin_lock_irqsave(&divert_lock, flags);
 			cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
 			cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
 			add_timer(&cs->timer);
 			spin_unlock_irqrestore(&divert_lock, flags);
-		}
-		else
+		} else
 			cs->akt_state = DEFLECT_ALERT;
 		break;
 
@@ -274,19 +271,19 @@
 /* insert a new rule before idx */
 /********************************/
 int insertrule(int idx, divert_rule *newrule)
-{ struct deflect_struc *ds, *ds1 = NULL;
+{
+	struct deflect_struc *ds, *ds1 = NULL;
 	unsigned long flags;
 
-	if (!(ds = kmalloc(sizeof(struct deflect_struc),
-			   GFP_KERNEL)))
+	if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
 		return (-ENOMEM); /* no memory */
 
 	ds->rule = *newrule; /* set rule */
 
 	spin_lock_irqsave(&divert_lock, flags);
 
-	if (idx >= 0)
-	{ ds1 = table_head;
+	if (idx >= 0) {
+		ds1 = table_head;
 		while ((ds1) && (idx > 0))
 		{ idx--;
 			ds1 = ds1->next;
@@ -294,17 +291,16 @@
 		if (!ds1) idx = -1;
 	}
 
-	if (idx < 0)
-	{ ds->prev = table_tail; /* previous entry */
+	if (idx < 0) {
+		ds->prev = table_tail; /* previous entry */
 		ds->next = NULL; /* end of chain */
 		if (ds->prev)
 			ds->prev->next = ds; /* last forward */
 		else
 			table_head = ds; /* is first entry */
 		table_tail = ds; /* end of queue */
-	}
-	else
-	{ ds->next = ds1; /* next entry */
+	} else {
+		ds->next = ds1; /* next entry */
 		ds->prev = ds1->prev; /* prev entry */
 		ds1->prev = ds; /* backward chain old element */
 		if (!ds->prev)
@@ -319,17 +315,18 @@
 /* delete the rule at position idx */
 /***********************************/
 int deleterule(int idx)
-{ struct deflect_struc *ds, *ds1;
+{
+	struct deflect_struc *ds, *ds1;
 	unsigned long flags;
 
-	if (idx < 0)
-	{ spin_lock_irqsave(&divert_lock, flags);
+	if (idx < 0) {
+		spin_lock_irqsave(&divert_lock, flags);
 		ds = table_head;
 		table_head = NULL;
 		table_tail = NULL;
 		spin_unlock_irqrestore(&divert_lock, flags);
-		while (ds)
-		{ ds1 = ds;
+		while (ds) {
+			ds1 = ds;
 			ds = ds->next;
 			kfree(ds1);
 		}
@@ -339,13 +336,12 @@
 	spin_lock_irqsave(&divert_lock, flags);
 	ds = table_head;
 
-	while ((ds) && (idx > 0))
-	{ idx--;
+	while ((ds) && (idx > 0)) {
+		idx--;
 		ds = ds->next;
 	}
 
-	if (!ds)
-	{
+	if (!ds) {
 		spin_unlock_irqrestore(&divert_lock, flags);
 		return (-EINVAL);
 	}
@@ -369,12 +365,13 @@
 /* get a pointer to a specific rule number */
 /*******************************************/
 divert_rule *getruleptr(int idx)
-{ struct deflect_struc *ds = table_head;
+{
+	struct deflect_struc *ds = table_head;
 
 	if (idx < 0) return (NULL);
-	while ((ds) && (idx >= 0))
-	{ if (!(idx--))
-		{ return (&ds->rule);
+	while ((ds) && (idx >= 0)) {
+		if (!(idx--)) {
+			return (&ds->rule);
 			break;
 		}
 		ds = ds->next;
@@ -386,7 +383,8 @@
 /* called from common module on an incoming call */
 /*************************************************/
 static int isdn_divert_icall(isdn_ctrl *ic)
-{ int retval = 0;
+{
+	int retval = 0;
 	unsigned long flags;
 	struct call_struc *cs = NULL;
 	struct deflect_struc *dv;
@@ -394,8 +392,8 @@
 	u_char accept;
 
 	/* first check the internal deflection table */
-	for (dv = table_head; dv; dv = dv->next)
-	{ /* scan table */
+	for (dv = table_head; dv; dv = dv->next) {
+		/* scan table */
 		if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
 		    ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
 			continue; /* call option check */
@@ -409,10 +407,10 @@
 		p = dv->rule.my_msn;
 		p1 = ic->parm.setup.eazmsn;
 		accept = 0;
-		while (*p)
-		{ /* complete compare */
-			if (*p == '-')
-			{ accept = 1; /* call accepted */
+		while (*p) {
+			/* complete compare */
+			if (*p == '-') {
+				accept = 1; /* call accepted */
 				break;
 			}
 			if (*p++ != *p1++)
@@ -422,14 +420,15 @@
 		} /* complete compare */
 		if (!accept) continue; /* not accepted */
 
-		if ((strcmp(dv->rule.caller, "0")) || (ic->parm.setup.phone[0]))
-		{ p = dv->rule.caller;
+		if ((strcmp(dv->rule.caller, "0")) ||
+		    (ic->parm.setup.phone[0])) {
+			p = dv->rule.caller;
 			p1 = ic->parm.setup.phone;
 			accept = 0;
-			while (*p)
-			{ /* complete compare */
-				if (*p == '-')
-				{ accept = 1; /* call accepted */
+			while (*p) {
+				/* complete compare */
+				if (*p == '-') {
+					accept = 1; /* call accepted */
 					break;
 				}
 				if (*p++ != *p1++)
@@ -440,10 +439,10 @@
 			if (!accept) continue; /* not accepted */
 		}
 
-		switch (dv->rule.action)
-		{ case DEFLECT_IGNORE:
-				return (0);
-				break;
+		switch (dv->rule.action) {
+		case DEFLECT_IGNORE:
+			return (0);
+			break;
 
 		case DEFLECT_ALERT:
 		case DEFLECT_PROCEED:
@@ -465,31 +464,29 @@
 			cs->ics.parm.setup.screen = dv->rule.screen;
 			if (dv->rule.waittime)
 				cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
+			else if (dv->rule.action == DEFLECT_PROCEED)
+				cs->timer.expires = jiffies + (HZ * extern_wait_max);
 			else
-				if (dv->rule.action == DEFLECT_PROCEED)
-					cs->timer.expires = jiffies + (HZ * extern_wait_max);
-				else
-					cs->timer.expires = 0;
+				cs->timer.expires = 0;
 			cs->akt_state = dv->rule.action;
 			spin_lock_irqsave(&divert_lock, flags);
 			cs->divert_id = next_id++; /* new sequence number */
 			spin_unlock_irqrestore(&divert_lock, flags);
 			cs->prev = NULL;
-			if (cs->akt_state == DEFLECT_ALERT)
-			{ strcpy(cs->deflect_dest, dv->rule.to_nr);
-				if (!cs->timer.expires)
-				{ strcpy(ic->parm.setup.eazmsn, "Testtext direct");
+			if (cs->akt_state == DEFLECT_ALERT) {
+				strcpy(cs->deflect_dest, dv->rule.to_nr);
+				if (!cs->timer.expires) {
+					strcpy(ic->parm.setup.eazmsn,
+					       "Testtext direct");
 					ic->parm.setup.screen = dv->rule.screen;
 					strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
 					cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
 					cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
 					retval = 5;
-				}
-				else
+				} else
 					retval = 1; /* alerting */
-			}
-			else
-			{ cs->deflect_dest[0] = '\0';
+			} else {
+				cs->deflect_dest[0] = '\0';
 				retval = 4; /* only proceed */
 			}
 			sprintf(cs->info, "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
@@ -505,8 +502,8 @@
 				dv->rule.waittime,
 				cs->deflect_dest);
 			if ((dv->rule.action == DEFLECT_REPORT) ||
-			    (dv->rule.action == DEFLECT_REJECT))
-			{ put_info_buffer(cs->info);
+			    (dv->rule.action == DEFLECT_REJECT)) {
+				put_info_buffer(cs->info);
 				kfree(cs); /* remove */
 				return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
 			}
@@ -519,8 +516,8 @@
 		break;
 	} /* scan_table */
 
-	if (cs)
-	{ cs->prev = NULL;
+	if (cs) {
+		cs->prev = NULL;
 		spin_lock_irqsave(&divert_lock, flags);
 		cs->next = divert_head;
 		divert_head = cs;
@@ -529,21 +526,21 @@
 
 		put_info_buffer(cs->info);
 		return (retval);
-	}
-	else
+	} else
 		return (0);
 } /* isdn_divert_icall */
 
 
 void deleteprocs(void)
-{ struct call_struc *cs, *cs1;
+{
+	struct call_struc *cs, *cs1;
 	unsigned long flags;
 
 	spin_lock_irqsave(&divert_lock, flags);
 	cs = divert_head;
 	divert_head = NULL;
-	while (cs)
-	{ del_timer(&cs->timer);
+	while (cs) {
+		del_timer(&cs->timer);
 		cs1 = cs;
 		cs = cs->next;
 		kfree(cs1);
@@ -555,12 +552,13 @@
 /* put a address including address type into buffer */
 /****************************************************/
 static int put_address(char *st, u_char *p, int len)
-{ u_char retval = 0;
+{
+	u_char retval = 0;
 	u_char adr_typ = 0; /* network standard */
 
 	if (len < 2) return (retval);
-	if (*p == 0xA1)
-	{ retval = *(++p) + 2; /* total length */
+	if (*p == 0xA1) {
+		retval = *(++p) + 2; /* total length */
 		if (retval > len) return (0); /* too short */
 		len = retval - 2; /* remaining length */
 		if (len < 3) return (0);
@@ -572,16 +570,13 @@
 		if (*p++ != 0x12) return (0);
 		if (*p > len) return (0); /* check number length */
 		len = *p++;
-	}
-	else
-		if (*p == 0x80)
-		{ retval = *(++p) + 2; /* total length */
-			if (retval > len) return (0);
-			len = retval - 2;
-			p++;
-		}
-		else
-			return (0); /* invalid address information */
+	} else if (*p == 0x80) {
+		retval = *(++p) + 2; /* total length */
+		if (retval > len) return (0);
+		len = retval - 2;
+		p++;
+	} else
+		return (0); /* invalid address information */
 
 	sprintf(st, "%d ", adr_typ);
 	st += strlen(st);
@@ -598,7 +593,8 @@
 /* report a successful interrogation */
 /*************************************/
 static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
-{ char *src = ic->parm.dss1_io.data;
+{
+	char *src = ic->parm.dss1_io.data;
 	int restlen = ic->parm.dss1_io.datalen;
 	int cnt = 1;
 	u_char n, n1;
@@ -608,50 +604,44 @@
 	if (*src++ != 0x30) return (-101);
 	if ((n = *src++) > 0x81) return (-102); /* invalid length field */
 	restlen -= 2; /* remaining bytes */
-	if (n == 0x80)
-	{ if (restlen < 2) return (-103);
+	if (n == 0x80) {
+		if (restlen < 2) return (-103);
 		if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
 		restlen -= 2;
-	}
+	} else if (n == 0x81) {
+		n = *src++;
+		restlen--;
+		if (n > restlen) return (-105);
+		restlen = n;
+	} else if (n > restlen)
+		return (-106);
 	else
-		if (n == 0x81)
-		{ n = *src++;
-			restlen--;
-			if (n > restlen) return (-105);
-			restlen = n;
-		}
-		else
-			if (n > restlen) return (-106);
-			else
-				restlen = n; /* standard format */
+		restlen = n; /* standard format */
 	if (restlen < 3) return (-107); /* no procedure */
 	if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
 	restlen -= 3;
 	if (restlen < 2) return (-109); /* list missing */
-	if (*src == 0x31)
-	{ src++;
+	if (*src == 0x31) {
+		src++;
 		if ((n = *src++) > 0x81) return (-110); /* invalid length field */
 		restlen -= 2; /* remaining bytes */
-		if (n == 0x80)
-		{ if (restlen < 2) return (-111);
+		if (n == 0x80) {
+			if (restlen < 2) return (-111);
 			if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
 			restlen -= 2;
-		}
+		} else if (n == 0x81) {
+			n = *src++;
+			restlen--;
+			if (n > restlen) return (-113);
+			restlen = n;
+		} else if (n > restlen)
+			return (-114);
 		else
-			if (n == 0x81)
-			{ n = *src++;
-				restlen--;
-				if (n > restlen) return (-113);
-				restlen = n;
-			}
-			else
-				if (n > restlen) return (-114);
-				else
-					restlen = n; /* standard format */
+			restlen = n; /* standard format */
 	} /* result list header */
 
-	while (restlen >= 2)
-	{ stp = st;
+	while (restlen >= 2) {
+		stp = st;
 		sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
 			cnt++, divert_if.drv_to_name(ic->driver));
 		stp += strlen(stp);
@@ -674,8 +664,8 @@
 		sprintf(stp, "%d ", (*p++) & 0xFF);
 		stp += strlen(stp);
 		n -= 6;
-		if (n > 2)
-		{ if (*p++ != 0x30) continue;
+		if (n > 2) {
+			if (*p++ != 0x30) continue;
 			if (*p > (n - 2)) continue;
 			n = *p++;
 			if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
@@ -692,58 +682,58 @@
 /* callback for protocol specific extensions */
 /*********************************************/
 static int prot_stat_callback(isdn_ctrl *ic)
-{ struct call_struc *cs, *cs1;
+{
+	struct call_struc *cs, *cs1;
 	int i;
 	unsigned long flags;
 
 	cs = divert_head; /* start of list */
 	cs1 = NULL;
-	while (cs)
-	{ if (ic->driver == cs->ics.driver)
-		{ switch (cs->ics.arg)
-			{ case DSS1_CMD_INVOKE:
-					if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
-					    (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
-					{ switch (ic->arg)
-						{  case DSS1_STAT_INVOKE_ERR:
-								sprintf(cs->info, "128 0x%lx 0x%x\n",
-									ic->parm.dss1_io.ll_id,
-									ic->parm.dss1_io.timeout);
-								put_info_buffer(cs->info);
-								break;
+	while (cs) {
+		if (ic->driver == cs->ics.driver) {
+			switch (cs->ics.arg) {
+			case DSS1_CMD_INVOKE:
+				if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
+				    (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
+					switch (ic->arg) {
+					case DSS1_STAT_INVOKE_ERR:
+						sprintf(cs->info, "128 0x%lx 0x%x\n",
+							ic->parm.dss1_io.ll_id,
+							ic->parm.dss1_io.timeout);
+						put_info_buffer(cs->info);
+						break;
 
-						case DSS1_STAT_INVOKE_RES:
-							switch (cs->ics.parm.dss1_io.proc)
-							{  case  7:
-							case  8:
-								put_info_buffer(cs->info);
-								break;
+					case DSS1_STAT_INVOKE_RES:
+						switch (cs->ics.parm.dss1_io.proc) {
+						case  7:
+						case  8:
+							put_info_buffer(cs->info);
+							break;
 
-							case  11:
-								i = interrogate_success(ic, cs);
-								if (i)
-									sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
-										ic->parm.dss1_io.ll_id, i);
-								put_info_buffer(cs->info);
-								break;
-
-							default:
-								printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
-								break;
-							}
-
-
+						case  11:
+							i = interrogate_success(ic, cs);
+							if (i)
+								sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
+									ic->parm.dss1_io.ll_id, i);
+							put_info_buffer(cs->info);
 							break;
 
 						default:
-							printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
+							printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
 							break;
 						}
-						cs1 = cs; /* remember structure */
-						cs = NULL;
-						continue; /* abort search */
-					} /* id found */
-					break;
+
+						break;
+
+					default:
+						printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
+						break;
+					}
+					cs1 = cs; /* remember structure */
+					cs = NULL;
+					continue; /* abort search */
+				} /* id found */
+				break;
 
 			case DSS1_CMD_INVOKE_ABORT:
 				printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
@@ -757,13 +747,12 @@
 		} /* driver ok */
 	}
 
-	if (!cs1)
-	{ printk(KERN_WARNING "dss1_divert unhandled process\n");
+	if (!cs1) {
+		printk(KERN_WARNING "dss1_divert unhandled process\n");
 		return (0);
 	}
 
-	if (cs1->ics.driver == -1)
-	{
+	if (cs1->ics.driver == -1) {
 		spin_lock_irqsave(&divert_lock, flags);
 		del_timer(&cs1->timer);
 		if (cs1->prev)
@@ -784,20 +773,22 @@
 /* status callback from HL */
 /***************************/
 static int isdn_divert_stat_callback(isdn_ctrl *ic)
-{ struct call_struc *cs, *cs1;
+{
+	struct call_struc *cs, *cs1;
 	unsigned long flags;
 	int retval;
 
 	retval = -1;
 	cs = divert_head; /* start of list */
-	while (cs)
-	{ if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
-		{ switch (ic->command)
-			{ case ISDN_STAT_DHUP:
-					sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
-					del_timer(&cs->timer);
-					cs->ics.driver = -1;
-					break;
+	while (cs) {
+		if ((ic->driver == cs->ics.driver) &&
+		    (ic->arg == cs->ics.arg)) {
+			switch (ic->command) {
+			case ISDN_STAT_DHUP:
+				sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
+				del_timer(&cs->timer);
+				cs->ics.driver = -1;
+				break;
 
 			case ISDN_STAT_CAUSE:
 				sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
@@ -818,8 +809,7 @@
 		}
 		cs1 = cs;
 		cs = cs->next;
-		if (cs1->ics.driver == -1)
-		{
+		if (cs1->ics.driver == -1) {
 			spin_lock_irqsave(&divert_lock, flags);
 			if (cs1->prev)
 				cs1->prev->next = cs1->next; /* forward link */
@@ -840,20 +830,19 @@
 /********************/
 int ll_callback(isdn_ctrl *ic)
 {
-	switch (ic->command)
-	{ case ISDN_STAT_ICALL:
+	switch (ic->command) {
+	case ISDN_STAT_ICALL:
 	case ISDN_STAT_ICALLW:
 		return (isdn_divert_icall(ic));
 		break;
 
 	case ISDN_STAT_PROT:
-		if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
-		{ if (ic->arg != DSS1_STAT_INVOKE_BRD)
+		if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
+			if (ic->arg != DSS1_STAT_INVOKE_BRD)
 				return (prot_stat_callback(ic));
 			else
 				return (0); /* DSS1 invoke broadcast */
-		}
-		else
+		} else
 			return (-1); /* protocol not euro */
 
 	default:
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
index 42f2893..55033dd8 100644
--- a/drivers/isdn/divert/isdn_divert.h
+++ b/drivers/isdn/divert/isdn_divert.h
@@ -43,8 +43,8 @@
 
 #define DEFLECT_ALL_IDS   0xFFFFFFFF /* all drivers selected */
 
-typedef struct
-{ ulong drvid;     /* driver ids, bit mapped */
+typedef struct {
+	ulong drvid;     /* driver ids, bit mapped */
 	char my_msn[35]; /* desired msn, subaddr allowed */
 	char caller[35]; /* caller id, partial string with * + subaddr allowed */
 	char to_nr[35];  /* deflected to number incl. subaddress */
@@ -65,18 +65,18 @@
 	u_char waittime; /* maximum wait time for proceeding */
 } divert_rule;
 
-typedef union
-{ int drv_version; /* return of driver version */
-	struct
-	{ int drvid;		/* id of driver */
+typedef union {
+	int drv_version; /* return of driver version */
+	struct {
+		int drvid;		/* id of driver */
 		char drvnam[30];	/* name of driver */
 	} getid;
-	struct
-	{ int ruleidx;	/* index of rule */
+	struct {
+		int ruleidx;	/* index of rule */
 		divert_rule rule;	/* rule parms */
 	} getsetrule;
-	struct
-	{ u_char subcmd;  /* 0 = hangup/reject,
+	struct {
+		u_char subcmd;  /* 0 = hangup/reject,
 			     1 = alert,
 			     2 = deflect */
 		ulong callid;   /* id of call delivered by ascii output */
@@ -84,8 +84,8 @@
 				   else uus1 string (maxlen 31),
 				   data from rule used if empty */
 	} fwd_ctrl;
-	struct
-	{ int drvid;      /* id of driver */
+	struct {
+		int drvid;      /* id of driver */
 		u_char cfproc;  /* cfu = 0, cfb = 1, cfnr = 2 */
 		ulong procid;   /* process id returned when no error */
 		u_char service; /* basically coded service, 0 = all */
@@ -104,8 +104,8 @@
 /**************************************************/
 /* structure keeping ascii info for device output */
 /**************************************************/
-struct divert_info
-{ struct divert_info *next;
+struct divert_info {
+	struct divert_info *next;
 	ulong usage_cnt; /* number of files still to work */
 	char info_start[2]; /* info string start */
 };
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 6849a11..7c78144 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -467,11 +467,6 @@
 
 	mutex_lock(&cs->mutex);
 
-	if (!cs->bcs)
-		goto f_cs;
-	if (!cs->inbuf)
-		goto f_bcs;
-
 	spin_lock_irqsave(&cs->lock, flags);
 	cs->running = 0;
 	spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
@@ -507,17 +502,16 @@
 		gig_dbg(DEBUG_INIT, "clearing at_state");
 		clear_at_state(&cs->at_state);
 		dealloc_temp_at_states(cs);
+		clear_events(cs);
 		tty_port_destroy(&cs->port);
 
 		/* fall through */
 	case 0:	/* error in basic setup */
-		clear_events(cs);
 		gig_dbg(DEBUG_INIT, "freeing inbuf");
 		kfree(cs->inbuf);
+		kfree(cs->bcs);
 	}
-f_bcs:	gig_dbg(DEBUG_INIT, "freeing bcs[]");
-	kfree(cs->bcs);
-f_cs:	gig_dbg(DEBUG_INIT, "freeing cs");
+
 	mutex_unlock(&cs->mutex);
 	free_cs(cs);
 }
@@ -687,19 +681,6 @@
 		return NULL;
 	}
 
-	gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
-	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
-	if (!cs->bcs) {
-		pr_err("out of memory\n");
-		goto error;
-	}
-	gig_dbg(DEBUG_INIT, "allocating inbuf");
-	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
-	if (!cs->inbuf) {
-		pr_err("out of memory\n");
-		goto error;
-	}
-
 	cs->cs_init = 0;
 	cs->channels = channels;
 	cs->onechannel = onechannel;
@@ -729,6 +710,12 @@
 	cs->mode = M_UNKNOWN;
 	cs->mstate = MS_UNINITIALIZED;
 
+	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
+	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
+	if (!cs->bcs || !cs->inbuf) {
+		pr_err("out of memory\n");
+		goto error;
+	}
 	++cs->cs_init;
 
 	gig_dbg(DEBUG_INIT, "setting up at_state");
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 2e6963d..7459b12 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -351,10 +351,11 @@
 
 
 static const struct resp_type_t {
-	unsigned char	*response;
-	int		resp_code;
-	int		type;
-} resp_type[] =
+	char	*response;
+	int	resp_code;
+	int	type;
+}
+resp_type[] =
 {
 	{"OK",		RSP_OK,		RT_NOTHING},
 	{"ERROR",	RSP_ERROR,	RT_NOTHING},
@@ -374,11 +375,12 @@
 };
 
 static const struct zsau_resp_t {
-	unsigned char	*str;
-	int		code;
-} zsau_resp[] =
+	char	*str;
+	int	code;
+}
+zsau_resp[] =
 {
-	{"OUTGOING_CALL_PROCEEDING",	ZSAU_OUTGOING_CALL_PROCEEDING},
+	{"OUTGOING_CALL_PROCEEDING",	ZSAU_PROCEEDING},
 	{"CALL_DELIVERED",		ZSAU_CALL_DELIVERED},
 	{"ACTIVE",			ZSAU_ACTIVE},
 	{"DISCONNECT_IND",		ZSAU_DISCONNECT_IND},
@@ -434,7 +436,7 @@
 	len = cs->cbytes;
 	if (!len) {
 		/* ignore additional LFs/CRs (M10x config mode or cx100) */
-		gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
+		gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[0]);
 		return;
 	}
 	cs->respdata[len] = 0;
@@ -707,27 +709,29 @@
 	cs->commands_pending = 1;
 }
 
-/* Add "AT" to a command, add the cid, dle encode it, send the result to the
-   hardware. */
-static void send_command(struct cardstate *cs, const char *cmd, int cid,
-			 int dle, gfp_t kmallocflags)
+/* send an AT command
+ * adding the "AT" prefix, cid and DLE encapsulation as appropriate
+ */
+static void send_command(struct cardstate *cs, const char *cmd,
+			 struct at_state_t *at_state)
 {
+	int cid = at_state->cid;
 	struct cmdbuf_t *cb;
 	size_t buflen;
 
 	buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */
-	cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags);
+	cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, GFP_ATOMIC);
 	if (!cb) {
 		dev_err(cs->dev, "%s: out of memory\n", __func__);
 		return;
 	}
 	if (cid > 0 && cid <= 65535)
 		cb->len = snprintf(cb->buf, buflen,
-				   dle ? "\020(AT%d%s\020)" : "AT%d%s",
+				   cs->dle ? "\020(AT%d%s\020)" : "AT%d%s",
 				   cid, cmd);
 	else
 		cb->len = snprintf(cb->buf, buflen,
-				   dle ? "\020(AT%s\020)" : "AT%s",
+				   cs->dle ? "\020(AT%s\020)" : "AT%s",
 				   cmd);
 	cb->offset = 0;
 	cb->next = NULL;
@@ -886,7 +890,7 @@
 		gigaset_isdn_stop(cs);
 	}
 
-	/* The rest is done by cleanup_cs () in user mode. */
+	/* The rest is done by cleanup_cs() in process context. */
 
 	cs->cmd_result = -ENODEV;
 	cs->waiting = 0;
@@ -976,10 +980,9 @@
 }
 
 static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
-			 struct at_state_t **p_at_state)
+			 struct at_state_t *at_state)
 {
 	int retval;
-	struct at_state_t *at_state = *p_at_state;
 
 	retval = gigaset_isdn_icall(at_state);
 	switch (retval) {
@@ -1176,7 +1179,7 @@
 		spin_unlock_irqrestore(&cs->lock, flags);
 		break;
 	case ACT_ICALL:
-		handle_icall(cs, bcs, p_at_state);
+		handle_icall(cs, bcs, at_state);
 		break;
 	case ACT_FAILSDOWN:
 		dev_warn(cs->dev, "Could not shut down the device.\n");
@@ -1264,7 +1267,7 @@
 			cs->commands_pending = 1;
 			break;
 		}
-		/* fall through */
+		/* bad cid: fall through */
 	case ACT_FAILCID:
 		cs->cur_at_seq = SEQ_NONE;
 		channel = cs->curchannel;
@@ -1339,7 +1342,6 @@
 			*p_resp_code = RSP_ERROR;
 			break;
 		}
-		/*at_state->getstring = 1;*/
 		cs->gotfwver = 0;
 		break;
 	case ACT_GOTVER:
@@ -1471,7 +1473,6 @@
 	int rcode;
 	int genresp = 0;
 	int resp_code = RSP_ERROR;
-	int sendcid;
 	struct at_state_t *at_state;
 	int index;
 	int curact;
@@ -1499,7 +1500,6 @@
 		at_state->ConState, ev->type);
 
 	bcs = at_state->bcs;
-	sendcid = at_state->cid;
 
 	/* Setting the pointer to the dial array */
 	rep = at_state->replystruct;
@@ -1510,10 +1510,12 @@
 		    || !at_state->timer_active) {
 			ev->type = RSP_NONE; /* old timeout */
 			gig_dbg(DEBUG_EVENT, "old timeout");
-		} else if (!at_state->waiting)
-			gig_dbg(DEBUG_EVENT, "timeout occurred");
-		else
-			gig_dbg(DEBUG_EVENT, "stopped waiting");
+		} else {
+			if (at_state->waiting)
+				gig_dbg(DEBUG_EVENT, "stopped waiting");
+			else
+				gig_dbg(DEBUG_EVENT, "timeout occurred");
+		}
 	}
 	spin_unlock_irqrestore(&cs->lock, flags);
 
@@ -1561,45 +1563,40 @@
 		do_action(rep->action[curact], cs, bcs, &at_state, &p_command,
 			  &genresp, &resp_code, ev);
 		if (!at_state)
-			break; /* may be freed after disconnect */
+			/* at_state destroyed by disconnect */
+			return;
 	}
 
-	if (at_state) {
-		/* Jump to the next con-state regarding the array */
-		if (rep->new_ConState >= 0)
-			at_state->ConState = rep->new_ConState;
+	/* Jump to the next con-state regarding the array */
+	if (rep->new_ConState >= 0)
+		at_state->ConState = rep->new_ConState;
 
-		if (genresp) {
-			spin_lock_irqsave(&cs->lock, flags);
+	if (genresp) {
+		spin_lock_irqsave(&cs->lock, flags);
+		at_state->timer_expires = 0;
+		at_state->timer_active = 0;
+		spin_unlock_irqrestore(&cs->lock, flags);
+		gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL);
+	} else {
+		/* Send command to modem if not NULL... */
+		if (p_command) {
+			if (cs->connected)
+				send_command(cs, p_command, at_state);
+			else
+				gigaset_add_event(cs, at_state, RSP_NODEV,
+						  NULL, 0, NULL);
+		}
+
+		spin_lock_irqsave(&cs->lock, flags);
+		if (!rep->timeout) {
 			at_state->timer_expires = 0;
 			at_state->timer_active = 0;
-			spin_unlock_irqrestore(&cs->lock, flags);
-			gigaset_add_event(cs, at_state, resp_code,
-					  NULL, 0, NULL);
-		} else {
-			/* Send command to modem if not NULL... */
-			if (p_command) {
-				if (cs->connected)
-					send_command(cs, p_command,
-						     sendcid, cs->dle,
-						     GFP_ATOMIC);
-				else
-					gigaset_add_event(cs, at_state,
-							  RSP_NODEV,
-							  NULL, 0, NULL);
-			}
-
-			spin_lock_irqsave(&cs->lock, flags);
-			if (!rep->timeout) {
-				at_state->timer_expires = 0;
-				at_state->timer_active = 0;
-			} else if (rep->timeout > 0) { /* new timeout */
-				at_state->timer_expires = rep->timeout * 10;
-				at_state->timer_active = 1;
-				++at_state->timer_index;
-			}
-			spin_unlock_irqrestore(&cs->lock, flags);
+		} else if (rep->timeout > 0) { /* new timeout */
+			at_state->timer_expires = rep->timeout * 10;
+			at_state->timer_active = 1;
+			++at_state->timer_index;
 		}
+		spin_unlock_irqrestore(&cs->lock, flags);
 	}
 }
 
@@ -1693,6 +1690,11 @@
 	for (i = 0; i < cs->channels; ++i) {
 		bcs = cs->bcs + i;
 		if (bcs->at_state.pending_commands & PC_HUP) {
+			if (cs->dle) {
+				cs->curchannel = bcs->channel;
+				schedule_sequence(cs, &cs->at_state, SEQ_DLE0);
+				return;
+			}
 			bcs->at_state.pending_commands &= ~PC_HUP;
 			if (bcs->at_state.pending_commands & PC_CID) {
 				/* not yet dialing: PC_NOCID is sufficient */
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 8e2fc8f..eb63a0f 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -111,11 +111,10 @@
 
 /* connection state */
 #define ZSAU_NONE			0
-#define ZSAU_DISCONNECT_IND		4
-#define ZSAU_OUTGOING_CALL_PROCEEDING	1
 #define ZSAU_PROCEEDING			1
 #define ZSAU_CALL_DELIVERED		2
 #define ZSAU_ACTIVE			3
+#define ZSAU_DISCONNECT_IND		4
 #define ZSAU_NULL			5
 #define ZSAU_DISCONNECT_REQ		6
 #define ZSAU_UNKNOWN			-1
@@ -183,18 +182,22 @@
 #define AT_NUM		7
 
 /* variables in struct at_state_t */
+/* - numeric */
 #define VAR_ZSAU	0
 #define VAR_ZDLE	1
 #define VAR_ZCTP	2
+/* total number */
 #define VAR_NUM		3
-
+/* - string */
 #define STR_NMBR	0
 #define STR_ZCPN	1
 #define STR_ZCON	2
 #define STR_ZBC		3
 #define STR_ZHLC	4
+/* total number */
 #define STR_NUM		5
 
+/* event types */
 #define EV_TIMEOUT	-105
 #define EV_IF_VER	-106
 #define EV_PROC_CIDMODE	-107
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 67abf3f..20b7e7a 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -112,36 +112,6 @@
 }
 
 /*** the terminal driver ***/
-/* stolen from usbserial and some other tty drivers */
-
-static int  if_open(struct tty_struct *tty, struct file *filp);
-static void if_close(struct tty_struct *tty, struct file *filp);
-static int  if_ioctl(struct tty_struct *tty,
-		     unsigned int cmd, unsigned long arg);
-static int  if_write_room(struct tty_struct *tty);
-static int  if_chars_in_buffer(struct tty_struct *tty);
-static void if_throttle(struct tty_struct *tty);
-static void if_unthrottle(struct tty_struct *tty);
-static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
-static int  if_tiocmget(struct tty_struct *tty);
-static int  if_tiocmset(struct tty_struct *tty,
-			unsigned int set, unsigned int clear);
-static int  if_write(struct tty_struct *tty,
-		     const unsigned char *buf, int count);
-
-static const struct tty_operations if_ops = {
-	.open =			if_open,
-	.close =		if_close,
-	.ioctl =		if_ioctl,
-	.write =		if_write,
-	.write_room =		if_write_room,
-	.chars_in_buffer =	if_chars_in_buffer,
-	.set_termios =		if_set_termios,
-	.throttle =		if_throttle,
-	.unthrottle =		if_unthrottle,
-	.tiocmget =		if_tiocmget,
-	.tiocmset =		if_tiocmset,
-};
 
 static int if_open(struct tty_struct *tty, struct file *filp)
 {
@@ -355,7 +325,7 @@
 static int if_write_room(struct tty_struct *tty)
 {
 	struct cardstate *cs = tty->driver_data;
-	int retval = -ENODEV;
+	int retval;
 
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
@@ -498,6 +468,20 @@
 	mutex_unlock(&cs->mutex);
 }
 
+static const struct tty_operations if_ops = {
+	.open =			if_open,
+	.close =		if_close,
+	.ioctl =		if_ioctl,
+	.write =		if_write,
+	.write_room =		if_write_room,
+	.chars_in_buffer =	if_chars_in_buffer,
+	.set_termios =		if_set_termios,
+	.throttle =		if_throttle,
+	.unthrottle =		if_unthrottle,
+	.tiocmget =		if_tiocmget,
+	.tiocmset =		if_tiocmset,
+};
+
 
 /* wakeup tasklet for the write operation */
 static void if_wake(unsigned long data)
diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h
index 0b26e3b..ca08e08 100644
--- a/drivers/isdn/i4l/isdn_x25iface.h
+++ b/drivers/isdn/i4l/isdn_x25iface.h
@@ -19,7 +19,6 @@
 #endif
 
 #include <linux/skbuff.h>
-#include <linux/wanrouter.h>
 #include <linux/isdn.h>
 #include <linux/concap.h>
 
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index 5f21f62..deda591 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/mISDNif.h>
 #include <linux/kthread.h>
+#include <linux/sched.h>
 #include "core.h"
 
 static u_int	*debug;
@@ -202,6 +203,9 @@
 mISDNStackd(void *data)
 {
 	struct mISDNstack *st = data;
+#ifdef MISDN_MSG_STATS
+	cputime_t utime, stime;
+#endif
 	int err = 0;
 
 	sigfillset(&current->blocked);
@@ -303,9 +307,10 @@
 	       "msg %d sleep %d stopped\n",
 	       dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
 	       st->stopped_cnt);
+	task_cputime(st->thread, &utime, &stime);
 	printk(KERN_DEBUG
 	       "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n",
-	       dev_name(&st->dev->dev), st->thread->utime, st->thread->stime);
+	       dev_name(&st->dev->dev), utime, stime);
 	printk(KERN_DEBUG
 	       "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
 	       dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
new file mode 100644
index 0000000..9545c9f
--- /dev/null
+++ b/drivers/mailbox/Kconfig
@@ -0,0 +1,19 @@
+menuconfig MAILBOX
+	bool "Mailbox Hardware Support"
+	help
+	  Mailbox is a framework to control hardware communication between
+	  on-chip processors through queued messages and interrupt driven
+	  signals. Say Y if your platform supports hardware mailboxes.
+
+if MAILBOX
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	depends on ARM_AMBA
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
+endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..543ad6a
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..c45b3ae
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_transmit);
+
+static irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_unregister_notifier);
+
+static int __init pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 49d9504..0223ad2 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1820,7 +1820,7 @@
 	struct dvb_frontend *fe = dvbdev->priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
-	int err = -ENOTTY;
+	int err = -EOPNOTSUPP;
 
 	dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd));
 	if (fepriv->exit != DVB_FE_NO_EXIT)
@@ -1938,7 +1938,7 @@
 		}
 
 	} else
-		err = -ENOTTY;
+		err = -EOPNOTSUPP;
 
 out:
 	kfree(tvp);
@@ -2071,7 +2071,7 @@
 	struct dvb_frontend *fe = dvbdev->priv;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-	int err = -ENOTTY;
+	int err = -EOPNOTSUPP;
 
 	switch (cmd) {
 	case FE_GET_INFO: {
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 4778bb1..8b5d685 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -750,6 +750,12 @@
 		.end = AB8500_INT_CH_WD_EXP,
 		.flags = IORESOURCE_IRQ,
 	},
+	{
+		.name = "VBUS_CH_DROP_END",
+		.start = AB8500_INT_VBUS_CH_DROP_END,
+		.end = AB8500_INT_VBUS_CH_DROP_END,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
 static struct resource ab8500_btemp_resources[] = {
@@ -1012,40 +1018,32 @@
 		.of_compatible = "stericsson,ab8500-charger",
 		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
 		.resources = ab8500_charger_resources,
-#ifndef CONFIG_OF
 		.platform_data = &ab8500_bm_data,
 		.pdata_size = sizeof(ab8500_bm_data),
-#endif
 	},
 	{
 		.name = "ab8500-btemp",
 		.of_compatible = "stericsson,ab8500-btemp",
 		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
 		.resources = ab8500_btemp_resources,
-#ifndef CONFIG_OF
 		.platform_data = &ab8500_bm_data,
 		.pdata_size = sizeof(ab8500_bm_data),
-#endif
 	},
 	{
 		.name = "ab8500-fg",
 		.of_compatible = "stericsson,ab8500-fg",
 		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
 		.resources = ab8500_fg_resources,
-#ifndef CONFIG_OF
 		.platform_data = &ab8500_bm_data,
 		.pdata_size = sizeof(ab8500_bm_data),
-#endif
 	},
 	{
 		.name = "ab8500-chargalg",
 		.of_compatible = "stericsson,ab8500-chargalg",
 		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
 		.resources = ab8500_chargalg_resources,
-#ifndef CONFIG_OF
 		.platform_data = &ab8500_bm_data,
 		.pdata_size = sizeof(ab8500_bm_data),
-#endif
 	},
 };
 
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 49d361a..77ee26ef 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/of_irq.h>
 #include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
 #include <linux/mutex.h>
@@ -60,6 +61,15 @@
 	},
 };
 
+#ifdef CONFIG_OF
+static struct of_device_id sec_dt_match[] = {
+	{	.compatible = "samsung,s5m8767-pmic",
+		.data = (void *)S5M8767X,
+	},
+	{},
+};
+#endif
+
 int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest)
 {
 	return regmap_read(sec_pmic->regmap, reg, dest);
@@ -95,6 +105,57 @@
 	.val_bits = 8,
 };
 
+
+#ifdef CONFIG_OF
+/*
+ * Only the common platform data elements for s5m8767 are parsed here from the
+ * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
+ * others have to parse their own platform data elements from device tree.
+ *
+ * The s5m8767 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+					struct device *dev)
+{
+	struct sec_platform_data *pd;
+
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd) {
+		dev_err(dev, "could not allocate memory for pdata\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/*
+	 * ToDo: the 'wakeup' member in the platform data is more of a linux
+	 * specfic information. Hence, there is no binding for that yet and
+	 * not parsed here.
+	 */
+
+	return pd;
+}
+#else
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+					struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+						const struct i2c_device_id *id)
+{
+#ifdef CONFIG_OF
+	if (i2c->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(sec_dt_match, i2c->dev.of_node);
+		return (int)match->data;
+	}
+#endif
+	return (int)id->driver_data;
+}
+
 static int sec_pmic_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
@@ -111,13 +172,22 @@
 	sec_pmic->dev = &i2c->dev;
 	sec_pmic->i2c = i2c;
 	sec_pmic->irq = i2c->irq;
-	sec_pmic->type = id->driver_data;
+	sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
 
+	if (sec_pmic->dev->of_node) {
+		pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
+		if (IS_ERR(pdata)) {
+			ret = PTR_ERR(pdata);
+			return ret;
+		}
+		pdata->device_type = sec_pmic->type;
+	}
 	if (pdata) {
 		sec_pmic->device_type = pdata->device_type;
 		sec_pmic->ono = pdata->ono;
 		sec_pmic->irq_base = pdata->irq_base;
 		sec_pmic->wakeup = pdata->wakeup;
+		sec_pmic->pdata = pdata;
 	}
 
 	sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
@@ -192,6 +262,7 @@
 	.driver = {
 		   .name = "sec_pmic",
 		   .owner = THIS_MODULE,
+		   .of_match_table = of_match_ptr(sec_dt_match),
 	},
 	.probe = sec_pmic_probe,
 	.remove = sec_pmic_remove,
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 1133a64..f6fcb87 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -96,6 +96,7 @@
 	.mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
 	.ack_base = ARIZONA_AOD_IRQ1,
 	.wake_base = ARIZONA_WAKE_CONTROL,
+	.wake_invert = 1,
 	.num_regs = 1,
 	.irqs = wm5102_aod_irqs,
 	.num_irqs = ARRAY_SIZE(wm5102_aod_irqs),
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index adda6b1..c415998 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -255,6 +255,7 @@
 	.mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
 	.ack_base = ARIZONA_AOD_IRQ1,
 	.wake_base = ARIZONA_WAKE_CONTROL,
+	.wake_invert = 1,
 	.num_regs = 1,
 	.irqs = wm5110_aod_irqs,
 	.num_irqs = ARRAY_SIZE(wm5110_aod_irqs),
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 492c8ca..44d273c 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -517,7 +517,7 @@
 {
 	int ret;
 
-	if (!is_uv_system())
+	if (!is_uv_system() || (is_uvx_hub() && !is_uv2_hub()))
 		return 0;
 
 #if defined CONFIG_IA64
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 1507723..372e921 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -20,6 +20,7 @@
 #include <linux/err.h>
 #include <linux/highmem.h>
 #include <linux/log2.h>
+#include <linux/mmc/pm.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/amba/bus.h>
@@ -59,6 +60,7 @@
  * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
  * @pwrreg_powerup: power up value for MMCIPOWER register
  * @signal_direction: input/out direction of bus signals can be indicated
+ * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
  */
 struct variant_data {
 	unsigned int		clkreg;
@@ -71,6 +73,7 @@
 	bool			blksz_datactrl16;
 	u32			pwrreg_powerup;
 	bool			signal_direction;
+	bool			pwrreg_clkgate;
 };
 
 static struct variant_data variant_arm = {
@@ -87,6 +90,14 @@
 	.pwrreg_powerup		= MCI_PWR_UP,
 };
 
+static struct variant_data variant_arm_extended_fifo_hwfc = {
+	.fifosize		= 128 * 4,
+	.fifohalfsize		= 64 * 4,
+	.clkreg_enable		= MCI_ARM_HWFCEN,
+	.datalength_bits	= 16,
+	.pwrreg_powerup		= MCI_PWR_UP,
+};
+
 static struct variant_data variant_u300 = {
 	.fifosize		= 16 * 4,
 	.fifohalfsize		= 8 * 4,
@@ -95,6 +106,7 @@
 	.sdio			= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
 	.signal_direction	= true,
+	.pwrreg_clkgate		= true,
 };
 
 static struct variant_data variant_nomadik = {
@@ -106,6 +118,7 @@
 	.st_clkdiv		= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
 	.signal_direction	= true,
+	.pwrreg_clkgate		= true,
 };
 
 static struct variant_data variant_ux500 = {
@@ -118,6 +131,7 @@
 	.st_clkdiv		= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
 	.signal_direction	= true,
+	.pwrreg_clkgate		= true,
 };
 
 static struct variant_data variant_ux500v2 = {
@@ -131,9 +145,28 @@
 	.blksz_datactrl16	= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
 	.signal_direction	= true,
+	.pwrreg_clkgate		= true,
 };
 
 /*
+ * Validate mmc prerequisites
+ */
+static int mmci_validate_data(struct mmci_host *host,
+			      struct mmc_data *data)
+{
+	if (!data)
+		return 0;
+
+	if (!is_power_of_2(data->blksz)) {
+		dev_err(mmc_dev(host->mmc),
+			"unsupported block size (%d bytes)\n", data->blksz);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
  * This must be called with host->lock held
  */
 static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
@@ -202,6 +235,9 @@
 	if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 		clk |= MCI_ST_8BIT_BUS;
 
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+		clk |= MCI_ST_UX500_NEG_EDGE;
+
 	mmci_write_clkreg(host, clk);
 }
 
@@ -352,10 +388,33 @@
 	host->dma_rx_channel = host->dma_tx_channel = NULL;
 }
 
+static void mmci_dma_data_error(struct mmci_host *host)
+{
+	dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+	dmaengine_terminate_all(host->dma_current);
+	host->dma_current = NULL;
+	host->dma_desc_current = NULL;
+	host->data->host_cookie = 0;
+}
+
 static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
 {
-	struct dma_chan *chan = host->dma_current;
+	struct dma_chan *chan;
 	enum dma_data_direction dir;
+
+	if (data->flags & MMC_DATA_READ) {
+		dir = DMA_FROM_DEVICE;
+		chan = host->dma_rx_channel;
+	} else {
+		dir = DMA_TO_DEVICE;
+		chan = host->dma_tx_channel;
+	}
+
+	dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+}
+
+static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
+{
 	u32 status;
 	int i;
 
@@ -374,19 +433,13 @@
 	 * contiguous buffers.  On TX, we'll get a FIFO underrun error.
 	 */
 	if (status & MCI_RXDATAAVLBLMASK) {
-		dmaengine_terminate_all(chan);
+		mmci_dma_data_error(host);
 		if (!data->error)
 			data->error = -EIO;
 	}
 
-	if (data->flags & MMC_DATA_WRITE) {
-		dir = DMA_TO_DEVICE;
-	} else {
-		dir = DMA_FROM_DEVICE;
-	}
-
 	if (!data->host_cookie)
-		dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+		mmci_dma_unmap(host, data);
 
 	/*
 	 * Use of DMA with scatter-gather is impossible.
@@ -396,16 +449,15 @@
 		dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n");
 		mmci_dma_release(host);
 	}
+
+	host->dma_current = NULL;
+	host->dma_desc_current = NULL;
 }
 
-static void mmci_dma_data_error(struct mmci_host *host)
-{
-	dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
-	dmaengine_terminate_all(host->dma_current);
-}
-
-static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
-			      struct mmci_host_next *next)
+/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
+static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
+				struct dma_chan **dma_chan,
+				struct dma_async_tx_descriptor **dma_desc)
 {
 	struct variant_data *variant = host->variant;
 	struct dma_slave_config conf = {
@@ -423,16 +475,6 @@
 	enum dma_data_direction buffer_dirn;
 	int nr_sg;
 
-	/* Check if next job is already prepared */
-	if (data->host_cookie && !next &&
-	    host->dma_current && host->dma_desc_current)
-		return 0;
-
-	if (!next) {
-		host->dma_current = NULL;
-		host->dma_desc_current = NULL;
-	}
-
 	if (data->flags & MMC_DATA_READ) {
 		conf.direction = DMA_DEV_TO_MEM;
 		buffer_dirn = DMA_FROM_DEVICE;
@@ -462,29 +504,41 @@
 	if (!desc)
 		goto unmap_exit;
 
-	if (next) {
-		next->dma_chan = chan;
-		next->dma_desc = desc;
-	} else {
-		host->dma_current = chan;
-		host->dma_desc_current = desc;
-	}
+	*dma_chan = chan;
+	*dma_desc = desc;
 
 	return 0;
 
  unmap_exit:
-	if (!next)
-		dmaengine_terminate_all(chan);
 	dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
 	return -ENOMEM;
 }
 
+static inline int mmci_dma_prep_data(struct mmci_host *host,
+				     struct mmc_data *data)
+{
+	/* Check if next job is already prepared. */
+	if (host->dma_current && host->dma_desc_current)
+		return 0;
+
+	/* No job were prepared thus do it now. */
+	return __mmci_dma_prep_data(host, data, &host->dma_current,
+				    &host->dma_desc_current);
+}
+
+static inline int mmci_dma_prep_next(struct mmci_host *host,
+				     struct mmc_data *data)
+{
+	struct mmci_host_next *nd = &host->next_data;
+	return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
+}
+
 static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 {
 	int ret;
 	struct mmc_data *data = host->data;
 
-	ret = mmci_dma_prep_data(host, host->data, NULL);
+	ret = mmci_dma_prep_data(host, host->data);
 	if (ret)
 		return ret;
 
@@ -514,19 +568,11 @@
 {
 	struct mmci_host_next *next = &host->next_data;
 
-	if (data->host_cookie && data->host_cookie != next->cookie) {
-		pr_warning("[%s] invalid cookie: data->host_cookie %d"
-		       " host->next_data.cookie %d\n",
-		       __func__, data->host_cookie, host->next_data.cookie);
-		data->host_cookie = 0;
-	}
-
-	if (!data->host_cookie)
-		return;
+	WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
+	WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
 
 	host->dma_desc_current = next->dma_desc;
 	host->dma_current = next->dma_chan;
-
 	next->dma_desc = NULL;
 	next->dma_chan = NULL;
 }
@@ -541,19 +587,13 @@
 	if (!data)
 		return;
 
-	if (data->host_cookie) {
-		data->host_cookie = 0;
-		return;
-	}
+	BUG_ON(data->host_cookie);
 
-	/* if config for dma */
-	if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) ||
-	    ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) {
-		if (mmci_dma_prep_data(host, data, nd))
-			data->host_cookie = 0;
-		else
-			data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
-	}
+	if (mmci_validate_data(host, data))
+		return;
+
+	if (!mmci_dma_prep_next(host, data))
+		data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
 }
 
 static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
@@ -561,29 +601,23 @@
 {
 	struct mmci_host *host = mmc_priv(mmc);
 	struct mmc_data *data = mrq->data;
-	struct dma_chan *chan;
-	enum dma_data_direction dir;
 
-	if (!data)
+	if (!data || !data->host_cookie)
 		return;
 
-	if (data->flags & MMC_DATA_READ) {
-		dir = DMA_FROM_DEVICE;
-		chan = host->dma_rx_channel;
-	} else {
-		dir = DMA_TO_DEVICE;
-		chan = host->dma_tx_channel;
-	}
+	mmci_dma_unmap(host, data);
 
+	if (err) {
+		struct mmci_host_next *next = &host->next_data;
+		struct dma_chan *chan;
+		if (data->flags & MMC_DATA_READ)
+			chan = host->dma_rx_channel;
+		else
+			chan = host->dma_tx_channel;
+		dmaengine_terminate_all(chan);
 
-	/* if config for dma */
-	if (chan) {
-		if (err)
-			dmaengine_terminate_all(chan);
-		if (data->host_cookie)
-			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-				     data->sg_len, dir);
-		mrq->data->host_cookie = 0;
+		next->dma_desc = NULL;
+		next->dma_chan = NULL;
 	}
 }
 
@@ -604,6 +638,11 @@
 {
 }
 
+static inline void mmci_dma_finalize(struct mmci_host *host,
+				     struct mmc_data *data)
+{
+}
+
 static inline void mmci_dma_data_error(struct mmci_host *host)
 {
 }
@@ -680,6 +719,9 @@
 			mmci_write_clkreg(host, clk);
 		}
 
+	if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+		datactrl |= MCI_ST_DPSM_DDRMODE;
+
 	/*
 	 * Attempt to use DMA operation mode, if this
 	 * should fail, fall back to PIO mode
@@ -751,8 +793,10 @@
 		u32 remain, success;
 
 		/* Terminate the DMA transfer */
-		if (dma_inprogress(host))
+		if (dma_inprogress(host)) {
 			mmci_dma_data_error(host);
+			mmci_dma_unmap(host, data);
+		}
 
 		/*
 		 * Calculate how far we are into the transfer.  Note that
@@ -791,7 +835,7 @@
 
 	if (status & MCI_DATAEND || data->error) {
 		if (dma_inprogress(host))
-			mmci_dma_unmap(host, data);
+			mmci_dma_finalize(host, data);
 		mmci_stop_data(host);
 
 		if (!data->error)
@@ -828,8 +872,10 @@
 	if (!cmd->data || cmd->error) {
 		if (host->data) {
 			/* Terminate the DMA transfer */
-			if (dma_inprogress(host))
+			if (dma_inprogress(host)) {
 				mmci_dma_data_error(host);
+				mmci_dma_unmap(host, host->data);
+			}
 			mmci_stop_data(host);
 		}
 		mmci_request_end(host, cmd->mrq);
@@ -1055,10 +1101,8 @@
 
 	WARN_ON(host->mrq != NULL);
 
-	if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
-		dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
-			mrq->data->blksz);
-		mrq->cmd->error = -EINVAL;
+	mrq->cmd->error = mmci_validate_data(host, mrq->data);
+	if (mrq->cmd->error) {
 		mmc_request_done(mmc, mrq);
 		return;
 	}
@@ -1086,7 +1130,6 @@
 	struct variant_data *variant = host->variant;
 	u32 pwr = 0;
 	unsigned long flags;
-	int ret;
 
 	pm_runtime_get_sync(mmc_dev(mmc));
 
@@ -1096,23 +1139,13 @@
 
 	switch (ios->power_mode) {
 	case MMC_POWER_OFF:
-		if (host->vcc)
-			ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
+		if (!IS_ERR(mmc->supply.vmmc))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
 		break;
 	case MMC_POWER_UP:
-		if (host->vcc) {
-			ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
-			if (ret) {
-				dev_err(mmc_dev(mmc), "unable to set OCR\n");
-				/*
-				 * The .set_ios() function in the mmc_host_ops
-				 * struct return void, and failing to set the
-				 * power should be rare so we print an error
-				 * and return here.
-				 */
-				goto out;
-			}
-		}
+		if (!IS_ERR(mmc->supply.vmmc))
+			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
+
 		/*
 		 * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
 		 * and instead uses MCI_PWR_ON so apply whatever value is
@@ -1154,6 +1187,13 @@
 		}
 	}
 
+	/*
+	 * If clock = 0 and the variant requires the MMCIPOWER to be used for
+	 * gating the clock, the MCI_PWR_ON bit is cleared.
+	 */
+	if (!ios->clock && variant->pwrreg_clkgate)
+		pwr &= ~MCI_PWR_ON;
+
 	spin_lock_irqsave(&host->lock, flags);
 
 	mmci_set_clkreg(host, ios->clock);
@@ -1161,7 +1201,6 @@
 
 	spin_unlock_irqrestore(&host->lock, flags);
 
- out:
 	pm_runtime_mark_last_busy(mmc_dev(mmc));
 	pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
@@ -1384,32 +1423,19 @@
 	} else
 		dev_warn(&dev->dev, "could not get default pinstate\n");
 
-#ifdef CONFIG_REGULATOR
-	/* If we're using the regulator framework, try to fetch a regulator */
-	host->vcc = regulator_get(&dev->dev, "vmmc");
-	if (IS_ERR(host->vcc))
-		host->vcc = NULL;
-	else {
-		int mask = mmc_regulator_get_ocrmask(host->vcc);
-
-		if (mask < 0)
-			dev_err(&dev->dev, "error getting OCR mask (%d)\n",
-				mask);
-		else {
-			host->mmc->ocr_avail = (u32) mask;
-			if (plat->ocr_mask)
-				dev_warn(&dev->dev,
-				 "Provided ocr_mask/setpower will not be used "
-				 "(using regulator instead)\n");
-		}
-	}
-#endif
-	/* Fall back to platform data if no regulator is found */
-	if (host->vcc == NULL)
+	/* Get regulators and the supported OCR mask */
+	mmc_regulator_get_supply(mmc);
+	if (!mmc->ocr_avail)
 		mmc->ocr_avail = plat->ocr_mask;
+	else if (plat->ocr_mask)
+		dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
+
 	mmc->caps = plat->capabilities;
 	mmc->caps2 = plat->capabilities2;
 
+	/* We support these PM capabilities. */
+	mmc->pm_caps = MMC_PM_KEEP_POWER;
+
 	/*
 	 * We can do SGIO
 	 */
@@ -1585,10 +1611,6 @@
 		clk_disable_unprepare(host->clk);
 		clk_put(host->clk);
 
-		if (host->vcc)
-			mmc_regulator_set_ocr(mmc, host->vcc, 0);
-		regulator_put(host->vcc);
-
 		mmc_free_host(mmc);
 
 		amba_release_regions(dev);
@@ -1636,8 +1658,37 @@
 }
 #endif
 
+#ifdef CONFIG_PM_RUNTIME
+static int mmci_runtime_suspend(struct device *dev)
+{
+	struct amba_device *adev = to_amba_device(dev);
+	struct mmc_host *mmc = amba_get_drvdata(adev);
+
+	if (mmc) {
+		struct mmci_host *host = mmc_priv(mmc);
+		clk_disable_unprepare(host->clk);
+	}
+
+	return 0;
+}
+
+static int mmci_runtime_resume(struct device *dev)
+{
+	struct amba_device *adev = to_amba_device(dev);
+	struct mmc_host *mmc = amba_get_drvdata(adev);
+
+	if (mmc) {
+		struct mmci_host *host = mmc_priv(mmc);
+		clk_prepare_enable(host->clk);
+	}
+
+	return 0;
+}
+#endif
+
 static const struct dev_pm_ops mmci_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
+	SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
 };
 
 static struct amba_id mmci_ids[] = {
@@ -1652,6 +1703,11 @@
 		.data	= &variant_arm_extended_fifo,
 	},
 	{
+		.id	= 0x02041180,
+		.mask	= 0xff0fffff,
+		.data	= &variant_arm_extended_fifo_hwfc,
+	},
+	{
 		.id	= 0x00041181,
 		.mask	= 0x000fffff,
 		.data	= &variant_arm,
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index d34d8c0..1f33ad5 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -28,6 +28,8 @@
 #define MCI_ST_UX500_NEG_EDGE	(1 << 13)
 #define MCI_ST_UX500_HWFCEN	(1 << 14)
 #define MCI_ST_UX500_CLK_INV	(1 << 15)
+/* Modified PL180 on Versatile Express platform */
+#define MCI_ARM_HWFCEN		(1 << 12)
 
 #define MMCIARGUMENT		0x008
 #define MMCICOMMAND		0x00c
@@ -193,7 +195,6 @@
 	/* pio stuff */
 	struct sg_mapping_iter	sg_miter;
 	unsigned int		size;
-	struct regulator	*vcc;
 
 	/* pinctrl handles */
 	struct pinctrl		*pinctrl;
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index e3f0fac..3a8c753 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -37,35 +37,14 @@
    ethernet adaptor have the name "eth[0123...]".
    */
 
-extern struct net_device *ne2_probe(int unit);
 extern struct net_device *hp100_probe(int unit);
 extern struct net_device *ultra_probe(int unit);
-extern struct net_device *ultra32_probe(int unit);
 extern struct net_device *wd_probe(int unit);
-extern struct net_device *el2_probe(int unit);
 extern struct net_device *ne_probe(int unit);
-extern struct net_device *hp_probe(int unit);
-extern struct net_device *hp_plus_probe(int unit);
-extern struct net_device *express_probe(int unit);
-extern struct net_device *eepro_probe(int unit);
-extern struct net_device *at1700_probe(int unit);
 extern struct net_device *fmv18x_probe(int unit);
-extern struct net_device *eth16i_probe(int unit);
 extern struct net_device *i82596_probe(int unit);
-extern struct net_device *ewrk3_probe(int unit);
-extern struct net_device *el1_probe(int unit);
-extern struct net_device *el16_probe(int unit);
-extern struct net_device *elmc_probe(int unit);
-extern struct net_device *elplus_probe(int unit);
-extern struct net_device *ac3200_probe(int unit);
-extern struct net_device *es_probe(int unit);
-extern struct net_device *lne390_probe(int unit);
-extern struct net_device *e2100_probe(int unit);
-extern struct net_device *ni5010_probe(int unit);
-extern struct net_device *ni52_probe(int unit);
 extern struct net_device *ni65_probe(int unit);
 extern struct net_device *sonic_probe(int unit);
-extern struct net_device *seeq8005_probe(int unit);
 extern struct net_device *smc_init(int unit);
 extern struct net_device *atarilance_probe(int unit);
 extern struct net_device *sun3lance_probe(int unit);
@@ -77,13 +56,9 @@
 extern struct net_device *lance_probe(int unit);
 extern struct net_device *mac8390_probe(int unit);
 extern struct net_device *mac89x0_probe(int unit);
-extern struct net_device *mc32_probe(int unit);
 extern struct net_device *cops_probe(int unit);
 extern struct net_device *ltpc_probe(void);
 
-/* Detachable devices ("pocket adaptors") */
-extern struct net_device *de620_probe(int unit);
-
 /* Fibre Channel adapters */
 extern int iph5526_probe(struct net_device *dev);
 
@@ -111,29 +86,6 @@
 }
 
 /*
- * This is a bit of an artificial separation as there are PCI drivers
- * that also probe for EISA cards (in the PCI group) and there are ISA
- * drivers that probe for EISA cards (in the ISA group).  These are the
- * legacy EISA only driver probes, and also the legacy PCI probes
- */
-
-static struct devprobe2 eisa_probes[] __initdata = {
-#ifdef CONFIG_ULTRA32
-	{ultra32_probe, 0},
-#endif
-#ifdef CONFIG_AC3200
-	{ac3200_probe, 0},
-#endif
-#ifdef CONFIG_ES3210
-	{es_probe, 0},
-#endif
-#ifdef CONFIG_LNE390
-	{lne390_probe, 0},
-#endif
-	{NULL, 0},
-};
-
-/*
  * ISA probes that touch addresses < 0x400 (including those that also
  * look for EISA/PCI cards in addition to ISA cards).
  */
@@ -150,18 +102,6 @@
 #ifdef CONFIG_WD80x3
 	{wd_probe, 0},
 #endif
-#ifdef CONFIG_EL2 		/* 3c503 */
-	{el2_probe, 0},
-#endif
-#ifdef CONFIG_HPLAN
-	{hp_probe, 0},
-#endif
-#ifdef CONFIG_HPLAN_PLUS
-	{hp_plus_probe, 0},
-#endif
-#ifdef CONFIG_E2100		/* Cabletron E21xx series. */
-	{e2100_probe, 0},
-#endif
 #if defined(CONFIG_NE2000) || \
     defined(CONFIG_NE_H8300)  /* ISA (use ne2k-pci for PCI cards) */
 	{ne_probe, 0},
@@ -172,60 +112,20 @@
 #ifdef CONFIG_SMC9194
 	{smc_init, 0},
 #endif
-#ifdef CONFIG_SEEQ8005
-	{seeq8005_probe, 0},
-#endif
 #ifdef CONFIG_CS89x0
 #ifndef CONFIG_CS89x0_PLATFORM
  	{cs89x0_probe, 0},
 #endif
 #endif
-#ifdef CONFIG_AT1700
-	{at1700_probe, 0},
-#endif
-#ifdef CONFIG_ETH16I
-	{eth16i_probe, 0},	/* ICL EtherTeam 16i/32 */
-#endif
-#ifdef CONFIG_EEXPRESS		/* Intel EtherExpress */
-	{express_probe, 0},
-#endif
-#ifdef CONFIG_EEXPRESS_PRO	/* Intel EtherExpress Pro/10 */
-	{eepro_probe, 0},
-#endif
-#ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
-    	{ewrk3_probe, 0},
-#endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)	/* Intel I82596 */
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)	/* Intel I82596 */
 	{i82596_probe, 0},
 #endif
-#ifdef CONFIG_EL1		/* 3c501 */
-	{el1_probe, 0},
-#endif
-#ifdef CONFIG_EL16		/* 3c507 */
-	{el16_probe, 0},
-#endif
-#ifdef CONFIG_ELPLUS		/* 3c505 */
-	{elplus_probe, 0},
-#endif
-#ifdef CONFIG_NI5010
-	{ni5010_probe, 0},
-#endif
-#ifdef CONFIG_NI52
-	{ni52_probe, 0},
-#endif
 #ifdef CONFIG_NI65
 	{ni65_probe, 0},
 #endif
 	{NULL, 0},
 };
 
-static struct devprobe2 parport_probes[] __initdata = {
-#ifdef CONFIG_DE620		/* D-Link DE-620 adapter */
-	{de620_probe, 0},
-#endif
-	{NULL, 0},
-};
-
 static struct devprobe2 m68k_probes[] __initdata = {
 #ifdef CONFIG_ATARILANCE	/* Lance-based Atari ethernet boards */
 	{atarilance_probe, 0},
@@ -264,9 +164,7 @@
 		return;
 
 	(void)(	probe_list2(unit, m68k_probes, base_addr == 0) &&
-		probe_list2(unit, eisa_probes, base_addr == 0) &&
-		probe_list2(unit, isa_probes, base_addr == 0) &&
-		probe_list2(unit, parport_probes, base_addr == 0));
+		probe_list2(unit, isa_probes, base_addr == 0));
 }
 
 /*  Statically configured drivers -- order matters here. */
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index a030e63..fc58d11 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -389,13 +389,13 @@
 
 /**
  * __initialize_port_locks - initialize a port's STATE machine spinlock
- * @port: the port we're looking at
+ * @port: the slave of the port we're looking at
  *
  */
-static inline void __initialize_port_locks(struct port *port)
+static inline void __initialize_port_locks(struct slave *slave)
 {
 	// make sure it isn't called twice
-	spin_lock_init(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
+	spin_lock_init(&(SLAVE_AD_INFO(slave).state_machine_lock));
 }
 
 //conversions
@@ -1127,7 +1127,7 @@
 				// INFO_RECEIVED_LOOPBACK_FRAMES
 				pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
 				       "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
-				       port->slave->dev->master->name, port->slave->dev->name);
+				       port->slave->bond->dev->name, port->slave->dev->name);
 				return;
 			}
 			__update_selected(lacpdu, port);
@@ -1306,7 +1306,7 @@
 		}
 		if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
 			pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
-				   port->slave->dev->master->name,
+				   port->slave->bond->dev->name,
 				   port->actor_port_number,
 				   port->slave->dev->name,
 				   port->aggregator->aggregator_identifier);
@@ -1386,7 +1386,7 @@
 				 port->aggregator->aggregator_identifier);
 		} else {
 			pr_err("%s: Port %d (on %s) did not find a suitable aggregator\n",
-			       port->slave->dev->master->name,
+			       port->slave->bond->dev->name,
 			       port->actor_port_number, port->slave->dev->name);
 		}
 	}
@@ -1463,7 +1463,7 @@
 
 	default:
 		pr_warning("%s: Impossible agg select mode %d\n",
-			   curr->slave->dev->master->name,
+			   curr->slave->bond->dev->name,
 			   __get_agg_selection_mode(curr->lag_ports));
 		break;
 	}
@@ -1571,7 +1571,7 @@
 		// check if any partner replys
 		if (best->is_individual) {
 			pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
-				   best->slave ? best->slave->dev->master->name : "NULL");
+				   best->slave ? best->slave->bond->dev->name : "NULL");
 		}
 
 		best->is_active = 1;
@@ -1898,7 +1898,7 @@
 
 	if (bond == NULL) {
 		pr_err("%s: The slave %s is not attached to its bond\n",
-		       slave->dev->master->name, slave->dev->name);
+		       slave->bond->dev->name, slave->dev->name);
 		return -1;
 	}
 
@@ -1910,6 +1910,7 @@
 
 		ad_initialize_port(port, bond->params.lacp_fast);
 
+		__initialize_port_locks(slave);
 		port->slave = slave;
 		port->actor_port_number = SLAVE_AD_INFO(slave).id;
 		// key is determined according to the link speed, duplex and user key(which is yet not supported)
@@ -1932,8 +1933,6 @@
 		port->next_port_in_aggregator = NULL;
 
 		__disable_port(port);
-		__initialize_port_locks(port);
-
 
 		// aggregator initialization
 		aggregator = &(SLAVE_AD_INFO(slave).aggregator);
@@ -1973,7 +1972,7 @@
 	// if slave is null, the whole port is not initialized
 	if (!port->slave) {
 		pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n",
-			   slave->dev->master->name, slave->dev->name);
+			   slave->bond->dev->name, slave->dev->name);
 		return;
 	}
 
@@ -2009,7 +2008,7 @@
 
 				if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
 					pr_info("%s: Removing an active aggregator\n",
-						aggregator->slave->dev->master->name);
+						aggregator->slave->bond->dev->name);
 					// select new active aggregator
 					 select_new_active_agg = 1;
 				}
@@ -2040,7 +2039,7 @@
 					ad_agg_selection_logic(__get_first_agg(port));
 			} else {
 				pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
-					   slave->dev->master->name);
+					   slave->bond->dev->name);
 			}
 		} else { // in case that the only port related to this aggregator is the one we want to remove
 			select_new_active_agg = aggregator->is_active;
@@ -2048,7 +2047,7 @@
 			ad_clear_agg(aggregator);
 			if (select_new_active_agg) {
 				pr_info("%s: Removing an active aggregator\n",
-					slave->dev->master->name);
+					slave->bond->dev->name);
 				// select new active aggregator
 				ad_agg_selection_logic(__get_first_agg(port));
 			}
@@ -2076,7 +2075,7 @@
 					ad_clear_agg(temp_aggregator);
 					if (select_new_active_agg) {
 						pr_info("%s: Removing an active aggregator\n",
-							slave->dev->master->name);
+							slave->bond->dev->name);
 						// select new active aggregator
 						ad_agg_selection_logic(__get_first_agg(port));
 					}
@@ -2184,7 +2183,7 @@
 
 		if (!port->slave) {
 			pr_warning("%s: Warning: port of slave %s is uninitialized\n",
-				   slave->dev->name, slave->dev->master->name);
+				   slave->dev->name, slave->bond->dev->name);
 			return ret;
 		}
 
@@ -2240,7 +2239,7 @@
 	// if slave is null, the whole port is not initialized
 	if (!port->slave) {
 		pr_warning("Warning: %s: speed changed for uninitialized port on %s\n",
-			   slave->dev->master->name, slave->dev->name);
+			   slave->bond->dev->name, slave->dev->name);
 		return;
 	}
 
@@ -2268,7 +2267,7 @@
 	// if slave is null, the whole port is not initialized
 	if (!port->slave) {
 		pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n",
-			   slave->dev->master->name, slave->dev->name);
+			   slave->bond->dev->name, slave->dev->name);
 		return;
 	}
 
@@ -2297,7 +2296,7 @@
 	// if slave is null, the whole port is not initialized
 	if (!port->slave) {
 		pr_warning("Warning: %s: link status changed for uninitialized port on %s\n",
-			   slave->dev->master->name, slave->dev->name);
+			   slave->bond->dev->name, slave->dev->name);
 		return;
 	}
 
@@ -2494,11 +2493,13 @@
 	struct port *port = NULL;
 	int lacp_fast;
 
-	read_lock(&bond->lock);
+	write_lock_bh(&bond->lock);
 	lacp_fast = bond->params.lacp_fast;
 
 	bond_for_each_slave(bond, slave, i) {
 		port = &(SLAVE_AD_INFO(slave).port);
+		if (port->slave == NULL)
+			continue;
 		__get_state_machine_lock(port);
 		if (lacp_fast)
 			port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
@@ -2507,5 +2508,5 @@
 		__release_state_machine_lock(port);
 	}
 
-	read_unlock(&bond->lock);
+	write_unlock_bh(&bond->lock);
 }
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 7c9d136..f5e0527 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -507,7 +507,7 @@
 				 client_info->mac_dst);
 		if (!skb) {
 			pr_err("%s: Error: failed to create an ARP packet\n",
-			       client_info->slave->dev->master->name);
+			       client_info->slave->bond->dev->name);
 			continue;
 		}
 
@@ -517,7 +517,7 @@
 			skb = vlan_put_tag(skb, client_info->vlan_id);
 			if (!skb) {
 				pr_err("%s: Error: failed to insert VLAN tag\n",
-				       client_info->slave->dev->master->name);
+				       client_info->slave->bond->dev->name);
 				continue;
 			}
 		}
@@ -1043,7 +1043,7 @@
 	if (dev_set_mac_address(dev, &s_addr)) {
 		pr_err("%s: Error: dev_set_mac_address of dev %s failed!\n"
 		       "ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
-		       dev->master->name, dev->name);
+		       slave->bond->dev->name, dev->name);
 		return -EOPNOTSUPP;
 	}
 	return 0;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b7d45f3..11d01d6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -746,11 +746,9 @@
 {
 	struct in_device *in_dev;
 
-	rcu_read_lock();
 	in_dev = __in_dev_get_rcu(dev);
 	if (in_dev)
 		ip_mc_rejoin_groups(in_dev);
-	rcu_read_unlock();
 }
 
 /*
@@ -760,9 +758,10 @@
  */
 static void bond_resend_igmp_join_requests(struct bonding *bond)
 {
-	struct net_device *bond_dev, *vlan_dev, *master_dev;
+	struct net_device *bond_dev, *vlan_dev, *upper_dev;
 	struct vlan_entry *vlan;
 
+	rcu_read_lock();
 	read_lock(&bond->lock);
 
 	bond_dev = bond->dev;
@@ -774,18 +773,14 @@
 	 * if bond is enslaved to a bridge,
 	 * then rejoin all groups on its master
 	 */
-	master_dev = bond_dev->master;
-	if (master_dev)
-		if ((master_dev->priv_flags & IFF_EBRIDGE)
-			&& (bond_dev->priv_flags & IFF_BRIDGE_PORT))
-			__bond_resend_igmp_join_requests(master_dev);
+	upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
+	if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
+		__bond_resend_igmp_join_requests(upper_dev);
 
 	/* rejoin all groups on vlan devices */
 	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-		rcu_read_lock();
 		vlan_dev = __vlan_find_dev_deep(bond_dev,
 						vlan->vlan_id);
-		rcu_read_unlock();
 		if (vlan_dev)
 			__bond_resend_igmp_join_requests(vlan_dev);
 	}
@@ -794,13 +789,16 @@
 		queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
 
 	read_unlock(&bond->lock);
+	rcu_read_unlock();
 }
 
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
 {
 	struct bonding *bond = container_of(work, struct bonding,
 					    mcast_work.work);
+	rcu_read_lock();
 	bond_resend_igmp_join_requests(bond);
+	rcu_read_unlock();
 }
 
 /*
@@ -1251,7 +1249,7 @@
 		return;
 
 	slave->np = NULL;
-	__netpoll_free_rcu(np);
+	__netpoll_free_async(np);
 }
 static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
 {
@@ -1322,14 +1320,15 @@
 
 /*---------------------------------- IOCTL ----------------------------------*/
 
-static int bond_sethwaddr(struct net_device *bond_dev,
-			  struct net_device *slave_dev)
+static void bond_set_dev_addr(struct net_device *bond_dev,
+			      struct net_device *slave_dev)
 {
 	pr_debug("bond_dev=%p\n", bond_dev);
 	pr_debug("slave_dev=%p\n", slave_dev);
 	pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len);
 	memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
-	return 0;
+	bond_dev->addr_assign_type = NET_ADDR_SET;
+	call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
 }
 
 static netdev_features_t bond_fix_features(struct net_device *dev,
@@ -1493,6 +1492,27 @@
 	return ret;
 }
 
+static int bond_master_upper_dev_link(struct net_device *bond_dev,
+				      struct net_device *slave_dev)
+{
+	int err;
+
+	err = netdev_master_upper_dev_link(slave_dev, bond_dev);
+	if (err)
+		return err;
+	slave_dev->flags |= IFF_SLAVE;
+	rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
+	return 0;
+}
+
+static void bond_upper_dev_unlink(struct net_device *bond_dev,
+				  struct net_device *slave_dev)
+{
+	netdev_upper_dev_unlink(slave_dev, bond_dev);
+	slave_dev->flags &= ~IFF_SLAVE;
+	rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
+}
+
 /* enslave device <slave> to bond device <master> */
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
@@ -1609,10 +1629,8 @@
 
 	/* If this is the first slave, then we need to set the master's hardware
 	 * address to be the same as the slave's. */
-	if (is_zero_ether_addr(bond->dev->dev_addr))
-		memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
-		       slave_dev->addr_len);
-
+	if (bond->dev_addr_from_first)
+		bond_set_dev_addr(bond->dev, slave_dev);
 
 	new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
 	if (!new_slave) {
@@ -1655,9 +1673,9 @@
 		}
 	}
 
-	res = netdev_set_bond_master(slave_dev, bond_dev);
+	res = bond_master_upper_dev_link(bond_dev, slave_dev);
 	if (res) {
-		pr_debug("Error %d calling netdev_set_bond_master\n", res);
+		pr_debug("Error %d calling bond_master_upper_dev_link\n", res);
 		goto err_restore_mac;
 	}
 
@@ -1891,7 +1909,7 @@
 	dev_close(slave_dev);
 
 err_unset_master:
-	netdev_set_bond_master(slave_dev, NULL);
+	bond_upper_dev_unlink(bond_dev, slave_dev);
 
 err_restore_mac:
 	if (!bond->params.fail_over_mac) {
@@ -1919,7 +1937,8 @@
 /*
  * Try to release the slave device <slave> from the bond device <master>
  * It is legal to access curr_active_slave without a lock because all the function
- * is write-locked.
+ * is write-locked. If "all" is true it means that the function is being called
+ * while destroying a bond interface and all slaves are being released.
  *
  * The rules for slave state should be:
  *   for Active/Backup:
@@ -1927,7 +1946,9 @@
  *   for Bonded connections:
  *     The first up interface should be left on and all others downed.
  */
-int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
+static int __bond_release_one(struct net_device *bond_dev,
+			      struct net_device *slave_dev,
+			      bool all)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct slave *slave, *oldcurrent;
@@ -1936,7 +1957,7 @@
 
 	/* slave is not a slave or master is not master of this slave */
 	if (!(slave_dev->flags & IFF_SLAVE) ||
-	    (slave_dev->master != bond_dev)) {
+	    !netdev_has_upper_dev(slave_dev, bond_dev)) {
 		pr_err("%s: Error: cannot release %s.\n",
 		       bond_dev->name, slave_dev->name);
 		return -EINVAL;
@@ -1964,7 +1985,7 @@
 	synchronize_net();
 	write_lock_bh(&bond->lock);
 
-	if (!bond->params.fail_over_mac) {
+	if (!all && !bond->params.fail_over_mac) {
 		if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
 		    bond->slave_cnt > 1)
 			pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
@@ -2010,7 +2031,9 @@
 		write_lock_bh(&bond->lock);
 	}
 
-	if (oldcurrent == slave) {
+	if (all) {
+		bond->curr_active_slave = NULL;
+	} else if (oldcurrent == slave) {
 		/*
 		 * Note that we hold RTNL over this sequence, so there
 		 * is no concern that another slave add/remove event
@@ -2029,12 +2052,8 @@
 
 	if (bond->slave_cnt == 0) {
 		bond_set_carrier(bond);
-
-		/* if the last slave was removed, zero the mac address
-		 * of the master so it will be set by the application
-		 * to the mac address of the first slave
-		 */
-		memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
+		eth_hw_addr_random(bond_dev);
+		bond->dev_addr_from_first = true;
 
 		if (bond_vlan_used(bond)) {
 			pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
@@ -2080,7 +2099,7 @@
 		netif_addr_unlock_bh(bond_dev);
 	}
 
-	netdev_set_bond_master(slave_dev, NULL);
+	bond_upper_dev_unlink(bond_dev, slave_dev);
 
 	slave_disable_netpoll(slave);
 
@@ -2103,6 +2122,12 @@
 	return 0;  /* deletion OK */
 }
 
+/* A wrapper used because of ndo_del_link */
+int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
+{
+	return __bond_release_one(bond_dev, slave_dev, false);
+}
+
 /*
 * First release a slave and then destroy the bond if no more slaves are left.
 * Must be under rtnl_lock when this function is called.
@@ -2124,121 +2149,6 @@
 }
 
 /*
- * This function releases all slaves.
- */
-static int bond_release_all(struct net_device *bond_dev)
-{
-	struct bonding *bond = netdev_priv(bond_dev);
-	struct slave *slave;
-	struct net_device *slave_dev;
-	struct sockaddr addr;
-
-	write_lock_bh(&bond->lock);
-
-	netif_carrier_off(bond_dev);
-
-	if (bond->slave_cnt == 0)
-		goto out;
-
-	bond->current_arp_slave = NULL;
-	bond->primary_slave = NULL;
-	bond_change_active_slave(bond, NULL);
-
-	while ((slave = bond->first_slave) != NULL) {
-		/* Inform AD package of unbinding of slave
-		 * before slave is detached from the list.
-		 */
-		if (bond->params.mode == BOND_MODE_8023AD)
-			bond_3ad_unbind_slave(slave);
-
-		slave_dev = slave->dev;
-		bond_detach_slave(bond, slave);
-
-		/* now that the slave is detached, unlock and perform
-		 * all the undo steps that should not be called from
-		 * within a lock.
-		 */
-		write_unlock_bh(&bond->lock);
-
-		/* unregister rx_handler early so bond_handle_frame wouldn't
-		 * be called for this slave anymore.
-		 */
-		netdev_rx_handler_unregister(slave_dev);
-		synchronize_net();
-
-		if (bond_is_lb(bond)) {
-			/* must be called only after the slave
-			 * has been detached from the list
-			 */
-			bond_alb_deinit_slave(bond, slave);
-		}
-
-		bond_destroy_slave_symlinks(bond_dev, slave_dev);
-		bond_del_vlans_from_slave(bond, slave_dev);
-
-		/* If the mode USES_PRIMARY, then we should only remove its
-		 * promisc and mc settings if it was the curr_active_slave, but that was
-		 * already taken care of above when we detached the slave
-		 */
-		if (!USES_PRIMARY(bond->params.mode)) {
-			/* unset promiscuity level from slave */
-			if (bond_dev->flags & IFF_PROMISC)
-				dev_set_promiscuity(slave_dev, -1);
-
-			/* unset allmulti level from slave */
-			if (bond_dev->flags & IFF_ALLMULTI)
-				dev_set_allmulti(slave_dev, -1);
-
-			/* flush master's mc_list from slave */
-			netif_addr_lock_bh(bond_dev);
-			bond_mc_list_flush(bond_dev, slave_dev);
-			netif_addr_unlock_bh(bond_dev);
-		}
-
-		netdev_set_bond_master(slave_dev, NULL);
-
-		slave_disable_netpoll(slave);
-
-		/* close slave before restoring its mac address */
-		dev_close(slave_dev);
-
-		if (!bond->params.fail_over_mac) {
-			/* restore original ("permanent") mac address*/
-			memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
-			addr.sa_family = slave_dev->type;
-			dev_set_mac_address(slave_dev, &addr);
-		}
-
-		kfree(slave);
-
-		/* re-acquire the lock before getting the next slave */
-		write_lock_bh(&bond->lock);
-	}
-
-	/* zero the mac address of the master so it will be
-	 * set by the application to the mac address of the
-	 * first slave
-	 */
-	memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
-
-	if (bond_vlan_used(bond)) {
-		pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
-			   bond_dev->name, bond_dev->name);
-		pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
-			   bond_dev->name);
-	}
-
-	pr_info("%s: released all slaves\n", bond_dev->name);
-
-out:
-	write_unlock_bh(&bond->lock);
-
-	bond_compute_features(bond);
-
-	return 0;
-}
-
-/*
  * This function changes the active slave to slave <slave_dev>.
  * It returns -EINVAL in the following cases.
  *  - <slave_dev> is not found in the list.
@@ -2259,8 +2169,9 @@
 	if (!USES_PRIMARY(bond->params.mode))
 		return -EINVAL;
 
-	/* Verify that master_dev is indeed the master of slave_dev */
-	if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev))
+	/* Verify that bond_dev is indeed the master of slave_dev */
+	if (!(slave_dev->flags & IFF_SLAVE) ||
+	    !netdev_has_upper_dev(slave_dev, bond_dev))
 		return -EINVAL;
 
 	read_lock(&bond->lock);
@@ -3258,36 +3169,32 @@
 static int bond_slave_netdev_event(unsigned long event,
 				   struct net_device *slave_dev)
 {
-	struct net_device *bond_dev = slave_dev->master;
-	struct bonding *bond = netdev_priv(bond_dev);
-	struct slave *slave = NULL;
+	struct slave *slave = bond_slave_get_rtnl(slave_dev);
+	struct bonding *bond = slave->bond;
+	struct net_device *bond_dev = slave->bond->dev;
+	u32 old_speed;
+	u8 old_duplex;
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
-		if (bond_dev) {
-			if (bond->setup_by_slave)
-				bond_release_and_destroy(bond_dev, slave_dev);
-			else
-				bond_release(bond_dev, slave_dev);
-		}
+		if (bond->setup_by_slave)
+			bond_release_and_destroy(bond_dev, slave_dev);
+		else
+			bond_release(bond_dev, slave_dev);
 		break;
 	case NETDEV_UP:
 	case NETDEV_CHANGE:
-		slave = bond_get_slave_by_dev(bond, slave_dev);
-		if (slave) {
-			u32 old_speed = slave->speed;
-			u8  old_duplex = slave->duplex;
+		old_speed = slave->speed;
+		old_duplex = slave->duplex;
 
-			bond_update_speed_duplex(slave);
+		bond_update_speed_duplex(slave);
 
-			if (bond->params.mode == BOND_MODE_8023AD) {
-				if (old_speed != slave->speed)
-					bond_3ad_adapter_speed_changed(slave);
-				if (old_duplex != slave->duplex)
-					bond_3ad_adapter_duplex_changed(slave);
-			}
+		if (bond->params.mode == BOND_MODE_8023AD) {
+			if (old_speed != slave->speed)
+				bond_3ad_adapter_speed_changed(slave);
+			if (old_duplex != slave->duplex)
+				bond_3ad_adapter_duplex_changed(slave);
 		}
-
 		break;
 	case NETDEV_DOWN:
 		/*
@@ -3604,6 +3511,7 @@
 	struct ifslave k_sinfo;
 	struct ifslave __user *u_sinfo = NULL;
 	struct mii_ioctl_data *mii = NULL;
+	struct net *net;
 	int res = 0;
 
 	pr_debug("bond_ioctl: master=%s, cmd=%d\n", bond_dev->name, cmd);
@@ -3670,10 +3578,12 @@
 		break;
 	}
 
-	if (!capable(CAP_NET_ADMIN))
+	net = dev_net(bond_dev);
+
+	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
 		return -EPERM;
 
-	slave_dev = dev_get_by_name(dev_net(bond_dev), ifr->ifr_slave);
+	slave_dev = dev_get_by_name(net, ifr->ifr_slave);
 
 	pr_debug("slave_dev=%p:\n", slave_dev);
 
@@ -3692,7 +3602,8 @@
 			break;
 		case BOND_SETHWADDR_OLD:
 		case SIOCBONDSETHWADDR:
-			res = bond_sethwaddr(bond_dev, slave_dev);
+			bond_set_dev_addr(bond_dev, slave_dev);
+			res = 0;
 			break;
 		case BOND_CHANGE_ACTIVE_OLD:
 		case SIOCBONDCHANGEACTIVE:
@@ -4314,11 +4225,12 @@
 }
 
 static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
-				    struct ethtool_drvinfo *drvinfo)
+				     struct ethtool_drvinfo *drvinfo)
 {
-	strncpy(drvinfo->driver, DRV_NAME, 32);
-	strncpy(drvinfo->version, DRV_VERSION, 32);
-	snprintf(drvinfo->fw_version, 32, "%d", BOND_ABI_VERSION);
+	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d",
+		 BOND_ABI_VERSION);
 }
 
 static const struct ethtool_ops bond_ethtool_ops = {
@@ -4352,6 +4264,10 @@
 	.ndo_fix_features	= bond_fix_features,
 };
 
+static const struct device_type bond_type = {
+	.name = "bond",
+};
+
 static void bond_destructor(struct net_device *bond_dev)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
@@ -4382,6 +4298,8 @@
 
 	bond_dev->destructor = bond_destructor;
 
+	SET_NETDEV_DEVTYPE(bond_dev, &bond_type);
+
 	/* Initialize the device options */
 	bond_dev->tx_queue_len = 0;
 	bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
@@ -4427,7 +4345,9 @@
 	bond_netpoll_cleanup(bond_dev);
 
 	/* Release the bonded slaves */
-	bond_release_all(bond_dev);
+	while (bond->first_slave != NULL)
+		__bond_release_one(bond_dev, bond->first_slave->dev, true);
+	pr_info("%s: released all slaves\n", bond_dev->name);
 
 	list_del(&bond->bond_list);
 
@@ -4841,6 +4761,13 @@
 
 	bond_debug_register(bond);
 
+	/* Ensure valid dev_addr */
+	if (is_zero_ether_addr(bond_dev->dev_addr) &&
+	    bond_dev->addr_assign_type == NET_ADDR_PERM) {
+		eth_hw_addr_random(bond_dev);
+		bond->dev_addr_from_first = true;
+	}
+
 	__hw_addr_init(&bond->mc_list);
 	return 0;
 }
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 21b68e5..2baec24 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -248,6 +248,7 @@
 	/* debugging support via debugfs */
 	struct	 dentry *debug_dir;
 #endif /* CONFIG_DEBUG_FS */
+	bool	dev_addr_from_first;
 };
 
 static inline bool bond_vlan_used(struct bonding *bond)
@@ -258,6 +259,9 @@
 #define bond_slave_get_rcu(dev) \
 	((struct slave *) rcu_dereference(dev->rx_handler_data))
 
+#define bond_slave_get_rtnl(dev) \
+	((struct slave *) rtnl_dereference(dev->rx_handler_data))
+
 /**
  * Returns NULL if the net_device does not belong to any of the bond's slaves
  *
@@ -280,11 +284,9 @@
 
 static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
 {
-	if (!slave || !slave->dev->master) {
+	if (!slave || !slave->bond)
 		return NULL;
-	}
-
-	return netdev_priv(slave->dev->master);
+	return slave->bond;
 }
 
 static inline bool bond_is_lb(const struct bonding *bond)
@@ -360,10 +362,9 @@
 
 static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
-	struct bonding *bond = netdev_priv(slave->dev->master);
-	if (!bond_is_lb(bond))
+	if (!bond_is_lb(slave->bond))
 		bond_set_backup_slave(slave);
-	if (!bond->params.all_slaves_active)
+	if (!slave->bond->params.all_slaves_active)
 		slave->inactive = 1;
 }
 
diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c
index bc497d7..bce8bac 100644
--- a/drivers/net/caif/caif_shmcore.c
+++ b/drivers/net/caif/caif_shmcore.c
@@ -633,9 +633,6 @@
 				kmalloc(sizeof(struct buf_list), GFP_KERNEL);
 
 		if (tx_buf == NULL) {
-			pr_warn("ERROR, Could not"
-					" allocate dynamic mem. for tx_buf,"
-					" Bailing out ...\n");
 			free_netdev(pshm_dev->pshm_netdev);
 			return -ENOMEM;
 		}
@@ -662,9 +659,6 @@
 				kmalloc(sizeof(struct buf_list), GFP_KERNEL);
 
 		if (rx_buf == NULL) {
-			pr_warn("ERROR, Could not"
-					" allocate dynamic mem.for rx_buf,"
-					" Bailing out ...\n");
 			free_netdev(pshm_dev->pshm_netdev);
 			return -ENOMEM;
 		}
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index b56bd9e..1cca19f 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -1,9 +1,7 @@
 menu "CAN Device Drivers"
-	depends on CAN
 
 config CAN_VCAN
 	tristate "Virtual Local CAN Interface (vcan)"
-	depends on CAN
 	---help---
 	  Similar to the network loopback devices, vcan offers a
 	  virtual local CAN interface.
@@ -13,7 +11,6 @@
 
 config CAN_SLCAN
 	tristate "Serial / USB serial CAN Adaptors (slcan)"
-	depends on CAN
 	---help---
 	  CAN driver for several 'low cost' CAN interfaces that are attached
 	  via serial lines or via USB-to-serial adapters using the LAWICEL
@@ -33,16 +30,16 @@
 
 config CAN_DEV
 	tristate "Platform CAN drivers with Netlink support"
-	depends on CAN
 	default y
 	---help---
 	  Enables the common framework for platform CAN drivers with Netlink
 	  support. This is the standard library for CAN drivers.
 	  If unsure, say Y.
 
+if CAN_DEV
+
 config CAN_CALC_BITTIMING
 	bool "CAN bit-timing calculation"
-	depends on CAN_DEV
 	default y
 	---help---
 	  If enabled, CAN bit-timing parameters will be calculated for the
@@ -54,15 +51,26 @@
 	  arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
 	  If unsure, say Y.
 
+config CAN_LEDS
+	bool "Enable LED triggers for Netlink based drivers"
+	depends on LEDS_CLASS
+	select LEDS_TRIGGERS
+	---help---
+	  This option adds two LED triggers for packet receive and transmit
+	  events on each supported CAN device.
+
+	  Say Y here if you are working on a system with led-class supported
+	  LEDs and you want to use them as canbus activity indicators.
+
 config CAN_AT91
 	tristate "Atmel AT91 onchip CAN controller"
-	depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
+	depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
 	---help---
 	  This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
 	  and AT91SAM9X5 processors.
 
 config CAN_TI_HECC
-	depends on CAN_DEV && ARCH_OMAP3
+	depends on ARCH_OMAP3
 	tristate "TI High End CAN Controller"
 	---help---
 	  Driver for TI HECC (High End CAN Controller) module found on many
@@ -70,12 +78,12 @@
 
 config CAN_MCP251X
 	tristate "Microchip MCP251x SPI CAN controllers"
-	depends on CAN_DEV && SPI && HAS_DMA
+	depends on SPI && HAS_DMA
 	---help---
 	  Driver for the Microchip MCP251x SPI CAN controllers.
 
 config CAN_BFIN
-	depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x)
+	depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
 	tristate "Analog Devices Blackfin on-chip CAN"
 	---help---
 	  Driver for the Analog Devices Blackfin on-chip CAN controllers
@@ -85,7 +93,7 @@
 
 config CAN_JANZ_ICAN3
 	tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
-	depends on CAN_DEV && MFD_JANZ_CMODIO
+	depends on MFD_JANZ_CMODIO
 	---help---
 	  Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
 	  connects to a MODULbus carrier board.
@@ -98,13 +106,13 @@
 
 config CAN_FLEXCAN
 	tristate "Support for Freescale FLEXCAN based chips"
-	depends on CAN_DEV && HAVE_CAN_FLEXCAN
+	depends on HAVE_CAN_FLEXCAN
 	---help---
 	  Say Y here if you want to support for Freescale FlexCAN.
 
 config PCH_CAN
 	tristate "Intel EG20T PCH CAN controller"
-	depends on CAN_DEV && PCI
+	depends on PCI
 	---help---
 	  This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
 	  is an IOH for x86 embedded processor (Intel Atom E6xx series).
@@ -112,7 +120,7 @@
 
 config CAN_GRCAN
 	tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
-	depends on CAN_DEV && OF
+	depends on OF
 	---help---
 	  Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
 	  Note that the driver supports little endian, even though little
@@ -131,9 +139,10 @@
 
 source "drivers/net/can/softing/Kconfig"
 
+endif
+
 config CAN_DEBUG_DEVICES
 	bool "CAN devices debugging messages"
-	depends on CAN
 	---help---
 	  Say Y here if you want the CAN device drivers to produce a bunch of
 	  debug messages to the system log.  Select this if you are having
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 7de5986..c744039 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -8,6 +8,8 @@
 obj-$(CONFIG_CAN_DEV)		+= can-dev.o
 can-dev-y			:= dev.o
 
+can-dev-$(CONFIG_CAN_LEDS)	+= led.o
+
 obj-y				+= usb/
 obj-y				+= softing/
 
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 81baefd..44f3637 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -37,6 +37,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 #define AT91_MB_MASK(i)		((1 << (i)) - 1)
 
@@ -641,6 +642,8 @@
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+
+	can_led_event(dev, CAN_LED_EVENT_RX);
 }
 
 /**
@@ -875,6 +878,7 @@
 			/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
 			can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
 			dev->stats.tx_packets++;
+			can_led_event(dev, CAN_LED_EVENT_TX);
 		}
 	}
 
@@ -1128,6 +1132,8 @@
 		goto out_close;
 	}
 
+	can_led_event(dev, CAN_LED_EVENT_OPEN);
+
 	/* start chip and queuing */
 	at91_chip_start(dev);
 	napi_enable(&priv->napi);
@@ -1159,6 +1165,8 @@
 
 	close_candev(dev);
 
+	can_led_event(dev, CAN_LED_EVENT_STOP);
+
 	return 0;
 }
 
@@ -1321,6 +1329,8 @@
 		goto exit_free;
 	}
 
+	devm_can_led_init(dev);
+
 	dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
 		 priv->reg_base, dev->irq);
 
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index 3b83baf..61ffc12 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -1,6 +1,6 @@
 menuconfig CAN_C_CAN
 	tristate "Bosch C_CAN/D_CAN devices"
-	depends on CAN_DEV && HAS_IOMEM
+	depends on HAS_IOMEM
 
 if CAN_C_CAN
 
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 2282b1a..a668cd4 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -39,6 +39,7 @@
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 #include "c_can.h"
 
@@ -477,6 +478,8 @@
 	stats->rx_packets++;
 	stats->rx_bytes += frame->can_dlc;
 
+	can_led_event(dev, CAN_LED_EVENT_RX);
+
 	return 0;
 }
 
@@ -755,6 +758,7 @@
 					C_CAN_IFACE(MSGCTRL_REG, 0))
 					& IF_MCONT_DLC_MASK;
 			stats->tx_packets++;
+			can_led_event(dev, CAN_LED_EVENT_TX);
 			c_can_inval_msg_object(dev, 0, msg_obj_no);
 		} else {
 			break;
@@ -1119,6 +1123,8 @@
 
 	napi_enable(&priv->napi);
 
+	can_led_event(dev, CAN_LED_EVENT_OPEN);
+
 	/* start the c_can controller */
 	c_can_start(dev);
 
@@ -1147,6 +1153,8 @@
 	c_can_reset_ram(priv, false);
 	c_can_pm_runtime_put_sync(priv);
 
+	can_led_event(dev, CAN_LED_EVENT_STOP);
+
 	return 0;
 }
 
@@ -1272,6 +1280,8 @@
 	err = register_candev(dev);
 	if (err)
 		c_can_pm_runtime_disable(priv);
+	else
+		devm_can_led_init(dev);
 
 	return err;
 }
diff --git a/drivers/net/can/cc770/Kconfig b/drivers/net/can/cc770/Kconfig
index 22c07a8..6a9a5ba 100644
--- a/drivers/net/can/cc770/Kconfig
+++ b/drivers/net/can/cc770/Kconfig
@@ -1,6 +1,6 @@
 menuconfig CAN_CC770
 	tristate "Bosch CC770 and Intel AN82527 devices"
-	depends on CAN_DEV && HAS_IOMEM
+	depends on HAS_IOMEM
 
 if CAN_CC770
 
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 8233e5e..f9cba41 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -24,7 +24,9 @@
 #include <linux/if_arp.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
+#include <linux/can/skb.h>
 #include <linux/can/netlink.h>
+#include <linux/can/led.h>
 #include <net/rtnetlink.h>
 
 #define MOD_DESC "CAN device driver interface"
@@ -501,13 +503,18 @@
 {
 	struct sk_buff *skb;
 
-	skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
+	skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+			       sizeof(struct can_frame));
 	if (unlikely(!skb))
 		return NULL;
 
 	skb->protocol = htons(ETH_P_CAN);
 	skb->pkt_type = PACKET_BROADCAST;
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	can_skb_reserve(skb);
+	can_skb_prv(skb)->ifindex = dev->ifindex;
+
 	*cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
 	memset(*cf, 0, sizeof(struct can_frame));
 
@@ -794,10 +801,25 @@
 }
 EXPORT_SYMBOL_GPL(unregister_candev);
 
+/*
+ * Test if a network device is a candev based device
+ * and return the can_priv* if so.
+ */
+struct can_priv *safe_candev_priv(struct net_device *dev)
+{
+	if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops))
+		return NULL;
+
+	return netdev_priv(dev);
+}
+EXPORT_SYMBOL_GPL(safe_candev_priv);
+
 static __init int can_dev_init(void)
 {
 	int err;
 
+	can_led_notifier_init();
+
 	err = rtnl_link_register(&can_link_ops);
 	if (!err)
 		printk(KERN_INFO MOD_DESC "\n");
@@ -809,6 +831,8 @@
 static __exit void can_dev_exit(void)
 {
 	rtnl_link_unregister(&can_link_ops);
+
+	can_led_notifier_exit();
 }
 module_exit(can_dev_exit);
 
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 0289a6d..769d29e 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -23,6 +23,7 @@
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 #include <linux/can/platform/flexcan.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -564,6 +565,8 @@
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
 
+	can_led_event(dev, CAN_LED_EVENT_RX);
+
 	return 1;
 }
 
@@ -652,6 +655,7 @@
 	if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
 		stats->tx_bytes += can_get_echo_skb(dev, 0);
 		stats->tx_packets++;
+		can_led_event(dev, CAN_LED_EVENT_TX);
 		flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
 		netif_wake_queue(dev);
 	}
@@ -865,6 +869,9 @@
 	err = flexcan_chip_start(dev);
 	if (err)
 		goto out_close;
+
+	can_led_event(dev, CAN_LED_EVENT_OPEN);
+
 	napi_enable(&priv->napi);
 	netif_start_queue(dev);
 
@@ -893,6 +900,8 @@
 
 	close_candev(dev);
 
+	can_led_event(dev, CAN_LED_EVENT_STOP);
+
 	return 0;
 }
 
@@ -1092,6 +1101,8 @@
 		goto failed_register;
 	}
 
+	devm_can_led_init(dev);
+
 	dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
 		 priv->base, dev->irq);
 
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c
new file mode 100644
index 0000000..f27fca6
--- /dev/null
+++ b/drivers/net/can/led.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
+ * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
+ *
+ * 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 <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/can/dev.h>
+
+#include <linux/can/led.h>
+
+static unsigned long led_delay = 50;
+module_param(led_delay, ulong, 0644);
+MODULE_PARM_DESC(led_delay,
+		"blink delay time for activity leds (msecs, default: 50).");
+
+/* Trigger a LED event in response to a CAN device event */
+void can_led_event(struct net_device *netdev, enum can_led_event event)
+{
+	struct can_priv *priv = netdev_priv(netdev);
+
+	switch (event) {
+	case CAN_LED_EVENT_OPEN:
+		led_trigger_event(priv->tx_led_trig, LED_FULL);
+		led_trigger_event(priv->rx_led_trig, LED_FULL);
+		break;
+	case CAN_LED_EVENT_STOP:
+		led_trigger_event(priv->tx_led_trig, LED_OFF);
+		led_trigger_event(priv->rx_led_trig, LED_OFF);
+		break;
+	case CAN_LED_EVENT_TX:
+		if (led_delay)
+			led_trigger_blink_oneshot(priv->tx_led_trig,
+						  &led_delay, &led_delay, 1);
+		break;
+	case CAN_LED_EVENT_RX:
+		if (led_delay)
+			led_trigger_blink_oneshot(priv->rx_led_trig,
+						  &led_delay, &led_delay, 1);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(can_led_event);
+
+static void can_led_release(struct device *gendev, void *res)
+{
+	struct can_priv *priv = netdev_priv(to_net_dev(gendev));
+
+	led_trigger_unregister_simple(priv->tx_led_trig);
+	led_trigger_unregister_simple(priv->rx_led_trig);
+}
+
+/* Register CAN LED triggers for a CAN device
+ *
+ * This is normally called from a driver's probe function
+ */
+void devm_can_led_init(struct net_device *netdev)
+{
+	struct can_priv *priv = netdev_priv(netdev);
+	void *res;
+
+	res = devres_alloc(can_led_release, 0, GFP_KERNEL);
+	if (!res) {
+		netdev_err(netdev, "cannot register LED triggers\n");
+		return;
+	}
+
+	snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
+		 "%s-tx", netdev->name);
+	snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
+		 "%s-rx", netdev->name);
+
+	led_trigger_register_simple(priv->tx_led_trig_name,
+				    &priv->tx_led_trig);
+	led_trigger_register_simple(priv->rx_led_trig_name,
+				    &priv->rx_led_trig);
+
+	devres_add(&netdev->dev, res);
+}
+EXPORT_SYMBOL_GPL(devm_can_led_init);
+
+/* NETDEV rename notifier to rename the associated led triggers too */
+static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
+			void *data)
+{
+	struct net_device *netdev = data;
+	struct can_priv *priv = safe_candev_priv(netdev);
+	char name[CAN_LED_NAME_SZ];
+
+	if (!priv)
+		return NOTIFY_DONE;
+
+	if (msg == NETDEV_CHANGENAME) {
+		snprintf(name, sizeof(name), "%s-tx", netdev->name);
+		led_trigger_rename_static(name, priv->tx_led_trig);
+
+		snprintf(name, sizeof(name), "%s-rx", netdev->name);
+		led_trigger_rename_static(name, priv->rx_led_trig);
+	}
+
+	return NOTIFY_DONE;
+}
+
+/* notifier block for netdevice event */
+static struct notifier_block can_netdev_notifier __read_mostly = {
+	.notifier_call = can_led_notifier,
+};
+
+int __init can_led_notifier_init(void)
+{
+	return register_netdevice_notifier(&can_netdev_notifier);
+}
+
+void __exit can_led_notifier_exit(void)
+{
+	unregister_netdevice_notifier(&can_netdev_notifier);
+}
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 5eaf47b..f32b9fc 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -60,6 +60,7 @@
 
 #include <linux/can/core.h>
 #include <linux/can/dev.h>
+#include <linux/can/led.h>
 #include <linux/can/platform/mcp251x.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
@@ -494,6 +495,9 @@
 
 	priv->net->stats.rx_packets++;
 	priv->net->stats.rx_bytes += frame->can_dlc;
+
+	can_led_event(priv->net, CAN_LED_EVENT_RX);
+
 	netif_rx_ni(skb);
 }
 
@@ -707,6 +711,8 @@
 
 	mutex_unlock(&priv->mcp_lock);
 
+	can_led_event(net, CAN_LED_EVENT_STOP);
+
 	return 0;
 }
 
@@ -905,6 +911,7 @@
 		if (intf & CANINTF_TX) {
 			net->stats.tx_packets++;
 			net->stats.tx_bytes += priv->tx_len - 1;
+			can_led_event(net, CAN_LED_EVENT_TX);
 			if (priv->tx_len) {
 				can_get_echo_skb(net, 0);
 				priv->tx_len = 0;
@@ -968,6 +975,9 @@
 		mcp251x_open_clean(net);
 		goto open_unlock;
 	}
+
+	can_led_event(net, CAN_LED_EVENT_OPEN);
+
 	netif_wake_queue(net);
 
 open_unlock:
@@ -1077,10 +1087,15 @@
 		pdata->transceiver_enable(0);
 
 	ret = register_candev(net);
-	if (!ret) {
-		dev_info(&spi->dev, "probed\n");
-		return ret;
-	}
+	if (ret)
+		goto error_probe;
+
+	devm_can_led_init(net);
+
+	dev_info(&spi->dev, "probed\n");
+
+	return ret;
+
 error_probe:
 	if (!mcp251x_enable_dma)
 		kfree(priv->spi_rx_buf);
diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig
index d387069..f19be52 100644
--- a/drivers/net/can/mscan/Kconfig
+++ b/drivers/net/can/mscan/Kconfig
@@ -1,5 +1,5 @@
 config CAN_MSCAN
-	depends on CAN_DEV && (PPC || M68K)
+	depends on PPC || M68K
 	tristate "Support for Freescale MSCAN based chips"
 	---help---
 	  The Motorola Scalable Controller Area Network (MSCAN) definition
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 92f73c7..b39ca5b 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -1,6 +1,6 @@
 menuconfig CAN_SJA1000
 	tristate "Philips/NXP SJA1000 devices"
-	depends on CAN_DEV && HAS_IOMEM
+	depends on HAS_IOMEM
 
 if CAN_SJA1000
 
@@ -99,11 +99,11 @@
 	tristate "TS-CAN1 PC104 boards"
 	depends on ISA
 	help
-	This driver is for Technologic Systems' TSCAN-1 PC104 boards.
-	http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
-	The driver supports multiple boards and automatically configures them:
-	PLD IO base addresses are read from jumpers JP1 and JP2,
-	IRQ numbers are read from jumpers JP4 and JP5,
-	SJA1000 IO base addresses are chosen heuristically (first that works).
+	  This driver is for Technologic Systems' TSCAN-1 PC104 boards.
+	  http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
+	  The driver supports multiple boards and automatically configures them:
+	  PLD IO base addresses are read from jumpers JP1 and JP2,
+	  IRQ numbers are read from jumpers JP4 and JP5,
+	  SJA1000 IO base addresses are chosen heuristically (first that works).
 
 endif
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 036a326..36d298d 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -238,7 +238,6 @@
 	/* Allocating card structures to hold addresses, ... */
 	card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
 	if (card == NULL) {
-		dev_err(&pdev->dev, "Unable to allocate memory\n");
 		pci_disable_device(pdev);
 		return -ENOMEM;
 	}
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index d84888f..d1e7f10 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -339,8 +339,7 @@
  */
 static void peak_pciec_start_led_work(struct peak_pciec_card *card)
 {
-	if (!delayed_work_pending(&card->led_work))
-		schedule_delayed_work(&card->led_work, HZ);
+	schedule_delayed_work(&card->led_work, HZ);
 }
 
 /*
@@ -451,11 +450,8 @@
 	} else {
 		/* create the bit banging I2C adapter structure */
 		card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
-		if (!card) {
-			dev_err(&pdev->dev,
-				 "failed allocating memory for i2c chip\n");
+		if (!card)
 			return -ENOMEM;
-		}
 
 		card->cfg_base = chan->cfg_base;
 		card->reg_base = priv->reg_base;
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
index f117514..1a7020b 100644
--- a/drivers/net/can/sja1000/peak_pcmcia.c
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -660,7 +660,6 @@
 
 	card = kzalloc(sizeof(struct pcan_pccard), GFP_KERNEL);
 	if (!card) {
-		dev_err(&pdev->dev, "couldn't allocate card memory\n");
 		err = -ENOMEM;
 		goto probe_err_2;
 	}
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index 11d1062..a042cdc 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -508,7 +508,6 @@
 	/* Allocate card structures to hold addresses, ... */
 	card = kzalloc(sizeof(*card), GFP_KERNEL);
 	if (!card) {
-		dev_err(&pdev->dev, "Unable to allocate memory\n");
 		pci_disable_device(pdev);
 		return -ENOMEM;
 	}
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 83ee11e..daf4013 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -60,6 +60,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 
 #include "sja1000.h"
 
@@ -368,6 +369,8 @@
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
+
+	can_led_event(dev, CAN_LED_EVENT_RX);
 }
 
 static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
@@ -521,6 +524,7 @@
 				can_get_echo_skb(dev, 0);
 			}
 			netif_wake_queue(dev);
+			can_led_event(dev, CAN_LED_EVENT_TX);
 		}
 		if (isrc & IRQ_RI) {
 			/* receive interrupt */
@@ -575,6 +579,8 @@
 	/* init and start chi */
 	sja1000_start(dev);
 
+	can_led_event(dev, CAN_LED_EVENT_OPEN);
+
 	netif_start_queue(dev);
 
 	return 0;
@@ -592,6 +598,8 @@
 
 	close_candev(dev);
 
+	can_led_event(dev, CAN_LED_EVENT_STOP);
+
 	return 0;
 }
 
@@ -639,6 +647,8 @@
 
 int register_sja1000dev(struct net_device *dev)
 {
+	int ret;
+
 	if (!sja1000_probe_chip(dev))
 		return -ENODEV;
 
@@ -648,7 +658,12 @@
 	set_reset_mode(dev);
 	chipset_init(dev);
 
-	return register_candev(dev);
+	ret =  register_candev(dev);
+
+	if (!ret)
+		devm_can_led_init(dev);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(register_sja1000dev);
 
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index adc3708..06b7e09 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/can.h>
+#include <linux/can/skb.h>
 
 static __initconst const char banner[] =
 	KERN_INFO "slcan: serial line CAN interface driver\n";
@@ -184,7 +185,8 @@
 		cf.data[i] |= tmp;
 	}
 
-	skb = dev_alloc_skb(sizeof(struct can_frame));
+	skb = dev_alloc_skb(sizeof(struct can_frame) +
+			    sizeof(struct can_skb_priv));
 	if (!skb)
 		return;
 
@@ -192,6 +194,10 @@
 	skb->protocol = htons(ETH_P_CAN);
 	skb->pkt_type = PACKET_BROADCAST;
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	can_skb_reserve(skb);
+	can_skb_prv(skb)->ifindex = sl->dev->ifindex;
+
 	memcpy(skb_put(skb, sizeof(struct can_frame)),
 	       &cf, sizeof(struct can_frame));
 	netif_rx_ni(skb);
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
index 5de46a9..96b6fe1 100644
--- a/drivers/net/can/softing/Kconfig
+++ b/drivers/net/can/softing/Kconfig
@@ -1,6 +1,6 @@
 config CAN_SOFTING
 	tristate "Softing Gmbh CAN generic support"
-	depends on CAN_DEV && HAS_IOMEM
+	depends on HAS_IOMEM
 	---help---
 	  Support for CAN cards from Softing Gmbh & some cards
 	  from Vector Gmbh.
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 300581b..f21fc37 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -50,6 +50,7 @@
 
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
+#include <linux/can/led.h>
 #include <linux/can/platform/ti_hecc.h>
 
 #define DRV_NAME "ti_hecc"
@@ -593,6 +594,7 @@
 	spin_unlock_irqrestore(&priv->mbx_lock, flags);
 
 	stats->rx_bytes += cf->can_dlc;
+	can_led_event(priv->ndev, CAN_LED_EVENT_RX);
 	netif_receive_skb(skb);
 	stats->rx_packets++;
 
@@ -796,6 +798,7 @@
 			stats->tx_bytes += hecc_read_mbx(priv, mbxno,
 						HECC_CANMCF) & 0xF;
 			stats->tx_packets++;
+			can_led_event(ndev, CAN_LED_EVENT_TX);
 			can_get_echo_skb(ndev, mbxno);
 			--priv->tx_tail;
 		}
@@ -851,6 +854,8 @@
 		return err;
 	}
 
+	can_led_event(ndev, CAN_LED_EVENT_OPEN);
+
 	ti_hecc_start(ndev);
 	napi_enable(&priv->napi);
 	netif_start_queue(ndev);
@@ -869,6 +874,8 @@
 	close_candev(ndev);
 	ti_hecc_transceiver_switch(priv, 0);
 
+	can_led_event(ndev, CAN_LED_EVENT_STOP);
+
 	return 0;
 }
 
@@ -961,6 +968,9 @@
 		dev_err(&pdev->dev, "register_candev() failed\n");
 		goto probe_exit_clk;
 	}
+
+	devm_can_led_init(ndev);
+
 	dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
 		priv->base, (u32) ndev->irq);
 
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a4e4bee..fc96a3d 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -1,5 +1,5 @@
 menu "CAN USB interfaces"
-	depends on USB && CAN_DEV
+	depends on USB
 
 config CAN_EMS_USB
 	tristate "EMS CPC-USB/ARM7 CAN/USB interface"
@@ -48,4 +48,10 @@
 	  This driver supports the PCAN-USB and PCAN-USB Pro adapters
 	  from PEAK-System Technik (http://www.peak-system.com).
 
+config CAN_8DEV_USB
+	tristate "8 devices USB2CAN interface"
+	---help---
+	  This driver supports the USB2CAN interface
+	  from 8 devices (http://www.8devices.com).
+
 endmenu
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index 80a2ee4..becef46 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -6,5 +6,6 @@
 obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
+obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index c69f0b7..5f9a7ad 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -1014,17 +1014,13 @@
 	}
 
 	dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL);
-	if (!dev->intr_in_buffer) {
-		dev_err(&intf->dev, "Couldn't alloc Intr buffer\n");
+	if (!dev->intr_in_buffer)
 		goto cleanup_intr_urb;
-	}
 
 	dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE +
 				     sizeof(struct ems_cpc_msg), GFP_KERNEL);
-	if (!dev->tx_msg_buffer) {
-		dev_err(&intf->dev, "Couldn't alloc Tx buffer\n");
+	if (!dev->tx_msg_buffer)
 		goto cleanup_intr_in_buffer;
-	}
 
 	usb_set_intfdata(intf, dev);
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 5b58a4d..45cb9f3 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -561,7 +561,6 @@
 
 	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
 	if (!buf) {
-		netdev_err(netdev, "No memory left for USB buffer\n");
 		usb_free_urb(urb);
 		return -ENOMEM;
 	}
@@ -1268,7 +1267,6 @@
 
 	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
 	if (!buf) {
-		netdev_err(netdev, "No memory left for USB buffer\n");
 		stats->tx_dropped++;
 		goto nobufmem;
 	}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index d9290ea..a0f647f 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -386,7 +386,6 @@
 
 		buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL);
 		if (!buf) {
-			netdev_err(netdev, "No memory left for USB buffer\n");
 			usb_free_urb(urb);
 			err = -ENOMEM;
 			break;
@@ -442,7 +441,6 @@
 
 		buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL);
 		if (!buf) {
-			netdev_err(netdev, "No memory left for USB buffer\n");
 			usb_free_urb(urb);
 			err = -ENOMEM;
 			break;
@@ -634,7 +632,6 @@
 	/* also allocate enough space for the commands to send */
 	buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC);
 	if (!buf) {
-		netdev_err(dev->netdev, "no memory left for async cmd\n");
 		usb_free_urb(urb);
 		return -ENOMEM;
 	}
@@ -729,8 +726,6 @@
 	/* allocate a buffer large enough to send commands */
 	dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
 	if (!dev->cmd_buf) {
-		dev_err(&intf->dev, "%s: couldn't alloc cmd buffer\n",
-			PCAN_USB_DRIVER_NAME);
 		err = -ENOMEM;
 		goto lbl_set_intf_data;
 	}
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
new file mode 100644
index 0000000..6e15ef0
--- /dev/null
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -0,0 +1,1031 @@
+/*
+ * CAN driver for "8 devices" USB2CAN converter
+ *
+ * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c
+ * and drivers/net/can/usb/esd_usb2.c
+ *
+ * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de)
+ * for testing and fixing this driver. Also many thanks to "8 devices",
+ * who were very cooperative and answered my questions.
+ */
+
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/led.h>
+
+/* driver constants */
+#define MAX_RX_URBS			20
+#define MAX_TX_URBS			20
+#define RX_BUFFER_SIZE			64
+
+/* vendor and product id */
+#define USB_8DEV_VENDOR_ID		0x0483
+#define USB_8DEV_PRODUCT_ID		0x1234
+
+/* endpoints */
+enum usb_8dev_endpoint {
+	USB_8DEV_ENDP_DATA_RX = 1,
+	USB_8DEV_ENDP_DATA_TX,
+	USB_8DEV_ENDP_CMD_RX,
+	USB_8DEV_ENDP_CMD_TX
+};
+
+/* device CAN clock */
+#define USB_8DEV_ABP_CLOCK		32000000
+
+/* setup flags */
+#define USB_8DEV_SILENT			0x01
+#define USB_8DEV_LOOPBACK		0x02
+#define USB_8DEV_DISABLE_AUTO_RESTRANS	0x04
+#define USB_8DEV_STATUS_FRAME		0x08
+
+/* commands */
+enum usb_8dev_cmd {
+	USB_8DEV_RESET = 1,
+	USB_8DEV_OPEN,
+	USB_8DEV_CLOSE,
+	USB_8DEV_SET_SPEED,
+	USB_8DEV_SET_MASK_FILTER,
+	USB_8DEV_GET_STATUS,
+	USB_8DEV_GET_STATISTICS,
+	USB_8DEV_GET_SERIAL,
+	USB_8DEV_GET_SOFTW_VER,
+	USB_8DEV_GET_HARDW_VER,
+	USB_8DEV_RESET_TIMESTAMP,
+	USB_8DEV_GET_SOFTW_HARDW_VER
+};
+
+/* command options */
+#define USB_8DEV_BAUD_MANUAL		0x09
+#define USB_8DEV_CMD_START		0x11
+#define USB_8DEV_CMD_END		0x22
+
+#define USB_8DEV_CMD_SUCCESS		0
+#define USB_8DEV_CMD_ERROR		255
+
+#define USB_8DEV_CMD_TIMEOUT		1000
+
+/* frames */
+#define USB_8DEV_DATA_START		0x55
+#define USB_8DEV_DATA_END		0xAA
+
+#define USB_8DEV_TYPE_CAN_FRAME		0
+#define USB_8DEV_TYPE_ERROR_FRAME	3
+
+#define USB_8DEV_EXTID			0x01
+#define USB_8DEV_RTR			0x02
+#define USB_8DEV_ERR_FLAG		0x04
+
+/* status */
+#define USB_8DEV_STATUSMSG_OK		0x00  /* Normal condition. */
+#define USB_8DEV_STATUSMSG_OVERRUN	0x01  /* Overrun occured when sending */
+#define USB_8DEV_STATUSMSG_BUSLIGHT	0x02  /* Error counter has reached 96 */
+#define USB_8DEV_STATUSMSG_BUSHEAVY	0x03  /* Error count. has reached 128 */
+#define USB_8DEV_STATUSMSG_BUSOFF	0x04  /* Device is in BUSOFF */
+#define USB_8DEV_STATUSMSG_STUFF	0x20  /* Stuff Error */
+#define USB_8DEV_STATUSMSG_FORM		0x21  /* Form Error */
+#define USB_8DEV_STATUSMSG_ACK		0x23  /* Ack Error */
+#define USB_8DEV_STATUSMSG_BIT0		0x24  /* Bit1 Error */
+#define USB_8DEV_STATUSMSG_BIT1		0x25  /* Bit0 Error */
+#define USB_8DEV_STATUSMSG_CRC		0x27  /* CRC Error */
+
+#define USB_8DEV_RP_MASK		0x7F  /* Mask for Receive Error Bit */
+
+
+/* table of devices that work with this driver */
+static const struct usb_device_id usb_8dev_table[] = {
+	{ USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_8dev_table);
+
+struct usb_8dev_tx_urb_context {
+	struct usb_8dev_priv *priv;
+
+	u32 echo_index;
+	u8 dlc;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_8dev_priv {
+	struct can_priv can; /* must be the first member */
+
+	struct sk_buff *echo_skb[MAX_TX_URBS];
+
+	struct usb_device *udev;
+	struct net_device *netdev;
+
+	atomic_t active_tx_urbs;
+	struct usb_anchor tx_submitted;
+	struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+	struct usb_anchor rx_submitted;
+
+	struct can_berr_counter bec;
+
+	u8 *cmd_msg_buffer;
+
+	struct mutex usb_8dev_cmd_lock;
+
+};
+
+/* tx frame */
+struct __packed usb_8dev_tx_msg {
+	u8 begin;
+	u8 flags;	/* RTR and EXT_ID flag */
+	__be32 id;	/* upper 3 bits not used */
+	u8 dlc;		/* data length code 0-8 bytes */
+	u8 data[8];	/* 64-bit data */
+	u8 end;
+};
+
+/* rx frame */
+struct __packed usb_8dev_rx_msg {
+	u8 begin;
+	u8 type;		/* frame type */
+	u8 flags;		/* RTR and EXT_ID flag */
+	__be32 id;		/* upper 3 bits not used */
+	u8 dlc;			/* data length code 0-8 bytes */
+	u8 data[8];		/* 64-bit data */
+	__be32 timestamp;	/* 32-bit timestamp */
+	u8 end;
+};
+
+/* command frame */
+struct __packed usb_8dev_cmd_msg {
+	u8 begin;
+	u8 channel;	/* unkown - always 0 */
+	u8 command;	/* command to execute */
+	u8 opt1;	/* optional parameter / return value */
+	u8 opt2;	/* optional parameter 2 */
+	u8 data[10];	/* optional parameter and data */
+	u8 end;
+};
+
+static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size)
+{
+	int actual_length;
+
+	return usb_bulk_msg(priv->udev,
+			    usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX),
+			    msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size,
+				int *actual_length)
+{
+	return usb_bulk_msg(priv->udev,
+			    usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX),
+			    msg, size, actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+/* Send command to device and receive result.
+ * Command was successful when opt1 = 0.
+ */
+static int usb_8dev_send_cmd(struct usb_8dev_priv *priv,
+			     struct usb_8dev_cmd_msg *out,
+			     struct usb_8dev_cmd_msg *in)
+{
+	int err;
+	int num_bytes_read;
+	struct net_device *netdev;
+
+	netdev = priv->netdev;
+
+	out->begin = USB_8DEV_CMD_START;
+	out->end = USB_8DEV_CMD_END;
+
+	mutex_lock(&priv->usb_8dev_cmd_lock);
+
+	memcpy(priv->cmd_msg_buffer, out,
+		sizeof(struct usb_8dev_cmd_msg));
+
+	err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer,
+				    sizeof(struct usb_8dev_cmd_msg));
+	if (err < 0) {
+		netdev_err(netdev, "sending command message failed\n");
+		goto failed;
+	}
+
+	err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer,
+				    sizeof(struct usb_8dev_cmd_msg),
+				    &num_bytes_read);
+	if (err < 0) {
+		netdev_err(netdev, "no command message answer\n");
+		goto failed;
+	}
+
+	memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg));
+
+	if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END ||
+			num_bytes_read != 16 || in->opt1 != 0)
+		err = -EPROTO;
+
+failed:
+	mutex_unlock(&priv->usb_8dev_cmd_lock);
+	return err;
+}
+
+/* Send open command to device */
+static int usb_8dev_cmd_open(struct usb_8dev_priv *priv)
+{
+	struct can_bittiming *bt = &priv->can.bittiming;
+	struct usb_8dev_cmd_msg outmsg;
+	struct usb_8dev_cmd_msg inmsg;
+	u32 ctrlmode = priv->can.ctrlmode;
+	u32 flags = USB_8DEV_STATUS_FRAME;
+	__be32 beflags;
+	__be16 bebrp;
+
+	memset(&outmsg, 0, sizeof(outmsg));
+	outmsg.command = USB_8DEV_OPEN;
+	outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+	outmsg.data[0] = bt->prop_seg + bt->phase_seg1;
+	outmsg.data[1] = bt->phase_seg2;
+	outmsg.data[2] = bt->sjw;
+
+	/* BRP */
+	bebrp = cpu_to_be16((u16)bt->brp);
+	memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
+
+	/* flags */
+	if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
+		flags |= USB_8DEV_LOOPBACK;
+	if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+		flags |= USB_8DEV_SILENT;
+	if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+		flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
+
+	beflags = cpu_to_be32(flags);
+	memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
+
+	return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Send close command to device */
+static int usb_8dev_cmd_close(struct usb_8dev_priv *priv)
+{
+	struct usb_8dev_cmd_msg inmsg;
+	struct usb_8dev_cmd_msg outmsg = {
+		.channel = 0,
+		.command = USB_8DEV_CLOSE,
+		.opt1 = 0,
+		.opt2 = 0
+	};
+
+	return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Get firmware and hardware version */
+static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res)
+{
+	struct usb_8dev_cmd_msg	inmsg;
+	struct usb_8dev_cmd_msg	outmsg = {
+		.channel = 0,
+		.command = USB_8DEV_GET_SOFTW_HARDW_VER,
+		.opt1 = 0,
+		.opt2 = 0
+	};
+
+	int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+	if (err)
+		return err;
+
+	*res = be32_to_cpup((__be32 *)inmsg.data);
+
+	return err;
+}
+
+/* Set network device mode
+ *
+ * Maybe we should leave this function empty, because the device
+ * set mode variable with open command.
+ */
+static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+	struct usb_8dev_priv *priv = netdev_priv(netdev);
+	int err = 0;
+
+	switch (mode) {
+	case CAN_MODE_START:
+		err = usb_8dev_cmd_open(priv);
+		if (err)
+			netdev_warn(netdev, "couldn't start device");
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return err;
+}
+
+/* Read error/status frames */
+static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
+				struct usb_8dev_rx_msg *msg)
+{
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct net_device_stats *stats = &priv->netdev->stats;
+
+	/* Error message:
+	 * byte 0: Status
+	 * byte 1: bit   7: Receive Passive
+	 * byte 1: bit 0-6: Receive Error Counter
+	 * byte 2: Transmit Error Counter
+	 * byte 3: Always 0 (maybe reserved for future use)
+	 */
+
+	u8 state = msg->data[0];
+	u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
+	u8 txerr = msg->data[2];
+	int rx_errors = 0;
+	int tx_errors = 0;
+
+	skb = alloc_can_err_skb(priv->netdev, &cf);
+	if (!skb)
+		return;
+
+	switch (state) {
+	case USB_8DEV_STATUSMSG_OK:
+		priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		cf->can_id |= CAN_ERR_PROT;
+		cf->data[2] = CAN_ERR_PROT_ACTIVE;
+		break;
+	case USB_8DEV_STATUSMSG_BUSOFF:
+		priv->can.state = CAN_STATE_BUS_OFF;
+		cf->can_id |= CAN_ERR_BUSOFF;
+		can_bus_off(priv->netdev);
+		break;
+	case USB_8DEV_STATUSMSG_OVERRUN:
+	case USB_8DEV_STATUSMSG_BUSLIGHT:
+	case USB_8DEV_STATUSMSG_BUSHEAVY:
+		cf->can_id |= CAN_ERR_CRTL;
+		break;
+	default:
+		priv->can.state = CAN_STATE_ERROR_WARNING;
+		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+		priv->can.can_stats.bus_error++;
+		break;
+	}
+
+	switch (state) {
+	case USB_8DEV_STATUSMSG_OK:
+	case USB_8DEV_STATUSMSG_BUSOFF:
+		break;
+	case USB_8DEV_STATUSMSG_ACK:
+		cf->can_id |= CAN_ERR_ACK;
+		tx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_CRC:
+		cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+		cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+			       CAN_ERR_PROT_LOC_CRC_DEL;
+		rx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_BIT0:
+		cf->data[2] |= CAN_ERR_PROT_BIT0;
+		tx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_BIT1:
+		cf->data[2] |= CAN_ERR_PROT_BIT1;
+		tx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_FORM:
+		cf->data[2] |= CAN_ERR_PROT_FORM;
+		rx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_STUFF:
+		cf->data[2] |= CAN_ERR_PROT_STUFF;
+		rx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_OVERRUN:
+		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+		stats->rx_over_errors++;
+		rx_errors = 1;
+		break;
+	case USB_8DEV_STATUSMSG_BUSLIGHT:
+		priv->can.state = CAN_STATE_ERROR_WARNING;
+		cf->data[1] = (txerr > rxerr) ?
+			CAN_ERR_CRTL_TX_WARNING :
+			CAN_ERR_CRTL_RX_WARNING;
+		priv->can.can_stats.error_warning++;
+		break;
+	case USB_8DEV_STATUSMSG_BUSHEAVY:
+		priv->can.state = CAN_STATE_ERROR_PASSIVE;
+		cf->data[1] = (txerr > rxerr) ?
+			CAN_ERR_CRTL_TX_PASSIVE :
+			CAN_ERR_CRTL_RX_PASSIVE;
+		priv->can.can_stats.error_passive++;
+		break;
+	default:
+		netdev_warn(priv->netdev,
+			    "Unknown status/error message (%d)\n", state);
+		break;
+	}
+
+	if (tx_errors) {
+		cf->data[2] |= CAN_ERR_PROT_TX;
+		stats->tx_errors++;
+	}
+
+	if (rx_errors)
+		stats->rx_errors++;
+
+	cf->data[6] = txerr;
+	cf->data[7] = rxerr;
+
+	priv->bec.txerr = txerr;
+	priv->bec.rxerr = rxerr;
+
+	netif_rx(skb);
+
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+}
+
+/* Read data and status frames */
+static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
+				struct usb_8dev_rx_msg *msg)
+{
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct net_device_stats *stats = &priv->netdev->stats;
+
+	if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
+		   msg->flags == USB_8DEV_ERR_FLAG) {
+		usb_8dev_rx_err_msg(priv, msg);
+	} else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
+		skb = alloc_can_skb(priv->netdev, &cf);
+		if (!skb)
+			return;
+
+		cf->can_id = be32_to_cpu(msg->id);
+		cf->can_dlc = get_can_dlc(msg->dlc & 0xF);
+
+		if (msg->flags & USB_8DEV_EXTID)
+			cf->can_id |= CAN_EFF_FLAG;
+
+		if (msg->flags & USB_8DEV_RTR)
+			cf->can_id |= CAN_RTR_FLAG;
+		else
+			memcpy(cf->data, msg->data, cf->can_dlc);
+
+		netif_rx(skb);
+
+		stats->rx_packets++;
+		stats->rx_bytes += cf->can_dlc;
+
+		can_led_event(priv->netdev, CAN_LED_EVENT_RX);
+	} else {
+		netdev_warn(priv->netdev, "frame type %d unknown",
+			 msg->type);
+	}
+
+}
+
+/* Callback for reading data from device
+ *
+ * Check urb status, call read function and resubmit urb read operation.
+ */
+static void usb_8dev_read_bulk_callback(struct urb *urb)
+{
+	struct usb_8dev_priv *priv = urb->context;
+	struct net_device *netdev;
+	int retval;
+	int pos = 0;
+
+	netdev = priv->netdev;
+
+	if (!netif_device_present(netdev))
+		return;
+
+	switch (urb->status) {
+	case 0: /* success */
+		break;
+
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+
+	default:
+		netdev_info(netdev, "Rx URB aborted (%d)\n",
+			 urb->status);
+		goto resubmit_urb;
+	}
+
+	while (pos < urb->actual_length) {
+		struct usb_8dev_rx_msg *msg;
+
+		if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) {
+			netdev_err(priv->netdev, "format error\n");
+			break;
+		}
+
+		msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos);
+		usb_8dev_rx_can_msg(priv, msg);
+
+		pos += sizeof(struct usb_8dev_rx_msg);
+	}
+
+resubmit_urb:
+	usb_fill_bulk_urb(urb, priv->udev,
+			  usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
+			  urb->transfer_buffer, RX_BUFFER_SIZE,
+			  usb_8dev_read_bulk_callback, priv);
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+	if (retval == -ENODEV)
+		netif_device_detach(netdev);
+	else if (retval)
+		netdev_err(netdev,
+			"failed resubmitting read bulk urb: %d\n", retval);
+}
+
+/* Callback handler for write operations
+ *
+ * Free allocated buffers, check transmit status and
+ * calculate statistic.
+ */
+static void usb_8dev_write_bulk_callback(struct urb *urb)
+{
+	struct usb_8dev_tx_urb_context *context = urb->context;
+	struct usb_8dev_priv *priv;
+	struct net_device *netdev;
+
+	BUG_ON(!context);
+
+	priv = context->priv;
+	netdev = priv->netdev;
+
+	/* free up our allocated buffer */
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
+
+	atomic_dec(&priv->active_tx_urbs);
+
+	if (!netif_device_present(netdev))
+		return;
+
+	if (urb->status)
+		netdev_info(netdev, "Tx URB aborted (%d)\n",
+			 urb->status);
+
+	netdev->stats.tx_packets++;
+	netdev->stats.tx_bytes += context->dlc;
+
+	can_get_echo_skb(netdev, context->echo_index);
+
+	can_led_event(netdev, CAN_LED_EVENT_TX);
+
+	/* Release context */
+	context->echo_index = MAX_TX_URBS;
+
+	netif_wake_queue(netdev);
+}
+
+/* Send data to device */
+static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
+				      struct net_device *netdev)
+{
+	struct usb_8dev_priv *priv = netdev_priv(netdev);
+	struct net_device_stats *stats = &netdev->stats;
+	struct can_frame *cf = (struct can_frame *) skb->data;
+	struct usb_8dev_tx_msg *msg;
+	struct urb *urb;
+	struct usb_8dev_tx_urb_context *context = NULL;
+	u8 *buf;
+	int i, err;
+	size_t size = sizeof(struct usb_8dev_tx_msg);
+
+	if (can_dropped_invalid_skb(netdev, skb))
+		return NETDEV_TX_OK;
+
+	/* create a URB, and a buffer for it, and copy the data to the URB */
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		netdev_err(netdev, "No memory left for URBs\n");
+		goto nomem;
+	}
+
+	buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC,
+				 &urb->transfer_dma);
+	if (!buf) {
+		netdev_err(netdev, "No memory left for USB buffer\n");
+		goto nomembuf;
+	}
+
+	memset(buf, 0, size);
+
+	msg = (struct usb_8dev_tx_msg *)buf;
+	msg->begin = USB_8DEV_DATA_START;
+	msg->flags = 0x00;
+
+	if (cf->can_id & CAN_RTR_FLAG)
+		msg->flags |= USB_8DEV_RTR;
+
+	if (cf->can_id & CAN_EFF_FLAG)
+		msg->flags |= USB_8DEV_EXTID;
+
+	msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK);
+	msg->dlc = cf->can_dlc;
+	memcpy(msg->data, cf->data, cf->can_dlc);
+	msg->end = USB_8DEV_DATA_END;
+
+	for (i = 0; i < MAX_TX_URBS; i++) {
+		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+			context = &priv->tx_contexts[i];
+			break;
+		}
+	}
+
+	/* May never happen! When this happens we'd more URBs in flight as
+	 * allowed (MAX_TX_URBS).
+	 */
+	if (!context)
+		goto nofreecontext;
+
+	context->priv = priv;
+	context->echo_index = i;
+	context->dlc = cf->can_dlc;
+
+	usb_fill_bulk_urb(urb, priv->udev,
+			  usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX),
+			  buf, size, usb_8dev_write_bulk_callback, context);
+	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	usb_anchor_urb(urb, &priv->tx_submitted);
+
+	can_put_echo_skb(skb, netdev, context->echo_index);
+
+	atomic_inc(&priv->active_tx_urbs);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (unlikely(err))
+		goto failed;
+	else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+		/* Slow down tx path */
+		netif_stop_queue(netdev);
+
+	/* Release our reference to this URB, the USB core will eventually free
+	 * it entirely.
+	 */
+	usb_free_urb(urb);
+
+	return NETDEV_TX_OK;
+
+nofreecontext:
+	usb_unanchor_urb(urb);
+	usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+	netdev_warn(netdev, "couldn't find free context");
+
+	return NETDEV_TX_BUSY;
+
+failed:
+	can_free_echo_skb(netdev, context->echo_index);
+
+	usb_unanchor_urb(urb);
+	usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+	atomic_dec(&priv->active_tx_urbs);
+
+	if (err == -ENODEV)
+		netif_device_detach(netdev);
+	else
+		netdev_warn(netdev, "failed tx_urb %d\n", err);
+
+nomembuf:
+	usb_free_urb(urb);
+
+nomem:
+	dev_kfree_skb(skb);
+	stats->tx_dropped++;
+
+	return NETDEV_TX_OK;
+}
+
+static int usb_8dev_get_berr_counter(const struct net_device *netdev,
+				     struct can_berr_counter *bec)
+{
+	struct usb_8dev_priv *priv = netdev_priv(netdev);
+
+	bec->txerr = priv->bec.txerr;
+	bec->rxerr = priv->bec.rxerr;
+
+	return 0;
+}
+
+/* Start USB device */
+static int usb_8dev_start(struct usb_8dev_priv *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	int err, i;
+
+	for (i = 0; i < MAX_RX_URBS; i++) {
+		struct urb *urb = NULL;
+		u8 *buf;
+
+		/* create a URB, and a buffer for it */
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			netdev_err(netdev, "No memory left for URBs\n");
+			err = -ENOMEM;
+			break;
+		}
+
+		buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+					 &urb->transfer_dma);
+		if (!buf) {
+			netdev_err(netdev, "No memory left for USB buffer\n");
+			usb_free_urb(urb);
+			err = -ENOMEM;
+			break;
+		}
+
+		usb_fill_bulk_urb(urb, priv->udev,
+				  usb_rcvbulkpipe(priv->udev,
+						  USB_8DEV_ENDP_DATA_RX),
+				  buf, RX_BUFFER_SIZE,
+				  usb_8dev_read_bulk_callback, priv);
+		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+		usb_anchor_urb(urb, &priv->rx_submitted);
+
+		err = usb_submit_urb(urb, GFP_KERNEL);
+		if (err) {
+			usb_unanchor_urb(urb);
+			usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
+					  urb->transfer_dma);
+			break;
+		}
+
+		/* Drop reference, USB core will take care of freeing it */
+		usb_free_urb(urb);
+	}
+
+	/* Did we submit any URBs */
+	if (i == 0) {
+		netdev_warn(netdev, "couldn't setup read URBs\n");
+		return err;
+	}
+
+	/* Warn if we've couldn't transmit all the URBs */
+	if (i < MAX_RX_URBS)
+		netdev_warn(netdev, "rx performance may be slow\n");
+
+	err = usb_8dev_cmd_open(priv);
+	if (err)
+		goto failed;
+
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	return 0;
+
+failed:
+	if (err == -ENODEV)
+		netif_device_detach(priv->netdev);
+
+	netdev_warn(netdev, "couldn't submit control: %d\n", err);
+
+	return err;
+}
+
+/* Open USB device */
+static int usb_8dev_open(struct net_device *netdev)
+{
+	struct usb_8dev_priv *priv = netdev_priv(netdev);
+	int err;
+
+	/* common open */
+	err = open_candev(netdev);
+	if (err)
+		return err;
+
+	can_led_event(netdev, CAN_LED_EVENT_OPEN);
+
+	/* finally start device */
+	err = usb_8dev_start(priv);
+	if (err) {
+		if (err == -ENODEV)
+			netif_device_detach(priv->netdev);
+
+		netdev_warn(netdev, "couldn't start device: %d\n",
+			 err);
+
+		close_candev(netdev);
+
+		return err;
+	}
+
+	netif_start_queue(netdev);
+
+	return 0;
+}
+
+static void unlink_all_urbs(struct usb_8dev_priv *priv)
+{
+	int i;
+
+	usb_kill_anchored_urbs(&priv->rx_submitted);
+
+	usb_kill_anchored_urbs(&priv->tx_submitted);
+	atomic_set(&priv->active_tx_urbs, 0);
+
+	for (i = 0; i < MAX_TX_URBS; i++)
+		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+/* Close USB device */
+static int usb_8dev_close(struct net_device *netdev)
+{
+	struct usb_8dev_priv *priv = netdev_priv(netdev);
+	int err = 0;
+
+	/* Send CLOSE command to CAN controller */
+	err = usb_8dev_cmd_close(priv);
+	if (err)
+		netdev_warn(netdev, "couldn't stop device");
+
+	priv->can.state = CAN_STATE_STOPPED;
+
+	netif_stop_queue(netdev);
+
+	/* Stop polling */
+	unlink_all_urbs(priv);
+
+	close_candev(netdev);
+
+	can_led_event(netdev, CAN_LED_EVENT_STOP);
+
+	return err;
+}
+
+static const struct net_device_ops usb_8dev_netdev_ops = {
+	.ndo_open = usb_8dev_open,
+	.ndo_stop = usb_8dev_close,
+	.ndo_start_xmit = usb_8dev_start_xmit,
+};
+
+static const struct can_bittiming_const usb_8dev_bittiming_const = {
+	.name = "usb_8dev",
+	.tseg1_min = 1,
+	.tseg1_max = 16,
+	.tseg2_min = 1,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 1024,
+	.brp_inc = 1,
+};
+
+/* Probe USB device
+ *
+ * Check device and firmware.
+ * Set supported modes and bittiming constants.
+ * Allocate some memory.
+ */
+static int usb_8dev_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct net_device *netdev;
+	struct usb_8dev_priv *priv;
+	int i, err = -ENOMEM;
+	u32 version;
+	char buf[18];
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+
+	/* product id looks strange, better we also check iProduct string */
+	if (usb_string(usbdev, usbdev->descriptor.iProduct, buf,
+		       sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) {
+		dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n");
+		return -ENODEV;
+	}
+
+	netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS);
+	if (!netdev) {
+		dev_err(&intf->dev, "Couldn't alloc candev\n");
+		return -ENOMEM;
+	}
+
+	priv = netdev_priv(netdev);
+
+	priv->udev = usbdev;
+	priv->netdev = netdev;
+
+	priv->can.state = CAN_STATE_STOPPED;
+	priv->can.clock.freq = USB_8DEV_ABP_CLOCK;
+	priv->can.bittiming_const = &usb_8dev_bittiming_const;
+	priv->can.do_set_mode = usb_8dev_set_mode;
+	priv->can.do_get_berr_counter = usb_8dev_get_berr_counter;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+				      CAN_CTRLMODE_LISTENONLY |
+				      CAN_CTRLMODE_ONE_SHOT;
+
+	netdev->netdev_ops = &usb_8dev_netdev_ops;
+
+	netdev->flags |= IFF_ECHO; /* we support local echo */
+
+	init_usb_anchor(&priv->rx_submitted);
+
+	init_usb_anchor(&priv->tx_submitted);
+	atomic_set(&priv->active_tx_urbs, 0);
+
+	for (i = 0; i < MAX_TX_URBS; i++)
+		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+	priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
+				      GFP_KERNEL);
+	if (!priv->cmd_msg_buffer)
+		goto cleanup_candev;
+
+	usb_set_intfdata(intf, priv);
+
+	SET_NETDEV_DEV(netdev, &intf->dev);
+
+	mutex_init(&priv->usb_8dev_cmd_lock);
+
+	err = register_candev(netdev);
+	if (err) {
+		netdev_err(netdev,
+			"couldn't register CAN device: %d\n", err);
+		goto cleanup_cmd_msg_buffer;
+	}
+
+	err = usb_8dev_cmd_version(priv, &version);
+	if (err) {
+		netdev_err(netdev, "can't get firmware version\n");
+		goto cleanup_cmd_msg_buffer;
+	} else {
+		netdev_info(netdev,
+			 "firmware: %d.%d, hardware: %d.%d\n",
+			 (version>>24) & 0xff, (version>>16) & 0xff,
+			 (version>>8) & 0xff, version & 0xff);
+	}
+
+	devm_can_led_init(netdev);
+
+	return 0;
+
+cleanup_cmd_msg_buffer:
+	kfree(priv->cmd_msg_buffer);
+
+cleanup_candev:
+	free_candev(netdev);
+
+	return err;
+
+}
+
+/* Called by the usb core when driver is unloaded or device is removed */
+static void usb_8dev_disconnect(struct usb_interface *intf)
+{
+	struct usb_8dev_priv *priv = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+
+	if (priv) {
+		netdev_info(priv->netdev, "device disconnected\n");
+
+		unregister_netdev(priv->netdev);
+		free_candev(priv->netdev);
+
+		unlink_all_urbs(priv);
+	}
+
+}
+
+static struct usb_driver usb_8dev_driver = {
+	.name =		"usb_8dev",
+	.probe =	usb_8dev_probe,
+	.disconnect =	usb_8dev_disconnect,
+	.id_table =	usb_8dev_table,
+};
+
+module_usb_driver(usb_8dev_driver);
+
+MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>");
+MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 021d69c..29e272c 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1448,10 +1448,10 @@
 static void e100_get_drvinfo(struct net_device *dev,
 			     struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1);
-	strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1);
-	strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1);
-	strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);
+	strlcpy(info->driver, "ETRAX 100LX", sizeof(info->driver));
+	strlcpy(info->version, "$Revision: 1.31 $", sizeof(info->version));
+	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+	strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
 }
 
 static int e100_nway_reset(struct net_device *dev)
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 325391d..7a54ec0 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -66,36 +68,30 @@
 {
 	int i;
 	int ret;
+	unsigned long timeout;
 
-	/*
-	 * Set all ports to the disabled state.
-	 */
+	/* Set all ports to the disabled state. */
 	for (i = 0; i < 6; i++) {
 		ret = REG_READ(REG_PORT(i), 0x04);
 		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
 	}
 
-	/*
-	 * Wait for transmit queues to drain.
-	 */
-	msleep(2);
+	/* Wait for transmit queues to drain. */
+	usleep_range(2000, 4000);
 
-	/*
-	 * Reset the switch.
-	 */
+	/* Reset the switch. */
 	REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
 
-	/*
-	 * Wait up to one second for reset to complete.
-	 */
-	for (i = 0; i < 1000; i++) {
+	/* Wait up to one second for reset to complete. */
+	timeout = jiffies + 1 * HZ;
+	while (time_before(jiffies, timeout)) {
 		ret = REG_READ(REG_GLOBAL, 0x00);
 		if ((ret & 0x8000) == 0x0000)
 			break;
 
-		msleep(1);
+		usleep_range(1000, 2000);
 	}
-	if (i == 1000)
+	if (time_after(jiffies, timeout))
 		return -ETIMEDOUT;
 
 	return 0;
@@ -103,15 +99,13 @@
 
 static int mv88e6060_setup_global(struct dsa_switch *ds)
 {
-	/*
-	 * Disable discarding of frames with excessive collisions,
+	/* Disable discarding of frames with excessive collisions,
 	 * set the maximum frame size to 1536 bytes, and mask all
 	 * interrupt sources.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
 
-	/*
-	 * Enable automatic address learning, set the address
+	/* Enable automatic address learning, set the address
 	 * database size to 1024 entries, and set the default aging
 	 * time to 5 minutes.
 	 */
@@ -124,16 +118,14 @@
 {
 	int addr = REG_PORT(p);
 
-	/*
-	 * Do not force flow control, disable Ingress and Egress
+	/* Do not force flow control, disable Ingress and Egress
 	 * Header tagging, disable VLAN tunneling, and set the port
 	 * state to Forwarding.  Additionally, if this is the CPU
 	 * port, enable Ingress and Egress Trailer tagging mode.
 	 */
 	REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
 
-	/*
-	 * Port based VLAN map: give each port its own address
+	/* Port based VLAN map: give each port its own address
 	 * database, allow the CPU port to talk to each of the 'real'
 	 * ports, and allow each of the 'real' ports to only talk to
 	 * the CPU port.
@@ -144,8 +136,7 @@
 				ds->phys_port_mask :
 				(1 << ds->dst->cpu_port)));
 
-	/*
-	 * Port Association Vector: when learning source addresses
+	/* Port Association Vector: when learning source addresses
 	 * of packets, add the address to the address database using
 	 * a port bitmap that has only the bit for this port set and
 	 * the other bits clear.
@@ -245,7 +236,7 @@
 
 		if (!link) {
 			if (netif_carrier_ok(dev)) {
-				printk(KERN_INFO "%s: link down\n", dev->name);
+				netdev_info(dev, "link down\n");
 				netif_carrier_off(dev);
 			}
 			continue;
@@ -256,10 +247,11 @@
 		fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
 
 		if (!netif_carrier_ok(dev)) {
-			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
-					 "flow control %sabled\n", dev->name,
-					 speed, duplex ? "full" : "half",
-					 fc ? "en" : "dis");
+			netdev_info(dev,
+				    "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+				    speed,
+				    duplex ? "full" : "half",
+				    fc ? "en" : "dis");
 			netif_carrier_on(dev);
 		}
 	}
diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c
index c17c75b..41ee5b6 100644
--- a/drivers/net/dsa/mv88e6123_61_65.c
+++ b/drivers/net/dsa/mv88e6123_61_65.c
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -50,36 +52,30 @@
 {
 	int i;
 	int ret;
+	unsigned long timeout;
 
-	/*
-	 * Set all ports to the disabled state.
-	 */
+	/* Set all ports to the disabled state. */
 	for (i = 0; i < 8; i++) {
 		ret = REG_READ(REG_PORT(i), 0x04);
 		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
 	}
 
-	/*
-	 * Wait for transmit queues to drain.
-	 */
-	msleep(2);
+	/* Wait for transmit queues to drain. */
+	usleep_range(2000, 4000);
 
-	/*
-	 * Reset the switch.
-	 */
+	/* Reset the switch. */
 	REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
 
-	/*
-	 * Wait up to one second for reset to complete.
-	 */
-	for (i = 0; i < 1000; i++) {
+	/* Wait up to one second for reset to complete. */
+	timeout = jiffies + 1 * HZ;
+	while (time_before(jiffies, timeout)) {
 		ret = REG_READ(REG_GLOBAL, 0x00);
 		if ((ret & 0xc800) == 0xc800)
 			break;
 
-		msleep(1);
+		usleep_range(1000, 2000);
 	}
-	if (i == 1000)
+	if (time_after(jiffies, timeout))
 		return -ETIMEDOUT;
 
 	return 0;
@@ -90,54 +86,45 @@
 	int ret;
 	int i;
 
-	/*
-	 * Disable the PHY polling unit (since there won't be any
+	/* Disable the PHY polling unit (since there won't be any
 	 * external PHYs to poll), don't discard packets with
 	 * excessive collisions, and mask all interrupt sources.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
 
-	/*
-	 * Set the default address aging time to 5 minutes, and
+	/* Set the default address aging time to 5 minutes, and
 	 * enable address learn messages to be sent to all message
 	 * ports.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
 
-	/*
-	 * Configure the priority mapping registers.
-	 */
+	/* Configure the priority mapping registers. */
 	ret = mv88e6xxx_config_prio(ds);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Configure the upstream port, and configure the upstream
+	/* Configure the upstream port, and configure the upstream
 	 * port as the port to which ingress and egress monitor frames
 	 * are to be sent.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
 
-	/*
-	 * Disable remote management for now, and set the switch's
+	/* Disable remote management for now, and set the switch's
 	 * DSA device number.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
 
-	/*
-	 * Send all frames with destination addresses matching
+	/* Send all frames with destination addresses matching
 	 * 01:80:c2:00:00:2x to the CPU port.
 	 */
 	REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
 
-	/*
-	 * Send all frames with destination addresses matching
+	/* Send all frames with destination addresses matching
 	 * 01:80:c2:00:00:0x to the CPU port.
 	 */
 	REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
 
-	/*
-	 * Disable the loopback filter, disable flow control
+	/* Disable the loopback filter, disable flow control
 	 * messages, disable flood broadcast override, disable
 	 * removing of provider tags, disable ATU age violation
 	 * interrupts, disable tag flow control, force flow
@@ -146,9 +133,7 @@
 	 */
 	REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 
-	/*
-	 * Program the DSA routing table.
-	 */
+	/* Program the DSA routing table. */
 	for (i = 0; i < 32; i++) {
 		int nexthop;
 
@@ -159,33 +144,24 @@
 		REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
 	}
 
-	/*
-	 * Clear all trunk masks.
-	 */
+	/* Clear all trunk masks. */
 	for (i = 0; i < 8; i++)
 		REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
 
-	/*
-	 * Clear all trunk mappings.
-	 */
+	/* Clear all trunk mappings. */
 	for (i = 0; i < 16; i++)
 		REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
 
-	/*
-	 * Disable ingress rate limiting by resetting all ingress
+	/* Disable ingress rate limiting by resetting all ingress
 	 * rate limit registers to their initial state.
 	 */
 	for (i = 0; i < 6; i++)
 		REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
 
-	/*
-	 * Initialise cross-chip port VLAN table to reset defaults.
-	 */
+	/* Initialise cross-chip port VLAN table to reset defaults. */
 	REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
 
-	/*
-	 * Clear the priority override table.
-	 */
+	/* Clear the priority override table. */
 	for (i = 0; i < 16; i++)
 		REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
 
@@ -199,8 +175,7 @@
 	int addr = REG_PORT(p);
 	u16 val;
 
-	/*
-	 * MAC Forcing register: don't force link, speed, duplex
+	/* MAC Forcing register: don't force link, speed, duplex
 	 * or flow control state to any particular values on physical
 	 * ports, but force the CPU port and all DSA ports to 1000 Mb/s
 	 * full duplex.
@@ -210,15 +185,13 @@
 	else
 		REG_WRITE(addr, 0x01, 0x0003);
 
-	/*
-	 * Do not limit the period of time that this port can be
+	/* Do not limit the period of time that this port can be
 	 * paused for by the remote end or the period of time that
 	 * this port can pause the remote end.
 	 */
 	REG_WRITE(addr, 0x02, 0x0000);
 
-	/*
-	 * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+	/* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
 	 * disable Header mode, enable IGMP/MLD snooping, disable VLAN
 	 * tunneling, determine priority by looking at 802.1p and IP
 	 * priority fields (IP prio has precedence), and set STP state
@@ -245,14 +218,12 @@
 		val |= 0x000c;
 	REG_WRITE(addr, 0x04, val);
 
-	/*
-	 * Port Control 1: disable trunking.  Also, if this is the
+	/* Port Control 1: disable trunking.  Also, if this is the
 	 * CPU port, enable learn messages to be sent to this port.
 	 */
 	REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 
-	/*
-	 * Port based VLAN map: give each port its own address
+	/* Port based VLAN map: give each port its own address
 	 * database, allow the CPU port to talk to each of the 'real'
 	 * ports, and allow each of the 'real' ports to only talk to
 	 * the upstream port.
@@ -264,14 +235,12 @@
 		val |= 1 << dsa_upstream_port(ds);
 	REG_WRITE(addr, 0x06, val);
 
-	/*
-	 * Default VLAN ID and priority: don't set a default VLAN
+	/* Default VLAN ID and priority: don't set a default VLAN
 	 * ID, and set the default packet priority to zero.
 	 */
 	REG_WRITE(addr, 0x07, 0x0000);
 
-	/*
-	 * Port Control 2: don't force a good FCS, set the maximum
+	/* Port Control 2: don't force a good FCS, set the maximum
 	 * frame size to 10240 bytes, don't let the switch add or
 	 * strip 802.1q tags, don't discard tagged or untagged frames
 	 * on this port, do a destination address lookup on all
@@ -281,48 +250,36 @@
 	 */
 	REG_WRITE(addr, 0x08, 0x2080);
 
-	/*
-	 * Egress rate control: disable egress rate control.
-	 */
+	/* Egress rate control: disable egress rate control. */
 	REG_WRITE(addr, 0x09, 0x0001);
 
-	/*
-	 * Egress rate control 2: disable egress rate control.
-	 */
+	/* Egress rate control 2: disable egress rate control. */
 	REG_WRITE(addr, 0x0a, 0x0000);
 
-	/*
-	 * Port Association Vector: when learning source addresses
+	/* Port Association Vector: when learning source addresses
 	 * of packets, add the address to the address database using
 	 * a port bitmap that has only the bit for this port set and
 	 * the other bits clear.
 	 */
 	REG_WRITE(addr, 0x0b, 1 << p);
 
-	/*
-	 * Port ATU control: disable limiting the number of address
+	/* Port ATU control: disable limiting the number of address
 	 * database entries that this port is allowed to use.
 	 */
 	REG_WRITE(addr, 0x0c, 0x0000);
 
-	/*
-	 * Priorit Override: disable DA, SA and VTU priority override.
-	 */
+	/* Priority Override: disable DA, SA and VTU priority override. */
 	REG_WRITE(addr, 0x0d, 0x0000);
 
-	/*
-	 * Port Ethertype: use the Ethertype DSA Ethertype value.
-	 */
+	/* Port Ethertype: use the Ethertype DSA Ethertype value. */
 	REG_WRITE(addr, 0x0f, ETH_P_EDSA);
 
-	/*
-	 * Tag Remap: use an identity 802.1p prio -> switch prio
+	/* Tag Remap: use an identity 802.1p prio -> switch prio
 	 * mapping.
 	 */
 	REG_WRITE(addr, 0x18, 0x3210);
 
-	/*
-	 * Tag Remap 2: use an identity 802.1p prio -> switch prio
+	/* Tag Remap 2: use an identity 802.1p prio -> switch prio
 	 * mapping.
 	 */
 	REG_WRITE(addr, 0x19, 0x7654);
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index 55888b0..dadfafb 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -15,9 +17,7 @@
 #include <net/dsa.h>
 #include "mv88e6xxx.h"
 
-/*
- * Switch product IDs
- */
+/* Switch product IDs */
 #define ID_6085		0x04a0
 #define ID_6095		0x0950
 #define ID_6131		0x1060
@@ -44,36 +44,30 @@
 {
 	int i;
 	int ret;
+	unsigned long timeout;
 
-	/*
-	 * Set all ports to the disabled state.
-	 */
+	/* Set all ports to the disabled state. */
 	for (i = 0; i < 11; i++) {
 		ret = REG_READ(REG_PORT(i), 0x04);
 		REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
 	}
 
-	/*
-	 * Wait for transmit queues to drain.
-	 */
-	msleep(2);
+	/* Wait for transmit queues to drain. */
+	usleep_range(2000, 4000);
 
-	/*
-	 * Reset the switch.
-	 */
+	/* Reset the switch. */
 	REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
 
-	/*
-	 * Wait up to one second for reset to complete.
-	 */
-	for (i = 0; i < 1000; i++) {
+	/* Wait up to one second for reset to complete. */
+	timeout = jiffies + 1 * HZ;
+	while (time_before(jiffies, timeout)) {
 		ret = REG_READ(REG_GLOBAL, 0x00);
 		if ((ret & 0xc800) == 0xc800)
 			break;
 
-		msleep(1);
+		usleep_range(1000, 2000);
 	}
-	if (i == 1000)
+	if (time_after(jiffies, timeout))
 		return -ETIMEDOUT;
 
 	return 0;
@@ -84,42 +78,34 @@
 	int ret;
 	int i;
 
-	/*
-	 * Enable the PHY polling unit, don't discard packets with
+	/* Enable the PHY polling unit, don't discard packets with
 	 * excessive collisions, use a weighted fair queueing scheme
 	 * to arbitrate between packet queues, set the maximum frame
 	 * size to 1632, and mask all interrupt sources.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
 
-	/*
-	 * Set the default address aging time to 5 minutes, and
+	/* Set the default address aging time to 5 minutes, and
 	 * enable address learn messages to be sent to all message
 	 * ports.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
 
-	/*
-	 * Configure the priority mapping registers.
-	 */
+	/* Configure the priority mapping registers. */
 	ret = mv88e6xxx_config_prio(ds);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Set the VLAN ethertype to 0x8100.
-	 */
+	/* Set the VLAN ethertype to 0x8100. */
 	REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
 
-	/*
-	 * Disable ARP mirroring, and configure the upstream port as
+	/* Disable ARP mirroring, and configure the upstream port as
 	 * the port to which ingress and egress monitor frames are to
 	 * be sent.
 	 */
 	REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
 
-	/*
-	 * Disable cascade port functionality unless this device
+	/* Disable cascade port functionality unless this device
 	 * is used in a cascade configuration, and set the switch's
 	 * DSA device number.
 	 */
@@ -128,23 +114,19 @@
 	else
 		REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
 
-	/*
-	 * Send all frames with destination addresses matching
+	/* Send all frames with destination addresses matching
 	 * 01:80:c2:00:00:0x to the CPU port.
 	 */
 	REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
 
-	/*
-	 * Ignore removed tag data on doubly tagged packets, disable
+	/* Ignore removed tag data on doubly tagged packets, disable
 	 * flow control messages, force flow control priority to the
 	 * highest, and send all special multicast frames to the CPU
 	 * port at the highest priority.
 	 */
 	REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 
-	/*
-	 * Program the DSA routing table.
-	 */
+	/* Program the DSA routing table. */
 	for (i = 0; i < 32; i++) {
 		int nexthop;
 
@@ -155,20 +137,15 @@
 		REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
 	}
 
-	/*
-	 * Clear all trunk masks.
-	 */
+	/* Clear all trunk masks. */
 	for (i = 0; i < 8; i++)
 		REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
 
-	/*
-	 * Clear all trunk mappings.
-	 */
+	/* Clear all trunk mappings. */
 	for (i = 0; i < 16; i++)
 		REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
 
-	/*
-	 * Force the priority of IGMP/MLD snoop frames and ARP frames
+	/* Force the priority of IGMP/MLD snoop frames and ARP frames
 	 * to the highest setting.
 	 */
 	REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
@@ -182,8 +159,7 @@
 	int addr = REG_PORT(p);
 	u16 val;
 
-	/*
-	 * MAC Forcing register: don't force link, speed, duplex
+	/* MAC Forcing register: don't force link, speed, duplex
 	 * or flow control state to any particular values on physical
 	 * ports, but force the CPU port and all DSA ports to 1000 Mb/s
 	 * (100 Mb/s on 6085) full duplex.
@@ -196,8 +172,7 @@
 	else
 		REG_WRITE(addr, 0x01, 0x0003);
 
-	/*
-	 * Port Control: disable Core Tag, disable Drop-on-Lock,
+	/* Port Control: disable Core Tag, disable Drop-on-Lock,
 	 * transmit frames unmodified, disable Header mode,
 	 * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
 	 * tunneling, determine priority by looking at 802.1p and
@@ -214,8 +189,7 @@
 	val = 0x0433;
 	if (p == dsa_upstream_port(ds)) {
 		val |= 0x0104;
-		/*
-		 * On 6085, unknown multicast forward is controlled
+		/* On 6085, unknown multicast forward is controlled
 		 * here rather than in Port Control 2 register.
 		 */
 		if (ps->id == ID_6085)
@@ -225,14 +199,12 @@
 		val |= 0x0100;
 	REG_WRITE(addr, 0x04, val);
 
-	/*
-	 * Port Control 1: disable trunking.  Also, if this is the
+	/* Port Control 1: disable trunking.  Also, if this is the
 	 * CPU port, enable learn messages to be sent to this port.
 	 */
 	REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 
-	/*
-	 * Port based VLAN map: give each port its own address
+	/* Port based VLAN map: give each port its own address
 	 * database, allow the CPU port to talk to each of the 'real'
 	 * ports, and allow each of the 'real' ports to only talk to
 	 * the upstream port.
@@ -244,14 +216,12 @@
 		val |= 1 << dsa_upstream_port(ds);
 	REG_WRITE(addr, 0x06, val);
 
-	/*
-	 * Default VLAN ID and priority: don't set a default VLAN
+	/* Default VLAN ID and priority: don't set a default VLAN
 	 * ID, and set the default packet priority to zero.
 	 */
 	REG_WRITE(addr, 0x07, 0x0000);
 
-	/*
-	 * Port Control 2: don't force a good FCS, don't use
+	/* Port Control 2: don't force a good FCS, don't use
 	 * VLAN-based, source address-based or destination
 	 * address-based priority overrides, don't let the switch
 	 * add or strip 802.1q tags, don't discard tagged or
@@ -264,8 +234,7 @@
 	 * forwarding of unknown multicast addresses.
 	 */
 	if (ps->id == ID_6085)
-		/*
-		 * on 6085, bits 3:0 are reserved, bit 6 control ARP
+		/* on 6085, bits 3:0 are reserved, bit 6 control ARP
 		 * mirroring, and multicast forward is handled in
 		 * Port Control register.
 		 */
@@ -277,32 +246,25 @@
 		REG_WRITE(addr, 0x08, val);
 	}
 
-	/*
-	 * Rate Control: disable ingress rate limiting.
-	 */
+	/* Rate Control: disable ingress rate limiting. */
 	REG_WRITE(addr, 0x09, 0x0000);
 
-	/*
-	 * Rate Control 2: disable egress rate limiting.
-	 */
+	/* Rate Control 2: disable egress rate limiting. */
 	REG_WRITE(addr, 0x0a, 0x0000);
 
-	/*
-	 * Port Association Vector: when learning source addresses
+	/* Port Association Vector: when learning source addresses
 	 * of packets, add the address to the address database using
 	 * a port bitmap that has only the bit for this port set and
 	 * the other bits clear.
 	 */
 	REG_WRITE(addr, 0x0b, 1 << p);
 
-	/*
-	 * Tag Remap: use an identity 802.1p prio -> switch prio
+	/* Tag Remap: use an identity 802.1p prio -> switch prio
 	 * mapping.
 	 */
 	REG_WRITE(addr, 0x18, 0x3210);
 
-	/*
-	 * Tag Remap 2: use an identity 802.1p prio -> switch prio
+	/* Tag Remap 2: use an identity 802.1p prio -> switch prio
 	 * mapping.
 	 */
 	REG_WRITE(addr, 0x19, 0x7654);
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index a2c62c2..17314ed 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -8,6 +8,8 @@
  * (at your option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -15,8 +17,7 @@
 #include <net/dsa.h>
 #include "mv88e6xxx.h"
 
-/*
- * If the switch's ADDR[4:0] strap pins are strapped to zero, it will
+/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
  * use all 32 SMI bus addresses on its SMI bus, and all switch registers
  * will be directly accessible on some {device address,register address}
  * pair.  If the ADDR[4:0] pins are not strapped to zero, the switch
@@ -48,30 +49,22 @@
 	if (sw_addr == 0)
 		return mdiobus_read(bus, addr, reg);
 
-	/*
-	 * Wait for the bus to become free.
-	 */
+	/* Wait for the bus to become free. */
 	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Transmit the read command.
-	 */
+	/* Transmit the read command. */
 	ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Wait for the read command to complete.
-	 */
+	/* Wait for the read command to complete. */
 	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Read the data.
-	 */
+	/* Read the data. */
 	ret = mdiobus_read(bus, sw_addr, 1);
 	if (ret < 0)
 		return ret;
@@ -100,30 +93,22 @@
 	if (sw_addr == 0)
 		return mdiobus_write(bus, addr, reg, val);
 
-	/*
-	 * Wait for the bus to become free.
-	 */
+	/* Wait for the bus to become free. */
 	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Transmit the data to write.
-	 */
+	/* Transmit the data to write. */
 	ret = mdiobus_write(bus, sw_addr, 1, val);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Transmit the write command.
-	 */
+	/* Transmit the write command. */
 	ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Wait for the write command to complete.
-	 */
+	/* Wait for the write command to complete. */
 	ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
 	if (ret < 0)
 		return ret;
@@ -146,9 +131,7 @@
 
 int mv88e6xxx_config_prio(struct dsa_switch *ds)
 {
-	/*
-	 * Configure the IP ToS mapping registers.
-	 */
+	/* Configure the IP ToS mapping registers. */
 	REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
 	REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
 	REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
@@ -158,9 +141,7 @@
 	REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
 	REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
 
-	/*
-	 * Configure the IEEE 802.1p priority mapping register.
-	 */
+	/* Configure the IEEE 802.1p priority mapping register. */
 	REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
 
 	return 0;
@@ -183,14 +164,10 @@
 	for (i = 0; i < 6; i++) {
 		int j;
 
-		/*
-		 * Write the MAC address byte.
-		 */
+		/* Write the MAC address byte. */
 		REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
 
-		/*
-		 * Wait for the write to complete.
-		 */
+		/* Wait for the write to complete. */
 		for (j = 0; j < 16; j++) {
 			ret = REG_READ(REG_GLOBAL2, 0x0d);
 			if ((ret & 0x8000) == 0)
@@ -221,16 +198,17 @@
 static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
 {
 	int ret;
-	int i;
+	unsigned long timeout;
 
 	ret = REG_READ(REG_GLOBAL, 0x04);
 	REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
 
-	for (i = 0; i < 1000; i++) {
-	        ret = REG_READ(REG_GLOBAL, 0x00);
-	        msleep(1);
-	        if ((ret & 0xc000) != 0xc000)
-	                return 0;
+	timeout = jiffies + 1 * HZ;
+	while (time_before(jiffies, timeout)) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		usleep_range(1000, 2000);
+		if ((ret & 0xc000) != 0xc000)
+			return 0;
 	}
 
 	return -ETIMEDOUT;
@@ -239,16 +217,17 @@
 static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
 {
 	int ret;
-	int i;
+	unsigned long timeout;
 
 	ret = REG_READ(REG_GLOBAL, 0x04);
 	REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
 
-	for (i = 0; i < 1000; i++) {
-	        ret = REG_READ(REG_GLOBAL, 0x00);
-	        msleep(1);
-	        if ((ret & 0xc000) == 0xc000)
-	                return 0;
+	timeout = jiffies + 1 * HZ;
+	while (time_before(jiffies, timeout)) {
+		ret = REG_READ(REG_GLOBAL, 0x00);
+		usleep_range(1000, 2000);
+		if ((ret & 0xc000) == 0xc000)
+			return 0;
 	}
 
 	return -ETIMEDOUT;
@@ -260,11 +239,11 @@
 
 	ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
 	if (mutex_trylock(&ps->ppu_mutex)) {
-	        struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
+		struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
 
-	        if (mv88e6xxx_ppu_enable(ds) == 0)
-	                ps->ppu_disabled = 0;
-	        mutex_unlock(&ps->ppu_mutex);
+		if (mv88e6xxx_ppu_enable(ds) == 0)
+			ps->ppu_disabled = 0;
+		mutex_unlock(&ps->ppu_mutex);
 	}
 }
 
@@ -282,22 +261,21 @@
 
 	mutex_lock(&ps->ppu_mutex);
 
-	/*
-	 * If the PHY polling unit is enabled, disable it so that
+	/* If the PHY polling unit is enabled, disable it so that
 	 * we can access the PHY registers.  If it was already
 	 * disabled, cancel the timer that is going to re-enable
 	 * it.
 	 */
 	if (!ps->ppu_disabled) {
-	        ret = mv88e6xxx_ppu_disable(ds);
-	        if (ret < 0) {
-	                mutex_unlock(&ps->ppu_mutex);
-	                return ret;
-	        }
-	        ps->ppu_disabled = 1;
+		ret = mv88e6xxx_ppu_disable(ds);
+		if (ret < 0) {
+			mutex_unlock(&ps->ppu_mutex);
+			return ret;
+		}
+		ps->ppu_disabled = 1;
 	} else {
-	        del_timer(&ps->ppu_timer);
-	        ret = 0;
+		del_timer(&ps->ppu_timer);
+		ret = 0;
 	}
 
 	return ret;
@@ -307,9 +285,7 @@
 {
 	struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
 
-	/*
-	 * Schedule a timer to re-enable the PHY polling unit.
-	 */
+	/* Schedule a timer to re-enable the PHY polling unit. */
 	mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
 	mutex_unlock(&ps->ppu_mutex);
 }
@@ -331,8 +307,8 @@
 
 	ret = mv88e6xxx_ppu_access_get(ds);
 	if (ret >= 0) {
-	        ret = mv88e6xxx_reg_read(ds, addr, regnum);
-	        mv88e6xxx_ppu_access_put(ds);
+		ret = mv88e6xxx_reg_read(ds, addr, regnum);
+		mv88e6xxx_ppu_access_put(ds);
 	}
 
 	return ret;
@@ -345,8 +321,8 @@
 
 	ret = mv88e6xxx_ppu_access_get(ds);
 	if (ret >= 0) {
-	        ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
-	        mv88e6xxx_ppu_access_put(ds);
+		ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
+		mv88e6xxx_ppu_access_put(ds);
 	}
 
 	return ret;
@@ -380,7 +356,7 @@
 
 		if (!link) {
 			if (netif_carrier_ok(dev)) {
-				printk(KERN_INFO "%s: link down\n", dev->name);
+				netdev_info(dev, "link down\n");
 				netif_carrier_off(dev);
 			}
 			continue;
@@ -404,10 +380,11 @@
 		fc = (port_status & 0x8000) ? 1 : 0;
 
 		if (!netif_carrier_ok(dev)) {
-			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
-					 "flow control %sabled\n", dev->name,
-					 speed, duplex ? "full" : "half",
-					 fc ? "en" : "dis");
+			netdev_info(dev,
+				    "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+				    speed,
+				    duplex ? "full" : "half",
+				    fc ? "en" : "dis");
 			netif_carrier_on(dev);
 		}
 	}
@@ -431,14 +408,10 @@
 {
 	int ret;
 
-	/*
-	 * Snapshot the hardware statistics counters for this port.
-	 */
+	/* Snapshot the hardware statistics counters for this port. */
 	REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
 
-	/*
-	 * Wait for the snapshotting to complete.
-	 */
+	/* Wait for the snapshotting to complete. */
 	ret = mv88e6xxx_stats_wait(ds);
 	if (ret < 0)
 		return ret;
@@ -502,9 +475,7 @@
 		return;
 	}
 
-	/*
-	 * Read each of the counters.
-	 */
+	/* Read each of the counters. */
 	for (i = 0; i < nr_stats; i++) {
 		struct mv88e6xxx_hw_stat *s = stats + i;
 		u32 low;
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index fc2cd7b..911ede5 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -16,16 +16,14 @@
 #define REG_GLOBAL2		0x1c
 
 struct mv88e6xxx_priv_state {
-	/*
-	 * When using multi-chip addressing, this mutex protects
+	/* When using multi-chip addressing, this mutex protects
 	 * access to the indirect access registers.  (In single-chip
 	 * mode, this mutex is effectively useless.)
 	 */
 	struct mutex	smi_mutex;
 
 #ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
-	/*
-	 * Handles automatic disabling and re-enabling of the PHY
+	/* Handles automatic disabling and re-enabling of the PHY
 	 * polling unit.
 	 */
 	struct mutex		ppu_mutex;
@@ -34,8 +32,7 @@
 	struct timer_list	ppu_timer;
 #endif
 
-	/*
-	 * This mutex serialises access to the statistics unit.
+	/* This mutex serialises access to the statistics unit.
 	 * Hold this mutex over snapshot + dump sequences.
 	 */
 	struct mutex	stats_mutex;
@@ -52,7 +49,7 @@
 int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
 int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
 int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
-                          int reg, u16 val);
+			  int reg, u16 val);
 int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
 int mv88e6xxx_config_prio(struct dsa_switch *ds);
 int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index c260af5..42aa54a 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -100,6 +100,15 @@
 	free_percpu(dev->dstats);
 }
 
+static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+
 static const struct net_device_ops dummy_netdev_ops = {
 	.ndo_init		= dummy_dev_init,
 	.ndo_uninit		= dummy_dev_uninit,
@@ -108,6 +117,7 @@
 	.ndo_set_rx_mode	= set_multicast_list,
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_get_stats64	= dummy_get_stats64,
+	.ndo_change_carrier	= dummy_change_carrier,
 };
 
 static void dummy_setup(struct net_device *dev)
diff --git a/drivers/net/ethernet/3com/3c501.c b/drivers/net/ethernet/3com/3c501.c
deleted file mode 100644
index 2038eaa..0000000
--- a/drivers/net/ethernet/3com/3c501.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/* 3c501.c: A 3Com 3c501 Ethernet driver for Linux. */
-/*
-    Written 1992,1993,1994  Donald Becker
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU General Public License,
-    incorporated herein by reference.
-
-    This is a device driver for the 3Com Etherlink 3c501.
-    Do not purchase this card, even as a joke.  It's performance is horrible,
-    and it breaks in many ways.
-
-    The original author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-    Fixed (again!) the missing interrupt locking on TX/RX shifting.
-	Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Removed calls to init_etherdev since they are no longer needed, and
-    cleaned up modularization just a bit. The driver still allows only
-    the default address for cards when loaded as a module, but that's
-    really less braindead than anyone using a 3c501 board. :)
-		    19950208 (invid@msen.com)
-
-    Added traps for interrupts hitting the window as we clear and TX load
-    the board. Now getting 150K/second FTP with a 3c501 card. Still playing
-    with a TX-TX optimisation to see if we can touch 180-200K/second as seems
-    theoretically maximum.
-		19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Cleaned up for 2.3.x because we broke SMP now.
-		20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Check up pass for 2.5. Nothing significant changed
-		20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-    Fixed zero fill corner case
-		20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-
-   For the avoidance of doubt the "preferred form" of this code is one which
-   is in an open non patent encumbered format. Where cryptographic key signing
-   forms part of the process of creating an executable the information
-   including keys needed to generate an equivalently functional executable
-   are deemed to be part of the source code.
-
-*/
-
-
-/**
- * DOC: 3c501 Card Notes
- *
- *  Some notes on this thing if you have to hack it.  [Alan]
- *
- *  Some documentation is available from 3Com. Due to the boards age
- *  standard responses when you ask for this will range from 'be serious'
- *  to 'give it to a museum'. The documentation is incomplete and mostly
- *  of historical interest anyway.
- *
- *  The basic system is a single buffer which can be used to receive or
- *  transmit a packet. A third command mode exists when you are setting
- *  things up.
- *
- *  If it's transmitting it's not receiving and vice versa. In fact the
- *  time to get the board back into useful state after an operation is
- *  quite large.
- *
- *  The driver works by keeping the board in receive mode waiting for a
- *  packet to arrive. When one arrives it is copied out of the buffer
- *  and delivered to the kernel. The card is reloaded and off we go.
- *
- *  When transmitting lp->txing is set and the card is reset (from
- *  receive mode) [possibly losing a packet just received] to command
- *  mode. A packet is loaded and transmit mode triggered. The interrupt
- *  handler runs different code for transmit interrupts and can handle
- *  returning to receive mode or retransmissions (yes you have to help
- *  out with those too).
- *
- * DOC: Problems
- *
- *  There are a wide variety of undocumented error returns from the card
- *  and you basically have to kick the board and pray if they turn up. Most
- *  only occur under extreme load or if you do something the board doesn't
- *  like (eg touching a register at the wrong time).
- *
- *  The driver is less efficient than it could be. It switches through
- *  receive mode even if more transmits are queued. If this worries you buy
- *  a real Ethernet card.
- *
- *  The combination of slow receive restart and no real multicast
- *  filter makes the board unusable with a kernel compiled for IP
- *  multicasting in a real multicast environment. That's down to the board,
- *  but even with no multicast programs running a multicast IP kernel is
- *  in group 224.0.0.1 and you will therefore be listening to all multicasts.
- *  One nv conference running over that Ethernet and you can give up.
- *
- */
-
-#define DRV_NAME	"3c501"
-#define DRV_VERSION	"2002/10/09"
-
-
-static const char version[] =
-	DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
-
-/*
- *	Braindamage remaining:
- *	The 3c501 board.
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c501.h"
-
-/*
- *	The boilerplate probe code.
- */
-
-static int io = 0x280;
-static int irq = 5;
-static int mem_start;
-
-/**
- * el1_probe		-	probe for a 3c501
- * @dev: The device structure passed in to probe.
- *
- * This can be called from two places. The network layer will probe using
- * a device structure passed in with the probe information completed. For a
- * modular driver we use #init_module to fill in our own structure and probe
- * for it.
- *
- * Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to
- * probe and failing to find anything.
- */
-
-struct net_device * __init el1_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	static const unsigned ports[] = { 0x280, 0x300, 0};
-	const unsigned *port;
-	int err = 0;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-		mem_start = dev->mem_start & 7;
-	}
-
-	if (io > 0x1ff) {	/* Check a single specified location. */
-		err = el1_probe1(dev, io);
-	} else if (io != 0) {
-		err = -ENXIO;		/* Don't probe at all. */
-	} else {
-		for (port = ports; *port && el1_probe1(dev, *port); port++)
-			;
-		if (!*port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	release_region(dev->base_addr, EL1_IO_EXTENT);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static const struct net_device_ops el_netdev_ops = {
-	.ndo_open		= el_open,
-	.ndo_stop		= el1_close,
-	.ndo_start_xmit 	= el_start_xmit,
-	.ndo_tx_timeout		= el_timeout,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/**
- *	el1_probe1:
- *	@dev: The device structure to use
- *	@ioaddr: An I/O address to probe at.
- *
- *	The actual probe. This is iterated over by #el1_probe in order to
- *	check all the applicable device locations.
- *
- *	Returns 0 for a success, in which case the device is activated,
- *	EAGAIN if the IRQ is in use by another driver, and ENODEV if the
- *	board cannot be found.
- */
-
-static int __init el1_probe1(struct net_device *dev, int ioaddr)
-{
-	struct net_local *lp;
-	const char *mname;		/* Vendor name */
-	unsigned char station_addr[6];
-	int autoirq = 0;
-	int i;
-
-	/*
-	 *	Reserve I/O resource for exclusive use by this driver
-	 */
-
-	if (!request_region(ioaddr, EL1_IO_EXTENT, DRV_NAME))
-		return -ENODEV;
-
-	/*
-	 *	Read the station address PROM data from the special port.
-	 */
-
-	for (i = 0; i < 6; i++) {
-		outw(i, ioaddr + EL1_DATAPTR);
-		station_addr[i] = inb(ioaddr + EL1_SAPROM);
-	}
-	/*
-	 *	Check the first three octets of the S.A. for 3Com's prefix, or
-	 *	for the Sager NP943 prefix.
-	 */
-
-	if (station_addr[0] == 0x02 && station_addr[1] == 0x60 &&
-	    station_addr[2] == 0x8c)
-		mname = "3c501";
-	else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 &&
-		 station_addr[2] == 0xC8)
-		mname = "NP943";
-	else {
-		release_region(ioaddr, EL1_IO_EXTENT);
-		return -ENODEV;
-	}
-
-	/*
-	 *	We auto-IRQ by shutting off the interrupt line and letting it
-	 *	float high.
-	 */
-
-	dev->irq = irq;
-
-	if (dev->irq < 2) {
-		unsigned long irq_mask;
-
-		irq_mask = probe_irq_on();
-		inb(RX_STATUS);		/* Clear pending interrupts. */
-		inb(TX_STATUS);
-		outb(AX_LOOP + 1, AX_CMD);
-
-		outb(0x00, AX_CMD);
-
-		mdelay(20);
-		autoirq = probe_irq_off(irq_mask);
-
-		if (autoirq == 0) {
-			pr_warning("%s probe at %#x failed to detect IRQ line.\n",
-				mname, ioaddr);
-			release_region(ioaddr, EL1_IO_EXTENT);
-			return -EAGAIN;
-		}
-	}
-
-	outb(AX_RESET+AX_LOOP, AX_CMD);			/* Loopback mode. */
-	dev->base_addr = ioaddr;
-	memcpy(dev->dev_addr, station_addr, ETH_ALEN);
-
-	if (mem_start & 0xf)
-		el_debug = mem_start & 0x7;
-	if (autoirq)
-		dev->irq = autoirq;
-
-	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
-	pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n");
-#endif
-
-	if (el_debug)
-		pr_debug("%s", version);
-
-	lp = netdev_priv(dev);
-	memset(lp, 0, sizeof(struct net_local));
-	spin_lock_init(&lp->lock);
-
-	/*
-	 *	The EL1-specific entries in the device structure.
-	 */
-
-	dev->netdev_ops = &el_netdev_ops;
-	dev->watchdog_timeo = HZ;
-	dev->ethtool_ops = &netdev_ethtool_ops;
-	return 0;
-}
-
-/**
- *	el1_open:
- *	@dev: device that is being opened
- *
- *	When an ifconfig is issued which changes the device flags to include
- *	IFF_UP this function is called. It is only called when the change
- *	occurs, not when the interface remains up. #el1_close will be called
- *	when it goes down.
- *
- *	Returns 0 for a successful open, or -EAGAIN if someone has run off
- *	with our interrupt line.
- */
-
-static int el_open(struct net_device *dev)
-{
-	int retval;
-	int ioaddr = dev->base_addr;
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	if (el_debug > 2)
-		pr_debug("%s: Doing el_open()...\n", dev->name);
-
-	retval = request_irq(dev->irq, el_interrupt, 0, dev->name, dev);
-	if (retval)
-		return retval;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	el_reset(dev);
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	lp->txing = 0;		/* Board in RX mode */
-	outb(AX_RX, AX_CMD);	/* Aux control, irq and receive enabled */
-	netif_start_queue(dev);
-	return 0;
-}
-
-/**
- * el_timeout:
- * @dev: The 3c501 card that has timed out
- *
- * Attempt to restart the board. This is basically a mixture of extreme
- * violence and prayer
- *
- */
-
-static void el_timeout(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	if (el_debug)
-		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++;
-	outb(TX_NORM, TX_CMD);
-	outb(RX_NORM, RX_CMD);
-	outb(AX_OFF, AX_CMD);	/* Just trigger a false interrupt. */
-	outb(AX_RX, AX_CMD);	/* Aux control, irq and receive enabled */
-	lp->txing = 0;		/* Ripped back in to RX */
-	netif_wake_queue(dev);
-}
-
-
-/**
- * el_start_xmit:
- * @skb: The packet that is queued to be sent
- * @dev: The 3c501 card we want to throw it down
- *
- * Attempt to send a packet to a 3c501 card. There are some interesting
- * catches here because the 3c501 is an extremely old and therefore
- * stupid piece of technology.
- *
- * If we are handling an interrupt on the other CPU we cannot load a packet
- * as we may still be attempting to retrieve the last RX packet buffer.
- *
- * When a transmit times out we dump the card into control mode and just
- * start again. It happens enough that it isn't worth logging.
- *
- * We avoid holding the spin locks when doing the packet load to the board.
- * The device is very slow, and its DMA mode is even slower. If we held the
- * lock while loading 1500 bytes onto the controller we would drop a lot of
- * serial port characters. This requires we do extra locking, but we have
- * no real choice.
- */
-
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	/*
-	 *	Avoid incoming interrupts between us flipping txing and flipping
-	 *	mode as the driver assumes txing is a faithful indicator of card
-	 *	state
-	 */
-
-	spin_lock_irqsave(&lp->lock, flags);
-
-	/*
-	 *	Avoid timer-based retransmission conflicts.
-	 */
-
-	netif_stop_queue(dev);
-
-	do {
-		int len = skb->len;
-		int pad = 0;
-		int gp_start;
-		unsigned char *buf = skb->data;
-
-		if (len < ETH_ZLEN)
-			pad = ETH_ZLEN - len;
-
-		gp_start = 0x800 - (len + pad);
-
-		lp->tx_pkt_start = gp_start;
-		lp->collisions = 0;
-
-		dev->stats.tx_bytes += skb->len;
-
-		/*
-		 *	Command mode with status cleared should [in theory]
-		 *	mean no more interrupts can be pending on the card.
-		 */
-
-		outb_p(AX_SYS, AX_CMD);
-		inb_p(RX_STATUS);
-		inb_p(TX_STATUS);
-
-		lp->loading = 1;
-		lp->txing = 1;
-
-		/*
-		 *	Turn interrupts back on while we spend a pleasant
-		 *	afternoon loading bytes into the board
-		 */
-
-		spin_unlock_irqrestore(&lp->lock, flags);
-
-		/* Set rx packet area to 0. */
-		outw(0x00, RX_BUF_CLR);
-		/* aim - packet will be loaded into buffer start */
-		outw(gp_start, GP_LOW);
-		/* load buffer (usual thing each byte increments the pointer) */
-		outsb(DATAPORT, buf, len);
-		if (pad) {
-			while (pad--)		/* Zero fill buffer tail */
-				outb(0, DATAPORT);
-		}
-		/* the board reuses the same register */
-		outw(gp_start, GP_LOW);
-
-		if (lp->loading != 2) {
-			/* fire ... Trigger xmit.  */
-			outb(AX_XMIT, AX_CMD);
-			lp->loading = 0;
-			if (el_debug > 2)
-				pr_debug(" queued xmit.\n");
-			dev_kfree_skb(skb);
-			return NETDEV_TX_OK;
-		}
-		/* A receive upset our load, despite our best efforts */
-		if (el_debug > 2)
-			pr_debug("%s: burped during tx load.\n", dev->name);
-		spin_lock_irqsave(&lp->lock, flags);
-	} while (1);
-}
-
-/**
- * el_interrupt:
- * @irq: Interrupt number
- * @dev_id: The 3c501 that burped
- *
- * Handle the ether interface interrupts. The 3c501 needs a lot more
- * hand holding than most cards. In particular we get a transmit interrupt
- * with a collision error because the board firmware isn't capable of rewinding
- * its own transmit buffer pointers. It can however count to 16 for us.
- *
- * On the receive side the card is also very dumb. It has no buffering to
- * speak of. We simply pull the packet out of its PIO buffer (which is slow)
- * and queue it for the kernel. Then we reset the card for the next packet.
- *
- * We sometimes get surprise interrupts late both because the SMP IRQ delivery
- * is message passing and because the card sometimes seems to deliver late. I
- * think if it is part way through a receive and the mode is changed it carries
- * on receiving and sends us an interrupt. We have to band aid all these cases
- * to get a sensible 150kBytes/second performance. Even then you want a small
- * TCP window.
- */
-
-static irqreturn_t el_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr;
-	int axsr;			/* Aux. status reg. */
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	spin_lock(&lp->lock);
-
-	/*
-	 *	What happened ?
-	 */
-
-	axsr = inb(AX_STATUS);
-
-	/*
-	 *	Log it
-	 */
-
-	if (el_debug > 3)
-		pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr);
-
-	if (lp->loading == 1 && !lp->txing)
-		pr_warning("%s: Inconsistent state loading while not in tx\n",
-			dev->name);
-
-	if (lp->txing) {
-		/*
-		 *	Board in transmit mode. May be loading. If we are
-		 *	loading we shouldn't have got this.
-		 */
-		int txsr = inb(TX_STATUS);
-
-		if (lp->loading == 1) {
-			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)
-			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) {
-			/*
-			 *	FIXME: is there a logic to whether to keep
-			 *	on trying or reset immediately ?
-			 */
-			if (el_debug > 1)
-				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));
-			lp->txing = 0;
-			netif_wake_queue(dev);
-		} else if (txsr & TX_16COLLISIONS) {
-			/*
-			 *	Timed out
-			 */
-			if (el_debug)
-				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++;
-			netif_wake_queue(dev);
-		} else if (txsr & TX_COLLISION) {
-			/*
-			 *	Retrigger xmit.
-			 */
-
-			if (el_debug > 6)
-				pr_debug("%s: retransmitting after a collision.\n", dev->name);
-			/*
-			 *	Poor little chip can't reset its own start
-			 *	pointer
-			 */
-
-			outb(AX_SYS, AX_CMD);
-			outw(lp->tx_pkt_start, GP_LOW);
-			outb(AX_XMIT, AX_CMD);
-			dev->stats.collisions++;
-			spin_unlock(&lp->lock);
-			goto out;
-		} else {
-			/*
-			 *	It worked.. we will now fall through and receive
-			 */
-			dev->stats.tx_packets++;
-			if (el_debug > 6)
-				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.
-			 */
-			lp->txing = 0;
-			/* In case more to transmit */
-			netif_wake_queue(dev);
-		}
-	} else {
-		/*
-		 *	In receive mode.
-		 */
-
-		int rxsr = inb(RX_STATUS);
-		if (el_debug > 5)
-			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.
-		 */
-		if (rxsr & RX_MISSED)
-			dev->stats.rx_missed_errors++;
-		else if (rxsr & RX_RUNT) {
-			/* Handled to avoid board lock-up. */
-			dev->stats.rx_length_errors++;
-			if (el_debug > 5)
-				pr_debug("%s: runt.\n", dev->name);
-		} else if (rxsr & RX_GOOD) {
-			/*
-			 *	Receive worked.
-			 */
-			el_receive(dev);
-		} else {
-			/*
-			 *	Nothing?  Something is broken!
-			 */
-			if (el_debug > 2)
-				pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
-					dev->name, rxsr);
-			el_reset(dev);
-		}
-	}
-
-	/*
-	 *	Move into receive mode
-	 */
-
-	outb(AX_RX, AX_CMD);
-	outw(0x00, RX_BUF_CLR);
-	inb(RX_STATUS);		/* Be certain that interrupts are cleared. */
-	inb(TX_STATUS);
-	spin_unlock(&lp->lock);
-out:
-	return IRQ_HANDLED;
-}
-
-
-/**
- * el_receive:
- * @dev: Device to pull the packets from
- *
- * We have a good packet. Well, not really "good", just mostly not broken.
- * We must check everything to see if it is good. In particular we occasionally
- * get wild packet sizes from the card. If the packet seems sane we PIO it
- * off the card and queue it for the protocol layers.
- */
-
-static void el_receive(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	int pkt_len;
-	struct sk_buff *skb;
-
-	pkt_len = inw(RX_LOW);
-
-	if (el_debug > 4)
-		pr_debug(" el_receive %d.\n", pkt_len);
-
-	if (pkt_len < 60 || pkt_len > 1536) {
-		if (el_debug)
-			pr_debug("%s: bogus packet, length=%d\n",
-						dev->name, pkt_len);
-		dev->stats.rx_over_errors++;
-		return;
-	}
-
-	/*
-	 *	Command mode so we can empty the buffer
-	 */
-
-	outb(AX_SYS, AX_CMD);
-	skb = netdev_alloc_skb(dev, pkt_len + 2);
-
-	/*
-	 *	Start of frame
-	 */
-
-	outw(0x00, GP_LOW);
-	if (skb == NULL) {
-		pr_info("%s: Memory squeeze, dropping packet.\n", dev->name);
-		dev->stats.rx_dropped++;
-		return;
-	} else {
-		skb_reserve(skb, 2);	/* Force 16 byte alignment */
-		/*
-		 *	The read increments through the bytes. The interrupt
-		 *	handler will fix the pointer when it returns to
-		 *	receive mode.
-		 */
-		insb(DATAPORT, skb_put(skb, pkt_len), pkt_len);
-		skb->protocol = eth_type_trans(skb, dev);
-		netif_rx(skb);
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += pkt_len;
-	}
-}
-
-/**
- * el_reset: Reset a 3c501 card
- * @dev: The 3c501 card about to get zapped
- *
- * Even resetting a 3c501 isn't simple. When you activate reset it loses all
- * its configuration. You must hold the lock when doing this. The function
- * cannot take the lock itself as it is callable from the irq handler.
- */
-
-static void  el_reset(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	if (el_debug > 2)
-		pr_info("3c501 reset...\n");
-	outb(AX_RESET, AX_CMD);		/* Reset the chip */
-	/* Aux control, irq and loopback enabled */
-	outb(AX_LOOP, AX_CMD);
-	{
-		int i;
-		for (i = 0; i < 6; i++)	/* Set the station address. */
-			outb(dev->dev_addr[i], ioaddr + i);
-	}
-
-	outw(0, RX_BUF_CLR);		/* Set rx packet area to 0. */
-	outb(TX_NORM, TX_CMD);		/* tx irq on done, collision */
-	outb(RX_NORM, RX_CMD);		/* Set Rx commands. */
-	inb(RX_STATUS);			/* Clear status. */
-	inb(TX_STATUS);
-	lp->txing = 0;
-}
-
-/**
- * el1_close:
- * @dev: 3c501 card to shut down
- *
- * Close a 3c501 card. The IFF_UP flag has been cleared by the user via
- * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued,
- * and then disable the interrupts. Finally we reset the chip. The effects
- * of the rest will be cleaned up by #el1_open. Always returns 0 indicating
- * a success.
- */
-
-static int el1_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	if (el_debug > 2)
-		pr_info("%s: Shutting down Ethernet card at %#x.\n",
-						dev->name, ioaddr);
-
-	netif_stop_queue(dev);
-
-	/*
-	 *	Free and disable the IRQ.
-	 */
-
-	free_irq(dev->irq, dev);
-	outb(AX_RESET, AX_CMD);		/* Reset the chip */
-
-	return 0;
-}
-
-/**
- * set_multicast_list:
- * @dev: The device to adjust
- *
- * Set or clear the multicast filter for this adaptor to use the best-effort
- * filtering supported. The 3c501 supports only three modes of filtering.
- * It always receives broadcasts and packets for itself. You can choose to
- * optionally receive all packets, or all multicast packets on top of this.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	if (dev->flags & IFF_PROMISC) {
-		outb(RX_PROM, RX_CMD);
-		inb(RX_STATUS);
-	} else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
-		/* Multicast or all multicast is the same */
-		outb(RX_MULT, RX_CMD);
-		inb(RX_STATUS);		/* Clear status. */
-	} else {
-		outb(RX_NORM, RX_CMD);
-		inb(RX_STATUS);
-	}
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-	return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-	debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-	.get_msglevel		= netdev_get_msglevel,
-	.set_msglevel		= netdev_set_msglevel,
-};
-
-#ifdef MODULE
-
-static struct net_device *dev_3c501;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink I/O base address");
-MODULE_PARM_DESC(irq, "EtherLink IRQ number");
-
-/**
- * init_module:
- *
- * When the driver is loaded as a module this function is called. We fake up
- * a device structure with the base I/O and interrupt set as if it were being
- * called from Space.c. This minimises the extra code that would otherwise
- * be required.
- *
- * Returns 0 for success or -EIO if a card is not found. Returning an error
- * here also causes the module to be unloaded
- */
-
-int __init init_module(void)
-{
-	dev_3c501 = el1_probe(-1);
-	if (IS_ERR(dev_3c501))
-		return PTR_ERR(dev_3c501);
-	return 0;
-}
-
-/**
- * cleanup_module:
- *
- * The module is being unloaded. We unhook our network device from the system
- * and then free up the resources we took when the card was found.
- */
-
-void __exit cleanup_module(void)
-{
-	struct net_device *dev = dev_3c501;
-	unregister_netdev(dev);
-	release_region(dev->base_addr, EL1_IO_EXTENT);
-	free_netdev(dev);
-}
-
-#endif /* MODULE */
-
-MODULE_AUTHOR("Donald Becker, Alan Cox");
-MODULE_DESCRIPTION("Support for the ancient 3Com 3c501 ethernet card");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/ethernet/3com/3c501.h b/drivers/net/ethernet/3com/3c501.h
deleted file mode 100644
index 183fd55..0000000
--- a/drivers/net/ethernet/3com/3c501.h
+++ /dev/null
@@ -1,91 +0,0 @@
-
-/*
- *	Index to functions.
- */
-
-static int  el1_probe1(struct net_device *dev, int ioaddr);
-static int  el_open(struct net_device *dev);
-static void el_timeout(struct net_device *dev);
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el_interrupt(int irq, void *dev_id);
-static void el_receive(struct net_device *dev);
-static void el_reset(struct net_device *dev);
-static int  el1_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-#define EL1_IO_EXTENT	16
-
-#ifndef EL_DEBUG
-#define EL_DEBUG  0	/* use 0 for production, 1 for devel., >2 for debug */
-#endif			/* Anything above 5 is wordy death! */
-#define debug el_debug
-static int el_debug = EL_DEBUG;
-
-/*
- *	Board-specific info in netdev_priv(dev).
- */
-
-struct net_local
-{
-	int		tx_pkt_start;	/* The length of the current Tx packet. */
-	int		collisions;	/* Tx collisions this packet */
-	int		loading;	/* Spot buffer load collisions */
-	int		txing;		/* True if card is in TX mode */
-	spinlock_t	lock;		/* Serializing lock */
-};
-
-
-#define RX_STATUS (ioaddr + 0x06)
-#define RX_CMD	  RX_STATUS
-#define TX_STATUS (ioaddr + 0x07)
-#define TX_CMD	  TX_STATUS
-#define GP_LOW 	  (ioaddr + 0x08)
-#define GP_HIGH   (ioaddr + 0x09)
-#define RX_BUF_CLR (ioaddr + 0x0A)
-#define RX_LOW	  (ioaddr + 0x0A)
-#define RX_HIGH   (ioaddr + 0x0B)
-#define SAPROM	  (ioaddr + 0x0C)
-#define AX_STATUS (ioaddr + 0x0E)
-#define AX_CMD	  AX_STATUS
-#define DATAPORT  (ioaddr + 0x0F)
-#define TX_RDY 0x08		/* In TX_STATUS */
-
-#define EL1_DATAPTR	0x08
-#define EL1_RXPTR	0x0A
-#define EL1_SAPROM	0x0C
-#define EL1_DATAPORT 	0x0f
-
-/*
- *	Writes to the ax command register.
- */
-
-#define AX_OFF	0x00			/* Irq off, buffer access on */
-#define AX_SYS  0x40			/* Load the buffer */
-#define AX_XMIT 0x44			/* Transmit a packet */
-#define AX_RX	0x48			/* Receive a packet */
-#define AX_LOOP	0x0C			/* Loopback mode */
-#define AX_RESET 0x80
-
-/*
- *	Normal receive mode written to RX_STATUS.  We must intr on short packets
- *	to avoid bogus rx lockups.
- */
-
-#define RX_NORM 0xA8		/* 0x68 == all addrs, 0xA8 only to me. */
-#define RX_PROM 0x68		/* Senior Prom, uhmm promiscuous mode. */
-#define RX_MULT 0xE8		/* Accept multicast packets. */
-#define TX_NORM 0x0A		/* Interrupt on everything that might hang the chip */
-
-/*
- *	TX_STATUS register.
- */
-
-#define TX_COLLISION 0x02
-#define TX_16COLLISIONS 0x04
-#define TX_READY 0x08
-
-#define RX_RUNT 0x08
-#define RX_MISSED 0x01		/* Missed a packet due to 3c501 braindamage. */
-#define RX_GOOD	0x30		/* Good packet 0x20, or simple overflow 0x10. */
-
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
index 633c709..f36ff99 100644
--- a/drivers/net/ethernet/3com/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -1161,8 +1161,8 @@
 
 static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c
index 59e1e00..94c656f 100644
--- a/drivers/net/ethernet/3com/3c515.c
+++ b/drivers/net/ethernet/3com/3c515.c
@@ -1542,9 +1542,10 @@
 static void netdev_get_drvinfo(struct net_device *dev,
 			       struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx",
+		 dev->base_addr);
 }
 
 static u32 netdev_get_msglevel(struct net_device *dev)
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index ed0feb3..1928e20 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -1293,7 +1293,6 @@
 		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)
 		pr_cont(" %pM", dev->dev_addr);
 	/* Unfortunately an all zero eeprom passes the checksum and this
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index eb56174..1c71c76 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -5,7 +5,7 @@
 config NET_VENDOR_3COM
 	bool "3Com devices"
 	default y
-	depends on ISA || EISA || MCA || PCI || PCMCIA
+	depends on ISA || EISA || PCI || PCMCIA
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y
 	  and read the Ethernet-HOWTO, available from
@@ -18,23 +18,9 @@
 
 if NET_VENDOR_3COM
 
-config EL1
-	tristate "3c501 \"EtherLink\" support"
-	depends on ISA
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.  Also, consider buying a
-	  new card, since the 3c501 is slow, broken, and obsolete: you will
-	  have problems.  Some people suggest to ping ("man ping") a nearby
-	  machine every minute ("man cron") when using this card.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called 3c501.
-
 config EL3
-	tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
-	depends on (ISA || EISA || MCA)
+	tristate "3c509/3c579 \"EtherLink III\" support"
+	depends on (ISA || EISA)
 	---help---
 	  If you have a network (Ethernet) card belonging to the 3Com
 	  EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index 1e5382a..74046af 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -2,7 +2,6 @@
 # Makefile for the 3Com Ethernet device drivers
 #
 
-obj-$(CONFIG_EL1) += 3c501.o
 obj-$(CONFIG_EL3) += 3c509.o
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
diff --git a/drivers/net/ethernet/8390/3c503.c b/drivers/net/ethernet/8390/3c503.c
deleted file mode 100644
index 49d76bd..0000000
--- a/drivers/net/ethernet/8390/3c503.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
-/*
-    Written 1992-94 by Donald Becker.
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU General Public License,
-    incorporated herein by reference.
-
-    The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-
-    This driver should work with the 3c503 and 3c503/16.  It should be used
-    in shared memory mode for best performance, although it may also work
-    in programmed-I/O mode.
-
-    Sources:
-    EtherLink II Technical Reference Manual,
-    EtherLink II/16 Technical Reference Manual Supplement,
-    3Com Corporation, 5400 Bayfront Plaza, Santa Clara CA 95052-8145
-
-    The Crynwr 3c503 packet driver.
-
-    Changelog:
-
-    Paul Gortmaker	: add support for the 2nd 8kB of RAM on 16 bit cards.
-    Paul Gortmaker	: multiple card support for module users.
-    rjohnson@analogic.com : Fix up PIO interface for efficient operation.
-    Jeff Garzik		: ethtool support
-
-*/
-
-#define DRV_NAME	"3c503"
-#define DRV_VERSION	"1.10a"
-#define DRV_RELDATE	"11/17/2001"
-
-
-static const char version[] =
-    DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Donald Becker (becker@scyld.com)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ethtool.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-#include "8390.h"
-#include "3c503.h"
-#define WRD_COUNT 4
-
-static int el2_pio_probe(struct net_device *dev);
-static int el2_probe1(struct net_device *dev, int ioaddr);
-
-/* A zero-terminated list of I/O addresses to be probed in PIO mode. */
-static unsigned int netcard_portlist[] __initdata =
-	{ 0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
-
-#define EL2_IO_EXTENT	16
-
-static int el2_open(struct net_device *dev);
-static int el2_close(struct net_device *dev);
-static void el2_reset_8390(struct net_device *dev);
-static void el2_init_card(struct net_device *dev);
-static void el2_block_output(struct net_device *dev, int count,
-			     const unsigned char *buf, int start_page);
-static void el2_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-			   int ring_offset);
-static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-			 int ring_page);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-
-/* This routine probes for a memory-mapped 3c503 board by looking for
-   the "location register" at the end of the jumpered boot PROM space.
-   This works even if a PROM isn't there.
-
-   If the ethercard isn't found there is an optional probe for
-   ethercard jumpered to programmed-I/O mode.
-   */
-static int __init do_el2_probe(struct net_device *dev)
-{
-    int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
-    int base_addr = dev->base_addr;
-    int irq = dev->irq;
-
-    if (base_addr > 0x1ff)	/* Check a single specified location. */
-	return el2_probe1(dev, base_addr);
-    else if (base_addr != 0)		/* Don't probe at all. */
-	return -ENXIO;
-
-    for (addr = addrs; *addr; addr++) {
-	void __iomem *p = ioremap(*addr, 1);
-	unsigned base_bits;
-	int i;
-
-	if (!p)
-		continue;
-	base_bits = readb(p);
-	iounmap(p);
-	i = ffs(base_bits) - 1;
-	if (i == -1 || base_bits != (1 << i))
-	    continue;
-	if (el2_probe1(dev, netcard_portlist[i]) == 0)
-	    return 0;
-	dev->irq = irq;
-    }
-#if ! defined(no_probe_nonshared_memory)
-    return el2_pio_probe(dev);
-#else
-    return -ENODEV;
-#endif
-}
-
-/*  Try all of the locations that aren't obviously empty.  This touches
-    a lot of locations, and is much riskier than the code above. */
-static int __init
-el2_pio_probe(struct net_device *dev)
-{
-    int i;
-    int base_addr = dev->base_addr;
-    int irq = dev->irq;
-
-    if (base_addr > 0x1ff)	/* Check a single specified location. */
-	return el2_probe1(dev, base_addr);
-    else if (base_addr != 0)	/* Don't probe at all. */
-	return -ENXIO;
-
-    for (i = 0; netcard_portlist[i]; i++) {
-	if (el2_probe1(dev, netcard_portlist[i]) == 0)
-	    return 0;
-	dev->irq = irq;
-    }
-
-    return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init el2_probe(int unit)
-{
-	struct net_device *dev = alloc_eip_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_el2_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops el2_netdev_ops = {
-	.ndo_open		= el2_open,
-	.ndo_stop		= el2_close,
-
-	.ndo_start_xmit		= eip_start_xmit,
-	.ndo_tx_timeout		= eip_tx_timeout,
-	.ndo_get_stats		= eip_get_stats,
-	.ndo_set_rx_mode	= eip_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_change_mtu		= eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= eip_poll,
-#endif
-};
-
-/* Probe for the Etherlink II card at I/O port base IOADDR,
-   returning non-zero on success.  If found, set the station
-   address and memory parameters in DEVICE. */
-static int __init
-el2_probe1(struct net_device *dev, int ioaddr)
-{
-    int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
-    static unsigned version_printed;
-    unsigned long vendor_id;
-
-    if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
-	return -EBUSY;
-
-    if (!request_region(ioaddr + 0x400, 8, DRV_NAME)) {
-	retval = -EBUSY;
-	goto out;
-    }
-
-    /* Reset and/or avoid any lurking NE2000 */
-    if (inb(ioaddr + 0x408) == 0xff) {
-    	mdelay(1);
-	retval = -ENODEV;
-	goto out1;
-    }
-
-    /* We verify that it's a 3C503 board by checking the first three octets
-       of its ethernet address. */
-    iobase_reg = inb(ioaddr+0x403);
-    membase_reg = inb(ioaddr+0x404);
-    /* ASIC location registers should be 0 or have only a single bit set. */
-    if ((iobase_reg  & (iobase_reg - 1)) ||
-	(membase_reg & (membase_reg - 1))) {
-	retval = -ENODEV;
-	goto out1;
-    }
-    saved_406 = inb_p(ioaddr + 0x406);
-    outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
-    outb_p(ECNTRL_THIN, ioaddr + 0x406);
-    /* Map the station addr PROM into the lower I/O ports. We now check
-       for both the old and new 3Com prefix */
-    outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
-    vendor_id = inb(ioaddr)*0x10000 + inb(ioaddr + 1)*0x100 + inb(ioaddr + 2);
-    if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) {
-	/* Restore the register we frobbed. */
-	outb(saved_406, ioaddr + 0x406);
-	retval = -ENODEV;
-	goto out1;
-    }
-
-    if (ei_debug  &&  version_printed++ == 0)
-	pr_debug("%s", version);
-
-    dev->base_addr = 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);
-    pr_cont("%pM", dev->dev_addr);
-
-    /* Map the 8390 back into the window. */
-    outb(ECNTRL_THIN, ioaddr + 0x406);
-
-    /* Check for EL2/16 as described in tech. man. */
-    outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
-    outb_p(0, ioaddr + EN0_DCFG);
-    outb_p(E8390_PAGE2, ioaddr + E8390_CMD);
-    wordlength = inb_p(ioaddr + EN0_DCFG) & ENDCFG_WTS;
-    outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
-
-    /* Probe for, turn on and clear the board's shared memory. */
-    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.
-       Right now we use a sleazy hack to pass in the interface number
-       at boot-time via the low bits of the mem_end field.  That value is
-       unused, and the low bits would be discarded even if it was used. */
-#if defined(EI8390_THICK) || defined(EL2_AUI)
-    ei_status.interface_num = 1;
-#else
-    ei_status.interface_num = dev->mem_end & 0xf;
-#endif
-    pr_cont(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex");
-
-    if ((membase_reg & 0xf0) == 0) {
-	dev->mem_start = 0;
-	ei_status.name = "3c503-PIO";
-	ei_status.mem = NULL;
-    } else {
-	dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) +
-	    ((membase_reg & 0xA0) ? 0x4000 : 0);
-#define EL2_MEMSIZE (EL2_MB1_STOP_PG - EL2_MB1_START_PG)*256
-	ei_status.mem = ioremap(dev->mem_start, EL2_MEMSIZE);
-
-#ifdef EL2MEMTEST
-	/* This has never found an error, but someone might care.
-	   Note that it only tests the 2nd 8kB on 16kB 3c503/16
-	   cards between card addr. 0x2000 and 0x3fff. */
-	{			/* Check the card's memory. */
-	    void __iomem *mem_base = ei_status.mem;
-	    unsigned int test_val = 0xbbadf00d;
-	    writel(0xba5eba5e, mem_base);
-	    for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) {
-		writel(test_val, mem_base + i);
-		if (readl(mem_base) != 0xba5eba5e ||
-		    readl(mem_base + i) != test_val) {
-		    pr_warning("3c503: memory failure or memory address conflict.\n");
-		    dev->mem_start = 0;
-		    ei_status.name = "3c503-PIO";
-		    iounmap(mem_base);
-		    ei_status.mem = NULL;
-		    break;
-		}
-		test_val += 0x55555555;
-		writel(0, mem_base + i);
-	    }
-	}
-#endif  /* EL2MEMTEST */
-
-	if (dev->mem_start)
-		dev->mem_end = dev->mem_start + EL2_MEMSIZE;
-
-	if (wordlength) {	/* No Tx pages to skip over to get to Rx */
-		ei_status.priv = 0;
-		ei_status.name = "3c503/16";
-	} else {
-		ei_status.priv = TX_PAGES * 256;
-		ei_status.name = "3c503";
-	}
-    }
-
-    /*
-	Divide up the memory on the card. This is the same regardless of
-	whether shared-mem or PIO is used. For 16 bit cards (16kB RAM),
-	we use the entire 8k of bank1 for an Rx ring. We only use 3k
-	of the bank0 for 2 full size Tx packet slots. For 8 bit cards,
-	(8kB RAM) we use 3kB of bank1 for two Tx slots, and the remaining
-	5kB for an Rx ring.  */
-
-    if (wordlength) {
-	ei_status.tx_start_page = EL2_MB0_START_PG;
-	ei_status.rx_start_page = EL2_MB1_START_PG;
-    } else {
-	ei_status.tx_start_page = EL2_MB1_START_PG;
-	ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
-    }
-
-    /* Finish setting the board's parameters. */
-    ei_status.stop_page = EL2_MB1_STOP_PG;
-    ei_status.word16 = wordlength;
-    ei_status.reset_8390 = el2_reset_8390;
-    ei_status.get_8390_hdr = el2_get_8390_hdr;
-    ei_status.block_input = el2_block_input;
-    ei_status.block_output = el2_block_output;
-
-    if (dev->irq == 2)
-	dev->irq = 9;
-    else if (dev->irq > 5 && dev->irq != 9) {
-	pr_warning("3c503: configured interrupt %d invalid, will use autoIRQ.\n",
-	       dev->irq);
-	dev->irq = 0;
-    }
-
-    ei_status.saved_irq = dev->irq;
-
-    dev->netdev_ops = &el2_netdev_ops;
-    dev->ethtool_ops = &netdev_ethtool_ops;
-
-    retval = register_netdev(dev);
-    if (retval)
-	goto out1;
-
-    if (dev->mem_start)
-	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);
-
-    else
-    {
-	ei_status.tx_start_page = EL2_MB1_START_PG;
-	ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
-	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);
-    return 0;
-out1:
-    release_region(ioaddr + 0x400, 8);
-out:
-    release_region(ioaddr, EL2_IO_EXTENT);
-    return retval;
-}
-
-static irqreturn_t el2_probe_interrupt(int irq, void *seen)
-{
-	*(bool *)seen = true;
-	return IRQ_HANDLED;
-}
-
-static int
-el2_open(struct net_device *dev)
-{
-    int retval;
-
-    if (dev->irq < 2) {
-	static const int irqlist[] = {5, 9, 3, 4, 0};
-	const int *irqp = irqlist;
-
-	outb(EGACFR_NORM, E33G_GACFR);	/* Enable RAM and interrupts. */
-	do {
-		bool seen;
-
-		retval = request_irq(*irqp, el2_probe_interrupt, 0,
-				     dev->name, &seen);
-		if (retval == -EBUSY)
-			continue;
-		if (retval < 0)
-			goto err_disable;
-
-		/* Twinkle the interrupt, and check if it's seen. */
-		seen = false;
-		smp_wmb();
-		outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
-		outb_p(0x00, E33G_IDCFR);
-		msleep(1);
-		free_irq(*irqp, &seen);
-		if (!seen)
-			continue;
-
-		retval = request_irq(dev->irq = *irqp, eip_interrupt, 0,
-				     dev->name, dev);
-		if (retval == -EBUSY)
-			continue;
-		if (retval < 0)
-			goto err_disable;
-		break;
-	} while (*++irqp);
-
-	if (*irqp == 0) {
-	err_disable:
-	    outb(EGACFR_IRQOFF, E33G_GACFR);	/* disable interrupts. */
-	    return -EAGAIN;
-	}
-    } else {
-	if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
-	    return retval;
-	}
-    }
-
-    el2_init_card(dev);
-    eip_open(dev);
-    return 0;
-}
-
-static int
-el2_close(struct net_device *dev)
-{
-    free_irq(dev->irq, dev);
-    dev->irq = ei_status.saved_irq;
-    outb(EGACFR_IRQOFF, E33G_GACFR);	/* disable interrupts. */
-
-    eip_close(dev);
-    return 0;
-}
-
-/* This is called whenever we have a unrecoverable failure:
-       transmit timeout
-       Bad ring buffer packet header
- */
-static void
-el2_reset_8390(struct net_device *dev)
-{
-    if (ei_debug > 1) {
-	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)
-	pr_cont("done\n");
-}
-
-/* Initialize the 3c503 GA registers after a reset. */
-static void
-el2_init_card(struct net_device *dev)
-{
-    /* Unmap the station PROM and select the DIX or BNC connector. */
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-
-    /* Set ASIC copy of rx's first and last+1 buffer pages */
-    /* These must be the same as in the 8390. */
-    outb(ei_status.rx_start_page, E33G_STARTPG);
-    outb(ei_status.stop_page,  E33G_STOPPG);
-
-    /* Point the vector pointer registers somewhere ?harmless?. */
-    outb(0xff, E33G_VP2);	/* Point at the ROM restart location 0xffff0 */
-    outb(0xff, E33G_VP1);
-    outb(0x00, E33G_VP0);
-    /* Turn off all interrupts until we're opened. */
-    outb_p(0x00,  dev->base_addr + EN0_IMR);
-    /* Enable IRQs iff started. */
-    outb(EGACFR_NORM, E33G_GACFR);
-
-    /* Set the interrupt line. */
-    outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
-    outb_p((WRD_COUNT << 1), E33G_DRQCNT);	/* Set burst size to 8 */
-    outb_p(0x20, E33G_DMAAH);	/* Put a valid addr in the GA DMA */
-    outb_p(0x00, E33G_DMAAL);
-    return;			/* We always succeed */
-}
-
-/*
- * Either use the shared memory (if enabled on the board) or put the packet
- * out through the ASIC FIFO.
- */
-static void
-el2_block_output(struct net_device *dev, int count,
-		 const unsigned char *buf, int start_page)
-{
-    unsigned short int *wrd;
-    int boguscount;		/* timeout counter */
-    unsigned short word;	/* temporary for better machine code */
-    void __iomem *base = ei_status.mem;
-
-    if (ei_status.word16)      /* Tx packets go into bank 0 on EL2/16 card */
-	outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
-    else
-	outb(EGACFR_NORM, E33G_GACFR);
-
-    if (base) {	/* Shared memory transfer */
-	memcpy_toio(base + ((start_page - ei_status.tx_start_page) << 8),
-			buf, count);
-	outb(EGACFR_NORM, E33G_GACFR);	/* Back to bank1 in case on bank0 */
-	return;
-    }
-
-/*
- *  No shared memory, put the packet out the other way.
- *  Set up then start the internal memory transfer to Tx Start Page
- */
-
-    word = (unsigned short)start_page;
-    outb(word&0xFF, E33G_DMAAH);
-    outb(word>>8, E33G_DMAAL);
-
-    outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT
-	   | ECNTRL_START, E33G_CNTRL);
-
-/*
- *  Here I am going to write data to the FIFO as quickly as possible.
- *  Note that E33G_FIFOH is defined incorrectly. It is really
- *  E33G_FIFOL, the lowest port address for both the byte and
- *  word write. Variable 'count' is NOT checked. Caller must supply a
- *  valid count. Note that I may write a harmless extra byte to the
- *  8390 if the byte-count was not even.
- */
-    wrd = (unsigned short int *) buf;
-    count  = (count + 1) >> 1;
-    for(;;)
-    {
-        boguscount = 0x1000;
-        while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-        {
-            if(!boguscount--)
-            {
-                pr_notice("%s: FIFO blocked in el2_block_output.\n", dev->name);
-                el2_reset_8390(dev);
-                goto blocked;
-            }
-        }
-        if(count > WRD_COUNT)
-        {
-            outsw(E33G_FIFOH, wrd, WRD_COUNT);
-            wrd   += WRD_COUNT;
-            count -= WRD_COUNT;
-        }
-        else
-        {
-            outsw(E33G_FIFOH, wrd, count);
-            break;
-        }
-    }
-    blocked:;
-    outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-/* Read the 4 byte, page aligned 8390 specific header. */
-static void
-el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-    int boguscount;
-    void __iomem *base = ei_status.mem;
-    unsigned short word;
-
-    if (base) {       /* Use the shared memory. */
-	void __iomem *hdr_start = base + ((ring_page - EL2_MB1_START_PG)<<8);
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = le16_to_cpu(hdr->count);
-	return;
-    }
-
-/*
- *  No shared memory, use programmed I/O.
- */
-
-    word = (unsigned short)ring_page;
-    outb(word&0xFF, E33G_DMAAH);
-    outb(word>>8, E33G_DMAAL);
-
-    outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
-	   | ECNTRL_START, E33G_CNTRL);
-    boguscount = 0x1000;
-    while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-    {
-        if(!boguscount--)
-        {
-            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;
-        }
-    }
-    insw(E33G_FIFOH, hdr, (sizeof(struct e8390_pkt_hdr))>> 1);
-    blocked:;
-    outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-
-static void
-el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-    int boguscount = 0;
-    void __iomem *base = ei_status.mem;
-    unsigned short int *buf;
-    unsigned short word;
-
-    /* Maybe enable shared memory just be to be safe... nahh.*/
-    if (base) {	/* Use the shared memory. */
-	ring_offset -= (EL2_MB1_START_PG<<8);
-	if (ring_offset + count > EL2_MEMSIZE) {
-	    /* We must wrap the input move. */
-	    int semi_count = EL2_MEMSIZE - ring_offset;
-	    memcpy_fromio(skb->data, base + ring_offset, semi_count);
-	    count -= semi_count;
-	    memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
-	} else {
-		memcpy_fromio(skb->data, base + ring_offset, count);
-	}
-	return;
-    }
-
-/*
- *  No shared memory, use programmed I/O.
- */
-    word = (unsigned short) ring_offset;
-    outb(word>>8, E33G_DMAAH);
-    outb(word&0xFF, E33G_DMAAL);
-
-    outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
-	   | ECNTRL_START, E33G_CNTRL);
-
-/*
- *  Here I also try to get data as fast as possible. I am betting that I
- *  can read one extra byte without clobbering anything in the kernel because
- *  this would only occur on an odd byte-count and allocation of skb->data
- *  is word-aligned. Variable 'count' is NOT checked. Caller must check
- *  for a valid count.
- *  [This is currently quite safe.... but if one day the 3c503 explodes
- *   you know where to come looking ;)]
- */
-
-    buf =  (unsigned short int *) skb->data;
-    count =  (count + 1) >> 1;
-    for(;;)
-    {
-        boguscount = 0x1000;
-        while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
-        {
-            if(!boguscount--)
-            {
-                pr_notice("%s: FIFO blocked in el2_block_input.\n", dev->name);
-                el2_reset_8390(dev);
-                goto blocked;
-            }
-        }
-        if(count > WRD_COUNT)
-        {
-            insw(E33G_FIFOH, buf, WRD_COUNT);
-            buf   += WRD_COUNT;
-            count -= WRD_COUNT;
-        }
-        else
-        {
-            insw(E33G_FIFOH, buf, count);
-            break;
-        }
-    }
-    blocked:;
-    outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-#ifdef MODULE
-#define MAX_EL2_CARDS	4	/* Max number of EL2 cards per module */
-
-static struct net_device *dev_el2[MAX_EL2_CARDS];
-static int io[MAX_EL2_CARDS];
-static int irq[MAX_EL2_CARDS];
-static int xcvr[MAX_EL2_CARDS];	/* choose int. or ext. xcvr */
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr, "transceiver(s) (0=internal, 1=external)");
-MODULE_DESCRIPTION("3Com ISA EtherLink II, II/16 (3c503, 3c503/16) driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	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 */
-			pr_notice("3c503.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_eip_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_end = xcvr[this_dev];	/* low 4bits = xcvr sel. */
-		if (do_el2_probe(dev) == 0) {
-			dev_el2[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		pr_warning("3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: el2_close() handles free_irq */
-	release_region(dev->base_addr, EL2_IO_EXTENT);
-	if (ei_status.mem)
-		iounmap(ei_status.mem);
-}
-
-void __exit
-cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
-		struct net_device *dev = dev_el2[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/3c503.h b/drivers/net/ethernet/8390/3c503.h
deleted file mode 100644
index e2367b8..0000000
--- a/drivers/net/ethernet/8390/3c503.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Definitions for the 3Com 3c503 Etherlink 2. */
-/* This file is distributed under the GPL.
-   Many of these names and comments are directly from the Crynwr packet
-   drivers, which are released under the GPL. */
-
-#define EL2H (dev->base_addr + 0x400)
-#define EL2L (dev->base_addr)
-
-/* Vendor unique hardware addr. prefix. 3Com has 2 because they ran
-   out of available addresses on the first one... */
-
-#define OLD_3COM_ID	0x02608c
-#define NEW_3COM_ID	0x0020af
-
-/* Shared memory management parameters. NB: The 8 bit cards have only
-   one bank (MB1) which serves both Tx and Rx packet space. The 16bit
-   cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
-   You choose which bank appears in the sh. mem window with EGACFR_MBSn */
-
-#define EL2_MB0_START_PG	(0x00)	/* EL2/16 Tx packets go in bank 0 */
-#define EL2_MB1_START_PG	(0x20)	/* First page of bank 1 */
-#define EL2_MB1_STOP_PG		(0x40)	/* Last page +1 of bank 1 */
-
-/* 3Com 3c503 ASIC registers */
-#define E33G_STARTPG	(EL2H+0)	/* Start page, matching EN0_STARTPG */
-#define E33G_STOPPG	(EL2H+1)	/* Stop page, must match EN0_STOPPG */
-#define E33G_DRQCNT	(EL2H+2)	/* DMA burst count */
-#define E33G_IOBASE	(EL2H+3)	/* Read of I/O base jumpers. */
-	/* (non-useful, but it also appears at the end of EPROM space) */
-#define E33G_ROMBASE	(EL2H+4)	/* Read of memory base jumpers. */
-#define E33G_GACFR	(EL2H+5)	/* Config/setup bits for the ASIC GA */
-#define E33G_CNTRL	(EL2H+6)	/* Board's main control register */
-#define E33G_STATUS	(EL2H+7)	/* Status on completions. */
-#define E33G_IDCFR	(EL2H+8)	/* Interrupt/DMA config register */
-				/* (Which IRQ to assert, DMA chan to use) */
-#define E33G_DMAAH	(EL2H+9)	/* High byte of DMA address reg */
-#define E33G_DMAAL	(EL2H+10)	/* Low byte of DMA address reg */
-/* "Vector pointer" - if this address matches a read, the EPROM (rather than
-   shared RAM) is mapped into memory space. */
-#define E33G_VP2	(EL2H+11)
-#define E33G_VP1	(EL2H+12)
-#define E33G_VP0	(EL2H+13)
-#define E33G_FIFOH	(EL2H+14)	/* FIFO for programmed I/O moves */
-#define E33G_FIFOL	(EL2H+15)	/* ... low byte of above. */
-
-/* Bits in E33G_CNTRL register: */
-
-#define ECNTRL_RESET	(0x01)	/* Software reset of the ASIC and 8390 */
-#define ECNTRL_THIN	(0x02)	/* Onboard xcvr enable, AUI disable */
-#define ECNTRL_AUI	(0x00)	/* Onboard xcvr disable, AUI enable */
-#define ECNTRL_SAPROM	(0x04)	/* Map the station address prom */
-#define ECNTRL_DBLBFR	(0x20)	/* FIFO configuration bit */
-#define ECNTRL_OUTPUT	(0x40)	/* PC-to-3C503 direction if 1 */
-#define ECNTRL_INPUT	(0x00)	/* 3C503-to-PC direction if 0 */
-#define ECNTRL_START	(0x80)	/* Start the DMA logic */
-
-/* Bits in E33G_STATUS register: */
-
-#define ESTAT_DPRDY	(0x80)	/* Data port (of FIFO) ready */
-#define ESTAT_UFLW	(0x40)	/* Tried to read FIFO when it was empty */
-#define ESTAT_OFLW	(0x20)	/* Tried to write FIFO when it was full */
-#define ESTAT_DTC	(0x10)	/* Terminal Count from PC bus DMA logic */
-#define ESTAT_DIP	(0x08)	/* DMA In Progress */
-
-/* Bits in E33G_GACFR register: */
-
-#define EGACFR_NIM	(0x80)	/* NIC interrupt mask */
-#define EGACFR_TCM	(0x40)	/* DMA term. count interrupt mask */
-#define EGACFR_RSEL	(0x08)	/* Map a bank of card mem into system mem */
-#define EGACFR_MBS2	(0x04)	/* Memory bank select, bit 2. */
-#define EGACFR_MBS1	(0x02)	/* Memory bank select, bit 1. */
-#define EGACFR_MBS0	(0x01)	/* Memory bank select, bit 0. */
-
-#define EGACFR_NORM	(0x49)	/* TCM | RSEL | MBS0 */
-#define EGACFR_IRQOFF	(0xc9)	/* TCM | RSEL | MBS0 | NIM */
-
-/*
-	MBS2	MBS1	MBS0	Sh. mem windows card mem at:
-	----	----	----	-----------------------------
-	0	0	0	0x0000 -- bank 0
-	0	0	1	0x2000 -- bank 1 (only choice for 8bit card)
-	0	1	0	0x4000 -- bank 2, not used
-	0	1	1	0x6000 -- bank 3, not used
-
-There was going to be a 32k card that used bank 2 and 3, but it
-never got produced.
-
-*/
-
-
-/* End of 3C503 parameter definitions */
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index e1219e0..1b78ca7 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -6,8 +6,8 @@
 	bool "National Semi-conductor 8390 devices"
 	default y
 	depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
-		   ISA || MCA || EISA || MAC || M32R || MACH_TX49XX || \
-		   MCA_LEGACY || H8300 || ARM || MIPS || ZORRO || PCMCIA || \
+		   ISA || MAC || M32R || MACH_TX49XX || \
+		   H8300 || ARM || MIPS || ZORRO || PCMCIA || \
 		   EXPERIMENTAL)
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y
@@ -21,30 +21,6 @@
 
 if NET_VENDOR_8390
 
-config EL2
-	tristate "3c503 \"EtherLink II\" support"
-	depends on ISA
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called 3c503.
-
-config AC3200
-	tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
-	depends on PCI && (ISA || EISA) && EXPERIMENTAL
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called ac3200.
-
 config PCMCIA_AXNET
 	tristate "Asix AX88190 PCMCIA support"
 	depends on PCMCIA
@@ -74,54 +50,6 @@
 	---help---
 	  Select this if your platform comes with an external 93CX6 eeprom.
 
-config E2100
-	tristate "Cabletron E21xx support"
-	depends on ISA
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called e2100.
-
-config ES3210
-	tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
-	depends on PCI && EISA && EXPERIMENTAL
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called es3210.
-
-config HPLAN_PLUS
-	tristate "HP PCLAN+ (27247B and 27252A) support"
-	depends on ISA
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called hp-plus.
-
-config HPLAN
-	tristate "HP PCLAN (27245 and other 27xxx series) support"
-	depends on ISA
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called hp.
-
 config HYDRA
 	tristate "Hydra support"
 	depends on ZORRO
@@ -140,18 +68,6 @@
 	  If you have an Acorn system with one of these network cards, you
 	  should say Y to this option if you wish to use it with Linux.
 
-config LNE390
-	tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
-	depends on PCI && EISA && EXPERIMENTAL
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called lne390.
-
 config MAC8390
 	bool "Macintosh NS 8390 based ethernet cards"
 	depends on MAC
@@ -187,11 +103,7 @@
 	  without a specific driver are compatible with NE2000.
 
 	  If you have a PCI NE2000 card however, say N here and Y to "PCI
-	  NE2000 and clone support" under "EISA, VLB, PCI and on board
-	  controllers" below. If you have a NE2000 card and are running on
-	  an MCA system (a bus system used on some IBM PS/2 computers and
-	  laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
-	  below.
+	  NE2000 and clone support" below.
 
 	  To compile this driver as a module, choose M here. The module
 	  will be called ne.
@@ -226,19 +138,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called apne.
 
-config NE3210
-	tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
-	depends on PCI && EISA && EXPERIMENTAL
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.  Note that this driver
-	  will NOT WORK for NE3200 cards as they are completely different.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called ne3210.
-
 config PCMCIA_PCNET
 	tristate "NE2000 compatible PCMCIA support"
 	depends on PCMCIA
@@ -288,18 +187,6 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called smc-ultra.
 
-config ULTRA32
-	tristate "SMC Ultra32 EISA support"
-	depends on EISA
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called smc-ultra32.
-
 config WD80x3
 	tristate "WD80*3 support"
 	depends on ISA
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index f43038b..588954a 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -3,27 +3,17 @@
 #
 
 obj-$(CONFIG_MAC8390) += mac8390.o
-obj-$(CONFIG_AC3200) += ac3200.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_ARM_ETHERH) += etherh.o
 obj-$(CONFIG_AX88796) += ax88796.o
-obj-$(CONFIG_E2100) += e2100.o 8390.o
-obj-$(CONFIG_EL2) += 3c503.o 8390p.o
-obj-$(CONFIG_ES3210) += es3210.o 8390.o
-obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
-obj-$(CONFIG_HPLAN) += hp.o 8390p.o
 obj-$(CONFIG_HYDRA) += hydra.o 8390.o
-obj-$(CONFIG_LNE390) += lne390.o 8390.o
 obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
-obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
 obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
-obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
diff --git a/drivers/net/ethernet/8390/ac3200.c b/drivers/net/ethernet/8390/ac3200.c
deleted file mode 100644
index ccf0794..0000000
--- a/drivers/net/ethernet/8390/ac3200.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
-/*
-	Written 1993, 1994 by Donald Becker.
-	Copyright 1993 United States Government as represented by the Director,
-	National Security Agency.  This software may only be used and distributed
-	according to the terms of the GNU General Public License as modified by SRC,
-	incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
-	Adapter.  The programming information is from the users manual, as related
-	by glee@ardnassak.math.clemson.edu.
-
-	Changelog:
-
-	Paul Gortmaker 05/98	: add support for shared mem above 1MB.
-
-  */
-
-static const char version[] =
-	"ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8390.h"
-
-#define DRV_NAME	"ac3200"
-
-/* Offsets from the base address. */
-#define AC_NIC_BASE	0x00
-#define AC_SA_PROM	0x16			/* The station address PROM. */
-#define AC_ADDR0	0x00			/* Prefix station address values. */
-#define AC_ADDR1	0x40
-#define AC_ADDR2	0x90
-#define AC_ID_PORT	0xC80
-#define AC_EISA_ID	0x0110d305
-#define AC_RESET_PORT	0xC84
-#define AC_RESET	0x00
-#define AC_ENABLE	0x01
-#define AC_CONFIG	0xC90	/* The configuration port. */
-
-#define AC_IO_EXTENT 0x20
-                                /* Actually accessed is:
-								 * AC_NIC_BASE (0-15)
-								 * AC_SA_PROM (0-5)
-								 * AC_ID_PORT (0-3)
-								 * AC_RESET_PORT
-								 * AC_CONFIG
-								 */
-
-/* Decoding of the configuration register. */
-static unsigned char config2irqmap[8] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static int addrmap[8] =
-{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000,  0xD0000, 0 };
-static const char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
-
-#define config2irq(configval)	config2irqmap[((configval) >> 3) & 7]
-#define config2mem(configval)	addrmap[(configval) & 7]
-#define config2name(configval)	port_name[((configval) >> 6) & 3]
-
-/* First and last 8390 pages. */
-#define AC_START_PG		0x00	/* First page of 8390 TX buffer */
-#define AC_STOP_PG		0x80	/* Last page +1 of the 8390 RX ring */
-
-static int ac_probe1(int ioaddr, struct net_device *dev);
-
-static int ac_open(struct net_device *dev);
-static void ac_reset_8390(struct net_device *dev);
-static void ac_block_input(struct net_device *dev, int count,
-					struct sk_buff *skb, int ring_offset);
-static void ac_block_output(struct net_device *dev, const int count,
-							const unsigned char *buf, const int start_page);
-static void ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-					int ring_page);
-
-static int ac_close_card(struct net_device *dev);
-
-
-/*	Probe for the AC3200.
-
-	The AC3200 can be identified by either the EISA configuration registers,
-	or the unique value in the station address PROM.
-	*/
-
-static int __init do_ac3200_probe(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-	int irq = dev->irq;
-	int mem_start = dev->mem_start;
-
-	if (ioaddr > 0x1ff)		/* Check a single specified location. */
-		return ac_probe1(ioaddr, dev);
-	else if (ioaddr > 0)		/* Don't probe at all. */
-		return -ENXIO;
-
-	if ( ! EISA_bus)
-		return -ENXIO;
-
-	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-		if (ac_probe1(ioaddr, dev) == 0)
-			return 0;
-		dev->irq = irq;
-		dev->mem_start = mem_start;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init ac3200_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_ac3200_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops ac_netdev_ops = {
-	.ndo_open		= ac_open,
-	.ndo_stop 		= ac_close_card,
-
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_change_mtu		= eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= ei_poll,
-#endif
-};
-
-static int __init ac_probe1(int ioaddr, struct net_device *dev)
-{
-	int i, retval;
-
-	if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-#ifndef final_version
-	printk(KERN_DEBUG "AC3200 ethercard configuration register is %#02x,"
-		   " EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
-		   inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
-		   inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
-#endif
-
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
-
-	printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM",
-	       ioaddr/0x1000, dev->dev_addr);
-#if 0
-	/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
-	if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
-		|| inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
-		|| inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
-		printk(", not found (invalid prefix).\n");
-		retval = -ENODEV;
-		goto out;
-	}
-#endif
-
-	/* Assign and allocate the interrupt now. */
-	if (dev->irq == 0) {
-		dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
-		printk(", using");
-	} else {
-		dev->irq = irq_canonicalize(dev->irq);
-		printk(", assigning");
-	}
-
-	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
-	if (retval) {
-		printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
-		goto out;
-	}
-
-	printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
-
-	dev->base_addr = ioaddr;
-
-#ifdef notyet
-	if (dev->mem_start)	{		/* Override the value from the board. */
-		for (i = 0; i < 7; i++)
-			if (addrmap[i] == dev->mem_start)
-				break;
-		if (i >= 7)
-			i = 0;
-		outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
-	}
-#endif
-
-	dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
-	dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
-
-	printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
-			dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
-
-	/*
-	 *  BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
-	 *  the card mem within the region covered by `normal' RAM  !!!
-	 *
-	 *  ioremap() will fail in that case.
-	 */
-	ei_status.mem = ioremap(dev->mem_start, AC_STOP_PG*0x100);
-	if (!ei_status.mem) {
-		printk(KERN_ERR "ac3200.c: Unable to remap card memory above 1MB !!\n");
-		printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n");
-		printk(KERN_ERR "ac3200.c: Driver NOT installed.\n");
-		retval = -EINVAL;
-		goto out1;
-	}
-	printk("ac3200.c: remapped %dkB card memory to virtual address %p\n",
-			AC_STOP_PG/4, ei_status.mem);
-
-	dev->mem_start = (unsigned long)ei_status.mem;
-	dev->mem_end = dev->mem_start + (AC_STOP_PG - AC_START_PG)*256;
-
-	ei_status.name = "AC3200";
-	ei_status.tx_start_page = AC_START_PG;
-	ei_status.rx_start_page = AC_START_PG + TX_PAGES;
-	ei_status.stop_page = AC_STOP_PG;
-	ei_status.word16 = 1;
-
-	if (ei_debug > 0)
-		printk(version);
-
-	ei_status.reset_8390 = &ac_reset_8390;
-	ei_status.block_input = &ac_block_input;
-	ei_status.block_output = &ac_block_output;
-	ei_status.get_8390_hdr = &ac_get_8390_hdr;
-
-	dev->netdev_ops = &ac_netdev_ops;
-	NS8390_init(dev, 0);
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out2;
-	return 0;
-out2:
-	if (ei_status.reg0)
-		iounmap(ei_status.mem);
-out1:
-	free_irq(dev->irq, dev);
-out:
-	release_region(ioaddr, AC_IO_EXTENT);
-	return retval;
-}
-
-static int ac_open(struct net_device *dev)
-{
-#ifdef notyet
-	/* Someday we may enable the IRQ and shared memory here. */
-	int ioaddr = dev->base_addr;
-#endif
-
-	ei_open(dev);
-	return 0;
-}
-
-static void ac_reset_8390(struct net_device *dev)
-{
-	ushort ioaddr = dev->base_addr;
-
-	outb(AC_RESET, ioaddr + AC_RESET_PORT);
-	if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies);
-
-	ei_status.txing = 0;
-	outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
-	if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void
-ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - AC_START_PG)<<8);
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-}
-
-/*  Block input and output are easy on shared memory ethercards, the only
-	complication is when the ring buffer wraps. */
-
-static void ac_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-						  int ring_offset)
-{
-	void __iomem *start = ei_status.mem + ring_offset - AC_START_PG*256;
-
-	if (ring_offset + count > AC_STOP_PG*256) {
-		/* We must wrap the input move. */
-		int semi_count = AC_STOP_PG*256 - ring_offset;
-		memcpy_fromio(skb->data, start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count,
-				ei_status.mem + TX_PAGES*256, count);
-	} else {
-		memcpy_fromio(skb->data, start, count);
-	}
-}
-
-static void ac_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, int start_page)
-{
-	void __iomem *shmem = ei_status.mem + ((start_page - AC_START_PG)<<8);
-
-	memcpy_toio(shmem, buf, count);
-}
-
-static int ac_close_card(struct net_device *dev)
-{
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-
-#ifdef notyet
-	/* We should someday disable shared memory and interrupts. */
-	outb(0x00, ioaddr + 6);	/* Disable interrupts. */
-	free_irq(dev->irq, dev);
-#endif
-
-	ei_close(dev);
-	return 0;
-}
-
-#ifdef MODULE
-#define MAX_AC32_CARDS	4	/* Max number of AC32 cards per module */
-static struct net_device *dev_ac32[MAX_AC32_CARDS];
-static int io[MAX_AC32_CARDS];
-static int irq[MAX_AC32_CARDS];
-static int mem[MAX_AC32_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "Memory base address(es)");
-MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-static int __init ac3200_module_init(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
-		if (io[this_dev] == 0 && this_dev != 0)
-			break;
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];		/* Currently ignored by driver */
-		if (do_ac3200_probe(dev) == 0) {
-			dev_ac32[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	/* Someday free_irq may be in ac_close_card() */
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, AC_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-static void __exit ac3200_module_exit(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
-		struct net_device *dev = dev_ac32[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-module_init(ac3200_module_init);
-module_exit(ac3200_module_exit);
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index 70dba5d..cab306a 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -358,7 +358,7 @@
 		return -ENODEV;
 	}
 
-	ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change, 0,
+	ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change,
 				 PHY_INTERFACE_MODE_MII);
 	if (ret) {
 		netdev_err(dev, "Could not attach to PHY\n");
@@ -469,9 +469,9 @@
 {
 	struct platform_device *pdev = to_platform_device(dev->dev.parent);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pdev->name);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pdev->name, sizeof(info->bus_info));
 }
 
 static int ax_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/8390/e2100.c b/drivers/net/ethernet/8390/e2100.c
deleted file mode 100644
index ed55ce8..0000000
--- a/drivers/net/ethernet/8390/e2100.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
-/*
-	Written 1993-1994 by Donald Becker.
-
-	Copyright 1994 by Donald Becker.
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.  This software may be used and
-	distributed according to the terms of the GNU General Public License,
-	incorporated herein by reference.
-
-	This is a driver for the Cabletron E2100 series ethercards.
-
-	The Author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	The E2100 series ethercard is a fairly generic shared memory 8390
-	implementation.  The only unusual aspect is the way the shared memory
-	registers are set: first you do an inb() in what is normally the
-	station address region, and the low three bits of next outb() *address*
-	is used	as the write value for that register.  Either someone wasn't
-	too used to dem bit en bites, or they were trying to obfuscate the
-	programming interface.
-
-	There is an additional complication when setting the window on the packet
-	buffer.  You must first do a read into the packet buffer region with the
-	low 8 address bits the address setting the page for the start of the packet
-	buffer window, and then do the above operation.  See mem_on() for details.
-
-	One bug on the chip is that even a hard reset won't disable the memory
-	window, usually resulting in a hung machine if mem_off() isn't called.
-	If this happens, you must power down the machine for about 30 seconds.
-*/
-
-static const char version[] =
-	"e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "e2100"
-
-static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
-
-/* Offsets from the base_addr.
-   Read from the ASIC register, and the low three bits of the next outb()
-   address is used to set the corresponding register. */
-#define E21_NIC_OFFSET  0		/* Offset to the 8390 NIC. */
-#define E21_ASIC		0x10
-#define E21_MEM_ENABLE	0x10
-#define  E21_MEM_ON		0x05	/* Enable memory in 16 bit mode. */
-#define  E21_MEM_ON_8	0x07	/* Enable memory in  8 bit mode. */
-#define E21_MEM_BASE	0x11
-#define E21_IRQ_LOW		0x12	/* The low three bits of the IRQ number. */
-#define E21_IRQ_HIGH	0x14	/* The high IRQ bit and media select ...  */
-#define E21_MEDIA		0x14	/* (alias). */
-#define  E21_ALT_IFPORT 0x02	/* Set to use the other (BNC,AUI) port. */
-#define  E21_BIG_MEM	0x04	/* Use a bigger (64K) buffer (we don't) */
-#define E21_SAPROM		0x10	/* Offset to station address data. */
-#define E21_IO_EXTENT	 0x20
-
-static inline void mem_on(short port, volatile char __iomem *mem_base,
-						  unsigned char start_page )
-{
-	/* This is a little weird: set the shared memory window by doing a
-	   read.  The low address bits specify the starting page. */
-	readb(mem_base+start_page);
-	inb(port + E21_MEM_ENABLE);
-	outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
-}
-
-static inline void mem_off(short port)
-{
-	inb(port + E21_MEM_ENABLE);
-	outb(0x00, port + E21_MEM_ENABLE);
-}
-
-/* In other drivers I put the TX pages first, but the E2100 window circuitry
-   is designed to have a 4K Tx region last. The windowing circuitry wraps the
-   window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
-   appear contiguously in the window. */
-#define E21_RX_START_PG		0x00	/* First page of RX buffer */
-#define E21_RX_STOP_PG		0x30	/* Last page +1 of RX ring */
-#define E21_BIG_RX_STOP_PG	0xF0	/* Last page +1 of RX ring */
-#define E21_TX_START_PG		E21_RX_STOP_PG	/* First page of TX buffer */
-
-static int e21_probe1(struct net_device *dev, int ioaddr);
-
-static int e21_open(struct net_device *dev);
-static void e21_reset_8390(struct net_device *dev);
-static void e21_block_input(struct net_device *dev, int count,
-						   struct sk_buff *skb, int ring_offset);
-static void e21_block_output(struct net_device *dev, int count,
-							 const unsigned char *buf, int start_page);
-static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-							int ring_page);
-static int e21_open(struct net_device *dev);
-static int e21_close(struct net_device *dev);
-
-
-/*  Probe for the E2100 series ethercards.  These cards have an 8390 at the
-	base address and the station address at both offset 0x10 and 0x18.  I read
-	the station address from offset 0x18 to avoid the dataport of NE2000
-	ethercards, and look for Ctron's unique ID (first three octets of the
-	station address).
- */
-
-static int  __init do_e2100_probe(struct net_device *dev)
-{
-	int *port;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return e21_probe1(dev, base_addr);
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-	for (port = e21_probe_list; *port; port++) {
-		dev->irq = irq;
-		if (e21_probe1(dev, *port) == 0)
-			return 0;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init e2100_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_e2100_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops e21_netdev_ops = {
-	.ndo_open		= e21_open,
-	.ndo_stop		= e21_close,
-
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_change_mtu		= eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ei_poll,
-#endif
-};
-
-static int __init e21_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, status, retval;
-	unsigned char *station_addr = dev->dev_addr;
-	static unsigned version_printed;
-
-	if (!request_region(ioaddr, E21_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	/* First check the station address for the Ctron prefix. */
-	if (inb(ioaddr + E21_SAPROM + 0) != 0x00 ||
-	    inb(ioaddr + E21_SAPROM + 1) != 0x00 ||
-	    inb(ioaddr + E21_SAPROM + 2) != 0x1d) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Verify by making certain that there is a 8390 at there. */
-	outb(E8390_NODMA + E8390_STOP, ioaddr);
-	udelay(1);	/* we want to delay one I/O cycle - which is 2MHz */
-	status = inb(ioaddr);
-	if (status != 0x21 && status != 0x23) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Read the station address PROM.  */
-	for (i = 0; i < 6; i++)
-		station_addr[i] = inb(ioaddr + E21_SAPROM + i);
-
-	inb(ioaddr + E21_MEDIA); 		/* Point to media selection. */
-	outb(0, ioaddr + E21_ASIC); 	/* and disable the secondary interface. */
-
-	if (ei_debug  &&  version_printed++ == 0)
-		printk(version);
-
-	for (i = 0; i < 6; i++)
-		printk(" %02X", station_addr[i]);
-
-	if (dev->irq < 2) {
-		static const int irqlist[] = {15, 11, 10, 12, 5, 9, 3, 4};
-		for (i = 0; i < ARRAY_SIZE(irqlist); i++)
-			if (request_irq (irqlist[i], NULL, 0, "bogus", NULL) != -EBUSY) {
-				dev->irq = irqlist[i];
-				break;
-			}
-		if (i >= ARRAY_SIZE(irqlist)) {
-			printk(" unable to get IRQ %d.\n", dev->irq);
-			retval = -EAGAIN;
-			goto out;
-		}
-	} else if (dev->irq == 2)	/* Fixup luser bogosity: IRQ2 is really IRQ9 */
-		dev->irq = 9;
-
-	/* The 8390 is at the base address. */
-	dev->base_addr = ioaddr;
-
-	ei_status.name = "E2100";
-	ei_status.word16 = 1;
-	ei_status.tx_start_page = E21_TX_START_PG;
-	ei_status.rx_start_page = E21_RX_START_PG;
-	ei_status.stop_page = E21_RX_STOP_PG;
-	ei_status.saved_irq = dev->irq;
-
-	/* Check the media port used.  The port can be passed in on the
-	   low mem_end bits. */
-	if (dev->mem_end & 15)
-		dev->if_port = dev->mem_end & 7;
-	else {
-		dev->if_port = 0;
-		inb(ioaddr + E21_MEDIA); 	/* Turn automatic media detection on. */
-		for(i = 0; i < 6; i++)
-			if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) {
-				dev->if_port = 1;
-				break;
-			}
-	}
-
-	/* Never map in the E21 shared memory unless you are actively using it.
-	   Also, the shared memory has effective only one setting -- spread all
-	   over the 128K region! */
-	if (dev->mem_start == 0)
-		dev->mem_start = 0xd0000;
-
-	ei_status.mem = ioremap(dev->mem_start, 2*1024);
-	if (!ei_status.mem) {
-		printk("unable to remap memory\n");
-		retval = -EAGAIN;
-		goto out;
-	}
-
-#ifdef notdef
-	/* These values are unused.  The E2100 has a 2K window into the packet
-	   buffer.  The window can be set to start on any page boundary. */
-	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = ei_status.rmem_end = dev->mem_start + 2*1024;
-#endif
-
-	printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
-		   dev->if_port ? "secondary" : "primary", dev->mem_start);
-
-	ei_status.reset_8390 = &e21_reset_8390;
-	ei_status.block_input = &e21_block_input;
-	ei_status.block_output = &e21_block_output;
-	ei_status.get_8390_hdr = &e21_get_8390_hdr;
-
-	dev->netdev_ops = &e21_netdev_ops;
-	NS8390_init(dev, 0);
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out;
-	return 0;
-out:
-	release_region(ioaddr, E21_IO_EXTENT);
-	return retval;
-}
-
-static int
-e21_open(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-	int retval;
-
-	if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
-		return retval;
-
-	/* Set the interrupt line and memory base on the hardware. */
-	inb(ioaddr + E21_IRQ_LOW);
-	outb(0, ioaddr + E21_ASIC + (dev->irq & 7));
-	inb(ioaddr + E21_IRQ_HIGH); 			/* High IRQ bit, and if_port. */
-	outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
-		   + (dev->if_port ? E21_ALT_IFPORT : 0));
-	inb(ioaddr + E21_MEM_BASE);
-	outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
-
-	ei_open(dev);
-	return 0;
-}
-
-static void
-e21_reset_8390(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-
-	outb(0x01, ioaddr);
-	if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies);
-	ei_status.txing = 0;
-
-	/* Set up the ASIC registers, just in case something changed them. */
-
-	if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. We put the 2k window so the header page
-   appears at the start of the shared memory. */
-
-static void
-e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-
-	short ioaddr = dev->base_addr;
-	char __iomem *shared_mem = ei_status.mem;
-
-	mem_on(ioaddr, shared_mem, ring_page);
-
-#ifdef notdef
-	/* Officially this is what we are doing, but the readl() is faster */
-	memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
-#else
-	((unsigned int*)hdr)[0] = readl(shared_mem);
-#endif
-
-	/* Turn off memory access: we would need to reprogram the window anyway. */
-	mem_off(ioaddr);
-
-}
-
-/*  Block input and output are easy on shared memory ethercards.
-	The E21xx makes block_input() especially easy by wrapping the top
-	ring buffer to the bottom automatically. */
-static void
-e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	short ioaddr = dev->base_addr;
-	char __iomem *shared_mem = ei_status.mem;
-
-	mem_on(ioaddr, shared_mem, (ring_offset>>8));
-
-	memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
-
-	mem_off(ioaddr);
-}
-
-static void
-e21_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				 int start_page)
-{
-	short ioaddr = dev->base_addr;
-	volatile char __iomem *shared_mem = ei_status.mem;
-
-	/* Set the shared memory window start by doing a read, with the low address
-	   bits specifying the starting page. */
-	readb(shared_mem + start_page);
-	mem_on(ioaddr, shared_mem, start_page);
-
-	memcpy_toio(shared_mem, buf, count);
-	mem_off(ioaddr);
-}
-
-static int
-e21_close(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-
-	free_irq(dev->irq, dev);
-	dev->irq = ei_status.saved_irq;
-
-	/* Shut off the interrupt line and secondary interface. */
-	inb(ioaddr + E21_IRQ_LOW);
-	outb(0, ioaddr + E21_ASIC);
-	inb(ioaddr + E21_IRQ_HIGH); 			/* High IRQ bit, and if_port. */
-	outb(0, ioaddr + E21_ASIC);
-
-	ei_close(dev);
-
-	/* Double-check that the memory has been turned off, because really
-	   really bad things happen if it isn't. */
-	mem_off(ioaddr);
-
-	return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_E21_CARDS	4	/* Max number of E21 cards per module */
-static struct net_device *dev_e21[MAX_E21_CARDS];
-static int io[MAX_E21_CARDS];
-static int irq[MAX_E21_CARDS];
-static int mem[MAX_E21_CARDS];
-static int xcvr[MAX_E21_CARDS];		/* choose int. or ext. xcvr */
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, " memory base address(es)");
-MODULE_PARM_DESC(xcvr, "transceiver(s) (0=internal, 1=external)");
-MODULE_DESCRIPTION("Cabletron E2100 ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-
-int __init init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];
-		dev->mem_end = xcvr[this_dev];	/* low 4bits = xcvr sel. */
-		if (do_e2100_probe(dev) == 0) {
-			dev_e21[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: e21_close() handles free_irq */
-	iounmap(ei_status.mem);
-	release_region(dev->base_addr, E21_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
-		struct net_device *dev = dev_e21[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/es3210.c b/drivers/net/ethernet/8390/es3210.c
deleted file mode 100644
index ba1b5c9..0000000
--- a/drivers/net/ethernet/8390/es3210.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-	es3210.c
-
-	Linux driver for Racal-Interlan ES3210 EISA Network Adapter
-
-	Copyright (C) 1996, Paul Gortmaker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	Information and Code Sources:
-
-	1) The existing myriad of Linux 8390 drivers written by Donald Becker.
-
-	2) Once again Russ Nelson's asm packet driver provided additional info.
-
-	3) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
-	   Too bad it doesn't work -- see below.
-
-	The ES3210 is an EISA shared memory NS8390 implementation. Note
-	that all memory copies to/from the board must be 32bit transfers.
-	Which rules out using eth_io_copy_and_sum() in this driver.
-
-	Apparently there are two slightly different revisions of the
-	card, since there are two distinct EISA cfg files (!rii0101.cfg
-	and !rii0102.cfg) One has media select in the cfg file and the
-	other doesn't. Hopefully this will work with either.
-
-	That is about all I can tell you about it, having never actually
-	even seen one of these cards. :)  Try http://www.interlan.com
-	if you want more info.
-
-	Thanks go to Mark Salazar for testing v0.02 of this driver.
-
-	Bugs, to-fix, etc:
-
-	1) The EISA cfg ports that are *supposed* to have the IRQ and shared
-	   mem values just read 0xff all the time. Hrrmpf. Apparently the
-	   same happens with the packet driver as the code for reading
-	   these registers is disabled there. In the meantime, boot with:
-	   ether=<IRQ>,0,0x<shared_mem_addr>,eth0 to override the IRQ and
-	   shared memory detection. (The i/o port detection is okay.)
-
-	2) Module support currently untested. Probably works though.
-
-*/
-
-static const char version[] =
-	"es3210.c: Driver revision v0.03, 14/09/96\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-static int es_probe1(struct net_device *dev, int ioaddr);
-
-static void es_reset_8390(struct net_device *dev);
-
-static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void es_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page);
-
-#define ES_START_PG	0x00    /* First page of TX buffer		*/
-#define ES_STOP_PG	0x40    /* Last page +1 of RX ring		*/
-
-#define ES_IO_EXTENT	0x37	/* The cfg file says 0xc90 -> 0xcc7	*/
-#define ES_ID_PORT	0xc80	/* Same for all EISA cards 		*/
-#define ES_SA_PROM	0xc90	/* Start of e'net addr.			*/
-#define ES_RESET_PORT	0xc84	/* From the packet driver source	*/
-#define ES_NIC_OFFSET	0xca0	/* Hello, the 8390 is *here*		*/
-
-#define ES_ADDR0	0x02	/* 3 byte vendor prefix			*/
-#define ES_ADDR1	0x07
-#define ES_ADDR2	0x01
-
-/*
- * Two card revisions. EISA ID's are always rev. minor, rev. major,, and
- * then the three vendor letters stored in 5 bits each, with an "a" = 1.
- * For eg: "rii" = 10010 01001 01001 = 0x4929, which is how the EISA
- * config utility determines automagically what config file(s) to use.
- */
-#define ES_EISA_ID1	0x01012949	/* !rii0101.cfg 		*/
-#define ES_EISA_ID2	0x02012949	/* !rii0102.cfg 		*/
-
-#define ES_CFG1		0xcc0	/* IOPORT(1) --> IOPORT(6) in cfg file	*/
-#define ES_CFG2		0xcc1
-#define ES_CFG3		0xcc2
-#define ES_CFG4		0xcc3
-#define ES_CFG5		0xcc4
-#define ES_CFG6		0xc84	/* NB: 0xc84 is also "reset" port.	*/
-
-/*
- *	You can OR any of the following bits together and assign it
- *	to ES_DEBUG to get verbose driver info during operation.
- *	Some of these don't do anything yet.
- */
-
-#define ES_D_PROBE	0x01
-#define ES_D_RX_PKT	0x02
-#define ES_D_TX_PKT	0x04
-#define ED_D_IRQ	0x08
-
-#define ES_DEBUG	0
-
-static unsigned char lo_irq_map[] __initdata = {3, 4, 5, 6, 7, 9, 10};
-static unsigned char hi_irq_map[] __initdata = {11, 12, 0, 14, 0, 0, 0, 15};
-
-/*
- *	Probe for the card. The best way is to read the EISA ID if it
- *	is known. Then we check the prefix of the station address
- *	PROM for a match against the Racal-Interlan assigned value.
- */
-
-static int __init do_es_probe(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-	int irq = dev->irq;
-	int mem_start = dev->mem_start;
-
-	if (ioaddr > 0x1ff)		/* Check a single specified location. */
-		return es_probe1(dev, ioaddr);
-	else if (ioaddr > 0)		/* Don't probe at all. */
-		return -ENXIO;
-
-	if (!EISA_bus) {
-#if ES_DEBUG & ES_D_PROBE
-		printk("es3210.c: Not EISA bus. Not probing high ports.\n");
-#endif
-		return -ENXIO;
-	}
-
-	/* EISA spec allows for up to 16 slots, but 8 is typical. */
-	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-		if (es_probe1(dev, ioaddr) == 0)
-			return 0;
-		dev->irq = irq;
-		dev->mem_start = mem_start;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init es_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_es_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static int __init es_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, retval;
-	unsigned long eisa_id;
-
-	if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
-		return -ENODEV;
-
-#if ES_DEBUG & ES_D_PROBE
-	printk("es3210.c: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + ES_ID_PORT));
-	printk("es3210.c: config regs: %#x %#x %#x %#x %#x %#x\n",
-		inb(ioaddr + ES_CFG1), inb(ioaddr + ES_CFG2), inb(ioaddr + ES_CFG3),
-		inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
-#endif
-
-/*	Check the EISA ID of the card. */
-	eisa_id = inl(ioaddr + ES_ID_PORT);
-	if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	for (i = 0; i < ETH_ALEN ; i++)
-		dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
-
-/*	Check the Racal vendor ID as well. */
-	if (dev->dev_addr[0] != ES_ADDR0 ||
-	    dev->dev_addr[1] != ES_ADDR1 ||
-	    dev->dev_addr[2] != ES_ADDR2) {
-		printk("es3210.c: card not found %pM (invalid_prefix).\n",
-		       dev->dev_addr);
-		retval = -ENODEV;
-		goto out;
-	}
-
-	printk("es3210.c: ES3210 rev. %ld at %#x, node %pM",
-	       eisa_id>>24, ioaddr, dev->dev_addr);
-
-	/* Snarf the interrupt now. */
-	if (dev->irq == 0) {
-		unsigned char hi_irq = inb(ioaddr + ES_CFG2) & 0x07;
-		unsigned char lo_irq = inb(ioaddr + ES_CFG1) & 0xfe;
-
-		if (hi_irq != 0) {
-			dev->irq = hi_irq_map[hi_irq - 1];
-		} else {
-			int i = 0;
-			while (lo_irq > (1<<i)) i++;
-			dev->irq = lo_irq_map[i];
-		}
-		printk(" using IRQ %d", dev->irq);
-#if ES_DEBUG & ES_D_PROBE
-		printk("es3210.c: hi_irq %#x, lo_irq %#x, dev->irq = %d\n",
-					hi_irq, lo_irq, dev->irq);
-#endif
-	} else {
-		if (dev->irq == 2)
-			dev->irq = 9;			/* Doh! */
-		printk(" assigning IRQ %d", dev->irq);
-	}
-
-	if (request_irq(dev->irq, ei_interrupt, 0, "es3210", dev)) {
-		printk (" unable to get IRQ %d.\n", dev->irq);
-		retval = -EAGAIN;
-		goto out;
-	}
-
-	if (dev->mem_start == 0) {
-		unsigned char mem_enabled = inb(ioaddr + ES_CFG2) & 0xc0;
-		unsigned char mem_bits = inb(ioaddr + ES_CFG3) & 0x07;
-
-		if (mem_enabled != 0x80) {
-			printk(" shared mem disabled - giving up\n");
-			retval = -ENXIO;
-			goto out1;
-		}
-		dev->mem_start = 0xC0000 + mem_bits*0x4000;
-		printk(" using ");
-	} else {
-		printk(" assigning ");
-	}
-
-	ei_status.mem = ioremap(dev->mem_start, (ES_STOP_PG - ES_START_PG)*256);
-	if (!ei_status.mem) {
-		printk("ioremap failed - giving up\n");
-		retval = -ENXIO;
-		goto out1;
-	}
-
-	dev->mem_end = dev->mem_start + (ES_STOP_PG - ES_START_PG)*256;
-
-	printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
-
-#if ES_DEBUG & ES_D_PROBE
-	if (inb(ioaddr + ES_CFG5))
-		printk("es3210: Warning - DMA channel enabled, but not used here.\n");
-#endif
-	/* Note, point at the 8390, and not the card... */
-	dev->base_addr = ioaddr + ES_NIC_OFFSET;
-
-	ei_status.name = "ES3210";
-	ei_status.tx_start_page = ES_START_PG;
-	ei_status.rx_start_page = ES_START_PG + TX_PAGES;
-	ei_status.stop_page = ES_STOP_PG;
-	ei_status.word16 = 1;
-
-	if (ei_debug > 0)
-		printk(version);
-
-	ei_status.reset_8390 = &es_reset_8390;
-	ei_status.block_input = &es_block_input;
-	ei_status.block_output = &es_block_output;
-	ei_status.get_8390_hdr = &es_get_8390_hdr;
-
-	dev->netdev_ops = &ei_netdev_ops;
-	NS8390_init(dev, 0);
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out1;
-	return 0;
-out1:
-	free_irq(dev->irq, dev);
-out:
-	release_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT);
-	return retval;
-}
-
-/*
- *	Reset as per the packet driver method. Judging by the EISA cfg
- *	file, this just toggles the "Board Enable" bits (bit 2 and 0).
- */
-
-static void es_reset_8390(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-	unsigned long end;
-
-	outb(0x04, ioaddr + ES_RESET_PORT);
-	if (ei_debug > 1) printk("%s: resetting the ES3210...", dev->name);
-
-	end = jiffies + 2*HZ/100;
-        while ((signed)(end - jiffies) > 0) continue;
-
-	ei_status.txing = 0;
-	outb(0x01, ioaddr + ES_RESET_PORT);
-	if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- *	Note: In the following three functions is the implicit assumption
- *	that the associated memcpy will only use "rep; movsl" as long as
- *	we keep the counts as some multiple of doublewords. This is a
- *	requirement of the hardware, and also prevents us from using
- *	eth_io_copy_and_sum() since we can't guarantee it will limit
- *	itself to doubleword access.
- */
-
-/*
- *	Grab the 8390 specific header. Similar to the block_input routine, but
- *	we don't need to be concerned with ring wrap as the header will be at
- *	the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - ES_START_PG)<<8);
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
-}
-
-/*
- *	Block input and output are easy on shared memory ethercards, the only
- *	complication is when the ring buffer wraps. The count will already
- *	be rounded up to a doubleword value via es_get_8390_hdr() above.
- */
-
-static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-						  int ring_offset)
-{
-	void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256;
-
-	if (ring_offset + count > ES_STOP_PG*256) {
-		/* Packet wraps over end of ring buffer. */
-		int semi_count = ES_STOP_PG*256 - ring_offset;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
-	} else {
-		/* Packet is in one chunk. */
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-}
-
-static void es_block_output(struct net_device *dev, int count,
-				const unsigned char *buf, int start_page)
-{
-	void __iomem *shmem = ei_status.mem + ((start_page - ES_START_PG)<<8);
-
-	count = (count + 3) & ~3;     /* Round up to doubleword */
-	memcpy_toio(shmem, buf, count);
-}
-
-#ifdef MODULE
-#define MAX_ES_CARDS	4	/* Max number of ES3210 cards per module */
-#define NAMELEN		8	/* # of chars for storing dev->name */
-static struct net_device *dev_es3210[MAX_ES_CARDS];
-static int io[MAX_ES_CARDS];
-static int irq[MAX_ES_CARDS];
-static int mem[MAX_ES_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "memory base address(es)");
-MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
-		if (io[this_dev] == 0 && this_dev != 0)
-			break;
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];
-		if (do_es_probe(dev) == 0) {
-			dev_es3210[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, ES_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-void __exit
-cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
-		struct net_device *dev = dev_es3210[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/8390/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c
deleted file mode 100644
index 52f70f9..0000000
--- a/drivers/net/ethernet/8390/hp-plus.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
-/*
-	Written 1994 by Donald Becker.
-
-	This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
-	These cards are sold under several model numbers, usually 2724*.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	As is often the case, a great deal of credit is owed to Russ Nelson.
-	The Crynwr packet driver was my primary source of HP-specific
-	programming information.
-*/
-
-static const char version[] =
-"hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-
-#include <linux/string.h>		/* Important -- this inlines word moves. */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "hp-plus"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int hpplus_portlist[] __initdata =
-{0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
-
-/*
-   The HP EtherTwist chip implementation is a fairly routine DP8390
-   implementation.  It allows both shared memory and programmed-I/O buffer
-   access, using a custom interface for both.  The programmed-I/O mode is
-   entirely implemented in the HP EtherTwist chip, bypassing the problem
-   ridden built-in 8390 facilities used on NE2000 designs.  The shared
-   memory mode is likewise special, with an offset register used to make
-   packets appear at the shared memory base.  Both modes use a base and bounds
-   page register to hide the Rx ring buffer wrap -- a packet that spans the
-   end of physical buffer memory appears continuous to the driver. (c.f. the
-   3c503 and Cabletron E2100)
-
-   A special note: the internal buffer of the board is only 8 bits wide.
-   This lays several nasty traps for the unaware:
-   - the 8390 must be programmed for byte-wide operations
-   - all I/O and memory operations must work on whole words (the access
-     latches are serially preloaded and have no byte-swapping ability).
-
-   This board is laid out in I/O space much like the earlier HP boards:
-   the first 16 locations are for the board registers, and the second 16 are
-   for the 8390.  The board is easy to identify, with both a dedicated 16 bit
-   ID register and a constant 0x530* value in the upper bits of the paging
-   register.
-*/
-
-#define HP_ID			0x00	/* ID register, always 0x4850. */
-#define HP_PAGING		0x02	/* Registers visible @ 8-f, see PageName. */
-#define HPP_OPTION		0x04	/* Bitmapped options, see HP_Option.	*/
-#define HPP_OUT_ADDR	0x08	/* I/O output location in Perf_Page.	*/
-#define HPP_IN_ADDR		0x0A	/* I/O input location in Perf_Page.		*/
-#define HP_DATAPORT		0x0c	/* I/O data transfer in Perf_Page.		*/
-#define NIC_OFFSET		0x10	/* Offset to the 8390 registers.		*/
-#define HP_IO_EXTENT	32
-
-#define HP_START_PG		0x00	/* First page of TX buffer */
-#define HP_STOP_PG		0x80	/* Last page +1 of RX ring */
-
-/* The register set selected in HP_PAGING. */
-enum PageName {
-	Perf_Page = 0,				/* Normal operation. */
-	MAC_Page = 1,				/* The ethernet address (+checksum). */
-	HW_Page = 2,				/* EEPROM-loaded hardware parameters. */
-	LAN_Page = 4,				/* Transceiver selection, testing, etc. */
-	ID_Page = 6 };
-
-/* The bit definitions for the HPP_OPTION register. */
-enum HP_Option {
-	NICReset = 1, ChipReset = 2, 	/* Active low, really UNreset. */
-	EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
-	MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
-
-static int hpp_probe1(struct net_device *dev, int ioaddr);
-
-static void hpp_reset_8390(struct net_device *dev);
-static int hpp_open(struct net_device *dev);
-static int hpp_close(struct net_device *dev);
-static void hpp_mem_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void hpp_mem_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, int start_page);
-static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						  int ring_page);
-static void hpp_io_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void hpp_io_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, int start_page);
-static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						  int ring_page);
-
-
-/*	Probe a list of addresses for an HP LAN+ adaptor.
-	This routine is almost boilerplate. */
-
-static int __init do_hpp_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return hpp_probe1(dev, base_addr);
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-	for (i = 0; hpplus_portlist[i]; i++) {
-		if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
-			return 0;
-		dev->irq = irq;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init hp_plus_probe(int unit)
-{
-	struct net_device *dev = alloc_eip_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_hpp_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops hpp_netdev_ops = {
-	.ndo_open		= hpp_open,
-	.ndo_stop		= hpp_close,
-	.ndo_start_xmit		= eip_start_xmit,
-	.ndo_tx_timeout		= eip_tx_timeout,
-	.ndo_get_stats		= eip_get_stats,
-	.ndo_set_rx_mode	= eip_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_change_mtu		= eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= eip_poll,
-#endif
-};
-
-
-/* Do the interesting part of the probe at a single address. */
-static int __init hpp_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, retval;
-	unsigned char checksum = 0;
-	const char name[] = "HP-PC-LAN+";
-	int mem_start;
-	static unsigned version_printed;
-
-	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	/* Check for the HP+ signature, 50 48 0x 53. */
-	if (inw(ioaddr + HP_ID) != 0x4850 ||
-	    (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	if (ei_debug  &&  version_printed++ == 0)
-		printk(version);
-
-	printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
-
-	/* Retrieve and checksum the station address. */
-	outw(MAC_Page, ioaddr + HP_PAGING);
-
-	for(i = 0; i < ETH_ALEN; i++) {
-		unsigned char inval = inb(ioaddr + 8 + i);
-		dev->dev_addr[i] = inval;
-		checksum += inval;
-	}
-	checksum += inb(ioaddr + 14);
-
-	printk("%pM", dev->dev_addr);
-
-	if (checksum != 0xff) {
-		printk(" bad checksum %2.2x.\n", checksum);
-		retval = -ENODEV;
-		goto out;
-	} else {
-		/* Point at the Software Configuration Flags. */
-		outw(ID_Page, ioaddr + HP_PAGING);
-		printk(" ID %4.4x", inw(ioaddr + 12));
-	}
-
-	/* Read the IRQ line. */
-	outw(HW_Page, ioaddr + HP_PAGING);
-	{
-		int irq = inb(ioaddr + 13) & 0x0f;
-		int option = inw(ioaddr + HPP_OPTION);
-
-		dev->irq = irq;
-		if (option & MemEnable) {
-			mem_start = inw(ioaddr + 9) << 8;
-			printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
-		} else {
-			mem_start = 0;
-			printk(", IRQ %d, programmed-I/O mode.\n", irq);
-		}
-	}
-
-	/* Set the wrap registers for string I/O reads.   */
-	outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
-
-	/* Set the base address to point to the NIC, not the "real" base! */
-	dev->base_addr = ioaddr + NIC_OFFSET;
-
-	dev->netdev_ops = &hpp_netdev_ops;
-
-	ei_status.name = name;
-	ei_status.word16 = 0;		/* Agggghhhhh! Debug time: 2 days! */
-	ei_status.tx_start_page = HP_START_PG;
-	ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
-	ei_status.stop_page = HP_STOP_PG;
-
-	ei_status.reset_8390 = &hpp_reset_8390;
-	ei_status.block_input = &hpp_io_block_input;
-	ei_status.block_output = &hpp_io_block_output;
-	ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
-
-	/* Check if the memory_enable flag is set in the option register. */
-	if (mem_start) {
-		ei_status.block_input = &hpp_mem_block_input;
-		ei_status.block_output = &hpp_mem_block_output;
-		ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
-		dev->mem_start = mem_start;
-		ei_status.mem = ioremap(mem_start,
-					(HP_STOP_PG - HP_START_PG)*256);
-		if (!ei_status.mem) {
-			retval = -ENOMEM;
-			goto out;
-		}
-		ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
-		dev->mem_end = ei_status.rmem_end
-			= dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
-	}
-
-	outw(Perf_Page, ioaddr + HP_PAGING);
-	NS8390p_init(dev, 0);
-	/* Leave the 8390 and HP chip reset. */
-	outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out1;
-	return 0;
-out1:
-	iounmap(ei_status.mem);
-out:
-	release_region(ioaddr, HP_IO_EXTENT);
-	return retval;
-}
-
-static int
-hpp_open(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	int option_reg;
-	int retval;
-
-	if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
-	    return retval;
-	}
-
-	/* Reset the 8390 and HP chip. */
-	option_reg = inw(ioaddr + HPP_OPTION);
-	outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
-	udelay(5);
-	/* Unreset the board and enable interrupts. */
-	outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
-
-	/* Set the wrap registers for programmed-I/O operation.   */
-	outw(HW_Page, ioaddr + HP_PAGING);
-	outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
-
-	/* Select the operational page. */
-	outw(Perf_Page, ioaddr + HP_PAGING);
-
-	return eip_open(dev);
-}
-
-static int
-hpp_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	int option_reg = inw(ioaddr + HPP_OPTION);
-
-	free_irq(dev->irq, dev);
-	eip_close(dev);
-	outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
-		 ioaddr + HPP_OPTION);
-
-	return 0;
-}
-
-static void
-hpp_reset_8390(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	int option_reg = inw(ioaddr + HPP_OPTION);
-
-	if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
-
-	outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
-	/* Pause a few cycles for the hardware reset to take place. */
-	udelay(5);
-	ei_status.txing = 0;
-	outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
-
-	udelay(5);
-
-
-	if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
-		printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-
-	if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-}
-
-/* The programmed-I/O version of reading the 4 byte 8390 specific header.
-   Note that transfer with the EtherTwist+ must be on word boundaries. */
-
-static void
-hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-
-	outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
-	insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-}
-
-/* Block input and output, similar to the Crynwr packet driver. */
-
-static void
-hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	char *buf = skb->data;
-
-	outw(ring_offset, ioaddr + HPP_IN_ADDR);
-	insw(ioaddr + HP_DATAPORT, buf, count>>1);
-	if (count & 0x01)
-        buf[count-1] = inw(ioaddr + HP_DATAPORT);
-}
-
-/* The corresponding shared memory versions of the above 2 functions. */
-
-static void
-hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	int option_reg = inw(ioaddr + HPP_OPTION);
-
-	outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
-	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-	memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
-	outw(option_reg, ioaddr + HPP_OPTION);
-	hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3;	/* Round up allocation. */
-}
-
-static void
-hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	int option_reg = inw(ioaddr + HPP_OPTION);
-
-	outw(ring_offset, ioaddr + HPP_IN_ADDR);
-
-	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-
-	/* Caution: this relies on get_8390_hdr() rounding up count!
-	   Also note that we *can't* use eth_io_copy_and_sum() because
-	   it will not always copy "count" bytes (e.g. padded IP).  */
-
-	memcpy_fromio(skb->data, ei_status.mem, count);
-	outw(option_reg, ioaddr + HPP_OPTION);
-}
-
-/* A special note: we *must* always transfer >=16 bit words.
-   It's always safe to round up, so we do. */
-static void
-hpp_io_block_output(struct net_device *dev, int count,
-					const unsigned char *buf, int start_page)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
-	outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
-}
-
-static void
-hpp_mem_block_output(struct net_device *dev, int count,
-				const unsigned char *buf, int start_page)
-{
-	int ioaddr = dev->base_addr - NIC_OFFSET;
-	int option_reg = inw(ioaddr + HPP_OPTION);
-
-	outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
-	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-	memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
-	outw(option_reg, ioaddr + HPP_OPTION);
-}
-
-
-#ifdef MODULE
-#define MAX_HPP_CARDS	4	/* Max number of HPP cards per module */
-static struct net_device *dev_hpp[MAX_HPP_CARDS];
-static int io[MAX_HPP_CARDS];
-static int irq[MAX_HPP_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O port address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
-MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_eip_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		if (do_hpp_probe(dev) == 0) {
-			dev_hpp[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: hpp_close() handles free_irq */
-	iounmap(ei_status.mem);
-	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
-		struct net_device *dev = dev_hpp[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/hp.c b/drivers/net/ethernet/8390/hp.c
deleted file mode 100644
index 37fa89a..0000000
--- a/drivers/net/ethernet/8390/hp.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/* hp.c: A HP LAN ethernet driver for linux. */
-/*
-	Written 1993-94 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This is a driver for the HP PC-LAN adaptors.
-
-	Sources:
-	  The Crynwr packet driver.
-*/
-
-static const char version[] =
-	"hp.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "hp"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int hppclan_portlist[] __initdata =
-{ 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
-
-#define HP_IO_EXTENT	32
-
-#define HP_DATAPORT		0x0c	/* "Remote DMA" data port. */
-#define HP_ID			0x07
-#define HP_CONFIGURE	0x08	/* Configuration register. */
-#define	 HP_RUN			0x01	/* 1 == Run, 0 == reset. */
-#define	 HP_IRQ			0x0E	/* Mask for software-configured IRQ line. */
-#define	 HP_DATAON		0x10	/* Turn on dataport */
-#define NIC_OFFSET		0x10	/* Offset the 8390 registers. */
-
-#define HP_START_PG		0x00	/* First page of TX buffer */
-#define HP_8BSTOP_PG	0x80	/* Last page +1 of RX ring */
-#define HP_16BSTOP_PG	0xFF	/* Same, for 16 bit cards. */
-
-static int hp_probe1(struct net_device *dev, int ioaddr);
-
-static void hp_reset_8390(struct net_device *dev);
-static void hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-					int ring_page);
-static void hp_block_input(struct net_device *dev, int count,
-					struct sk_buff *skb , int ring_offset);
-static void hp_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, int start_page);
-
-static void hp_init_card(struct net_device *dev);
-
-/* The map from IRQ number to HP_CONFIGURE register setting. */
-/* My default is IRQ5	             0  1  2  3  4  5  6  7  8  9 10 11 */
-static char irqmap[16] __initdata= { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
-
-
-/*	Probe for an HP LAN adaptor.
-	Also initialize the card and fill in STATION_ADDR with the station
-	address. */
-
-static int __init do_hp_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return hp_probe1(dev, base_addr);
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-	for (i = 0; hppclan_portlist[i]; i++) {
-		if (hp_probe1(dev, hppclan_portlist[i]) == 0)
-			return 0;
-		dev->irq = irq;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init hp_probe(int unit)
-{
-	struct net_device *dev = alloc_eip_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_hp_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static int __init hp_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, retval, board_id, wordmode;
-	const char *name;
-	static unsigned version_printed;
-
-	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	/* Check for the HP physical address, 08 00 09 xx xx xx. */
-	/* This really isn't good enough: we may pick up HP LANCE boards
-	   also!  Avoid the lance 0x5757 signature. */
-	if (inb(ioaddr) != 0x08
-		|| inb(ioaddr+1) != 0x00
-		|| inb(ioaddr+2) != 0x09
-		|| inb(ioaddr+14) == 0x57) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Set up the parameters based on the board ID.
-	   If you have additional mappings, please mail them to me -djb. */
-	if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
-		name = "HP27247";
-		wordmode = 1;
-	} else {
-		name = "HP27250";
-		wordmode = 0;
-	}
-
-	if (ei_debug  &&  version_printed++ == 0)
-		printk(version);
-
-	printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
-
-	for(i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[i] = inb(ioaddr + i);
-
-	printk(" %pM", dev->dev_addr);
-
-	/* Snarf the interrupt now.  Someday this could be moved to open(). */
-	if (dev->irq < 2) {
-		static const int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
-		static const int irq_8list[] = { 7, 5, 3, 4, 9, 0};
-		const int *irqp = wordmode ? irq_16list : irq_8list;
-		do {
-			int irq = *irqp;
-			if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
-				unsigned long cookie = probe_irq_on();
-				/* Twinkle the interrupt, and check if it's seen. */
-				outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
-				outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
-				if (irq == probe_irq_off(cookie)		 /* It's a good IRQ line! */
-					&& request_irq (irq, eip_interrupt, 0, DRV_NAME, dev) == 0) {
-					printk(" selecting IRQ %d.\n", irq);
-					dev->irq = *irqp;
-					break;
-				}
-			}
-		} while (*++irqp);
-		if (*irqp == 0) {
-			printk(" no free IRQ lines.\n");
-			retval = -EBUSY;
-			goto out;
-		}
-	} else {
-		if (dev->irq == 2)
-			dev->irq = 9;
-		if ((retval = request_irq(dev->irq, eip_interrupt, 0, DRV_NAME, dev))) {
-			printk (" unable to get IRQ %d.\n", dev->irq);
-			goto out;
-		}
-	}
-
-	/* Set the base address to point to the NIC, not the "real" base! */
-	dev->base_addr = ioaddr + NIC_OFFSET;
-	dev->netdev_ops = &eip_netdev_ops;
-
-	ei_status.name = name;
-	ei_status.word16 = wordmode;
-	ei_status.tx_start_page = HP_START_PG;
-	ei_status.rx_start_page = HP_START_PG + TX_PAGES;
-	ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
-
-	ei_status.reset_8390 = hp_reset_8390;
-	ei_status.get_8390_hdr = hp_get_8390_hdr;
-	ei_status.block_input = hp_block_input;
-	ei_status.block_output = hp_block_output;
-	hp_init_card(dev);
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out1;
-	return 0;
-out1:
-	free_irq(dev->irq, dev);
-out:
-	release_region(ioaddr, HP_IO_EXTENT);
-	return retval;
-}
-
-static void
-hp_reset_8390(struct net_device *dev)
-{
-	int hp_base = dev->base_addr - NIC_OFFSET;
-	int saved_config = inb_p(hp_base + HP_CONFIGURE);
-
-	if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
-	outb_p(0x00, hp_base + HP_CONFIGURE);
-	ei_status.txing = 0;
-	/* Pause just a few cycles for the hardware reset to take place. */
-	udelay(5);
-
-	outb_p(saved_config, hp_base + HP_CONFIGURE);
-	udelay(5);
-
-	if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
-		printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-
-	if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-}
-
-static void
-hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	int nic_base = dev->base_addr;
-	int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
-	outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
-	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
-	outb_p(0, nic_base + EN0_RCNTHI);
-	outb_p(0, nic_base + EN0_RSARLO);	/* On page boundary */
-	outb_p(ring_page, nic_base + EN0_RSARHI);
-	outb_p(E8390_RREAD+E8390_START, nic_base);
-
-	if (ei_status.word16)
-	  insw(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-	else
-	  insb(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
-
-	outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-/* Block input and output, similar to the Crynwr packet driver. If you are
-   porting to a new ethercard look at the packet driver source for hints.
-   The HP LAN doesn't use shared memory -- we put the packet
-   out through the "remote DMA" dataport. */
-
-static void
-hp_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	int nic_base = dev->base_addr;
-	int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-	int xfer_count = count;
-	char *buf = skb->data;
-
-	outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
-	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-	outb_p(count >> 8, nic_base + EN0_RCNTHI);
-	outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-	outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-	outb_p(E8390_RREAD+E8390_START, nic_base);
-	if (ei_status.word16) {
-	  insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
-	  if (count & 0x01)
-		buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
-	} else {
-		insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
-	}
-	/* This is for the ALPHA version only, remove for later releases. */
-	if (ei_debug > 0) {			/* DMA termination address check... */
-	  int high = inb_p(nic_base + EN0_RSARHI);
-	  int low = inb_p(nic_base + EN0_RSARLO);
-	  int addr = (high << 8) + low;
-	  /* Check only the lower 8 bits so we can ignore ring wrap. */
-	  if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
-		printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
-			   dev->name, ring_offset + xfer_count, addr);
-	}
-	outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-static void
-hp_block_output(struct net_device *dev, int count,
-				const unsigned char *buf, int start_page)
-{
-	int nic_base = dev->base_addr;
-	int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
-	outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-	/* Round the count up for word writes.	Do we need to do this?
-	   What effect will an odd byte count have on the 8390?
-	   I should check someday. */
-	if (ei_status.word16 && (count & 0x01))
-	  count++;
-	/* We should already be in page 0, but to be safe... */
-	outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
-
-#ifdef NE8390_RW_BUGFIX
-	/* Handle the read-before-write bug the same way as the
-	   Crynwr packet driver -- the NatSemi method doesn't work. */
-	outb_p(0x42, nic_base + EN0_RCNTLO);
-	outb_p(0,	nic_base + EN0_RCNTHI);
-	outb_p(0xff, nic_base + EN0_RSARLO);
-	outb_p(0x00, nic_base + EN0_RSARHI);
-#define NE_CMD	 	0x00
-	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
-	/* Make certain that the dummy read has occurred. */
-	inb_p(0x61);
-	inb_p(0x61);
-#endif
-
-	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-	outb_p(count >> 8,	 nic_base + EN0_RCNTHI);
-	outb_p(0x00, nic_base + EN0_RSARLO);
-	outb_p(start_page, nic_base + EN0_RSARHI);
-
-	outb_p(E8390_RWRITE+E8390_START, nic_base);
-	if (ei_status.word16) {
-		/* Use the 'rep' sequence for 16 bit boards. */
-		outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
-	} else {
-		outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
-	}
-
-	/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
-
-	/* This is for the ALPHA version only, remove for later releases. */
-	if (ei_debug > 0) {			/* DMA termination address check... */
-	  int high = inb_p(nic_base + EN0_RSARHI);
-	  int low  = inb_p(nic_base + EN0_RSARLO);
-	  int addr = (high << 8) + low;
-	  if ((start_page << 8) + count != addr)
-		printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
-			   dev->name, (start_page << 8) + count, addr);
-	}
-	outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-/* This function resets the ethercard if something screws up. */
-static void __init
-hp_init_card(struct net_device *dev)
-{
-	int irq = dev->irq;
-	NS8390p_init(dev, 0);
-	outb_p(irqmap[irq&0x0f] | HP_RUN,
-		   dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
-}
-
-#ifdef MODULE
-#define MAX_HP_CARDS	4	/* Max number of HP cards per module */
-static struct net_device *dev_hp[MAX_HP_CARDS];
-static int io[MAX_HP_CARDS];
-static int irq[MAX_HP_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_DESCRIPTION("HP PC-LAN ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_eip_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		if (do_hp_probe(dev) == 0) {
-			dev_hp[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
-		struct net_device *dev = dev_hp[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/lne390.c b/drivers/net/ethernet/8390/lne390.c
deleted file mode 100644
index 479409b..0000000
--- a/drivers/net/ethernet/8390/lne390.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
-	lne390.c
-
-	Linux driver for Mylex LNE390 EISA Network Adapter
-
-	Copyright (C) 1996-1998, Paul Gortmaker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	Information and Code Sources:
-
-	1) Based upon framework of es3210 driver.
-	2) The existing myriad of other Linux 8390 drivers by Donald Becker.
-	3) Russ Nelson's asm packet driver provided additional info.
-	4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
-
-	The LNE390 is an EISA shared memory NS8390 implementation. Note
-	that all memory copies to/from the board must be 32bit transfers.
-	There are two versions of the card: the lne390a and the lne390b.
-	Going by the EISA cfg files, the "a" has jumpers to select between
-	BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
-	The shared memory address selection is also slightly different.
-	Note that shared memory address > 1MB are supported with this driver.
-
-	You can try <http://www.mylex.com> if you want more info, as I've
-	never even seen one of these cards.  :)
-
-	Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/01
-	- get rid of check_region
-	- no need to check if dev == NULL in lne390_probe1
-*/
-
-static const char *version =
-	"lne390.c: Driver revision v0.99.1, 01/09/2000\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "lne390"
-
-static int lne390_probe1(struct net_device *dev, int ioaddr);
-
-static void lne390_reset_8390(struct net_device *dev);
-
-static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void lne390_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
-
-#define LNE390_START_PG		0x00    /* First page of TX buffer	*/
-#define LNE390_STOP_PG		0x80    /* Last page +1 of RX ring	*/
-
-#define LNE390_ID_PORT		0xc80	/* Same for all EISA cards 	*/
-#define LNE390_IO_EXTENT	0x20
-#define LNE390_SA_PROM		0x16	/* Start of e'net addr.		*/
-#define LNE390_RESET_PORT	0xc84	/* From the pkt driver source	*/
-#define LNE390_NIC_OFFSET	0x00	/* Hello, the 8390 is *here*	*/
-
-#define LNE390_ADDR0		0x00	/* 3 byte vendor prefix		*/
-#define LNE390_ADDR1		0x80
-#define LNE390_ADDR2		0xe5
-
-#define LNE390_ID0	0x10009835	/* 0x3598 = 01101 01100 11000 = mlx */
-#define LNE390_ID1	0x11009835	/* above is the 390A, this is 390B  */
-
-#define LNE390_CFG1		0xc84	/* NB: 0xc84 is also "reset" port. */
-#define LNE390_CFG2		0xc90
-
-/*
- *	You can OR any of the following bits together and assign it
- *	to LNE390_DEBUG to get verbose driver info during operation.
- *	Currently only the probe one is implemented.
- */
-
-#define LNE390_D_PROBE	0x01
-#define LNE390_D_RX_PKT	0x02
-#define LNE390_D_TX_PKT	0x04
-#define LNE390_D_IRQ	0x08
-
-#define LNE390_DEBUG	0
-
-static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
-static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
-
-/*
- *	Probe for the card. The best way is to read the EISA ID if it
- *	is known. Then we can check the prefix of the station address
- *	PROM for a match against the value assigned to Mylex.
- */
-
-static int __init do_lne390_probe(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-	int irq = dev->irq;
-	int mem_start = dev->mem_start;
-	int ret;
-
-	if (ioaddr > 0x1ff) {		/* Check a single specified location. */
-		if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
-			return -EBUSY;
-		ret = lne390_probe1(dev, ioaddr);
-		if (ret)
-			release_region(ioaddr, LNE390_IO_EXTENT);
-		return ret;
-	}
-	else if (ioaddr > 0)		/* Don't probe at all. */
-		return -ENXIO;
-
-	if (!EISA_bus) {
-#if LNE390_DEBUG & LNE390_D_PROBE
-		printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
-#endif
-		return -ENXIO;
-	}
-
-	/* EISA spec allows for up to 16 slots, but 8 is typical. */
-	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-		if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
-			continue;
-		if (lne390_probe1(dev, ioaddr) == 0)
-			return 0;
-		release_region(ioaddr, LNE390_IO_EXTENT);
-		dev->irq = irq;
-		dev->mem_start = mem_start;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init lne390_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_lne390_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static int __init lne390_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, revision, ret;
-	unsigned long eisa_id;
-
-	if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
-
-#if LNE390_DEBUG & LNE390_D_PROBE
-	printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
-	printk("lne390-debug: config regs: %#x %#x\n",
-		inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
-#endif
-
-
-/*	Check the EISA ID of the card. */
-	eisa_id = inl(ioaddr + LNE390_ID_PORT);
-	if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
-		return -ENODEV;
-	}
-
-	revision = (eisa_id >> 24) & 0x01;	/* 0 = rev A, 1 rev B */
-
-#if 0
-/*	Check the Mylex vendor ID as well. Not really required. */
-	if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
-		|| inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
-		|| inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
-		printk("lne390.c: card not found");
-		for (i = 0; i < ETH_ALEN; i++)
-			printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
-		printk(" (invalid prefix).\n");
-		return -ENODEV;
-	}
-#endif
-
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
-	printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
-	       0xa+revision, ioaddr/0x1000, dev->dev_addr);
-
-	printk("lne390.c: ");
-
-	/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
-	if (dev->irq == 0) {
-		unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
-		dev->irq = irq_map[irq_reg & 0x07];
-		printk("using");
-	} else {
-		/* This is useless unless we reprogram the card here too */
-		if (dev->irq == 2) dev->irq = 9;	/* Doh! */
-		printk("assigning");
-	}
-	printk(" IRQ %d,", dev->irq);
-
-	if ((ret = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
-		printk (" unable to get IRQ %d.\n", dev->irq);
-		return ret;
-	}
-
-	if (dev->mem_start == 0) {
-		unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
-
-		if (revision)	/* LNE390B */
-			dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
-		else		/* LNE390A */
-			dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
-		printk(" using ");
-	} else {
-		/* Should check for value in shmem_map and reprogram the card to use it */
-		dev->mem_start &= 0xfff0000;
-		printk(" assigning ");
-	}
-
-	printk("%dkB memory at physical address %#lx\n",
-			LNE390_STOP_PG/4, dev->mem_start);
-
-	/*
-	   BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
-	   the card mem within the region covered by `normal' RAM  !!!
-
-	   ioremap() will fail in that case.
-	*/
-	ei_status.mem = ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
-	if (!ei_status.mem) {
-		printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
-		printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
-		printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
-		ret = -EAGAIN;
-		goto cleanup;
-	}
-	printk("lne390.c: remapped %dkB card memory to virtual address %p\n",
-			LNE390_STOP_PG/4, ei_status.mem);
-
-	dev->mem_start = (unsigned long)ei_status.mem;
-	dev->mem_end = dev->mem_start + (LNE390_STOP_PG - LNE390_START_PG)*256;
-
-	/* The 8390 offset is zero for the LNE390 */
-	dev->base_addr = ioaddr;
-
-	ei_status.name = "LNE390";
-	ei_status.tx_start_page = LNE390_START_PG;
-	ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
-	ei_status.stop_page = LNE390_STOP_PG;
-	ei_status.word16 = 1;
-
-	if (ei_debug > 0)
-		printk(version);
-
-	ei_status.reset_8390 = &lne390_reset_8390;
-	ei_status.block_input = &lne390_block_input;
-	ei_status.block_output = &lne390_block_output;
-	ei_status.get_8390_hdr = &lne390_get_8390_hdr;
-
-	dev->netdev_ops = &ei_netdev_ops;
-	NS8390_init(dev, 0);
-
-	ret = register_netdev(dev);
-	if (ret)
-		goto unmap;
-	return 0;
-unmap:
-	if (ei_status.reg0)
-		iounmap(ei_status.mem);
-cleanup:
-	free_irq(dev->irq, dev);
-	return ret;
-}
-
-/*
- *	Reset as per the packet driver method. Judging by the EISA cfg
- *	file, this just toggles the "Board Enable" bits (bit 2 and 0).
- */
-
-static void lne390_reset_8390(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-
-	outb(0x04, ioaddr + LNE390_RESET_PORT);
-	if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
-
-	mdelay(2);
-
-	ei_status.txing = 0;
-	outb(0x01, ioaddr + LNE390_RESET_PORT);
-	if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- *	Note: In the following three functions is the implicit assumption
- *	that the associated memcpy will only use "rep; movsl" as long as
- *	we keep the counts as some multiple of doublewords. This is a
- *	requirement of the hardware, and also prevents us from using
- *	eth_io_copy_and_sum() since we can't guarantee it will limit
- *	itself to doubleword access.
- */
-
-/*
- *	Grab the 8390 specific header. Similar to the block_input routine, but
- *	we don't need to be concerned with ring wrap as the header will be at
- *	the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - LNE390_START_PG)<<8);
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
-}
-
-/*
- *	Block input and output are easy on shared memory ethercards, the only
- *	complication is when the ring buffer wraps. The count will already
- *	be rounded up to a doubleword value via lne390_get_8390_hdr() above.
- */
-
-static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-						  int ring_offset)
-{
-	void __iomem *xfer_start = ei_status.mem + ring_offset - (LNE390_START_PG<<8);
-
-	if (ring_offset + count > (LNE390_STOP_PG<<8)) {
-		/* Packet wraps over end of ring buffer. */
-		int semi_count = (LNE390_STOP_PG<<8) - ring_offset;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count,
-			ei_status.mem + (TX_PAGES<<8), count);
-	} else {
-		/* Packet is in one chunk. */
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-}
-
-static void lne390_block_output(struct net_device *dev, int count,
-				const unsigned char *buf, int start_page)
-{
-	void __iomem *shmem = ei_status.mem + ((start_page - LNE390_START_PG)<<8);
-
-	count = (count + 3) & ~3;     /* Round up to doubleword */
-	memcpy_toio(shmem, buf, count);
-}
-
-
-#ifdef MODULE
-#define MAX_LNE_CARDS	4	/* Max number of LNE390 cards per module */
-static struct net_device *dev_lne[MAX_LNE_CARDS];
-static int io[MAX_LNE_CARDS];
-static int irq[MAX_LNE_CARDS];
-static int mem[MAX_LNE_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "memory base address(es)");
-MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
-		if (io[this_dev] == 0 && this_dev != 0)
-			break;
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];
-		if (do_lne390_probe(dev) == 0) {
-			dev_lne[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr, LNE390_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-void __exit cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
-		struct net_device *dev = dev_lne[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c
index c0c1279..587a885 100644
--- a/drivers/net/ethernet/8390/ne2k-pci.c
+++ b/drivers/net/ethernet/8390/ne2k-pci.c
@@ -374,7 +374,6 @@
 	NS8390_init(dev, 0);
 
 	memcpy(dev->dev_addr, SA_prom, dev->addr_len);
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	i = register_netdev(dev);
 	if (i)
diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c
deleted file mode 100644
index ebcdb52..0000000
--- a/drivers/net/ethernet/8390/ne3210.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
-	ne3210.c
-
-	Linux driver for Novell NE3210 EISA Network Adapter
-
-	Copyright (C) 1998, Paul Gortmaker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	Information and Code Sources:
-
-	1) Based upon my other EISA 8390 drivers (lne390, es3210, smc-ultra32)
-	2) The existing myriad of other Linux 8390 drivers by Donald Becker.
-	3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
-
-	The NE3210 is an EISA shared memory NS8390 implementation.  Shared
-	memory address > 1MB should work with this driver.
-
-	Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
-	around (or perhaps there are some defective/backwards cards ???)
-
-	This driver WILL NOT WORK FOR THE NE3200 - it is completely different
-	and does not use an 8390 at all.
-
-	Updated to EISA probing API 5/2003 by Marc Zyngier.
-*/
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "ne3210"
-
-static void ne3210_reset_8390(struct net_device *dev);
-
-static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void ne3210_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
-
-#define NE3210_START_PG		0x00    /* First page of TX buffer	*/
-#define NE3210_STOP_PG		0x80    /* Last page +1 of RX ring	*/
-
-#define NE3210_IO_EXTENT	0x20
-#define NE3210_SA_PROM		0x16	/* Start of e'net addr.		*/
-#define NE3210_RESET_PORT	0xc84
-#define NE3210_NIC_OFFSET	0x00	/* Hello, the 8390 is *here*	*/
-
-#define NE3210_ADDR0		0x00	/* 3 byte vendor prefix		*/
-#define NE3210_ADDR1		0x00
-#define NE3210_ADDR2		0x1b
-
-#define NE3210_CFG1		0xc84	/* NB: 0xc84 is also "reset" port. */
-#define NE3210_CFG2		0xc90
-#define NE3210_CFG_EXTENT       (NE3210_CFG2 - NE3210_CFG1 + 1)
-
-/*
- *	You can OR any of the following bits together and assign it
- *	to NE3210_DEBUG to get verbose driver info during operation.
- *	Currently only the probe one is implemented.
- */
-
-#define NE3210_D_PROBE	0x01
-#define NE3210_D_RX_PKT	0x02
-#define NE3210_D_TX_PKT	0x04
-#define NE3210_D_IRQ	0x08
-
-#define NE3210_DEBUG	0x0
-
-static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
-static const char * const ifmap[] __initconst = {"UTP", "?", "BNC", "AUI"};
-static int ifmap_val[] __initdata = {
-		IF_PORT_10BASET,
-		IF_PORT_UNKNOWN,
-		IF_PORT_10BASE2,
-		IF_PORT_AUI,
-};
-
-static int __init ne3210_eisa_probe (struct device *device)
-{
-	unsigned long ioaddr, phys_mem;
-	int i, retval, port_index;
-	struct eisa_device *edev = to_eisa_device (device);
-	struct net_device *dev;
-
-	/* Allocate dev->priv and fill in 8390 specific dev fields. */
-	if (!(dev = alloc_ei_netdev ())) {
-		printk ("ne3210.c: unable to allocate memory for dev!\n");
-		return -ENOMEM;
-	}
-
-	SET_NETDEV_DEV(dev, device);
-	dev_set_drvdata(device, dev);
-	ioaddr = edev->base_addr;
-
-	if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) {
-		retval = -EBUSY;
-		goto out;
-	}
-
-	if (!request_region(ioaddr + NE3210_CFG1,
-			    NE3210_CFG_EXTENT, DRV_NAME)) {
-		retval = -EBUSY;
-		goto out1;
-	}
-
-#if NE3210_DEBUG & NE3210_D_PROBE
-	printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
-	printk("ne3210-debug: config regs: %#x %#x\n",
-		inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
-#endif
-
-	port_index = inb(ioaddr + NE3210_CFG2) >> 6;
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
-	printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
-		edev->slot, ifmap[port_index], dev->dev_addr);
-
-	/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
-	dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
-	printk("ne3210.c: using IRQ %d, ", dev->irq);
-
-	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
-	if (retval) {
-		printk (" unable to get IRQ %d.\n", dev->irq);
-		goto out2;
-	}
-
-	phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
-
-	/*
-	   BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
-	   the card mem within the region covered by `normal' RAM  !!!
-	*/
-	if (phys_mem > 1024*1024) {	/* phys addr > 1MB */
-		if (phys_mem < virt_to_phys(high_memory)) {
-			printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
-			printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
-			printk(KERN_CRIT "ne3210.c: or to an address above 0x%llx.\n",
-				(u64)virt_to_phys(high_memory));
-			printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
-			retval = -EINVAL;
-			goto out3;
-		}
-	}
-
-	if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
-		printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
-			phys_mem);
-		goto out3;
-	}
-
-	printk("%dkB memory at physical address %#lx\n",
-	       NE3210_STOP_PG/4, phys_mem);
-
-	ei_status.mem = ioremap(phys_mem, NE3210_STOP_PG*0x100);
-	if (!ei_status.mem) {
-		printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
-		printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
-		retval = -EAGAIN;
-		goto out4;
-	}
-	printk("ne3210.c: remapped %dkB card memory to virtual address %p\n",
-	       NE3210_STOP_PG/4, ei_status.mem);
-	dev->mem_start = (unsigned long)ei_status.mem;
-	dev->mem_end = dev->mem_start + (NE3210_STOP_PG - NE3210_START_PG)*256;
-
-	/* The 8390 offset is zero for the NE3210 */
-	dev->base_addr = ioaddr;
-
-	ei_status.name = "NE3210";
-	ei_status.tx_start_page = NE3210_START_PG;
-	ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
-	ei_status.stop_page = NE3210_STOP_PG;
-	ei_status.word16 = 1;
-	ei_status.priv = phys_mem;
-
-	if (ei_debug > 0)
-		printk("ne3210 loaded.\n");
-
-	ei_status.reset_8390 = &ne3210_reset_8390;
-	ei_status.block_input = &ne3210_block_input;
-	ei_status.block_output = &ne3210_block_output;
-	ei_status.get_8390_hdr = &ne3210_get_8390_hdr;
-
-	dev->netdev_ops = &ei_netdev_ops;
-
-	dev->if_port = ifmap_val[port_index];
-
-	if ((retval = register_netdev (dev)))
-		goto out5;
-
-	NS8390_init(dev, 0);
-	return 0;
-
- out5:
-	iounmap(ei_status.mem);
- out4:
-	release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
- out3:
-	free_irq (dev->irq, dev);
- out2:
-	release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
- out1:
-	release_region (ioaddr, NE3210_IO_EXTENT);
- out:
-	free_netdev (dev);
-
-	return retval;
-}
-
-static int ne3210_eisa_remove(struct device *device)
-{
-	struct net_device  *dev    = dev_get_drvdata(device);
-	unsigned long       ioaddr = to_eisa_device (device)->base_addr;
-
-	unregister_netdev (dev);
-	iounmap(ei_status.mem);
-	release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
-	free_irq (dev->irq, dev);
-	release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
-	release_region (ioaddr, NE3210_IO_EXTENT);
-	free_netdev (dev);
-
-	return 0;
-}
-
-/*
- *	Reset by toggling the "Board Enable" bits (bit 2 and 0).
- */
-
-static void ne3210_reset_8390(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-
-	outb(0x04, ioaddr + NE3210_RESET_PORT);
-	if (ei_debug > 1) printk("%s: resetting the NE3210...", dev->name);
-
-	mdelay(2);
-
-	ei_status.txing = 0;
-	outb(0x01, ioaddr + NE3210_RESET_PORT);
-	if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- *	Note: In the following three functions is the implicit assumption
- *	that the associated memcpy will only use "rep; movsl" as long as
- *	we keep the counts as some multiple of doublewords. This is a
- *	requirement of the hardware, and also prevents us from using
- *	eth_io_copy_and_sum() since we can't guarantee it will limit
- *	itself to doubleword access.
- */
-
-/*
- *	Grab the 8390 specific header. Similar to the block_input routine, but
- *	we don't need to be concerned with ring wrap as the header will be at
- *	the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - NE3210_START_PG)<<8);
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
-}
-
-/*
- *	Block input and output are easy on shared memory ethercards, the only
- *	complication is when the ring buffer wraps. The count will already
- *	be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
- */
-
-static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-						  int ring_offset)
-{
-	void __iomem *start = ei_status.mem + ring_offset - NE3210_START_PG*256;
-
-	if (ring_offset + count > NE3210_STOP_PG*256) {
-		/* Packet wraps over end of ring buffer. */
-		int semi_count = NE3210_STOP_PG*256 - ring_offset;
-		memcpy_fromio(skb->data, start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count,
-				ei_status.mem + TX_PAGES*256, count);
-	} else {
-		/* Packet is in one chunk. */
-		memcpy_fromio(skb->data, start, count);
-	}
-}
-
-static void ne3210_block_output(struct net_device *dev, int count,
-				const unsigned char *buf, int start_page)
-{
-	void __iomem *shmem = ei_status.mem + ((start_page - NE3210_START_PG)<<8);
-
-	count = (count + 3) & ~3;     /* Round up to doubleword */
-	memcpy_toio(shmem, buf, count);
-}
-
-static struct eisa_device_id ne3210_ids[] = {
-	{ "EGL0101" },
-	{ "NVL1801" },
-	{ "" },
-};
-MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-
-static struct eisa_driver ne3210_eisa_driver = {
-	.id_table = ne3210_ids,
-	.driver   = {
-		.name   = "ne3210",
-		.probe  = ne3210_eisa_probe,
-		.remove = ne3210_eisa_remove,
-	},
-};
-
-MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-
-static int ne3210_init(void)
-{
-	return eisa_driver_register (&ne3210_eisa_driver);
-}
-
-static void ne3210_cleanup(void)
-{
-	eisa_driver_unregister (&ne3210_eisa_driver);
-}
-
-module_init (ne3210_init);
-module_exit (ne3210_cleanup);
diff --git a/drivers/net/ethernet/8390/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c
deleted file mode 100644
index 923e42a..0000000
--- a/drivers/net/ethernet/8390/smc-ultra32.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/* 	smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux.
-
-Sources:
-
-	This driver is based on (cloned from) the ISA SMC Ultra driver
-	written by Donald Becker. Modifications to support the EISA
-	version of the card by Paul Gortmaker and Leonard N. Zubkoff.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-Theory of Operation:
-
-	The SMC Ultra32C card uses the SMC 83c790 chip which is also
-	found on the ISA SMC Ultra cards. It has a shared memory mode of
-	operation that makes it similar to the ISA version of the card.
-	The main difference is that the EISA card has 32KB of RAM, but
-	only an 8KB window into that memory. The EISA card also can be
-	set for a bus-mastering mode of operation via the ECU, but that
-	is not (and probably will never be) supported by this driver.
-	The ECU should be run to enable shared memory and to disable the
-	bus-mastering feature for use with linux.
-
-	By programming the 8390 to use only 8KB RAM, the modifications
-	to the ISA driver can be limited to the probe and initialization
-	code. This allows easy integration of EISA support into the ISA
-	driver. However, the driver development kit from SMC provided the
-	register information for sliding the 8KB window, and hence the 8390
-	is programmed to use the full 32KB RAM.
-
-	Unfortunately this required code changes outside the probe/init
-	routines, and thus we decided to separate the EISA driver from
-	the ISA one. In this way, ISA users don't end up with a larger
-	driver due to the EISA code, and EISA users don't end up with a
-	larger driver due to the ISA EtherEZ PIO code. The driver is
-	similar to the 3c503/16 driver, in that the window must be set
-	back to the 1st 8KB of space for access to the two 8390 Tx slots.
-
-	In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to
-	be a limiting factor, since the EISA bus could get packets off
-	the card fast enough, but having the use of lots of RAM as Rx
-	space is extra insurance if interrupt latencies become excessive.
-
-*/
-
-static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
-
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "smc-ultra32"
-
-static int ultra32_probe1(struct net_device *dev, int ioaddr);
-static int ultra32_open(struct net_device *dev);
-static void ultra32_reset_8390(struct net_device *dev);
-static void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-				 int ring_page);
-static void ultra32_block_input(struct net_device *dev, int count,
-				struct sk_buff *skb, int ring_offset);
-static void ultra32_block_output(struct net_device *dev, int count,
-				 const unsigned char *buf,
-				 const int start_page);
-static int ultra32_close(struct net_device *dev);
-
-#define ULTRA32_CMDREG	0	/* Offset to ASIC command register. */
-#define	 ULTRA32_RESET	0x80	/* Board reset, in ULTRA32_CMDREG. */
-#define	 ULTRA32_MEMENB	0x40	/* Enable the shared memory. */
-#define ULTRA32_NIC_OFFSET 16	/* NIC register offset from the base_addr. */
-#define ULTRA32_IO_EXTENT 32
-#define EN0_ERWCNT		0x08	/* Early receive warning count. */
-
-/*
- * Defines that apply only to the Ultra32 EISA card. Note that
- * "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates
- * into an EISA ID of 0x1080A34D
- */
-#define ULTRA32_BASE	0xca0
-#define ULTRA32_ID	0x1080a34d
-#define ULTRA32_IDPORT	(-0x20)	/* 0xc80 */
-/* Config regs 1->7 from the EISA !SMC8010.CFG file. */
-#define ULTRA32_CFG1	0x04	/* 0xca4 */
-#define ULTRA32_CFG2	0x05	/* 0xca5 */
-#define ULTRA32_CFG3	(-0x18)	/* 0xc88 */
-#define ULTRA32_CFG4	(-0x17)	/* 0xc89 */
-#define ULTRA32_CFG5	(-0x16)	/* 0xc8a */
-#define ULTRA32_CFG6	(-0x15)	/* 0xc8b */
-#define ULTRA32_CFG7	0x0d	/* 0xcad */
-
-static void cleanup_card(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
-	/* NB: ultra32_close_card() does free_irq */
-	release_region(ioaddr, ULTRA32_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-/*	Probe for the Ultra32.  This looks like a 8013 with the station
-	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-	following.
-*/
-
-struct net_device * __init ultra32_probe(int unit)
-{
-	struct net_device *dev;
-	int base;
-	int irq;
-	int err = -ENODEV;
-
-	if (!EISA_bus)
-		return ERR_PTR(-ENODEV);
-
-	dev = alloc_ei_netdev();
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-	}
-
-	irq = dev->irq;
-
-	/* EISA spec allows for up to 16 slots, but 8 is typical. */
-	for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) {
-		if (ultra32_probe1(dev, base) == 0)
-			break;
-		dev->irq = irq;
-	}
-	if (base >= 0x9000)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	cleanup_card(dev);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-
-static const struct net_device_ops ultra32_netdev_ops = {
-	.ndo_open 		= ultra32_open,
-	.ndo_stop 		= ultra32_close,
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_change_mtu		= eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= ei_poll,
-#endif
-};
-
-static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, edge, media, retval;
-	int checksum = 0;
-	const char *model_name;
-	static unsigned version_printed;
-	/* Values from various config regs. */
-	unsigned char idreg;
-	unsigned char reg4;
-	const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
-
-	if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
-	    inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
-	edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
-	printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
-		ioaddr >> 12, ifmap[media],
-		(edge ? "Edge Triggered" : "Level Sensitive"));
-
-	idreg = inb(ioaddr + 7);
-	reg4 = inb(ioaddr + 4) & 0x7f;
-
-	/* Check the ID nibble. */
-	if ((idreg & 0xf0) != 0x20) {			/* SMC Ultra */
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Select the station address register set. */
-	outb(reg4, ioaddr + 4);
-
-	for (i = 0; i < 8; i++)
-		checksum += inb(ioaddr + 8 + i);
-	if ((checksum & 0xff) != 0xff) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	if (ei_debug  &&  version_printed++ == 0)
-		printk(version);
-
-	model_name = "SMC Ultra32";
-
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = inb(ioaddr + 8 + i);
-
-	printk("%s: %s at 0x%X, %pM",
-	       dev->name, model_name, ioaddr, dev->dev_addr);
-
-	/* Switch from the station address to the alternate register set and
-	   read the useful registers there. */
-	outb(0x80 | reg4, ioaddr + 4);
-
-	/* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
-	outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
-
-	/* Reset RAM addr. */
-	outb(0x00, ioaddr + 0x0b);
-
-	/* Switch back to the station address register set so that the
-	   MS-DOS driver can find the card after a warm boot. */
-	outb(reg4, ioaddr + 4);
-
-	if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) {
-		printk("\nsmc-ultra32: Card RAM is disabled!  "
-		       "Run EISA config utility.\n");
-		retval = -ENODEV;
-		goto out;
-	}
-	if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0)
-		printk("\nsmc-ultra32: Ignoring Bus-Master enable bit.  "
-		       "Run EISA config utility.\n");
-
-	if (dev->irq < 2) {
-		unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
-		int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07];
-		if (irq == 0) {
-			printk(", failed to detect IRQ line.\n");
-			retval = -EAGAIN;
-			goto out;
-		}
-		dev->irq = irq;
-	}
-
-	/* The 8390 isn't at the base address, so fake the offset */
-	dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET;
-
-	/* Save RAM address in the unused reg0 to avoid excess inb's. */
-	ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc;
-
-	dev->mem_start =  0xc0000 + ((ei_status.reg0 & 0x7c) << 11);
-
-	ei_status.name = model_name;
-	ei_status.word16 = 1;
-	ei_status.tx_start_page = 0;
-	ei_status.rx_start_page = TX_PAGES;
-	/* All Ultra32 cards have 32KB memory with an 8KB window. */
-	ei_status.stop_page = 128;
-
-	ei_status.mem = ioremap(dev->mem_start, 0x2000);
-	if (!ei_status.mem) {
-		printk(", failed to ioremap.\n");
-		retval = -ENOMEM;
-		goto out;
-	}
-	dev->mem_end = dev->mem_start + 0x1fff;
-
-	printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
-	       dev->irq, dev->mem_start, dev->mem_end);
-	ei_status.block_input = &ultra32_block_input;
-	ei_status.block_output = &ultra32_block_output;
-	ei_status.get_8390_hdr = &ultra32_get_8390_hdr;
-	ei_status.reset_8390 = &ultra32_reset_8390;
-
-	dev->netdev_ops = &ultra32_netdev_ops;
-	NS8390_init(dev, 0);
-
-	return 0;
-out:
-	release_region(ioaddr, ULTRA32_IO_EXTENT);
-	return retval;
-}
-
-static int ultra32_open(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
-	int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED;
-	int retval;
-
-	retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
-	if (retval)
-		return retval;
-
-	outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
-	outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
-	outb(0x84, ioaddr + 5);	/* Enable MEM16 & Disable Bus Master. */
-	outb(0x01, ioaddr + 6);	/* Enable Interrupts. */
-	/* Set the early receive warning level in window 0 high enough not
-	   to receive ERW interrupts. */
-	outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
-	outb(0xff, dev->base_addr + EN0_ERWCNT);
-	ei_open(dev);
-	return 0;
-}
-
-static int ultra32_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
-
-	netif_stop_queue(dev);
-
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-
-	outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */
-	outb(0x00, ioaddr + 6);		/* Disable interrupts. */
-	free_irq(dev->irq, dev);
-
-	NS8390_init(dev, 0);
-
-	return 0;
-}
-
-static void ultra32_reset_8390(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */
-
-	outb(ULTRA32_RESET, ioaddr);
-	if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies);
-	ei_status.txing = 0;
-
-	outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
-	outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
-	outb(0x84, ioaddr + 5);	/* Enable MEM16 & Disable Bus Master. */
-	outb(0x01, ioaddr + 6);	/* Enable Interrupts. */
-	if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void ultra32_get_8390_hdr(struct net_device *dev,
-				 struct e8390_pkt_hdr *hdr,
-				 int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8);
-	unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
-	/* Select correct 8KB Window. */
-	outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg);
-
-#ifdef __BIG_ENDIAN
-	/* Officially this is what we are doing, but the readl() is faster */
-	/* unfortunately it isn't endian aware of the struct               */
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = le16_to_cpu(hdr->count);
-#else
-	((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-}
-
-/* Block input and output are easy on shared memory ethercards, the only
-   complication is when the ring buffer wraps, or in this case, when a
-   packet spans an 8KB boundary. Note that the current 8KB segment is
-   already set by the get_8390_hdr routine. */
-
-static void ultra32_block_input(struct net_device *dev,
-				int count,
-				struct sk_buff *skb,
-				int ring_offset)
-{
-	void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff);
-	unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
-	if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) {
-		int semi_count = 8192 - (ring_offset & 0x1FFF);
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		if (ring_offset < 96*256) {
-			/* Select next 8KB Window. */
-			ring_offset += semi_count;
-			outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg);
-			memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
-		} else {
-			/* Select first 8KB Window. */
-			outb(ei_status.reg0, RamReg);
-			memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
-		}
-	} else {
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-}
-
-static void ultra32_block_output(struct net_device *dev,
-				 int count,
-				 const unsigned char *buf,
-				 int start_page)
-{
-	void __iomem *xfer_start = ei_status.mem + (start_page<<8);
-	unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
-	/* Select first 8KB Window. */
-	outb(ei_status.reg0, RamReg);
-
-	memcpy_toio(xfer_start, buf, count);
-}
-
-#ifdef MODULE
-#define MAX_ULTRA32_CARDS   4	/* Max number of Ultra cards per module */
-static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
-
-MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
-		struct net_device *dev = ultra32_probe(-1);
-		if (IS_ERR(dev))
-			break;
-		dev_ultra[found++] = dev;
-	}
-	if (found)
-		return 0;
-	printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
-	return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
-		struct net_device *dev = dev_ultra[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index e4ff389..ed956e0 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -135,7 +135,6 @@
 source "drivers/net/ethernet/packetengines/Kconfig"
 source "drivers/net/ethernet/pasemi/Kconfig"
 source "drivers/net/ethernet/qlogic/Kconfig"
-source "drivers/net/ethernet/racal/Kconfig"
 source "drivers/net/ethernet/realtek/Kconfig"
 source "drivers/net/ethernet/renesas/Kconfig"
 source "drivers/net/ethernet/rdc/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index d447307..8268d85 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -53,7 +53,6 @@
 obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
 obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
 obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
-obj-$(CONFIG_NET_VENDOR_RACAL) += racal/
 obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
 obj-$(CONFIG_SH_ETH) += renesas/
 obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index c1fdb8b..a175d0b 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -425,8 +425,8 @@
 		return -EINVAL;
 	}
 
-	phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
-			0, phy_mode);
+	phydev = phy_connect(dev, dev_name(&phydev->dev),
+			     &bfin_mac_adjust_link, phy_mode);
 
 	if (IS_ERR(phydev)) {
 		netdev_err(dev, "could not attach PHY\n");
@@ -498,10 +498,10 @@
 static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
 					struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, KBUILD_MODNAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->fw_version, "N/A");
-	strcpy(info->bus_info, dev_name(&dev->dev));
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+	strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
 }
 
 static void bfin_mac_ethtool_getwol(struct net_device *dev,
@@ -647,7 +647,6 @@
 	if (netif_running(dev))
 		return -EBUSY;
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	setup_mac_addr(dev->dev_addr);
 	return 0;
 }
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index aa53115..0be2195 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1127,10 +1127,11 @@
 {
 	struct greth_private *greth = netdev_priv(dev);
 
-	strncpy(info->driver, dev_driver_string(greth->dev), 32);
-	strncpy(info->version, "revision: 1.0", 32);
-	strncpy(info->bus_info, greth->dev->bus->name, 32);
-	strncpy(info->fw_version, "N/A", 32);
+	strlcpy(info->driver, dev_driver_string(greth->dev),
+		sizeof(info->driver));
+	strlcpy(info->version, "revision: 1.0", sizeof(info->version));
+	strlcpy(info->bus_info, greth->dev->bus->name, sizeof(info->bus_info));
+	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 	info->eedump_len = 0;
 	info->regdump_len = sizeof(struct greth_regs);
 }
@@ -1287,9 +1288,7 @@
 	}
 
 	ret = phy_connect_direct(dev, phy, &greth_link_change,
-			0, greth->gbit_mac ?
-			PHY_INTERFACE_MODE_GMII :
-			PHY_INTERFACE_MODE_MII);
+				 greth->gbit_mac ? PHY_INTERFACE_MODE_GMII : PHY_INTERFACE_MODE_MII);
 	if (ret) {
 		if (netif_msg_ifup(greth))
 			dev_err(&dev->dev, "could not attach to PHY\n");
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 8350f4b..13d74aa4 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -7,7 +7,7 @@
 	default y
 	depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \
 		   SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \
-		   (ARM && ARCH_EBSA110) || ISA || EISA || MCA || PCMCIA
+		   (ARM && ARCH_EBSA110) || ISA || EISA || PCMCIA
 	---help---
 	  If you have a network (Ethernet) chipset belonging to this class,
 	  say Y.
@@ -105,19 +105,6 @@
 	  DEC (now Compaq) based on the AMD LANCE chipset, including the
 	  DEPCA series.  (This chipset is better known via the NE2100 cards.)
 
-config DEPCA
-	tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
-	depends on (ISA || EISA || MCA)
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto> as well as
-	  <file:drivers/net/ethernet/amd/depca.c>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called depca.
-
 config HPLANCE
 	bool "HP on-board LANCE support"
 	depends on DIO
diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile
index 175caa5..cdd4301 100644
--- a/drivers/net/ethernet/amd/Makefile
+++ b/drivers/net/ethernet/amd/Makefile
@@ -8,7 +8,6 @@
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_DECLANCE) += declance.o
-obj-$(CONFIG_DEPCA) += depca.o
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_LANCE) += lance.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 2ea221e..de774d4 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -437,8 +437,8 @@
 	/* now we are supposed to have a proper phydev, to attach to... */
 	BUG_ON(phydev->attached_dev);
 
-	phydev = phy_connect(dev, dev_name(&phydev->dev), &au1000_adjust_link,
-			0, PHY_INTERFACE_MODE_MII);
+	phydev = phy_connect(dev, dev_name(&phydev->dev),
+			     &au1000_adjust_link, PHY_INTERFACE_MODE_MII);
 
 	if (IS_ERR(phydev)) {
 		netdev_err(dev, "Could not attach to PHY\n");
@@ -587,10 +587,10 @@
 {
 	struct au1000_private *aup = netdev_priv(dev);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	info->fw_version[0] = '\0';
-	sprintf(info->bus_info, "%s %d", DRV_NAME, aup->mac_id);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME,
+		 aup->mac_id);
 	info->regdump_len = 0;
 }
 
diff --git a/drivers/net/ethernet/amd/depca.c b/drivers/net/ethernet/amd/depca.c
deleted file mode 100644
index 34a4853..0000000
--- a/drivers/net/ethernet/amd/depca.c
+++ /dev/null
@@ -1,1910 +0,0 @@
-/*  depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
-
-    Written 1994, 1995 by David C. Davies.
-
-
-                      Copyright 1994 David C. Davies
-		                   and
-			 United States Government
-	 (as represented by the Director, National Security Agency).
-
-               Copyright 1995  Digital Equipment Corporation.
-
-
-    This software may be used and distributed according to the terms of
-    the GNU General Public License, incorporated herein by reference.
-
-    This driver is written for the Digital Equipment Corporation series
-    of DEPCA and EtherWORKS ethernet cards:
-
-        DEPCA       (the original)
-    	DE100
-    	DE101
-	DE200 Turbo
-	DE201 Turbo
-	DE202 Turbo (TP BNC)
-	DE210
-	DE422       (EISA)
-
-    The  driver has been tested on DE100, DE200 and DE202 cards  in  a
-    relatively busy network. The DE422 has been tested a little.
-
-    This  driver will NOT work   for the DE203,  DE204  and DE205 series  of
-    cards,  since they have  a  new custom ASIC in   place of the AMD  LANCE
-    chip.  See the 'ewrk3.c'   driver in the  Linux  source tree for running
-    those cards.
-
-    I have benchmarked the driver with a  DE100 at 595kB/s to (542kB/s from)
-    a DECstation 5000/200.
-
-    The author may be reached at davies@maniac.ultranet.com
-
-    =========================================================================
-
-    The  driver was originally based  on   the 'lance.c' driver from  Donald
-    Becker   which  is included with  the  standard  driver distribution for
-    linux.  V0.4  is  a complete  re-write  with only  the kernel  interface
-    remaining from the original code.
-
-    1) Lance.c code in /linux/drivers/net/
-    2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
-       AMD, 1992 [(800) 222-9323].
-    3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
-       AMD, Pub. #17881, May 1993.
-    4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
-       AMD, Pub. #16907, May 1992
-    5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
-       Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
-    6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
-       Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
-    7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
-       Digital Equipment Corporation, 1989
-    8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
-       Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
-
-
-    Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
-    driver.
-
-    The original DEPCA  card requires that the  ethernet ROM address counter
-    be enabled to count and has an 8 bit NICSR.  The ROM counter enabling is
-    only  done when a  0x08 is read as the  first address octet (to minimise
-    the chances  of writing over some  other hardware's  I/O register).  The
-    NICSR accesses   have been changed  to  byte accesses  for all the cards
-    supported by this driver, since there is only one  useful bit in the MSB
-    (remote boot timeout) and it  is not used.  Also, there  is a maximum of
-    only 48kB network  RAM for this  card.  My thanks  to Torbjorn Lindh for
-    help debugging all this (and holding my feet to  the fire until I got it
-    right).
-
-    The DE200  series  boards have  on-board 64kB  RAM for  use  as a shared
-    memory network  buffer. Only the DE100  cards make use  of a  2kB buffer
-    mode which has not  been implemented in  this driver (only the 32kB  and
-    64kB modes are supported [16kB/48kB for the original DEPCA]).
-
-    At the most only 2 DEPCA cards can  be supported on  the ISA bus because
-    there is only provision  for two I/O base addresses  on each card (0x300
-    and 0x200). The I/O address is detected by searching for a byte sequence
-    in the Ethernet station address PROM at the expected I/O address for the
-    Ethernet  PROM.   The shared memory  base   address  is 'autoprobed'  by
-    looking  for the self  test PROM  and detecting the  card name.   When a
-    second  DEPCA is  detected,  information  is   placed in the   base_addr
-    variable of the  next device structure (which  is created if necessary),
-    thus  enabling ethif_probe  initialization  for the device.  More than 2
-    EISA cards can  be  supported, but  care will  be  needed assigning  the
-    shared memory to ensure that each slot has the  correct IRQ, I/O address
-    and shared memory address assigned.
-
-    ************************************************************************
-
-    NOTE: If you are using two  ISA DEPCAs, it is  important that you assign
-    the base memory addresses correctly.   The  driver autoprobes I/O  0x300
-    then 0x200.  The  base memory address for  the first device must be less
-    than that of the second so that the auto probe will correctly assign the
-    I/O and memory addresses on the same card.  I can't think of a way to do
-    this unambiguously at the moment, since there is nothing on the cards to
-    tie I/O and memory information together.
-
-    I am unable  to  test  2 cards   together for now,    so this  code   is
-    unchecked. All reports, good or bad, are welcome.
-
-    ************************************************************************
-
-    The board IRQ   setting must be  at an  unused IRQ which  is auto-probed
-    using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
-    {2,3,4,5,7}, whereas the  DE200 is at {5,9,10,11,15}.  Note that IRQ2 is
-    really IRQ9 in machines with 16 IRQ lines.
-
-    No 16MB memory  limitation should exist with this  driver as DMA is  not
-    used and the common memory area is in low memory on the network card (my
-    current system has 20MB and I've not had problems yet).
-
-    The ability to load this driver as a loadable module has been added. To
-    utilise this ability, you have to do <8 things:
-
-    0) have a copy of the loadable modules code installed on your system.
-    1) copy depca.c from the  /linux/drivers/net directory to your favourite
-    temporary directory.
-    2) if you wish, edit the  source code near  line 1530 to reflect the I/O
-    address and IRQ you're using (see also 5).
-    3) compile  depca.c, but include -DMODULE in  the command line to ensure
-    that the correct bits are compiled (see end of source code).
-    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
-    kernel with the depca configuration turned off and reboot.
-    5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
-       [Alan Cox: Changed the code to allow command line irq/io assignments]
-       [Dave Davies: Changed the code to allow command line mem/name
-                                                                assignments]
-    6) run the net startup bits for your eth?? interface manually
-    (usually /etc/rc.inet[12] at boot time).
-    7) enjoy!
-
-    Note that autoprobing is not allowed in loadable modules - the system is
-    already up and running and you're messing with interrupts.
-
-    To unload a module, turn off the associated interface
-    'ifconfig eth?? down' then 'rmmod depca'.
-
-    To assign a base memory address for the shared memory  when running as a
-    loadable module, see 5 above.  To include the adapter  name (if you have
-    no PROM  but know the card name)  also see 5  above. Note that this last
-    option  will not work  with kernel  built-in  depca's.
-
-    The shared memory assignment for a loadable module  makes sense to avoid
-    the 'memory autoprobe' picking the wrong shared memory  (for the case of
-    2 depca's in a PC).
-
-    ************************************************************************
-    Support for MCA EtherWORKS cards added 11-3-98. (MCA since deleted)
-    Verified to work with up to 2 DE212 cards in a system (although not
-      fully stress-tested).
-
-    Revision History
-    ----------------
-
-    Version   Date        Description
-
-      0.1     25-jan-94   Initial writing.
-      0.2     27-jan-94   Added LANCE TX hardware buffer chaining.
-      0.3      1-feb-94   Added multiple DEPCA support.
-      0.31     4-feb-94   Added DE202 recognition.
-      0.32    19-feb-94   Tidy up. Improve multi-DEPCA support.
-      0.33    25-feb-94   Fix DEPCA ethernet ROM counter enable.
-                          Add jabber packet fix from murf@perftech.com
-			  and becker@super.org
-      0.34     7-mar-94   Fix DEPCA max network memory RAM & NICSR access.
-      0.35     8-mar-94   Added DE201 recognition. Tidied up.
-      0.351   30-apr-94   Added EISA support. Added DE422 recognition.
-      0.36    16-may-94   DE422 fix released.
-      0.37    22-jul-94   Added MODULE support
-      0.38    15-aug-94   Added DBR ROM switch in depca_close().
-                          Multi DEPCA bug fix.
-      0.38axp 15-sep-94   Special version for Alpha AXP Linux V1.0.
-      0.381   12-dec-94   Added DE101 recognition, fix multicast bug.
-      0.382    9-feb-95   Fix recognition bug reported by <bkm@star.rl.ac.uk>.
-      0.383   22-feb-95   Fix for conflict with VESA SCSI reported by
-                          <stromain@alf.dec.com>
-      0.384   17-mar-95   Fix a ring full bug reported by <bkm@star.rl.ac.uk>
-      0.385    3-apr-95   Fix a recognition bug reported by
-                                                <ryan.niemi@lastfrontier.com>
-      0.386   21-apr-95   Fix the last fix...sorry, must be galloping senility
-      0.40    25-May-95   Rewrite for portability & updated.
-                          ALPHA support from <jestabro@amt.tay1.dec.com>
-      0.41    26-Jun-95   Added verify_area() calls in depca_ioctl() from
-                          suggestion by <heiko@colossus.escape.de>
-      0.42    27-Dec-95   Add 'mem' shared memory assignment for loadable
-                          modules.
-                          Add 'adapter_name' for loadable modules when no PROM.
-			  Both above from a suggestion by
-			  <pchen@woodruffs121.residence.gatech.edu>.
-			  Add new multicasting code.
-      0.421   22-Apr-96	  Fix alloc_device() bug <jari@markkus2.fimr.fi>
-      0.422   29-Apr-96	  Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
-      0.423    7-Jun-96   Fix module load bug <kmg@barco.be>
-      0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
-      0.44     1-Sep-97   Fix *_probe() to test check_region() first - bug
-                           reported by <mmogilvi@elbert.uccs.edu>
-      0.45     3-Nov-98   Added support for MCA EtherWORKS (DE210/DE212) cards
-                           by <tymm@computer.org>
-      0.451    5-Nov-98   Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
-      0.5     14-Nov-98   Re-spin for 2.1.x kernels.
-      0.51    27-Jun-99   Correct received packet length for CRC from
-                           report by <worm@dkik.dk>
-      0.52    16-Oct-00   Fixes for 2.3 io memory accesses
-                          Fix show-stopper (ints left masked) in depca_interrupt
-			   by <peterd@pnd-pc.demon.co.uk>
-      0.53    12-Jan-01	  Release resources on failure, bss tidbits
-      			   by acme@conectiva.com.br
-      0.54    08-Nov-01	  use library crc32 functions
-      			   by Matt_Domsch@dell.com
-      0.55    01-Mar-03   Use EISA/sysfs framework <maz@wild-wind.fr.eu.org>
-
-    =========================================================================
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#ifdef CONFIG_EISA
-#include <linux/eisa.h>
-#endif
-
-#include "depca.h"
-
-static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
-
-#ifdef DEPCA_DEBUG
-static int depca_debug = DEPCA_DEBUG;
-#else
-static int depca_debug = 1;
-#endif
-
-#define DEPCA_NDA 0xffe0	/* No Device Address */
-
-#define TX_TIMEOUT (1*HZ)
-
-/*
-** Ethernet PROM defines
-*/
-#define PROBE_LENGTH    32
-#define ETH_PROM_SIG    0xAA5500FFUL
-
-/*
-** Set the number of Tx and Rx buffers. Ensure that the memory requested
-** here is <= to the amount of shared memory set up by the board switches.
-** The number of descriptors MUST BE A POWER OF 2.
-**
-** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
-*/
-#define NUM_RX_DESC     8	/* Number of RX descriptors */
-#define NUM_TX_DESC     8	/* Number of TX descriptors */
-#define RX_BUFF_SZ	1536	/* Buffer size for each Rx buffer */
-#define TX_BUFF_SZ	1536	/* Buffer size for each Tx buffer */
-
-/*
-** EISA bus defines
-*/
-#define DEPCA_EISA_IO_PORTS 0x0c00	/* I/O port base address, slot 0 */
-
-/*
-** ISA Bus defines
-*/
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#define DEPCA_TOTAL_SIZE 0x10
-
-static struct {
-	u_long iobase;
-	struct platform_device *device;
-} depca_io_ports[] = {
-	{ 0x300, NULL },
-	{ 0x200, NULL },
-	{ 0    , NULL },
-};
-
-/*
-** Name <-> Adapter mapping
-*/
-#define DEPCA_SIGNATURE {"DEPCA",\
-			 "DE100","DE101",\
-                         "DE200","DE201","DE202",\
-			 "DE210","DE212",\
-                         "DE422",\
-                         ""}
-
-static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
-
-enum depca_type {
-	DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
-};
-
-static char depca_string[] = "depca";
-
-static int depca_device_remove (struct device *device);
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id depca_eisa_ids[] = {
-	{ "DEC4220", de422 },
-	{ "" }
-};
-MODULE_DEVICE_TABLE(eisa, depca_eisa_ids);
-
-static int depca_eisa_probe  (struct device *device);
-
-static struct eisa_driver depca_eisa_driver = {
-	.id_table = depca_eisa_ids,
-	.driver   = {
-		.name    = depca_string,
-		.probe   = depca_eisa_probe,
-		.remove  = depca_device_remove
-	}
-};
-#endif
-
-static int depca_isa_probe (struct platform_device *);
-
-static int depca_isa_remove(struct platform_device *pdev)
-{
-	return depca_device_remove(&pdev->dev);
-}
-
-static struct platform_driver depca_isa_driver = {
-	.probe  = depca_isa_probe,
-	.remove = depca_isa_remove,
-	.driver	= {
-		.name   = depca_string,
-	},
-};
-
-/*
-** Miscellaneous info...
-*/
-#define DEPCA_STRLEN 16
-
-/*
-** Memory Alignment. Each descriptor is 4 longwords long. To force a
-** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
-** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
-*/
-#define DEPCA_ALIGN4      ((u_long)4 - 1)	/* 1 longword align */
-#define DEPCA_ALIGN8      ((u_long)8 - 1)	/* 2 longword (quadword) align */
-#define DEPCA_ALIGN         DEPCA_ALIGN8	/* Keep the LANCE happy... */
-
-/*
-** The DEPCA Rx and Tx ring descriptors.
-*/
-struct depca_rx_desc {
-	volatile s32 base;
-	s16 buf_length;		/* This length is negative 2's complement! */
-	s16 msg_length;		/* This length is "normal". */
-};
-
-struct depca_tx_desc {
-	volatile s32 base;
-	s16 length;		/* This length is negative 2's complement! */
-	s16 misc;		/* Errors and TDR info */
-};
-
-#define LA_MASK 0x0000ffff	/* LANCE address mask for mapping network RAM
-				   to LANCE memory address space */
-
-/*
-** The Lance initialization block, described in databook, in common memory.
-*/
-struct depca_init {
-	u16 mode;		/* Mode register */
-	u8 phys_addr[ETH_ALEN];	/* Physical ethernet address */
-	u8 mcast_table[8];	/* Multicast Hash Table. */
-	u32 rx_ring;		/* Rx ring base pointer & ring length */
-	u32 tx_ring;		/* Tx ring base pointer & ring length */
-};
-
-#define DEPCA_PKT_STAT_SZ 16
-#define DEPCA_PKT_BIN_SZ  128	/* Should be >=100 unless you
-				   increase DEPCA_PKT_STAT_SZ */
-struct depca_private {
-	char adapter_name[DEPCA_STRLEN];	/* /proc/ioports string                  */
-	enum depca_type adapter;		/* Adapter type */
-	enum {
-                DEPCA_BUS_ISA = 1,
-                DEPCA_BUS_EISA,
-        } depca_bus;	        /* type of bus */
-	struct depca_init init_block;	/* Shadow Initialization block            */
-/* CPU address space fields */
-	struct depca_rx_desc __iomem *rx_ring;	/* Pointer to start of RX descriptor ring */
-	struct depca_tx_desc __iomem *tx_ring;	/* Pointer to start of TX descriptor ring */
-	void __iomem *rx_buff[NUM_RX_DESC];	/* CPU virt address of sh'd memory buffs  */
-	void __iomem *tx_buff[NUM_TX_DESC];	/* CPU virt address of sh'd memory buffs  */
-	void __iomem *sh_mem;	/* CPU mapped virt address of device RAM  */
-	u_long mem_start;	/* Bus address of device RAM (before remap) */
-	u_long mem_len;		/* device memory size */
-/* Device address space fields */
-	u_long device_ram_start;	/* Start of RAM in device addr space      */
-/* Offsets used in both address spaces */
-	u_long rx_ring_offset;	/* Offset from start of RAM to rx_ring    */
-	u_long tx_ring_offset;	/* Offset from start of RAM to tx_ring    */
-	u_long buffs_offset;	/* LANCE Rx and Tx buffers start address. */
-/* Kernel-only (not device) fields */
-	int rx_new, tx_new;	/* The next free ring entry               */
-	int rx_old, tx_old;	/* The ring entries to be free()ed.       */
-	spinlock_t lock;
-	struct {		/* Private stats counters                 */
-		u32 bins[DEPCA_PKT_STAT_SZ];
-		u32 unicast;
-		u32 multicast;
-		u32 broadcast;
-		u32 excessive_collisions;
-		u32 tx_underruns;
-		u32 excessive_underruns;
-	} pktStats;
-	int txRingMask;		/* TX ring mask                           */
-	int rxRingMask;		/* RX ring mask                           */
-	s32 rx_rlen;		/* log2(rxRingMask+1) for the descriptors */
-	s32 tx_rlen;		/* log2(txRingMask+1) for the descriptors */
-};
-
-/*
-** The transmit ring full condition is described by the tx_old and tx_new
-** pointers by:
-**    tx_old            = tx_new    Empty ring
-**    tx_old            = tx_new+1  Full ring
-**    tx_old+txRingMask = tx_new    Full ring  (wrapped condition)
-*/
-#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
-			 lp->tx_old+lp->txRingMask-lp->tx_new:\
-                         lp->tx_old               -lp->tx_new-1)
-
-/*
-** Public Functions
-*/
-static int depca_open(struct net_device *dev);
-static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
-				    struct net_device *dev);
-static irqreturn_t depca_interrupt(int irq, void *dev_id);
-static int depca_close(struct net_device *dev);
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void depca_tx_timeout(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/*
-** Private functions
-*/
-static void depca_init_ring(struct net_device *dev);
-static int depca_rx(struct net_device *dev);
-static int depca_tx(struct net_device *dev);
-
-static void LoadCSRs(struct net_device *dev);
-static int InitRestartDepca(struct net_device *dev);
-static int DepcaSignature(char *name, u_long paddr);
-static int DevicePresent(u_long ioaddr);
-static int get_hw_addr(struct net_device *dev);
-static void SetMulticastFilter(struct net_device *dev);
-static int load_packet(struct net_device *dev, struct sk_buff *skb);
-static void depca_dbg_open(struct net_device *dev);
-
-static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
-static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
-static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
-static u_char *depca_irq;
-
-static int irq;
-static int io;
-static char *adapter_name;
-static int mem;			/* For loadable module assignment
-				   use insmod mem=0x????? .... */
-module_param (irq, int, 0);
-module_param (io, int, 0);
-module_param (adapter_name, charp, 0);
-module_param (mem, int, 0);
-MODULE_PARM_DESC(irq, "DEPCA IRQ number");
-MODULE_PARM_DESC(io, "DEPCA I/O base address");
-MODULE_PARM_DESC(adapter_name, "DEPCA adapter name");
-MODULE_PARM_DESC(mem, "DEPCA shared memory address");
-MODULE_LICENSE("GPL");
-
-/*
-** Miscellaneous defines...
-*/
-#define STOP_DEPCA \
-    outw(CSR0, DEPCA_ADDR);\
-    outw(STOP, DEPCA_DATA)
-
-static const struct net_device_ops depca_netdev_ops = {
-	.ndo_open 		= depca_open,
-	.ndo_start_xmit 	= depca_start_xmit,
-	.ndo_stop 		= depca_close,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_do_ioctl 		= depca_ioctl,
-	.ndo_tx_timeout 	= depca_tx_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init depca_hw_init (struct net_device *dev, struct device *device)
-{
-	struct depca_private *lp;
-	int i, j, offset, netRAM, mem_len, status = 0;
-	s16 nicsr;
-	u_long ioaddr;
-	u_long mem_start;
-
-	/*
-	 * We are now supposed to enter this function with the
-	 * following fields filled with proper values :
-	 *
-	 * dev->base_addr
-	 * lp->mem_start
-	 * lp->depca_bus
-	 * lp->adapter
-	 *
-	 * dev->irq can be set if known from device configuration (on
-	 * MCA or EISA) or module option. Otherwise, it will be auto
-	 * detected.
-	 */
-
-	ioaddr = dev->base_addr;
-
-	STOP_DEPCA;
-
-	nicsr = inb(DEPCA_NICSR);
-	nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
-	outb(nicsr, DEPCA_NICSR);
-
-	if (inw(DEPCA_DATA) != STOP) {
-		return -ENXIO;
-	}
-
-	lp = netdev_priv(dev);
-	mem_start = lp->mem_start;
-
-	if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown)
-		return -ENXIO;
-
-	printk("%s: %s at 0x%04lx",
-	       dev_name(device), depca_signature[lp->adapter], ioaddr);
-
-	switch (lp->depca_bus) {
-#ifdef CONFIG_EISA
-	case DEPCA_BUS_EISA:
-		printk(" (EISA slot %d)", to_eisa_device(device)->slot);
-		break;
-#endif
-
-	case DEPCA_BUS_ISA:
-		break;
-
-	default:
-		printk("Unknown DEPCA bus %d\n", lp->depca_bus);
-		return -ENXIO;
-	}
-
-	printk(", h/w address ");
-	status = get_hw_addr(dev);
-	printk("%pM", dev->dev_addr);
-	if (status != 0) {
-		printk("      which has an Ethernet PROM CRC error.\n");
-		return -ENXIO;
-	}
-
-	/* Set up the maximum amount of network RAM(kB) */
-	netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
-	if ((nicsr & _128KB) && (lp->adapter == de422))
-		netRAM = 128;
-
-	/* Shared Memory Base Address */
-	if (nicsr & BUF) {
-		nicsr &= ~BS;	/* DEPCA RAM in top 32k */
-		netRAM -= 32;
-		mem_start += 0x8000;
-	}
-
-	if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
-	    > (netRAM << 10)) {
-		printk(",\n       requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
-		return -ENXIO;
-	}
-
-	printk(",\n      has %dkB RAM at 0x%.5lx", netRAM, mem_start);
-
-	/* Enable the shadow RAM. */
-	if (lp->adapter != DEPCA) {
-		nicsr |= SHE;
-		outb(nicsr, DEPCA_NICSR);
-	}
-
-	spin_lock_init(&lp->lock);
-	sprintf(lp->adapter_name, "%s (%s)",
-		depca_signature[lp->adapter], dev_name(device));
-	status = -EBUSY;
-
-	/* Initialisation Block */
-	if (!request_mem_region (mem_start, mem_len, lp->adapter_name)) {
-		printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
-		goto out_priv;
-	}
-
-	status = -EIO;
-	lp->sh_mem = ioremap(mem_start, mem_len);
-	if (lp->sh_mem == NULL) {
-		printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
-		goto out1;
-	}
-
-	lp->mem_start = mem_start;
-	lp->mem_len   = mem_len;
-	lp->device_ram_start = mem_start & LA_MASK;
-
-	offset = 0;
-	offset += sizeof(struct depca_init);
-
-	/* Tx & Rx descriptors (aligned to a quadword boundary) */
-	offset = (offset + DEPCA_ALIGN) & ~DEPCA_ALIGN;
-	lp->rx_ring = lp->sh_mem + offset;
-	lp->rx_ring_offset = offset;
-
-	offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
-	lp->tx_ring = lp->sh_mem + offset;
-	lp->tx_ring_offset = offset;
-
-	offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
-
-	lp->buffs_offset = offset;
-
-	/* Finish initialising the ring information. */
-	lp->rxRingMask = NUM_RX_DESC - 1;
-	lp->txRingMask = NUM_TX_DESC - 1;
-
-	/* Calculate Tx/Rx RLEN size for the descriptors. */
-	for (i = 0, j = lp->rxRingMask; j > 0; i++) {
-		j >>= 1;
-	}
-	lp->rx_rlen = (s32) (i << 29);
-	for (i = 0, j = lp->txRingMask; j > 0; i++) {
-		j >>= 1;
-	}
-	lp->tx_rlen = (s32) (i << 29);
-
-	/* Load the initialisation block */
-	depca_init_ring(dev);
-
-	/* Initialise the control and status registers */
-	LoadCSRs(dev);
-
-	/* Enable DEPCA board interrupts for autoprobing */
-	nicsr = ((nicsr & ~IM) | IEN);
-	outb(nicsr, DEPCA_NICSR);
-
-	/* To auto-IRQ we enable the initialization-done and DMA err,
-	   interrupts. For now we will always get a DMA error. */
-	if (dev->irq < 2) {
-		unsigned char irqnum;
-		unsigned long irq_mask, delay;
-
-		irq_mask = probe_irq_on();
-
-		/* Assign the correct irq list */
-		switch (lp->adapter) {
-		case DEPCA:
-		case de100:
-		case de101:
-			depca_irq = de1xx_irq;
-			break;
-		case de200:
-		case de201:
-		case de202:
-		case de210:
-		case de212:
-			depca_irq = de2xx_irq;
-			break;
-		case de422:
-			depca_irq = de422_irq;
-			break;
-
-		default:
-			break;	/* Not reached */
-		}
-
-		/* Trigger an initialization just for the interrupt. */
-		outw(INEA | INIT, DEPCA_DATA);
-
-		delay = jiffies + HZ/50;
-		while (time_before(jiffies, delay))
-			yield();
-
-		irqnum = probe_irq_off(irq_mask);
-
-		status = -ENXIO;
-		if (!irqnum) {
-			printk(" and failed to detect IRQ line.\n");
-			goto out2;
-		} else {
-			for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
-				if (irqnum == depca_irq[i]) {
-					dev->irq = irqnum;
-					printk(" and uses IRQ%d.\n", dev->irq);
-				}
-
-			if (!dev->irq) {
-				printk(" but incorrect IRQ line detected.\n");
-				goto out2;
-			}
-		}
-	} else {
-		printk(" and assigned IRQ%d.\n", dev->irq);
-	}
-
-	if (depca_debug > 1) {
-		printk(version);
-	}
-
-	/* The DEPCA-specific entries in the device structure. */
-	dev->netdev_ops = &depca_netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	dev->mem_start = 0;
-
-	dev_set_drvdata(device, dev);
-	SET_NETDEV_DEV (dev, device);
-
-	status = register_netdev(dev);
-	if (status == 0)
-		return 0;
-out2:
-	iounmap(lp->sh_mem);
-out1:
-	release_mem_region (mem_start, mem_len);
-out_priv:
-	return status;
-}
-
-
-static int depca_open(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_long ioaddr = dev->base_addr;
-	s16 nicsr;
-	int status = 0;
-
-	STOP_DEPCA;
-	nicsr = inb(DEPCA_NICSR);
-
-	/* Make sure the shadow RAM is enabled */
-	if (lp->adapter != DEPCA) {
-		nicsr |= SHE;
-		outb(nicsr, DEPCA_NICSR);
-	}
-
-	/* Re-initialize the DEPCA... */
-	depca_init_ring(dev);
-	LoadCSRs(dev);
-
-	depca_dbg_open(dev);
-
-	if (request_irq(dev->irq, depca_interrupt, 0, lp->adapter_name, dev)) {
-		printk("depca_open(): Requested IRQ%d is busy\n", dev->irq);
-		status = -EAGAIN;
-	} else {
-
-		/* Enable DEPCA board interrupts and turn off LED */
-		nicsr = ((nicsr & ~IM & ~LED) | IEN);
-		outb(nicsr, DEPCA_NICSR);
-		outw(CSR0, DEPCA_ADDR);
-
-		netif_start_queue(dev);
-
-		status = InitRestartDepca(dev);
-
-		if (depca_debug > 1) {
-			printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA));
-			printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR));
-		}
-	}
-	return status;
-}
-
-/* Initialize the lance Rx and Tx descriptor rings. */
-static void depca_init_ring(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_int i;
-	u_long offset;
-
-	/* Lock out other processes whilst setting up the hardware */
-	netif_stop_queue(dev);
-
-	lp->rx_new = lp->tx_new = 0;
-	lp->rx_old = lp->tx_old = 0;
-
-	/* Initialize the base address and length of each buffer in the ring */
-	for (i = 0; i <= lp->rxRingMask; i++) {
-		offset = lp->buffs_offset + i * RX_BUFF_SZ;
-		writel((lp->device_ram_start + offset) | R_OWN, &lp->rx_ring[i].base);
-		writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
-		lp->rx_buff[i] = lp->sh_mem + offset;
-	}
-
-	for (i = 0; i <= lp->txRingMask; i++) {
-		offset = lp->buffs_offset + (i + lp->rxRingMask + 1) * TX_BUFF_SZ;
-		writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base);
-		lp->tx_buff[i] = lp->sh_mem + offset;
-	}
-
-	/* Set up the initialization block */
-	lp->init_block.rx_ring = (lp->device_ram_start + lp->rx_ring_offset) | lp->rx_rlen;
-	lp->init_block.tx_ring = (lp->device_ram_start + lp->tx_ring_offset) | lp->tx_rlen;
-
-	SetMulticastFilter(dev);
-
-	for (i = 0; i < ETH_ALEN; i++) {
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	}
-
-	lp->init_block.mode = 0x0000;	/* Enable the Tx and Rx */
-}
-
-
-static void depca_tx_timeout(struct net_device *dev)
-{
-	u_long ioaddr = dev->base_addr;
-
-	printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA));
-
-	STOP_DEPCA;
-	depca_init_ring(dev);
-	LoadCSRs(dev);
-	dev->trans_start = jiffies; /* prevent tx timeout */
-	netif_wake_queue(dev);
-	InitRestartDepca(dev);
-}
-
-
-/*
-** Writes a socket buffer to TX descriptor ring and starts transmission
-*/
-static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
-				    struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_long ioaddr = dev->base_addr;
-	int status = 0;
-
-	/* Transmitter timeout, serious problems. */
-	if (skb->len < 1)
-		goto out;
-
-	if (skb_padto(skb, ETH_ZLEN))
-		goto out;
-
-	netif_stop_queue(dev);
-
-	if (TX_BUFFS_AVAIL) {	/* Fill in a Tx ring entry */
-		status = load_packet(dev, skb);
-
-		if (!status) {
-			/* Trigger an immediate send demand. */
-			outw(CSR0, DEPCA_ADDR);
-			outw(INEA | TDMD, DEPCA_DATA);
-
-			dev_kfree_skb(skb);
-		}
-		if (TX_BUFFS_AVAIL)
-			netif_start_queue(dev);
-	} else
-		status = NETDEV_TX_LOCKED;
-
-      out:
-	return status;
-}
-
-/*
-** The DEPCA interrupt handler.
-*/
-static irqreturn_t depca_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct depca_private *lp;
-	s16 csr0, nicsr;
-	u_long ioaddr;
-
-	if (dev == NULL) {
-		printk("depca_interrupt(): irq %d for unknown device.\n", irq);
-		return IRQ_NONE;
-	}
-
-	lp = netdev_priv(dev);
-	ioaddr = dev->base_addr;
-
-	spin_lock(&lp->lock);
-
-	/* mask the DEPCA board interrupts and turn on the LED */
-	nicsr = inb(DEPCA_NICSR);
-	nicsr |= (IM | LED);
-	outb(nicsr, DEPCA_NICSR);
-
-	outw(CSR0, DEPCA_ADDR);
-	csr0 = inw(DEPCA_DATA);
-
-	/* Acknowledge all of the current interrupt sources ASAP. */
-	outw(csr0 & INTE, DEPCA_DATA);
-
-	if (csr0 & RINT)	/* Rx interrupt (packet arrived) */
-		depca_rx(dev);
-
-	if (csr0 & TINT)	/* Tx interrupt (packet sent) */
-		depca_tx(dev);
-
-	/* Any resources available? */
-	if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
-		netif_wake_queue(dev);
-	}
-
-	/* Unmask the DEPCA board interrupts and turn off the LED */
-	nicsr = (nicsr & ~IM & ~LED);
-	outb(nicsr, DEPCA_NICSR);
-
-	spin_unlock(&lp->lock);
-	return IRQ_HANDLED;
-}
-
-/* Called with lp->lock held */
-static int depca_rx(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	int i, entry;
-	s32 status;
-
-	for (entry = lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry = lp->rx_new) {
-		status = readl(&lp->rx_ring[entry].base) >> 16;
-		if (status & R_STP) {	/* Remember start of frame */
-			lp->rx_old = entry;
-		}
-		if (status & R_ENP) {	/* Valid frame status */
-			if (status & R_ERR) {	/* There was an error. */
-				dev->stats.rx_errors++;	/* Update the error stats. */
-				if (status & R_FRAM)
-					dev->stats.rx_frame_errors++;
-				if (status & R_OFLO)
-					dev->stats.rx_over_errors++;
-				if (status & R_CRC)
-					dev->stats.rx_crc_errors++;
-				if (status & R_BUFF)
-					dev->stats.rx_fifo_errors++;
-			} else {
-				short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
-				struct sk_buff *skb;
-
-				skb = netdev_alloc_skb(dev, pkt_len + 2);
-				if (skb != NULL) {
-					unsigned char *buf;
-					skb_reserve(skb, 2);	/* 16 byte align the IP header */
-					buf = skb_put(skb, pkt_len);
-					if (entry < lp->rx_old) {	/* Wrapped buffer */
-						len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
-						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
-						memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len - len);
-					} else {	/* Linear buffer */
-						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
-					}
-
-					/*
-					   ** Notify the upper protocol layers that there is another
-					   ** packet to handle
-					 */
-					skb->protocol = eth_type_trans(skb, dev);
-					netif_rx(skb);
-
-					/*
-					   ** Update stats
-					 */
-					dev->stats.rx_packets++;
-					dev->stats.rx_bytes += pkt_len;
-					for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
-						if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
-							lp->pktStats.bins[i]++;
-							i = DEPCA_PKT_STAT_SZ;
-						}
-					}
-					if (is_multicast_ether_addr(buf)) {
-						if (is_broadcast_ether_addr(buf)) {
-							lp->pktStats.broadcast++;
-						} else {
-							lp->pktStats.multicast++;
-						}
-					} else if (ether_addr_equal(buf,
-								    dev->dev_addr)) {
-						lp->pktStats.unicast++;
-					}
-
-					lp->pktStats.bins[0]++;	/* Duplicates stats.rx_packets */
-					if (lp->pktStats.bins[0] == 0) {	/* Reset counters */
-						memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
-					}
-				} else {
-					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-					dev->stats.rx_dropped++;	/* Really, deferred. */
-					break;
-				}
-			}
-			/* Change buffer ownership for this last frame, back to the adapter */
-			for (; lp->rx_old != entry; lp->rx_old = (lp->rx_old + 1) & lp->rxRingMask) {
-				writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
-			}
-			writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
-		}
-
-		/*
-		   ** Update entry information
-		 */
-		lp->rx_new = (lp->rx_new + 1) & lp->rxRingMask;
-	}
-
-	return 0;
-}
-
-/*
-** Buffer sent - check for buffer errors.
-** Called with lp->lock held
-*/
-static int depca_tx(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	int entry;
-	s32 status;
-	u_long ioaddr = dev->base_addr;
-
-	for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
-		status = readl(&lp->tx_ring[entry].base) >> 16;
-
-		if (status < 0) {	/* Packet not yet sent! */
-			break;
-		} else if (status & T_ERR) {	/* An error occurred. */
-			status = readl(&lp->tx_ring[entry].misc);
-			dev->stats.tx_errors++;
-			if (status & TMD3_RTRY)
-				dev->stats.tx_aborted_errors++;
-			if (status & TMD3_LCAR)
-				dev->stats.tx_carrier_errors++;
-			if (status & TMD3_LCOL)
-				dev->stats.tx_window_errors++;
-			if (status & TMD3_UFLO)
-				dev->stats.tx_fifo_errors++;
-			if (status & (TMD3_BUFF | TMD3_UFLO)) {
-				/* Trigger an immediate send demand. */
-				outw(CSR0, DEPCA_ADDR);
-				outw(INEA | TDMD, DEPCA_DATA);
-			}
-		} else if (status & (T_MORE | T_ONE)) {
-			dev->stats.collisions++;
-		} else {
-			dev->stats.tx_packets++;
-		}
-
-		/* Update all the pointers */
-		lp->tx_old = (lp->tx_old + 1) & lp->txRingMask;
-	}
-
-	return 0;
-}
-
-static int depca_close(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	s16 nicsr;
-	u_long ioaddr = dev->base_addr;
-
-	netif_stop_queue(dev);
-
-	outw(CSR0, DEPCA_ADDR);
-
-	if (depca_debug > 1) {
-		printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
-	}
-
-	/*
-	   ** We stop the DEPCA here -- it occasionally polls
-	   ** memory if we don't.
-	 */
-	outw(STOP, DEPCA_DATA);
-
-	/*
-	   ** Give back the ROM in case the user wants to go to DOS
-	 */
-	if (lp->adapter != DEPCA) {
-		nicsr = inb(DEPCA_NICSR);
-		nicsr &= ~SHE;
-		outb(nicsr, DEPCA_NICSR);
-	}
-
-	/*
-	   ** Free the associated irq
-	 */
-	free_irq(dev->irq, dev);
-	return 0;
-}
-
-static void LoadCSRs(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_long ioaddr = dev->base_addr;
-
-	outw(CSR1, DEPCA_ADDR);	/* initialisation block address LSW */
-	outw((u16) lp->device_ram_start, DEPCA_DATA);
-	outw(CSR2, DEPCA_ADDR);	/* initialisation block address MSW */
-	outw((u16) (lp->device_ram_start >> 16), DEPCA_DATA);
-	outw(CSR3, DEPCA_ADDR);	/* ALE control */
-	outw(ACON, DEPCA_DATA);
-
-	outw(CSR0, DEPCA_ADDR);	/* Point back to CSR0 */
-}
-
-static int InitRestartDepca(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_long ioaddr = dev->base_addr;
-	int i, status = 0;
-
-	/* Copy the shadow init_block to shared memory */
-	memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
-
-	outw(CSR0, DEPCA_ADDR);	/* point back to CSR0 */
-	outw(INIT, DEPCA_DATA);	/* initialize DEPCA */
-
-	/* wait for lance to complete initialisation */
-	for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++);
-
-	if (i != 100) {
-		/* clear IDON by writing a "1", enable interrupts and start lance */
-		outw(IDON | INEA | STRT, DEPCA_DATA);
-		if (depca_debug > 2) {
-			printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
-		}
-	} else {
-		printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
-		status = -1;
-	}
-
-	return status;
-}
-
-/*
-** Set or clear the multicast filter for this adaptor.
-*/
-static void set_multicast_list(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_long ioaddr = dev->base_addr;
-
-	netif_stop_queue(dev);
-	while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
-
-	STOP_DEPCA;	/* Temporarily stop the depca.  */
-	depca_init_ring(dev);	/* Initialize the descriptor rings */
-
-	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous mode */
-		lp->init_block.mode |= PROM;
-	} else {
-		SetMulticastFilter(dev);
-		lp->init_block.mode &= ~PROM;	/* Unset promiscuous mode */
-	}
-
-	LoadCSRs(dev);	/* Reload CSR3 */
-	InitRestartDepca(dev);	/* Resume normal operation. */
-	netif_start_queue(dev);	/* Unlock the TX ring */
-}
-
-/*
-** Calculate the hash code and update the logical address filter
-** from a list of ethernet multicast addresses.
-** Big endian crc one liner is mine, all mine, ha ha ha ha!
-** LANCE calculates its hash codes big endian.
-*/
-static void SetMulticastFilter(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	struct netdev_hw_addr *ha;
-	int i, j, bit, byte;
-	u16 hashcode;
-	u32 crc;
-
-	if (dev->flags & IFF_ALLMULTI) {	/* Set all multicast bits */
-		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-			lp->init_block.mcast_table[i] = (char) 0xff;
-		}
-	} else {
-		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {	/* Clear the multicast table */
-			lp->init_block.mcast_table[i] = 0;
-		}
-		/* Add multicast addresses */
-		netdev_for_each_mc_addr(ha, dev) {
-			crc = ether_crc(ETH_ALEN, ha->addr);
-			hashcode = (crc & 1);	/* hashcode is 6 LSb of CRC ... */
-			for (j = 0; j < 5; j++) {	/* ... in reverse order. */
-				hashcode = (hashcode << 1) | ((crc >>= 1) & 1);
-			}
-
-			byte = hashcode >> 3;	/* bit[3-5] -> byte in filter */
-			bit = 1 << (hashcode & 0x07);	/* bit[0-2] -> bit in byte */
-			lp->init_block.mcast_table[byte] |= bit;
-		}
-	}
-}
-
-static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
-{
-	int status = 0;
-
-	if (!request_region (ioaddr, DEPCA_TOTAL_SIZE, depca_string)) {
-		status = -EBUSY;
-		goto out;
-	}
-
-	if (DevicePresent(ioaddr)) {
-		status = -ENODEV;
-		goto out_release;
-	}
-
-	if (!(*devp = alloc_etherdev (sizeof (struct depca_private)))) {
-		status = -ENOMEM;
-		goto out_release;
-	}
-
-	return 0;
-
- out_release:
-	release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
-	return status;
-}
-
-/*
-** ISA bus I/O device probe
-*/
-
-static void __init depca_platform_probe (void)
-{
-	int i;
-	struct platform_device *pldev;
-
-	for (i = 0; depca_io_ports[i].iobase; i++) {
-		depca_io_ports[i].device = NULL;
-
-		/* if an address has been specified on the command
-		 * line, use it (if valid) */
-		if (io && io != depca_io_ports[i].iobase)
-			continue;
-
-		pldev = platform_device_alloc(depca_string, i);
-		if (!pldev)
-			continue;
-
-		pldev->dev.platform_data = (void *) depca_io_ports[i].iobase;
-		depca_io_ports[i].device = pldev;
-
-		if (platform_device_add(pldev)) {
-			depca_io_ports[i].device = NULL;
-			pldev->dev.platform_data = NULL;
-			platform_device_put(pldev);
-			continue;
-		}
-
-		if (!pldev->dev.driver) {
-		/* The driver was not bound to this device, there was
-		 * no hardware at this address. Unregister it, as the
-		 * release function will take care of freeing the
-		 * allocated structure */
-
-			depca_io_ports[i].device = NULL;
-			pldev->dev.platform_data = NULL;
-			platform_device_unregister (pldev);
-		}
-	}
-}
-
-static enum depca_type __init depca_shmem_probe (ulong *mem_start)
-{
-	u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
-	enum depca_type adapter = unknown;
-	int i;
-
-	for (i = 0; mem_base[i]; i++) {
-		*mem_start = mem ? mem : mem_base[i];
-		adapter = DepcaSignature (adapter_name, *mem_start);
-		if (adapter != unknown)
-			break;
-	}
-
-	return adapter;
-}
-
-static int depca_isa_probe(struct platform_device *device)
-{
-	struct net_device *dev;
-	struct depca_private *lp;
-	u_long ioaddr, mem_start = 0;
-	enum depca_type adapter = unknown;
-	int status = 0;
-
-	ioaddr = (u_long) device->dev.platform_data;
-
-	if ((status = depca_common_init (ioaddr, &dev)))
-		goto out;
-
-	adapter = depca_shmem_probe (&mem_start);
-
-	if (adapter == unknown) {
-		status = -ENODEV;
-		goto out_free;
-	}
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;		/* Use whatever value the user gave
-				 * us, and 0 if he didn't. */
-	lp = netdev_priv(dev);
-	lp->depca_bus = DEPCA_BUS_ISA;
-	lp->adapter = adapter;
-	lp->mem_start = mem_start;
-
-	if ((status = depca_hw_init(dev, &device->dev)))
-		goto out_free;
-
-	return 0;
-
- out_free:
-	free_netdev (dev);
-	release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
-	return status;
-}
-
-/*
-** EISA callbacks from sysfs.
-*/
-
-#ifdef CONFIG_EISA
-static int __init depca_eisa_probe (struct device *device)
-{
-	enum depca_type adapter = unknown;
-	struct eisa_device *edev;
-	struct net_device *dev;
-	struct depca_private *lp;
-	u_long ioaddr, mem_start;
-	int status = 0;
-
-	edev = to_eisa_device (device);
-	ioaddr = edev->base_addr + DEPCA_EISA_IO_PORTS;
-
-	if ((status = depca_common_init (ioaddr, &dev)))
-		goto out;
-
-	/* It would have been nice to get card configuration from the
-	 * card. Unfortunately, this register is write-only (shares
-	 * it's address with the ethernet prom)... As we don't parse
-	 * the EISA configuration structures (yet... :-), just rely on
-	 * the ISA probing to sort it out... */
-
-	adapter = depca_shmem_probe (&mem_start);
-	if (adapter == unknown) {
-		status = -ENODEV;
-		goto out_free;
-	}
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	lp = netdev_priv(dev);
-	lp->depca_bus = DEPCA_BUS_EISA;
-	lp->adapter = edev->id.driver_data;
-	lp->mem_start = mem_start;
-
-	if ((status = depca_hw_init(dev, device)))
-		goto out_free;
-
-	return 0;
-
- out_free:
-	free_netdev (dev);
-	release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
-	return status;
-}
-#endif
-
-static int depca_device_remove(struct device *device)
-{
-	struct net_device *dev;
-	struct depca_private *lp;
-	int bus;
-
-	dev  = dev_get_drvdata(device);
-	lp   = netdev_priv(dev);
-
-	unregister_netdev (dev);
-	iounmap (lp->sh_mem);
-	release_mem_region (lp->mem_start, lp->mem_len);
-	release_region (dev->base_addr, DEPCA_TOTAL_SIZE);
-	bus = lp->depca_bus;
-	free_netdev (dev);
-
-	return 0;
-}
-
-/*
-** Look for a particular board name in the on-board Remote Diagnostics
-** and Boot (readb) ROM. This will also give us a clue to the network RAM
-** base address.
-*/
-static int __init DepcaSignature(char *name, u_long base_addr)
-{
-	u_int i, j, k;
-	void __iomem *ptr;
-	char tmpstr[16];
-	u_long prom_addr = base_addr + 0xc000;
-	u_long mem_addr = base_addr + 0x8000; /* 32KB */
-
-	/* Can't reserve the prom region, it is already marked as
-	 * used, at least on x86. Instead, reserve a memory region a
-	 * board would certainly use. If it works, go ahead. If not,
-	 * run like hell... */
-
-	if (!request_mem_region (mem_addr, 16, depca_string))
-		return unknown;
-
-	/* Copy the first 16 bytes of ROM */
-
-	ptr = ioremap(prom_addr, 16);
-	if (ptr == NULL) {
-		printk(KERN_ERR "depca: I/O remap failed at %lx\n", prom_addr);
-		return unknown;
-	}
-	for (i = 0; i < 16; i++) {
-		tmpstr[i] = readb(ptr + i);
-	}
-	iounmap(ptr);
-
-	release_mem_region (mem_addr, 16);
-
-	/* Check if PROM contains a valid string */
-	for (i = 0; *depca_signature[i] != '\0'; i++) {
-		for (j = 0, k = 0; j < 16 && k < strlen(depca_signature[i]); j++) {
-			if (depca_signature[i][k] == tmpstr[j]) {	/* track signature */
-				k++;
-			} else {	/* lost signature; begin search again */
-				k = 0;
-			}
-		}
-		if (k == strlen(depca_signature[i]))
-			break;
-	}
-
-	/* Check if name string is valid, provided there's no PROM */
-	if (name && *name && (i == unknown)) {
-		for (i = 0; *depca_signature[i] != '\0'; i++) {
-			if (strcmp(name, depca_signature[i]) == 0)
-				break;
-		}
-	}
-
-	return i;
-}
-
-/*
-** Look for a special sequence in the Ethernet station address PROM that
-** is common across all DEPCA products. Note that the original DEPCA needs
-** its ROM address counter to be initialized and enabled. Only enable
-** if the first address octet is a 0x08 - this minimises the chances of
-** messing around with some other hardware, but it assumes that this DEPCA
-** card initialized itself correctly.
-**
-** Search the Ethernet address ROM for the signature. Since the ROM address
-** counter can start at an arbitrary point, the search must include the entire
-** probe sequence length plus the (length_of_the_signature - 1).
-** Stop the search IMMEDIATELY after the signature is found so that the
-** PROM address counter is correctly positioned at the start of the
-** ethernet address for later read out.
-*/
-static int __init DevicePresent(u_long ioaddr)
-{
-	union {
-		struct {
-			u32 a;
-			u32 b;
-		} llsig;
-		char Sig[sizeof(u32) << 1];
-	}
-	dev;
-	short sigLength = 0;
-	s8 data;
-	s16 nicsr;
-	int i, j, status = 0;
-
-	data = inb(DEPCA_PROM);	/* clear counter on DEPCA */
-	data = inb(DEPCA_PROM);	/* read data */
-
-	if (data == 0x08) {	/* Enable counter on DEPCA */
-		nicsr = inb(DEPCA_NICSR);
-		nicsr |= AAC;
-		outb(nicsr, DEPCA_NICSR);
-	}
-
-	dev.llsig.a = ETH_PROM_SIG;
-	dev.llsig.b = ETH_PROM_SIG;
-	sigLength = sizeof(u32) << 1;
-
-	for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
-		data = inb(DEPCA_PROM);
-		if (dev.Sig[j] == data) {	/* track signature */
-			j++;
-		} else {	/* lost signature; begin search again */
-			if (data == dev.Sig[0]) {	/* rare case.... */
-				j = 1;
-			} else {
-				j = 0;
-			}
-		}
-	}
-
-	if (j != sigLength) {
-		status = -ENODEV;	/* search failed */
-	}
-
-	return status;
-}
-
-/*
-** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
-** reason: access the upper half of the PROM with x=0; access the lower half
-** with x=1.
-*/
-static int __init get_hw_addr(struct net_device *dev)
-{
-	u_long ioaddr = dev->base_addr;
-	struct depca_private *lp = netdev_priv(dev);
-	int i, k, tmp, status = 0;
-	u_short j, x, chksum;
-
-	x = (((lp->adapter == de100) || (lp->adapter == de101)) ? 1 : 0);
-
-	for (i = 0, k = 0, j = 0; j < 3; j++) {
-		k <<= 1;
-		if (k > 0xffff)
-			k -= 0xffff;
-
-		k += (u_char) (tmp = inb(DEPCA_PROM + x));
-		dev->dev_addr[i++] = (u_char) tmp;
-		k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
-		dev->dev_addr[i++] = (u_char) tmp;
-
-		if (k > 0xffff)
-			k -= 0xffff;
-	}
-	if (k == 0xffff)
-		k = 0;
-
-	chksum = (u_char) inb(DEPCA_PROM + x);
-	chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
-	if (k != chksum)
-		status = -1;
-
-	return status;
-}
-
-/*
-** Load a packet into the shared memory
-*/
-static int load_packet(struct net_device *dev, struct sk_buff *skb)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	int i, entry, end, len, status = NETDEV_TX_OK;
-
-	entry = lp->tx_new;	/* Ring around buffer number. */
-	end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
-	if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {	/* Enough room? */
-		/*
-		   ** Caution: the write order is important here... don't set up the
-		   ** ownership rights until all the other information is in place.
-		 */
-		if (end < entry) {	/* wrapped buffer */
-			len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
-			memcpy_toio(lp->tx_buff[entry], skb->data, len);
-			memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
-		} else {	/* linear buffer */
-			memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
-		}
-
-		/* set up the buffer descriptors */
-		len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-		for (i = entry; i != end; i = (i+1) & lp->txRingMask) {
-			/* clean out flags */
-			writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
-			writew(0x0000, &lp->tx_ring[i].misc);	/* clears other error flags */
-			writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);	/* packet length in buffer */
-			len -= TX_BUFF_SZ;
-		}
-		/* clean out flags */
-		writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
-		writew(0x0000, &lp->tx_ring[end].misc);	/* clears other error flags */
-		writew(-len, &lp->tx_ring[end].length);	/* packet length in last buff */
-
-		/* start of packet */
-		writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
-		/* end of packet */
-		writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
-
-		for (i = end; i != entry; --i) {
-			/* ownership of packet */
-			writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
-			if (i == 0)
-				i = lp->txRingMask + 1;
-		}
-		writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
-
-		lp->tx_new = (++end) & lp->txRingMask;	/* update current pointers */
-	} else {
-		status = NETDEV_TX_LOCKED;
-	}
-
-	return status;
-}
-
-static void depca_dbg_open(struct net_device *dev)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	u_long ioaddr = dev->base_addr;
-	struct depca_init *p = &lp->init_block;
-	int i;
-
-	if (depca_debug > 1) {
-		/* Do not copy the shadow init block into shared memory */
-		/* Debugging should not affect normal operation! */
-		/* The shadow init block will get copied across during InitRestartDepca */
-		printk("%s: depca open with irq %d\n", dev->name, dev->irq);
-		printk("Descriptor head addresses (CPU):\n");
-		printk("        0x%lx  0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
-		printk("Descriptor addresses (CPU):\nRX: ");
-		for (i = 0; i < lp->rxRingMask; i++) {
-			if (i < 3) {
-				printk("%p ", &lp->rx_ring[i].base);
-			}
-		}
-		printk("...%p\n", &lp->rx_ring[i].base);
-		printk("TX: ");
-		for (i = 0; i < lp->txRingMask; i++) {
-			if (i < 3) {
-				printk("%p ", &lp->tx_ring[i].base);
-			}
-		}
-		printk("...%p\n", &lp->tx_ring[i].base);
-		printk("\nDescriptor buffers (Device):\nRX: ");
-		for (i = 0; i < lp->rxRingMask; i++) {
-			if (i < 3) {
-				printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
-			}
-		}
-		printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
-		printk("TX: ");
-		for (i = 0; i < lp->txRingMask; i++) {
-			if (i < 3) {
-				printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
-			}
-		}
-		printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
-		printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
-		printk("        mode: 0x%4.4x\n", p->mode);
-		printk("        physical address: %pM\n", p->phys_addr);
-		printk("        multicast hash table: ");
-		for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
-			printk("%2.2x:", p->mcast_table[i]);
-		}
-		printk("%2.2x\n", p->mcast_table[i]);
-		printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
-		printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
-		printk("buffers (Phys): 0x%8.8lx\n", lp->mem_start + lp->buffs_offset);
-		printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
-		printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
-		outw(CSR2, DEPCA_ADDR);
-		printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA));
-		outw(CSR1, DEPCA_ADDR);
-		printk("%4.4x\n", inw(DEPCA_DATA));
-		outw(CSR3, DEPCA_ADDR);
-		printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
-	}
-}
-
-/*
-** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases.
-** All multicast IOCTLs will not work here and are for testing purposes only.
-*/
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct depca_private *lp = netdev_priv(dev);
-	struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru;
-	int i, status = 0;
-	u_long ioaddr = dev->base_addr;
-	union {
-		u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
-		u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-		u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
-	} tmp;
-	unsigned long flags;
-	void *buf;
-
-	switch (ioc->cmd) {
-	case DEPCA_GET_HWADDR:	/* Get the hardware address */
-		for (i = 0; i < ETH_ALEN; i++) {
-			tmp.addr[i] = dev->dev_addr[i];
-		}
-		ioc->len = ETH_ALEN;
-		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-			return -EFAULT;
-		break;
-
-	case DEPCA_SET_HWADDR:	/* Set the hardware address */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
-			return -EFAULT;
-		for (i = 0; i < ETH_ALEN; i++) {
-			dev->dev_addr[i] = tmp.addr[i];
-		}
-		netif_stop_queue(dev);
-		while (lp->tx_old != lp->tx_new)
-			cpu_relax();	/* Wait for the ring to empty */
-
-		STOP_DEPCA;	/* Temporarily stop the depca.  */
-		depca_init_ring(dev);	/* Initialize the descriptor rings */
-		LoadCSRs(dev);	/* Reload CSR3 */
-		InitRestartDepca(dev);	/* Resume normal operation. */
-		netif_start_queue(dev);	/* Unlock the TX ring */
-		break;
-
-	case DEPCA_SET_PROM:	/* Set Promiscuous Mode */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		netif_stop_queue(dev);
-		while (lp->tx_old != lp->tx_new)
-			cpu_relax();	/* Wait for the ring to empty */
-
-		STOP_DEPCA;	/* Temporarily stop the depca.  */
-		depca_init_ring(dev);	/* Initialize the descriptor rings */
-		lp->init_block.mode |= PROM;	/* Set promiscuous mode */
-
-		LoadCSRs(dev);	/* Reload CSR3 */
-		InitRestartDepca(dev);	/* Resume normal operation. */
-		netif_start_queue(dev);	/* Unlock the TX ring */
-		break;
-
-	case DEPCA_CLR_PROM:	/* Clear Promiscuous Mode */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		netif_stop_queue(dev);
-		while (lp->tx_old != lp->tx_new)
-			cpu_relax();	/* Wait for the ring to empty */
-
-		STOP_DEPCA;	/* Temporarily stop the depca.  */
-		depca_init_ring(dev);	/* Initialize the descriptor rings */
-		lp->init_block.mode &= ~PROM;	/* Clear promiscuous mode */
-
-		LoadCSRs(dev);	/* Reload CSR3 */
-		InitRestartDepca(dev);	/* Resume normal operation. */
-		netif_start_queue(dev);	/* Unlock the TX ring */
-		break;
-
-	case DEPCA_SAY_BOO:	/* Say "Boo!" to the kernel log file */
-		if(!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		printk("%s: Boo!\n", dev->name);
-		break;
-
-	case DEPCA_GET_MCA:	/* Get the multicast address table */
-		ioc->len = (HASH_TABLE_LEN >> 3);
-		if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
-			return -EFAULT;
-		break;
-
-	case DEPCA_SET_MCA:	/* Set a multicast address */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (ioc->len >= HASH_TABLE_LEN)
-			return -EINVAL;
-		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
-			return -EFAULT;
-		set_multicast_list(dev);
-		break;
-
-	case DEPCA_CLR_MCA:	/* Clear all multicast addresses */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		set_multicast_list(dev);
-		break;
-
-	case DEPCA_MCA_EN:	/* Enable pass all multicast addressing */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		set_multicast_list(dev);
-		break;
-
-	case DEPCA_GET_STATS:	/* Get the driver statistics */
-		ioc->len = sizeof(lp->pktStats);
-		buf = kmalloc(ioc->len, GFP_KERNEL);
-		if(!buf)
-			return -ENOMEM;
-		spin_lock_irqsave(&lp->lock, flags);
-		memcpy(buf, &lp->pktStats, ioc->len);
-		spin_unlock_irqrestore(&lp->lock, flags);
-		if (copy_to_user(ioc->data, buf, ioc->len))
-			status = -EFAULT;
-		kfree(buf);
-		break;
-
-	case DEPCA_CLR_STATS:	/* Zero out the driver statistics */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		spin_lock_irqsave(&lp->lock, flags);
-		memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-		spin_unlock_irqrestore(&lp->lock, flags);
-		break;
-
-	case DEPCA_GET_REG:	/* Get the DEPCA Registers */
-		i = 0;
-		tmp.sval[i++] = inw(DEPCA_NICSR);
-		outw(CSR0, DEPCA_ADDR);	/* status register */
-		tmp.sval[i++] = inw(DEPCA_DATA);
-		memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
-		ioc->len = i + sizeof(struct depca_init);
-		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-			return -EFAULT;
-		break;
-
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return status;
-}
-
-static int __init depca_module_init (void)
-{
-	int err = 0;
-
-#ifdef CONFIG_EISA
-	err = eisa_driver_register(&depca_eisa_driver);
-	if (err)
-		goto err_eisa;
-#endif
-	err = platform_driver_register(&depca_isa_driver);
-	if (err)
-		goto err_eisa;
-
-	depca_platform_probe();
-	return 0;
-
-err_eisa:
-#ifdef CONFIG_EISA
-	eisa_driver_unregister(&depca_eisa_driver);
-#endif
-	return err;
-}
-
-static void __exit depca_module_exit (void)
-{
-	int i;
-#ifdef CONFIG_EISA
-        eisa_driver_unregister (&depca_eisa_driver);
-#endif
-	platform_driver_unregister (&depca_isa_driver);
-
-	for (i = 0; depca_io_ports[i].iobase; i++) {
-		if (depca_io_ports[i].device) {
-			depca_io_ports[i].device->dev.platform_data = NULL;
-			platform_device_unregister (depca_io_ports[i].device);
-			depca_io_ports[i].device = NULL;
-		}
-	}
-}
-
-module_init (depca_module_init);
-module_exit (depca_module_exit);
diff --git a/drivers/net/ethernet/amd/depca.h b/drivers/net/ethernet/amd/depca.h
deleted file mode 100644
index cdcfe42..0000000
--- a/drivers/net/ethernet/amd/depca.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-    Written 1994 by David C. Davies.
-
-    Copyright 1994 David C. Davies. This software may be used and distributed
-    according to the terms of the GNU General Public License, incorporated herein by
-    reference.
-*/
-
-/*
-** I/O addresses. Note that the 2k buffer option is not supported in
-** this driver.
-*/
-#define DEPCA_NICSR ioaddr+0x00   /* Network interface CSR */
-#define DEPCA_RBI   ioaddr+0x02   /* RAM buffer index (2k buffer mode) */
-#define DEPCA_DATA  ioaddr+0x04   /* LANCE registers' data port */
-#define DEPCA_ADDR  ioaddr+0x06   /* LANCE registers' address port */
-#define DEPCA_HBASE ioaddr+0x08   /* EISA high memory base address reg. */
-#define DEPCA_PROM  ioaddr+0x0c   /* Ethernet address ROM data port */
-#define DEPCA_CNFG  ioaddr+0x0c   /* EISA Configuration port */
-#define DEPCA_RBSA  ioaddr+0x0e   /* RAM buffer starting address (2k buff.) */
-
-/*
-** These are LANCE registers addressable through DEPCA_ADDR
-*/
-#define CSR0       0
-#define CSR1       1
-#define CSR2       2
-#define CSR3       3
-
-/*
-** NETWORK INTERFACE CSR (NI_CSR) bit definitions
-*/
-
-#define TO       	0x0100	/* Time Out for remote boot */
-#define SHE      	0x0080  /* SHadow memory Enable */
-#define BS       	0x0040  /* Bank Select */
-#define BUF      	0x0020	/* BUFfer size (1->32k, 0->64k) */
-#define RBE      	0x0010	/* Remote Boot Enable (1->net boot) */
-#define AAC      	0x0008  /* Address ROM Address Counter (1->enable) */
-#define _128KB      	0x0008  /* 128kB Network RAM (1->enable) */
-#define IM       	0x0004	/* Interrupt Mask (1->mask) */
-#define IEN      	0x0002	/* Interrupt tristate ENable (1->enable) */
-#define LED      	0x0001	/* LED control */
-
-/*
-** Control and Status Register 0 (CSR0) bit definitions
-*/
-
-#define ERR     	0x8000 	/* Error summary */
-#define BABL    	0x4000 	/* Babble transmitter timeout error  */
-#define CERR    	0x2000 	/* Collision Error */
-#define MISS    	0x1000 	/* Missed packet */
-#define MERR    	0x0800 	/* Memory Error */
-#define RINT    	0x0400 	/* Receiver Interrupt */
-#define TINT    	0x0200 	/* Transmit Interrupt */
-#define IDON    	0x0100 	/* Initialization Done */
-#define INTR    	0x0080 	/* Interrupt Flag */
-#define INEA    	0x0040 	/* Interrupt Enable */
-#define RXON    	0x0020 	/* Receiver on */
-#define TXON    	0x0010 	/* Transmitter on */
-#define TDMD    	0x0008 	/* Transmit Demand */
-#define STOP    	0x0004 	/* Stop */
-#define STRT    	0x0002 	/* Start */
-#define INIT    	0x0001 	/* Initialize */
-#define INTM            0xff00  /* Interrupt Mask */
-#define INTE            0xfff0  /* Interrupt Enable */
-
-/*
-** CONTROL AND STATUS REGISTER 3 (CSR3)
-*/
-
-#define BSWP    	0x0004	/* Byte SWaP */
-#define ACON    	0x0002	/* ALE control */
-#define BCON    	0x0001	/* Byte CONtrol */
-
-/*
-** Initialization Block Mode Register
-*/
-
-#define PROM       	0x8000 	/* Promiscuous Mode */
-#define EMBA       	0x0080	/* Enable Modified Back-off Algorithm */
-#define INTL       	0x0040 	/* Internal Loopback */
-#define DRTY       	0x0020 	/* Disable Retry */
-#define COLL       	0x0010 	/* Force Collision */
-#define DTCR       	0x0008 	/* Disable Transmit CRC */
-#define LOOP       	0x0004 	/* Loopback */
-#define DTX        	0x0002 	/* Disable the Transmitter */
-#define DRX        	0x0001 	/* Disable the Receiver */
-
-/*
-** Receive Message Descriptor 1 (RMD1) bit definitions.
-*/
-
-#define R_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
-#define R_ERR     	0x4000 	/* Error Summary */
-#define R_FRAM    	0x2000 	/* Framing Error */
-#define R_OFLO    	0x1000 	/* Overflow Error */
-#define R_CRC     	0x0800 	/* CRC Error */
-#define R_BUFF    	0x0400 	/* Buffer Error */
-#define R_STP     	0x0200 	/* Start of Packet */
-#define R_ENP     	0x0100 	/* End of Packet */
-
-/*
-** Transmit Message Descriptor 1 (TMD1) bit definitions.
-*/
-
-#define T_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
-#define T_ERR     	0x4000 	/* Error Summary */
-#define T_ADD_FCS 	0x2000 	/* More the 1 retry needed to Xmit */
-#define T_MORE    	0x1000	/* >1 retry to transmit packet */
-#define T_ONE     	0x0800 	/* 1 try needed to transmit the packet */
-#define T_DEF     	0x0400 	/* Deferred */
-#define T_STP       0x02000000 	/* Start of Packet */
-#define T_ENP       0x01000000	/* End of Packet */
-#define T_FLAGS     0xff000000  /* TX Flags Field */
-
-/*
-** Transmit Message Descriptor 3 (TMD3) bit definitions.
-*/
-
-#define TMD3_BUFF    0x8000	/* BUFFer error */
-#define TMD3_UFLO    0x4000	/* UnderFLOw error */
-#define TMD3_RES     0x2000	/* REServed */
-#define TMD3_LCOL    0x1000	/* Late COLlision */
-#define TMD3_LCAR    0x0800	/* Loss of CARrier */
-#define TMD3_RTRY    0x0400	/* ReTRY error */
-
-/*
-** EISA configuration Register (CNFG) bit definitions
-*/
-
-#define TIMEOUT       	0x0100	/* 0:2.5 mins, 1: 30 secs */
-#define REMOTE      	0x0080  /* Remote Boot Enable -> 1 */
-#define IRQ11       	0x0040  /* Enable -> 1 */
-#define IRQ10    	0x0020	/* Enable -> 1 */
-#define IRQ9    	0x0010	/* Enable -> 1 */
-#define IRQ5      	0x0008  /* Enable -> 1 */
-#define BUFF     	0x0004	/* 0: 64kB or 128kB, 1: 32kB */
-#define PADR16   	0x0002	/* RAM on 64kB boundary */
-#define PADR17    	0x0001	/* RAM on 128kB boundary */
-
-/*
-** Miscellaneous
-*/
-#define HASH_TABLE_LEN   64           /* Bits */
-#define HASH_BITS        0x003f       /* 6 LS bits */
-
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
-
-#define EISA_EN         0x0001        /* Enable EISA bus buffers */
-#define EISA_ID         iobase+0x0080 /* ID long word for EISA card */
-#define EISA_CTRL       iobase+0x0084 /* Control word for EISA card */
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-struct depca_ioctl {
-	unsigned short cmd;                /* Command to run */
-	unsigned short len;                /* Length of the data buffer */
-	unsigned char  __user *data;       /* Pointer to the data buffer */
-};
-
-/*
-** Recognised commands for the driver
-*/
-#define DEPCA_GET_HWADDR	0x01 /* Get the hardware address */
-#define DEPCA_SET_HWADDR	0x02 /* Get the hardware address */
-#define DEPCA_SET_PROM  	0x03 /* Set Promiscuous Mode */
-#define DEPCA_CLR_PROM  	0x04 /* Clear Promiscuous Mode */
-#define DEPCA_SAY_BOO	        0x05 /* Say "Boo!" to the kernel log file */
-#define DEPCA_GET_MCA   	0x06 /* Get a multicast address */
-#define DEPCA_SET_MCA   	0x07 /* Set a multicast address */
-#define DEPCA_CLR_MCA    	0x08 /* Clear a multicast address */
-#define DEPCA_MCA_EN    	0x09 /* Enable a multicast address group */
-#define DEPCA_GET_STATS  	0x0a /* Get the driver statistics */
-#define DEPCA_CLR_STATS 	0x0b /* Zero out the driver statistics */
-#define DEPCA_GET_REG   	0x0c /* Get the Register contents */
-#define DEPCA_SET_REG   	0x0d /* Set the Register contents */
-#define DEPCA_DUMP              0x0f /* Dump the DEPCA Status */
-
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index a227ccd..797f847 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -494,19 +494,15 @@
 	}
 	memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
 
-	new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
-				GFP_ATOMIC);
-	if (!new_dma_addr_list) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t),
+				    GFP_ATOMIC);
+	if (!new_dma_addr_list)
 		goto free_new_tx_ring;
-	}
 
-	new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
-				GFP_ATOMIC);
-	if (!new_skb_list) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *),
+			       GFP_ATOMIC);
+	if (!new_skb_list)
 		goto free_new_lists;
-	}
 
 	kfree(lp->tx_skbuff);
 	kfree(lp->tx_dma_addr);
@@ -564,19 +560,14 @@
 	}
 	memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
 
-	new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
-				GFP_ATOMIC);
-	if (!new_dma_addr_list) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t), GFP_ATOMIC);
+	if (!new_dma_addr_list)
 		goto free_new_rx_ring;
-	}
 
-	new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
-				GFP_ATOMIC);
-	if (!new_skb_list) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *),
+			       GFP_ATOMIC);
+	if (!new_skb_list)
 		goto free_new_lists;
-	}
 
 	/* first copy the current receive buffers */
 	overlap = min(size, lp->rx_ring_size);
@@ -1688,10 +1679,9 @@
 			memcpy(dev->dev_addr, promaddr, 6);
 		}
 	}
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	/* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
-	if (!is_valid_ether_addr(dev->perm_addr))
+	if (!is_valid_ether_addr(dev->dev_addr))
 		memset(dev->dev_addr, 0, ETH_ALEN);
 
 	if (pcnet32_debug & NETIF_MSG_PROBE) {
@@ -1934,31 +1924,23 @@
 
 	lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
 				  GFP_ATOMIC);
-	if (!lp->tx_dma_addr) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	if (!lp->tx_dma_addr)
 		return -ENOMEM;
-	}
 
 	lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
 				  GFP_ATOMIC);
-	if (!lp->rx_dma_addr) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	if (!lp->rx_dma_addr)
 		return -ENOMEM;
-	}
 
 	lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
 				GFP_ATOMIC);
-	if (!lp->tx_skbuff) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	if (!lp->tx_skbuff)
 		return -ENOMEM;
-	}
 
 	lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
 				GFP_ATOMIC);
-	if (!lp->rx_skbuff) {
-		netif_err(lp, drv, dev, "Memory allocation failed\n");
+	if (!lp->rx_skbuff)
 		return -ENOMEM;
-	}
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index c2d696c..6a40290 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -1284,8 +1284,8 @@
 /* Ethtool support... */
 static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, "sunlance");
-	strcpy(info->version, "2.02");
+	strlcpy(info->driver, "sunlance", sizeof(info->driver));
+	strlcpy(info->version, "2.02", sizeof(info->version));
 }
 
 static const struct ethtool_ops sparc_lance_ethtool_ops = {
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 56d3f69..1f07fc6 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -21,7 +21,7 @@
 
 #include "atl1c.h"
 
-#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
+#define ATL1C_DRV_VERSION "1.0.1.1-NAPI"
 char atl1c_driver_name[] = "atl1c";
 char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 
@@ -472,7 +472,6 @@
 
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
-	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr);
 
@@ -983,11 +982,9 @@
 	size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 +
 		rfd_ring->count);
 	tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
-	if (unlikely(!tpd_ring->buffer_info)) {
-		dev_err(&pdev->dev, "kzalloc failed, size = %d\n",
-			size);
+	if (unlikely(!tpd_ring->buffer_info))
 		goto err_nomem;
-	}
+
 	for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
 		tpd_ring[i].buffer_info =
 			(tpd_ring->buffer_info + count);
@@ -1652,6 +1649,7 @@
 	u16 num_alloc = 0;
 	u16 rfd_next_to_use, next_next;
 	struct atl1c_rx_free_desc *rfd_desc;
+	dma_addr_t mapping;
 
 	next_next = rfd_next_to_use = rfd_ring->next_to_use;
 	if (++next_next == rfd_ring->count)
@@ -1678,9 +1676,18 @@
 		ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
 		buffer_info->skb = skb;
 		buffer_info->length = adapter->rx_buffer_len;
-		buffer_info->dma = pci_map_single(pdev, vir_addr,
+		mapping = pci_map_single(pdev, vir_addr,
 						buffer_info->length,
 						PCI_DMA_FROMDEVICE);
+		if (unlikely(pci_dma_mapping_error(pdev, mapping))) {
+			dev_kfree_skb(skb);
+			buffer_info->skb = NULL;
+			buffer_info->length = 0;
+			ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
+			netif_warn(adapter, rx_err, adapter->netdev, "RX pci_map_single failed");
+			break;
+		}
+		buffer_info->dma = mapping;
 		ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
 			ATL1C_PCIMAP_FROMDEVICE);
 		rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -2015,7 +2022,29 @@
 	return 0;
 }
 
-static void atl1c_tx_map(struct atl1c_adapter *adapter,
+static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
+			      struct atl1c_tpd_desc *first_tpd,
+			      enum atl1c_trans_queue type)
+{
+	struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type];
+	struct atl1c_buffer *buffer_info;
+	struct atl1c_tpd_desc *tpd;
+	u16 first_index, index;
+
+	first_index = first_tpd - (struct atl1c_tpd_desc *)tpd_ring->desc;
+	index = first_index;
+	while (index != tpd_ring->next_to_use) {
+		tpd = ATL1C_TPD_DESC(tpd_ring, index);
+		buffer_info = &tpd_ring->buffer_info[index];
+		atl1c_clean_buffer(adpt->pdev, buffer_info, 0);
+		memset(tpd, 0, sizeof(struct atl1c_tpd_desc));
+		if (++index == tpd_ring->count)
+			index = 0;
+	}
+	tpd_ring->next_to_use = first_index;
+}
+
+static int atl1c_tx_map(struct atl1c_adapter *adapter,
 		      struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
 			enum atl1c_trans_queue type)
 {
@@ -2040,6 +2069,9 @@
 		buffer_info->length = map_len;
 		buffer_info->dma = pci_map_single(adapter->pdev,
 					skb->data, hdr_len, PCI_DMA_TODEVICE);
+		if (unlikely(pci_dma_mapping_error(adapter->pdev,
+						   buffer_info->dma)))
+			goto err_dma;
 		ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
 		ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
 			ATL1C_PCIMAP_TODEVICE);
@@ -2062,6 +2094,10 @@
 		buffer_info->dma =
 			pci_map_single(adapter->pdev, skb->data + mapped_len,
 					buffer_info->length, PCI_DMA_TODEVICE);
+		if (unlikely(pci_dma_mapping_error(adapter->pdev,
+						   buffer_info->dma)))
+			goto err_dma;
+
 		ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
 		ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
 			ATL1C_PCIMAP_TODEVICE);
@@ -2083,6 +2119,9 @@
 						    frag, 0,
 						    buffer_info->length,
 						    DMA_TO_DEVICE);
+		if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
+			goto err_dma;
+
 		ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
 		ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE,
 			ATL1C_PCIMAP_TODEVICE);
@@ -2095,6 +2134,13 @@
 	/* The last buffer info contain the skb address,
 	   so it will be free after unmap */
 	buffer_info->skb = skb;
+
+	return 0;
+
+err_dma:
+	buffer_info->dma = 0;
+	buffer_info->length = 0;
+	return -1;
 }
 
 static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
@@ -2157,10 +2203,18 @@
 	if (skb_network_offset(skb) != ETH_HLEN)
 		tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */
 
-	atl1c_tx_map(adapter, skb, tpd, type);
-	atl1c_tx_queue(adapter, skb, tpd, type);
+	if (atl1c_tx_map(adapter, skb, tpd, type) < 0) {
+		netif_info(adapter, tx_done, adapter->netdev,
+			   "tx-skb droppted due to dma error\n");
+		/* roll back tpd/buffer */
+		atl1c_tx_rollback(adapter, tpd, type);
+		spin_unlock_irqrestore(&adapter->tx_lock, flags);
+		dev_kfree_skb(skb);
+	} else {
+		atl1c_tx_queue(adapter, skb, tpd, type);
+		spin_unlock_irqrestore(&adapter->tx_lock, flags);
+	}
 
-	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 	return NETDEV_TX_OK;
 }
 
@@ -2540,10 +2594,9 @@
 	}
 	if (atl1c_read_mac_addr(&adapter->hw)) {
 		/* got a random MAC address, set NET_ADDR_RANDOM to netdev */
-		netdev->addr_assign_type |= NET_ADDR_RANDOM;
+		netdev->addr_assign_type = NET_ADDR_RANDOM;
 	}
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
 	if (netif_msg_probe(adapter))
 		dev_dbg(&pdev->dev, "mac address : %pM\n",
 			adapter->hw.mac_addr);
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index e4466a3..92f4734 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -819,8 +819,6 @@
 	size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count);
 	tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL);
 	if (tx_ring->tx_buffer == NULL) {
-		netdev_err(adapter->netdev, "kzalloc failed, size = D%d\n",
-			   size);
 		err = -ENOMEM;
 		goto failed;
 	}
@@ -2342,7 +2340,6 @@
 	}
 
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
 	netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr);
 
 	INIT_WORK(&adapter->reset_task, atl1e_reset_task);
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 71b3d7d..5b0d993 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -3053,7 +3053,7 @@
 	/* copy the MAC address out of the EEPROM */
 	if (atl1_read_mac_addr(&adapter->hw)) {
 		/* mark random mac */
-		netdev->addr_assign_type |= NET_ADDR_RANDOM;
+		netdev->addr_assign_type = NET_ADDR_RANDOM;
 	}
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index aab83a2..1278b47 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -1433,14 +1433,7 @@
 	/* copy the MAC address out of the EEPROM */
 	atl2_read_mac_addr(&adapter->hw);
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-/* FIXME: do we still need this? */
-#ifdef ETHTOOL_GPERMADDR
-	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
-
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
-#else
 	if (!is_valid_ether_addr(netdev->dev_addr)) {
-#endif
 		err = -EIO;
 		goto err_eeprom;
 	}
diff --git a/drivers/net/ethernet/atheros/atlx/atlx.c b/drivers/net/ethernet/atheros/atlx/atlx.c
index 77ffbc4..f82eb16 100644
--- a/drivers/net/ethernet/atheros/atlx/atlx.c
+++ b/drivers/net/ethernet/atheros/atlx/atlx.c
@@ -84,7 +84,6 @@
 
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
-	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	atlx_set_mac_addr(&adapter->hw);
 	return 0;
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index f552673..3e69b3f 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -121,4 +121,22 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called bnx2x.  This is recommended.
 
+config BNX2X_SRIOV
+	bool "Broadcom 578xx and 57712 SR-IOV support"
+	depends on BNX2X && PCI_IOV
+	default y
+	---help---
+	  This configuration parameter enables Single Root Input Output
+	  Virtualization support in the 578xx and 57712 products. This
+	  allows for virtual function acceleration in virtual environments.
+
+config BGMAC
+	tristate "BCMA bus GBit core support"
+	depends on BCMA_HOST_SOC && HAS_DMA
+	---help---
+	  This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
+	  They can be found on BCM47xx SoCs and provide gigabit ethernet.
+	  In case of using this driver on BCM4706 it's also requires to enable
+	  BCMA_DRIVER_GMAC_CMN to make it work.
+
 endif # NET_VENDOR_BROADCOM
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index b789605..68efa1a 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -9,3 +9,4 @@
 obj-$(CONFIG_BNX2X) += bnx2x/
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_BGMAC) += bgmac.o
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 330b090..9b017d9 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -809,11 +809,10 @@
 			struct sk_buff *copy_skb;
 
 			b44_recycle_rx(bp, cons, bp->rx_prod);
-			copy_skb = netdev_alloc_skb(bp->dev, len + 2);
+			copy_skb = netdev_alloc_skb_ip_align(bp->dev, len);
 			if (copy_skb == NULL)
 				goto drop_it_no_recycle;
 
-			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			/* DMA sync done above, copy just the actual packet */
 			skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET,
@@ -1518,10 +1517,8 @@
 	u8 pwol_mask[B44_PMASK_SIZE];
 
 	pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
-	if (!pwol_pattern) {
-		pr_err("Memory not available for WOL\n");
+	if (!pwol_pattern)
 		return;
-	}
 
 	/* Ipv4 magic packet pattern - pattern 0.*/
 	memset(pwol_mask, 0, B44_PMASK_SIZE);
@@ -2111,8 +2108,6 @@
 		return -EINVAL;
 	}
 
-	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
-
 	bp->imask = IMASK_DEF;
 
 	/* XXX - really required?
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 39387d6..7d81e05 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -799,7 +799,7 @@
 		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
 			 priv->mii_bus->id, priv->phy_id);
 
-		phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 0,
+		phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link,
 				     PHY_INTERFACE_MODE_MII);
 
 		if (IS_ERR(phydev)) {
@@ -886,10 +886,9 @@
 	priv->tx_desc_alloc_size = size;
 	priv->tx_desc_cpu = p;
 
-	priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size,
+	priv->tx_skb = kcalloc(priv->tx_ring_size, sizeof(struct sk_buff *),
 			       GFP_KERNEL);
 	if (!priv->tx_skb) {
-		dev_err(kdev, "cannot allocate rx skb queue\n");
 		ret = -ENOMEM;
 		goto out_free_tx_ring;
 	}
@@ -900,10 +899,9 @@
 	spin_lock_init(&priv->tx_lock);
 
 	/* init & fill rx ring with skbs */
-	priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size,
+	priv->rx_skb = kcalloc(priv->rx_ring_size, sizeof(struct sk_buff *),
 			       GFP_KERNEL);
 	if (!priv->rx_skb) {
-		dev_err(kdev, "cannot allocate rx skb queue\n");
 		ret = -ENOMEM;
 		goto out_free_tx_skb;
 	}
@@ -1227,10 +1225,11 @@
 static void bcm_enet_get_drvinfo(struct net_device *netdev,
 				 struct ethtool_drvinfo *drvinfo)
 {
-	strncpy(drvinfo->driver, bcm_enet_driver_name, 32);
-	strncpy(drvinfo->version, bcm_enet_driver_version, 32);
-	strncpy(drvinfo->fw_version, "N/A", 32);
-	strncpy(drvinfo->bus_info, "bcm63xx", 32);
+	strlcpy(drvinfo->driver, bcm_enet_driver_name, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, bcm_enet_driver_version,
+		sizeof(drvinfo->version));
+	strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+	strlcpy(drvinfo->bus_info, "bcm63xx", sizeof(drvinfo->bus_info));
 	drvinfo->n_stats = BCM_ENET_STATS_LEN;
 }
 
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
new file mode 100644
index 0000000..834d9df
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -0,0 +1,1461 @@
+/*
+ * Driver for (BCM4706)? GBit MAC core on BCMA bus.
+ *
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bgmac.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <bcm47xx_nvram.h>
+
+static const struct bcma_device_id bgmac_bcma_tbl[] = {
+	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+	BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
+
+static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
+			     u32 value, int timeout)
+{
+	u32 val;
+	int i;
+
+	for (i = 0; i < timeout / 10; i++) {
+		val = bcma_read32(core, reg);
+		if ((val & mask) == value)
+			return true;
+		udelay(10);
+	}
+	pr_err("Timeout waiting for reg 0x%X\n", reg);
+	return false;
+}
+
+/**************************************************
+ * DMA
+ **************************************************/
+
+static void bgmac_dma_tx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+	u32 val;
+	int i;
+
+	if (!ring->mmio_base)
+		return;
+
+	/* Suspend DMA TX ring first.
+	 * bgmac_wait_value doesn't support waiting for any of few values, so
+	 * implement whole loop here.
+	 */
+	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL,
+		    BGMAC_DMA_TX_SUSPEND);
+	for (i = 0; i < 10000 / 10; i++) {
+		val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+		val &= BGMAC_DMA_TX_STAT;
+		if (val == BGMAC_DMA_TX_STAT_DISABLED ||
+		    val == BGMAC_DMA_TX_STAT_IDLEWAIT ||
+		    val == BGMAC_DMA_TX_STAT_STOPPED) {
+			i = 0;
+			break;
+		}
+		udelay(10);
+	}
+	if (i)
+		bgmac_err(bgmac, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
+			  ring->mmio_base, val);
+
+	/* Remove SUSPEND bit */
+	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
+	if (!bgmac_wait_value(bgmac->core,
+			      ring->mmio_base + BGMAC_DMA_TX_STATUS,
+			      BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
+			      10000)) {
+		bgmac_warn(bgmac, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
+			   ring->mmio_base);
+		udelay(300);
+		val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+		if ((val & BGMAC_DMA_TX_STAT) != BGMAC_DMA_TX_STAT_DISABLED)
+			bgmac_err(bgmac, "Reset of DMA TX ring 0x%X failed\n",
+				  ring->mmio_base);
+	}
+}
+
+static void bgmac_dma_tx_enable(struct bgmac *bgmac,
+				struct bgmac_dma_ring *ring)
+{
+	u32 ctl;
+
+	ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL);
+	ctl |= BGMAC_DMA_TX_ENABLE;
+	ctl |= BGMAC_DMA_TX_PARITY_DISABLE;
+	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
+}
+
+static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
+				    struct bgmac_dma_ring *ring,
+				    struct sk_buff *skb)
+{
+	struct device *dma_dev = bgmac->core->dma_dev;
+	struct net_device *net_dev = bgmac->net_dev;
+	struct bgmac_dma_desc *dma_desc;
+	struct bgmac_slot_info *slot;
+	u32 ctl0, ctl1;
+	int free_slots;
+
+	if (skb->len > BGMAC_DESC_CTL1_LEN) {
+		bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
+		goto err_stop_drop;
+	}
+
+	if (ring->start <= ring->end)
+		free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
+	else
+		free_slots = ring->start - ring->end;
+	if (free_slots == 1) {
+		bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
+		netif_stop_queue(net_dev);
+		return NETDEV_TX_BUSY;
+	}
+
+	slot = &ring->slots[ring->end];
+	slot->skb = skb;
+	slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len,
+					DMA_TO_DEVICE);
+	if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+		bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
+			  ring->mmio_base);
+		goto err_stop_drop;
+	}
+
+	ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF;
+	if (ring->end == ring->num_slots - 1)
+		ctl0 |= BGMAC_DESC_CTL0_EOT;
+	ctl1 = skb->len & BGMAC_DESC_CTL1_LEN;
+
+	dma_desc = ring->cpu_base;
+	dma_desc += ring->end;
+	dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
+	dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
+	dma_desc->ctl0 = cpu_to_le32(ctl0);
+	dma_desc->ctl1 = cpu_to_le32(ctl1);
+
+	wmb();
+
+	/* Increase ring->end to point empty slot. We tell hardware the first
+	 * slot it should *not* read.
+	 */
+	if (++ring->end >= BGMAC_TX_RING_SLOTS)
+		ring->end = 0;
+	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
+		    ring->end * sizeof(struct bgmac_dma_desc));
+
+	/* Always keep one slot free to allow detecting bugged calls. */
+	if (--free_slots == 1)
+		netif_stop_queue(net_dev);
+
+	return NETDEV_TX_OK;
+
+err_stop_drop:
+	netif_stop_queue(net_dev);
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+/* Free transmitted packets */
+static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+	struct device *dma_dev = bgmac->core->dma_dev;
+	int empty_slot;
+	bool freed = false;
+
+	/* The last slot that hardware didn't consume yet */
+	empty_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+	empty_slot &= BGMAC_DMA_TX_STATDPTR;
+	empty_slot /= sizeof(struct bgmac_dma_desc);
+
+	while (ring->start != empty_slot) {
+		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+
+		if (slot->skb) {
+			/* Unmap no longer used buffer */
+			dma_unmap_single(dma_dev, slot->dma_addr,
+					 slot->skb->len, DMA_TO_DEVICE);
+			slot->dma_addr = 0;
+
+			/* Free memory! :) */
+			dev_kfree_skb(slot->skb);
+			slot->skb = NULL;
+		} else {
+			bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
+				  ring->start, ring->end);
+		}
+
+		if (++ring->start >= BGMAC_TX_RING_SLOTS)
+			ring->start = 0;
+		freed = true;
+	}
+
+	if (freed && netif_queue_stopped(bgmac->net_dev))
+		netif_wake_queue(bgmac->net_dev);
+}
+
+static void bgmac_dma_rx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+	if (!ring->mmio_base)
+		return;
+
+	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, 0);
+	if (!bgmac_wait_value(bgmac->core,
+			      ring->mmio_base + BGMAC_DMA_RX_STATUS,
+			      BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
+			      10000))
+		bgmac_err(bgmac, "Reset of ring 0x%X RX failed\n",
+			  ring->mmio_base);
+}
+
+static void bgmac_dma_rx_enable(struct bgmac *bgmac,
+				struct bgmac_dma_ring *ring)
+{
+	u32 ctl;
+
+	ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL);
+	ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
+	ctl |= BGMAC_DMA_RX_ENABLE;
+	ctl |= BGMAC_DMA_RX_PARITY_DISABLE;
+	ctl |= BGMAC_DMA_RX_OVERFLOW_CONT;
+	ctl |= BGMAC_RX_FRAME_OFFSET << BGMAC_DMA_RX_FRAME_OFFSET_SHIFT;
+	bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, ctl);
+}
+
+static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
+				     struct bgmac_slot_info *slot)
+{
+	struct device *dma_dev = bgmac->core->dma_dev;
+	struct bgmac_rx_header *rx;
+
+	/* Alloc skb */
+	slot->skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
+	if (!slot->skb) {
+		bgmac_err(bgmac, "Allocation of skb failed!\n");
+		return -ENOMEM;
+	}
+
+	/* Poison - if everything goes fine, hardware will overwrite it */
+	rx = (struct bgmac_rx_header *)slot->skb->data;
+	rx->len = cpu_to_le16(0xdead);
+	rx->flags = cpu_to_le16(0xbeef);
+
+	/* Map skb for the DMA */
+	slot->dma_addr = dma_map_single(dma_dev, slot->skb->data,
+					BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+		bgmac_err(bgmac, "DMA mapping error\n");
+		return -ENOMEM;
+	}
+	if (slot->dma_addr & 0xC0000000)
+		bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+	return 0;
+}
+
+static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
+			     int weight)
+{
+	u32 end_slot;
+	int handled = 0;
+
+	end_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS);
+	end_slot &= BGMAC_DMA_RX_STATDPTR;
+	end_slot /= sizeof(struct bgmac_dma_desc);
+
+	ring->end = end_slot;
+
+	while (ring->start != ring->end) {
+		struct device *dma_dev = bgmac->core->dma_dev;
+		struct bgmac_slot_info *slot = &ring->slots[ring->start];
+		struct sk_buff *skb = slot->skb;
+		struct sk_buff *new_skb;
+		struct bgmac_rx_header *rx;
+		u16 len, flags;
+
+		/* Unmap buffer to make it accessible to the CPU */
+		dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
+					BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+		/* Get info from the header */
+		rx = (struct bgmac_rx_header *)skb->data;
+		len = le16_to_cpu(rx->len);
+		flags = le16_to_cpu(rx->flags);
+
+		/* Check for poison and drop or pass the packet */
+		if (len == 0xdead && flags == 0xbeef) {
+			bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+				  ring->start);
+		} else {
+			new_skb = netdev_alloc_skb_ip_align(bgmac->net_dev, len);
+			if (new_skb) {
+				skb_put(new_skb, len);
+				skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET,
+								 new_skb->data,
+								 len);
+				new_skb->protocol =
+					eth_type_trans(new_skb, bgmac->net_dev);
+				netif_receive_skb(new_skb);
+				handled++;
+			} else {
+				bgmac->net_dev->stats.rx_dropped++;
+				bgmac_err(bgmac, "Allocation of skb for copying packet failed!\n");
+			}
+
+			/* Poison the old skb */
+			rx->len = cpu_to_le16(0xdead);
+			rx->flags = cpu_to_le16(0xbeef);
+		}
+
+		/* Make it back accessible to the hardware */
+		dma_sync_single_for_device(dma_dev, slot->dma_addr,
+					   BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+		if (++ring->start >= BGMAC_RX_RING_SLOTS)
+			ring->start = 0;
+
+		if (handled >= weight) /* Should never be greater */
+			break;
+	}
+
+	return handled;
+}
+
+/* Does ring support unaligned addressing? */
+static bool bgmac_dma_unaligned(struct bgmac *bgmac,
+				struct bgmac_dma_ring *ring,
+				enum bgmac_dma_ring_type ring_type)
+{
+	switch (ring_type) {
+	case BGMAC_DMA_RING_TX:
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
+			    0xff0);
+		if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO))
+			return true;
+		break;
+	case BGMAC_DMA_RING_RX:
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
+			    0xff0);
+		if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO))
+			return true;
+		break;
+	}
+	return false;
+}
+
+static void bgmac_dma_ring_free(struct bgmac *bgmac,
+				struct bgmac_dma_ring *ring)
+{
+	struct device *dma_dev = bgmac->core->dma_dev;
+	struct bgmac_slot_info *slot;
+	int size;
+	int i;
+
+	for (i = 0; i < ring->num_slots; i++) {
+		slot = &ring->slots[i];
+		if (slot->skb) {
+			if (slot->dma_addr)
+				dma_unmap_single(dma_dev, slot->dma_addr,
+						 slot->skb->len, DMA_TO_DEVICE);
+			dev_kfree_skb(slot->skb);
+		}
+	}
+
+	if (ring->cpu_base) {
+		/* Free ring of descriptors */
+		size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+		dma_free_coherent(dma_dev, size, ring->cpu_base,
+				  ring->dma_base);
+	}
+}
+
+static void bgmac_dma_free(struct bgmac *bgmac)
+{
+	int i;
+
+	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+		bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
+	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+		bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
+}
+
+static int bgmac_dma_alloc(struct bgmac *bgmac)
+{
+	struct device *dma_dev = bgmac->core->dma_dev;
+	struct bgmac_dma_ring *ring;
+	static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
+					 BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
+	int size; /* ring size: different for Tx and Rx */
+	int err;
+	int i;
+
+	BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
+	BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
+
+	if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
+		bgmac_err(bgmac, "Core does not report 64-bit DMA\n");
+		return -ENOTSUPP;
+	}
+
+	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+		ring = &bgmac->tx_ring[i];
+		ring->num_slots = BGMAC_TX_RING_SLOTS;
+		ring->mmio_base = ring_base[i];
+		if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_TX))
+			bgmac_warn(bgmac, "TX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
+				   ring->mmio_base);
+
+		/* Alloc ring of descriptors */
+		size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+		ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+						     &ring->dma_base,
+						     GFP_KERNEL);
+		if (!ring->cpu_base) {
+			bgmac_err(bgmac, "Allocation of TX ring 0x%X failed\n",
+				  ring->mmio_base);
+			goto err_dma_free;
+		}
+		if (ring->dma_base & 0xC0000000)
+			bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+		/* No need to alloc TX slots yet */
+	}
+
+	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+		ring = &bgmac->rx_ring[i];
+		ring->num_slots = BGMAC_RX_RING_SLOTS;
+		ring->mmio_base = ring_base[i];
+		if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_RX))
+			bgmac_warn(bgmac, "RX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
+				   ring->mmio_base);
+
+		/* Alloc ring of descriptors */
+		size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+		ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+						     &ring->dma_base,
+						     GFP_KERNEL);
+		if (!ring->cpu_base) {
+			bgmac_err(bgmac, "Allocation of RX ring 0x%X failed\n",
+				  ring->mmio_base);
+			err = -ENOMEM;
+			goto err_dma_free;
+		}
+		if (ring->dma_base & 0xC0000000)
+			bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+		/* Alloc RX slots */
+		for (i = 0; i < ring->num_slots; i++) {
+			err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[i]);
+			if (err) {
+				bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n");
+				goto err_dma_free;
+			}
+		}
+	}
+
+	return 0;
+
+err_dma_free:
+	bgmac_dma_free(bgmac);
+	return -ENOMEM;
+}
+
+static void bgmac_dma_init(struct bgmac *bgmac)
+{
+	struct bgmac_dma_ring *ring;
+	struct bgmac_dma_desc *dma_desc;
+	u32 ctl0, ctl1;
+	int i;
+
+	for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+		ring = &bgmac->tx_ring[i];
+
+		/* We don't implement unaligned addressing, so enable first */
+		bgmac_dma_tx_enable(bgmac, ring);
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
+			    lower_32_bits(ring->dma_base));
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGHI,
+			    upper_32_bits(ring->dma_base));
+
+		ring->start = 0;
+		ring->end = 0;	/* Points the slot that should *not* be read */
+	}
+
+	for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+		ring = &bgmac->rx_ring[i];
+
+		/* We don't implement unaligned addressing, so enable first */
+		bgmac_dma_rx_enable(bgmac, ring);
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
+			    lower_32_bits(ring->dma_base));
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI,
+			    upper_32_bits(ring->dma_base));
+
+		for (i = 0, dma_desc = ring->cpu_base; i < ring->num_slots;
+		     i++, dma_desc++) {
+			ctl0 = ctl1 = 0;
+
+			if (i == ring->num_slots - 1)
+				ctl0 |= BGMAC_DESC_CTL0_EOT;
+			ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
+			/* Is there any BGMAC device that requires extension? */
+			/* ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) &
+			 * B43_DMA64_DCTL1_ADDREXT_MASK;
+			 */
+
+			dma_desc->addr_low = cpu_to_le32(lower_32_bits(ring->slots[i].dma_addr));
+			dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[i].dma_addr));
+			dma_desc->ctl0 = cpu_to_le32(ctl0);
+			dma_desc->ctl1 = cpu_to_le32(ctl1);
+		}
+
+		bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
+			    ring->num_slots * sizeof(struct bgmac_dma_desc));
+
+		ring->start = 0;
+		ring->end = 0;
+	}
+}
+
+/**************************************************
+ * PHY ops
+ **************************************************/
+
+static u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
+{
+	struct bcma_device *core;
+	u16 phy_access_addr;
+	u16 phy_ctl_addr;
+	u32 tmp;
+
+	BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
+	BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
+	BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
+	BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
+	BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
+	BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
+	BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
+	BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
+	BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
+	BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
+	BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
+
+	if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+		core = bgmac->core->bus->drv_gmac_cmn.core;
+		phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+		phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+	} else {
+		core = bgmac->core;
+		phy_access_addr = BGMAC_PHY_ACCESS;
+		phy_ctl_addr = BGMAC_PHY_CNTL;
+	}
+
+	tmp = bcma_read32(core, phy_ctl_addr);
+	tmp &= ~BGMAC_PC_EPA_MASK;
+	tmp |= phyaddr;
+	bcma_write32(core, phy_ctl_addr, tmp);
+
+	tmp = BGMAC_PA_START;
+	tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+	tmp |= reg << BGMAC_PA_REG_SHIFT;
+	bcma_write32(core, phy_access_addr, tmp);
+
+	if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+		bgmac_err(bgmac, "Reading PHY %d register 0x%X failed\n",
+			  phyaddr, reg);
+		return 0xffff;
+	}
+
+	return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
+static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
+{
+	struct bcma_device *core;
+	u16 phy_access_addr;
+	u16 phy_ctl_addr;
+	u32 tmp;
+
+	if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+		core = bgmac->core->bus->drv_gmac_cmn.core;
+		phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+		phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+	} else {
+		core = bgmac->core;
+		phy_access_addr = BGMAC_PHY_ACCESS;
+		phy_ctl_addr = BGMAC_PHY_CNTL;
+	}
+
+	tmp = bcma_read32(core, phy_ctl_addr);
+	tmp &= ~BGMAC_PC_EPA_MASK;
+	tmp |= phyaddr;
+	bcma_write32(core, phy_ctl_addr, tmp);
+
+	bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
+	if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
+		bgmac_warn(bgmac, "Error setting MDIO int\n");
+
+	tmp = BGMAC_PA_START;
+	tmp |= BGMAC_PA_WRITE;
+	tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+	tmp |= reg << BGMAC_PA_REG_SHIFT;
+	tmp |= value;
+	bcma_write32(core, phy_access_addr, tmp);
+
+	if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+		bgmac_err(bgmac, "Writing to PHY %d register 0x%X failed\n",
+			  phyaddr, reg);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyforce */
+static void bgmac_phy_force(struct bgmac *bgmac)
+{
+	u16 ctl;
+	u16 mask = ~(BGMAC_PHY_CTL_SPEED | BGMAC_PHY_CTL_SPEED_MSB |
+		     BGMAC_PHY_CTL_ANENAB | BGMAC_PHY_CTL_DUPLEX);
+
+	if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+		return;
+
+	if (bgmac->autoneg)
+		return;
+
+	ctl = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL);
+	ctl &= mask;
+	if (bgmac->full_duplex)
+		ctl |= BGMAC_PHY_CTL_DUPLEX;
+	if (bgmac->speed == BGMAC_SPEED_100)
+		ctl |= BGMAC_PHY_CTL_SPEED_100;
+	else if (bgmac->speed == BGMAC_SPEED_1000)
+		ctl |= BGMAC_PHY_CTL_SPEED_1000;
+	bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, ctl);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyadvertise */
+static void bgmac_phy_advertise(struct bgmac *bgmac)
+{
+	u16 adv;
+
+	if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+		return;
+
+	if (!bgmac->autoneg)
+		return;
+
+	/* Adv selected 10/100 speeds */
+	adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV);
+	adv &= ~(BGMAC_PHY_ADV_10HALF | BGMAC_PHY_ADV_10FULL |
+		 BGMAC_PHY_ADV_100HALF | BGMAC_PHY_ADV_100FULL);
+	if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
+		adv |= BGMAC_PHY_ADV_10HALF;
+	if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
+		adv |= BGMAC_PHY_ADV_100HALF;
+	if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
+		adv |= BGMAC_PHY_ADV_10FULL;
+	if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
+		adv |= BGMAC_PHY_ADV_100FULL;
+	bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV, adv);
+
+	/* Adv selected 1000 speeds */
+	adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2);
+	adv &= ~(BGMAC_PHY_ADV2_1000HALF | BGMAC_PHY_ADV2_1000FULL);
+	if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
+		adv |= BGMAC_PHY_ADV2_1000HALF;
+	if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
+		adv |= BGMAC_PHY_ADV2_1000FULL;
+	bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2, adv);
+
+	/* Restart */
+	bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
+			bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) |
+			BGMAC_PHY_CTL_RESTART);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
+static void bgmac_phy_init(struct bgmac *bgmac)
+{
+	struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+	struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+	u8 i;
+
+	if (ci->id == BCMA_CHIP_ID_BCM5356) {
+		for (i = 0; i < 5; i++) {
+			bgmac_phy_write(bgmac, i, 0x1f, 0x008b);
+			bgmac_phy_write(bgmac, i, 0x15, 0x0100);
+			bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+			bgmac_phy_write(bgmac, i, 0x12, 0x2aaa);
+			bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+		}
+	}
+	if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
+	    (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
+	    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
+		bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
+		bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
+		for (i = 0; i < 5; i++) {
+			bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+			bgmac_phy_write(bgmac, i, 0x16, 0x5284);
+			bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+			bgmac_phy_write(bgmac, i, 0x17, 0x0010);
+			bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+			bgmac_phy_write(bgmac, i, 0x16, 0x5296);
+			bgmac_phy_write(bgmac, i, 0x17, 0x1073);
+			bgmac_phy_write(bgmac, i, 0x17, 0x9073);
+			bgmac_phy_write(bgmac, i, 0x16, 0x52b6);
+			bgmac_phy_write(bgmac, i, 0x17, 0x9273);
+			bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+		}
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
+static void bgmac_phy_reset(struct bgmac *bgmac)
+{
+	if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+		return;
+
+	bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
+			BGMAC_PHY_CTL_RESET);
+	udelay(100);
+	if (bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) &
+	    BGMAC_PHY_CTL_RESET)
+		bgmac_err(bgmac, "PHY reset failed\n");
+	bgmac_phy_init(bgmac);
+}
+
+/**************************************************
+ * Chip ops
+ **************************************************/
+
+/* TODO: can we just drop @force? Can we don't reset MAC at all if there is
+ * nothing to change? Try if after stabilizng driver.
+ */
+static void bgmac_cmdcfg_maskset(struct bgmac *bgmac, u32 mask, u32 set,
+				 bool force)
+{
+	u32 cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+	u32 new_val = (cmdcfg & mask) | set;
+
+	bgmac_set(bgmac, BGMAC_CMDCFG, BGMAC_CMDCFG_SR);
+	udelay(2);
+
+	if (new_val != cmdcfg || force)
+		bgmac_write(bgmac, BGMAC_CMDCFG, new_val);
+
+	bgmac_mask(bgmac, BGMAC_CMDCFG, ~BGMAC_CMDCFG_SR);
+	udelay(2);
+}
+
+static void bgmac_write_mac_address(struct bgmac *bgmac, u8 *addr)
+{
+	u32 tmp;
+
+	tmp = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+	bgmac_write(bgmac, BGMAC_MACADDR_HIGH, tmp);
+	tmp = (addr[4] << 8) | addr[5];
+	bgmac_write(bgmac, BGMAC_MACADDR_LOW, tmp);
+}
+
+static void bgmac_set_rx_mode(struct net_device *net_dev)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+
+	if (net_dev->flags & IFF_PROMISC)
+		bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_PROM, true);
+	else
+		bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_PROM, 0, true);
+}
+
+#if 0 /* We don't use that regs yet */
+static void bgmac_chip_stats_update(struct bgmac *bgmac)
+{
+	int i;
+
+	if (bgmac->core->id.id != BCMA_CORE_4706_MAC_GBIT) {
+		for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+			bgmac->mib_tx_regs[i] =
+				bgmac_read(bgmac,
+					   BGMAC_TX_GOOD_OCTETS + (i * 4));
+		for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
+			bgmac->mib_rx_regs[i] =
+				bgmac_read(bgmac,
+					   BGMAC_RX_GOOD_OCTETS + (i * 4));
+	}
+
+	/* TODO: what else? how to handle BCM4706? Specs are needed */
+}
+#endif
+
+static void bgmac_clear_mib(struct bgmac *bgmac)
+{
+	int i;
+
+	if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT)
+		return;
+
+	bgmac_set(bgmac, BGMAC_DEV_CTL, BGMAC_DC_MROR);
+	for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+		bgmac_read(bgmac, BGMAC_TX_GOOD_OCTETS + (i * 4));
+	for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
+		bgmac_read(bgmac, BGMAC_RX_GOOD_OCTETS + (i * 4));
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */
+static void bgmac_speed(struct bgmac *bgmac, int speed)
+{
+	u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD);
+	u32 set = 0;
+
+	if (speed & BGMAC_SPEED_10)
+		set |= BGMAC_CMDCFG_ES_10;
+	if (speed & BGMAC_SPEED_100)
+		set |= BGMAC_CMDCFG_ES_100;
+	if (speed & BGMAC_SPEED_1000)
+		set |= BGMAC_CMDCFG_ES_1000;
+	if (!bgmac->full_duplex)
+		set |= BGMAC_CMDCFG_HD;
+	bgmac_cmdcfg_maskset(bgmac, mask, set, true);
+}
+
+static void bgmac_miiconfig(struct bgmac *bgmac)
+{
+	u8 imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+			BGMAC_DS_MM_SHIFT;
+	if (imode == 0 || imode == 1) {
+		if (bgmac->autoneg)
+			bgmac_speed(bgmac, BGMAC_SPEED_100);
+		else
+			bgmac_speed(bgmac, bgmac->speed);
+	}
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */
+static void bgmac_chip_reset(struct bgmac *bgmac)
+{
+	struct bcma_device *core = bgmac->core;
+	struct bcma_bus *bus = core->bus;
+	struct bcma_chipinfo *ci = &bus->chipinfo;
+	u32 flags = 0;
+	u32 iost;
+	int i;
+
+	if (bcma_core_is_enabled(core)) {
+		if (!bgmac->stats_grabbed) {
+			/* bgmac_chip_stats_update(bgmac); */
+			bgmac->stats_grabbed = true;
+		}
+
+		for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+			bgmac_dma_tx_reset(bgmac, &bgmac->tx_ring[i]);
+
+		bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false);
+		udelay(1);
+
+		for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+			bgmac_dma_rx_reset(bgmac, &bgmac->rx_ring[i]);
+
+		/* TODO: Clear software multicast filter list */
+	}
+
+	iost = bcma_aread32(core, BCMA_IOST);
+	if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 10) ||
+	    (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
+	    (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9))
+		iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+
+	if (iost & BGMAC_BCMA_IOST_ATTACHED) {
+		flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
+		if (!bgmac->has_robosw)
+			flags |= BGMAC_BCMA_IOCTL_SW_RESET;
+	}
+
+	bcma_core_enable(core, flags);
+
+	if (core->id.rev > 2) {
+		bgmac_set(bgmac, BCMA_CLKCTLST, 1 << 8);
+		bgmac_wait_value(bgmac->core, BCMA_CLKCTLST, 1 << 24, 1 << 24,
+				 1000);
+	}
+
+	if (ci->id == BCMA_CHIP_ID_BCM5357 || ci->id == BCMA_CHIP_ID_BCM4749 ||
+	    ci->id == BCMA_CHIP_ID_BCM53572) {
+		struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+		u8 et_swtype = 0;
+		u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
+			     BGMAC_CHIPCTL_1_IF_TYPE_RMII;
+		char buf[2];
+
+		if (bcm47xx_nvram_getenv("et_swtype", buf, 1) > 0) {
+			if (kstrtou8(buf, 0, &et_swtype))
+				bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
+					  buf);
+			et_swtype &= 0x0f;
+			et_swtype <<= 4;
+			sw_type = et_swtype;
+		} else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 9) {
+			sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
+		} else if ((ci->id != BCMA_CHIP_ID_BCM53572 && ci->pkg == 10) ||
+			   (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9)) {
+			sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
+				  BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
+		}
+		bcma_chipco_chipctl_maskset(cc, 1,
+					    ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
+					      BGMAC_CHIPCTL_1_SW_TYPE_MASK),
+					    sw_type);
+	}
+
+	if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+		bcma_awrite32(core, BCMA_IOCTL,
+			      bcma_aread32(core, BCMA_IOCTL) &
+			      ~BGMAC_BCMA_IOCTL_SW_RESET);
+
+	/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset
+	 * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine
+	 * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to
+	 * be keps until taking MAC out of the reset.
+	 */
+	bgmac_cmdcfg_maskset(bgmac,
+			     ~(BGMAC_CMDCFG_TE |
+			       BGMAC_CMDCFG_RE |
+			       BGMAC_CMDCFG_RPI |
+			       BGMAC_CMDCFG_TAI |
+			       BGMAC_CMDCFG_HD |
+			       BGMAC_CMDCFG_ML |
+			       BGMAC_CMDCFG_CFE |
+			       BGMAC_CMDCFG_RL |
+			       BGMAC_CMDCFG_RED |
+			       BGMAC_CMDCFG_PE |
+			       BGMAC_CMDCFG_TPI |
+			       BGMAC_CMDCFG_PAD_EN |
+			       BGMAC_CMDCFG_PF),
+			     BGMAC_CMDCFG_PROM |
+			     BGMAC_CMDCFG_NLC |
+			     BGMAC_CMDCFG_CFE |
+			     BGMAC_CMDCFG_SR,
+			     false);
+
+	bgmac_clear_mib(bgmac);
+	if (core->id.id == BCMA_CORE_4706_MAC_GBIT)
+		bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0,
+			       BCMA_GMAC_CMN_PC_MTE);
+	else
+		bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE);
+	bgmac_miiconfig(bgmac);
+	bgmac_phy_init(bgmac);
+
+	bgmac->int_status = 0;
+}
+
+static void bgmac_chip_intrs_on(struct bgmac *bgmac)
+{
+	bgmac_write(bgmac, BGMAC_INT_MASK, bgmac->int_mask);
+}
+
+static void bgmac_chip_intrs_off(struct bgmac *bgmac)
+{
+	bgmac_write(bgmac, BGMAC_INT_MASK, 0);
+	bgmac_read(bgmac, BGMAC_INT_MASK);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */
+static void bgmac_enable(struct bgmac *bgmac)
+{
+	struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+	u32 cmdcfg;
+	u32 mode;
+	u32 rxq_ctl;
+	u32 fl_ctl;
+	u16 bp_clk;
+	u8 mdp;
+
+	cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+	bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE),
+			     BGMAC_CMDCFG_SR, true);
+	udelay(2);
+	cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE;
+	bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg);
+
+	mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+		BGMAC_DS_MM_SHIFT;
+	if (ci->id != BCMA_CHIP_ID_BCM47162 || mode != 0)
+		bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+	if (ci->id == BCMA_CHIP_ID_BCM47162 && mode == 2)
+		bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0,
+					    BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
+
+	switch (ci->id) {
+	case BCMA_CHIP_ID_BCM5357:
+	case BCMA_CHIP_ID_BCM4749:
+	case BCMA_CHIP_ID_BCM53572:
+	case BCMA_CHIP_ID_BCM4716:
+	case BCMA_CHIP_ID_BCM47162:
+		fl_ctl = 0x03cb04cb;
+		if (ci->id == BCMA_CHIP_ID_BCM5357 ||
+		    ci->id == BCMA_CHIP_ID_BCM4749 ||
+		    ci->id == BCMA_CHIP_ID_BCM53572)
+			fl_ctl = 0x2300e1;
+		bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl);
+		bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff);
+		break;
+	}
+
+	rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
+	rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
+	bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) / 1000000;
+	mdp = (bp_clk * 128 / 1000) - 3;
+	rxq_ctl |= (mdp << BGMAC_RXQ_CTL_MDP_SHIFT);
+	bgmac_write(bgmac, BGMAC_RXQ_CTL, rxq_ctl);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
+static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
+{
+	struct bgmac_dma_ring *ring;
+	int i;
+
+	/* 1 interrupt per received frame */
+	bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
+
+	/* Enable 802.3x tx flow control (honor received PAUSE frames) */
+	bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_RPI, 0, true);
+
+	bgmac_set_rx_mode(bgmac->net_dev);
+
+	bgmac_write_mac_address(bgmac, bgmac->net_dev->dev_addr);
+
+	if (bgmac->loopback)
+		bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false);
+	else
+		bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_ML, 0, false);
+
+	bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
+
+	if (!bgmac->autoneg) {
+		bgmac_speed(bgmac, bgmac->speed);
+		bgmac_phy_force(bgmac);
+	} else if (bgmac->speed) { /* if there is anything to adv */
+		bgmac_phy_advertise(bgmac);
+	}
+
+	if (full_init) {
+		bgmac_dma_init(bgmac);
+		if (1) /* FIXME: is there any case we don't want IRQs? */
+			bgmac_chip_intrs_on(bgmac);
+	} else {
+		for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+			ring = &bgmac->rx_ring[i];
+			bgmac_dma_rx_enable(bgmac, ring);
+		}
+	}
+
+	bgmac_enable(bgmac);
+}
+
+static irqreturn_t bgmac_interrupt(int irq, void *dev_id)
+{
+	struct bgmac *bgmac = netdev_priv(dev_id);
+
+	u32 int_status = bgmac_read(bgmac, BGMAC_INT_STATUS);
+	int_status &= bgmac->int_mask;
+
+	if (!int_status)
+		return IRQ_NONE;
+
+	/* Ack */
+	bgmac_write(bgmac, BGMAC_INT_STATUS, int_status);
+
+	/* Disable new interrupts until handling existing ones */
+	bgmac_chip_intrs_off(bgmac);
+
+	bgmac->int_status = int_status;
+
+	napi_schedule(&bgmac->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int bgmac_poll(struct napi_struct *napi, int weight)
+{
+	struct bgmac *bgmac = container_of(napi, struct bgmac, napi);
+	struct bgmac_dma_ring *ring;
+	int handled = 0;
+
+	if (bgmac->int_status & BGMAC_IS_TX0) {
+		ring = &bgmac->tx_ring[0];
+		bgmac_dma_tx_free(bgmac, ring);
+		bgmac->int_status &= ~BGMAC_IS_TX0;
+	}
+
+	if (bgmac->int_status & BGMAC_IS_RX) {
+		ring = &bgmac->rx_ring[0];
+		handled += bgmac_dma_rx_read(bgmac, ring, weight);
+		bgmac->int_status &= ~BGMAC_IS_RX;
+	}
+
+	if (bgmac->int_status) {
+		bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status);
+		bgmac->int_status = 0;
+	}
+
+	if (handled < weight)
+		napi_complete(napi);
+
+	bgmac_chip_intrs_on(bgmac);
+
+	return handled;
+}
+
+/**************************************************
+ * net_device_ops
+ **************************************************/
+
+static int bgmac_open(struct net_device *net_dev)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+	int err = 0;
+
+	bgmac_chip_reset(bgmac);
+	/* Specs say about reclaiming rings here, but we do that in DMA init */
+	bgmac_chip_init(bgmac, true);
+
+	err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
+			  KBUILD_MODNAME, net_dev);
+	if (err < 0) {
+		bgmac_err(bgmac, "IRQ request error: %d!\n", err);
+		goto err_out;
+	}
+	napi_enable(&bgmac->napi);
+
+	netif_carrier_on(net_dev);
+
+err_out:
+	return err;
+}
+
+static int bgmac_stop(struct net_device *net_dev)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+
+	netif_carrier_off(net_dev);
+
+	napi_disable(&bgmac->napi);
+	bgmac_chip_intrs_off(bgmac);
+	free_irq(bgmac->core->irq, net_dev);
+
+	bgmac_chip_reset(bgmac);
+
+	return 0;
+}
+
+static netdev_tx_t bgmac_start_xmit(struct sk_buff *skb,
+				    struct net_device *net_dev)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+	struct bgmac_dma_ring *ring;
+
+	/* No QOS support yet */
+	ring = &bgmac->tx_ring[0];
+	return bgmac_dma_tx_add(bgmac, ring, skb);
+}
+
+static int bgmac_set_mac_address(struct net_device *net_dev, void *addr)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+	int ret;
+
+	ret = eth_prepare_mac_addr_change(net_dev, addr);
+	if (ret < 0)
+		return ret;
+	bgmac_write_mac_address(bgmac, (u8 *)addr);
+	eth_commit_mac_addr_change(net_dev, addr);
+	return 0;
+}
+
+static int bgmac_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+	struct mii_ioctl_data *data = if_mii(ifr);
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = bgmac->phyaddr;
+		/* fallthru */
+	case SIOCGMIIREG:
+		if (!netif_running(net_dev))
+			return -EAGAIN;
+		data->val_out = bgmac_phy_read(bgmac, data->phy_id,
+					       data->reg_num & 0x1f);
+		return 0;
+	case SIOCSMIIREG:
+		if (!netif_running(net_dev))
+			return -EAGAIN;
+		bgmac_phy_write(bgmac, data->phy_id, data->reg_num & 0x1f,
+				data->val_in);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static const struct net_device_ops bgmac_netdev_ops = {
+	.ndo_open		= bgmac_open,
+	.ndo_stop		= bgmac_stop,
+	.ndo_start_xmit		= bgmac_start_xmit,
+	.ndo_set_rx_mode	= bgmac_set_rx_mode,
+	.ndo_set_mac_address	= bgmac_set_mac_address,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl           = bgmac_ioctl,
+};
+
+/**************************************************
+ * ethtool_ops
+ **************************************************/
+
+static int bgmac_get_settings(struct net_device *net_dev,
+			      struct ethtool_cmd *cmd)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+
+	cmd->supported = SUPPORTED_10baseT_Half |
+			 SUPPORTED_10baseT_Full |
+			 SUPPORTED_100baseT_Half |
+			 SUPPORTED_100baseT_Full |
+			 SUPPORTED_1000baseT_Half |
+			 SUPPORTED_1000baseT_Full |
+			 SUPPORTED_Autoneg;
+
+	if (bgmac->autoneg) {
+		WARN_ON(cmd->advertising);
+		if (bgmac->full_duplex) {
+			if (bgmac->speed & BGMAC_SPEED_10)
+				cmd->advertising |= ADVERTISED_10baseT_Full;
+			if (bgmac->speed & BGMAC_SPEED_100)
+				cmd->advertising |= ADVERTISED_100baseT_Full;
+			if (bgmac->speed & BGMAC_SPEED_1000)
+				cmd->advertising |= ADVERTISED_1000baseT_Full;
+		} else {
+			if (bgmac->speed & BGMAC_SPEED_10)
+				cmd->advertising |= ADVERTISED_10baseT_Half;
+			if (bgmac->speed & BGMAC_SPEED_100)
+				cmd->advertising |= ADVERTISED_100baseT_Half;
+			if (bgmac->speed & BGMAC_SPEED_1000)
+				cmd->advertising |= ADVERTISED_1000baseT_Half;
+		}
+	} else {
+		switch (bgmac->speed) {
+		case BGMAC_SPEED_10:
+			ethtool_cmd_speed_set(cmd, SPEED_10);
+			break;
+		case BGMAC_SPEED_100:
+			ethtool_cmd_speed_set(cmd, SPEED_100);
+			break;
+		case BGMAC_SPEED_1000:
+			ethtool_cmd_speed_set(cmd, SPEED_1000);
+			break;
+		}
+	}
+
+	cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+
+	cmd->autoneg = bgmac->autoneg;
+
+	return 0;
+}
+
+#if 0
+static int bgmac_set_settings(struct net_device *net_dev,
+			      struct ethtool_cmd *cmd)
+{
+	struct bgmac *bgmac = netdev_priv(net_dev);
+
+	return -1;
+}
+#endif
+
+static void bgmac_get_drvinfo(struct net_device *net_dev,
+			      struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strlcpy(info->bus_info, "BCMA", sizeof(info->bus_info));
+}
+
+static const struct ethtool_ops bgmac_ethtool_ops = {
+	.get_settings		= bgmac_get_settings,
+	.get_drvinfo		= bgmac_get_drvinfo,
+};
+
+/**************************************************
+ * BCMA bus ops
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+static int bgmac_probe(struct bcma_device *core)
+{
+	struct net_device *net_dev;
+	struct bgmac *bgmac;
+	struct ssb_sprom *sprom = &core->bus->sprom;
+	u8 *mac = core->core_unit ? sprom->et1mac : sprom->et0mac;
+	int err;
+
+	/* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */
+	if (core->core_unit > 1) {
+		pr_err("Unsupported core_unit %d\n", core->core_unit);
+		return -ENOTSUPP;
+	}
+
+	if (!is_valid_ether_addr(mac)) {
+		dev_err(&core->dev, "Invalid MAC addr: %pM\n", mac);
+		eth_random_addr(mac);
+		dev_warn(&core->dev, "Using random MAC: %pM\n", mac);
+	}
+
+	/* Allocation and references */
+	net_dev = alloc_etherdev(sizeof(*bgmac));
+	if (!net_dev)
+		return -ENOMEM;
+	net_dev->netdev_ops = &bgmac_netdev_ops;
+	net_dev->irq = core->irq;
+	SET_ETHTOOL_OPS(net_dev, &bgmac_ethtool_ops);
+	bgmac = netdev_priv(net_dev);
+	bgmac->net_dev = net_dev;
+	bgmac->core = core;
+	bcma_set_drvdata(core, bgmac);
+
+	/* Defaults */
+	bgmac->autoneg = true;
+	bgmac->full_duplex = true;
+	bgmac->speed = BGMAC_SPEED_10 | BGMAC_SPEED_100 | BGMAC_SPEED_1000;
+	memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
+
+	/* On BCM4706 we need common core to access PHY */
+	if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+	    !core->bus->drv_gmac_cmn.core) {
+		bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n");
+		err = -ENODEV;
+		goto err_netdev_free;
+	}
+	bgmac->cmn = core->bus->drv_gmac_cmn.core;
+
+	bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr :
+			 sprom->et0phyaddr;
+	bgmac->phyaddr &= BGMAC_PHY_MASK;
+	if (bgmac->phyaddr == BGMAC_PHY_MASK) {
+		bgmac_err(bgmac, "No PHY found\n");
+		err = -ENODEV;
+		goto err_netdev_free;
+	}
+	bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr,
+		   bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
+
+	if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
+		bgmac_err(bgmac, "PCI setup not implemented\n");
+		err = -ENOTSUPP;
+		goto err_netdev_free;
+	}
+
+	bgmac_chip_reset(bgmac);
+
+	err = bgmac_dma_alloc(bgmac);
+	if (err) {
+		bgmac_err(bgmac, "Unable to alloc memory for DMA\n");
+		goto err_netdev_free;
+	}
+
+	bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
+	if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0)
+		bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
+
+	/* TODO: reset the external phy. Specs are needed */
+	bgmac_phy_reset(bgmac);
+
+	bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
+			       BGMAC_BFL_ENETROBO);
+	if (bgmac->has_robosw)
+		bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
+
+	if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+		bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+
+	err = register_netdev(bgmac->net_dev);
+	if (err) {
+		bgmac_err(bgmac, "Cannot register net device\n");
+		err = -ENOTSUPP;
+		goto err_dma_free;
+	}
+
+	netif_carrier_off(net_dev);
+
+	netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+
+	return 0;
+
+err_dma_free:
+	bgmac_dma_free(bgmac);
+
+err_netdev_free:
+	bcma_set_drvdata(core, NULL);
+	free_netdev(net_dev);
+
+	return err;
+}
+
+static void bgmac_remove(struct bcma_device *core)
+{
+	struct bgmac *bgmac = bcma_get_drvdata(core);
+
+	netif_napi_del(&bgmac->napi);
+	unregister_netdev(bgmac->net_dev);
+	bgmac_dma_free(bgmac);
+	bcma_set_drvdata(core, NULL);
+	free_netdev(bgmac->net_dev);
+}
+
+static struct bcma_driver bgmac_bcma_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= bgmac_bcma_tbl,
+	.probe		= bgmac_probe,
+	.remove		= bgmac_remove,
+};
+
+static int __init bgmac_init(void)
+{
+	int err;
+
+	err = bcma_driver_register(&bgmac_bcma_driver);
+	if (err)
+		return err;
+	pr_info("Broadcom 47xx GBit MAC driver loaded\n");
+
+	return 0;
+}
+
+static void __exit bgmac_exit(void)
+{
+	bcma_driver_unregister(&bgmac_bcma_driver);
+}
+
+module_init(bgmac_init)
+module_exit(bgmac_exit)
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
new file mode 100644
index 0000000..4ede614
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -0,0 +1,453 @@
+#ifndef _BGMAC_H
+#define _BGMAC_H
+
+#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
+
+#define bgmac_err(bgmac, fmt, ...) \
+	dev_err(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+#define bgmac_warn(bgmac, fmt, ...) \
+	dev_warn(&(bgmac)->core->dev, fmt,  ##__VA_ARGS__)
+#define bgmac_info(bgmac, fmt, ...) \
+	dev_info(&(bgmac)->core->dev, fmt,  ##__VA_ARGS__)
+#define bgmac_dbg(bgmac, fmt, ...) \
+	dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+
+#include <linux/bcma/bcma.h>
+#include <linux/netdevice.h>
+
+#define BGMAC_DEV_CTL				0x000
+#define  BGMAC_DC_TSM				0x00000002
+#define  BGMAC_DC_CFCO				0x00000004
+#define  BGMAC_DC_RLSS				0x00000008
+#define  BGMAC_DC_MROR				0x00000010
+#define  BGMAC_DC_FCM_MASK			0x00000060
+#define  BGMAC_DC_FCM_SHIFT			5
+#define  BGMAC_DC_NAE				0x00000080
+#define  BGMAC_DC_TF				0x00000100
+#define  BGMAC_DC_RDS_MASK			0x00030000
+#define  BGMAC_DC_RDS_SHIFT			16
+#define  BGMAC_DC_TDS_MASK			0x000c0000
+#define  BGMAC_DC_TDS_SHIFT			18
+#define BGMAC_DEV_STATUS			0x004		/* Configuration of the interface */
+#define  BGMAC_DS_RBF				0x00000001
+#define  BGMAC_DS_RDF				0x00000002
+#define  BGMAC_DS_RIF				0x00000004
+#define  BGMAC_DS_TBF				0x00000008
+#define  BGMAC_DS_TDF				0x00000010
+#define  BGMAC_DS_TIF				0x00000020
+#define  BGMAC_DS_PO				0x00000040
+#define  BGMAC_DS_MM_MASK			0x00000300	/* Mode of the interface */
+#define  BGMAC_DS_MM_SHIFT			8
+#define BGMAC_BIST_STATUS			0x00c
+#define BGMAC_INT_STATUS			0x020		/* Interrupt status */
+#define  BGMAC_IS_MRO				0x00000001
+#define  BGMAC_IS_MTO				0x00000002
+#define  BGMAC_IS_TFD				0x00000004
+#define  BGMAC_IS_LS				0x00000008
+#define  BGMAC_IS_MDIO				0x00000010
+#define  BGMAC_IS_MR				0x00000020
+#define  BGMAC_IS_MT				0x00000040
+#define  BGMAC_IS_TO				0x00000080
+#define  BGMAC_IS_DESC_ERR			0x00000400	/* Descriptor error */
+#define  BGMAC_IS_DATA_ERR			0x00000800	/* Data error */
+#define  BGMAC_IS_DESC_PROT_ERR			0x00001000	/* Descriptor protocol error */
+#define  BGMAC_IS_RX_DESC_UNDERF		0x00002000	/* Receive descriptor underflow */
+#define  BGMAC_IS_RX_F_OVERF			0x00004000	/* Receive FIFO overflow */
+#define  BGMAC_IS_TX_F_UNDERF			0x00008000	/* Transmit FIFO underflow */
+#define  BGMAC_IS_RX				0x00010000	/* Interrupt for RX queue 0 */
+#define  BGMAC_IS_TX0				0x01000000	/* Interrupt for TX queue 0 */
+#define  BGMAC_IS_TX1				0x02000000	/* Interrupt for TX queue 1 */
+#define  BGMAC_IS_TX2				0x04000000	/* Interrupt for TX queue 2 */
+#define  BGMAC_IS_TX3				0x08000000	/* Interrupt for TX queue 3 */
+#define  BGMAC_IS_TX_MASK			0x0f000000
+#define  BGMAC_IS_INTMASK			0x0f01fcff
+#define  BGMAC_IS_ERRMASK			0x0000fc00
+#define BGMAC_INT_MASK				0x024		/* Interrupt mask */
+#define BGMAC_GP_TIMER				0x028
+#define BGMAC_INT_RECV_LAZY			0x100
+#define  BGMAC_IRL_TO_MASK			0x00ffffff
+#define  BGMAC_IRL_FC_MASK			0xff000000
+#define  BGMAC_IRL_FC_SHIFT			24		/* Shift the number of interrupts triggered per received frame */
+#define BGMAC_FLOW_CTL_THRESH			0x104		/* Flow control thresholds */
+#define BGMAC_WRRTHRESH				0x108
+#define BGMAC_GMAC_IDLE_CNT_THRESH		0x10c
+#define BGMAC_PHY_ACCESS			0x180		/* PHY access address */
+#define  BGMAC_PA_DATA_MASK			0x0000ffff
+#define  BGMAC_PA_ADDR_MASK			0x001f0000
+#define  BGMAC_PA_ADDR_SHIFT			16
+#define  BGMAC_PA_REG_MASK			0x1f000000
+#define  BGMAC_PA_REG_SHIFT			24
+#define  BGMAC_PA_WRITE				0x20000000
+#define  BGMAC_PA_START				0x40000000
+#define BGMAC_PHY_CNTL				0x188		/* PHY control address */
+#define  BGMAC_PC_EPA_MASK			0x0000001f
+#define  BGMAC_PC_MCT_MASK			0x007f0000
+#define  BGMAC_PC_MCT_SHIFT			16
+#define  BGMAC_PC_MTE				0x00800000
+#define BGMAC_TXQ_CTL				0x18c
+#define  BGMAC_TXQ_CTL_DBT_MASK			0x00000fff
+#define  BGMAC_TXQ_CTL_DBT_SHIFT		0
+#define BGMAC_RXQ_CTL				0x190
+#define  BGMAC_RXQ_CTL_DBT_MASK			0x00000fff
+#define  BGMAC_RXQ_CTL_DBT_SHIFT		0
+#define  BGMAC_RXQ_CTL_PTE			0x00001000
+#define  BGMAC_RXQ_CTL_MDP_MASK			0x3f000000
+#define  BGMAC_RXQ_CTL_MDP_SHIFT		24
+#define BGMAC_GPIO_SELECT			0x194
+#define BGMAC_GPIO_OUTPUT_EN			0x198
+/* For 0x1e0 see BCMA_CLKCTLST */
+#define BGMAC_HW_WAR				0x1e4
+#define BGMAC_PWR_CTL				0x1e8
+#define BGMAC_DMA_BASE0				0x200		/* Tx and Rx controller */
+#define BGMAC_DMA_BASE1				0x240		/* Tx controller only */
+#define BGMAC_DMA_BASE2				0x280		/* Tx controller only */
+#define BGMAC_DMA_BASE3				0x2C0		/* Tx controller only */
+#define BGMAC_TX_GOOD_OCTETS			0x300
+#define BGMAC_TX_GOOD_OCTETS_HIGH		0x304
+#define BGMAC_TX_GOOD_PKTS			0x308
+#define BGMAC_TX_OCTETS				0x30c
+#define BGMAC_TX_OCTETS_HIGH			0x310
+#define BGMAC_TX_PKTS				0x314
+#define BGMAC_TX_BROADCAST_PKTS			0x318
+#define BGMAC_TX_MULTICAST_PKTS			0x31c
+#define BGMAC_TX_LEN_64				0x320
+#define BGMAC_TX_LEN_65_TO_127			0x324
+#define BGMAC_TX_LEN_128_TO_255			0x328
+#define BGMAC_TX_LEN_256_TO_511			0x32c
+#define BGMAC_TX_LEN_512_TO_1023		0x330
+#define BGMAC_TX_LEN_1024_TO_1522		0x334
+#define BGMAC_TX_LEN_1523_TO_2047		0x338
+#define BGMAC_TX_LEN_2048_TO_4095		0x33c
+#define BGMAC_TX_LEN_4095_TO_8191		0x340
+#define BGMAC_TX_LEN_8192_TO_MAX		0x344
+#define BGMAC_TX_JABBER_PKTS			0x348		/* Error */
+#define BGMAC_TX_OVERSIZE_PKTS			0x34c		/* Error */
+#define BGMAC_TX_FRAGMENT_PKTS			0x350
+#define BGMAC_TX_UNDERRUNS			0x354		/* Error */
+#define BGMAC_TX_TOTAL_COLS			0x358
+#define BGMAC_TX_SINGLE_COLS			0x35c
+#define BGMAC_TX_MULTIPLE_COLS			0x360
+#define BGMAC_TX_EXCESSIVE_COLS			0x364		/* Error */
+#define BGMAC_TX_LATE_COLS			0x368		/* Error */
+#define BGMAC_TX_DEFERED			0x36c
+#define BGMAC_TX_CARRIER_LOST			0x370
+#define BGMAC_TX_PAUSE_PKTS			0x374
+#define BGMAC_TX_UNI_PKTS			0x378
+#define BGMAC_TX_Q0_PKTS			0x37c
+#define BGMAC_TX_Q0_OCTETS			0x380
+#define BGMAC_TX_Q0_OCTETS_HIGH			0x384
+#define BGMAC_TX_Q1_PKTS			0x388
+#define BGMAC_TX_Q1_OCTETS			0x38c
+#define BGMAC_TX_Q1_OCTETS_HIGH			0x390
+#define BGMAC_TX_Q2_PKTS			0x394
+#define BGMAC_TX_Q2_OCTETS			0x398
+#define BGMAC_TX_Q2_OCTETS_HIGH			0x39c
+#define BGMAC_TX_Q3_PKTS			0x3a0
+#define BGMAC_TX_Q3_OCTETS			0x3a4
+#define BGMAC_TX_Q3_OCTETS_HIGH			0x3a8
+#define BGMAC_RX_GOOD_OCTETS			0x3b0
+#define BGMAC_RX_GOOD_OCTETS_HIGH		0x3b4
+#define BGMAC_RX_GOOD_PKTS			0x3b8
+#define BGMAC_RX_OCTETS				0x3bc
+#define BGMAC_RX_OCTETS_HIGH			0x3c0
+#define BGMAC_RX_PKTS				0x3c4
+#define BGMAC_RX_BROADCAST_PKTS			0x3c8
+#define BGMAC_RX_MULTICAST_PKTS			0x3cc
+#define BGMAC_RX_LEN_64				0x3d0
+#define BGMAC_RX_LEN_65_TO_127			0x3d4
+#define BGMAC_RX_LEN_128_TO_255			0x3d8
+#define BGMAC_RX_LEN_256_TO_511			0x3dc
+#define BGMAC_RX_LEN_512_TO_1023		0x3e0
+#define BGMAC_RX_LEN_1024_TO_1522		0x3e4
+#define BGMAC_RX_LEN_1523_TO_2047		0x3e8
+#define BGMAC_RX_LEN_2048_TO_4095		0x3ec
+#define BGMAC_RX_LEN_4095_TO_8191		0x3f0
+#define BGMAC_RX_LEN_8192_TO_MAX		0x3f4
+#define BGMAC_RX_JABBER_PKTS			0x3f8		/* Error */
+#define BGMAC_RX_OVERSIZE_PKTS			0x3fc		/* Error */
+#define BGMAC_RX_FRAGMENT_PKTS			0x400
+#define BGMAC_RX_MISSED_PKTS			0x404		/* Error */
+#define BGMAC_RX_CRC_ALIGN_ERRS			0x408		/* Error */
+#define BGMAC_RX_UNDERSIZE			0x40c		/* Error */
+#define BGMAC_RX_CRC_ERRS			0x410		/* Error */
+#define BGMAC_RX_ALIGN_ERRS			0x414		/* Error */
+#define BGMAC_RX_SYMBOL_ERRS			0x418		/* Error */
+#define BGMAC_RX_PAUSE_PKTS			0x41c
+#define BGMAC_RX_NONPAUSE_PKTS			0x420
+#define BGMAC_RX_SACHANGES			0x424
+#define BGMAC_RX_UNI_PKTS			0x428
+#define BGMAC_UNIMAC_VERSION			0x800
+#define BGMAC_HDBKP_CTL				0x804
+#define BGMAC_CMDCFG				0x808		/* Configuration */
+#define  BGMAC_CMDCFG_TE			0x00000001	/* Set to activate TX */
+#define  BGMAC_CMDCFG_RE			0x00000002	/* Set to activate RX */
+#define  BGMAC_CMDCFG_ES_MASK			0x0000000c	/* Ethernet speed see gmac_speed */
+#define   BGMAC_CMDCFG_ES_10			0x00000000
+#define   BGMAC_CMDCFG_ES_100			0x00000004
+#define   BGMAC_CMDCFG_ES_1000			0x00000008
+#define  BGMAC_CMDCFG_PROM			0x00000010	/* Set to activate promiscuous mode */
+#define  BGMAC_CMDCFG_PAD_EN			0x00000020
+#define  BGMAC_CMDCFG_CF			0x00000040
+#define  BGMAC_CMDCFG_PF			0x00000080
+#define  BGMAC_CMDCFG_RPI			0x00000100	/* Unset to enable 802.3x tx flow control */
+#define  BGMAC_CMDCFG_TAI			0x00000200
+#define  BGMAC_CMDCFG_HD			0x00000400	/* Set if in half duplex mode */
+#define  BGMAC_CMDCFG_HD_SHIFT			10
+#define  BGMAC_CMDCFG_SR			0x00000800	/* Set to reset mode */
+#define  BGMAC_CMDCFG_ML			0x00008000	/* Set to activate mac loopback mode */
+#define  BGMAC_CMDCFG_AE			0x00400000
+#define  BGMAC_CMDCFG_CFE			0x00800000
+#define  BGMAC_CMDCFG_NLC			0x01000000
+#define  BGMAC_CMDCFG_RL			0x02000000
+#define  BGMAC_CMDCFG_RED			0x04000000
+#define  BGMAC_CMDCFG_PE			0x08000000
+#define  BGMAC_CMDCFG_TPI			0x10000000
+#define  BGMAC_CMDCFG_AT			0x20000000
+#define BGMAC_MACADDR_HIGH			0x80c		/* High 4 octets of own mac address */
+#define BGMAC_MACADDR_LOW			0x810		/* Low 2 octets of own mac address */
+#define BGMAC_RXMAX_LENGTH			0x814		/* Max receive frame length with vlan tag */
+#define BGMAC_PAUSEQUANTA			0x818
+#define BGMAC_MAC_MODE				0x844
+#define BGMAC_OUTERTAG				0x848
+#define BGMAC_INNERTAG				0x84c
+#define BGMAC_TXIPG				0x85c
+#define BGMAC_PAUSE_CTL				0xb30
+#define BGMAC_TX_FLUSH				0xb34
+#define BGMAC_RX_STATUS				0xb38
+#define BGMAC_TX_STATUS				0xb3c
+
+#define BGMAC_PHY_CTL				0x00
+#define  BGMAC_PHY_CTL_SPEED_MSB		0x0040
+#define  BGMAC_PHY_CTL_DUPLEX			0x0100		/* duplex mode */
+#define  BGMAC_PHY_CTL_RESTART			0x0200		/* restart autonegotiation */
+#define  BGMAC_PHY_CTL_ANENAB			0x1000		/* enable autonegotiation */
+#define  BGMAC_PHY_CTL_SPEED			0x2000
+#define  BGMAC_PHY_CTL_LOOP			0x4000		/* loopback */
+#define  BGMAC_PHY_CTL_RESET			0x8000		/* reset */
+/* Helpers */
+#define  BGMAC_PHY_CTL_SPEED_10			0
+#define  BGMAC_PHY_CTL_SPEED_100		BGMAC_PHY_CTL_SPEED
+#define  BGMAC_PHY_CTL_SPEED_1000		BGMAC_PHY_CTL_SPEED_MSB
+#define BGMAC_PHY_ADV				0x04
+#define  BGMAC_PHY_ADV_10HALF			0x0020		/* advertise 10MBits/s half duplex */
+#define  BGMAC_PHY_ADV_10FULL			0x0040		/* advertise 10MBits/s full duplex */
+#define  BGMAC_PHY_ADV_100HALF			0x0080		/* advertise 100MBits/s half duplex */
+#define  BGMAC_PHY_ADV_100FULL			0x0100		/* advertise 100MBits/s full duplex */
+#define BGMAC_PHY_ADV2				0x09
+#define  BGMAC_PHY_ADV2_1000HALF		0x0100		/* advertise 1000MBits/s half duplex */
+#define  BGMAC_PHY_ADV2_1000FULL		0x0200		/* advertise 1000MBits/s full duplex */
+
+/* BCMA GMAC core specific IO Control (BCMA_IOCTL) flags */
+#define BGMAC_BCMA_IOCTL_SW_CLKEN		0x00000004	/* PHY Clock Enable */
+#define BGMAC_BCMA_IOCTL_SW_RESET		0x00000008	/* PHY Reset */
+
+/* BCMA GMAC core specific IO status (BCMA_IOST) flags */
+#define BGMAC_BCMA_IOST_ATTACHED		0x00000800
+
+#define BGMAC_NUM_MIB_TX_REGS	\
+		(((BGMAC_TX_Q3_OCTETS_HIGH - BGMAC_TX_GOOD_OCTETS) / 4) + 1)
+#define BGMAC_NUM_MIB_RX_REGS	\
+		(((BGMAC_RX_UNI_PKTS - BGMAC_RX_GOOD_OCTETS) / 4) + 1)
+
+#define BGMAC_DMA_TX_CTL			0x00
+#define  BGMAC_DMA_TX_ENABLE			0x00000001
+#define  BGMAC_DMA_TX_SUSPEND			0x00000002
+#define  BGMAC_DMA_TX_LOOPBACK			0x00000004
+#define  BGMAC_DMA_TX_FLUSH			0x00000010
+#define  BGMAC_DMA_TX_PARITY_DISABLE		0x00000800
+#define  BGMAC_DMA_TX_ADDREXT_MASK		0x00030000
+#define  BGMAC_DMA_TX_ADDREXT_SHIFT		16
+#define BGMAC_DMA_TX_INDEX			0x04
+#define BGMAC_DMA_TX_RINGLO			0x08
+#define BGMAC_DMA_TX_RINGHI			0x0C
+#define BGMAC_DMA_TX_STATUS			0x10
+#define  BGMAC_DMA_TX_STATDPTR			0x00001FFF
+#define  BGMAC_DMA_TX_STAT			0xF0000000
+#define   BGMAC_DMA_TX_STAT_DISABLED		0x00000000
+#define   BGMAC_DMA_TX_STAT_ACTIVE		0x10000000
+#define   BGMAC_DMA_TX_STAT_IDLEWAIT		0x20000000
+#define   BGMAC_DMA_TX_STAT_STOPPED		0x30000000
+#define   BGMAC_DMA_TX_STAT_SUSP		0x40000000
+#define BGMAC_DMA_TX_ERROR			0x14
+#define  BGMAC_DMA_TX_ERRDPTR			0x0001FFFF
+#define  BGMAC_DMA_TX_ERR			0xF0000000
+#define   BGMAC_DMA_TX_ERR_NOERR		0x00000000
+#define   BGMAC_DMA_TX_ERR_PROT			0x10000000
+#define   BGMAC_DMA_TX_ERR_UNDERRUN		0x20000000
+#define   BGMAC_DMA_TX_ERR_TRANSFER		0x30000000
+#define   BGMAC_DMA_TX_ERR_DESCREAD		0x40000000
+#define   BGMAC_DMA_TX_ERR_CORE			0x50000000
+#define BGMAC_DMA_RX_CTL			0x20
+#define  BGMAC_DMA_RX_ENABLE			0x00000001
+#define  BGMAC_DMA_RX_FRAME_OFFSET_MASK		0x000000FE
+#define  BGMAC_DMA_RX_FRAME_OFFSET_SHIFT	1
+#define  BGMAC_DMA_RX_DIRECT_FIFO		0x00000100
+#define  BGMAC_DMA_RX_OVERFLOW_CONT		0x00000400
+#define  BGMAC_DMA_RX_PARITY_DISABLE		0x00000800
+#define  BGMAC_DMA_RX_ADDREXT_MASK		0x00030000
+#define  BGMAC_DMA_RX_ADDREXT_SHIFT		16
+#define BGMAC_DMA_RX_INDEX			0x24
+#define BGMAC_DMA_RX_RINGLO			0x28
+#define BGMAC_DMA_RX_RINGHI			0x2C
+#define BGMAC_DMA_RX_STATUS			0x30
+#define  BGMAC_DMA_RX_STATDPTR			0x00001FFF
+#define  BGMAC_DMA_RX_STAT			0xF0000000
+#define   BGMAC_DMA_RX_STAT_DISABLED		0x00000000
+#define   BGMAC_DMA_RX_STAT_ACTIVE		0x10000000
+#define   BGMAC_DMA_RX_STAT_IDLEWAIT		0x20000000
+#define   BGMAC_DMA_RX_STAT_STOPPED		0x30000000
+#define   BGMAC_DMA_RX_STAT_SUSP		0x40000000
+#define BGMAC_DMA_RX_ERROR			0x34
+#define  BGMAC_DMA_RX_ERRDPTR			0x0001FFFF
+#define  BGMAC_DMA_RX_ERR			0xF0000000
+#define   BGMAC_DMA_RX_ERR_NOERR		0x00000000
+#define   BGMAC_DMA_RX_ERR_PROT			0x10000000
+#define   BGMAC_DMA_RX_ERR_UNDERRUN		0x20000000
+#define   BGMAC_DMA_RX_ERR_TRANSFER		0x30000000
+#define   BGMAC_DMA_RX_ERR_DESCREAD		0x40000000
+#define   BGMAC_DMA_RX_ERR_CORE			0x50000000
+
+#define BGMAC_DESC_CTL0_EOT			0x10000000	/* End of ring */
+#define BGMAC_DESC_CTL0_IOC			0x20000000	/* IRQ on complete */
+#define BGMAC_DESC_CTL0_SOF			0x40000000	/* Start of frame */
+#define BGMAC_DESC_CTL0_EOF			0x80000000	/* End of frame */
+#define BGMAC_DESC_CTL1_LEN			0x00001FFF
+
+#define BGMAC_PHY_NOREGS			0x1E
+#define BGMAC_PHY_MASK				0x1F
+
+#define BGMAC_MAX_TX_RINGS			4
+#define BGMAC_MAX_RX_RINGS			1
+
+#define BGMAC_TX_RING_SLOTS			128
+#define BGMAC_RX_RING_SLOTS			512 - 1		/* Why -1? Well, Broadcom does that... */
+
+#define BGMAC_RX_HEADER_LEN			28		/* Last 24 bytes are unused. Well... */
+#define BGMAC_RX_FRAME_OFFSET			30		/* There are 2 unused bytes between header and real data */
+#define BGMAC_RX_MAX_FRAME_SIZE			1536		/* Copied from b44/tg3 */
+#define BGMAC_RX_BUF_SIZE			(BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
+
+#define BGMAC_BFL_ENETROBO			0x0010		/* has ephy roboswitch spi */
+#define BGMAC_BFL_ENETADM			0x0080		/* has ADMtek switch */
+#define BGMAC_BFL_ENETVLAN			0x0100		/* can do vlan */
+
+#define BGMAC_CHIPCTL_1_IF_TYPE_MASK		0x00000030
+#define BGMAC_CHIPCTL_1_IF_TYPE_RMII		0x00000000
+#define BGMAC_CHIPCTL_1_IF_TYPE_MI		0x00000010
+#define BGMAC_CHIPCTL_1_IF_TYPE_RGMII		0x00000020
+#define BGMAC_CHIPCTL_1_SW_TYPE_MASK		0x000000C0
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHY		0x00000000
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHYMII		0x00000040
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII	0x00000080
+#define BGMAC_CHIPCTL_1_SW_TYPE_RGMII		0x000000C0
+#define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS		0x00010000
+
+#define BGMAC_SPEED_10				0x0001
+#define BGMAC_SPEED_100				0x0002
+#define BGMAC_SPEED_1000			0x0004
+
+#define BGMAC_WEIGHT	64
+
+#define ETHER_MAX_LEN   1518
+
+struct bgmac_slot_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+};
+
+struct bgmac_dma_desc {
+	__le32 ctl0;
+	__le32 ctl1;
+	__le32 addr_low;
+	__le32 addr_high;
+} __packed;
+
+enum bgmac_dma_ring_type {
+	BGMAC_DMA_RING_TX,
+	BGMAC_DMA_RING_RX,
+};
+
+/**
+ * bgmac_dma_ring - contains info about DMA ring (either TX or RX one)
+ * @start: index of the first slot containing data
+ * @end: index of a slot that can *not* be read (yet)
+ *
+ * Be really aware of the specific @end meaning. It's an index of a slot *after*
+ * the one containing data that can be read. If @start equals @end the ring is
+ * empty.
+ */
+struct bgmac_dma_ring {
+	u16 num_slots;
+	u16 start;
+	u16 end;
+
+	u16 mmio_base;
+	struct bgmac_dma_desc *cpu_base;
+	dma_addr_t dma_base;
+
+	struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
+};
+
+struct bgmac_rx_header {
+	__le16 len;
+	__le16 flags;
+	__le16 pad[12];
+};
+
+struct bgmac {
+	struct bcma_device *core;
+	struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
+	struct net_device *net_dev;
+	struct napi_struct napi;
+
+	/* DMA */
+	struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
+	struct bgmac_dma_ring rx_ring[BGMAC_MAX_RX_RINGS];
+
+	/* Stats */
+	bool stats_grabbed;
+	u32 mib_tx_regs[BGMAC_NUM_MIB_TX_REGS];
+	u32 mib_rx_regs[BGMAC_NUM_MIB_RX_REGS];
+
+	/* Int */
+	u32 int_mask;
+	u32 int_status;
+
+	/* Speed-related */
+	int speed;
+	bool autoneg;
+	bool full_duplex;
+
+	u8 phyaddr;
+	bool has_robosw;
+
+	bool loopback;
+};
+
+static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
+{
+	return bcma_read32(bgmac->core, offset);
+}
+
+static inline void bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
+{
+	bcma_write32(bgmac->core, offset, value);
+}
+
+static inline void bgmac_maskset(struct bgmac *bgmac, u16 offset, u32 mask,
+				   u32 set)
+{
+	bgmac_write(bgmac, offset, (bgmac_read(bgmac, offset) & mask) | set);
+}
+
+static inline void bgmac_mask(struct bgmac *bgmac, u16 offset, u32 mask)
+{
+	bgmac_maskset(bgmac, offset, mask, 0);
+}
+
+static inline void bgmac_set(struct bgmac *bgmac, u16 offset, u32 set)
+{
+	bgmac_maskset(bgmac, offset, ~0, set);
+}
+
+#endif /* _BGMAC_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index a1adfaf..2f0ba8f 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -8543,7 +8543,6 @@
 	pci_set_drvdata(pdev, dev);
 
 	memcpy(dev->dev_addr, bp->mac_addr, 6);
-	memcpy(dev->perm_addr, bp->mac_addr, 6);
 
 	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
 		NETIF_F_TSO | NETIF_F_TSO_ECN |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/Makefile b/drivers/net/ethernet/broadcom/bnx2x/Makefile
index 48fbdd4..116762d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/Makefile
+++ b/drivers/net/ethernet/broadcom/bnx2x/Makefile
@@ -4,4 +4,5 @@
 
 obj-$(CONFIG_BNX2X) += bnx2x.o
 
-bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-y := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-$(CONFIG_BNX2X_SRIOV) += bnx2x_vfpf.o bnx2x_sriov.o
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index e8d4db1..e4605a9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1,6 +1,6 @@
 /* bnx2x.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -13,9 +13,12 @@
 
 #ifndef BNX2X_H
 #define BNX2X_H
+
+#include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/dma-mapping.h>
 #include <linux/types.h>
+#include <linux/pci_regs.h>
 
 /* compilation time flags */
 
@@ -23,8 +26,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.78.00-0"
-#define DRV_MODULE_RELDATE      "2012/09/27"
+#define DRV_MODULE_VERSION      "1.78.02-0"
+#define DRV_MODULE_RELDATE      "2013/01/14"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
@@ -48,6 +51,13 @@
 #include "bnx2x_sp.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_stats.h"
+#include "bnx2x_vfpf.h"
+
+enum bnx2x_int_mode {
+	BNX2X_INT_MODE_MSIX,
+	BNX2X_INT_MODE_INTX,
+	BNX2X_INT_MODE_MSI
+};
 
 /* error/debug prints */
 
@@ -112,29 +122,29 @@
 		dev_info(&bp->pdev->dev, fmt, ##__VA_ARGS__);	 \
 } while (0)
 
+/* Error handling */
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int);
 #ifdef BNX2X_STOP_ON_ERROR
-void bnx2x_int_disable(struct bnx2x *bp);
 #define bnx2x_panic()				\
 do {						\
 	bp->panic = 1;				\
 	BNX2X_ERR("driver assert\n");		\
-	bnx2x_int_disable(bp);			\
-	bnx2x_panic_dump(bp);			\
+	bnx2x_panic_dump(bp, true);		\
 } while (0)
 #else
 #define bnx2x_panic()				\
 do {						\
 	bp->panic = 1;				\
 	BNX2X_ERR("driver assert\n");		\
-	bnx2x_panic_dump(bp);			\
+	bnx2x_panic_dump(bp, false);		\
 } while (0)
 #endif
 
 #define bnx2x_mc_addr(ha)      ((ha)->addr)
 #define bnx2x_uc_addr(ha)      ((ha)->addr)
 
-#define U64_LO(x)			(u32)(((u64)(x)) & 0xffffffff)
-#define U64_HI(x)			(u32)(((u64)(x)) >> 32)
+#define U64_LO(x)			((u32)(((u64)(x)) & 0xffffffff))
+#define U64_HI(x)			((u32)(((u64)(x)) >> 32))
 #define HILO_U64(hi, lo)		((((u64)(hi)) << 32) + (lo))
 
 
@@ -334,6 +344,9 @@
 #define SGE_PAGE_SIZE		PAGE_SIZE
 #define SGE_PAGE_SHIFT		PAGE_SHIFT
 #define SGE_PAGE_ALIGN(addr)	PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
+#define SGE_PAGES		(SGE_PAGE_SIZE * PAGES_PER_SGE)
+#define TPA_AGG_SIZE		min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) * \
+					    SGE_PAGES), 0xffff)
 
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES	2
@@ -789,48 +802,63 @@
 #define CHIP_NUM_57711E			0x1650
 #define CHIP_NUM_57712			0x1662
 #define CHIP_NUM_57712_MF		0x1663
+#define CHIP_NUM_57712_VF		0x166f
 #define CHIP_NUM_57713			0x1651
 #define CHIP_NUM_57713E			0x1652
 #define CHIP_NUM_57800			0x168a
 #define CHIP_NUM_57800_MF		0x16a5
+#define CHIP_NUM_57800_VF		0x16a9
 #define CHIP_NUM_57810			0x168e
 #define CHIP_NUM_57810_MF		0x16ae
+#define CHIP_NUM_57810_VF		0x16af
 #define CHIP_NUM_57811			0x163d
 #define CHIP_NUM_57811_MF		0x163e
-#define CHIP_NUM_57840_OBSOLETE	0x168d
+#define CHIP_NUM_57811_VF		0x163f
+#define CHIP_NUM_57840_OBSOLETE		0x168d
 #define CHIP_NUM_57840_MF_OBSOLETE	0x16ab
 #define CHIP_NUM_57840_4_10		0x16a1
 #define CHIP_NUM_57840_2_20		0x16a2
 #define CHIP_NUM_57840_MF		0x16a4
+#define CHIP_NUM_57840_VF		0x16ad
 #define CHIP_IS_E1(bp)			(CHIP_NUM(bp) == CHIP_NUM_57710)
 #define CHIP_IS_57711(bp)		(CHIP_NUM(bp) == CHIP_NUM_57711)
 #define CHIP_IS_57711E(bp)		(CHIP_NUM(bp) == CHIP_NUM_57711E)
 #define CHIP_IS_57712(bp)		(CHIP_NUM(bp) == CHIP_NUM_57712)
+#define CHIP_IS_57712_VF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57712_VF)
 #define CHIP_IS_57712_MF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57712_MF)
 #define CHIP_IS_57800(bp)		(CHIP_NUM(bp) == CHIP_NUM_57800)
 #define CHIP_IS_57800_MF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57800_MF)
+#define CHIP_IS_57800_VF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57800_VF)
 #define CHIP_IS_57810(bp)		(CHIP_NUM(bp) == CHIP_NUM_57810)
 #define CHIP_IS_57810_MF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57810_MF)
+#define CHIP_IS_57810_VF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57810_VF)
 #define CHIP_IS_57811(bp)		(CHIP_NUM(bp) == CHIP_NUM_57811)
 #define CHIP_IS_57811_MF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57811_MF)
+#define CHIP_IS_57811_VF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57811_VF)
 #define CHIP_IS_57840(bp)		\
 		((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) || \
 		 (CHIP_NUM(bp) == CHIP_NUM_57840_2_20) || \
 		 (CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE))
 #define CHIP_IS_57840_MF(bp)	((CHIP_NUM(bp) == CHIP_NUM_57840_MF) || \
 				 (CHIP_NUM(bp) == CHIP_NUM_57840_MF_OBSOLETE))
+#define CHIP_IS_57840_VF(bp)		(CHIP_NUM(bp) == CHIP_NUM_57840_VF)
 #define CHIP_IS_E1H(bp)			(CHIP_IS_57711(bp) || \
 					 CHIP_IS_57711E(bp))
 #define CHIP_IS_E2(bp)			(CHIP_IS_57712(bp) || \
-					 CHIP_IS_57712_MF(bp))
+					 CHIP_IS_57712_MF(bp) || \
+					 CHIP_IS_57712_VF(bp))
 #define CHIP_IS_E3(bp)			(CHIP_IS_57800(bp) || \
 					 CHIP_IS_57800_MF(bp) || \
+					 CHIP_IS_57800_VF(bp) || \
 					 CHIP_IS_57810(bp) || \
 					 CHIP_IS_57810_MF(bp) || \
+					 CHIP_IS_57810_VF(bp) || \
 					 CHIP_IS_57811(bp) || \
 					 CHIP_IS_57811_MF(bp) || \
+					 CHIP_IS_57811_VF(bp) || \
 					 CHIP_IS_57840(bp) || \
-					 CHIP_IS_57840_MF(bp))
+					 CHIP_IS_57840_MF(bp) || \
+					 CHIP_IS_57840_VF(bp))
 #define CHIP_IS_E1x(bp)			(CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp)))
 #define USES_WARPCORE(bp)		(CHIP_IS_E3(bp))
 #define IS_E1H_OFFSET			(!CHIP_IS_E1(bp))
@@ -954,6 +982,11 @@
 extern struct workqueue_struct *bnx2x_wq;
 
 #define BNX2X_MAX_NUM_OF_VFS	64
+#define BNX2X_VF_CID_WND	0
+#define BNX2X_CIDS_PER_VF	(1 << BNX2X_VF_CID_WND)
+#define BNX2X_CLIENTS_PER_VF	1
+#define BNX2X_FIRST_VF_CID	256
+#define BNX2X_VF_CIDS		(BNX2X_MAX_NUM_OF_VFS * BNX2X_CIDS_PER_VF)
 #define BNX2X_VF_ID_INVALID	0xFF
 
 /*
@@ -1104,6 +1137,7 @@
 /* forward */
 struct bnx2x_ilt;
 
+struct bnx2x_vfdb;
 
 enum bnx2x_recovery_state {
 	BNX2X_RECOVERY_DONE,
@@ -1165,19 +1199,22 @@
 };
 
 struct bnx2x_fw_stats_data {
-	struct stats_counter	storm_counters;
-	struct per_port_stats	port;
-	struct per_pf_stats	pf;
+	struct stats_counter		storm_counters;
+	struct per_port_stats		port;
+	struct per_pf_stats		pf;
 	struct fcoe_statistics_params	fcoe;
-	struct per_queue_stats  queue_stats[1];
+	struct per_queue_stats		queue_stats[1];
 };
 
 /* Public slow path states */
 enum {
 	BNX2X_SP_RTNL_SETUP_TC,
 	BNX2X_SP_RTNL_TX_TIMEOUT,
-	BNX2X_SP_RTNL_AFEX_F_UPDATE,
 	BNX2X_SP_RTNL_FAN_FAILURE,
+	BNX2X_SP_RTNL_AFEX_F_UPDATE,
+	BNX2X_SP_RTNL_ENABLE_SRIOV,
+	BNX2X_SP_RTNL_VFPF_MCAST,
+	BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
 };
 
 
@@ -1231,6 +1268,21 @@
 	  (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2  : 1))
 #define BP_FW_MB_IDX(bp)		BP_FW_MB_IDX_VN(bp, BP_VN(bp))
 
+#ifdef CONFIG_BNX2X_SRIOV
+	/* vf pf channel mailbox contains request and response buffers */
+	struct bnx2x_vf_mbx_msg	*vf2pf_mbox;
+	dma_addr_t		vf2pf_mbox_mapping;
+
+	/* we set aside a copy of the acquire response */
+	struct pfvf_acquire_resp_tlv acquire_resp;
+
+	/* bulletin board for messages from pf to vf */
+	union pf_vf_bulletin   *pf2vf_bulletin;
+	dma_addr_t		pf2vf_bulletin_mapping;
+
+	struct pf_vf_bulletin_content	old_bulletin;
+#endif /* CONFIG_BNX2X_SRIOV */
+
 	struct net_device	*dev;
 	struct pci_dev		*pdev;
 
@@ -1295,8 +1347,6 @@
 	__le16			*eq_cons_sb;
 	atomic_t		eq_spq_left; /* COMMON_XXX ramrods credit */
 
-
-
 	/* Counter for marking that there is a STAT_QUERY ramrod pending */
 	u16			stats_pending;
 	/*  Counter for completed statistics ramrods */
@@ -1318,8 +1368,6 @@
 #define DISABLE_MSI_FLAG		(1 << 7)
 #define TPA_ENABLE_FLAG			(1 << 8)
 #define NO_MCP_FLAG			(1 << 9)
-
-#define BP_NOMCP(bp)			(bp->flags & NO_MCP_FLAG)
 #define GRO_ENABLE_FLAG			(1 << 10)
 #define MF_FUNC_DIS			(1 << 11)
 #define OWN_CNIC_IRQ			(1 << 12)
@@ -1330,6 +1378,17 @@
 #define BC_SUPPORTS_FCOE_FEATURES	(1 << 19)
 #define USING_SINGLE_MSIX_FLAG		(1 << 20)
 #define BC_SUPPORTS_DCBX_MSG_NON_PMF	(1 << 21)
+#define IS_VF_FLAG			(1 << 22)
+
+#define BP_NOMCP(bp)			((bp)->flags & NO_MCP_FLAG)
+
+#ifdef CONFIG_BNX2X_SRIOV
+#define IS_VF(bp)			((bp)->flags & IS_VF_FLAG)
+#define IS_PF(bp)			(!((bp)->flags & IS_VF_FLAG))
+#else
+#define IS_VF(bp)			false
+#define IS_PF(bp)			true
+#endif
 
 #define NO_ISCSI(bp)		((bp)->flags & NO_ISCSI_FLAG)
 #define NO_ISCSI_OOO(bp)	((bp)->flags & NO_ISCSI_OOO_FLAG)
@@ -1349,6 +1408,7 @@
 	int			mrrs;
 
 	struct delayed_work	sp_task;
+	atomic_t		interrupt_occurred;
 	struct delayed_work	sp_rtnl_task;
 
 	struct delayed_work	period_task;
@@ -1432,6 +1492,7 @@
 	u8			igu_sb_cnt;
 	u8			min_msix_vec_cnt;
 
+	u32			igu_base_addr;
 	dma_addr_t		def_status_blk_mapping;
 
 	struct bnx2x_slowpath	*slowpath;
@@ -1580,6 +1641,9 @@
 	char			fw_ver[32];
 	const struct firmware	*firmware;
 
+	struct bnx2x_vfdb	*vfdb;
+#define IS_SRIOV(bp)		((bp)->vfdb)
+
 	/* DCB support on/off */
 	u16 dcb_state;
 #define BNX2X_DCB_STATE_OFF			0
@@ -1599,6 +1663,10 @@
 	int					dcb_version;
 
 	/* CAM credit pools */
+
+	/* used only in sriov */
+	struct bnx2x_credit_pool_obj		vlans_pool;
+
 	struct bnx2x_credit_pool_obj		macs_pool;
 
 	/* RX_MODE object */
@@ -1636,6 +1704,9 @@
 
 	/* priority to cos mapping */
 	u8					prio_to_cos[8];
+
+	int fp_array_size;
+	u32 dump_preset_idx;
 };
 
 /* Tx queues may be less or equal to Rx queues */
@@ -1813,12 +1884,16 @@
 
 /* Init Function API  */
 void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p);
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+		    u8 vf_valid, int fw_sb_id, int igu_sb_id);
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp);
 int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode);
 int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 void bnx2x_read_mf_cfg(struct bnx2x *bp);
 
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val);
 
 /* dmae */
 void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
@@ -1830,6 +1905,18 @@
 u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
 		      bool with_comp, u8 comp_type);
 
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
+			       u8 src_type, u8 dst_type);
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae);
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl);
+
+/* FLR related routines */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp);
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count);
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt);
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev);
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+				    char *msg, u32 poll_cnt);
 
 void bnx2x_calc_fc_adv(struct bnx2x *bp);
 int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
@@ -1854,6 +1941,9 @@
 	return val;
 }
 
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
+			    bool is_pf);
+
 #define BNX2X_ILT_ZALLOC(x, y, size) \
 	do { \
 		x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
@@ -1990,10 +2080,8 @@
 #define BNX2X_LOOPBACK_FAILED		(BNX2X_MAC_LOOPBACK_FAILED | \
 					 BNX2X_PHY_LOOPBACK_FAILED)
 
-
 #define STROM_ASSERT_ARRAY_SIZE		50
 
-
 /* must be used on a CID before placing it on a HW ring */
 #define HW_CID(bp, x)			((BP_PORT(bp) << 23) | \
 					 (BP_VN(bp) << BNX2X_SWCID_SHIFT) | \
@@ -2024,7 +2112,6 @@
 /* Memory of fairness algorithm . 2 cycles */
 #define FAIR_MEM					2
 
-
 #define ATTN_NIG_FOR_FUNC		(1L << 8)
 #define ATTN_SW_TIMER_4_FUNC		(1L << 9)
 #define GPIO_2_FUNC			(1L << 10)
@@ -2067,6 +2154,7 @@
 				(AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \
 				 AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \
 				 AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_BRB_HW_INTERRUPT | \
 				 AEU_INPUTS_ATTN_BITS_PBCLIENT_HW_INTERRUPT)
 #define HW_PRTY_ASSERT_SET_0	(AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \
 				 AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \
@@ -2128,7 +2216,6 @@
 
 #define MULTI_MASK			0x7f
 
-
 #define DEF_USB_FUNC_OFF	offsetof(struct cstorm_def_status_block_u, func)
 #define DEF_CSB_FUNC_OFF	offsetof(struct cstorm_def_status_block_c, func)
 #define DEF_XSB_FUNC_OFF	offsetof(struct xstorm_def_status_block, func)
@@ -2156,18 +2243,6 @@
 		(&bp->def_status_blk->sp_sb.\
 					index_values[HC_SP_INDEX_ETH_DEF_CONS])
 
-#define SET_FLAG(value, mask, flag) \
-	do {\
-		(value) &= ~(mask);\
-		(value) |= ((flag) << (mask##_SHIFT));\
-	} while (0)
-
-#define GET_FLAG(value, mask) \
-	(((value) & (mask)) >> (mask##_SHIFT))
-
-#define GET_FIELD(value, fname) \
-	(((value) & (fname##_MASK)) >> (fname##_SHIFT))
-
 #define CAM_IS_INVALID(x) \
 	(GET_FLAG(x.flags, \
 	MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \
@@ -2178,7 +2253,6 @@
 #define MC_HASH_OFFSET(bp, i)		(BAR_TSTRORM_INTMEM + \
 	TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(BP_FUNC(bp)) + i*4)
 
-
 #ifndef PXP2_REG_PXP2_INT_STS
 #define PXP2_REG_PXP2_INT_STS		PXP2_REG_PXP2_INT_STS_0
 #endif
@@ -2190,9 +2264,16 @@
 #define BNX2X_VPD_LEN			128
 #define VENDOR_ID_LEN			4
 
+#define VF_ACQUIRE_THRESH		3
+#define VF_ACQUIRE_MAC_FILTERS		1
+#define VF_ACQUIRE_MC_FILTERS		10
+
+#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
+			    (!((me_reg) & ME_REG_VF_ERR)))
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code);
 /* Congestion management fairness mode */
-#define CMNG_FNS_NONE		0
-#define CMNG_FNS_MINMAX		1
+#define CMNG_FNS_NONE			0
+#define CMNG_FNS_MINMAX			1
 
 #define HC_SEG_ACCESS_DEF		0   /*Driver decision 0-3*/
 #define HC_SEG_ACCESS_ATTN		4
@@ -2208,7 +2289,6 @@
 void bnx2x_set_ethtool_ops(struct net_device *netdev);
 void bnx2x_notify_link_changed(struct bnx2x *bp);
 
-
 #define BNX2X_MF_SD_PROTOCOL(bp) \
 	((bp)->mf_config[BP_VN(bp)] & FUNC_MF_CFG_PROTOCOL_MASK)
 
@@ -2229,6 +2309,18 @@
 				(BNX2X_IS_MF_SD_PROTOCOL_ISCSI(bp) || \
 				 BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)))
 
+#define SET_FLAG(value, mask, flag) \
+	do {\
+		(value) &= ~(mask);\
+		(value) |= ((flag) << (mask##_SHIFT));\
+	} while (0)
+
+#define GET_FLAG(value, mask) \
+	(((value) & (mask)) >> (mask##_SHIFT))
+
+#define GET_FIELD(value, fname) \
+	(((value) & (fname##_MASK)) >> (fname##_SHIFT))
+
 enum {
 	SWITCH_UPDATE,
 	AFEX_UPDATE,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f771ddf..ecac04a3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1,6 +1,6 @@
 /* bnx2x_cmn.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -21,6 +21,7 @@
 #include <linux/if_vlan.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
+#include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
 #include <linux/prefetch.h>
@@ -28,8 +29,6 @@
 #include "bnx2x_init.h"
 #include "bnx2x_sp.h"
 
-
-
 /**
  * bnx2x_move_fp - move content of the fastpath structure.
  *
@@ -87,6 +86,34 @@
 }
 
 /**
+ * bnx2x_fill_fw_str - Fill buffer with FW version string.
+ *
+ * @bp:        driver handle
+ * @buf:       character buffer to fill with the fw name
+ * @buf_len:   length of the above buffer
+ *
+ */
+void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
+{
+	if (IS_PF(bp)) {
+		u8 phy_fw_ver[PHY_FW_VER_LEN];
+
+		phy_fw_ver[0] = '\0';
+		bnx2x_get_ext_phy_fw_version(&bp->link_params,
+					     phy_fw_ver, PHY_FW_VER_LEN);
+		strlcpy(buf, bp->fw_ver, buf_len);
+		snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+			 "bc %d.%d.%d%s%s",
+			 (bp->common.bc_ver & 0xff0000) >> 16,
+			 (bp->common.bc_ver & 0xff00) >> 8,
+			 (bp->common.bc_ver & 0xff),
+			 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+	} else {
+		bnx2x_vf_fill_fw_str(bp, buf, buf_len);
+	}
+}
+
+/**
  * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact
  *
  * @bp:	driver handle
@@ -210,7 +237,7 @@
 		   txdata->txq_index, hw_cons, sw_cons, pkt_cons);
 
 		bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons,
-		    &pkts_compl, &bytes_compl);
+					    &pkts_compl, &bytes_compl);
 
 		sw_cons++;
 	}
@@ -316,14 +343,14 @@
 	   fp->last_max_sge, fp->rx_sge_prod);
 }
 
-/* Set Toeplitz hash value in the skb using the value from the
+/* Get Toeplitz hash value in the skb using the value from the
  * CQE (calculated by HW).
  */
 static u32 bnx2x_get_rxhash(const struct bnx2x *bp,
 			    const struct eth_fast_path_rx_cqe *cqe,
 			    bool *l4_rxhash)
 {
-	/* Set Toeplitz hash from CQE */
+	/* Get Toeplitz hash from CQE */
 	if ((bp->dev->features & NETIF_F_RXHASH) &&
 	    (cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG)) {
 		enum eth_rss_hash_type htype;
@@ -390,8 +417,7 @@
 	tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe, &tpa_info->l4_rxhash);
 	if (fp->mode == TPA_MODE_GRO) {
 		u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len);
-		tpa_info->full_page =
-			SGE_PAGE_SIZE * PAGES_PER_SGE / gro_size * gro_size;
+		tpa_info->full_page = SGE_PAGES / gro_size * gro_size;
 		tpa_info->gro_size = gro_size;
 	}
 
@@ -412,31 +438,34 @@
  */
 #define TPA_TSTAMP_OPT_LEN	12
 /**
- * bnx2x_set_lro_mss - calculate the approximate value of the MSS
+ * bnx2x_set_gro_params - compute GRO values
  *
- * @bp:			driver handle
+ * @skb:		packet skb
  * @parsing_flags:	parsing flags from the START CQE
  * @len_on_bd:		total length of the first packet for the
  *			aggregation.
+ * @pkt_len:		length of all segments
  *
  * Approximate value of the MSS for this aggregation calculated using
  * the first packet of it.
+ * Compute number of aggregated segments, and gso_type.
  */
-static u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
-			     u16 len_on_bd)
+static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
+				 u16 len_on_bd, unsigned int pkt_len)
 {
-	/*
-	 * TPA arrgregation won't have either IP options or TCP options
+	/* TPA aggregation won't have either IP options or TCP options
 	 * other than timestamp or IPv6 extension headers.
 	 */
 	u16 hdrs_len = ETH_HLEN + sizeof(struct tcphdr);
 
 	if (GET_FLAG(parsing_flags, PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
-	    PRS_FLAG_OVERETH_IPV6)
+	    PRS_FLAG_OVERETH_IPV6) {
 		hdrs_len += sizeof(struct ipv6hdr);
-	else /* IPv4 */
+		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+	} else {
 		hdrs_len += sizeof(struct iphdr);
-
+		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+	}
 
 	/* Check if there was a TCP timestamp, if there is it's will
 	 * always be 12 bytes length: nop nop kind length echo val.
@@ -446,7 +475,13 @@
 	if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG)
 		hdrs_len += TPA_TSTAMP_OPT_LEN;
 
-	return len_on_bd - hdrs_len;
+	skb_shinfo(skb)->gso_size = len_on_bd - hdrs_len;
+
+	/* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
+	 * to skb_shinfo(skb)->gso_segs
+	 */
+	NAPI_GRO_CB(skb)->count = DIV_ROUND_UP(pkt_len - hdrs_len,
+					       skb_shinfo(skb)->gso_size);
 }
 
 static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
@@ -463,7 +498,7 @@
 	}
 
 	mapping = dma_map_page(&bp->pdev->dev, page, 0,
-			       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+			       SGE_PAGES, DMA_FROM_DEVICE);
 	if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
 		__free_pages(page, PAGES_PER_SGE_SHIFT);
 		BNX2X_ERR("Can't map sge\n");
@@ -500,22 +535,12 @@
 	}
 
 	/* This is needed in order to enable forwarding support */
-	if (frag_size) {
-		skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp,
-					tpa_info->parsing_flags, len_on_bd);
-
-		/* set for GRO */
-		if (fp->mode == TPA_MODE_GRO)
-			skb_shinfo(skb)->gso_type =
-			    (GET_FLAG(tpa_info->parsing_flags,
-				      PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
-						PRS_FLAG_OVERETH_IPV6) ?
-				SKB_GSO_TCPV6 : SKB_GSO_TCPV4;
-	}
-
+	if (frag_size)
+		bnx2x_set_gro_params(skb, tpa_info->parsing_flags, len_on_bd,
+				     le16_to_cpu(cqe->pkt_len));
 
 #ifdef BNX2X_STOP_ON_ERROR
-	if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
+	if (pages > min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGES) {
 		BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
 			  pages, cqe_idx);
 		BNX2X_ERR("cqe->pkt_len = %d\n", cqe->pkt_len);
@@ -533,8 +558,7 @@
 		if (fp->mode == TPA_MODE_GRO)
 			frag_len = min_t(u32, frag_size, (u32)full_page);
 		else /* LRO */
-			frag_len = min_t(u32, frag_size,
-					 (u32)(SGE_PAGE_SIZE * PAGES_PER_SGE));
+			frag_len = min_t(u32, frag_size, (u32)SGE_PAGES);
 
 		rx_pg = &fp->rx_page_ring[sge_idx];
 		old_rx_pg = *rx_pg;
@@ -550,7 +574,7 @@
 		/* Unmap the page as we r going to pass it to the stack */
 		dma_unmap_page(&bp->pdev->dev,
 			       dma_unmap_addr(&old_rx_pg, mapping),
-			       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+			       SGE_PAGES, DMA_FROM_DEVICE);
 		/* Add one frag and update the appropriate fields in the skb */
 		if (fp->mode == TPA_MODE_LRO)
 			skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
@@ -568,7 +592,7 @@
 		}
 
 		skb->data_len += frag_len;
-		skb->truesize += SGE_PAGE_SIZE * PAGES_PER_SGE;
+		skb->truesize += SGE_PAGES;
 		skb->len += frag_len;
 
 		frag_size -= frag_len;
@@ -593,6 +617,54 @@
 	return kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
 }
 
+#ifdef CONFIG_INET
+static void bnx2x_gro_ip_csum(struct bnx2x *bp, struct sk_buff *skb)
+{
+	const struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th;
+
+	skb_set_transport_header(skb, sizeof(struct iphdr));
+	th = tcp_hdr(skb);
+
+	th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
+				  iph->saddr, iph->daddr, 0);
+}
+
+static void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	struct tcphdr *th;
+
+	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+	th = tcp_hdr(skb);
+
+	th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
+				  &iph->saddr, &iph->daddr, 0);
+}
+#endif
+
+static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+			       struct sk_buff *skb)
+{
+#ifdef CONFIG_INET
+	if (skb_shinfo(skb)->gso_size) {
+		skb_set_network_header(skb, 0);
+		switch (be16_to_cpu(skb->protocol)) {
+		case ETH_P_IP:
+			bnx2x_gro_ip_csum(bp, skb);
+			break;
+		case ETH_P_IPV6:
+			bnx2x_gro_ipv6_csum(bp, skb);
+			break;
+		default:
+			BNX2X_ERR("FW GRO supports only IPv4/IPv6, not 0x%04x\n",
+				  be16_to_cpu(skb->protocol));
+		}
+		tcp_gro_complete(skb);
+	}
+#endif
+	napi_gro_receive(&fp->napi, skb);
+}
 
 static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 			   struct bnx2x_agg_info *tpa_info,
@@ -647,7 +719,7 @@
 					 skb, cqe, cqe_idx)) {
 			if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
 				__vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag);
-			napi_gro_receive(&fp->napi, skb);
+			bnx2x_gro_receive(bp, fp, skb);
 		} else {
 			DP(NETIF_MSG_RX_STATUS,
 			   "Failed to allocate new pages - dropping packet!\n");
@@ -1089,7 +1161,7 @@
 	struct bnx2x_link_report_data cur_data;
 
 	/* reread mf_cfg */
-	if (!CHIP_IS_E1(bp))
+	if (IS_PF(bp) && !CHIP_IS_E1(bp))
 		bnx2x_read_mf_cfg(bp);
 
 	/* Read the current link report info */
@@ -1431,10 +1503,14 @@
 
 	if (nvecs == offset)
 		return;
-	free_irq(bp->msix_table[offset].vector, bp->dev);
-	DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
-	   bp->msix_table[offset].vector);
-	offset++;
+
+	/* VFs don't have a default SB */
+	if (IS_PF(bp)) {
+		free_irq(bp->msix_table[offset].vector, bp->dev);
+		DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
+		   bp->msix_table[offset].vector);
+		offset++;
+	}
 
 	if (CNIC_SUPPORT(bp)) {
 		if (nvecs == offset)
@@ -1455,21 +1531,30 @@
 void bnx2x_free_irq(struct bnx2x *bp)
 {
 	if (bp->flags & USING_MSIX_FLAG &&
-	    !(bp->flags & USING_SINGLE_MSIX_FLAG))
-		bnx2x_free_msix_irqs(bp, BNX2X_NUM_ETH_QUEUES(bp) +
-				     CNIC_SUPPORT(bp) + 1);
-	else
+	    !(bp->flags & USING_SINGLE_MSIX_FLAG)) {
+		int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp);
+
+		/* vfs don't have a default status block */
+		if (IS_PF(bp))
+			nvecs++;
+
+		bnx2x_free_msix_irqs(bp, nvecs);
+	} else {
 		free_irq(bp->dev->irq, bp->dev);
+	}
 }
 
 int bnx2x_enable_msix(struct bnx2x *bp)
 {
-	int msix_vec = 0, i, rc, req_cnt;
+	int msix_vec = 0, i, rc;
 
-	bp->msix_table[msix_vec].entry = msix_vec;
-	BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
-	   bp->msix_table[0].entry);
-	msix_vec++;
+	/* VFs don't have a default status block */
+	if (IS_PF(bp)) {
+		bp->msix_table[msix_vec].entry = msix_vec;
+		BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
+			       bp->msix_table[0].entry);
+		msix_vec++;
+	}
 
 	/* Cnic requires an msix vector for itself */
 	if (CNIC_SUPPORT(bp)) {
@@ -1487,9 +1572,10 @@
 		msix_vec++;
 	}
 
-	req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp) + 1;
+	DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
+	   msix_vec);
 
-	rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt);
+	rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec);
 
 	/*
 	 * reconfigure number of tx/rx queues according to available
@@ -1497,7 +1583,7 @@
 	 */
 	if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) {
 		/* how less vectors we will have? */
-		int diff = req_cnt - rc;
+		int diff = msix_vec - rc;
 
 		BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
 
@@ -1551,12 +1637,15 @@
 {
 	int i, rc, offset = 0;
 
-	rc = request_irq(bp->msix_table[offset++].vector,
-			 bnx2x_msix_sp_int, 0,
-			 bp->dev->name, bp->dev);
-	if (rc) {
-		BNX2X_ERR("request sp irq failed\n");
-		return -EBUSY;
+	/* no default status block for vf */
+	if (IS_PF(bp)) {
+		rc = request_irq(bp->msix_table[offset++].vector,
+				 bnx2x_msix_sp_int, 0,
+				 bp->dev->name, bp->dev);
+		if (rc) {
+			BNX2X_ERR("request sp irq failed\n");
+			return -EBUSY;
+		}
 	}
 
 	if (CNIC_SUPPORT(bp))
@@ -1580,12 +1669,20 @@
 	}
 
 	i = BNX2X_NUM_ETH_QUEUES(bp);
-	offset = 1 + CNIC_SUPPORT(bp);
-	netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d ... fp[%d] %d\n",
-	       bp->msix_table[0].vector,
-	       0, bp->msix_table[offset].vector,
-	       i - 1, bp->msix_table[offset + i - 1].vector);
-
+	if (IS_PF(bp)) {
+		offset = 1 + CNIC_SUPPORT(bp);
+		netdev_info(bp->dev,
+			    "using MSI-X  IRQs: sp %d  fp[%d] %d ... fp[%d] %d\n",
+			    bp->msix_table[0].vector,
+			    0, bp->msix_table[offset].vector,
+			    i - 1, bp->msix_table[offset + i - 1].vector);
+	} else {
+		offset = CNIC_SUPPORT(bp);
+		netdev_info(bp->dev,
+			    "using MSI-X  IRQs: fp[%d] %d ... fp[%d] %d\n",
+			    0, bp->msix_table[offset].vector,
+			    i - 1, bp->msix_table[offset + i - 1].vector);
+	}
 	return 0;
 }
 
@@ -1630,7 +1727,6 @@
 		if (rc)
 			return rc;
 	} else {
-		bnx2x_ack_int(bp);
 		rc = bnx2x_req_irq(bp);
 		if (rc) {
 			BNX2X_ERR("IRQ request failed  rc %d, aborting\n", rc);
@@ -1728,7 +1824,6 @@
 	return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp));
 }
 
-
 void bnx2x_set_num_queues(struct bnx2x *bp)
 {
 	/* RSS queues */
@@ -1993,27 +2088,212 @@
 	} while (0)
 #endif /*BNX2X_STOP_ON_ERROR*/
 
-bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
+static void bnx2x_free_fw_stats_mem(struct bnx2x *bp)
 {
-	/* build FW version dword */
-	u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
-		    (BCM_5710_FW_MINOR_VERSION << 8) +
-		    (BCM_5710_FW_REVISION_VERSION << 16) +
-		    (BCM_5710_FW_ENGINEERING_VERSION << 24);
+	BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
+		       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+	return;
+}
 
-	/* read loaded FW from chip */
-	u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
+{
+	int num_groups, vf_headroom = 0;
+	int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
 
-	DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw);
+	/* number of queues for statistics is number of eth queues + FCoE */
+	u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
 
-	if (loaded_fw != my_fw) {
-		if (is_err)
-			BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n",
-				  loaded_fw, my_fw);
-		return false;
+	/* Total number of FW statistics requests =
+	 * 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper
+	 * and fcoe l2 queue) stats + num of queues (which includes another 1
+	 * for fcoe l2 queue if applicable)
+	 */
+	bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
+
+	/* vf stats appear in the request list, but their data is allocated by
+	 * the VFs themselves. We don't include them in the bp->fw_stats_num as
+	 * it is used to determine where to place the vf stats queries in the
+	 * request struct
+	 */
+	if (IS_SRIOV(bp))
+		vf_headroom = bnx2x_vf_headroom(bp);
+
+	/* Request is built from stats_query_header and an array of
+	 * stats_query_cmd_group each of which contains
+	 * STATS_QUERY_CMD_COUNT rules. The real number or requests is
+	 * configured in the stats_query_header.
+	 */
+	num_groups =
+		(((bp->fw_stats_num + vf_headroom) / STATS_QUERY_CMD_COUNT) +
+		 (((bp->fw_stats_num + vf_headroom) % STATS_QUERY_CMD_COUNT) ?
+		 1 : 0));
+
+	DP(BNX2X_MSG_SP, "stats fw_stats_num %d, vf headroom %d, num_groups %d\n",
+	   bp->fw_stats_num, vf_headroom, num_groups);
+	bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
+		num_groups * sizeof(struct stats_query_cmd_group);
+
+	/* Data for statistics requests + stats_counter
+	 * stats_counter holds per-STORM counters that are incremented
+	 * when STORM has finished with the current request.
+	 * memory for FCoE offloaded statistics are counted anyway,
+	 * even if they will not be sent.
+	 * VF stats are not accounted for here as the data of VF stats is stored
+	 * in memory allocated by the VF, not here.
+	 */
+	bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
+		sizeof(struct per_pf_stats) +
+		sizeof(struct fcoe_statistics_params) +
+		sizeof(struct per_queue_stats) * num_queue_stats +
+		sizeof(struct stats_counter);
+
+	BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
+			bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+
+	/* Set shortcuts */
+	bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
+	bp->fw_stats_req_mapping = bp->fw_stats_mapping;
+	bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
+		((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
+	bp->fw_stats_data_mapping = bp->fw_stats_mapping +
+		bp->fw_stats_req_sz;
+
+	DP(BNX2X_MSG_SP, "statistics request base address set to %x %x",
+	   U64_HI(bp->fw_stats_req_mapping),
+	   U64_LO(bp->fw_stats_req_mapping));
+	DP(BNX2X_MSG_SP, "statistics data base address set to %x %x",
+	   U64_HI(bp->fw_stats_data_mapping),
+	   U64_LO(bp->fw_stats_data_mapping));
+	return 0;
+
+alloc_mem_err:
+	bnx2x_free_fw_stats_mem(bp);
+	BNX2X_ERR("Can't allocate FW stats memory\n");
+	return -ENOMEM;
+}
+
+/* send load request to mcp and analyze response */
+static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
+{
+	/* init fw_seq */
+	bp->fw_seq =
+		(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+		 DRV_MSG_SEQ_NUMBER_MASK);
+	BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+
+	/* Get current FW pulse sequence */
+	bp->fw_drv_pulse_wr_seq =
+		(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
+		 DRV_PULSE_SEQ_MASK);
+	BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
+
+	/* load request */
+	(*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
+					DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
+
+	/* if mcp fails to respond we must abort */
+	if (!(*load_code)) {
+		BNX2X_ERR("MCP response failure, aborting\n");
+		return -EBUSY;
 	}
 
-	return true;
+	/* If mcp refused (e.g. other port is in diagnostic mode) we
+	 * must abort
+	 */
+	if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+		BNX2X_ERR("MCP refused load request, aborting\n");
+		return -EBUSY;
+	}
+	return 0;
+}
+
+/* check whether another PF has already loaded FW to chip. In
+ * virtualized environments a pf from another VM may have already
+ * initialized the device including loading FW
+ */
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
+{
+	/* is another pf loaded on this engine? */
+	if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
+	    load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
+		/* build my FW version dword */
+		u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
+			(BCM_5710_FW_MINOR_VERSION << 8) +
+			(BCM_5710_FW_REVISION_VERSION << 16) +
+			(BCM_5710_FW_ENGINEERING_VERSION << 24);
+
+		/* read loaded FW from chip */
+		u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+
+		DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n",
+		   loaded_fw, my_fw);
+
+		/* abort nic load if version mismatch */
+		if (my_fw != loaded_fw) {
+			BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. aborting\n",
+				  loaded_fw, my_fw);
+			return -EBUSY;
+		}
+	}
+	return 0;
+}
+
+/* returns the "mcp load_code" according to global load_count array */
+static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
+{
+	int path = BP_PATH(bp);
+
+	DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d]      %d, %d, %d\n",
+	   path, load_count[path][0], load_count[path][1],
+	   load_count[path][2]);
+	load_count[path][0]++;
+	load_count[path][1 + port]++;
+	DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d]  %d, %d, %d\n",
+	   path, load_count[path][0], load_count[path][1],
+	   load_count[path][2]);
+	if (load_count[path][0] == 1)
+		return FW_MSG_CODE_DRV_LOAD_COMMON;
+	else if (load_count[path][1 + port] == 1)
+		return FW_MSG_CODE_DRV_LOAD_PORT;
+	else
+		return FW_MSG_CODE_DRV_LOAD_FUNCTION;
+}
+
+/* mark PMF if applicable */
+static void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code)
+{
+	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+	    (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
+	    (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
+		bp->port.pmf = 1;
+		/* We need the barrier to ensure the ordering between the
+		 * writing to bp->port.pmf here and reading it from the
+		 * bnx2x_periodic_task().
+		 */
+		smp_mb();
+	} else {
+		bp->port.pmf = 0;
+	}
+
+	DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
+}
+
+static void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
+{
+	if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+	     (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
+	    (bp->common.shmem2_base)) {
+		if (SHMEM2_HAS(bp, dcc_support))
+			SHMEM2_WR(bp, dcc_support,
+				  (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
+				   SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
+		if (SHMEM2_HAS(bp, afex_driver_support))
+			SHMEM2_WR(bp, afex_driver_support,
+				  SHMEM_AFEX_SUPPORTED_VERSION_ONE);
+	}
+
+	/* Set AFEX default VLAN tag to an invalid value */
+	bp->afex_def_vlan_tag = -1;
 }
 
 /**
@@ -2028,49 +2308,15 @@
 static void bnx2x_bz_fp(struct bnx2x *bp, int index)
 {
 	struct bnx2x_fastpath *fp = &bp->fp[index];
-	struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[index];
 
 	int cos;
 	struct napi_struct orig_napi = fp->napi;
 	struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info;
 	/* bzero bnx2x_fastpath contents */
-	if (bp->stats_init) {
-		memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
-		memset(fp, 0, sizeof(*fp));
-	} else {
-		/* Keep Queue statistics */
-		struct bnx2x_eth_q_stats *tmp_eth_q_stats;
-		struct bnx2x_eth_q_stats_old *tmp_eth_q_stats_old;
-
-		tmp_eth_q_stats = kzalloc(sizeof(struct bnx2x_eth_q_stats),
-					  GFP_KERNEL);
-		if (tmp_eth_q_stats)
-			memcpy(tmp_eth_q_stats, &fp_stats->eth_q_stats,
-			       sizeof(struct bnx2x_eth_q_stats));
-
-		tmp_eth_q_stats_old =
-			kzalloc(sizeof(struct bnx2x_eth_q_stats_old),
-				GFP_KERNEL);
-		if (tmp_eth_q_stats_old)
-			memcpy(tmp_eth_q_stats_old, &fp_stats->eth_q_stats_old,
-			       sizeof(struct bnx2x_eth_q_stats_old));
-
-		memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
-		memset(fp, 0, sizeof(*fp));
-
-		if (tmp_eth_q_stats) {
-			memcpy(&fp_stats->eth_q_stats, tmp_eth_q_stats,
-			       sizeof(struct bnx2x_eth_q_stats));
-			kfree(tmp_eth_q_stats);
-		}
-
-		if (tmp_eth_q_stats_old) {
-			memcpy(&fp_stats->eth_q_stats_old, tmp_eth_q_stats_old,
-			       sizeof(struct bnx2x_eth_q_stats_old));
-			kfree(tmp_eth_q_stats_old);
-		}
-
-	}
+	if (fp->tpa_info)
+		memset(fp->tpa_info, 0, ETH_MAX_AGGREGATION_QUEUES_E1H_E2 *
+		       sizeof(struct bnx2x_agg_info));
+	memset(fp, 0, sizeof(*fp));
 
 	/* Restore the NAPI object as it has been already initialized */
 	fp->napi = orig_napi;
@@ -2116,10 +2362,12 @@
 
 	mutex_init(&bp->cnic_mutex);
 
-	rc = bnx2x_alloc_mem_cnic(bp);
-	if (rc) {
-		BNX2X_ERR("Unable to allocate bp memory for cnic\n");
-		LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
+	if (IS_PF(bp)) {
+		rc = bnx2x_alloc_mem_cnic(bp);
+		if (rc) {
+			BNX2X_ERR("Unable to allocate bp memory for cnic\n");
+			LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
+		}
 	}
 
 	rc = bnx2x_alloc_fp_mem_cnic(bp);
@@ -2146,14 +2394,17 @@
 
 	bnx2x_nic_init_cnic(bp);
 
-	/* Enable Timer scan */
-	REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
+	if (IS_PF(bp)) {
+		/* Enable Timer scan */
+		REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
 
-	for_each_cnic_queue(bp, i) {
-		rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
-		if (rc) {
-			BNX2X_ERR("Queue setup failed\n");
-			LOAD_ERROR_EXIT(bp, load_error_cnic2);
+		/* setup cnic queues */
+		for_each_cnic_queue(bp, i) {
+			rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+			if (rc) {
+				BNX2X_ERR("Queue setup failed\n");
+				LOAD_ERROR_EXIT(bp, load_error_cnic2);
+			}
 		}
 	}
 
@@ -2194,13 +2445,11 @@
 #endif /* ! BNX2X_STOP_ON_ERROR */
 }
 
-
 /* must be called with rtnl_lock */
 int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 {
 	int port = BP_PORT(bp);
-	u32 load_code;
-	int i, rc;
+	int i, rc = 0, load_code = 0;
 
 	DP(NETIF_MSG_IFUP, "Starting NIC load\n");
 	DP(NETIF_MSG_IFUP,
@@ -2215,15 +2464,13 @@
 
 	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
 
-	/* Set the initial link reported state to link down */
-	bnx2x_acquire_phy_lock(bp);
 	memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link));
 	__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
 		&bp->last_reported_link.link_report_flags);
-	bnx2x_release_phy_lock(bp);
 
-	/* must be called before memory allocation and HW init */
-	bnx2x_ilt_set_info(bp);
+	if (IS_PF(bp))
+		/* must be called before memory allocation and HW init */
+		bnx2x_ilt_set_info(bp);
 
 	/*
 	 * Zero fastpath structures preserving invariants like napi, which are
@@ -2242,8 +2489,33 @@
 	/* Set the receive queues buffer size */
 	bnx2x_set_rx_buf_size(bp);
 
-	if (bnx2x_alloc_mem(bp))
-		return -ENOMEM;
+	if (IS_PF(bp)) {
+		rc = bnx2x_alloc_mem(bp);
+		if (rc) {
+			BNX2X_ERR("Unable to allocate bp memory\n");
+			return rc;
+		}
+	}
+
+	/* Allocated memory for FW statistics  */
+	if (bnx2x_alloc_fw_stats_mem(bp))
+		LOAD_ERROR_EXIT(bp, load_error0);
+
+	/* need to be done after alloc mem, since it's self adjusting to amount
+	 * of memory available for RSS queues
+	 */
+	rc = bnx2x_alloc_fp_mem(bp);
+	if (rc) {
+		BNX2X_ERR("Unable to allocate memory for fps\n");
+		LOAD_ERROR_EXIT(bp, load_error0);
+	}
+
+	/* request pf to initialize status blocks */
+	if (IS_VF(bp)) {
+		rc = bnx2x_vfpf_init(bp);
+		if (rc)
+			LOAD_ERROR_EXIT(bp, load_error0);
+	}
 
 	/* As long as bnx2x_alloc_mem() may possibly update
 	 * bp->num_queues, bnx2x_set_real_num_queues() should always
@@ -2266,98 +2538,48 @@
 	DP(NETIF_MSG_IFUP, "napi added\n");
 	bnx2x_napi_enable(bp);
 
-	/* set pf load just before approaching the MCP */
-	bnx2x_set_pf_load(bp);
+	if (IS_PF(bp)) {
+		/* set pf load just before approaching the MCP */
+		bnx2x_set_pf_load(bp);
 
-	/* Send LOAD_REQUEST command to MCP
-	 * Returns the type of LOAD command:
-	 * if it is the first port to be initialized
-	 * common blocks should be initialized, otherwise - not
-	 */
-	if (!BP_NOMCP(bp)) {
-		/* init fw_seq */
-		bp->fw_seq =
-			(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
-			 DRV_MSG_SEQ_NUMBER_MASK);
-		BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+		/* if mcp exists send load request and analyze response */
+		if (!BP_NOMCP(bp)) {
+			/* attempt to load pf */
+			rc = bnx2x_nic_load_request(bp, &load_code);
+			if (rc)
+				LOAD_ERROR_EXIT(bp, load_error1);
 
-		/* Get current FW pulse sequence */
-		bp->fw_drv_pulse_wr_seq =
-			(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
-			 DRV_PULSE_SEQ_MASK);
-		BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
-
-		load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
-					     DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
-		if (!load_code) {
-			BNX2X_ERR("MCP response failure, aborting\n");
-			rc = -EBUSY;
-			LOAD_ERROR_EXIT(bp, load_error1);
-		}
-		if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
-			BNX2X_ERR("Driver load refused\n");
-			rc = -EBUSY; /* other port in diagnostic mode */
-			LOAD_ERROR_EXIT(bp, load_error1);
-		}
-		if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
-		    load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
-			/* abort nic load if version mismatch */
-			if (!bnx2x_test_firmware_version(bp, true)) {
-				rc = -EBUSY;
+			/* what did mcp say? */
+			rc = bnx2x_nic_load_analyze_req(bp, load_code);
+			if (rc) {
+				bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
 				LOAD_ERROR_EXIT(bp, load_error2);
 			}
+		} else {
+			load_code = bnx2x_nic_load_no_mcp(bp, port);
 		}
 
-	} else {
-		int path = BP_PATH(bp);
+		/* mark pmf if applicable */
+		bnx2x_nic_load_pmf(bp, load_code);
 
-		DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d]      %d, %d, %d\n",
-		   path, load_count[path][0], load_count[path][1],
-		   load_count[path][2]);
-		load_count[path][0]++;
-		load_count[path][1 + port]++;
-		DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d]  %d, %d, %d\n",
-		   path, load_count[path][0], load_count[path][1],
-		   load_count[path][2]);
-		if (load_count[path][0] == 1)
-			load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
-		else if (load_count[path][1 + port] == 1)
-			load_code = FW_MSG_CODE_DRV_LOAD_PORT;
-		else
-			load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
-	}
+		/* Init Function state controlling object */
+		bnx2x__init_func_obj(bp);
 
-	if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
-	    (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
-	    (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
-		bp->port.pmf = 1;
-		/*
-		 * We need the barrier to ensure the ordering between the
-		 * writing to bp->port.pmf here and reading it from the
-		 * bnx2x_periodic_task().
-		 */
-		smp_mb();
-	} else
-		bp->port.pmf = 0;
-
-	DP(NETIF_MSG_IFUP, "pmf %d\n", bp->port.pmf);
-
-	/* Init Function state controlling object */
-	bnx2x__init_func_obj(bp);
-
-	/* Initialize HW */
-	rc = bnx2x_init_hw(bp, load_code);
-	if (rc) {
-		BNX2X_ERR("HW init failed, aborting\n");
-		bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
-		LOAD_ERROR_EXIT(bp, load_error2);
+		/* Initialize HW */
+		rc = bnx2x_init_hw(bp, load_code);
+		if (rc) {
+			BNX2X_ERR("HW init failed, aborting\n");
+			bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+			LOAD_ERROR_EXIT(bp, load_error2);
+		}
 	}
 
 	/* Connect to IRQs */
 	rc = bnx2x_setup_irqs(bp);
 	if (rc) {
-		BNX2X_ERR("IRQs setup failed\n");
-		bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+		BNX2X_ERR("setup irqs failed\n");
+		if (IS_PF(bp))
+			bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
 		LOAD_ERROR_EXIT(bp, load_error2);
 	}
 
@@ -2365,78 +2587,89 @@
 	bnx2x_nic_init(bp, load_code);
 
 	/* Init per-function objects */
-	bnx2x_init_bp_objs(bp);
+	if (IS_PF(bp)) {
+		bnx2x_init_bp_objs(bp);
+		bnx2x_iov_nic_init(bp);
 
-	if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
-	    (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
-	    (bp->common.shmem2_base)) {
-		if (SHMEM2_HAS(bp, dcc_support))
-			SHMEM2_WR(bp, dcc_support,
-				  (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
-				   SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
-		if (SHMEM2_HAS(bp, afex_driver_support))
-			SHMEM2_WR(bp, afex_driver_support,
-				  SHMEM_AFEX_SUPPORTED_VERSION_ONE);
-	}
-
-	/* Set AFEX default VLAN tag to an invalid value */
-	bp->afex_def_vlan_tag = -1;
-
-	bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
-	rc = bnx2x_func_start(bp);
-	if (rc) {
-		BNX2X_ERR("Function start failed!\n");
-		bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
-		LOAD_ERROR_EXIT(bp, load_error3);
-	}
-
-	/* Send LOAD_DONE command to MCP */
-	if (!BP_NOMCP(bp)) {
-		load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
-		if (!load_code) {
-			BNX2X_ERR("MCP response failure, aborting\n");
-			rc = -EBUSY;
-			LOAD_ERROR_EXIT(bp, load_error3);
-		}
-	}
-
-	rc = bnx2x_setup_leading(bp);
-	if (rc) {
-		BNX2X_ERR("Setup leading failed!\n");
-		LOAD_ERROR_EXIT(bp, load_error3);
-	}
-
-	for_each_nondefault_eth_queue(bp, i) {
-		rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+		/* Set AFEX default VLAN tag to an invalid value */
+		bp->afex_def_vlan_tag = -1;
+		bnx2x_nic_load_afex_dcc(bp, load_code);
+		bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
+		rc = bnx2x_func_start(bp);
 		if (rc) {
-			BNX2X_ERR("Queue setup failed\n");
+			BNX2X_ERR("Function start failed!\n");
+			bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+
 			LOAD_ERROR_EXIT(bp, load_error3);
 		}
-	}
 
-	rc = bnx2x_init_rss_pf(bp);
-	if (rc) {
-		BNX2X_ERR("PF RSS init failed\n");
-		LOAD_ERROR_EXIT(bp, load_error3);
+		/* Send LOAD_DONE command to MCP */
+		if (!BP_NOMCP(bp)) {
+			load_code = bnx2x_fw_command(bp,
+						     DRV_MSG_CODE_LOAD_DONE, 0);
+			if (!load_code) {
+				BNX2X_ERR("MCP response failure, aborting\n");
+				rc = -EBUSY;
+				LOAD_ERROR_EXIT(bp, load_error3);
+			}
+		}
+
+		/* setup the leading queue */
+		rc = bnx2x_setup_leading(bp);
+		if (rc) {
+			BNX2X_ERR("Setup leading failed!\n");
+			LOAD_ERROR_EXIT(bp, load_error3);
+		}
+
+		/* set up the rest of the queues */
+		for_each_nondefault_eth_queue(bp, i) {
+			rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+			if (rc) {
+				BNX2X_ERR("Queue setup failed\n");
+				LOAD_ERROR_EXIT(bp, load_error3);
+			}
+		}
+
+		/* setup rss */
+		rc = bnx2x_init_rss_pf(bp);
+		if (rc) {
+			BNX2X_ERR("PF RSS init failed\n");
+			LOAD_ERROR_EXIT(bp, load_error3);
+		}
+
+	} else { /* vf */
+		for_each_eth_queue(bp, i) {
+			rc = bnx2x_vfpf_setup_q(bp, i);
+			if (rc) {
+				BNX2X_ERR("Queue setup failed\n");
+				LOAD_ERROR_EXIT(bp, load_error3);
+			}
+		}
 	}
 
 	/* Now when Clients are configured we are ready to work */
 	bp->state = BNX2X_STATE_OPEN;
 
 	/* Configure a ucast MAC */
-	rc = bnx2x_set_eth_mac(bp, true);
+	if (IS_PF(bp))
+		rc = bnx2x_set_eth_mac(bp, true);
+	else /* vf */
+		rc = bnx2x_vfpf_set_mac(bp);
 	if (rc) {
 		BNX2X_ERR("Setting Ethernet MAC failed\n");
 		LOAD_ERROR_EXIT(bp, load_error3);
 	}
 
-	if (bp->pending_max) {
+	if (IS_PF(bp) && bp->pending_max) {
 		bnx2x_update_max_mf_config(bp, bp->pending_max);
 		bp->pending_max = 0;
 	}
 
-	if (bp->port.pmf)
-		bnx2x_initial_phy_init(bp, load_mode);
+	if (bp->port.pmf) {
+		rc = bnx2x_initial_phy_init(bp, load_mode);
+		if (rc)
+			LOAD_ERROR_EXIT(bp, load_error3);
+	}
 	bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN;
 
 	/* Start fast path */
@@ -2478,8 +2711,8 @@
 	if (CNIC_ENABLED(bp))
 		bnx2x_load_cnic(bp);
 
-	/* mark driver is loaded in shmem2 */
-	if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
+	if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
+		/* mark driver is loaded in shmem2 */
 		u32 val;
 		val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
 		SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
@@ -2488,7 +2721,7 @@
 	}
 
 	/* Wait for all pending SP commands to complete */
-	if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) {
+	if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) {
 		BNX2X_ERR("Timeout waiting for SP elements to complete\n");
 		bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
 		return -EBUSY;
@@ -2504,10 +2737,12 @@
 
 #ifndef BNX2X_STOP_ON_ERROR
 load_error3:
-	bnx2x_int_disable_sync(bp, 1);
+	if (IS_PF(bp)) {
+		bnx2x_int_disable_sync(bp, 1);
 
-	/* Clean queueable objects */
-	bnx2x_squeeze_objects(bp);
+		/* Clean queueable objects */
+		bnx2x_squeeze_objects(bp);
+	}
 
 	/* Free SKBs, SGEs, TPA pool and driver internals */
 	bnx2x_free_skbs(bp);
@@ -2517,7 +2752,7 @@
 	/* Release IRQs */
 	bnx2x_free_irq(bp);
 load_error2:
-	if (!BP_NOMCP(bp)) {
+	if (IS_PF(bp) && !BP_NOMCP(bp)) {
 		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
 		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
 	}
@@ -2525,15 +2760,35 @@
 	bp->port.pmf = 0;
 load_error1:
 	bnx2x_napi_disable(bp);
+
 	/* clear pf_load status, as it was already set */
-	bnx2x_clear_pf_load(bp);
+	if (IS_PF(bp))
+		bnx2x_clear_pf_load(bp);
 load_error0:
+	bnx2x_free_fp_mem(bp);
+	bnx2x_free_fw_stats_mem(bp);
 	bnx2x_free_mem(bp);
 
 	return rc;
 #endif /* ! BNX2X_STOP_ON_ERROR */
 }
 
+static int bnx2x_drain_tx_queues(struct bnx2x *bp)
+{
+	u8 rc = 0, cos, i;
+
+	/* Wait until tx fastpath tasks complete */
+	for_each_tx_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		for_each_cos_in_tx_queue(fp, cos)
+			rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
 /* must be called with rtnl_lock */
 int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
 {
@@ -2543,15 +2798,16 @@
 	DP(NETIF_MSG_IFUP, "Starting NIC unload\n");
 
 	/* mark driver is unloaded in shmem2 */
-	if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
+	if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
 		u32 val;
 		val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
 		SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
 			  val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
 	}
 
-	if ((bp->state == BNX2X_STATE_CLOSED) ||
-	    (bp->state == BNX2X_STATE_ERROR)) {
+	if (IS_PF(bp) && bp->recovery_state != BNX2X_RECOVERY_DONE &&
+	    (bp->state == BNX2X_STATE_CLOSED ||
+	     bp->state == BNX2X_STATE_ERROR)) {
 		/* We can get here if the driver has been unloaded
 		 * during parity error recovery and is either waiting for a
 		 * leader to complete or for other functions to unload and
@@ -2569,8 +2825,16 @@
 		return -EINVAL;
 	}
 
-	/*
-	 * It's important to set the bp->state to the value different from
+	/* Nothing to do during unload if previous bnx2x_nic_load()
+	 * have not completed succesfully - all resourses are released.
+	 *
+	 * we can get here only after unsuccessful ndo_* callback, during which
+	 * dev->IFF_UP flag is still on.
+	 */
+	if (bp->state == BNX2X_STATE_CLOSED || bp->state == BNX2X_STATE_ERROR)
+		return 0;
+
+	/* It's important to set the bp->state to the value different from
 	 * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int()
 	 * may restart the Tx from the NAPI context (see bnx2x_tx_int()).
 	 */
@@ -2588,16 +2852,24 @@
 
 	del_timer_sync(&bp->timer);
 
-	/* Set ALWAYS_ALIVE bit in shmem */
-	bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
+	if (IS_PF(bp)) {
+		/* Set ALWAYS_ALIVE bit in shmem */
+		bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
+		bnx2x_drv_pulse(bp);
+		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+		bnx2x_save_statistics(bp);
+	}
 
-	bnx2x_drv_pulse(bp);
+	/* wait till consumers catch up with producers in all queues */
+	bnx2x_drain_tx_queues(bp);
 
-	bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-	bnx2x_save_statistics(bp);
-
-	/* Cleanup the chip if needed */
-	if (unload_mode != UNLOAD_RECOVERY)
+	/* if VF indicate to PF this function is going down (PF will delete sp
+	 * elements and clear initializations
+	 */
+	if (IS_VF(bp))
+		bnx2x_vfpf_close_vf(bp);
+	else if (unload_mode != UNLOAD_RECOVERY)
+		/* if this is a normal/close unload need to clean up chip*/
 		bnx2x_chip_cleanup(bp, unload_mode, keep_link);
 	else {
 		/* Send the UNLOAD_REQUEST to the MCP */
@@ -2630,7 +2902,8 @@
 	 * At this stage no more interrupts will arrive so we may safly clean
 	 * the queueable objects here in case they failed to get cleaned so far.
 	 */
-	bnx2x_squeeze_objects(bp);
+	if (IS_PF(bp))
+		bnx2x_squeeze_objects(bp);
 
 	/* There should be no more pending SP commands at this stage */
 	bp->sp_state = 0;
@@ -2644,19 +2917,22 @@
 	for_each_rx_queue(bp, i)
 		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
 
-	if (CNIC_LOADED(bp)) {
+	bnx2x_free_fp_mem(bp);
+	if (CNIC_LOADED(bp))
 		bnx2x_free_fp_mem_cnic(bp);
-		bnx2x_free_mem_cnic(bp);
-	}
-	bnx2x_free_mem(bp);
 
+	if (IS_PF(bp)) {
+		bnx2x_free_mem(bp);
+		if (CNIC_LOADED(bp))
+			bnx2x_free_mem_cnic(bp);
+	}
 	bp->state = BNX2X_STATE_CLOSED;
 	bp->cnic_loaded = false;
 
 	/* Check if there are pending parity attentions. If there are - set
 	 * RECOVERY_IN_PROGRESS.
 	 */
-	if (bnx2x_chk_parity_attn(bp, &global, false)) {
+	if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) {
 		bnx2x_set_reset_in_progress(bp);
 
 		/* Set RESET_IS_GLOBAL if needed */
@@ -2668,7 +2944,9 @@
 	/* The last driver must disable a "close the gate" if there is no
 	 * parity attention or "process kill" pending.
 	 */
-	if (!bnx2x_clear_pf_load(bp) && bnx2x_reset_is_done(bp, BP_PATH(bp)))
+	if (IS_PF(bp) &&
+	    !bnx2x_clear_pf_load(bp) &&
+	    bnx2x_reset_is_done(bp, BP_PATH(bp)))
 		bnx2x_disable_close_the_gate(bp);
 
 	DP(NETIF_MSG_IFUP, "Ending NIC unload\n");
@@ -2752,7 +3030,6 @@
 			if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
 				bnx2x_tx_int(bp, fp->txdata_ptr[cos]);
 
-
 		if (bnx2x_has_rx_work(fp)) {
 			work_done += bnx2x_rx_int(fp, budget - work_done);
 
@@ -2851,17 +3128,21 @@
 	return bd_prod;
 }
 
-static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
+#define bswab32(b32) ((__force __le32) swab32((__force __u32) (b32)))
+#define bswab16(b16) ((__force __le16) swab16((__force __u16) (b16)))
+static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
 {
+	__sum16 tsum = (__force __sum16) csum;
+
 	if (fix > 0)
-		csum = (u16) ~csum_fold(csum_sub(csum,
-				csum_partial(t_header - fix, fix, 0)));
+		tsum = ~csum_fold(csum_sub((__force __wsum) csum,
+				  csum_partial(t_header - fix, fix, 0)));
 
 	else if (fix < 0)
-		csum = (u16) ~csum_fold(csum_add(csum,
-				csum_partial(t_header, -fix, 0)));
+		tsum = ~csum_fold(csum_add((__force __wsum) csum,
+				  csum_partial(t_header, -fix, 0)));
 
-	return swab16(csum);
+	return bswab16(csum);
 }
 
 static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
@@ -2995,23 +3276,24 @@
 				     u32 xmit_type)
 {
 	pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
-	pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+	pbd->tcp_send_seq = bswab32(tcp_hdr(skb)->seq);
 	pbd->tcp_flags = pbd_tcp_flags(skb);
 
 	if (xmit_type & XMIT_GSO_V4) {
-		pbd->ip_id = swab16(ip_hdr(skb)->id);
+		pbd->ip_id = bswab16(ip_hdr(skb)->id);
 		pbd->tcp_pseudo_csum =
-			swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-						  ip_hdr(skb)->daddr,
-						  0, IPPROTO_TCP, 0));
+			bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+						   ip_hdr(skb)->daddr,
+						   0, IPPROTO_TCP, 0));
 
 	} else
 		pbd->tcp_pseudo_csum =
-			swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-						&ipv6_hdr(skb)->daddr,
-						0, IPPROTO_TCP, 0));
+			bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						 &ipv6_hdr(skb)->daddr,
+						 0, IPPROTO_TCP, 0));
 
-	pbd->global_data |= ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN;
+	pbd->global_data |=
+		cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN);
 }
 
 /**
@@ -3025,12 +3307,12 @@
  * 57712 related
  */
 static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
-	u32 *parsing_data, u32 xmit_type)
+					u32 *parsing_data, u32 xmit_type)
 {
 	*parsing_data |=
-			((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
-			ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
-			ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
+		((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
+		ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+		ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
 
 	if (xmit_type & XMIT_CSUM_TCP) {
 		*parsing_data |= ((tcp_hdrlen(skb) / 4) <<
@@ -3038,12 +3320,11 @@
 			ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
 
 		return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
-	} else
-		/* We support checksum offload for TCP and UDP only.
-		 * No need to pass the UDP header length - it's a constant.
-		 */
-		return skb_transport_header(skb) +
-				sizeof(struct udphdr) - skb->data;
+	}
+	/* We support checksum offload for TCP and UDP only.
+	 * No need to pass the UDP header length - it's a constant.
+	 */
+	return skb_transport_header(skb) + sizeof(struct udphdr) - skb->data;
 }
 
 static inline void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
@@ -3078,8 +3359,9 @@
 
 	/* for now NS flag is not used in Linux */
 	pbd->global_data =
-		(hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
-			 ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
+		cpu_to_le16(hlen |
+			    ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+			     ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
 
 	pbd->ip_hlen_w = (skb_transport_header(skb) -
 			skb_network_header(skb)) >> 1;
@@ -3096,7 +3378,7 @@
 	hlen = hlen*2;
 
 	if (xmit_type & XMIT_CSUM_TCP) {
-		pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
+		pbd->tcp_pseudo_csum = bswab16(tcp_hdr(skb)->check);
 
 	} else {
 		s8 fix = SKB_CS_OFF(skb); /* signed! */
@@ -3176,17 +3458,18 @@
 			dev_kfree_skb(skb);
 			return NETDEV_TX_OK;
 		}
-			bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
-			netif_tx_stop_queue(txq);
+		bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
+		netif_tx_stop_queue(txq);
 		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
 
 		return NETDEV_TX_BUSY;
 	}
 
 	DP(NETIF_MSG_TX_QUEUED,
-	   "queue[%d]: SKB: summed %x  protocol %x protocol(%x,%x) gso type %x  xmit_type %x\n",
+	   "queue[%d]: SKB: summed %x  protocol %x protocol(%x,%x) gso type %x  xmit_type %x len %d\n",
 	   txq_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
-	   ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
+	   ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type,
+	   skb->len);
 
 	eth = (struct ethhdr *)skb->data;
 
@@ -3267,8 +3550,22 @@
 		    cpu_to_le16(vlan_tx_tag_get(skb));
 		tx_start_bd->bd_flags.as_bitfield |=
 		    (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
-	} else
-		tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+	} else {
+		/* when transmitting in a vf, start bd must hold the ethertype
+		 * for fw to enforce it
+		 */
+#ifndef BNX2X_STOP_ON_ERROR
+		if (IS_VF(bp)) {
+#endif
+			tx_start_bd->vlan_or_ethertype =
+				cpu_to_le16(ntohs(eth->h_proto));
+#ifndef BNX2X_STOP_ON_ERROR
+		} else {
+			/* used by FW for packet accounting */
+			tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+		}
+#endif
+	}
 
 	/* turn on parsing and get a BD */
 	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
@@ -3284,9 +3581,9 @@
 			hlen = bnx2x_set_pbd_csum_e2(bp, skb,
 						     &pbd_e2_parsing_data,
 						     xmit_type);
-		if (IS_MF_SI(bp)) {
-			/*
-			 * fill in the MAC addresses in the PBD - for local
+
+		if (IS_MF_SI(bp) || IS_VF(bp)) {
+			/* fill in the MAC addresses in the PBD - for local
 			 * switching
 			 */
 			bnx2x_set_fw_mac_addr(&pbd_e2->src_mac_addr_hi,
@@ -3567,7 +3864,6 @@
 			return rc;
 	}
 
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 	if (netif_running(dev))
@@ -3763,6 +4059,8 @@
 	} else /* if rx_ring_size specified - use it */
 		rx_ring_size = bp->rx_ring_size;
 
+	DP(BNX2X_MSG_SP, "calculated rx_ring_size %d\n", rx_ring_size);
+
 	/* Common */
 	sb = &bnx2x_fp(bp, index, status_blk);
 
@@ -3909,7 +4207,10 @@
 
 void bnx2x_free_mem_bp(struct bnx2x *bp)
 {
-	kfree(bp->fp->tpa_info);
+	int i;
+
+	for (i = 0; i < bp->fp_array_size; i++)
+		kfree(bp->fp[i].tpa_info);
 	kfree(bp->fp);
 	kfree(bp->sp_objs);
 	kfree(bp->fp_stats);
@@ -3929,18 +4230,22 @@
 
 	/*
 	 * The biggest MSI-X table we might need is as a maximum number of fast
-	 * path IGU SBs plus default SB (for PF).
+	 * path IGU SBs plus default SB (for PF only).
 	 */
-	msix_table_size = bp->igu_sb_cnt + 1;
+	msix_table_size = bp->igu_sb_cnt;
+	if (IS_PF(bp))
+		msix_table_size++;
+	BNX2X_DEV_INFO("msix_table_size %d\n", msix_table_size);
 
 	/* fp array: RSS plus CNIC related L2 queues */
 	fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp);
-	BNX2X_DEV_INFO("fp_array_size %d", fp_array_size);
+	bp->fp_array_size = fp_array_size;
+	BNX2X_DEV_INFO("fp_array_size %d\n", bp->fp_array_size);
 
-	fp = kcalloc(fp_array_size, sizeof(*fp), GFP_KERNEL);
+	fp = kcalloc(bp->fp_array_size, sizeof(*fp), GFP_KERNEL);
 	if (!fp)
 		goto alloc_err;
-	for (i = 0; i < fp_array_size; i++) {
+	for (i = 0; i < bp->fp_array_size; i++) {
 		fp[i].tpa_info =
 			kcalloc(ETH_MAX_AGGREGATION_QUEUES_E1H_E2,
 				sizeof(struct bnx2x_agg_info), GFP_KERNEL);
@@ -3951,13 +4256,13 @@
 	bp->fp = fp;
 
 	/* allocate sp objs */
-	bp->sp_objs = kcalloc(fp_array_size, sizeof(struct bnx2x_sp_objs),
+	bp->sp_objs = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_sp_objs),
 			      GFP_KERNEL);
 	if (!bp->sp_objs)
 		goto alloc_err;
 
 	/* allocate fp_stats */
-	bp->fp_stats = kcalloc(fp_array_size, sizeof(struct bnx2x_fp_stats),
+	bp->fp_stats = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_fp_stats),
 			       GFP_KERNEL);
 	if (!bp->fp_stats)
 		goto alloc_err;
@@ -4036,7 +4341,7 @@
 {
 	u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp);
 	/*
-	 * The selected actived PHY is always after swapping (in case PHY
+	 * The selected activated PHY is always after swapping (in case PHY
 	 * swapping is enabled). So when swapping is enabled, we need to reverse
 	 * the configuration
 	 */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 0991534..aee7671 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1,6 +1,6 @@
 /* bnx2x_cmn.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -24,6 +24,7 @@
 
 
 #include "bnx2x.h"
+#include "bnx2x_sriov.h"
 
 /* This is used as a replacement for an MCP if it's not present */
 extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -196,6 +197,7 @@
 
 /* Disable transactions from chip to host */
 void bnx2x_pf_disable(struct bnx2x *bp);
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val);
 
 /**
  * bnx2x__link_status_update - handles link status change.
@@ -401,7 +403,7 @@
  * If bp->state is OPEN, should be called with
  * netif_addr_lock_bh().
  */
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
 
 /**
  * bnx2x_set_q_rx_mode - configures rx_mode for a single queue.
@@ -413,11 +415,11 @@
  * @tx_accept_flags:	tx accept configuration (tx switch)
  * @ramrod_flags:	ramrod configuration
  */
-void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-			 unsigned long rx_mode_flags,
-			 unsigned long rx_accept_flags,
-			 unsigned long tx_accept_flags,
-			 unsigned long ramrod_flags);
+int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+			unsigned long rx_mode_flags,
+			unsigned long rx_accept_flags,
+			unsigned long tx_accept_flags,
+			unsigned long ramrod_flags);
 
 /* Parity errors related */
 void bnx2x_set_pf_load(struct bnx2x *bp);
@@ -477,8 +479,6 @@
  */
 void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value);
 /* Error handling */
-void bnx2x_panic_dump(struct bnx2x *bp);
-
 void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl);
 
 /* validate currect fw is loaded */
@@ -496,9 +496,44 @@
 /* setup_tc callback */
 int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);
 
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
+
 /* select_queue callback */
 u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
 
+static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
+					struct bnx2x_fastpath *fp,
+					u16 bd_prod, u16 rx_comp_prod,
+					u16 rx_sge_prod)
+{
+	struct ustorm_eth_rx_producers rx_prods = {0};
+	u32 i;
+
+	/* Update producers */
+	rx_prods.bd_prod = bd_prod;
+	rx_prods.cqe_prod = rx_comp_prod;
+	rx_prods.sge_prod = rx_sge_prod;
+
+	/* Make sure that the BD and SGE data is updated before updating the
+	 * producers since FW might read the BD/SGE right after the producer
+	 * is updated.
+	 * This is only applicable for weak-ordered memory model archs such
+	 * as IA-64. The following barrier is also mandatory since FW will
+	 * assumes BDs must have buffers.
+	 */
+	wmb();
+
+	for (i = 0; i < sizeof(rx_prods)/4; i++)
+		REG_WR(bp, fp->ustorm_rx_prods_offset + i*4,
+		       ((u32 *)&rx_prods)[i]);
+
+	mmiowb(); /* keep prod updates ordered */
+
+	DP(NETIF_MSG_RX_STATUS,
+	   "queue[%d]:  wrote  bd_prod %u  cqe_prod %u  sge_prod %u\n",
+	   fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
+}
+
 /* reload helper */
 int bnx2x_reload_if_running(struct net_device *dev);
 
@@ -507,9 +542,6 @@
 /* NAPI poll Rx part */
 int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
 
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-			u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod);
-
 /* NAPI poll Tx part */
 int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata);
 
@@ -612,38 +644,6 @@
 	fp->fp_hc_idx = fp->sb_running_index[SM_RX_ID];
 }
 
-static inline void bnx2x_update_rx_prod_gen(struct bnx2x *bp,
-			struct bnx2x_fastpath *fp, u16 bd_prod,
-			u16 rx_comp_prod, u16 rx_sge_prod, u32 start)
-{
-	struct ustorm_eth_rx_producers rx_prods = {0};
-	u32 i;
-
-	/* Update producers */
-	rx_prods.bd_prod = bd_prod;
-	rx_prods.cqe_prod = rx_comp_prod;
-	rx_prods.sge_prod = rx_sge_prod;
-
-	/*
-	 * Make sure that the BD and SGE data is updated before updating the
-	 * producers since FW might read the BD/SGE right after the producer
-	 * is updated.
-	 * This is only applicable for weak-ordered memory model archs such
-	 * as IA-64. The following barrier is also mandatory since FW will
-	 * assumes BDs must have buffers.
-	 */
-	wmb();
-
-	for (i = 0; i < sizeof(rx_prods)/4; i++)
-		REG_WR(bp, start + i*4, ((u32 *)&rx_prods)[i]);
-
-	mmiowb(); /* keep prod updates ordered */
-
-	DP(NETIF_MSG_RX_STATUS,
-	   "queue[%d]:  wrote  bd_prod %u  cqe_prod %u  sge_prod %u\n",
-	   fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
-}
-
 static inline void bnx2x_igu_ack_sb_gen(struct bnx2x *bp, u8 igu_sb_id,
 					u8 segment, u16 index, u8 op,
 					u8 update, u32 igu_addr)
@@ -819,7 +819,7 @@
 		return;
 
 	dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
-		       SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+		       SGE_PAGES, DMA_FROM_DEVICE);
 	__free_pages(page, PAGES_PER_SGE_SHIFT);
 
 	sw_buf->page = NULL;
@@ -863,7 +863,7 @@
 		netif_napi_del(&bnx2x_fp(bp, i, napi));
 }
 
-void bnx2x_set_int_mode(struct bnx2x *bp);
+int bnx2x_set_int_mode(struct bnx2x *bp);
 
 static inline void bnx2x_disable_msi(struct bnx2x *bp)
 {
@@ -973,7 +973,6 @@
 	return bnx2x_func_state_change(bp, &func_params);
 }
 
-
 /**
  * bnx2x_set_fw_mac_addr - fill in a MAC address in FW format
  *
@@ -982,8 +981,8 @@
  * @fw_lo:	pointer to lower part
  * @mac:	pointer to MAC address
  */
-static inline void bnx2x_set_fw_mac_addr(u16 *fw_hi, u16 *fw_mid, u16 *fw_lo,
-					 u8 *mac)
+static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid,
+					 __le16 *fw_lo, u8 *mac)
 {
 	((u8 *)fw_hi)[0]  = mac[1];
 	((u8 *)fw_hi)[1]  = mac[0];
@@ -1108,6 +1107,9 @@
 	bnx2x_init_mac_credit_pool(bp, &bp->macs_pool, BP_FUNC(bp),
 				   bnx2x_get_path_func_num(bp));
 
+	bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_ABS_FUNC(bp)>>1,
+				    bnx2x_get_path_func_num(bp));
+
 	/* RSS configuration object */
 	bnx2x_init_rss_config_obj(bp, &bp->rss_conf_obj, bp->fp->cl_id,
 				  bp->fp->cid, BP_FUNC(bp), BP_FUNC(bp),
@@ -1125,15 +1127,7 @@
 		return fp->cl_id;
 }
 
-static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
-{
-	struct bnx2x *bp = fp->bp;
-
-	if (!CHIP_IS_E1x(bp))
-		return USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
-	else
-		return USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
-}
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
 
 static inline void bnx2x_init_txdata(struct bnx2x *bp,
 				     struct bnx2x_fp_txdata *txdata, u32 cid,
@@ -1228,7 +1222,7 @@
 #endif
 		}
 		cnt--;
-		usleep_range(1000, 1000);
+		usleep_range(1000, 2000);
 	}
 
 	return 0;
@@ -1263,7 +1257,7 @@
 		}
 		netif_addr_unlock_bh(bp->dev);
 
-		usleep_range(1000, 1000);
+		usleep_range(1000, 2000);
 	}
 
 	smp_mb();
@@ -1393,4 +1387,13 @@
 	return false;
 }
 
+/**
+ * bnx2x_fill_fw_str - Fill buffer with FW version string
+ *
+ * @bp:        driver handle
+ * @buf:       character buffer to fill with the fw name
+ * @buf_len:   length of the above buffer
+ *
+ */
+void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
 #endif /* BNX2X_CMN_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 10bc093..5682054 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -1,6 +1,6 @@
 /* bnx2x_dcb.c: Broadcom Everest network driver.
  *
- * Copyright 2009-2012 Broadcom Corporation
+ * Copyright 2009-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -416,6 +416,7 @@
 	int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&
 			     GET_FLAGS(SHMEM2_RD(bp, drv_flags),
 				       1 << DRV_FLAGS_DCB_MFW_CONFIGURED);
+
 	if (bp->dcbx_port_params.pfc.enabled &&
 	    (!(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) || mfw_configured))
 		/*
@@ -558,6 +559,7 @@
 	int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&
 			     GET_FLAGS(SHMEM2_RD(bp, drv_flags),
 				       1 << DRV_FLAGS_DCB_MFW_CONFIGURED);
+
 	bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
 
 	if (!bp->dcbx_port_params.ets.enabled ||
@@ -1904,11 +1906,13 @@
 	struct bnx2x *bp = netdev_priv(netdev);
 	DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");
 
+	/* Fail to set state to "enabled" if dcbx is disabled in nvram */
 	if (state && ((bp->dcbx_enabled == BNX2X_DCBX_ENABLED_OFF) ||
 		      (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_INVALID))) {
 		DP(BNX2X_MSG_DCB, "Can not set dcbx to enabled while it is disabled in nvm\n");
 		return 1;
 	}
+
 	bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);
 	return 0;
 }
@@ -2052,7 +2056,6 @@
 	if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)
 		return;
 
-
 	if (setting) {
 		bp->dcbx_config_params.admin_pfc_bitmap |= (1 << prio);
 		bp->dcbx_config_params.admin_pfc_tx_enable = 1;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
index 06c7a04..d153f44 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
@@ -1,6 +1,6 @@
 /* bnx2x_dcb.h: Broadcom Everest network driver.
  *
- * Copyright 2009-2012 Broadcom Corporation
+ * Copyright 2009-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index b926f58..bff5e33 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
@@ -1,6 +1,6 @@
 /* bnx2x_dump.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -22,120 +22,37 @@
 #ifndef BNX2X_DUMP_H
 #define BNX2X_DUMP_H
 
+/* WaitP Definitions */
+#define DRV_DUMP_XSTORM_WAITP_ADDRESS    0x2b8a80
+#define DRV_DUMP_TSTORM_WAITP_ADDRESS    0x1b8a80
+#define DRV_DUMP_USTORM_WAITP_ADDRESS    0x338a80
+#define DRV_DUMP_CSTORM_WAITP_ADDRESS    0x238a80
 
 
-/*definitions */
-#define XSTORM_WAITP_ADDR	0x2b8a80
-#define TSTORM_WAITP_ADDR	0x1b8a80
-#define USTORM_WAITP_ADDR	0x338a80
-#define CSTORM_WAITP_ADDR	0x238a80
-#define TSTORM_CAM_MODE	0x1B1440
+/* Possible Chips */
+#define DUMP_CHIP_E1 1
+#define DUMP_CHIP_E1H 2
+#define DUMP_CHIP_E2 4
+#define DUMP_CHIP_E3A0 8
+#define DUMP_CHIP_E3B0 16
+#define DUMP_PATH_0 512
+#define DUMP_PATH_1 1024
+#define NUM_PRESETS 13
+#define NUM_CHIPS 5
 
-#define MAX_TIMER_PENDING	200
-#define TIMER_SCAN_DONT_CARE	0xFF
-#define RI_E1				0x1
-#define RI_E1H				0x2
-#define RI_E2				0x4
-#define RI_E3				0x8
-#define RI_E3B0				0x10
-#define RI_ONLINE			0x100
-#define RI_OFFLINE			0x0
-#define RI_PATH0_DUMP			0x200
-#define RI_PATH1_DUMP			0x400
-
-#define RI_E1_ONLINE		(RI_E1 | RI_ONLINE)
-#define RI_E1H_ONLINE		(RI_E1H | RI_ONLINE)
-#define RI_E1E1H_ONLINE		(RI_E1 | RI_E1H | RI_ONLINE)
-#define RI_E2_ONLINE		(RI_E2 | RI_ONLINE)
-#define RI_E1E2_ONLINE		(RI_E1 | RI_E2 | RI_ONLINE)
-#define RI_E1HE2_ONLINE		(RI_E1H | RI_E2 | RI_ONLINE)
-#define RI_E1E1HE2_ONLINE	(RI_E1 | RI_E1H | RI_E2 | RI_ONLINE)
-#define RI_E3_ONLINE		(RI_E3 | RI_ONLINE)
-#define RI_E1E3_ONLINE		(RI_E1 | RI_E3 | RI_ONLINE)
-#define RI_E1HE3_ONLINE		(RI_E1H | RI_E3 | RI_ONLINE)
-#define RI_E1E1HE3_ONLINE	(RI_E1 | RI_E1H | RI_E3 | RI_ONLINE)
-#define RI_E2E3_ONLINE		(RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1E2E3_ONLINE	(RI_E1 | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1HE2E3_ONLINE	(RI_E1H | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1E1HE2E3_ONLINE	(RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E3B0_ONLINE		(RI_E3B0 | RI_ONLINE)
-#define RI_E1E3B0_ONLINE	(RI_E1 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE3B0_ONLINE	(RI_E1H | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE3B0_ONLINE	(RI_E1 | RI_E1H | RI_E3B0 | RI_ONLINE)
-#define RI_E2E3B0_ONLINE	(RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E2E3B0_ONLINE	(RI_E1 | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE2E3B0_ONLINE	(RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE2E3B0_ONLINE	(RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E3E3B0_ONLINE	(RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E3E3B0_ONLINE	(RI_E1 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE3E3B0_ONLINE	(RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE3E3B0_ONLINE	(RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E2E3E3B0_ONLINE	(RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E2E3E3B0_ONLINE	(RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE2E3E3B0_ONLINE	(RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE2E3E3B0_ONLINE	\
-	(RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1_OFFLINE		(RI_E1 | RI_OFFLINE)
-#define RI_E1H_OFFLINE		(RI_E1H | RI_OFFLINE)
-#define RI_E1E1H_OFFLINE	(RI_E1 | RI_E1H | RI_OFFLINE)
-#define RI_E2_OFFLINE		(RI_E2 | RI_OFFLINE)
-#define RI_E1E2_OFFLINE		(RI_E1 | RI_E2 | RI_OFFLINE)
-#define RI_E1HE2_OFFLINE	(RI_E1H | RI_E2 | RI_OFFLINE)
-#define RI_E1E1HE2_OFFLINE	(RI_E1 | RI_E1H | RI_E2 | RI_OFFLINE)
-#define RI_E3_OFFLINE		(RI_E3 | RI_OFFLINE)
-#define RI_E1E3_OFFLINE		(RI_E1 | RI_E3 | RI_OFFLINE)
-#define RI_E1HE3_OFFLINE	(RI_E1H | RI_E3 | RI_OFFLINE)
-#define RI_E1E1HE3_OFFLINE	(RI_E1 | RI_E1H | RI_E3 | RI_OFFLINE)
-#define RI_E2E3_OFFLINE		(RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1E2E3_OFFLINE	(RI_E1 | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1HE2E3_OFFLINE	(RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1E1HE2E3_OFFLINE	(RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E3B0_OFFLINE		(RI_E3B0 | RI_OFFLINE)
-#define RI_E1E3B0_OFFLINE	(RI_E1 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE3B0_OFFLINE	(RI_E1H | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE3B0_OFFLINE	(RI_E1 | RI_E1H | RI_E3B0 | RI_OFFLINE)
-#define RI_E2E3B0_OFFLINE	(RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E2E3B0_OFFLINE	(RI_E1 | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE2E3B0_OFFLINE	(RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE2E3B0_OFFLINE	(RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E3E3B0_OFFLINE	(RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E3E3B0_OFFLINE	(RI_E1 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE3E3B0_OFFLINE	(RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE3E3B0_OFFLINE	(RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E2E3E3B0_OFFLINE	(RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E2E3E3B0_OFFLINE	(RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE2E3E3B0_OFFLINE	(RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE2E3E3B0_OFFLINE	\
-	(RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_ALL_ONLINE		RI_E1E1HE2E3E3B0_ONLINE
-#define RI_ALL_OFFLINE		RI_E1E1HE2E3E3B0_OFFLINE
-
-#define DBG_DMP_TRACE_BUFFER_SIZE	0x800
-#define DBG_DMP_TRACE_BUFFER_OFFSET(shmem0_offset) \
-	((shmem0_offset) - DBG_DMP_TRACE_BUFFER_SIZE)
-
-struct dump_sign {
-	u32 time_stamp;
-	u32 diag_ver;
-	u32 grc_dump_ver;
+struct	dump_header {
+	u32 header_size; /* Size in DWORDs excluding this field */
+	u32 version;
+	u32 preset;
+	u32 dump_meta_data; /* OR of CHIP and PATH. */
 };
 
-struct dump_hdr {
-	u32  hdr_size;	/* in dwords, excluding this field */
-	struct dump_sign	dump_sign;
-	u32  xstorm_waitp;
-	u32  tstorm_waitp;
-	u32  ustorm_waitp;
-	u32  cstorm_waitp;
-	u16  info;
-	u8   idle_chk;
-	u8   reserved;
-};
-
+#define BNX2X_DUMP_VERSION 0x50acff01
 struct reg_addr {
 	u32 addr;
 	u32 size;
-	u16 info;
+	u32 chips;
+	u32 presets;
 };
 
 struct wreg_addr {
@@ -143,1005 +60,2168 @@
 	u32 size;
 	u32 read_regs_count;
 	const u32 *read_regs;
-	u16 info;
+	u32 chips;
+	u32 presets;
+};
+
+#define PAGE_MODE_VALUES_E2 2
+#define PAGE_READ_REGS_E2 1
+#define PAGE_WRITE_REGS_E2 1
+static const u32 page_vals_e2[] = {0, 128};
+static const u32 page_write_regs_e2[] = {328476};
+static const struct reg_addr page_read_regs_e2[] = {
+	{0x58000, 4608, DUMP_CHIP_E2, 0x30}
+};
+
+#define PAGE_MODE_VALUES_E3 2
+#define PAGE_READ_REGS_E3 1
+#define PAGE_WRITE_REGS_E3 1
+static const u32 page_vals_e3[] = {0, 128};
+static const u32 page_write_regs_e3[] = {328476};
+static const struct reg_addr page_read_regs_e3[] = {
+	{0x58000, 4608, DUMP_CHIP_E3A0 | DUMP_CHIP_E3B0, 0x30}
 };
 
 static const struct reg_addr reg_addrs[] = {
-	{ 0x2000, 341, RI_ALL_ONLINE },
-	{ 0x2800, 103, RI_ALL_ONLINE },
-	{ 0x3000, 287, RI_ALL_ONLINE },
-	{ 0x3800, 331, RI_ALL_ONLINE },
-	{ 0x8800, 6, RI_ALL_ONLINE },
-	{ 0x8818, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x9000, 147, RI_E2E3E3B0_ONLINE },
-	{ 0x924c, 1, RI_E2_ONLINE },
-	{ 0x9250, 16, RI_E2E3E3B0_ONLINE },
-	{ 0x9400, 33, RI_E2E3E3B0_ONLINE },
-	{ 0x9484, 5, RI_E3E3B0_ONLINE },
-	{ 0xa000, 27, RI_ALL_ONLINE },
-	{ 0xa06c, 1, RI_E1E1H_ONLINE },
-	{ 0xa070, 71, RI_ALL_ONLINE },
-	{ 0xa18c, 4, RI_E1E1H_ONLINE },
-	{ 0xa19c, 62, RI_ALL_ONLINE },
-	{ 0xa294, 2, RI_E1E1H_ONLINE },
-	{ 0xa29c, 2, RI_ALL_ONLINE },
-	{ 0xa2a4, 2, RI_E1E1HE2_ONLINE },
-	{ 0xa2ac, 52, RI_ALL_ONLINE },
-	{ 0xa39c, 7, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3b8, 2, RI_E3E3B0_ONLINE },
-	{ 0xa3c0, 3, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3d0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3d8, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3e0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3e8, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3f0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa3f8, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa400, 40, RI_ALL_ONLINE },
-	{ 0xa4a0, 1, RI_E1E1HE2_ONLINE },
-	{ 0xa4a4, 2, RI_ALL_ONLINE },
-	{ 0xa4ac, 2, RI_E1E1H_ONLINE },
-	{ 0xa4b4, 1, RI_E1E1HE2_ONLINE },
-	{ 0xa4b8, 2, RI_E1E1H_ONLINE },
-	{ 0xa4c0, 3, RI_ALL_ONLINE },
-	{ 0xa4cc, 5, RI_E1E1H_ONLINE },
-	{ 0xa4e0, 3, RI_ALL_ONLINE },
-	{ 0xa4fc, 2, RI_ALL_ONLINE },
-	{ 0xa504, 1, RI_E1E1H_ONLINE },
-	{ 0xa508, 3, RI_ALL_ONLINE },
-	{ 0xa518, 1, RI_ALL_ONLINE },
-	{ 0xa520, 1, RI_ALL_ONLINE },
-	{ 0xa528, 1, RI_ALL_ONLINE },
-	{ 0xa530, 1, RI_ALL_ONLINE },
-	{ 0xa538, 1, RI_ALL_ONLINE },
-	{ 0xa540, 1, RI_ALL_ONLINE },
-	{ 0xa548, 1, RI_E1E1H_ONLINE },
-	{ 0xa550, 1, RI_E1E1H_ONLINE },
-	{ 0xa558, 1, RI_E1E1H_ONLINE },
-	{ 0xa560, 1, RI_E1E1H_ONLINE },
-	{ 0xa568, 1, RI_E1E1H_ONLINE },
-	{ 0xa570, 1, RI_ALL_ONLINE },
-	{ 0xa580, 1, RI_ALL_ONLINE },
-	{ 0xa590, 1, RI_ALL_ONLINE },
-	{ 0xa5a0, 1, RI_E1E1HE2_ONLINE },
-	{ 0xa5c0, 1, RI_ALL_ONLINE },
-	{ 0xa5e0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa5e8, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa5f0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa5f8, 1, RI_E1HE2_ONLINE },
-	{ 0xa5fc, 9, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xa620, 6, RI_E2E3E3B0_ONLINE },
-	{ 0xa638, 20, RI_E2_ONLINE },
-	{ 0xa688, 42, RI_E2E3E3B0_ONLINE },
-	{ 0xa730, 1, RI_E2_ONLINE },
-	{ 0xa734, 2, RI_E2E3E3B0_ONLINE },
-	{ 0xa73c, 4, RI_E2_ONLINE },
-	{ 0xa74c, 5, RI_E2E3E3B0_ONLINE },
-	{ 0xa760, 5, RI_E2_ONLINE },
-	{ 0xa774, 7, RI_E2E3E3B0_ONLINE },
-	{ 0xa790, 15, RI_E2_ONLINE },
-	{ 0xa7cc, 4, RI_E2E3E3B0_ONLINE },
-	{ 0xa7e0, 6, RI_E3E3B0_ONLINE },
-	{ 0xa800, 18, RI_E2_ONLINE },
-	{ 0xa848, 33, RI_E2E3E3B0_ONLINE },
-	{ 0xa8cc, 2, RI_E3E3B0_ONLINE },
-	{ 0xa8d4, 4, RI_E2E3E3B0_ONLINE },
-	{ 0xa8e4, 1, RI_E3E3B0_ONLINE },
-	{ 0xa8e8, 1, RI_E2E3E3B0_ONLINE },
-	{ 0xa8f0, 1, RI_E2E3E3B0_ONLINE },
-	{ 0xa8f8, 30, RI_E3E3B0_ONLINE },
-	{ 0xa974, 73, RI_E3E3B0_ONLINE },
-	{ 0xac30, 1, RI_E3E3B0_ONLINE },
-	{ 0xac40, 1, RI_E3E3B0_ONLINE },
-	{ 0xac50, 1, RI_E3E3B0_ONLINE },
-	{ 0xac60, 1, RI_E3B0_ONLINE },
-	{ 0x10000, 9, RI_ALL_ONLINE },
-	{ 0x10024, 1, RI_E1E1HE2_ONLINE },
-	{ 0x10028, 5, RI_ALL_ONLINE },
-	{ 0x1003c, 6, RI_E1E1HE2_ONLINE },
-	{ 0x10054, 20, RI_ALL_ONLINE },
-	{ 0x100a4, 4, RI_E1E1HE2_ONLINE },
-	{ 0x100b4, 11, RI_ALL_ONLINE },
-	{ 0x100e0, 4, RI_E1E1HE2_ONLINE },
-	{ 0x100f0, 8, RI_ALL_ONLINE },
-	{ 0x10110, 6, RI_E1E1HE2_ONLINE },
-	{ 0x10128, 110, RI_ALL_ONLINE },
-	{ 0x102e0, 4, RI_E1E1HE2_ONLINE },
-	{ 0x102f0, 18, RI_ALL_ONLINE },
-	{ 0x10338, 20, RI_E1E1HE2_ONLINE },
-	{ 0x10388, 10, RI_ALL_ONLINE },
-	{ 0x10400, 6, RI_E1E1HE2_ONLINE },
-	{ 0x10418, 6, RI_ALL_ONLINE },
-	{ 0x10430, 10, RI_E1E1HE2_ONLINE },
-	{ 0x10458, 22, RI_ALL_ONLINE },
-	{ 0x104b0, 12, RI_E1E1HE2_ONLINE },
-	{ 0x104e0, 1, RI_ALL_ONLINE },
-	{ 0x104e8, 2, RI_ALL_ONLINE },
-	{ 0x104f4, 2, RI_ALL_ONLINE },
-	{ 0x10500, 146, RI_ALL_ONLINE },
-	{ 0x10750, 2, RI_E1E1HE2_ONLINE },
-	{ 0x10760, 2, RI_E1E1HE2_ONLINE },
-	{ 0x10770, 2, RI_E1E1HE2_ONLINE },
-	{ 0x10780, 2, RI_E1E1HE2_ONLINE },
-	{ 0x10790, 2, RI_ALL_ONLINE },
-	{ 0x107a0, 2, RI_E1E1HE2_ONLINE },
-	{ 0x107b0, 2, RI_E1E1HE2_ONLINE },
-	{ 0x107c0, 2, RI_E1E1HE2_ONLINE },
-	{ 0x107d0, 2, RI_E1E1HE2_ONLINE },
-	{ 0x107e0, 2, RI_ALL_ONLINE },
-	{ 0x10880, 2, RI_ALL_ONLINE },
-	{ 0x10900, 2, RI_ALL_ONLINE },
-	{ 0x16000, 1, RI_E1HE2_ONLINE },
-	{ 0x16004, 25, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x16070, 8, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x16090, 4, RI_E1HE2E3_ONLINE },
-	{ 0x160a0, 6, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x160c0, 7, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x160dc, 2, RI_E1HE2_ONLINE },
-	{ 0x160e4, 10, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1610c, 2, RI_E1HE2_ONLINE },
-	{ 0x16114, 6, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x16140, 48, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x16204, 5, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x18000, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x18008, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x18010, 35, RI_E2E3E3B0_ONLINE },
-	{ 0x180a4, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x180c0, 9, RI_E2E3E3B0_ONLINE },
-	{ 0x180e4, 1, RI_E2E3_ONLINE },
-	{ 0x180e8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x180f0, 1, RI_E2E3_ONLINE },
-	{ 0x180f4, 79, RI_E2E3E3B0_ONLINE },
-	{ 0x18230, 1, RI_E2E3_ONLINE },
-	{ 0x18234, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x1823c, 1, RI_E2E3_ONLINE },
-	{ 0x18240, 13, RI_E2E3E3B0_ONLINE },
-	{ 0x18274, 1, RI_E2_ONLINE },
-	{ 0x18278, 81, RI_E2E3E3B0_ONLINE },
-	{ 0x18440, 63, RI_E2E3E3B0_ONLINE },
-	{ 0x18570, 42, RI_E3E3B0_ONLINE },
-	{ 0x18618, 25, RI_E3B0_ONLINE },
-	{ 0x18680, 44, RI_E3B0_ONLINE },
-	{ 0x18748, 12, RI_E3B0_ONLINE },
-	{ 0x18788, 1, RI_E3B0_ONLINE },
-	{ 0x1879c, 6, RI_E3B0_ONLINE },
-	{ 0x187c4, 51, RI_E3B0_ONLINE },
-	{ 0x18a00, 48, RI_E3B0_ONLINE },
-	{ 0x20000, 24, RI_ALL_ONLINE },
-	{ 0x20060, 8, RI_ALL_ONLINE },
-	{ 0x20080, 94, RI_ALL_ONLINE },
-	{ 0x201f8, 1, RI_E1E1H_ONLINE },
-	{ 0x201fc, 1, RI_ALL_ONLINE },
-	{ 0x20200, 1, RI_E1E1H_ONLINE },
-	{ 0x20204, 1, RI_ALL_ONLINE },
-	{ 0x20208, 1, RI_E1E1H_ONLINE },
-	{ 0x2020c, 39, RI_ALL_ONLINE },
-	{ 0x202c8, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x202d8, 4, RI_E2E3E3B0_ONLINE },
-	{ 0x202f0, 1, RI_E3B0_ONLINE },
-	{ 0x20400, 2, RI_ALL_ONLINE },
-	{ 0x2040c, 8, RI_ALL_ONLINE },
-	{ 0x2042c, 18, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x20480, 1, RI_ALL_ONLINE },
-	{ 0x20500, 1, RI_ALL_ONLINE },
-	{ 0x20600, 1, RI_ALL_ONLINE },
-	{ 0x28000, 1, RI_ALL_ONLINE },
-	{ 0x28004, 8191, RI_ALL_OFFLINE },
-	{ 0x30000, 1, RI_ALL_ONLINE },
-	{ 0x30004, 16383, RI_ALL_OFFLINE },
-	{ 0x40000, 98, RI_ALL_ONLINE },
-	{ 0x401a8, 8, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x401c8, 1, RI_E1H_ONLINE },
-	{ 0x401cc, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x401d4, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x40200, 4, RI_ALL_ONLINE },
-	{ 0x40220, 6, RI_E2E3E3B0_ONLINE },
-	{ 0x40238, 8, RI_E2E3_ONLINE },
-	{ 0x40258, 4, RI_E2E3E3B0_ONLINE },
-	{ 0x40268, 2, RI_E3E3B0_ONLINE },
-	{ 0x40270, 17, RI_E3B0_ONLINE },
-	{ 0x40400, 43, RI_ALL_ONLINE },
-	{ 0x404cc, 3, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x404e0, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x40500, 2, RI_ALL_ONLINE },
-	{ 0x40510, 2, RI_ALL_ONLINE },
-	{ 0x40520, 2, RI_ALL_ONLINE },
-	{ 0x40530, 2, RI_ALL_ONLINE },
-	{ 0x40540, 2, RI_ALL_ONLINE },
-	{ 0x40550, 10, RI_E2E3E3B0_ONLINE },
-	{ 0x40610, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x42000, 164, RI_ALL_ONLINE },
-	{ 0x422c0, 4, RI_E2E3E3B0_ONLINE },
-	{ 0x422d4, 5, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x422e8, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x42400, 49, RI_ALL_ONLINE },
-	{ 0x424c8, 38, RI_ALL_ONLINE },
-	{ 0x42568, 2, RI_ALL_ONLINE },
-	{ 0x42640, 5, RI_E2E3E3B0_ONLINE },
-	{ 0x42800, 1, RI_ALL_ONLINE },
-	{ 0x50000, 1, RI_ALL_ONLINE },
-	{ 0x50004, 19, RI_ALL_ONLINE },
-	{ 0x50050, 8, RI_ALL_ONLINE },
-	{ 0x50070, 88, RI_ALL_ONLINE },
-	{ 0x501f0, 4, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x50200, 2, RI_ALL_ONLINE },
-	{ 0x5020c, 7, RI_ALL_ONLINE },
-	{ 0x50228, 6, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x50240, 1, RI_ALL_ONLINE },
-	{ 0x50280, 1, RI_ALL_ONLINE },
-	{ 0x50300, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x5030c, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x50318, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x5031c, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x50320, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x50330, 1, RI_E3B0_ONLINE },
-	{ 0x52000, 1, RI_ALL_ONLINE },
-	{ 0x54000, 1, RI_ALL_ONLINE },
-	{ 0x54004, 3327, RI_ALL_OFFLINE },
-	{ 0x58000, 1, RI_ALL_ONLINE },
-	{ 0x58004, 8191, RI_E1E1H_OFFLINE },
-	{ 0x60000, 26, RI_ALL_ONLINE },
-	{ 0x60068, 8, RI_E1E1H_ONLINE },
-	{ 0x60088, 12, RI_ALL_ONLINE },
-	{ 0x600b8, 9, RI_E1E1H_ONLINE },
-	{ 0x600dc, 1, RI_ALL_ONLINE },
-	{ 0x600e0, 5, RI_E1E1H_ONLINE },
-	{ 0x600f4, 1, RI_E1E1HE2_ONLINE },
-	{ 0x600f8, 1, RI_E1E1H_ONLINE },
-	{ 0x600fc, 8, RI_ALL_ONLINE },
-	{ 0x6013c, 24, RI_E1H_ONLINE },
-	{ 0x6019c, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x601ac, 18, RI_E2E3E3B0_ONLINE },
-	{ 0x60200, 1, RI_ALL_ONLINE },
-	{ 0x60204, 2, RI_ALL_OFFLINE },
-	{ 0x60210, 13, RI_E2E3E3B0_ONLINE },
-	{ 0x60244, 16, RI_E3B0_ONLINE },
-	{ 0x61000, 1, RI_ALL_ONLINE },
-	{ 0x61004, 511, RI_ALL_OFFLINE },
-	{ 0x61800, 512, RI_E3E3B0_OFFLINE },
-	{ 0x70000, 8, RI_ALL_ONLINE },
-	{ 0x70020, 8184, RI_ALL_OFFLINE },
-	{ 0x78000, 8192, RI_E3E3B0_OFFLINE },
-	{ 0x85000, 3, RI_ALL_OFFLINE },
-	{ 0x8501c, 7, RI_ALL_OFFLINE },
-	{ 0x85048, 1, RI_ALL_OFFLINE },
-	{ 0x85200, 32, RI_ALL_OFFLINE },
-	{ 0xb0000, 16384, RI_E1H_OFFLINE },
-	{ 0xc1000, 7, RI_ALL_ONLINE },
-	{ 0xc103c, 2, RI_E2E3E3B0_ONLINE },
-	{ 0xc1800, 2, RI_ALL_ONLINE },
-	{ 0xc2000, 164, RI_ALL_ONLINE },
-	{ 0xc22c0, 5, RI_E2E3E3B0_ONLINE },
-	{ 0xc22d8, 4, RI_E2E3E3B0_ONLINE },
-	{ 0xc2400, 49, RI_ALL_ONLINE },
-	{ 0xc24c8, 38, RI_ALL_ONLINE },
-	{ 0xc2568, 2, RI_ALL_ONLINE },
-	{ 0xc2600, 1, RI_ALL_ONLINE },
-	{ 0xc4000, 165, RI_ALL_ONLINE },
-	{ 0xc42d8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0xc42e0, 7, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xc42fc, 1, RI_E2E3E3B0_ONLINE },
-	{ 0xc4400, 51, RI_ALL_ONLINE },
-	{ 0xc44d0, 38, RI_ALL_ONLINE },
-	{ 0xc4570, 2, RI_ALL_ONLINE },
-	{ 0xc4578, 5, RI_E2E3E3B0_ONLINE },
-	{ 0xc4600, 1, RI_ALL_ONLINE },
-	{ 0xd0000, 19, RI_ALL_ONLINE },
-	{ 0xd004c, 8, RI_ALL_ONLINE },
-	{ 0xd006c, 91, RI_ALL_ONLINE },
-	{ 0xd01fc, 1, RI_E2E3E3B0_ONLINE },
-	{ 0xd0200, 2, RI_ALL_ONLINE },
-	{ 0xd020c, 7, RI_ALL_ONLINE },
-	{ 0xd0228, 18, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xd0280, 1, RI_ALL_ONLINE },
-	{ 0xd0300, 1, RI_ALL_ONLINE },
-	{ 0xd0400, 1, RI_ALL_ONLINE },
-	{ 0xd0818, 1, RI_E3B0_ONLINE },
-	{ 0xd4000, 1, RI_ALL_ONLINE },
-	{ 0xd4004, 2559, RI_ALL_OFFLINE },
-	{ 0xd8000, 1, RI_ALL_ONLINE },
-	{ 0xd8004, 8191, RI_ALL_OFFLINE },
-	{ 0xe0000, 21, RI_ALL_ONLINE },
-	{ 0xe0054, 8, RI_ALL_ONLINE },
-	{ 0xe0074, 49, RI_ALL_ONLINE },
-	{ 0xe0138, 1, RI_E1E1H_ONLINE },
-	{ 0xe013c, 35, RI_ALL_ONLINE },
-	{ 0xe01f4, 1, RI_E2_ONLINE },
-	{ 0xe01f8, 1, RI_E2E3E3B0_ONLINE },
-	{ 0xe0200, 2, RI_ALL_ONLINE },
-	{ 0xe020c, 8, RI_ALL_ONLINE },
-	{ 0xe022c, 18, RI_E1HE2E3E3B0_ONLINE },
-	{ 0xe0280, 1, RI_ALL_ONLINE },
-	{ 0xe0300, 1, RI_ALL_ONLINE },
-	{ 0xe0400, 1, RI_E3B0_ONLINE },
-	{ 0xe1000, 1, RI_ALL_ONLINE },
-	{ 0xe2000, 1, RI_ALL_ONLINE },
-	{ 0xe2004, 2047, RI_ALL_OFFLINE },
-	{ 0xf0000, 1, RI_ALL_ONLINE },
-	{ 0xf0004, 16383, RI_ALL_OFFLINE },
-	{ 0x101000, 12, RI_ALL_ONLINE },
-	{ 0x101050, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x101054, 3, RI_E2E3E3B0_ONLINE },
-	{ 0x101100, 1, RI_ALL_ONLINE },
-	{ 0x101800, 8, RI_ALL_ONLINE },
-	{ 0x102000, 18, RI_ALL_ONLINE },
-	{ 0x102068, 6, RI_E2E3E3B0_ONLINE },
-	{ 0x102080, 17, RI_ALL_ONLINE },
-	{ 0x1020c8, 8, RI_E1H_ONLINE },
-	{ 0x1020e8, 9, RI_E2E3E3B0_ONLINE },
-	{ 0x102400, 1, RI_ALL_ONLINE },
-	{ 0x103000, 26, RI_ALL_ONLINE },
-	{ 0x103098, 5, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1030ac, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x1030b4, 1, RI_E2_ONLINE },
-	{ 0x1030b8, 7, RI_E2E3E3B0_ONLINE },
-	{ 0x1030d8, 8, RI_E2E3E3B0_ONLINE },
-	{ 0x103400, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x103404, 135, RI_E2E3E3B0_OFFLINE },
-	{ 0x103800, 8, RI_ALL_ONLINE },
-	{ 0x104000, 63, RI_ALL_ONLINE },
-	{ 0x10411c, 16, RI_E2E3E3B0_ONLINE },
-	{ 0x104200, 17, RI_ALL_ONLINE },
-	{ 0x104400, 64, RI_ALL_ONLINE },
-	{ 0x104500, 192, RI_ALL_OFFLINE },
-	{ 0x104800, 64, RI_ALL_ONLINE },
-	{ 0x104900, 192, RI_ALL_OFFLINE },
-	{ 0x105000, 256, RI_ALL_ONLINE },
-	{ 0x105400, 768, RI_ALL_OFFLINE },
-	{ 0x107000, 7, RI_E2E3E3B0_ONLINE },
-	{ 0x10701c, 1, RI_E3E3B0_ONLINE },
-	{ 0x108000, 33, RI_E1E1H_ONLINE },
-	{ 0x1080ac, 5, RI_E1H_ONLINE },
-	{ 0x108100, 5, RI_E1E1H_ONLINE },
-	{ 0x108120, 5, RI_E1E1H_ONLINE },
-	{ 0x108200, 74, RI_E1E1H_ONLINE },
-	{ 0x108400, 74, RI_E1E1H_ONLINE },
-	{ 0x108800, 152, RI_E1E1H_ONLINE },
-	{ 0x110000, 111, RI_E2E3E3B0_ONLINE },
-	{ 0x1101dc, 1, RI_E3E3B0_ONLINE },
-	{ 0x110200, 4, RI_E2E3E3B0_ONLINE },
-	{ 0x120000, 2, RI_ALL_ONLINE },
-	{ 0x120008, 4, RI_ALL_ONLINE },
-	{ 0x120018, 3, RI_ALL_ONLINE },
-	{ 0x120024, 4, RI_ALL_ONLINE },
-	{ 0x120034, 3, RI_ALL_ONLINE },
-	{ 0x120040, 4, RI_ALL_ONLINE },
-	{ 0x120050, 3, RI_ALL_ONLINE },
-	{ 0x12005c, 4, RI_ALL_ONLINE },
-	{ 0x12006c, 3, RI_ALL_ONLINE },
-	{ 0x120078, 4, RI_ALL_ONLINE },
-	{ 0x120088, 3, RI_ALL_ONLINE },
-	{ 0x120094, 4, RI_ALL_ONLINE },
-	{ 0x1200a4, 3, RI_ALL_ONLINE },
-	{ 0x1200b0, 4, RI_ALL_ONLINE },
-	{ 0x1200c0, 3, RI_ALL_ONLINE },
-	{ 0x1200cc, 4, RI_ALL_ONLINE },
-	{ 0x1200dc, 3, RI_ALL_ONLINE },
-	{ 0x1200e8, 4, RI_ALL_ONLINE },
-	{ 0x1200f8, 3, RI_ALL_ONLINE },
-	{ 0x120104, 4, RI_ALL_ONLINE },
-	{ 0x120114, 1, RI_ALL_ONLINE },
-	{ 0x120118, 22, RI_ALL_ONLINE },
-	{ 0x120170, 2, RI_E1E1H_ONLINE },
-	{ 0x120178, 243, RI_ALL_ONLINE },
-	{ 0x120544, 4, RI_E1E1H_ONLINE },
-	{ 0x120554, 6, RI_ALL_ONLINE },
-	{ 0x12059c, 6, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1205b4, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1205b8, 15, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1205f4, 1, RI_E1HE2_ONLINE },
-	{ 0x1205f8, 4, RI_E2E3E3B0_ONLINE },
-	{ 0x120618, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x12061c, 20, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x12066c, 11, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x120698, 3, RI_E2E3E3B0_ONLINE },
-	{ 0x1206a4, 1, RI_E2_ONLINE },
-	{ 0x1206a8, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1206b0, 75, RI_E2E3E3B0_ONLINE },
-	{ 0x1207dc, 1, RI_E2_ONLINE },
-	{ 0x1207fc, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x12080c, 65, RI_ALL_ONLINE },
-	{ 0x120910, 7, RI_E2E3E3B0_ONLINE },
-	{ 0x120930, 9, RI_E2E3E3B0_ONLINE },
-	{ 0x12095c, 37, RI_E3E3B0_ONLINE },
-	{ 0x120a00, 2, RI_E1E1HE2_ONLINE },
-	{ 0x120b00, 1, RI_E3E3B0_ONLINE },
-	{ 0x122000, 2, RI_ALL_ONLINE },
-	{ 0x122008, 2046, RI_E1_OFFLINE },
-	{ 0x128000, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x128008, 6142, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x130000, 35, RI_E2E3E3B0_ONLINE },
-	{ 0x130100, 29, RI_E2E3E3B0_ONLINE },
-	{ 0x130180, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x130200, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x130280, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x130300, 5, RI_E2E3E3B0_ONLINE },
-	{ 0x130380, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x130400, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x130480, 5, RI_E2E3E3B0_ONLINE },
-	{ 0x130800, 72, RI_E2E3E3B0_ONLINE },
-	{ 0x131000, 136, RI_E2E3E3B0_ONLINE },
-	{ 0x132000, 148, RI_E2E3E3B0_ONLINE },
-	{ 0x134000, 544, RI_E2E3E3B0_ONLINE },
-	{ 0x140000, 1, RI_ALL_ONLINE },
-	{ 0x140004, 9, RI_E1E1HE2E3_ONLINE },
-	{ 0x140028, 8, RI_ALL_ONLINE },
-	{ 0x140048, 10, RI_E1E1HE2E3_ONLINE },
-	{ 0x140070, 1, RI_ALL_ONLINE },
-	{ 0x140074, 10, RI_E1E1HE2E3_ONLINE },
-	{ 0x14009c, 1, RI_ALL_ONLINE },
-	{ 0x1400a0, 5, RI_E1E1HE2E3_ONLINE },
-	{ 0x1400b4, 7, RI_ALL_ONLINE },
-	{ 0x1400d0, 10, RI_E1E1HE2E3_ONLINE },
-	{ 0x1400f8, 2, RI_ALL_ONLINE },
-	{ 0x140100, 5, RI_E1E1H_ONLINE },
-	{ 0x140114, 5, RI_E1E1HE2E3_ONLINE },
-	{ 0x140128, 7, RI_ALL_ONLINE },
-	{ 0x140144, 9, RI_E1E1HE2E3_ONLINE },
-	{ 0x140168, 8, RI_ALL_ONLINE },
-	{ 0x140188, 3, RI_E1E1HE2E3_ONLINE },
-	{ 0x140194, 13, RI_ALL_ONLINE },
-	{ 0x140200, 6, RI_E1E1HE2E3_ONLINE },
-	{ 0x140260, 4, RI_E2E3_ONLINE },
-	{ 0x140280, 4, RI_E2E3_ONLINE },
-	{ 0x1402e0, 2, RI_E2E3_ONLINE },
-	{ 0x1402e8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x1402f0, 9, RI_E2E3_ONLINE },
-	{ 0x140314, 44, RI_E3B0_ONLINE },
-	{ 0x144000, 4, RI_E1E1H_ONLINE },
-	{ 0x148000, 4, RI_E1E1H_ONLINE },
-	{ 0x14c000, 4, RI_E1E1H_ONLINE },
-	{ 0x150000, 4, RI_E1E1H_ONLINE },
-	{ 0x154000, 4, RI_E1E1H_ONLINE },
-	{ 0x158000, 4, RI_E1E1H_ONLINE },
-	{ 0x15c000, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x15c008, 5, RI_E1H_ONLINE },
-	{ 0x15c020, 8, RI_E2E3E3B0_ONLINE },
-	{ 0x15c040, 1, RI_E2E3_ONLINE },
-	{ 0x15c044, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x15c04c, 8, RI_E2E3_ONLINE },
-	{ 0x15c06c, 8, RI_E2E3E3B0_ONLINE },
-	{ 0x15c090, 13, RI_E2E3E3B0_ONLINE },
-	{ 0x15c0c8, 24, RI_E2E3E3B0_ONLINE },
-	{ 0x15c128, 2, RI_E2E3_ONLINE },
-	{ 0x15c130, 8, RI_E2E3E3B0_ONLINE },
-	{ 0x15c150, 2, RI_E3E3B0_ONLINE },
-	{ 0x15c158, 2, RI_E3_ONLINE },
-	{ 0x15c160, 149, RI_E3B0_ONLINE },
-	{ 0x161000, 7, RI_ALL_ONLINE },
-	{ 0x16103c, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x161800, 2, RI_ALL_ONLINE },
-	{ 0x162000, 54, RI_E3E3B0_ONLINE },
-	{ 0x162200, 60, RI_E3E3B0_ONLINE },
-	{ 0x162400, 54, RI_E3E3B0_ONLINE },
-	{ 0x162600, 60, RI_E3E3B0_ONLINE },
-	{ 0x162800, 54, RI_E3E3B0_ONLINE },
-	{ 0x162a00, 60, RI_E3E3B0_ONLINE },
-	{ 0x162c00, 54, RI_E3E3B0_ONLINE },
-	{ 0x162e00, 60, RI_E3E3B0_ONLINE },
-	{ 0x164000, 60, RI_ALL_ONLINE },
-	{ 0x164110, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x164118, 15, RI_E2E3E3B0_ONLINE },
-	{ 0x164200, 1, RI_ALL_ONLINE },
-	{ 0x164208, 1, RI_ALL_ONLINE },
-	{ 0x164210, 1, RI_ALL_ONLINE },
-	{ 0x164218, 1, RI_ALL_ONLINE },
-	{ 0x164220, 1, RI_ALL_ONLINE },
-	{ 0x164228, 1, RI_ALL_ONLINE },
-	{ 0x164230, 1, RI_ALL_ONLINE },
-	{ 0x164238, 1, RI_ALL_ONLINE },
-	{ 0x164240, 1, RI_ALL_ONLINE },
-	{ 0x164248, 1, RI_ALL_ONLINE },
-	{ 0x164250, 1, RI_ALL_ONLINE },
-	{ 0x164258, 1, RI_ALL_ONLINE },
-	{ 0x164260, 1, RI_ALL_ONLINE },
-	{ 0x164270, 2, RI_ALL_ONLINE },
-	{ 0x164280, 2, RI_ALL_ONLINE },
-	{ 0x164800, 2, RI_ALL_ONLINE },
-	{ 0x165000, 2, RI_ALL_ONLINE },
-	{ 0x166000, 164, RI_ALL_ONLINE },
-	{ 0x1662cc, 7, RI_E2E3E3B0_ONLINE },
-	{ 0x166400, 49, RI_ALL_ONLINE },
-	{ 0x1664c8, 38, RI_ALL_ONLINE },
-	{ 0x166568, 2, RI_ALL_ONLINE },
-	{ 0x166570, 5, RI_E2E3E3B0_ONLINE },
-	{ 0x166800, 1, RI_ALL_ONLINE },
-	{ 0x168000, 137, RI_ALL_ONLINE },
-	{ 0x168224, 2, RI_E1E1H_ONLINE },
-	{ 0x16822c, 29, RI_ALL_ONLINE },
-	{ 0x1682a0, 12, RI_E1E1H_ONLINE },
-	{ 0x1682d0, 12, RI_ALL_ONLINE },
-	{ 0x168300, 2, RI_E1E1H_ONLINE },
-	{ 0x168308, 68, RI_ALL_ONLINE },
-	{ 0x168418, 2, RI_E1E1H_ONLINE },
-	{ 0x168420, 6, RI_ALL_ONLINE },
-	{ 0x168800, 19, RI_ALL_ONLINE },
-	{ 0x168900, 1, RI_ALL_ONLINE },
-	{ 0x168a00, 128, RI_ALL_ONLINE },
-	{ 0x16a000, 1, RI_ALL_ONLINE },
-	{ 0x16a004, 1535, RI_ALL_OFFLINE },
-	{ 0x16c000, 1, RI_ALL_ONLINE },
-	{ 0x16c004, 1535, RI_ALL_OFFLINE },
-	{ 0x16e000, 16, RI_E1H_ONLINE },
-	{ 0x16e040, 8, RI_E2E3E3B0_ONLINE },
-	{ 0x16e100, 1, RI_E1H_ONLINE },
-	{ 0x16e200, 2, RI_E1H_ONLINE },
-	{ 0x16e400, 161, RI_E1H_ONLINE },
-	{ 0x16e684, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x16e68c, 12, RI_E1H_ONLINE },
-	{ 0x16e6bc, 4, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x16e6cc, 4, RI_E1H_ONLINE },
-	{ 0x16e6e0, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x16e6e8, 5, RI_E2E3_ONLINE },
-	{ 0x16e6fc, 5, RI_E2E3E3B0_ONLINE },
-	{ 0x16e768, 17, RI_E2E3E3B0_ONLINE },
-	{ 0x16e7ac, 12, RI_E3B0_ONLINE },
-	{ 0x170000, 24, RI_ALL_ONLINE },
-	{ 0x170060, 4, RI_E1E1H_ONLINE },
-	{ 0x170070, 65, RI_ALL_ONLINE },
-	{ 0x170194, 11, RI_E2E3E3B0_ONLINE },
-	{ 0x1701c4, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1701cc, 7, RI_E2E3E3B0_ONLINE },
-	{ 0x1701e8, 1, RI_E3E3B0_ONLINE },
-	{ 0x1701ec, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1701f4, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x170200, 4, RI_ALL_ONLINE },
-	{ 0x170214, 1, RI_ALL_ONLINE },
-	{ 0x170218, 77, RI_E2E3E3B0_ONLINE },
-	{ 0x170400, 64, RI_E2E3E3B0_ONLINE },
-	{ 0x178000, 1, RI_ALL_ONLINE },
-	{ 0x180000, 61, RI_ALL_ONLINE },
-	{ 0x18013c, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x180200, 58, RI_ALL_ONLINE },
-	{ 0x180340, 4, RI_ALL_ONLINE },
-	{ 0x180380, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x180388, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x180390, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x180398, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1803a0, 5, RI_E2E3E3B0_ONLINE },
-	{ 0x1803b4, 2, RI_E3E3B0_ONLINE },
-	{ 0x180404, 255, RI_E1E1H_OFFLINE },
-	{ 0x181000, 4, RI_ALL_ONLINE },
-	{ 0x181010, 1020, RI_ALL_OFFLINE },
-	{ 0x182000, 4, RI_E3E3B0_ONLINE },
-	{ 0x1a0000, 1, RI_ALL_ONLINE },
-	{ 0x1a0004, 5631, RI_ALL_OFFLINE },
-	{ 0x1a5800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x1a8000, 1, RI_ALL_ONLINE },
-	{ 0x1a8004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x1b0000, 1, RI_ALL_ONLINE },
-	{ 0x1b0004, 15, RI_E1H_OFFLINE },
-	{ 0x1b0040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b0044, 239, RI_E1H_OFFLINE },
-	{ 0x1b0400, 1, RI_ALL_ONLINE },
-	{ 0x1b0404, 255, RI_E1H_OFFLINE },
-	{ 0x1b0800, 1, RI_ALL_ONLINE },
-	{ 0x1b0840, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b0c00, 1, RI_ALL_ONLINE },
-	{ 0x1b1000, 1, RI_ALL_ONLINE },
-	{ 0x1b1040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b1400, 1, RI_ALL_ONLINE },
-	{ 0x1b1440, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b1480, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b14c0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b1800, 128, RI_ALL_OFFLINE },
-	{ 0x1b1c00, 128, RI_ALL_OFFLINE },
-	{ 0x1b2000, 1, RI_ALL_ONLINE },
-	{ 0x1b2400, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b2404, 5631, RI_E2E3E3B0_OFFLINE },
-	{ 0x1b8000, 1, RI_ALL_ONLINE },
-	{ 0x1b8040, 1, RI_ALL_ONLINE },
-	{ 0x1b8080, 1, RI_ALL_ONLINE },
-	{ 0x1b80c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8100, 1, RI_ALL_ONLINE },
-	{ 0x1b8140, 1, RI_ALL_ONLINE },
-	{ 0x1b8180, 1, RI_ALL_ONLINE },
-	{ 0x1b81c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8200, 1, RI_ALL_ONLINE },
-	{ 0x1b8240, 1, RI_ALL_ONLINE },
-	{ 0x1b8280, 1, RI_ALL_ONLINE },
-	{ 0x1b82c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8300, 1, RI_ALL_ONLINE },
-	{ 0x1b8340, 1, RI_ALL_ONLINE },
-	{ 0x1b8380, 1, RI_ALL_ONLINE },
-	{ 0x1b83c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8400, 1, RI_ALL_ONLINE },
-	{ 0x1b8440, 1, RI_ALL_ONLINE },
-	{ 0x1b8480, 1, RI_ALL_ONLINE },
-	{ 0x1b84c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8500, 1, RI_ALL_ONLINE },
-	{ 0x1b8540, 1, RI_ALL_ONLINE },
-	{ 0x1b8580, 1, RI_ALL_ONLINE },
-	{ 0x1b85c0, 19, RI_E2E3E3B0_ONLINE },
-	{ 0x1b8800, 1, RI_ALL_ONLINE },
-	{ 0x1b8840, 1, RI_ALL_ONLINE },
-	{ 0x1b8880, 1, RI_ALL_ONLINE },
-	{ 0x1b88c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8900, 1, RI_ALL_ONLINE },
-	{ 0x1b8940, 1, RI_ALL_ONLINE },
-	{ 0x1b8980, 1, RI_ALL_ONLINE },
-	{ 0x1b89c0, 1, RI_ALL_ONLINE },
-	{ 0x1b8a00, 1, RI_ALL_ONLINE },
-	{ 0x1b8a40, 1, RI_ALL_ONLINE },
-	{ 0x1b8a80, 1, RI_ALL_ONLINE },
-	{ 0x1b8ac0, 1, RI_ALL_ONLINE },
-	{ 0x1b8b00, 1, RI_ALL_ONLINE },
-	{ 0x1b8b40, 1, RI_ALL_ONLINE },
-	{ 0x1b8b80, 1, RI_ALL_ONLINE },
-	{ 0x1b8bc0, 1, RI_ALL_ONLINE },
-	{ 0x1b8c00, 1, RI_ALL_ONLINE },
-	{ 0x1b8c40, 1, RI_ALL_ONLINE },
-	{ 0x1b8c80, 1, RI_ALL_ONLINE },
-	{ 0x1b8cc0, 1, RI_ALL_ONLINE },
-	{ 0x1b8cc4, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1b8d00, 1, RI_ALL_ONLINE },
-	{ 0x1b8d40, 1, RI_ALL_ONLINE },
-	{ 0x1b8d80, 1, RI_ALL_ONLINE },
-	{ 0x1b8dc0, 1, RI_ALL_ONLINE },
-	{ 0x1b8e00, 1, RI_ALL_ONLINE },
-	{ 0x1b8e40, 1, RI_ALL_ONLINE },
-	{ 0x1b8e80, 1, RI_ALL_ONLINE },
-	{ 0x1b8e84, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1b8ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b8f00, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b8f40, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b8f80, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b8fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x1b8fc4, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x1b8fd0, 6, RI_E2E3E3B0_ONLINE },
-	{ 0x1b8fe8, 2, RI_E3E3B0_ONLINE },
-	{ 0x1b9000, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x1b9040, 3, RI_E2E3E3B0_ONLINE },
-	{ 0x1b905c, 1, RI_E3E3B0_ONLINE },
-	{ 0x1b9064, 1, RI_E3B0_ONLINE },
-	{ 0x1b9080, 10, RI_E3B0_ONLINE },
-	{ 0x1b9400, 14, RI_E2E3E3B0_OFFLINE },
-	{ 0x1b943c, 19, RI_E2E3E3B0_OFFLINE },
-	{ 0x1b9490, 10, RI_E2E3E3B0_OFFLINE },
-	{ 0x1c0000, 2, RI_ALL_ONLINE },
-	{ 0x200000, 65, RI_ALL_ONLINE },
-	{ 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x200200, 58, RI_ALL_ONLINE },
-	{ 0x200340, 4, RI_ALL_ONLINE },
-	{ 0x200380, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x200388, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x200390, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x200398, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2003a0, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2003a8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x200404, 255, RI_E1E1H_OFFLINE },
-	{ 0x202000, 4, RI_ALL_ONLINE },
-	{ 0x202010, 2044, RI_ALL_OFFLINE },
-	{ 0x204000, 4, RI_E3E3B0_ONLINE },
-	{ 0x220000, 1, RI_ALL_ONLINE },
-	{ 0x220004, 5631, RI_ALL_OFFLINE },
-	{ 0x225800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x228000, 1, RI_ALL_ONLINE },
-	{ 0x228004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x230000, 1, RI_ALL_ONLINE },
-	{ 0x230004, 15, RI_E1H_OFFLINE },
-	{ 0x230040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x230044, 239, RI_E1H_OFFLINE },
-	{ 0x230400, 1, RI_ALL_ONLINE },
-	{ 0x230404, 255, RI_E1H_OFFLINE },
-	{ 0x230800, 1, RI_ALL_ONLINE },
-	{ 0x230840, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x230c00, 1, RI_ALL_ONLINE },
-	{ 0x231000, 1, RI_ALL_ONLINE },
-	{ 0x231040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x231400, 1, RI_ALL_ONLINE },
-	{ 0x231440, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x231480, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2314c0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x231800, 128, RI_ALL_OFFLINE },
-	{ 0x231c00, 128, RI_ALL_OFFLINE },
-	{ 0x232000, 1, RI_ALL_ONLINE },
-	{ 0x232400, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x232404, 5631, RI_E2E3E3B0_OFFLINE },
-	{ 0x238000, 1, RI_ALL_ONLINE },
-	{ 0x238040, 1, RI_ALL_ONLINE },
-	{ 0x238080, 1, RI_ALL_ONLINE },
-	{ 0x2380c0, 1, RI_ALL_ONLINE },
-	{ 0x238100, 1, RI_ALL_ONLINE },
-	{ 0x238140, 1, RI_ALL_ONLINE },
-	{ 0x238180, 1, RI_ALL_ONLINE },
-	{ 0x2381c0, 1, RI_ALL_ONLINE },
-	{ 0x238200, 1, RI_ALL_ONLINE },
-	{ 0x238240, 1, RI_ALL_ONLINE },
-	{ 0x238280, 1, RI_ALL_ONLINE },
-	{ 0x2382c0, 1, RI_ALL_ONLINE },
-	{ 0x238300, 1, RI_ALL_ONLINE },
-	{ 0x238340, 1, RI_ALL_ONLINE },
-	{ 0x238380, 1, RI_ALL_ONLINE },
-	{ 0x2383c0, 1, RI_ALL_ONLINE },
-	{ 0x238400, 1, RI_ALL_ONLINE },
-	{ 0x238440, 1, RI_ALL_ONLINE },
-	{ 0x238480, 1, RI_ALL_ONLINE },
-	{ 0x2384c0, 1, RI_ALL_ONLINE },
-	{ 0x238500, 1, RI_ALL_ONLINE },
-	{ 0x238540, 1, RI_ALL_ONLINE },
-	{ 0x238580, 1, RI_ALL_ONLINE },
-	{ 0x2385c0, 19, RI_E2E3E3B0_ONLINE },
-	{ 0x238800, 1, RI_ALL_ONLINE },
-	{ 0x238840, 1, RI_ALL_ONLINE },
-	{ 0x238880, 1, RI_ALL_ONLINE },
-	{ 0x2388c0, 1, RI_ALL_ONLINE },
-	{ 0x238900, 1, RI_ALL_ONLINE },
-	{ 0x238940, 1, RI_ALL_ONLINE },
-	{ 0x238980, 1, RI_ALL_ONLINE },
-	{ 0x2389c0, 1, RI_ALL_ONLINE },
-	{ 0x238a00, 1, RI_ALL_ONLINE },
-	{ 0x238a40, 1, RI_ALL_ONLINE },
-	{ 0x238a80, 1, RI_ALL_ONLINE },
-	{ 0x238ac0, 1, RI_ALL_ONLINE },
-	{ 0x238b00, 1, RI_ALL_ONLINE },
-	{ 0x238b40, 1, RI_ALL_ONLINE },
-	{ 0x238b80, 1, RI_ALL_ONLINE },
-	{ 0x238bc0, 1, RI_ALL_ONLINE },
-	{ 0x238c00, 1, RI_ALL_ONLINE },
-	{ 0x238c40, 1, RI_ALL_ONLINE },
-	{ 0x238c80, 1, RI_ALL_ONLINE },
-	{ 0x238cc0, 1, RI_ALL_ONLINE },
-	{ 0x238cc4, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x238d00, 1, RI_ALL_ONLINE },
-	{ 0x238d40, 1, RI_ALL_ONLINE },
-	{ 0x238d80, 1, RI_ALL_ONLINE },
-	{ 0x238dc0, 1, RI_ALL_ONLINE },
-	{ 0x238e00, 1, RI_ALL_ONLINE },
-	{ 0x238e40, 1, RI_ALL_ONLINE },
-	{ 0x238e80, 1, RI_ALL_ONLINE },
-	{ 0x238e84, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x238ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x238f00, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x238f40, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x238f80, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x238fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x238fc4, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x238fd0, 6, RI_E2E3E3B0_ONLINE },
-	{ 0x238fe8, 2, RI_E3E3B0_ONLINE },
-	{ 0x239000, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x239040, 3, RI_E2E3E3B0_ONLINE },
-	{ 0x23905c, 1, RI_E3E3B0_ONLINE },
-	{ 0x239064, 1, RI_E3B0_ONLINE },
-	{ 0x239080, 10, RI_E3B0_ONLINE },
-	{ 0x240000, 2, RI_ALL_ONLINE },
-	{ 0x280000, 65, RI_ALL_ONLINE },
-	{ 0x28014c, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x280200, 58, RI_ALL_ONLINE },
-	{ 0x280340, 4, RI_ALL_ONLINE },
-	{ 0x280380, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x280388, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x280390, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x280398, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2803a0, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2803a8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x280404, 255, RI_E1E1H_OFFLINE },
-	{ 0x282000, 4, RI_ALL_ONLINE },
-	{ 0x282010, 2044, RI_ALL_OFFLINE },
-	{ 0x284000, 4, RI_E3E3B0_ONLINE },
-	{ 0x2a0000, 1, RI_ALL_ONLINE },
-	{ 0x2a0004, 5631, RI_ALL_OFFLINE },
-	{ 0x2a5800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x2a8000, 1, RI_ALL_ONLINE },
-	{ 0x2a8004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x2b0000, 1, RI_ALL_ONLINE },
-	{ 0x2b0004, 15, RI_E1H_OFFLINE },
-	{ 0x2b0040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b0044, 239, RI_E1H_OFFLINE },
-	{ 0x2b0400, 1, RI_ALL_ONLINE },
-	{ 0x2b0404, 255, RI_E1H_OFFLINE },
-	{ 0x2b0800, 1, RI_ALL_ONLINE },
-	{ 0x2b0840, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b0c00, 1, RI_ALL_ONLINE },
-	{ 0x2b1000, 1, RI_ALL_ONLINE },
-	{ 0x2b1040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b1400, 1, RI_ALL_ONLINE },
-	{ 0x2b1440, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b1480, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b14c0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b1800, 128, RI_ALL_OFFLINE },
-	{ 0x2b1c00, 128, RI_ALL_OFFLINE },
-	{ 0x2b2000, 1, RI_ALL_ONLINE },
-	{ 0x2b2400, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b2404, 5631, RI_E2E3E3B0_OFFLINE },
-	{ 0x2b8000, 1, RI_ALL_ONLINE },
-	{ 0x2b8040, 1, RI_ALL_ONLINE },
-	{ 0x2b8080, 1, RI_ALL_ONLINE },
-	{ 0x2b80c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8100, 1, RI_ALL_ONLINE },
-	{ 0x2b8140, 1, RI_ALL_ONLINE },
-	{ 0x2b8180, 1, RI_ALL_ONLINE },
-	{ 0x2b81c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8200, 1, RI_ALL_ONLINE },
-	{ 0x2b8240, 1, RI_ALL_ONLINE },
-	{ 0x2b8280, 1, RI_ALL_ONLINE },
-	{ 0x2b82c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8300, 1, RI_ALL_ONLINE },
-	{ 0x2b8340, 1, RI_ALL_ONLINE },
-	{ 0x2b8380, 1, RI_ALL_ONLINE },
-	{ 0x2b83c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8400, 1, RI_ALL_ONLINE },
-	{ 0x2b8440, 1, RI_ALL_ONLINE },
-	{ 0x2b8480, 1, RI_ALL_ONLINE },
-	{ 0x2b84c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8500, 1, RI_ALL_ONLINE },
-	{ 0x2b8540, 1, RI_ALL_ONLINE },
-	{ 0x2b8580, 1, RI_ALL_ONLINE },
-	{ 0x2b85c0, 19, RI_E2E3E3B0_ONLINE },
-	{ 0x2b8800, 1, RI_ALL_ONLINE },
-	{ 0x2b8840, 1, RI_ALL_ONLINE },
-	{ 0x2b8880, 1, RI_ALL_ONLINE },
-	{ 0x2b88c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8900, 1, RI_ALL_ONLINE },
-	{ 0x2b8940, 1, RI_ALL_ONLINE },
-	{ 0x2b8980, 1, RI_ALL_ONLINE },
-	{ 0x2b89c0, 1, RI_ALL_ONLINE },
-	{ 0x2b8a00, 1, RI_ALL_ONLINE },
-	{ 0x2b8a40, 1, RI_ALL_ONLINE },
-	{ 0x2b8a80, 1, RI_ALL_ONLINE },
-	{ 0x2b8ac0, 1, RI_ALL_ONLINE },
-	{ 0x2b8b00, 1, RI_ALL_ONLINE },
-	{ 0x2b8b40, 1, RI_ALL_ONLINE },
-	{ 0x2b8b80, 1, RI_ALL_ONLINE },
-	{ 0x2b8bc0, 1, RI_ALL_ONLINE },
-	{ 0x2b8c00, 1, RI_ALL_ONLINE },
-	{ 0x2b8c40, 1, RI_ALL_ONLINE },
-	{ 0x2b8c80, 1, RI_ALL_ONLINE },
-	{ 0x2b8cc0, 1, RI_ALL_ONLINE },
-	{ 0x2b8cc4, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2b8d00, 1, RI_ALL_ONLINE },
-	{ 0x2b8d40, 1, RI_ALL_ONLINE },
-	{ 0x2b8d80, 1, RI_ALL_ONLINE },
-	{ 0x2b8dc0, 1, RI_ALL_ONLINE },
-	{ 0x2b8e00, 1, RI_ALL_ONLINE },
-	{ 0x2b8e40, 1, RI_ALL_ONLINE },
-	{ 0x2b8e80, 1, RI_ALL_ONLINE },
-	{ 0x2b8e84, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2b8ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b8f00, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b8f40, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b8f80, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b8fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x2b8fc4, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x2b8fd0, 6, RI_E2E3E3B0_ONLINE },
-	{ 0x2b8fe8, 2, RI_E3E3B0_ONLINE },
-	{ 0x2b9000, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x2b9040, 3, RI_E2E3E3B0_ONLINE },
-	{ 0x2b905c, 1, RI_E3E3B0_ONLINE },
-	{ 0x2b9064, 1, RI_E3B0_ONLINE },
-	{ 0x2b9080, 10, RI_E3B0_ONLINE },
-	{ 0x2b9400, 14, RI_E2E3E3B0_ONLINE },
-	{ 0x2b943c, 19, RI_E2E3E3B0_ONLINE },
-	{ 0x2b9490, 10, RI_E2E3E3B0_ONLINE },
-	{ 0x2c0000, 2, RI_ALL_ONLINE },
-	{ 0x300000, 65, RI_ALL_ONLINE },
-	{ 0x30014c, 2, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x300200, 58, RI_ALL_ONLINE },
-	{ 0x300340, 4, RI_ALL_ONLINE },
-	{ 0x300380, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x300388, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x300390, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x300398, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x3003a0, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x3003a8, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x300404, 255, RI_E1E1H_OFFLINE },
-	{ 0x302000, 4, RI_ALL_ONLINE },
-	{ 0x302010, 2044, RI_ALL_OFFLINE },
-	{ 0x304000, 4, RI_E3E3B0_ONLINE },
-	{ 0x320000, 1, RI_ALL_ONLINE },
-	{ 0x320004, 5631, RI_ALL_OFFLINE },
-	{ 0x325800, 2560, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x328000, 1, RI_ALL_ONLINE },
-	{ 0x328004, 8191, RI_E1HE2E3E3B0_OFFLINE },
-	{ 0x330000, 1, RI_ALL_ONLINE },
-	{ 0x330004, 15, RI_E1H_OFFLINE },
-	{ 0x330040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x330044, 239, RI_E1H_OFFLINE },
-	{ 0x330400, 1, RI_ALL_ONLINE },
-	{ 0x330404, 255, RI_E1H_OFFLINE },
-	{ 0x330800, 1, RI_ALL_ONLINE },
-	{ 0x330840, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x330c00, 1, RI_ALL_ONLINE },
-	{ 0x331000, 1, RI_ALL_ONLINE },
-	{ 0x331040, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x331400, 1, RI_ALL_ONLINE },
-	{ 0x331440, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x331480, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x3314c0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x331800, 128, RI_ALL_OFFLINE },
-	{ 0x331c00, 128, RI_ALL_OFFLINE },
-	{ 0x332000, 1, RI_ALL_ONLINE },
-	{ 0x332400, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x332404, 5631, RI_E2E3E3B0_OFFLINE },
-	{ 0x338000, 1, RI_ALL_ONLINE },
-	{ 0x338040, 1, RI_ALL_ONLINE },
-	{ 0x338080, 1, RI_ALL_ONLINE },
-	{ 0x3380c0, 1, RI_ALL_ONLINE },
-	{ 0x338100, 1, RI_ALL_ONLINE },
-	{ 0x338140, 1, RI_ALL_ONLINE },
-	{ 0x338180, 1, RI_ALL_ONLINE },
-	{ 0x3381c0, 1, RI_ALL_ONLINE },
-	{ 0x338200, 1, RI_ALL_ONLINE },
-	{ 0x338240, 1, RI_ALL_ONLINE },
-	{ 0x338280, 1, RI_ALL_ONLINE },
-	{ 0x3382c0, 1, RI_ALL_ONLINE },
-	{ 0x338300, 1, RI_ALL_ONLINE },
-	{ 0x338340, 1, RI_ALL_ONLINE },
-	{ 0x338380, 1, RI_ALL_ONLINE },
-	{ 0x3383c0, 1, RI_ALL_ONLINE },
-	{ 0x338400, 1, RI_ALL_ONLINE },
-	{ 0x338440, 1, RI_ALL_ONLINE },
-	{ 0x338480, 1, RI_ALL_ONLINE },
-	{ 0x3384c0, 1, RI_ALL_ONLINE },
-	{ 0x338500, 1, RI_ALL_ONLINE },
-	{ 0x338540, 1, RI_ALL_ONLINE },
-	{ 0x338580, 1, RI_ALL_ONLINE },
-	{ 0x3385c0, 19, RI_E2E3E3B0_ONLINE },
-	{ 0x338800, 1, RI_ALL_ONLINE },
-	{ 0x338840, 1, RI_ALL_ONLINE },
-	{ 0x338880, 1, RI_ALL_ONLINE },
-	{ 0x3388c0, 1, RI_ALL_ONLINE },
-	{ 0x338900, 1, RI_ALL_ONLINE },
-	{ 0x338940, 1, RI_ALL_ONLINE },
-	{ 0x338980, 1, RI_ALL_ONLINE },
-	{ 0x3389c0, 1, RI_ALL_ONLINE },
-	{ 0x338a00, 1, RI_ALL_ONLINE },
-	{ 0x338a40, 1, RI_ALL_ONLINE },
-	{ 0x338a80, 1, RI_ALL_ONLINE },
-	{ 0x338ac0, 1, RI_ALL_ONLINE },
-	{ 0x338b00, 1, RI_ALL_ONLINE },
-	{ 0x338b40, 1, RI_ALL_ONLINE },
-	{ 0x338b80, 1, RI_ALL_ONLINE },
-	{ 0x338bc0, 1, RI_ALL_ONLINE },
-	{ 0x338c00, 1, RI_ALL_ONLINE },
-	{ 0x338c40, 1, RI_ALL_ONLINE },
-	{ 0x338c80, 1, RI_ALL_ONLINE },
-	{ 0x338cc0, 1, RI_ALL_ONLINE },
-	{ 0x338cc4, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x338d00, 1, RI_ALL_ONLINE },
-	{ 0x338d40, 1, RI_ALL_ONLINE },
-	{ 0x338d80, 1, RI_ALL_ONLINE },
-	{ 0x338dc0, 1, RI_ALL_ONLINE },
-	{ 0x338e00, 1, RI_ALL_ONLINE },
-	{ 0x338e40, 1, RI_ALL_ONLINE },
-	{ 0x338e80, 1, RI_ALL_ONLINE },
-	{ 0x338e84, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x338ec0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x338f00, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x338f40, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x338f80, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x338fc0, 1, RI_E1HE2E3E3B0_ONLINE },
-	{ 0x338fc4, 2, RI_E2E3E3B0_ONLINE },
-	{ 0x338fd0, 6, RI_E2E3E3B0_ONLINE },
-	{ 0x338fe8, 2, RI_E3E3B0_ONLINE },
-	{ 0x339000, 1, RI_E2E3E3B0_ONLINE },
-	{ 0x339040, 3, RI_E2E3E3B0_ONLINE },
-	{ 0x33905c, 1, RI_E3E3B0_ONLINE },
-	{ 0x339064, 1, RI_E3B0_ONLINE },
-	{ 0x339080, 10, RI_E3B0_ONLINE },
-	{ 0x340000, 2, RI_ALL_ONLINE },
+	{ 0x2000, 1, 0x1f, 0xfff},
+	{ 0x2004, 1, 0x1f, 0x1fff},
+	{ 0x2008, 25, 0x1f, 0xfff},
+	{ 0x206c, 1, 0x1f, 0x1fff},
+	{ 0x2070, 313, 0x1f, 0xfff},
+	{ 0x2800, 103, 0x1f, 0xfff},
+	{ 0x3000, 287, 0x1f, 0xfff},
+	{ 0x3800, 331, 0x1f, 0xfff},
+	{ 0x8800, 6, 0x1f, 0x924},
+	{ 0x8818, 1, 0x1e, 0x924},
+	{ 0x9000, 4, 0x1c, 0x924},
+	{ 0x9010, 7, 0x1c, 0xfff},
+	{ 0x902c, 1, 0x1c, 0x924},
+	{ 0x9030, 1, 0x1c, 0xfff},
+	{ 0x9034, 13, 0x1c, 0x924},
+	{ 0x9068, 16, 0x1c, 0xfff},
+	{ 0x90a8, 98, 0x1c, 0x924},
+	{ 0x9230, 2, 0x1c, 0xfff},
+	{ 0x9238, 3, 0x1c, 0x924},
+	{ 0x9244, 1, 0x1c, 0xfff},
+	{ 0x9248, 1, 0x1c, 0x924},
+	{ 0x924c, 1, 0x4, 0x924},
+	{ 0x9250, 16, 0x1c, 0x924},
+	{ 0x92a8, 2, 0x1c, 0x1fff},
+	{ 0x92b4, 1, 0x1c, 0x1fff},
+	{ 0x9400, 33, 0x1c, 0x924},
+	{ 0x9484, 5, 0x18, 0x924},
+	{ 0xa000, 27, 0x1f, 0x924},
+	{ 0xa06c, 1, 0x3, 0x924},
+	{ 0xa070, 2, 0x1f, 0x924},
+	{ 0xa078, 1, 0x1f, 0x1fff},
+	{ 0xa07c, 31, 0x1f, 0x924},
+	{ 0xa0f8, 1, 0x1f, 0x1fff},
+	{ 0xa0fc, 3, 0x1f, 0x924},
+	{ 0xa108, 1, 0x1f, 0x1fff},
+	{ 0xa10c, 3, 0x1f, 0x924},
+	{ 0xa118, 1, 0x1f, 0x1fff},
+	{ 0xa11c, 28, 0x1f, 0x924},
+	{ 0xa18c, 4, 0x3, 0x924},
+	{ 0xa19c, 3, 0x1f, 0x924},
+	{ 0xa1a8, 1, 0x1f, 0x1fff},
+	{ 0xa1ac, 3, 0x1f, 0x924},
+	{ 0xa1b8, 1, 0x1f, 0x1fff},
+	{ 0xa1bc, 54, 0x1f, 0x924},
+	{ 0xa294, 2, 0x3, 0x924},
+	{ 0xa29c, 2, 0x1f, 0x924},
+	{ 0xa2a4, 2, 0x7, 0x924},
+	{ 0xa2ac, 2, 0x1f, 0x924},
+	{ 0xa2b4, 1, 0x1f, 0x1fff},
+	{ 0xa2b8, 49, 0x1f, 0x924},
+	{ 0xa38c, 2, 0x1f, 0x1fff},
+	{ 0xa398, 1, 0x1f, 0x1fff},
+	{ 0xa39c, 7, 0x1e, 0x924},
+	{ 0xa3b8, 2, 0x18, 0x924},
+	{ 0xa3c0, 1, 0x1e, 0x924},
+	{ 0xa3c4, 1, 0x1e, 0xfff},
+	{ 0xa3c8, 1, 0x1e, 0x924},
+	{ 0xa3d0, 1, 0x1e, 0x924},
+	{ 0xa3d8, 1, 0x1e, 0x924},
+	{ 0xa3e0, 1, 0x1e, 0x924},
+	{ 0xa3e8, 1, 0x1e, 0x924},
+	{ 0xa3f0, 1, 0x1e, 0x924},
+	{ 0xa3f8, 1, 0x1e, 0x924},
+	{ 0xa400, 1, 0x1f, 0x924},
+	{ 0xa404, 1, 0x1f, 0xfff},
+	{ 0xa408, 2, 0x1f, 0x1fff},
+	{ 0xa410, 7, 0x1f, 0x924},
+	{ 0xa42c, 12, 0x1f, 0xfff},
+	{ 0xa45c, 1, 0x1f, 0x924},
+	{ 0xa460, 1, 0x1f, 0x1924},
+	{ 0xa464, 15, 0x1f, 0x924},
+	{ 0xa4a0, 1, 0x7, 0x924},
+	{ 0xa4a4, 2, 0x1f, 0x924},
+	{ 0xa4ac, 2, 0x3, 0x924},
+	{ 0xa4b4, 1, 0x7, 0x924},
+	{ 0xa4b8, 2, 0x3, 0x924},
+	{ 0xa4c0, 3, 0x1f, 0x924},
+	{ 0xa4cc, 5, 0x3, 0x924},
+	{ 0xa4e0, 3, 0x1f, 0x924},
+	{ 0xa4fc, 2, 0x1f, 0x924},
+	{ 0xa504, 1, 0x3, 0x924},
+	{ 0xa508, 3, 0x1f, 0x924},
+	{ 0xa518, 1, 0x1f, 0x924},
+	{ 0xa520, 1, 0x1f, 0x924},
+	{ 0xa528, 1, 0x1f, 0x924},
+	{ 0xa530, 1, 0x1f, 0x924},
+	{ 0xa538, 1, 0x1f, 0x924},
+	{ 0xa540, 1, 0x1f, 0x924},
+	{ 0xa548, 1, 0x3, 0x924},
+	{ 0xa550, 1, 0x3, 0x924},
+	{ 0xa558, 1, 0x3, 0x924},
+	{ 0xa560, 1, 0x3, 0x924},
+	{ 0xa568, 1, 0x3, 0x924},
+	{ 0xa570, 1, 0x1f, 0x924},
+	{ 0xa580, 1, 0x1f, 0x1fff},
+	{ 0xa590, 1, 0x1f, 0x1fff},
+	{ 0xa5a0, 1, 0x7, 0x924},
+	{ 0xa5c0, 1, 0x1f, 0x924},
+	{ 0xa5e0, 1, 0x1e, 0x924},
+	{ 0xa5e8, 1, 0x1e, 0x924},
+	{ 0xa5f0, 1, 0x1e, 0x924},
+	{ 0xa5f8, 1, 0x6, 0x924},
+	{ 0xa5fc, 1, 0x1e, 0x924},
+	{ 0xa600, 5, 0x1e, 0xfff},
+	{ 0xa614, 1, 0x1e, 0x924},
+	{ 0xa618, 1, 0x1e, 0xfff},
+	{ 0xa61c, 1, 0x1e, 0x924},
+	{ 0xa620, 6, 0x1c, 0x924},
+	{ 0xa638, 20, 0x4, 0x924},
+	{ 0xa688, 35, 0x1c, 0x924},
+	{ 0xa714, 1, 0x1c, 0xfff},
+	{ 0xa718, 2, 0x1c, 0x924},
+	{ 0xa720, 1, 0x1c, 0xfff},
+	{ 0xa724, 3, 0x1c, 0x924},
+	{ 0xa730, 1, 0x4, 0x924},
+	{ 0xa734, 2, 0x1c, 0x924},
+	{ 0xa73c, 4, 0x4, 0x924},
+	{ 0xa74c, 1, 0x1c, 0x924},
+	{ 0xa750, 1, 0x1c, 0xfff},
+	{ 0xa754, 3, 0x1c, 0x924},
+	{ 0xa760, 5, 0x4, 0x924},
+	{ 0xa774, 7, 0x1c, 0x924},
+	{ 0xa790, 15, 0x4, 0x924},
+	{ 0xa7cc, 4, 0x1c, 0x924},
+	{ 0xa7e0, 6, 0x18, 0x924},
+	{ 0xa800, 18, 0x4, 0x924},
+	{ 0xa848, 33, 0x1c, 0x924},
+	{ 0xa8cc, 2, 0x18, 0x924},
+	{ 0xa8d4, 4, 0x1c, 0x924},
+	{ 0xa8e4, 1, 0x18, 0x924},
+	{ 0xa8e8, 1, 0x1c, 0x924},
+	{ 0xa8f0, 1, 0x1c, 0x924},
+	{ 0xa8f8, 30, 0x18, 0x924},
+	{ 0xa974, 73, 0x18, 0x924},
+	{ 0xac30, 1, 0x18, 0x924},
+	{ 0xac40, 1, 0x18, 0x924},
+	{ 0xac50, 1, 0x18, 0x924},
+	{ 0xac60, 1, 0x10, 0x924},
+	{ 0x10000, 9, 0x1f, 0x924},
+	{ 0x10024, 1, 0x7, 0x924},
+	{ 0x10028, 5, 0x1f, 0x924},
+	{ 0x1003c, 6, 0x7, 0x924},
+	{ 0x10054, 20, 0x1f, 0x924},
+	{ 0x100a4, 4, 0x7, 0x924},
+	{ 0x100b4, 11, 0x1f, 0x924},
+	{ 0x100e0, 4, 0x7, 0x924},
+	{ 0x100f0, 8, 0x1f, 0x924},
+	{ 0x10110, 6, 0x7, 0x924},
+	{ 0x10128, 110, 0x1f, 0x924},
+	{ 0x102e0, 4, 0x7, 0x924},
+	{ 0x102f0, 18, 0x1f, 0x924},
+	{ 0x10338, 20, 0x7, 0x924},
+	{ 0x10388, 10, 0x1f, 0x924},
+	{ 0x103d0, 2, 0x3, 0x1fff},
+	{ 0x103dc, 1, 0x3, 0x1fff},
+	{ 0x10400, 6, 0x7, 0x924},
+	{ 0x10418, 1, 0x1f, 0xfff},
+	{ 0x1041c, 1, 0x1f, 0x924},
+	{ 0x10420, 1, 0x1f, 0xfff},
+	{ 0x10424, 1, 0x1f, 0x924},
+	{ 0x10428, 1, 0x1f, 0xfff},
+	{ 0x1042c, 1, 0x1f, 0x924},
+	{ 0x10430, 10, 0x7, 0x924},
+	{ 0x10458, 2, 0x1f, 0x924},
+	{ 0x10460, 1, 0x1f, 0xfff},
+	{ 0x10464, 4, 0x1f, 0x924},
+	{ 0x10474, 1, 0x1f, 0xfff},
+	{ 0x10478, 14, 0x1f, 0x924},
+	{ 0x104b0, 12, 0x7, 0x924},
+	{ 0x104e0, 1, 0x1f, 0xfff},
+	{ 0x104e8, 1, 0x1f, 0x924},
+	{ 0x104ec, 1, 0x1f, 0xfff},
+	{ 0x104f4, 1, 0x1f, 0x924},
+	{ 0x104f8, 1, 0x1f, 0xfff},
+	{ 0x10500, 2, 0x1f, 0x924},
+	{ 0x10508, 1, 0x1f, 0xfff},
+	{ 0x1050c, 9, 0x1f, 0x924},
+	{ 0x10530, 1, 0x1f, 0xfff},
+	{ 0x10534, 1, 0x1f, 0x924},
+	{ 0x10538, 1, 0x1f, 0xfff},
+	{ 0x1053c, 3, 0x1f, 0x924},
+	{ 0x10548, 1, 0x1f, 0xfff},
+	{ 0x1054c, 3, 0x1f, 0x924},
+	{ 0x10558, 1, 0x1f, 0xfff},
+	{ 0x1055c, 123, 0x1f, 0x924},
+	{ 0x10750, 2, 0x7, 0x924},
+	{ 0x10760, 2, 0x7, 0x924},
+	{ 0x10770, 2, 0x7, 0x924},
+	{ 0x10780, 2, 0x7, 0x924},
+	{ 0x10790, 2, 0x1f, 0x924},
+	{ 0x107a0, 2, 0x7, 0x924},
+	{ 0x107b0, 2, 0x7, 0x924},
+	{ 0x107c0, 2, 0x7, 0x924},
+	{ 0x107d0, 2, 0x7, 0x924},
+	{ 0x107e0, 2, 0x1f, 0x924},
+	{ 0x10880, 2, 0x1f, 0x924},
+	{ 0x10900, 2, 0x1f, 0x924},
+	{ 0x16000, 1, 0x6, 0x924},
+	{ 0x16004, 25, 0x1e, 0x924},
+	{ 0x16070, 8, 0x1e, 0x924},
+	{ 0x16090, 4, 0xe, 0x924},
+	{ 0x160a0, 6, 0x1e, 0x924},
+	{ 0x160c0, 7, 0x1e, 0x924},
+	{ 0x160dc, 2, 0x6, 0x924},
+	{ 0x160e4, 6, 0x1e, 0x924},
+	{ 0x160fc, 4, 0x1e, 0x1fff},
+	{ 0x1610c, 2, 0x6, 0x924},
+	{ 0x16114, 6, 0x1e, 0x924},
+	{ 0x16140, 48, 0x1e, 0x1fff},
+	{ 0x16204, 5, 0x1e, 0x924},
+	{ 0x18000, 1, 0x1e, 0x924},
+	{ 0x18008, 1, 0x1e, 0x924},
+	{ 0x18010, 35, 0x1c, 0x924},
+	{ 0x180a4, 2, 0x1c, 0x924},
+	{ 0x180c0, 9, 0x1c, 0x924},
+	{ 0x180e4, 1, 0xc, 0x924},
+	{ 0x180e8, 2, 0x1c, 0x924},
+	{ 0x180f0, 1, 0xc, 0x924},
+	{ 0x180f4, 79, 0x1c, 0x924},
+	{ 0x18230, 1, 0xc, 0x924},
+	{ 0x18234, 2, 0x1c, 0x924},
+	{ 0x1823c, 1, 0xc, 0x924},
+	{ 0x18240, 13, 0x1c, 0x924},
+	{ 0x18274, 1, 0x4, 0x924},
+	{ 0x18278, 12, 0x1c, 0x924},
+	{ 0x182a8, 1, 0x1c, 0xfff},
+	{ 0x182ac, 3, 0x1c, 0x924},
+	{ 0x182b8, 1, 0x1c, 0xfff},
+	{ 0x182bc, 19, 0x1c, 0x924},
+	{ 0x18308, 1, 0x1c, 0xfff},
+	{ 0x1830c, 3, 0x1c, 0x924},
+	{ 0x18318, 1, 0x1c, 0xfff},
+	{ 0x1831c, 7, 0x1c, 0x924},
+	{ 0x18338, 1, 0x1c, 0xfff},
+	{ 0x1833c, 3, 0x1c, 0x924},
+	{ 0x18348, 1, 0x1c, 0xfff},
+	{ 0x1834c, 28, 0x1c, 0x924},
+	{ 0x183bc, 2, 0x1c, 0x1fff},
+	{ 0x183c8, 3, 0x1c, 0x1fff},
+	{ 0x183d8, 1, 0x1c, 0x1fff},
+	{ 0x18440, 48, 0x1c, 0x1fff},
+	{ 0x18500, 15, 0x1c, 0x924},
+	{ 0x18570, 1, 0x18, 0xfff},
+	{ 0x18574, 1, 0x18, 0x924},
+	{ 0x18578, 1, 0x18, 0xfff},
+	{ 0x1857c, 4, 0x18, 0x924},
+	{ 0x1858c, 1, 0x18, 0xfff},
+	{ 0x18590, 1, 0x18, 0x924},
+	{ 0x18594, 1, 0x18, 0xfff},
+	{ 0x18598, 32, 0x18, 0x924},
+	{ 0x18618, 5, 0x10, 0x924},
+	{ 0x1862c, 4, 0x10, 0xfff},
+	{ 0x1863c, 16, 0x10, 0x924},
+	{ 0x18680, 44, 0x10, 0x924},
+	{ 0x18748, 12, 0x10, 0x924},
+	{ 0x18788, 1, 0x10, 0x924},
+	{ 0x1879c, 6, 0x10, 0x924},
+	{ 0x187c4, 51, 0x10, 0x924},
+	{ 0x18a00, 48, 0x10, 0x924},
+	{ 0x20000, 24, 0x1f, 0x924},
+	{ 0x20060, 8, 0x1f, 0x9e4},
+	{ 0x20080, 94, 0x1f, 0x924},
+	{ 0x201f8, 1, 0x3, 0x924},
+	{ 0x201fc, 1, 0x1f, 0x924},
+	{ 0x20200, 1, 0x3, 0x924},
+	{ 0x20204, 1, 0x1f, 0x924},
+	{ 0x20208, 1, 0x3, 0x924},
+	{ 0x2020c, 4, 0x1f, 0x924},
+	{ 0x2021c, 11, 0x1f, 0xfff},
+	{ 0x20248, 24, 0x1f, 0x924},
+	{ 0x202b8, 2, 0x1f, 0x1fff},
+	{ 0x202c4, 1, 0x1f, 0x1fff},
+	{ 0x202c8, 1, 0x1c, 0x924},
+	{ 0x202d8, 4, 0x1c, 0x924},
+	{ 0x202f0, 1, 0x10, 0x924},
+	{ 0x20400, 1, 0x1f, 0x924},
+	{ 0x20404, 1, 0x1f, 0xfff},
+	{ 0x2040c, 2, 0x1f, 0xfff},
+	{ 0x20414, 2, 0x1f, 0x924},
+	{ 0x2041c, 2, 0x1f, 0xfff},
+	{ 0x20424, 2, 0x1f, 0x924},
+	{ 0x2042c, 18, 0x1e, 0x924},
+	{ 0x20480, 1, 0x1f, 0x924},
+	{ 0x20500, 1, 0x1f, 0x924},
+	{ 0x20600, 1, 0x1f, 0x924},
+	{ 0x28000, 1, 0x1f, 0x9e4},
+	{ 0x28004, 255, 0x1f, 0x180},
+	{ 0x28400, 1, 0x1f, 0x1c0},
+	{ 0x28404, 255, 0x1f, 0x180},
+	{ 0x28800, 1, 0x1f, 0x1c0},
+	{ 0x28804, 255, 0x1f, 0x180},
+	{ 0x28c00, 1, 0x1f, 0x1c0},
+	{ 0x28c04, 255, 0x1f, 0x180},
+	{ 0x29000, 1, 0x1f, 0x1c0},
+	{ 0x29004, 255, 0x1f, 0x180},
+	{ 0x29400, 1, 0x1f, 0x1c0},
+	{ 0x29404, 255, 0x1f, 0x180},
+	{ 0x29800, 1, 0x1f, 0x1c0},
+	{ 0x29804, 255, 0x1f, 0x180},
+	{ 0x29c00, 1, 0x1f, 0x1c0},
+	{ 0x29c04, 255, 0x1f, 0x180},
+	{ 0x2a000, 1, 0x1f, 0x1c0},
+	{ 0x2a004, 255, 0x1f, 0x180},
+	{ 0x2a400, 1, 0x1f, 0x1c0},
+	{ 0x2a404, 255, 0x1f, 0x180},
+	{ 0x2a800, 1, 0x1f, 0x1c0},
+	{ 0x2a804, 255, 0x1f, 0x180},
+	{ 0x2ac00, 1, 0x1f, 0x1c0},
+	{ 0x2ac04, 255, 0x1f, 0x180},
+	{ 0x2b000, 1, 0x1f, 0x1c0},
+	{ 0x2b004, 255, 0x1f, 0x180},
+	{ 0x2b400, 1, 0x1f, 0x1c0},
+	{ 0x2b404, 255, 0x1f, 0x180},
+	{ 0x2b800, 1, 0x1f, 0x1c0},
+	{ 0x2b804, 255, 0x1f, 0x180},
+	{ 0x2bc00, 1, 0x1f, 0x1c0},
+	{ 0x2bc04, 255, 0x1f, 0x180},
+	{ 0x2c000, 1, 0x1f, 0x1c0},
+	{ 0x2c004, 255, 0x1f, 0x180},
+	{ 0x2c400, 1, 0x1f, 0x1c0},
+	{ 0x2c404, 255, 0x1f, 0x180},
+	{ 0x2c800, 1, 0x1f, 0x1c0},
+	{ 0x2c804, 255, 0x1f, 0x180},
+	{ 0x2cc00, 1, 0x1f, 0x1c0},
+	{ 0x2cc04, 255, 0x1f, 0x180},
+	{ 0x2d000, 1, 0x1f, 0x1c0},
+	{ 0x2d004, 255, 0x1f, 0x180},
+	{ 0x2d400, 1, 0x1f, 0x1c0},
+	{ 0x2d404, 255, 0x1f, 0x180},
+	{ 0x2d800, 1, 0x1f, 0x1c0},
+	{ 0x2d804, 255, 0x1f, 0x180},
+	{ 0x2dc00, 1, 0x1f, 0x1c0},
+	{ 0x2dc04, 255, 0x1f, 0x180},
+	{ 0x2e000, 1, 0x1f, 0x1c0},
+	{ 0x2e004, 255, 0x1f, 0x180},
+	{ 0x2e400, 1, 0x1f, 0x1c0},
+	{ 0x2e404, 255, 0x1f, 0x180},
+	{ 0x2e800, 1, 0x1f, 0x1c0},
+	{ 0x2e804, 255, 0x1f, 0x180},
+	{ 0x2ec00, 1, 0x1f, 0x1c0},
+	{ 0x2ec04, 255, 0x1f, 0x180},
+	{ 0x2f000, 1, 0x1f, 0x1c0},
+	{ 0x2f004, 255, 0x1f, 0x180},
+	{ 0x2f400, 1, 0x1f, 0x1c0},
+	{ 0x2f404, 255, 0x1f, 0x180},
+	{ 0x2f800, 1, 0x1f, 0x1c0},
+	{ 0x2f804, 255, 0x1f, 0x180},
+	{ 0x2fc00, 1, 0x1f, 0x1c0},
+	{ 0x2fc04, 255, 0x1f, 0x180},
+	{ 0x30000, 1, 0x1f, 0x9e4},
+	{ 0x30004, 255, 0x1f, 0x180},
+	{ 0x30400, 1, 0x1f, 0x1c0},
+	{ 0x30404, 255, 0x1f, 0x180},
+	{ 0x30800, 1, 0x1f, 0x1c0},
+	{ 0x30804, 255, 0x1f, 0x180},
+	{ 0x30c00, 1, 0x1f, 0x1c0},
+	{ 0x30c04, 255, 0x1f, 0x180},
+	{ 0x31000, 1, 0x1f, 0x1c0},
+	{ 0x31004, 255, 0x1f, 0x180},
+	{ 0x31400, 1, 0x1f, 0x1c0},
+	{ 0x31404, 255, 0x1f, 0x180},
+	{ 0x31800, 1, 0x1f, 0x1c0},
+	{ 0x31804, 255, 0x1f, 0x180},
+	{ 0x31c00, 1, 0x1f, 0x1c0},
+	{ 0x31c04, 255, 0x1f, 0x180},
+	{ 0x32000, 1, 0x1f, 0x1c0},
+	{ 0x32004, 255, 0x1f, 0x180},
+	{ 0x32400, 1, 0x1f, 0x1c0},
+	{ 0x32404, 255, 0x1f, 0x180},
+	{ 0x32800, 1, 0x1f, 0x1c0},
+	{ 0x32804, 255, 0x1f, 0x180},
+	{ 0x32c00, 1, 0x1f, 0x1c0},
+	{ 0x32c04, 255, 0x1f, 0x180},
+	{ 0x33000, 1, 0x1f, 0x1c0},
+	{ 0x33004, 255, 0x1f, 0x180},
+	{ 0x33400, 1, 0x1f, 0x1c0},
+	{ 0x33404, 255, 0x1f, 0x180},
+	{ 0x33800, 1, 0x1f, 0x1c0},
+	{ 0x33804, 255, 0x1f, 0x180},
+	{ 0x33c00, 1, 0x1f, 0x1c0},
+	{ 0x33c04, 255, 0x1f, 0x180},
+	{ 0x34000, 1, 0x1f, 0x1c0},
+	{ 0x34004, 255, 0x1f, 0x180},
+	{ 0x34400, 1, 0x1f, 0x1c0},
+	{ 0x34404, 255, 0x1f, 0x180},
+	{ 0x34800, 1, 0x1f, 0x1c0},
+	{ 0x34804, 255, 0x1f, 0x180},
+	{ 0x34c00, 1, 0x1f, 0x1c0},
+	{ 0x34c04, 255, 0x1f, 0x180},
+	{ 0x35000, 1, 0x1f, 0x1c0},
+	{ 0x35004, 255, 0x1f, 0x180},
+	{ 0x35400, 1, 0x1f, 0x1c0},
+	{ 0x35404, 255, 0x1f, 0x180},
+	{ 0x35800, 1, 0x1f, 0x1c0},
+	{ 0x35804, 255, 0x1f, 0x180},
+	{ 0x35c00, 1, 0x1f, 0x1c0},
+	{ 0x35c04, 255, 0x1f, 0x180},
+	{ 0x36000, 1, 0x1f, 0x1c0},
+	{ 0x36004, 255, 0x1f, 0x180},
+	{ 0x36400, 1, 0x1f, 0x1c0},
+	{ 0x36404, 255, 0x1f, 0x180},
+	{ 0x36800, 1, 0x1f, 0x1c0},
+	{ 0x36804, 255, 0x1f, 0x180},
+	{ 0x36c00, 1, 0x1f, 0x1c0},
+	{ 0x36c04, 255, 0x1f, 0x180},
+	{ 0x37000, 1, 0x1f, 0x1c0},
+	{ 0x37004, 255, 0x1f, 0x180},
+	{ 0x37400, 1, 0x1f, 0x1c0},
+	{ 0x37404, 255, 0x1f, 0x180},
+	{ 0x37800, 1, 0x1f, 0x1c0},
+	{ 0x37804, 255, 0x1f, 0x180},
+	{ 0x37c00, 1, 0x1f, 0x1c0},
+	{ 0x37c04, 255, 0x1f, 0x180},
+	{ 0x38000, 1, 0x1f, 0x1c0},
+	{ 0x38004, 255, 0x1f, 0x180},
+	{ 0x38400, 1, 0x1f, 0x1c0},
+	{ 0x38404, 255, 0x1f, 0x180},
+	{ 0x38800, 1, 0x1f, 0x1c0},
+	{ 0x38804, 255, 0x1f, 0x180},
+	{ 0x38c00, 1, 0x1f, 0x1c0},
+	{ 0x38c04, 255, 0x1f, 0x180},
+	{ 0x39000, 1, 0x1f, 0x1c0},
+	{ 0x39004, 255, 0x1f, 0x180},
+	{ 0x39400, 1, 0x1f, 0x1c0},
+	{ 0x39404, 255, 0x1f, 0x180},
+	{ 0x39800, 1, 0x1f, 0x1c0},
+	{ 0x39804, 255, 0x1f, 0x180},
+	{ 0x39c00, 1, 0x1f, 0x1c0},
+	{ 0x39c04, 255, 0x1f, 0x180},
+	{ 0x3a000, 1, 0x1f, 0x1c0},
+	{ 0x3a004, 255, 0x1f, 0x180},
+	{ 0x3a400, 1, 0x1f, 0x1c0},
+	{ 0x3a404, 255, 0x1f, 0x180},
+	{ 0x3a800, 1, 0x1f, 0x1c0},
+	{ 0x3a804, 255, 0x1f, 0x180},
+	{ 0x3ac00, 1, 0x1f, 0x1c0},
+	{ 0x3ac04, 255, 0x1f, 0x180},
+	{ 0x3b000, 1, 0x1f, 0x1c0},
+	{ 0x3b004, 255, 0x1f, 0x180},
+	{ 0x3b400, 1, 0x1f, 0x1c0},
+	{ 0x3b404, 255, 0x1f, 0x180},
+	{ 0x3b800, 1, 0x1f, 0x1c0},
+	{ 0x3b804, 255, 0x1f, 0x180},
+	{ 0x3bc00, 1, 0x1f, 0x1c0},
+	{ 0x3bc04, 255, 0x1f, 0x180},
+	{ 0x3c000, 1, 0x1f, 0x1c0},
+	{ 0x3c004, 255, 0x1f, 0x180},
+	{ 0x3c400, 1, 0x1f, 0x1c0},
+	{ 0x3c404, 255, 0x1f, 0x180},
+	{ 0x3c800, 1, 0x1f, 0x1c0},
+	{ 0x3c804, 255, 0x1f, 0x180},
+	{ 0x3cc00, 1, 0x1f, 0x1c0},
+	{ 0x3cc04, 255, 0x1f, 0x180},
+	{ 0x3d000, 1, 0x1f, 0x1c0},
+	{ 0x3d004, 255, 0x1f, 0x180},
+	{ 0x3d400, 1, 0x1f, 0x1c0},
+	{ 0x3d404, 255, 0x1f, 0x180},
+	{ 0x3d800, 1, 0x1f, 0x1c0},
+	{ 0x3d804, 255, 0x1f, 0x180},
+	{ 0x3dc00, 1, 0x1f, 0x1c0},
+	{ 0x3dc04, 255, 0x1f, 0x180},
+	{ 0x3e000, 1, 0x1f, 0x1c0},
+	{ 0x3e004, 255, 0x1f, 0x180},
+	{ 0x3e400, 1, 0x1f, 0x1c0},
+	{ 0x3e404, 255, 0x1f, 0x180},
+	{ 0x3e800, 1, 0x1f, 0x1c0},
+	{ 0x3e804, 255, 0x1f, 0x180},
+	{ 0x3ec00, 1, 0x1f, 0x1c0},
+	{ 0x3ec04, 255, 0x1f, 0x180},
+	{ 0x3f000, 1, 0x1f, 0x1c0},
+	{ 0x3f004, 255, 0x1f, 0x180},
+	{ 0x3f400, 1, 0x1f, 0x1c0},
+	{ 0x3f404, 255, 0x1f, 0x180},
+	{ 0x3f800, 1, 0x1f, 0x1c0},
+	{ 0x3f804, 255, 0x1f, 0x180},
+	{ 0x3fc00, 1, 0x1f, 0x1c0},
+	{ 0x3fc04, 255, 0x1f, 0x180},
+	{ 0x40000, 85, 0x1f, 0x924},
+	{ 0x40154, 13, 0x1f, 0xfff},
+	{ 0x40198, 2, 0x1f, 0x1fff},
+	{ 0x401a4, 1, 0x1f, 0x1fff},
+	{ 0x401a8, 8, 0x1e, 0x924},
+	{ 0x401c8, 1, 0x2, 0x924},
+	{ 0x401cc, 2, 0x1e, 0x924},
+	{ 0x401d4, 2, 0x1c, 0x924},
+	{ 0x40200, 4, 0x1f, 0x924},
+	{ 0x40220, 6, 0x1c, 0x924},
+	{ 0x40238, 8, 0xc, 0x924},
+	{ 0x40258, 4, 0x1c, 0x924},
+	{ 0x40268, 2, 0x18, 0x924},
+	{ 0x40270, 17, 0x10, 0x924},
+	{ 0x40400, 43, 0x1f, 0x924},
+	{ 0x404bc, 2, 0x1f, 0x1fff},
+	{ 0x404c8, 1, 0x1f, 0x1fff},
+	{ 0x404cc, 3, 0x1e, 0x924},
+	{ 0x404e0, 1, 0x1c, 0x924},
+	{ 0x40500, 2, 0x1f, 0x924},
+	{ 0x40510, 2, 0x1f, 0x924},
+	{ 0x40520, 2, 0x1f, 0x924},
+	{ 0x40530, 2, 0x1f, 0x924},
+	{ 0x40540, 2, 0x1f, 0x924},
+	{ 0x40550, 10, 0x1c, 0x924},
+	{ 0x40610, 2, 0x1c, 0x924},
+	{ 0x42000, 164, 0x1f, 0x924},
+	{ 0x422b0, 2, 0x1f, 0x1fff},
+	{ 0x422bc, 1, 0x1f, 0x1fff},
+	{ 0x422c0, 4, 0x1c, 0x924},
+	{ 0x422d4, 5, 0x1e, 0x924},
+	{ 0x422e8, 1, 0x1c, 0x924},
+	{ 0x42400, 49, 0x1f, 0x924},
+	{ 0x424c8, 32, 0x1f, 0x924},
+	{ 0x42548, 1, 0x1f, 0xfff},
+	{ 0x4254c, 1, 0x1f, 0x924},
+	{ 0x42550, 1, 0x1f, 0xfff},
+	{ 0x42554, 1, 0x1f, 0x924},
+	{ 0x42558, 1, 0x1f, 0xfff},
+	{ 0x4255c, 1, 0x1f, 0x924},
+	{ 0x42568, 2, 0x1f, 0x924},
+	{ 0x42640, 5, 0x1c, 0x924},
+	{ 0x42800, 1, 0x1f, 0x924},
+	{ 0x50000, 1, 0x1f, 0x1fff},
+	{ 0x50004, 19, 0x1f, 0x924},
+	{ 0x50050, 8, 0x1f, 0x93c},
+	{ 0x50070, 60, 0x1f, 0x924},
+	{ 0x50160, 8, 0x1f, 0xfff},
+	{ 0x50180, 20, 0x1f, 0x924},
+	{ 0x501e0, 2, 0x1f, 0x1fff},
+	{ 0x501ec, 1, 0x1f, 0x1fff},
+	{ 0x501f0, 4, 0x1e, 0x924},
+	{ 0x50200, 1, 0x1f, 0x924},
+	{ 0x50204, 1, 0x1f, 0xfff},
+	{ 0x5020c, 2, 0x1f, 0xfff},
+	{ 0x50214, 2, 0x1f, 0x924},
+	{ 0x5021c, 1, 0x1f, 0xfff},
+	{ 0x50220, 2, 0x1f, 0x924},
+	{ 0x50228, 6, 0x1e, 0x924},
+	{ 0x50240, 1, 0x1f, 0x924},
+	{ 0x50280, 1, 0x1f, 0x924},
+	{ 0x50300, 1, 0x1c, 0x924},
+	{ 0x5030c, 1, 0x1c, 0x924},
+	{ 0x50318, 1, 0x1c, 0x934},
+	{ 0x5031c, 1, 0x1c, 0x924},
+	{ 0x50320, 2, 0x1c, 0x934},
+	{ 0x50330, 1, 0x10, 0x924},
+	{ 0x52000, 1, 0x1f, 0x924},
+	{ 0x54000, 1, 0x1f, 0x93c},
+	{ 0x54004, 255, 0x1f, 0x30},
+	{ 0x54400, 1, 0x1f, 0x38},
+	{ 0x54404, 255, 0x1f, 0x30},
+	{ 0x54800, 1, 0x1f, 0x38},
+	{ 0x54804, 255, 0x1f, 0x30},
+	{ 0x54c00, 1, 0x1f, 0x38},
+	{ 0x54c04, 255, 0x1f, 0x30},
+	{ 0x55000, 1, 0x1f, 0x38},
+	{ 0x55004, 255, 0x1f, 0x30},
+	{ 0x55400, 1, 0x1f, 0x38},
+	{ 0x55404, 255, 0x1f, 0x30},
+	{ 0x55800, 1, 0x1f, 0x38},
+	{ 0x55804, 255, 0x1f, 0x30},
+	{ 0x55c00, 1, 0x1f, 0x38},
+	{ 0x55c04, 255, 0x1f, 0x30},
+	{ 0x56000, 1, 0x1f, 0x38},
+	{ 0x56004, 255, 0x1f, 0x30},
+	{ 0x56400, 1, 0x1f, 0x38},
+	{ 0x56404, 255, 0x1f, 0x30},
+	{ 0x56800, 1, 0x1f, 0x38},
+	{ 0x56804, 255, 0x1f, 0x30},
+	{ 0x56c00, 1, 0x1f, 0x38},
+	{ 0x56c04, 255, 0x1f, 0x30},
+	{ 0x57000, 1, 0x1f, 0x38},
+	{ 0x57004, 255, 0x1f, 0x30},
+	{ 0x58000, 1, 0x1f, 0x934},
+	{ 0x58004, 8191, 0x3, 0x30},
+	{ 0x60000, 26, 0x1f, 0x924},
+	{ 0x60068, 8, 0x3, 0x924},
+	{ 0x60088, 2, 0x1f, 0x924},
+	{ 0x60090, 1, 0x1f, 0xfff},
+	{ 0x60094, 9, 0x1f, 0x924},
+	{ 0x600b8, 9, 0x3, 0x924},
+	{ 0x600dc, 1, 0x1f, 0x924},
+	{ 0x600e0, 5, 0x3, 0x924},
+	{ 0x600f4, 1, 0x7, 0x924},
+	{ 0x600f8, 1, 0x3, 0x924},
+	{ 0x600fc, 8, 0x1f, 0x924},
+	{ 0x6012c, 2, 0x1f, 0x1fff},
+	{ 0x60138, 1, 0x1f, 0x1fff},
+	{ 0x6013c, 24, 0x2, 0x924},
+	{ 0x6019c, 2, 0x1c, 0x924},
+	{ 0x601ac, 18, 0x1c, 0x924},
+	{ 0x60200, 1, 0x1f, 0xb6d},
+	{ 0x60204, 2, 0x1f, 0x249},
+	{ 0x60210, 13, 0x1c, 0x924},
+	{ 0x60244, 16, 0x10, 0x924},
+	{ 0x61000, 1, 0x1f, 0xb6d},
+	{ 0x61004, 511, 0x1f, 0x249},
+	{ 0x61800, 512, 0x18, 0x249},
+	{ 0x70000, 8, 0x1f, 0xb6d},
+	{ 0x70020, 8184, 0x1f, 0x249},
+	{ 0x78000, 8192, 0x18, 0x249},
+	{ 0x85000, 3, 0x1f, 0x1000},
+	{ 0x8501c, 7, 0x1f, 0x1000},
+	{ 0x85048, 1, 0x1f, 0x1000},
+	{ 0x85200, 32, 0x1f, 0x1000},
+	{ 0xa0000, 16384, 0x3, 0x1000},
+	{ 0xb0000, 16384, 0x2, 0x1000},
+	{ 0xc1000, 7, 0x1f, 0x924},
+	{ 0xc102c, 2, 0x1f, 0x1fff},
+	{ 0xc1038, 1, 0x1f, 0x1fff},
+	{ 0xc103c, 2, 0x1c, 0x924},
+	{ 0xc1800, 2, 0x1f, 0x924},
+	{ 0xc2000, 164, 0x1f, 0x924},
+	{ 0xc22b0, 2, 0x1f, 0x1fff},
+	{ 0xc22bc, 1, 0x1f, 0x1fff},
+	{ 0xc22c0, 5, 0x1c, 0x924},
+	{ 0xc22d8, 4, 0x1c, 0x924},
+	{ 0xc2400, 49, 0x1f, 0x924},
+	{ 0xc24c8, 32, 0x1f, 0x924},
+	{ 0xc2548, 1, 0x1f, 0xfff},
+	{ 0xc254c, 1, 0x1f, 0x924},
+	{ 0xc2550, 1, 0x1f, 0xfff},
+	{ 0xc2554, 1, 0x1f, 0x924},
+	{ 0xc2558, 1, 0x1f, 0xfff},
+	{ 0xc255c, 1, 0x1f, 0x924},
+	{ 0xc2568, 2, 0x1f, 0x924},
+	{ 0xc2600, 1, 0x1f, 0x924},
+	{ 0xc4000, 165, 0x1f, 0x924},
+	{ 0xc42b4, 2, 0x1f, 0x1fff},
+	{ 0xc42c0, 1, 0x1f, 0x1fff},
+	{ 0xc42d8, 2, 0x1c, 0x924},
+	{ 0xc42e0, 7, 0x1e, 0x924},
+	{ 0xc42fc, 1, 0x1c, 0x924},
+	{ 0xc4400, 51, 0x1f, 0x924},
+	{ 0xc44d0, 32, 0x1f, 0x924},
+	{ 0xc4550, 1, 0x1f, 0xfff},
+	{ 0xc4554, 1, 0x1f, 0x924},
+	{ 0xc4558, 1, 0x1f, 0xfff},
+	{ 0xc455c, 1, 0x1f, 0x924},
+	{ 0xc4560, 1, 0x1f, 0xfff},
+	{ 0xc4564, 1, 0x1f, 0x924},
+	{ 0xc4570, 2, 0x1f, 0x924},
+	{ 0xc4578, 5, 0x1c, 0x924},
+	{ 0xc4600, 1, 0x1f, 0x924},
+	{ 0xd0000, 19, 0x1f, 0x924},
+	{ 0xd004c, 8, 0x1f, 0x1927},
+	{ 0xd006c, 64, 0x1f, 0x924},
+	{ 0xd016c, 8, 0x1f, 0xfff},
+	{ 0xd018c, 19, 0x1f, 0x924},
+	{ 0xd01e8, 2, 0x1f, 0x1fff},
+	{ 0xd01f4, 1, 0x1f, 0x1fff},
+	{ 0xd01fc, 1, 0x1c, 0x924},
+	{ 0xd0200, 1, 0x1f, 0x924},
+	{ 0xd0204, 1, 0x1f, 0xfff},
+	{ 0xd020c, 3, 0x1f, 0xfff},
+	{ 0xd0218, 4, 0x1f, 0x924},
+	{ 0xd0228, 18, 0x1e, 0x924},
+	{ 0xd0280, 1, 0x1f, 0x924},
+	{ 0xd0300, 1, 0x1f, 0x924},
+	{ 0xd0400, 1, 0x1f, 0x924},
+	{ 0xd0818, 1, 0x10, 0x924},
+	{ 0xd4000, 1, 0x1f, 0x1927},
+	{ 0xd4004, 255, 0x1f, 0x6},
+	{ 0xd4400, 1, 0x1f, 0x1007},
+	{ 0xd4404, 255, 0x1f, 0x6},
+	{ 0xd4800, 1, 0x1f, 0x1007},
+	{ 0xd4804, 255, 0x1f, 0x6},
+	{ 0xd4c00, 1, 0x1f, 0x1007},
+	{ 0xd4c04, 255, 0x1f, 0x6},
+	{ 0xd5000, 1, 0x1f, 0x1007},
+	{ 0xd5004, 255, 0x1f, 0x6},
+	{ 0xd5400, 1, 0x1f, 0x1007},
+	{ 0xd5404, 255, 0x1f, 0x6},
+	{ 0xd5800, 1, 0x1f, 0x1007},
+	{ 0xd5804, 255, 0x1f, 0x6},
+	{ 0xd5c00, 1, 0x1f, 0x1007},
+	{ 0xd5c04, 255, 0x1f, 0x6},
+	{ 0xd6000, 1, 0x1f, 0x1007},
+	{ 0xd6004, 255, 0x1f, 0x6},
+	{ 0xd6400, 1, 0x1f, 0x1007},
+	{ 0xd6404, 255, 0x1f, 0x6},
+	{ 0xd8000, 1, 0x1f, 0x1927},
+	{ 0xd8004, 255, 0x1f, 0x6},
+	{ 0xd8400, 1, 0x1f, 0x1007},
+	{ 0xd8404, 255, 0x1f, 0x6},
+	{ 0xd8800, 1, 0x1f, 0x1007},
+	{ 0xd8804, 255, 0x1f, 0x6},
+	{ 0xd8c00, 1, 0x1f, 0x1007},
+	{ 0xd8c04, 255, 0x1f, 0x6},
+	{ 0xd9000, 1, 0x1f, 0x1007},
+	{ 0xd9004, 255, 0x1f, 0x6},
+	{ 0xd9400, 1, 0x1f, 0x1007},
+	{ 0xd9404, 255, 0x1f, 0x6},
+	{ 0xd9800, 1, 0x1f, 0x1007},
+	{ 0xd9804, 255, 0x1f, 0x6},
+	{ 0xd9c00, 1, 0x1f, 0x1007},
+	{ 0xd9c04, 255, 0x1f, 0x6},
+	{ 0xda000, 1, 0x1f, 0x1007},
+	{ 0xda004, 255, 0x1f, 0x6},
+	{ 0xda400, 1, 0x1f, 0x1007},
+	{ 0xda404, 255, 0x1f, 0x6},
+	{ 0xda800, 1, 0x1f, 0x1007},
+	{ 0xda804, 255, 0x1f, 0x6},
+	{ 0xdac00, 1, 0x1f, 0x1007},
+	{ 0xdac04, 255, 0x1f, 0x6},
+	{ 0xdb000, 1, 0x1f, 0x1007},
+	{ 0xdb004, 255, 0x1f, 0x6},
+	{ 0xdb400, 1, 0x1f, 0x1007},
+	{ 0xdb404, 255, 0x1f, 0x6},
+	{ 0xdb800, 1, 0x1f, 0x1007},
+	{ 0xdb804, 255, 0x1f, 0x6},
+	{ 0xdbc00, 1, 0x1f, 0x1007},
+	{ 0xdbc04, 255, 0x1f, 0x6},
+	{ 0xdc000, 1, 0x1f, 0x1007},
+	{ 0xdc004, 255, 0x1f, 0x6},
+	{ 0xdc400, 1, 0x1f, 0x1007},
+	{ 0xdc404, 255, 0x1f, 0x6},
+	{ 0xdc800, 1, 0x1f, 0x1007},
+	{ 0xdc804, 255, 0x1f, 0x6},
+	{ 0xdcc00, 1, 0x1f, 0x1007},
+	{ 0xdcc04, 255, 0x1f, 0x6},
+	{ 0xdd000, 1, 0x1f, 0x1007},
+	{ 0xdd004, 255, 0x1f, 0x6},
+	{ 0xdd400, 1, 0x1f, 0x1007},
+	{ 0xdd404, 255, 0x1f, 0x6},
+	{ 0xdd800, 1, 0x1f, 0x1007},
+	{ 0xdd804, 255, 0x1f, 0x6},
+	{ 0xddc00, 1, 0x1f, 0x1007},
+	{ 0xddc04, 255, 0x1f, 0x6},
+	{ 0xde000, 1, 0x1f, 0x1007},
+	{ 0xde004, 255, 0x1f, 0x6},
+	{ 0xde400, 1, 0x1f, 0x1007},
+	{ 0xde404, 255, 0x1f, 0x6},
+	{ 0xde800, 1, 0x1f, 0x1007},
+	{ 0xde804, 255, 0x1f, 0x6},
+	{ 0xdec00, 1, 0x1f, 0x1007},
+	{ 0xdec04, 255, 0x1f, 0x6},
+	{ 0xdf000, 1, 0x1f, 0x1007},
+	{ 0xdf004, 255, 0x1f, 0x6},
+	{ 0xdf400, 1, 0x1f, 0x1007},
+	{ 0xdf404, 255, 0x1f, 0x6},
+	{ 0xdf800, 1, 0x1f, 0x1007},
+	{ 0xdf804, 255, 0x1f, 0x6},
+	{ 0xdfc00, 1, 0x1f, 0x1007},
+	{ 0xdfc04, 255, 0x1f, 0x6},
+	{ 0xe0000, 21, 0x1f, 0x924},
+	{ 0xe0054, 8, 0x1f, 0xf24},
+	{ 0xe0074, 49, 0x1f, 0x924},
+	{ 0xe0138, 1, 0x3, 0x924},
+	{ 0xe013c, 6, 0x1f, 0x924},
+	{ 0xe0154, 8, 0x1f, 0xfff},
+	{ 0xe0174, 21, 0x1f, 0x924},
+	{ 0xe01d8, 2, 0x1f, 0x1fff},
+	{ 0xe01e4, 1, 0x1f, 0x1fff},
+	{ 0xe01f4, 1, 0x4, 0x924},
+	{ 0xe01f8, 1, 0x1c, 0x924},
+	{ 0xe0200, 1, 0x1f, 0x924},
+	{ 0xe0204, 1, 0x1f, 0xfff},
+	{ 0xe020c, 2, 0x1f, 0xfff},
+	{ 0xe0214, 2, 0x1f, 0x924},
+	{ 0xe021c, 2, 0x1f, 0xfff},
+	{ 0xe0224, 2, 0x1f, 0x924},
+	{ 0xe022c, 18, 0x1e, 0x924},
+	{ 0xe0280, 1, 0x1f, 0x924},
+	{ 0xe0300, 1, 0x1f, 0x924},
+	{ 0xe0400, 1, 0x10, 0x924},
+	{ 0xe1000, 1, 0x1f, 0x924},
+	{ 0xe2000, 1, 0x1f, 0xf24},
+	{ 0xe2004, 255, 0x1f, 0xc00},
+	{ 0xe2400, 1, 0x1f, 0xe00},
+	{ 0xe2404, 255, 0x1f, 0xc00},
+	{ 0xe2800, 1, 0x1f, 0xe00},
+	{ 0xe2804, 255, 0x1f, 0xc00},
+	{ 0xe2c00, 1, 0x1f, 0xe00},
+	{ 0xe2c04, 255, 0x1f, 0xc00},
+	{ 0xe3000, 1, 0x1f, 0xe00},
+	{ 0xe3004, 255, 0x1f, 0xc00},
+	{ 0xe3400, 1, 0x1f, 0xe00},
+	{ 0xe3404, 255, 0x1f, 0xc00},
+	{ 0xe3800, 1, 0x1f, 0xe00},
+	{ 0xe3804, 255, 0x1f, 0xc00},
+	{ 0xe3c00, 1, 0x1f, 0xe00},
+	{ 0xe3c04, 255, 0x1f, 0xc00},
+	{ 0xf0000, 1, 0x1f, 0xf24},
+	{ 0xf0004, 255, 0x1f, 0xc00},
+	{ 0xf0400, 1, 0x1f, 0xe00},
+	{ 0xf0404, 255, 0x1f, 0xc00},
+	{ 0xf0800, 1, 0x1f, 0xe00},
+	{ 0xf0804, 255, 0x1f, 0xc00},
+	{ 0xf0c00, 1, 0x1f, 0xe00},
+	{ 0xf0c04, 255, 0x1f, 0xc00},
+	{ 0xf1000, 1, 0x1f, 0xe00},
+	{ 0xf1004, 255, 0x1f, 0xc00},
+	{ 0xf1400, 1, 0x1f, 0xe00},
+	{ 0xf1404, 255, 0x1f, 0xc00},
+	{ 0xf1800, 1, 0x1f, 0xe00},
+	{ 0xf1804, 255, 0x1f, 0xc00},
+	{ 0xf1c00, 1, 0x1f, 0xe00},
+	{ 0xf1c04, 255, 0x1f, 0xc00},
+	{ 0xf2000, 1, 0x1f, 0xe00},
+	{ 0xf2004, 255, 0x1f, 0xc00},
+	{ 0xf2400, 1, 0x1f, 0xe00},
+	{ 0xf2404, 255, 0x1f, 0xc00},
+	{ 0xf2800, 1, 0x1f, 0xe00},
+	{ 0xf2804, 255, 0x1f, 0xc00},
+	{ 0xf2c00, 1, 0x1f, 0xe00},
+	{ 0xf2c04, 255, 0x1f, 0xc00},
+	{ 0xf3000, 1, 0x1f, 0xe00},
+	{ 0xf3004, 255, 0x1f, 0xc00},
+	{ 0xf3400, 1, 0x1f, 0xe00},
+	{ 0xf3404, 255, 0x1f, 0xc00},
+	{ 0xf3800, 1, 0x1f, 0xe00},
+	{ 0xf3804, 255, 0x1f, 0xc00},
+	{ 0xf3c00, 1, 0x1f, 0xe00},
+	{ 0xf3c04, 255, 0x1f, 0xc00},
+	{ 0xf4000, 1, 0x1f, 0xe00},
+	{ 0xf4004, 255, 0x1f, 0xc00},
+	{ 0xf4400, 1, 0x1f, 0xe00},
+	{ 0xf4404, 255, 0x1f, 0xc00},
+	{ 0xf4800, 1, 0x1f, 0xe00},
+	{ 0xf4804, 255, 0x1f, 0xc00},
+	{ 0xf4c00, 1, 0x1f, 0xe00},
+	{ 0xf4c04, 255, 0x1f, 0xc00},
+	{ 0xf5000, 1, 0x1f, 0xe00},
+	{ 0xf5004, 255, 0x1f, 0xc00},
+	{ 0xf5400, 1, 0x1f, 0xe00},
+	{ 0xf5404, 255, 0x1f, 0xc00},
+	{ 0xf5800, 1, 0x1f, 0xe00},
+	{ 0xf5804, 255, 0x1f, 0xc00},
+	{ 0xf5c00, 1, 0x1f, 0xe00},
+	{ 0xf5c04, 255, 0x1f, 0xc00},
+	{ 0xf6000, 1, 0x1f, 0xe00},
+	{ 0xf6004, 255, 0x1f, 0xc00},
+	{ 0xf6400, 1, 0x1f, 0xe00},
+	{ 0xf6404, 255, 0x1f, 0xc00},
+	{ 0xf6800, 1, 0x1f, 0xe00},
+	{ 0xf6804, 255, 0x1f, 0xc00},
+	{ 0xf6c00, 1, 0x1f, 0xe00},
+	{ 0xf6c04, 255, 0x1f, 0xc00},
+	{ 0xf7000, 1, 0x1f, 0xe00},
+	{ 0xf7004, 255, 0x1f, 0xc00},
+	{ 0xf7400, 1, 0x1f, 0xe00},
+	{ 0xf7404, 255, 0x1f, 0xc00},
+	{ 0xf7800, 1, 0x1f, 0xe00},
+	{ 0xf7804, 255, 0x1f, 0xc00},
+	{ 0xf7c00, 1, 0x1f, 0xe00},
+	{ 0xf7c04, 255, 0x1f, 0xc00},
+	{ 0xf8000, 1, 0x1f, 0xe00},
+	{ 0xf8004, 255, 0x1f, 0xc00},
+	{ 0xf8400, 1, 0x1f, 0xe00},
+	{ 0xf8404, 255, 0x1f, 0xc00},
+	{ 0xf8800, 1, 0x1f, 0xe00},
+	{ 0xf8804, 255, 0x1f, 0xc00},
+	{ 0xf8c00, 1, 0x1f, 0xe00},
+	{ 0xf8c04, 255, 0x1f, 0xc00},
+	{ 0xf9000, 1, 0x1f, 0xe00},
+	{ 0xf9004, 255, 0x1f, 0xc00},
+	{ 0xf9400, 1, 0x1f, 0xe00},
+	{ 0xf9404, 255, 0x1f, 0xc00},
+	{ 0xf9800, 1, 0x1f, 0xe00},
+	{ 0xf9804, 255, 0x1f, 0xc00},
+	{ 0xf9c00, 1, 0x1f, 0xe00},
+	{ 0xf9c04, 255, 0x1f, 0xc00},
+	{ 0xfa000, 1, 0x1f, 0xe00},
+	{ 0xfa004, 255, 0x1f, 0xc00},
+	{ 0xfa400, 1, 0x1f, 0xe00},
+	{ 0xfa404, 255, 0x1f, 0xc00},
+	{ 0xfa800, 1, 0x1f, 0xe00},
+	{ 0xfa804, 255, 0x1f, 0xc00},
+	{ 0xfac00, 1, 0x1f, 0xe00},
+	{ 0xfac04, 255, 0x1f, 0xc00},
+	{ 0xfb000, 1, 0x1f, 0xe00},
+	{ 0xfb004, 255, 0x1f, 0xc00},
+	{ 0xfb400, 1, 0x1f, 0xe00},
+	{ 0xfb404, 255, 0x1f, 0xc00},
+	{ 0xfb800, 1, 0x1f, 0xe00},
+	{ 0xfb804, 255, 0x1f, 0xc00},
+	{ 0xfbc00, 1, 0x1f, 0xe00},
+	{ 0xfbc04, 255, 0x1f, 0xc00},
+	{ 0xfc000, 1, 0x1f, 0xe00},
+	{ 0xfc004, 255, 0x1f, 0xc00},
+	{ 0xfc400, 1, 0x1f, 0xe00},
+	{ 0xfc404, 255, 0x1f, 0xc00},
+	{ 0xfc800, 1, 0x1f, 0xe00},
+	{ 0xfc804, 255, 0x1f, 0xc00},
+	{ 0xfcc00, 1, 0x1f, 0xe00},
+	{ 0xfcc04, 255, 0x1f, 0xc00},
+	{ 0xfd000, 1, 0x1f, 0xe00},
+	{ 0xfd004, 255, 0x1f, 0xc00},
+	{ 0xfd400, 1, 0x1f, 0xe00},
+	{ 0xfd404, 255, 0x1f, 0xc00},
+	{ 0xfd800, 1, 0x1f, 0xe00},
+	{ 0xfd804, 255, 0x1f, 0xc00},
+	{ 0xfdc00, 1, 0x1f, 0xe00},
+	{ 0xfdc04, 255, 0x1f, 0xc00},
+	{ 0xfe000, 1, 0x1f, 0xe00},
+	{ 0xfe004, 255, 0x1f, 0xc00},
+	{ 0xfe400, 1, 0x1f, 0xe00},
+	{ 0xfe404, 255, 0x1f, 0xc00},
+	{ 0xfe800, 1, 0x1f, 0xe00},
+	{ 0xfe804, 255, 0x1f, 0xc00},
+	{ 0xfec00, 1, 0x1f, 0xe00},
+	{ 0xfec04, 255, 0x1f, 0xc00},
+	{ 0xff000, 1, 0x1f, 0xe00},
+	{ 0xff004, 255, 0x1f, 0xc00},
+	{ 0xff400, 1, 0x1f, 0xe00},
+	{ 0xff404, 255, 0x1f, 0xc00},
+	{ 0xff800, 1, 0x1f, 0xe00},
+	{ 0xff804, 255, 0x1f, 0xc00},
+	{ 0xffc00, 1, 0x1f, 0xe00},
+	{ 0xffc04, 255, 0x1f, 0xc00},
+	{ 0x101000, 5, 0x1f, 0x924},
+	{ 0x101014, 1, 0x1f, 0xfff},
+	{ 0x101018, 6, 0x1f, 0x924},
+	{ 0x101040, 2, 0x1f, 0x1fff},
+	{ 0x10104c, 1, 0x1f, 0x1fff},
+	{ 0x101050, 1, 0x1e, 0x924},
+	{ 0x101054, 3, 0x1c, 0x924},
+	{ 0x101100, 1, 0x1f, 0x924},
+	{ 0x101800, 8, 0x1f, 0x924},
+	{ 0x102000, 18, 0x1f, 0x924},
+	{ 0x102058, 2, 0x1f, 0x1fff},
+	{ 0x102064, 1, 0x1f, 0x1fff},
+	{ 0x102068, 6, 0x1c, 0x924},
+	{ 0x102080, 16, 0x1f, 0xfff},
+	{ 0x1020c0, 1, 0x1f, 0x924},
+	{ 0x1020c8, 8, 0x2, 0x924},
+	{ 0x1020e8, 9, 0x1c, 0x924},
+	{ 0x102400, 1, 0x1f, 0x924},
+	{ 0x103000, 1, 0x1f, 0x924},
+	{ 0x103004, 2, 0x1f, 0xfff},
+	{ 0x10300c, 23, 0x1f, 0x924},
+	{ 0x103088, 2, 0x1f, 0x1fff},
+	{ 0x103094, 1, 0x1f, 0x1fff},
+	{ 0x103098, 1, 0x1e, 0x924},
+	{ 0x10309c, 2, 0x1e, 0xfff},
+	{ 0x1030a4, 2, 0x1e, 0x924},
+	{ 0x1030ac, 2, 0x1c, 0x924},
+	{ 0x1030b4, 1, 0x4, 0x924},
+	{ 0x1030b8, 2, 0x1c, 0xfff},
+	{ 0x1030c0, 3, 0x1c, 0x924},
+	{ 0x1030cc, 1, 0x1c, 0xfff},
+	{ 0x1030d0, 1, 0x1c, 0x924},
+	{ 0x1030d8, 2, 0x1c, 0x924},
+	{ 0x1030e0, 1, 0x1c, 0xfff},
+	{ 0x1030e4, 5, 0x1c, 0x924},
+	{ 0x103400, 136, 0x1c, 0x1fff},
+	{ 0x103800, 8, 0x1f, 0x924},
+	{ 0x104000, 1, 0x1f, 0x924},
+	{ 0x104004, 1, 0x1f, 0xfff},
+	{ 0x104008, 4, 0x1f, 0x924},
+	{ 0x104018, 1, 0x1f, 0xfff},
+	{ 0x10401c, 1, 0x1f, 0x924},
+	{ 0x104020, 1, 0x1f, 0xfff},
+	{ 0x104024, 6, 0x1f, 0x924},
+	{ 0x10403c, 1, 0x1f, 0xfff},
+	{ 0x104040, 47, 0x1f, 0x924},
+	{ 0x10410c, 2, 0x1f, 0x1fff},
+	{ 0x104118, 1, 0x1f, 0x1fff},
+	{ 0x10411c, 16, 0x1c, 0x924},
+	{ 0x104200, 17, 0x1f, 0x924},
+	{ 0x104400, 1, 0x1f, 0x1fff},
+	{ 0x104404, 63, 0x1f, 0xfff},
+	{ 0x104500, 192, 0x1f, 0xdb6},
+	{ 0x104800, 1, 0x1f, 0x1fff},
+	{ 0x104804, 63, 0x1f, 0xfff},
+	{ 0x104900, 192, 0x1f, 0xdb6},
+	{ 0x105000, 4, 0x1f, 0x1fff},
+	{ 0x105010, 252, 0x1f, 0xfff},
+	{ 0x105400, 768, 0x1f, 0xdb6},
+	{ 0x107000, 7, 0x1c, 0x924},
+	{ 0x10701c, 1, 0x18, 0x924},
+	{ 0x108000, 33, 0x3, 0x924},
+	{ 0x1080ac, 5, 0x2, 0x924},
+	{ 0x108100, 5, 0x3, 0x924},
+	{ 0x108120, 5, 0x3, 0x924},
+	{ 0x108200, 74, 0x3, 0x924},
+	{ 0x108400, 74, 0x3, 0x924},
+	{ 0x108800, 152, 0x3, 0x924},
+	{ 0x110000, 111, 0x1c, 0x924},
+	{ 0x1101cc, 2, 0x1c, 0x1fff},
+	{ 0x1101d8, 1, 0x1c, 0x1fff},
+	{ 0x1101dc, 1, 0x18, 0x924},
+	{ 0x110200, 4, 0x1c, 0x924},
+	{ 0x120000, 92, 0x1f, 0x924},
+	{ 0x120170, 2, 0x3, 0x924},
+	{ 0x120178, 14, 0x1f, 0x924},
+	{ 0x1201b0, 2, 0x1f, 0xfff},
+	{ 0x1201b8, 93, 0x1f, 0x924},
+	{ 0x12032c, 1, 0x1f, 0xfff},
+	{ 0x120330, 15, 0x1f, 0x924},
+	{ 0x12036c, 3, 0x1f, 0xfff},
+	{ 0x120378, 36, 0x1f, 0x924},
+	{ 0x120408, 2, 0x1f, 0xfff},
+	{ 0x120410, 1, 0x1f, 0x924},
+	{ 0x120414, 15, 0x1f, 0xfff},
+	{ 0x120450, 10, 0x1f, 0x924},
+	{ 0x120478, 2, 0x1f, 0xfff},
+	{ 0x120480, 43, 0x1f, 0x924},
+	{ 0x12052c, 1, 0x1f, 0xfff},
+	{ 0x120530, 5, 0x1f, 0x924},
+	{ 0x120544, 4, 0x3, 0x924},
+	{ 0x120554, 4, 0x1f, 0x924},
+	{ 0x120564, 2, 0x1f, 0xfff},
+	{ 0x12057c, 2, 0x1f, 0x1fff},
+	{ 0x120588, 3, 0x1f, 0x1fff},
+	{ 0x120598, 1, 0x1f, 0x1fff},
+	{ 0x12059c, 22, 0x1e, 0x924},
+	{ 0x1205f4, 1, 0x6, 0x924},
+	{ 0x1205f8, 4, 0x1c, 0x924},
+	{ 0x120618, 1, 0x1c, 0x924},
+	{ 0x12061c, 31, 0x1e, 0x924},
+	{ 0x120698, 3, 0x1c, 0x924},
+	{ 0x1206a4, 1, 0x4, 0x924},
+	{ 0x1206a8, 1, 0x1c, 0x924},
+	{ 0x1206b0, 38, 0x1c, 0x924},
+	{ 0x120748, 1, 0x1c, 0xfff},
+	{ 0x12074c, 11, 0x1c, 0x924},
+	{ 0x120778, 2, 0x1c, 0xfff},
+	{ 0x120780, 23, 0x1c, 0x924},
+	{ 0x1207dc, 1, 0x4, 0x924},
+	{ 0x1207fc, 1, 0x1c, 0x924},
+	{ 0x12080c, 2, 0x1f, 0xfff},
+	{ 0x120814, 1, 0x1f, 0x924},
+	{ 0x120818, 1, 0x1f, 0xfff},
+	{ 0x12081c, 1, 0x1f, 0x924},
+	{ 0x120820, 1, 0x1f, 0xfff},
+	{ 0x120824, 1, 0x1f, 0x924},
+	{ 0x120828, 1, 0x1f, 0xfff},
+	{ 0x12082c, 1, 0x1f, 0x924},
+	{ 0x120830, 1, 0x1f, 0xfff},
+	{ 0x120834, 1, 0x1f, 0x924},
+	{ 0x120838, 1, 0x1f, 0xfff},
+	{ 0x12083c, 1, 0x1f, 0x924},
+	{ 0x120840, 1, 0x1f, 0xfff},
+	{ 0x120844, 1, 0x1f, 0x924},
+	{ 0x120848, 1, 0x1f, 0xfff},
+	{ 0x12084c, 1, 0x1f, 0x924},
+	{ 0x120850, 1, 0x1f, 0xfff},
+	{ 0x120854, 1, 0x1f, 0x924},
+	{ 0x120858, 1, 0x1f, 0xfff},
+	{ 0x12085c, 1, 0x1f, 0x924},
+	{ 0x120860, 1, 0x1f, 0xfff},
+	{ 0x120864, 1, 0x1f, 0x924},
+	{ 0x120868, 1, 0x1f, 0xfff},
+	{ 0x12086c, 1, 0x1f, 0x924},
+	{ 0x120870, 1, 0x1f, 0xfff},
+	{ 0x120874, 1, 0x1f, 0x924},
+	{ 0x120878, 1, 0x1f, 0xfff},
+	{ 0x12087c, 1, 0x1f, 0x924},
+	{ 0x120880, 1, 0x1f, 0xfff},
+	{ 0x120884, 1, 0x1f, 0x924},
+	{ 0x120888, 1, 0x1f, 0xfff},
+	{ 0x12088c, 1, 0x1f, 0x924},
+	{ 0x120890, 1, 0x1f, 0xfff},
+	{ 0x120894, 1, 0x1f, 0x924},
+	{ 0x120898, 1, 0x1f, 0xfff},
+	{ 0x12089c, 1, 0x1f, 0x924},
+	{ 0x1208a0, 1, 0x1f, 0xfff},
+	{ 0x1208a4, 1, 0x1f, 0x924},
+	{ 0x1208a8, 1, 0x1f, 0xfff},
+	{ 0x1208ac, 1, 0x1f, 0x924},
+	{ 0x1208b0, 1, 0x1f, 0xfff},
+	{ 0x1208b4, 1, 0x1f, 0x924},
+	{ 0x1208b8, 1, 0x1f, 0xfff},
+	{ 0x1208bc, 1, 0x1f, 0x924},
+	{ 0x1208c0, 1, 0x1f, 0xfff},
+	{ 0x1208c4, 1, 0x1f, 0x924},
+	{ 0x1208c8, 1, 0x1f, 0xfff},
+	{ 0x1208cc, 1, 0x1f, 0x924},
+	{ 0x1208d0, 1, 0x1f, 0xfff},
+	{ 0x1208d4, 1, 0x1f, 0x924},
+	{ 0x1208d8, 1, 0x1f, 0xfff},
+	{ 0x1208dc, 1, 0x1f, 0x924},
+	{ 0x1208e0, 1, 0x1f, 0xfff},
+	{ 0x1208e4, 1, 0x1f, 0x924},
+	{ 0x1208e8, 1, 0x1f, 0xfff},
+	{ 0x1208ec, 1, 0x1f, 0x924},
+	{ 0x1208f0, 1, 0x1f, 0xfff},
+	{ 0x1208f4, 1, 0x1f, 0x924},
+	{ 0x1208f8, 1, 0x1f, 0xfff},
+	{ 0x1208fc, 1, 0x1f, 0x924},
+	{ 0x120900, 1, 0x1f, 0xfff},
+	{ 0x120904, 1, 0x1f, 0x924},
+	{ 0x120908, 1, 0x1f, 0xfff},
+	{ 0x12090c, 1, 0x1f, 0x924},
+	{ 0x120910, 7, 0x1c, 0x924},
+	{ 0x120930, 9, 0x1c, 0x924},
+	{ 0x12095c, 37, 0x18, 0x924},
+	{ 0x120a00, 2, 0x7, 0x924},
+	{ 0x120b00, 1, 0x18, 0x924},
+	{ 0x122000, 2, 0x1f, 0x924},
+	{ 0x122008, 2046, 0x1, 0x924},
+	{ 0x128000, 6144, 0x1e, 0x924},
+	{ 0x130000, 1, 0x1c, 0x1fff},
+	{ 0x130004, 11, 0x1c, 0x924},
+	{ 0x130030, 1, 0x1c, 0xfff},
+	{ 0x130034, 6, 0x1c, 0x924},
+	{ 0x13004c, 3, 0x1c, 0xfff},
+	{ 0x130058, 3, 0x1c, 0x924},
+	{ 0x130064, 2, 0x1c, 0xfff},
+	{ 0x13006c, 8, 0x1c, 0x924},
+	{ 0x13009c, 2, 0x1c, 0x1fff},
+	{ 0x1300a8, 1, 0x1c, 0x1fff},
+	{ 0x130100, 12, 0x1c, 0x924},
+	{ 0x130130, 1, 0x1c, 0xfff},
+	{ 0x130134, 14, 0x1c, 0x924},
+	{ 0x13016c, 1, 0x1c, 0xfff},
+	{ 0x130170, 1, 0x1c, 0x924},
+	{ 0x130180, 1, 0x1c, 0x924},
+	{ 0x130200, 1, 0x1c, 0x924},
+	{ 0x130280, 1, 0x1c, 0x924},
+	{ 0x130300, 1, 0x1c, 0xfff},
+	{ 0x130304, 4, 0x1c, 0x924},
+	{ 0x130380, 1, 0x1c, 0x924},
+	{ 0x130400, 1, 0x1c, 0x924},
+	{ 0x130480, 1, 0x1c, 0xfff},
+	{ 0x130484, 4, 0x1c, 0x924},
+	{ 0x130800, 72, 0x1c, 0x924},
+	{ 0x131000, 136, 0x1c, 0x924},
+	{ 0x132000, 148, 0x1c, 0x924},
+	{ 0x134000, 544, 0x1c, 0x924},
+	{ 0x140000, 1, 0x1f, 0x924},
+	{ 0x140004, 9, 0xf, 0x924},
+	{ 0x140028, 8, 0x1f, 0x924},
+	{ 0x140048, 5, 0xf, 0x924},
+	{ 0x14005c, 2, 0xf, 0xfff},
+	{ 0x140064, 3, 0xf, 0x924},
+	{ 0x140070, 1, 0x1f, 0x924},
+	{ 0x140074, 10, 0xf, 0x924},
+	{ 0x14009c, 1, 0x1f, 0x924},
+	{ 0x1400a0, 5, 0xf, 0x924},
+	{ 0x1400b4, 7, 0x1f, 0x924},
+	{ 0x1400d0, 2, 0xf, 0xfff},
+	{ 0x1400d8, 2, 0xf, 0x924},
+	{ 0x1400e0, 1, 0xf, 0xfff},
+	{ 0x1400e4, 5, 0xf, 0x924},
+	{ 0x1400f8, 2, 0x1f, 0x924},
+	{ 0x140100, 5, 0x3, 0x924},
+	{ 0x140114, 5, 0xf, 0x924},
+	{ 0x140128, 7, 0x1f, 0x924},
+	{ 0x140144, 9, 0xf, 0x924},
+	{ 0x140168, 8, 0x1f, 0x924},
+	{ 0x140188, 3, 0xf, 0x924},
+	{ 0x140194, 13, 0x1f, 0x924},
+	{ 0x1401d8, 2, 0x1f, 0x1fff},
+	{ 0x1401e4, 1, 0x1f, 0x1fff},
+	{ 0x140200, 6, 0xf, 0xfff},
+	{ 0x1402e0, 2, 0xc, 0x924},
+	{ 0x1402e8, 2, 0x1c, 0x924},
+	{ 0x1402f0, 9, 0xc, 0x924},
+	{ 0x140314, 9, 0x10, 0x924},
+	{ 0x140338, 7, 0x10, 0xfff},
+	{ 0x140354, 7, 0x10, 0x924},
+	{ 0x140370, 7, 0x10, 0xfff},
+	{ 0x14038c, 14, 0x10, 0x924},
+	{ 0x1404b0, 14, 0x10, 0x924},
+	{ 0x15c000, 2, 0x1e, 0x924},
+	{ 0x15c008, 5, 0x2, 0x924},
+	{ 0x15c020, 8, 0x1c, 0x924},
+	{ 0x15c040, 1, 0xc, 0x924},
+	{ 0x15c044, 2, 0x1c, 0x924},
+	{ 0x15c04c, 8, 0xc, 0x924},
+	{ 0x15c06c, 8, 0x1c, 0x924},
+	{ 0x15c090, 13, 0x1c, 0x924},
+	{ 0x15c0c8, 24, 0x1c, 0x924},
+	{ 0x15c128, 2, 0xc, 0x924},
+	{ 0x15c130, 1, 0x1c, 0x924},
+	{ 0x15c138, 6, 0x1c, 0x924},
+	{ 0x15c150, 2, 0x18, 0x924},
+	{ 0x15c158, 2, 0x8, 0x924},
+	{ 0x15c160, 23, 0x10, 0x924},
+	{ 0x15c1bc, 6, 0x10, 0xfff},
+	{ 0x15c1d4, 23, 0x10, 0x924},
+	{ 0x15c230, 7, 0x10, 0xfff},
+	{ 0x15c24c, 90, 0x10, 0x924},
+	{ 0x160004, 6, 0x18, 0x924},
+	{ 0x16003c, 1, 0x10, 0x924},
+	{ 0x160040, 6, 0x18, 0x924},
+	{ 0x16005c, 6, 0x18, 0x924},
+	{ 0x160074, 1, 0x10, 0x924},
+	{ 0x160078, 2, 0x18, 0x924},
+	{ 0x160300, 8, 0x18, 0x924},
+	{ 0x160330, 6, 0x18, 0x924},
+	{ 0x160404, 6, 0x18, 0x924},
+	{ 0x16043c, 1, 0x10, 0x924},
+	{ 0x160440, 6, 0x18, 0x924},
+	{ 0x16045c, 6, 0x18, 0x924},
+	{ 0x160474, 1, 0x10, 0x924},
+	{ 0x160478, 2, 0x18, 0x924},
+	{ 0x160700, 8, 0x18, 0x924},
+	{ 0x160730, 6, 0x18, 0x924},
+	{ 0x161000, 7, 0x1f, 0x924},
+	{ 0x16102c, 2, 0x1f, 0x1fff},
+	{ 0x161038, 1, 0x1f, 0x1fff},
+	{ 0x16103c, 2, 0x1c, 0x924},
+	{ 0x161800, 2, 0x1f, 0x924},
+	{ 0x162000, 54, 0x18, 0x924},
+	{ 0x162200, 60, 0x18, 0x924},
+	{ 0x162400, 54, 0x18, 0x924},
+	{ 0x162600, 60, 0x18, 0x924},
+	{ 0x162800, 54, 0x18, 0x924},
+	{ 0x162a00, 60, 0x18, 0x924},
+	{ 0x162c00, 54, 0x18, 0x924},
+	{ 0x162e00, 60, 0x18, 0x924},
+	{ 0x163000, 1, 0x18, 0x924},
+	{ 0x163008, 1, 0x18, 0x924},
+	{ 0x163010, 1, 0x18, 0x924},
+	{ 0x163018, 1, 0x18, 0x924},
+	{ 0x163020, 5, 0x18, 0x924},
+	{ 0x163038, 3, 0x18, 0x924},
+	{ 0x163048, 3, 0x18, 0x924},
+	{ 0x163058, 1, 0x18, 0x924},
+	{ 0x163060, 1, 0x18, 0x924},
+	{ 0x163068, 1, 0x18, 0x924},
+	{ 0x163070, 3, 0x18, 0x924},
+	{ 0x163080, 1, 0x18, 0x924},
+	{ 0x163088, 3, 0x18, 0x924},
+	{ 0x163098, 1, 0x18, 0x924},
+	{ 0x1630a0, 1, 0x18, 0x924},
+	{ 0x1630a8, 1, 0x18, 0x924},
+	{ 0x1630b0, 2, 0x10, 0x924},
+	{ 0x1630c0, 1, 0x18, 0x924},
+	{ 0x1630c8, 1, 0x18, 0x924},
+	{ 0x1630d0, 1, 0x18, 0x924},
+	{ 0x1630d8, 1, 0x18, 0x924},
+	{ 0x1630e0, 2, 0x18, 0x924},
+	{ 0x163110, 1, 0x18, 0x924},
+	{ 0x163120, 2, 0x18, 0x924},
+	{ 0x163420, 4, 0x18, 0x924},
+	{ 0x163438, 2, 0x18, 0x924},
+	{ 0x163488, 2, 0x18, 0x924},
+	{ 0x163520, 2, 0x18, 0x924},
+	{ 0x163800, 1, 0x18, 0x924},
+	{ 0x163808, 1, 0x18, 0x924},
+	{ 0x163810, 1, 0x18, 0x924},
+	{ 0x163818, 1, 0x18, 0x924},
+	{ 0x163820, 5, 0x18, 0x924},
+	{ 0x163838, 3, 0x18, 0x924},
+	{ 0x163848, 3, 0x18, 0x924},
+	{ 0x163858, 1, 0x18, 0x924},
+	{ 0x163860, 1, 0x18, 0x924},
+	{ 0x163868, 1, 0x18, 0x924},
+	{ 0x163870, 3, 0x18, 0x924},
+	{ 0x163880, 1, 0x18, 0x924},
+	{ 0x163888, 3, 0x18, 0x924},
+	{ 0x163898, 1, 0x18, 0x924},
+	{ 0x1638a0, 1, 0x18, 0x924},
+	{ 0x1638a8, 1, 0x18, 0x924},
+	{ 0x1638b0, 2, 0x10, 0x924},
+	{ 0x1638c0, 1, 0x18, 0x924},
+	{ 0x1638c8, 1, 0x18, 0x924},
+	{ 0x1638d0, 1, 0x18, 0x924},
+	{ 0x1638d8, 1, 0x18, 0x924},
+	{ 0x1638e0, 2, 0x18, 0x924},
+	{ 0x163910, 1, 0x18, 0x924},
+	{ 0x163920, 2, 0x18, 0x924},
+	{ 0x163c20, 4, 0x18, 0x924},
+	{ 0x163c38, 2, 0x18, 0x924},
+	{ 0x163c88, 2, 0x18, 0x924},
+	{ 0x163d20, 2, 0x18, 0x924},
+	{ 0x164000, 5, 0x1f, 0x924},
+	{ 0x164014, 2, 0x1f, 0xfff},
+	{ 0x16401c, 53, 0x1f, 0x924},
+	{ 0x164100, 2, 0x1f, 0x1fff},
+	{ 0x16410c, 1, 0x1f, 0x1fff},
+	{ 0x164110, 2, 0x1e, 0x924},
+	{ 0x164118, 15, 0x1c, 0x924},
+	{ 0x164200, 1, 0x1f, 0x924},
+	{ 0x164208, 1, 0x1f, 0x924},
+	{ 0x164210, 1, 0x1f, 0x924},
+	{ 0x164218, 1, 0x1f, 0x924},
+	{ 0x164220, 1, 0x1f, 0x924},
+	{ 0x164228, 1, 0x1f, 0x924},
+	{ 0x164230, 1, 0x1f, 0x924},
+	{ 0x164238, 1, 0x1f, 0x924},
+	{ 0x164240, 1, 0x1f, 0x924},
+	{ 0x164248, 1, 0x1f, 0x924},
+	{ 0x164250, 1, 0x1f, 0x924},
+	{ 0x164258, 1, 0x1f, 0x924},
+	{ 0x164260, 1, 0x1f, 0x924},
+	{ 0x164270, 2, 0x1f, 0x924},
+	{ 0x164280, 2, 0x1f, 0x924},
+	{ 0x164800, 2, 0x1f, 0x924},
+	{ 0x165000, 2, 0x1f, 0x924},
+	{ 0x166000, 164, 0x1f, 0x924},
+	{ 0x1662b0, 2, 0x1f, 0x1fff},
+	{ 0x1662bc, 1, 0x1f, 0x1fff},
+	{ 0x1662cc, 7, 0x1c, 0x924},
+	{ 0x166400, 49, 0x1f, 0x924},
+	{ 0x1664c8, 32, 0x1f, 0x924},
+	{ 0x166548, 1, 0x1f, 0xfff},
+	{ 0x16654c, 1, 0x1f, 0x924},
+	{ 0x166550, 1, 0x1f, 0xfff},
+	{ 0x166554, 1, 0x1f, 0x924},
+	{ 0x166558, 1, 0x1f, 0xfff},
+	{ 0x16655c, 1, 0x1f, 0x924},
+	{ 0x166568, 2, 0x1f, 0x924},
+	{ 0x166570, 5, 0x1c, 0x924},
+	{ 0x166800, 1, 0x1f, 0x924},
+	{ 0x168000, 1, 0x1f, 0xfff},
+	{ 0x168004, 1, 0x1f, 0x924},
+	{ 0x168008, 1, 0x1f, 0xfff},
+	{ 0x16800c, 1, 0x1f, 0x924},
+	{ 0x168010, 1, 0x1f, 0xfff},
+	{ 0x168014, 1, 0x1f, 0x924},
+	{ 0x168018, 1, 0x1f, 0xfff},
+	{ 0x16801c, 3, 0x1f, 0x924},
+	{ 0x168028, 2, 0x1f, 0xfff},
+	{ 0x168030, 10, 0x1f, 0x924},
+	{ 0x168058, 9, 0x1f, 0xfff},
+	{ 0x16807c, 106, 0x1f, 0x924},
+	{ 0x168224, 2, 0x3, 0x924},
+	{ 0x16822c, 3, 0x1f, 0x924},
+	{ 0x168238, 1, 0x1f, 0xfff},
+	{ 0x16823c, 25, 0x1f, 0x924},
+	{ 0x1682a0, 12, 0x3, 0x924},
+	{ 0x1682d0, 7, 0x1f, 0xfff},
+	{ 0x1682ec, 5, 0x1f, 0x924},
+	{ 0x168300, 2, 0x3, 0xfff},
+	{ 0x168308, 65, 0x1f, 0xfff},
+	{ 0x16840c, 1, 0x1f, 0x924},
+	{ 0x168410, 2, 0x1f, 0xfff},
+	{ 0x168418, 2, 0x3, 0x924},
+	{ 0x168420, 6, 0x1f, 0x924},
+	{ 0x168448, 2, 0x1f, 0x1fff},
+	{ 0x168454, 1, 0x1f, 0x1fff},
+	{ 0x168800, 19, 0x1f, 0x924},
+	{ 0x168900, 1, 0x1f, 0x924},
+	{ 0x168a00, 128, 0x1f, 0xfff},
+	{ 0x16a000, 1536, 0x1f, 0x924},
+	{ 0x16c000, 1536, 0x1f, 0x924},
+	{ 0x16e000, 16, 0x2, 0x924},
+	{ 0x16e040, 8, 0x1c, 0x924},
+	{ 0x16e100, 1, 0x2, 0x924},
+	{ 0x16e200, 2, 0x2, 0xfff},
+	{ 0x16e400, 1, 0x2, 0x924},
+	{ 0x16e404, 2, 0x2, 0xfff},
+	{ 0x16e40c, 94, 0x2, 0x924},
+	{ 0x16e584, 64, 0x2, 0xfff},
+	{ 0x16e684, 2, 0x1e, 0xfff},
+	{ 0x16e68c, 4, 0x2, 0xfff},
+	{ 0x16e69c, 8, 0x2, 0x924},
+	{ 0x16e6bc, 4, 0x1e, 0x924},
+	{ 0x16e6cc, 4, 0x2, 0x924},
+	{ 0x16e6e0, 2, 0x1c, 0x924},
+	{ 0x16e6e8, 5, 0xc, 0x924},
+	{ 0x16e6fc, 4, 0x1c, 0xfff},
+	{ 0x16e70c, 1, 0x1c, 0x924},
+	{ 0x16e768, 17, 0x1c, 0x924},
+	{ 0x16e7ac, 12, 0x10, 0xfff},
+	{ 0x170000, 24, 0x1f, 0x924},
+	{ 0x170060, 4, 0x3, 0x924},
+	{ 0x170070, 13, 0x1f, 0x924},
+	{ 0x1700a4, 1, 0x1f, 0xfff},
+	{ 0x1700a8, 1, 0x1f, 0x924},
+	{ 0x1700ac, 2, 0x1f, 0xfff},
+	{ 0x1700b4, 3, 0x1f, 0x924},
+	{ 0x1700c0, 1, 0x1f, 0xfff},
+	{ 0x1700c4, 44, 0x1f, 0x924},
+	{ 0x170184, 2, 0x1f, 0x1fff},
+	{ 0x170190, 1, 0x1f, 0x1fff},
+	{ 0x170194, 11, 0x1c, 0x924},
+	{ 0x1701c4, 1, 0x1c, 0x924},
+	{ 0x1701cc, 7, 0x1c, 0x924},
+	{ 0x1701e8, 1, 0x18, 0x924},
+	{ 0x1701ec, 1, 0x1c, 0x924},
+	{ 0x1701f4, 1, 0x1c, 0x924},
+	{ 0x170200, 4, 0x1f, 0x924},
+	{ 0x170214, 1, 0x1f, 0x924},
+	{ 0x170218, 77, 0x1c, 0x924},
+	{ 0x170400, 64, 0x1c, 0x924},
+	{ 0x178000, 1, 0x1f, 0x924},
+	{ 0x180000, 61, 0x1f, 0x924},
+	{ 0x180114, 2, 0x1f, 0x1fff},
+	{ 0x180120, 3, 0x1f, 0x1fff},
+	{ 0x180130, 1, 0x1f, 0x1fff},
+	{ 0x18013c, 2, 0x1e, 0x924},
+	{ 0x180200, 27, 0x1f, 0x924},
+	{ 0x18026c, 1, 0x1f, 0xfff},
+	{ 0x180270, 12, 0x1f, 0x924},
+	{ 0x1802a0, 1, 0x1f, 0xfff},
+	{ 0x1802a4, 17, 0x1f, 0x924},
+	{ 0x180340, 4, 0x1f, 0x924},
+	{ 0x180380, 1, 0x1c, 0x924},
+	{ 0x180388, 1, 0x1c, 0x924},
+	{ 0x180390, 1, 0x1c, 0x924},
+	{ 0x180398, 1, 0x1c, 0x924},
+	{ 0x1803a0, 5, 0x1c, 0x924},
+	{ 0x1803b4, 2, 0x18, 0x924},
+	{ 0x180400, 256, 0x3, 0xfff},
+	{ 0x181000, 4, 0x1f, 0x93c},
+	{ 0x181010, 1020, 0x1f, 0x38},
+	{ 0x182000, 4, 0x18, 0x924},
+	{ 0x1a0000, 1, 0x1f, 0x92c},
+	{ 0x1a0004, 5631, 0x1f, 0x8},
+	{ 0x1a5800, 2560, 0x1e, 0x8},
+	{ 0x1a8000, 1, 0x1f, 0x92c},
+	{ 0x1a8004, 8191, 0x1e, 0x8},
+	{ 0x1b0000, 1, 0x1f, 0x92c},
+	{ 0x1b0004, 15, 0x2, 0x8},
+	{ 0x1b0040, 1, 0x1e, 0x92c},
+	{ 0x1b0044, 239, 0x2, 0x8},
+	{ 0x1b0400, 1, 0x1f, 0x92c},
+	{ 0x1b0404, 255, 0x2, 0x8},
+	{ 0x1b0800, 1, 0x1f, 0x924},
+	{ 0x1b0840, 1, 0x1e, 0x924},
+	{ 0x1b0c00, 1, 0x1f, 0x1fff},
+	{ 0x1b1000, 1, 0x1f, 0x1fff},
+	{ 0x1b1040, 1, 0x1e, 0x1fff},
+	{ 0x1b1400, 1, 0x1f, 0x924},
+	{ 0x1b1440, 1, 0x1e, 0x924},
+	{ 0x1b1480, 1, 0x1e, 0x924},
+	{ 0x1b14c0, 1, 0x1e, 0x924},
+	{ 0x1b1800, 128, 0x1f, 0x10},
+	{ 0x1b1c00, 128, 0x1f, 0x10},
+	{ 0x1b2000, 1, 0x1f, 0xdb6},
+	{ 0x1b2400, 1, 0x1e, 0x92c},
+	{ 0x1b2404, 5631, 0x1c, 0x8},
+	{ 0x1b8000, 1, 0x1f, 0xfff},
+	{ 0x1b8040, 1, 0x1f, 0xfff},
+	{ 0x1b8080, 1, 0x1f, 0xfff},
+	{ 0x1b80c0, 1, 0x1f, 0xfff},
+	{ 0x1b8100, 1, 0x1f, 0x924},
+	{ 0x1b8140, 1, 0x1f, 0x924},
+	{ 0x1b8180, 1, 0x1f, 0x924},
+	{ 0x1b81c0, 1, 0x1f, 0x924},
+	{ 0x1b8200, 1, 0x1f, 0x924},
+	{ 0x1b8240, 1, 0x1f, 0x924},
+	{ 0x1b8280, 1, 0x1f, 0x924},
+	{ 0x1b82c0, 1, 0x1f, 0x924},
+	{ 0x1b8300, 1, 0x1f, 0x924},
+	{ 0x1b8340, 1, 0x1f, 0x924},
+	{ 0x1b8380, 1, 0x1f, 0x924},
+	{ 0x1b83c0, 1, 0x1f, 0x924},
+	{ 0x1b8400, 1, 0x1f, 0x924},
+	{ 0x1b8440, 1, 0x1f, 0x924},
+	{ 0x1b8480, 1, 0x1f, 0x924},
+	{ 0x1b84c0, 1, 0x1f, 0x924},
+	{ 0x1b8500, 1, 0x1f, 0x924},
+	{ 0x1b8540, 1, 0x1f, 0x924},
+	{ 0x1b8580, 1, 0x1f, 0x924},
+	{ 0x1b85c0, 19, 0x1c, 0x924},
+	{ 0x1b8800, 1, 0x1f, 0x924},
+	{ 0x1b8840, 1, 0x1f, 0x924},
+	{ 0x1b8880, 1, 0x1f, 0x924},
+	{ 0x1b88c0, 1, 0x1f, 0x924},
+	{ 0x1b8900, 1, 0x1f, 0x924},
+	{ 0x1b8940, 1, 0x1f, 0x924},
+	{ 0x1b8980, 1, 0x1f, 0x924},
+	{ 0x1b89c0, 1, 0x1f, 0x924},
+	{ 0x1b8a00, 1, 0x1f, 0x934},
+	{ 0x1b8a40, 1, 0x1f, 0x924},
+	{ 0x1b8a80, 1, 0x1f, 0x492},
+	{ 0x1b8ac0, 1, 0x1f, 0x924},
+	{ 0x1b8b00, 1, 0x1f, 0x924},
+	{ 0x1b8b40, 1, 0x1f, 0x924},
+	{ 0x1b8b80, 1, 0x1f, 0x924},
+	{ 0x1b8bc0, 1, 0x1f, 0x924},
+	{ 0x1b8c00, 1, 0x1f, 0x924},
+	{ 0x1b8c40, 1, 0x1f, 0x924},
+	{ 0x1b8c80, 1, 0x1f, 0x924},
+	{ 0x1b8cc0, 1, 0x1f, 0x924},
+	{ 0x1b8cc4, 1, 0x1c, 0x924},
+	{ 0x1b8d00, 1, 0x1f, 0x924},
+	{ 0x1b8d40, 1, 0x1f, 0x924},
+	{ 0x1b8d80, 1, 0x1f, 0x924},
+	{ 0x1b8dc0, 1, 0x1f, 0x924},
+	{ 0x1b8e00, 1, 0x1f, 0x924},
+	{ 0x1b8e40, 1, 0x1f, 0x924},
+	{ 0x1b8e80, 1, 0x1f, 0x924},
+	{ 0x1b8e84, 1, 0x1c, 0x924},
+	{ 0x1b8ec0, 1, 0x1e, 0x924},
+	{ 0x1b8f00, 1, 0x1e, 0x924},
+	{ 0x1b8f40, 1, 0x1e, 0x924},
+	{ 0x1b8f80, 1, 0x1e, 0x924},
+	{ 0x1b8fc0, 1, 0x1e, 0x924},
+	{ 0x1b8fd4, 5, 0x1c, 0x924},
+	{ 0x1b8fe8, 2, 0x18, 0x924},
+	{ 0x1b9000, 1, 0x1c, 0x924},
+	{ 0x1b9040, 3, 0x1c, 0x924},
+	{ 0x1b905c, 1, 0x18, 0x924},
+	{ 0x1b9064, 1, 0x10, 0x924},
+	{ 0x1b9080, 10, 0x10, 0x924},
+	{ 0x1c0000, 2, 0x1f, 0x924},
+	{ 0x200000, 65, 0x1f, 0x924},
+	{ 0x200124, 2, 0x1f, 0x1fff},
+	{ 0x200130, 3, 0x1f, 0x1fff},
+	{ 0x200140, 1, 0x1f, 0x1fff},
+	{ 0x20014c, 2, 0x1e, 0x924},
+	{ 0x200200, 27, 0x1f, 0x924},
+	{ 0x20026c, 1, 0x1f, 0xfff},
+	{ 0x200270, 12, 0x1f, 0x924},
+	{ 0x2002a0, 1, 0x1f, 0xfff},
+	{ 0x2002a4, 17, 0x1f, 0x924},
+	{ 0x200340, 4, 0x1f, 0x924},
+	{ 0x200380, 1, 0x1c, 0x924},
+	{ 0x200388, 1, 0x1c, 0x924},
+	{ 0x200390, 1, 0x1c, 0x924},
+	{ 0x200398, 1, 0x1c, 0x924},
+	{ 0x2003a0, 1, 0x1c, 0x924},
+	{ 0x2003a8, 2, 0x1c, 0x924},
+	{ 0x200400, 256, 0x3, 0xfff},
+	{ 0x202000, 4, 0x1f, 0x1927},
+	{ 0x202010, 2044, 0x1f, 0x1007},
+	{ 0x204000, 4, 0x18, 0x924},
+	{ 0x220000, 1, 0x1f, 0x925},
+	{ 0x220004, 5631, 0x1f, 0x1},
+	{ 0x225800, 2560, 0x1e, 0x1},
+	{ 0x228000, 1, 0x1f, 0x925},
+	{ 0x228004, 8191, 0x1e, 0x1},
+	{ 0x230000, 1, 0x1f, 0x925},
+	{ 0x230004, 15, 0x2, 0x1},
+	{ 0x230040, 1, 0x1e, 0x925},
+	{ 0x230044, 239, 0x2, 0x1},
+	{ 0x230400, 1, 0x1f, 0x925},
+	{ 0x230404, 255, 0x2, 0x1},
+	{ 0x230800, 1, 0x1f, 0x924},
+	{ 0x230840, 1, 0x1e, 0x924},
+	{ 0x230c00, 1, 0x1f, 0x924},
+	{ 0x231000, 1, 0x1f, 0x924},
+	{ 0x231040, 1, 0x1e, 0x924},
+	{ 0x231400, 1, 0x1f, 0x924},
+	{ 0x231440, 1, 0x1e, 0x924},
+	{ 0x231480, 1, 0x1e, 0x924},
+	{ 0x2314c0, 1, 0x1e, 0x924},
+	{ 0x231800, 128, 0x1f, 0x2},
+	{ 0x231c00, 128, 0x1f, 0x2},
+	{ 0x232000, 1, 0x1f, 0xdb6},
+	{ 0x232400, 1, 0x1e, 0x925},
+	{ 0x232404, 5631, 0x1c, 0x1},
+	{ 0x238000, 1, 0x1f, 0xfff},
+	{ 0x238040, 1, 0x1f, 0xfff},
+	{ 0x238080, 1, 0x1f, 0xfff},
+	{ 0x2380c0, 1, 0x1f, 0xfff},
+	{ 0x238100, 1, 0x1f, 0x924},
+	{ 0x238140, 1, 0x1f, 0x924},
+	{ 0x238180, 1, 0x1f, 0x924},
+	{ 0x2381c0, 1, 0x1f, 0x924},
+	{ 0x238200, 1, 0x1f, 0x924},
+	{ 0x238240, 1, 0x1f, 0x924},
+	{ 0x238280, 1, 0x1f, 0x924},
+	{ 0x2382c0, 1, 0x1f, 0x924},
+	{ 0x238300, 1, 0x1f, 0x924},
+	{ 0x238340, 1, 0x1f, 0x924},
+	{ 0x238380, 1, 0x1f, 0x924},
+	{ 0x2383c0, 1, 0x1f, 0x924},
+	{ 0x238400, 1, 0x1f, 0x924},
+	{ 0x238440, 1, 0x1f, 0x924},
+	{ 0x238480, 1, 0x1f, 0x924},
+	{ 0x2384c0, 1, 0x1f, 0x924},
+	{ 0x238500, 1, 0x1f, 0x924},
+	{ 0x238540, 1, 0x1f, 0x924},
+	{ 0x238580, 1, 0x1f, 0x924},
+	{ 0x2385c0, 19, 0x1c, 0x924},
+	{ 0x238800, 1, 0x1f, 0x924},
+	{ 0x238840, 1, 0x1f, 0x924},
+	{ 0x238880, 1, 0x1f, 0x924},
+	{ 0x2388c0, 1, 0x1f, 0x924},
+	{ 0x238900, 1, 0x1f, 0x924},
+	{ 0x238940, 1, 0x1f, 0x924},
+	{ 0x238980, 1, 0x1f, 0x924},
+	{ 0x2389c0, 1, 0x1f, 0x924},
+	{ 0x238a00, 1, 0x1f, 0x926},
+	{ 0x238a40, 1, 0x1f, 0x924},
+	{ 0x238a80, 1, 0x1f, 0x492},
+	{ 0x238ac0, 1, 0x1f, 0x924},
+	{ 0x238b00, 1, 0x1f, 0x924},
+	{ 0x238b40, 1, 0x1f, 0x924},
+	{ 0x238b80, 1, 0x1f, 0x924},
+	{ 0x238bc0, 1, 0x1f, 0x924},
+	{ 0x238c00, 1, 0x1f, 0x924},
+	{ 0x238c40, 1, 0x1f, 0x924},
+	{ 0x238c80, 1, 0x1f, 0x924},
+	{ 0x238cc0, 1, 0x1f, 0x924},
+	{ 0x238cc4, 1, 0x1c, 0x924},
+	{ 0x238d00, 1, 0x1f, 0x924},
+	{ 0x238d40, 1, 0x1f, 0x924},
+	{ 0x238d80, 1, 0x1f, 0x924},
+	{ 0x238dc0, 1, 0x1f, 0x924},
+	{ 0x238e00, 1, 0x1f, 0x924},
+	{ 0x238e40, 1, 0x1f, 0x924},
+	{ 0x238e80, 1, 0x1f, 0x924},
+	{ 0x238e84, 1, 0x1c, 0x924},
+	{ 0x238ec0, 1, 0x1e, 0x924},
+	{ 0x238f00, 1, 0x1e, 0x924},
+	{ 0x238f40, 1, 0x1e, 0x924},
+	{ 0x238f80, 1, 0x1e, 0x924},
+	{ 0x238fc0, 1, 0x1e, 0x924},
+	{ 0x238fd4, 5, 0x1c, 0x924},
+	{ 0x238fe8, 2, 0x18, 0x924},
+	{ 0x239000, 1, 0x1c, 0x924},
+	{ 0x239040, 3, 0x1c, 0x924},
+	{ 0x23905c, 1, 0x18, 0x924},
+	{ 0x239064, 1, 0x10, 0x924},
+	{ 0x239080, 10, 0x10, 0x924},
+	{ 0x240000, 2, 0x1f, 0x924},
+	{ 0x280000, 65, 0x1f, 0x924},
+	{ 0x280124, 2, 0x1f, 0x1fff},
+	{ 0x280130, 3, 0x1f, 0x1fff},
+	{ 0x280140, 1, 0x1f, 0x1fff},
+	{ 0x28014c, 2, 0x1e, 0x924},
+	{ 0x280200, 27, 0x1f, 0x924},
+	{ 0x28026c, 1, 0x1f, 0xfff},
+	{ 0x280270, 12, 0x1f, 0x924},
+	{ 0x2802a0, 1, 0x1f, 0xfff},
+	{ 0x2802a4, 17, 0x1f, 0x924},
+	{ 0x280340, 4, 0x1f, 0x924},
+	{ 0x280380, 1, 0x1c, 0x924},
+	{ 0x280388, 1, 0x1c, 0x924},
+	{ 0x280390, 1, 0x1c, 0x924},
+	{ 0x280398, 1, 0x1c, 0x924},
+	{ 0x2803a0, 1, 0x1c, 0x924},
+	{ 0x2803a8, 2, 0x1c, 0x924},
+	{ 0x280400, 256, 0x3, 0xfff},
+	{ 0x282000, 4, 0x1f, 0x9e4},
+	{ 0x282010, 2044, 0x1f, 0x1c0},
+	{ 0x284000, 4, 0x18, 0x924},
+	{ 0x2a0000, 1, 0x1f, 0x964},
+	{ 0x2a0004, 5631, 0x1f, 0x40},
+	{ 0x2a5800, 2560, 0x1e, 0x40},
+	{ 0x2a8000, 1, 0x1f, 0x964},
+	{ 0x2a8004, 8191, 0x1e, 0x40},
+	{ 0x2b0000, 1, 0x1f, 0x964},
+	{ 0x2b0004, 15, 0x2, 0x40},
+	{ 0x2b0040, 1, 0x1e, 0x964},
+	{ 0x2b0044, 239, 0x2, 0x40},
+	{ 0x2b0400, 1, 0x1f, 0x964},
+	{ 0x2b0404, 255, 0x2, 0x40},
+	{ 0x2b0800, 1, 0x1f, 0x924},
+	{ 0x2b0840, 1, 0x1e, 0x924},
+	{ 0x2b0c00, 1, 0x1f, 0x924},
+	{ 0x2b1000, 1, 0x1f, 0x924},
+	{ 0x2b1040, 1, 0x1e, 0x924},
+	{ 0x2b1400, 1, 0x1f, 0x924},
+	{ 0x2b1440, 1, 0x1e, 0x924},
+	{ 0x2b1480, 1, 0x1e, 0x924},
+	{ 0x2b14c0, 1, 0x1e, 0x924},
+	{ 0x2b1800, 128, 0x1f, 0x80},
+	{ 0x2b1c00, 128, 0x1f, 0x80},
+	{ 0x2b2000, 1, 0x1f, 0xdb6},
+	{ 0x2b2400, 1, 0x1e, 0x964},
+	{ 0x2b2404, 5631, 0x1c, 0x40},
+	{ 0x2b8000, 1, 0x1f, 0xfff},
+	{ 0x2b8040, 1, 0x1f, 0xfff},
+	{ 0x2b8080, 1, 0x1f, 0xfff},
+	{ 0x2b80c0, 1, 0x1f, 0x924},
+	{ 0x2b8100, 1, 0x1f, 0x924},
+	{ 0x2b8140, 1, 0x1f, 0x924},
+	{ 0x2b8180, 1, 0x1f, 0x924},
+	{ 0x2b81c0, 1, 0x1f, 0x924},
+	{ 0x2b8200, 1, 0x1f, 0x924},
+	{ 0x2b8240, 1, 0x1f, 0x924},
+	{ 0x2b8280, 1, 0x1f, 0x924},
+	{ 0x2b82c0, 1, 0x1f, 0x924},
+	{ 0x2b8300, 1, 0x1f, 0x924},
+	{ 0x2b8340, 1, 0x1f, 0x924},
+	{ 0x2b8380, 1, 0x1f, 0x924},
+	{ 0x2b83c0, 1, 0x1f, 0x924},
+	{ 0x2b8400, 1, 0x1f, 0x924},
+	{ 0x2b8440, 1, 0x1f, 0x924},
+	{ 0x2b8480, 1, 0x1f, 0x924},
+	{ 0x2b84c0, 1, 0x1f, 0x924},
+	{ 0x2b8500, 1, 0x1f, 0x924},
+	{ 0x2b8540, 1, 0x1f, 0x924},
+	{ 0x2b8580, 1, 0x1f, 0x924},
+	{ 0x2b85c0, 19, 0x1c, 0x924},
+	{ 0x2b8800, 1, 0x1f, 0x924},
+	{ 0x2b8840, 1, 0x1f, 0x924},
+	{ 0x2b8880, 1, 0x1f, 0x924},
+	{ 0x2b88c0, 1, 0x1f, 0x924},
+	{ 0x2b8900, 1, 0x1f, 0x924},
+	{ 0x2b8940, 1, 0x1f, 0x924},
+	{ 0x2b8980, 1, 0x1f, 0x924},
+	{ 0x2b89c0, 1, 0x1f, 0x924},
+	{ 0x2b8a00, 1, 0x1f, 0x9a4},
+	{ 0x2b8a40, 1, 0x1f, 0x924},
+	{ 0x2b8a80, 1, 0x1f, 0x492},
+	{ 0x2b8ac0, 1, 0x1f, 0x924},
+	{ 0x2b8b00, 1, 0x1f, 0x924},
+	{ 0x2b8b40, 1, 0x1f, 0x924},
+	{ 0x2b8b80, 1, 0x1f, 0x924},
+	{ 0x2b8bc0, 1, 0x1f, 0x924},
+	{ 0x2b8c00, 1, 0x1f, 0x924},
+	{ 0x2b8c40, 1, 0x1f, 0x924},
+	{ 0x2b8c80, 1, 0x1f, 0x924},
+	{ 0x2b8cc0, 1, 0x1f, 0x924},
+	{ 0x2b8cc4, 1, 0x1c, 0x924},
+	{ 0x2b8d00, 1, 0x1f, 0x924},
+	{ 0x2b8d40, 1, 0x1f, 0x924},
+	{ 0x2b8d80, 1, 0x1f, 0x924},
+	{ 0x2b8dc0, 1, 0x1f, 0x924},
+	{ 0x2b8e00, 1, 0x1f, 0x924},
+	{ 0x2b8e40, 1, 0x1f, 0x924},
+	{ 0x2b8e80, 1, 0x1f, 0x924},
+	{ 0x2b8e84, 1, 0x1c, 0x924},
+	{ 0x2b8ec0, 1, 0x1e, 0x924},
+	{ 0x2b8f00, 1, 0x1e, 0x924},
+	{ 0x2b8f40, 1, 0x1e, 0x924},
+	{ 0x2b8f80, 1, 0x1e, 0x924},
+	{ 0x2b8fc0, 1, 0x1e, 0x924},
+	{ 0x2b8fd4, 5, 0x1c, 0x924},
+	{ 0x2b8fe8, 2, 0x18, 0x924},
+	{ 0x2b9000, 1, 0x1c, 0x924},
+	{ 0x2b9040, 3, 0x1c, 0x924},
+	{ 0x2b905c, 1, 0x18, 0x924},
+	{ 0x2b9064, 1, 0x10, 0x924},
+	{ 0x2b9080, 10, 0x10, 0x924},
+	{ 0x2c0000, 2, 0x1f, 0x1fff},
+	{ 0x300000, 65, 0x1f, 0x924},
+	{ 0x300124, 2, 0x1f, 0x1fff},
+	{ 0x300130, 3, 0x1f, 0x1fff},
+	{ 0x300140, 1, 0x1f, 0x1fff},
+	{ 0x30014c, 2, 0x1e, 0x924},
+	{ 0x300200, 27, 0x1f, 0x924},
+	{ 0x30026c, 1, 0x1f, 0xfff},
+	{ 0x300270, 12, 0x1f, 0x924},
+	{ 0x3002a0, 1, 0x1f, 0xfff},
+	{ 0x3002a4, 17, 0x1f, 0x924},
+	{ 0x300340, 4, 0x1f, 0x924},
+	{ 0x300380, 1, 0x1c, 0x924},
+	{ 0x300388, 1, 0x1c, 0x924},
+	{ 0x300390, 1, 0x1c, 0x924},
+	{ 0x300398, 1, 0x1c, 0x924},
+	{ 0x3003a0, 1, 0x1c, 0x924},
+	{ 0x3003a8, 2, 0x1c, 0x924},
+	{ 0x300400, 256, 0x3, 0xfff},
+	{ 0x302000, 4, 0x1f, 0xf24},
+	{ 0x302010, 2044, 0x1f, 0xe00},
+	{ 0x304000, 4, 0x18, 0x924},
+	{ 0x320000, 1, 0x1f, 0xb24},
+	{ 0x320004, 5631, 0x1f, 0x200},
+	{ 0x325800, 2560, 0x1e, 0x200},
+	{ 0x328000, 1, 0x1f, 0xb24},
+	{ 0x328004, 8191, 0x1e, 0x200},
+	{ 0x330000, 1, 0x1f, 0xb24},
+	{ 0x330004, 15, 0x2, 0x200},
+	{ 0x330040, 1, 0x1e, 0xb24},
+	{ 0x330044, 239, 0x2, 0x200},
+	{ 0x330400, 1, 0x1f, 0xb24},
+	{ 0x330404, 255, 0x2, 0x200},
+	{ 0x330800, 1, 0x1f, 0x924},
+	{ 0x330840, 1, 0x1e, 0x924},
+	{ 0x330c00, 1, 0x1f, 0x924},
+	{ 0x331000, 1, 0x1f, 0x924},
+	{ 0x331040, 1, 0x1e, 0x924},
+	{ 0x331400, 1, 0x1f, 0x924},
+	{ 0x331440, 1, 0x1e, 0x924},
+	{ 0x331480, 1, 0x1e, 0x924},
+	{ 0x3314c0, 1, 0x1e, 0x924},
+	{ 0x331800, 128, 0x1f, 0x400},
+	{ 0x331c00, 128, 0x1f, 0x400},
+	{ 0x332000, 1, 0x1f, 0xdb6},
+	{ 0x332400, 1, 0x1e, 0xb24},
+	{ 0x332404, 5631, 0x1c, 0x200},
+	{ 0x338000, 1, 0x1f, 0xfff},
+	{ 0x338040, 1, 0x1f, 0xfff},
+	{ 0x338080, 1, 0x1f, 0xfff},
+	{ 0x3380c0, 1, 0x1f, 0xfff},
+	{ 0x338100, 1, 0x1f, 0x924},
+	{ 0x338140, 1, 0x1f, 0x924},
+	{ 0x338180, 1, 0x1f, 0x924},
+	{ 0x3381c0, 1, 0x1f, 0x924},
+	{ 0x338200, 1, 0x1f, 0x924},
+	{ 0x338240, 1, 0x1f, 0x924},
+	{ 0x338280, 1, 0x1f, 0x924},
+	{ 0x3382c0, 1, 0x1f, 0x924},
+	{ 0x338300, 1, 0x1f, 0x924},
+	{ 0x338340, 1, 0x1f, 0x924},
+	{ 0x338380, 1, 0x1f, 0x924},
+	{ 0x3383c0, 1, 0x1f, 0x924},
+	{ 0x338400, 1, 0x1f, 0x924},
+	{ 0x338440, 1, 0x1f, 0x924},
+	{ 0x338480, 1, 0x1f, 0x924},
+	{ 0x3384c0, 1, 0x1f, 0x924},
+	{ 0x338500, 1, 0x1f, 0x924},
+	{ 0x338540, 1, 0x1f, 0x924},
+	{ 0x338580, 1, 0x1f, 0x924},
+	{ 0x3385c0, 19, 0x1c, 0x924},
+	{ 0x338800, 1, 0x1f, 0x924},
+	{ 0x338840, 1, 0x1f, 0x924},
+	{ 0x338880, 1, 0x1f, 0x924},
+	{ 0x3388c0, 1, 0x1f, 0x924},
+	{ 0x338900, 1, 0x1f, 0x924},
+	{ 0x338940, 1, 0x1f, 0x924},
+	{ 0x338980, 1, 0x1f, 0x924},
+	{ 0x3389c0, 1, 0x1f, 0x924},
+	{ 0x338a00, 1, 0x1f, 0xd24},
+	{ 0x338a40, 1, 0x1f, 0x924},
+	{ 0x338a80, 1, 0x1f, 0x492},
+	{ 0x338ac0, 1, 0x1f, 0x924},
+	{ 0x338b00, 1, 0x1f, 0x924},
+	{ 0x338b40, 1, 0x1f, 0x924},
+	{ 0x338b80, 1, 0x1f, 0x924},
+	{ 0x338bc0, 1, 0x1f, 0x924},
+	{ 0x338c00, 1, 0x1f, 0x924},
+	{ 0x338c40, 1, 0x1f, 0x924},
+	{ 0x338c80, 1, 0x1f, 0x924},
+	{ 0x338cc0, 1, 0x1f, 0x924},
+	{ 0x338cc4, 1, 0x1c, 0x924},
+	{ 0x338d00, 1, 0x1f, 0x924},
+	{ 0x338d40, 1, 0x1f, 0x924},
+	{ 0x338d80, 1, 0x1f, 0x924},
+	{ 0x338dc0, 1, 0x1f, 0x924},
+	{ 0x338e00, 1, 0x1f, 0x924},
+	{ 0x338e40, 1, 0x1f, 0x924},
+	{ 0x338e80, 1, 0x1f, 0x924},
+	{ 0x338e84, 1, 0x1c, 0x924},
+	{ 0x338ec0, 1, 0x1e, 0x924},
+	{ 0x338f00, 1, 0x1e, 0x924},
+	{ 0x338f40, 1, 0x1e, 0x924},
+	{ 0x338f80, 1, 0x1e, 0x924},
+	{ 0x338fc0, 1, 0x1e, 0x924},
+	{ 0x338fd4, 5, 0x1c, 0x924},
+	{ 0x338fe8, 2, 0x18, 0x924},
+	{ 0x339000, 1, 0x1c, 0x924},
+	{ 0x339040, 3, 0x1c, 0x924},
+	{ 0x33905c, 1, 0x18, 0x924},
+	{ 0x339064, 1, 0x10, 0x924},
+	{ 0x339080, 10, 0x10, 0x924},
+	{ 0x340000, 2, 0x1f, 0x924},
+	{ 0x3a0000, 40960, 0x1c, 0x1000}
 };
-#define REGS_COUNT			ARRAY_SIZE(reg_addrs)
 
-static const struct dump_sign dump_sign_all = { 0x4e23fde1, 0x70017, 0x3a };
+#define REGS_COUNT ARRAY_SIZE(reg_addrs)
 
-static const u32 page_vals_e2[] = { 0, 128 };
-#define PAGE_MODE_VALUES_E2		ARRAY_SIZE(page_vals_e2)
+static const struct reg_addr idle_reg_addrs[] = {
+	{ 0x2104, 1, 0x1f, 0xfff},
+	{ 0x2110, 2, 0x1f, 0xfff},
+	{ 0x211c, 8, 0x1f, 0xfff},
+	{ 0x2814, 1, 0x1f, 0xfff},
+	{ 0x281c, 2, 0x1f, 0xfff},
+	{ 0x2854, 1, 0x1f, 0xfff},
+	{ 0x285c, 1, 0x1f, 0xfff},
+	{ 0x3040, 1, 0x1f, 0xfff},
+	{ 0x9010, 7, 0x1c, 0xfff},
+	{ 0x9030, 1, 0x1c, 0xfff},
+	{ 0x9068, 16, 0x1c, 0xfff},
+	{ 0x9230, 2, 0x1c, 0xfff},
+	{ 0x9244, 1, 0x1c, 0xfff},
+	{ 0x9298, 1, 0x1c, 0xfff},
+	{ 0x92a8, 1, 0x1c, 0x1fff},
+	{ 0xa38c, 1, 0x1f, 0x1fff},
+	{ 0xa3c4, 1, 0x1e, 0xfff},
+	{ 0xa404, 1, 0x1f, 0xfff},
+	{ 0xa408, 2, 0x1f, 0x1fff},
+	{ 0xa42c, 12, 0x1f, 0xfff},
+	{ 0xa580, 1, 0x1f, 0x1fff},
+	{ 0xa590, 1, 0x1f, 0x1fff},
+	{ 0xa600, 5, 0x1e, 0xfff},
+	{ 0xa618, 1, 0x1e, 0xfff},
+	{ 0xa714, 1, 0x1c, 0xfff},
+	{ 0xa720, 1, 0x1c, 0xfff},
+	{ 0xa750, 1, 0x1c, 0xfff},
+	{ 0xc09c, 1, 0x3, 0xfff},
+	{ 0x103b0, 1, 0x1f, 0xfff},
+	{ 0x103c0, 1, 0x1f, 0xfff},
+	{ 0x103d0, 1, 0x3, 0x1fff},
+	{ 0x10418, 1, 0x1f, 0xfff},
+	{ 0x10420, 1, 0x1f, 0xfff},
+	{ 0x10428, 1, 0x1f, 0xfff},
+	{ 0x10460, 1, 0x1f, 0xfff},
+	{ 0x10474, 1, 0x1f, 0xfff},
+	{ 0x104e0, 1, 0x1f, 0xfff},
+	{ 0x104ec, 1, 0x1f, 0xfff},
+	{ 0x104f8, 1, 0x1f, 0xfff},
+	{ 0x10508, 1, 0x1f, 0xfff},
+	{ 0x10530, 1, 0x1f, 0xfff},
+	{ 0x10538, 1, 0x1f, 0xfff},
+	{ 0x10548, 1, 0x1f, 0xfff},
+	{ 0x10558, 1, 0x1f, 0xfff},
+	{ 0x182a8, 1, 0x1c, 0xfff},
+	{ 0x182b8, 1, 0x1c, 0xfff},
+	{ 0x18308, 1, 0x1c, 0xfff},
+	{ 0x18318, 1, 0x1c, 0xfff},
+	{ 0x18338, 1, 0x1c, 0xfff},
+	{ 0x18348, 1, 0x1c, 0xfff},
+	{ 0x183bc, 1, 0x1c, 0x1fff},
+	{ 0x183cc, 1, 0x1c, 0x1fff},
+	{ 0x18570, 1, 0x18, 0xfff},
+	{ 0x18578, 1, 0x18, 0xfff},
+	{ 0x1858c, 1, 0x18, 0xfff},
+	{ 0x18594, 1, 0x18, 0xfff},
+	{ 0x1862c, 4, 0x10, 0xfff},
+	{ 0x2021c, 11, 0x1f, 0xfff},
+	{ 0x202a8, 1, 0x1f, 0xfff},
+	{ 0x202b8, 1, 0x1f, 0x1fff},
+	{ 0x20404, 1, 0x1f, 0xfff},
+	{ 0x2040c, 2, 0x1f, 0xfff},
+	{ 0x2041c, 2, 0x1f, 0xfff},
+	{ 0x40154, 14, 0x1f, 0xfff},
+	{ 0x40198, 1, 0x1f, 0x1fff},
+	{ 0x404ac, 1, 0x1f, 0xfff},
+	{ 0x404bc, 1, 0x1f, 0x1fff},
+	{ 0x42290, 1, 0x1f, 0xfff},
+	{ 0x422a0, 1, 0x1f, 0xfff},
+	{ 0x422b0, 1, 0x1f, 0x1fff},
+	{ 0x42548, 1, 0x1f, 0xfff},
+	{ 0x42550, 1, 0x1f, 0xfff},
+	{ 0x42558, 1, 0x1f, 0xfff},
+	{ 0x50160, 8, 0x1f, 0xfff},
+	{ 0x501d0, 1, 0x1f, 0xfff},
+	{ 0x501e0, 1, 0x1f, 0x1fff},
+	{ 0x50204, 1, 0x1f, 0xfff},
+	{ 0x5020c, 2, 0x1f, 0xfff},
+	{ 0x5021c, 1, 0x1f, 0xfff},
+	{ 0x60090, 1, 0x1f, 0xfff},
+	{ 0x6011c, 1, 0x1f, 0xfff},
+	{ 0x6012c, 1, 0x1f, 0x1fff},
+	{ 0xc101c, 1, 0x1f, 0xfff},
+	{ 0xc102c, 1, 0x1f, 0x1fff},
+	{ 0xc2290, 1, 0x1f, 0xfff},
+	{ 0xc22a0, 1, 0x1f, 0xfff},
+	{ 0xc22b0, 1, 0x1f, 0x1fff},
+	{ 0xc2548, 1, 0x1f, 0xfff},
+	{ 0xc2550, 1, 0x1f, 0xfff},
+	{ 0xc2558, 1, 0x1f, 0xfff},
+	{ 0xc4294, 1, 0x1f, 0xfff},
+	{ 0xc42a4, 1, 0x1f, 0xfff},
+	{ 0xc42b4, 1, 0x1f, 0x1fff},
+	{ 0xc4550, 1, 0x1f, 0xfff},
+	{ 0xc4558, 1, 0x1f, 0xfff},
+	{ 0xc4560, 1, 0x1f, 0xfff},
+	{ 0xd016c, 8, 0x1f, 0xfff},
+	{ 0xd01d8, 1, 0x1f, 0xfff},
+	{ 0xd01e8, 1, 0x1f, 0x1fff},
+	{ 0xd0204, 1, 0x1f, 0xfff},
+	{ 0xd020c, 3, 0x1f, 0xfff},
+	{ 0xe0154, 8, 0x1f, 0xfff},
+	{ 0xe01c8, 1, 0x1f, 0xfff},
+	{ 0xe01d8, 1, 0x1f, 0x1fff},
+	{ 0xe0204, 1, 0x1f, 0xfff},
+	{ 0xe020c, 2, 0x1f, 0xfff},
+	{ 0xe021c, 2, 0x1f, 0xfff},
+	{ 0x101014, 1, 0x1f, 0xfff},
+	{ 0x101030, 1, 0x1f, 0xfff},
+	{ 0x101040, 1, 0x1f, 0x1fff},
+	{ 0x102058, 1, 0x1f, 0x1fff},
+	{ 0x102080, 16, 0x1f, 0xfff},
+	{ 0x103004, 2, 0x1f, 0xfff},
+	{ 0x103068, 1, 0x1f, 0xfff},
+	{ 0x103078, 1, 0x1f, 0xfff},
+	{ 0x103088, 1, 0x1f, 0x1fff},
+	{ 0x10309c, 2, 0x1e, 0xfff},
+	{ 0x1030b8, 2, 0x1c, 0xfff},
+	{ 0x1030cc, 1, 0x1c, 0xfff},
+	{ 0x1030e0, 1, 0x1c, 0xfff},
+	{ 0x104004, 1, 0x1f, 0xfff},
+	{ 0x104018, 1, 0x1f, 0xfff},
+	{ 0x104020, 1, 0x1f, 0xfff},
+	{ 0x10403c, 1, 0x1f, 0xfff},
+	{ 0x1040fc, 1, 0x1f, 0xfff},
+	{ 0x10410c, 1, 0x1f, 0x1fff},
+	{ 0x104400, 1, 0x1f, 0x1fff},
+	{ 0x104404, 63, 0x1f, 0xfff},
+	{ 0x104800, 1, 0x1f, 0x1fff},
+	{ 0x104804, 63, 0x1f, 0xfff},
+	{ 0x105000, 4, 0x1f, 0x1fff},
+	{ 0x105010, 252, 0x1f, 0xfff},
+	{ 0x108094, 1, 0x3, 0xfff},
+	{ 0x1201b0, 2, 0x1f, 0xfff},
+	{ 0x12032c, 1, 0x1f, 0xfff},
+	{ 0x12036c, 3, 0x1f, 0xfff},
+	{ 0x120408, 2, 0x1f, 0xfff},
+	{ 0x120414, 15, 0x1f, 0xfff},
+	{ 0x120478, 2, 0x1f, 0xfff},
+	{ 0x12052c, 1, 0x1f, 0xfff},
+	{ 0x120564, 3, 0x1f, 0xfff},
+	{ 0x12057c, 1, 0x1f, 0x1fff},
+	{ 0x12058c, 1, 0x1f, 0x1fff},
+	{ 0x120608, 1, 0x1e, 0xfff},
+	{ 0x120748, 1, 0x1c, 0xfff},
+	{ 0x120778, 2, 0x1c, 0xfff},
+	{ 0x120808, 3, 0x1f, 0xfff},
+	{ 0x120818, 1, 0x1f, 0xfff},
+	{ 0x120820, 1, 0x1f, 0xfff},
+	{ 0x120828, 1, 0x1f, 0xfff},
+	{ 0x120830, 1, 0x1f, 0xfff},
+	{ 0x120838, 1, 0x1f, 0xfff},
+	{ 0x120840, 1, 0x1f, 0xfff},
+	{ 0x120848, 1, 0x1f, 0xfff},
+	{ 0x120850, 1, 0x1f, 0xfff},
+	{ 0x120858, 1, 0x1f, 0xfff},
+	{ 0x120860, 1, 0x1f, 0xfff},
+	{ 0x120868, 1, 0x1f, 0xfff},
+	{ 0x120870, 1, 0x1f, 0xfff},
+	{ 0x120878, 1, 0x1f, 0xfff},
+	{ 0x120880, 1, 0x1f, 0xfff},
+	{ 0x120888, 1, 0x1f, 0xfff},
+	{ 0x120890, 1, 0x1f, 0xfff},
+	{ 0x120898, 1, 0x1f, 0xfff},
+	{ 0x1208a0, 1, 0x1f, 0xfff},
+	{ 0x1208a8, 1, 0x1f, 0xfff},
+	{ 0x1208b0, 1, 0x1f, 0xfff},
+	{ 0x1208b8, 1, 0x1f, 0xfff},
+	{ 0x1208c0, 1, 0x1f, 0xfff},
+	{ 0x1208c8, 1, 0x1f, 0xfff},
+	{ 0x1208d0, 1, 0x1f, 0xfff},
+	{ 0x1208d8, 1, 0x1f, 0xfff},
+	{ 0x1208e0, 1, 0x1f, 0xfff},
+	{ 0x1208e8, 1, 0x1f, 0xfff},
+	{ 0x1208f0, 1, 0x1f, 0xfff},
+	{ 0x1208f8, 1, 0x1f, 0xfff},
+	{ 0x120900, 1, 0x1f, 0xfff},
+	{ 0x120908, 1, 0x1f, 0xfff},
+	{ 0x130030, 1, 0x1c, 0xfff},
+	{ 0x13004c, 3, 0x1c, 0xfff},
+	{ 0x130064, 2, 0x1c, 0xfff},
+	{ 0x13009c, 1, 0x1c, 0x1fff},
+	{ 0x130130, 1, 0x1c, 0xfff},
+	{ 0x13016c, 1, 0x1c, 0xfff},
+	{ 0x130300, 1, 0x1c, 0xfff},
+	{ 0x130480, 1, 0x1c, 0xfff},
+	{ 0x14005c, 2, 0xf, 0xfff},
+	{ 0x1400d0, 2, 0xf, 0xfff},
+	{ 0x1400e0, 1, 0xf, 0xfff},
+	{ 0x1401c8, 1, 0xf, 0xfff},
+	{ 0x140200, 6, 0xf, 0xfff},
+	{ 0x140338, 7, 0x10, 0xfff},
+	{ 0x140370, 7, 0x10, 0xfff},
+	{ 0x15c1bc, 6, 0x10, 0xfff},
+	{ 0x15c230, 7, 0x10, 0xfff},
+	{ 0x16101c, 1, 0x1f, 0xfff},
+	{ 0x16102c, 1, 0x1f, 0x1fff},
+	{ 0x164014, 2, 0x1f, 0xfff},
+	{ 0x1640f0, 1, 0x1f, 0xfff},
+	{ 0x166290, 1, 0x1f, 0xfff},
+	{ 0x1662a0, 1, 0x1f, 0xfff},
+	{ 0x1662b0, 1, 0x1f, 0x1fff},
+	{ 0x166548, 1, 0x1f, 0xfff},
+	{ 0x166550, 1, 0x1f, 0xfff},
+	{ 0x166558, 1, 0x1f, 0xfff},
+	{ 0x168000, 1, 0x1f, 0xfff},
+	{ 0x168008, 1, 0x1f, 0xfff},
+	{ 0x168010, 1, 0x1f, 0xfff},
+	{ 0x168018, 1, 0x1f, 0xfff},
+	{ 0x168028, 2, 0x1f, 0xfff},
+	{ 0x168058, 9, 0x1f, 0xfff},
+	{ 0x168238, 1, 0x1f, 0xfff},
+	{ 0x1682d0, 7, 0x1f, 0xfff},
+	{ 0x168300, 2, 0x3, 0xfff},
+	{ 0x168308, 65, 0x1f, 0xfff},
+	{ 0x168410, 2, 0x1f, 0xfff},
+	{ 0x168438, 1, 0x1f, 0xfff},
+	{ 0x168448, 1, 0x1f, 0x1fff},
+	{ 0x168a00, 128, 0x1f, 0xfff},
+	{ 0x16e200, 128, 0x2, 0xfff},
+	{ 0x16e404, 2, 0x2, 0xfff},
+	{ 0x16e584, 64, 0x2, 0xfff},
+	{ 0x16e684, 2, 0x1e, 0xfff},
+	{ 0x16e68c, 4, 0x2, 0xfff},
+	{ 0x16e6fc, 4, 0x1c, 0xfff},
+	{ 0x16e7ac, 12, 0x10, 0xfff},
+	{ 0x1700a4, 1, 0x1f, 0xfff},
+	{ 0x1700ac, 2, 0x1f, 0xfff},
+	{ 0x1700c0, 1, 0x1f, 0xfff},
+	{ 0x170174, 1, 0x1f, 0xfff},
+	{ 0x170184, 1, 0x1f, 0x1fff},
+	{ 0x1800f4, 1, 0x1f, 0xfff},
+	{ 0x180104, 1, 0x1f, 0xfff},
+	{ 0x180114, 1, 0x1f, 0x1fff},
+	{ 0x180124, 1, 0x1f, 0x1fff},
+	{ 0x18026c, 1, 0x1f, 0xfff},
+	{ 0x1802a0, 1, 0x1f, 0xfff},
+	{ 0x1b8000, 1, 0x1f, 0xfff},
+	{ 0x1b8040, 1, 0x1f, 0xfff},
+	{ 0x1b8080, 1, 0x1f, 0xfff},
+	{ 0x1b80c0, 1, 0x1f, 0xfff},
+	{ 0x200104, 1, 0x1f, 0xfff},
+	{ 0x200114, 1, 0x1f, 0xfff},
+	{ 0x200124, 1, 0x1f, 0x1fff},
+	{ 0x200134, 1, 0x1f, 0x1fff},
+	{ 0x20026c, 1, 0x1f, 0xfff},
+	{ 0x2002a0, 1, 0x1f, 0xfff},
+	{ 0x238000, 1, 0x1f, 0xfff},
+	{ 0x238040, 1, 0x1f, 0xfff},
+	{ 0x238080, 1, 0x1f, 0xfff},
+	{ 0x2380c0, 1, 0x1f, 0xfff},
+	{ 0x280104, 1, 0x1f, 0xfff},
+	{ 0x280114, 1, 0x1f, 0xfff},
+	{ 0x280124, 1, 0x1f, 0x1fff},
+	{ 0x280134, 1, 0x1f, 0x1fff},
+	{ 0x28026c, 1, 0x1f, 0xfff},
+	{ 0x2802a0, 1, 0x1f, 0xfff},
+	{ 0x2b8000, 1, 0x1f, 0xfff},
+	{ 0x2b8040, 1, 0x1f, 0xfff},
+	{ 0x2b8080, 1, 0x1f, 0xfff},
+	{ 0x300104, 1, 0x1f, 0xfff},
+	{ 0x300114, 1, 0x1f, 0xfff},
+	{ 0x300124, 1, 0x1f, 0x1fff},
+	{ 0x300134, 1, 0x1f, 0x1fff},
+	{ 0x30026c, 1, 0x1f, 0xfff},
+	{ 0x3002a0, 1, 0x1f, 0xfff},
+	{ 0x338000, 1, 0x1f, 0xfff},
+	{ 0x338040, 1, 0x1f, 0xfff},
+	{ 0x338080, 1, 0x1f, 0xfff},
+	{ 0x3380c0, 1, 0x1f, 0xfff}
+};
 
-static const u32 page_write_regs_e2[] = { 328476 };
-#define PAGE_WRITE_REGS_E2		ARRAY_SIZE(page_write_regs_e2)
+#define IDLE_REGS_COUNT ARRAY_SIZE(idle_reg_addrs)
 
-static const struct reg_addr page_read_regs_e2[] = {
-	{ 0x58000, 4608, RI_E2_ONLINE } };
-#define PAGE_READ_REGS_E2		ARRAY_SIZE(page_read_regs_e2)
+static const u32 read_reg_e1[] = {
+	0x1b1000};
 
-static const u32 page_vals_e3[] = { 0, 128 };
-#define PAGE_MODE_VALUES_E3		ARRAY_SIZE(page_vals_e3)
+static const struct wreg_addr wreg_addr_e1 = {
+	0x1b0c00, 192, 1, read_reg_e1, 0x1f, 0x1fff};
 
-static const u32 page_write_regs_e3[] = { 328476 };
-#define PAGE_WRITE_REGS_E3		ARRAY_SIZE(page_write_regs_e3)
+static const u32 read_reg_e1h[] = {
+	0x1b1040, 0x1b1000};
 
-static const struct reg_addr page_read_regs_e3[] = {
-	{ 0x58000, 4608, RI_E3E3B0_ONLINE } };
-#define PAGE_READ_REGS_E3		ARRAY_SIZE(page_read_regs_e3)
+static const struct wreg_addr wreg_addr_e1h = {
+	0x1b0c00, 256, 2, read_reg_e1h, 0x1f, 0x1fff};
 
-#endif /* BNX2X_DUMP_H */
+static const u32 read_reg_e2[] = {
+	0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e2 = {
+	0x1b0c00, 128, 2, read_reg_e2, 0x1f, 0x1fff};
+
+static const u32 read_reg_e3[] = {
+	0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e3 = {
+	0x1b0c00, 128, 2, read_reg_e3, 0x1f, 0x1fff};
+
+static const u32 read_reg_e3b0[] = {
+	0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e3b0 = {
+	0x1b0c00, 128, 2, read_reg_e3b0, 0x1f, 0x1fff};
+
+static const unsigned int dump_num_registers[NUM_CHIPS][NUM_PRESETS] = {
+	{20782, 18567, 27975, 19729, 18311, 27719, 20836, 32391, 41799, 20812,
+	 26247, 35655, 19074},
+	{32774, 19297, 33277, 31721, 19041, 33021, 32828, 33121, 47101, 32804,
+	 26977, 40957, 35895},
+	{36527, 17928, 33697, 35474, 18700, 34466, 36581, 31752, 47521, 36557,
+	 25608, 41377, 43903},
+	{45239, 17936, 34387, 44186, 18708, 35156, 45293, 31760, 48211, 45269,
+	 25616, 42067, 43903},
+	{45302, 17999, 34802, 44249, 18771, 35571, 45356, 31823, 48626, 45332,
+	 25679, 42482, 43903}
+};
+#endif
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index a427b49..9a674b1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -1,6 +1,6 @@
 /* bnx2x_ethtool.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -186,6 +186,7 @@
 };
 
 #define BNX2X_NUM_STATS		ARRAY_SIZE(bnx2x_stats_arr)
+
 static int bnx2x_get_port_type(struct bnx2x *bp)
 {
 	int port_type;
@@ -233,7 +234,7 @@
 
 	if ((bp->state == BNX2X_STATE_OPEN) && bp->link_vars.link_up &&
 	    !(bp->flags & MF_FUNC_DIS)) {
-			cmd->duplex = bp->link_vars.duplex;
+		cmd->duplex = bp->link_vars.duplex;
 
 		if (IS_MF(bp) && !BP_NOMCP(bp))
 			ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp));
@@ -399,7 +400,7 @@
 		DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n");
 		return -EINVAL;
 	}
-	/* Save new config in case command complete successully */
+	/* Save new config in case command complete successfully */
 	new_multi_phy_config = bp->link_params.multi_phy_config;
 	/* Get the new cfg_idx */
 	cfg_idx = bnx2x_get_link_cfg_idx(bp);
@@ -596,29 +597,58 @@
 	return 0;
 }
 
-#define IS_E1_ONLINE(info)	(((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
-#define IS_E1H_ONLINE(info)	(((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
-#define IS_E2_ONLINE(info)	(((info) & RI_E2_ONLINE) == RI_E2_ONLINE)
-#define IS_E3_ONLINE(info)	(((info) & RI_E3_ONLINE) == RI_E3_ONLINE)
-#define IS_E3B0_ONLINE(info)	(((info) & RI_E3B0_ONLINE) == RI_E3B0_ONLINE)
+#define DUMP_ALL_PRESETS		0x1FFF
+#define DUMP_MAX_PRESETS		13
 
-static bool bnx2x_is_reg_online(struct bnx2x *bp,
-				const struct reg_addr *reg_info)
+static int __bnx2x_get_preset_regs_len(struct bnx2x *bp, u32 preset)
 {
 	if (CHIP_IS_E1(bp))
-		return IS_E1_ONLINE(reg_info->info);
+		return dump_num_registers[0][preset-1];
 	else if (CHIP_IS_E1H(bp))
-		return IS_E1H_ONLINE(reg_info->info);
+		return dump_num_registers[1][preset-1];
 	else if (CHIP_IS_E2(bp))
-		return IS_E2_ONLINE(reg_info->info);
+		return dump_num_registers[2][preset-1];
 	else if (CHIP_IS_E3A0(bp))
-		return IS_E3_ONLINE(reg_info->info);
+		return dump_num_registers[3][preset-1];
 	else if (CHIP_IS_E3B0(bp))
-		return IS_E3B0_ONLINE(reg_info->info);
+		return dump_num_registers[4][preset-1];
 	else
-		return false;
+		return 0;
 }
 
+static int __bnx2x_get_regs_len(struct bnx2x *bp)
+{
+	u32 preset_idx;
+	int regdump_len = 0;
+
+	/* Calculate the total preset regs length */
+	for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++)
+		regdump_len += __bnx2x_get_preset_regs_len(bp, preset_idx);
+
+	return regdump_len;
+}
+
+static int bnx2x_get_regs_len(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int regdump_len = 0;
+
+	regdump_len = __bnx2x_get_regs_len(bp);
+	regdump_len *= 4;
+	regdump_len += sizeof(struct dump_header);
+
+	return regdump_len;
+}
+
+#define IS_E1_REG(chips)	((chips & DUMP_CHIP_E1) == DUMP_CHIP_E1)
+#define IS_E1H_REG(chips)	((chips & DUMP_CHIP_E1H) == DUMP_CHIP_E1H)
+#define IS_E2_REG(chips)	((chips & DUMP_CHIP_E2) == DUMP_CHIP_E2)
+#define IS_E3A0_REG(chips)	((chips & DUMP_CHIP_E3A0) == DUMP_CHIP_E3A0)
+#define IS_E3B0_REG(chips)	((chips & DUMP_CHIP_E3B0) == DUMP_CHIP_E3B0)
+
+#define IS_REG_IN_PRESET(presets, idx)  \
+		((presets & (1 << (idx-1))) == (1 << (idx-1)))
+
 /******* Paged registers info selectors ********/
 static const u32 *__bnx2x_get_page_addr_ar(struct bnx2x *bp)
 {
@@ -680,38 +710,39 @@
 		return 0;
 }
 
-static int __bnx2x_get_regs_len(struct bnx2x *bp)
+static bool bnx2x_is_reg_in_chip(struct bnx2x *bp,
+				       const struct reg_addr *reg_info)
 {
-	int num_pages = __bnx2x_get_page_reg_num(bp);
-	int page_write_num = __bnx2x_get_page_write_num(bp);
-	const struct reg_addr *page_read_addr = __bnx2x_get_page_read_ar(bp);
-	int page_read_num = __bnx2x_get_page_read_num(bp);
-	int regdump_len = 0;
-	int i, j, k;
-
-	for (i = 0; i < REGS_COUNT; i++)
-		if (bnx2x_is_reg_online(bp, &reg_addrs[i]))
-			regdump_len += reg_addrs[i].size;
-
-	for (i = 0; i < num_pages; i++)
-		for (j = 0; j < page_write_num; j++)
-			for (k = 0; k < page_read_num; k++)
-				if (bnx2x_is_reg_online(bp, &page_read_addr[k]))
-					regdump_len += page_read_addr[k].size;
-
-	return regdump_len;
+	if (CHIP_IS_E1(bp))
+		return IS_E1_REG(reg_info->chips);
+	else if (CHIP_IS_E1H(bp))
+		return IS_E1H_REG(reg_info->chips);
+	else if (CHIP_IS_E2(bp))
+		return IS_E2_REG(reg_info->chips);
+	else if (CHIP_IS_E3A0(bp))
+		return IS_E3A0_REG(reg_info->chips);
+	else if (CHIP_IS_E3B0(bp))
+		return IS_E3B0_REG(reg_info->chips);
+	else
+		return false;
 }
 
-static int bnx2x_get_regs_len(struct net_device *dev)
+
+static bool bnx2x_is_wreg_in_chip(struct bnx2x *bp,
+	const struct wreg_addr *wreg_info)
 {
-	struct bnx2x *bp = netdev_priv(dev);
-	int regdump_len = 0;
-
-	regdump_len = __bnx2x_get_regs_len(bp);
-	regdump_len *= 4;
-	regdump_len += sizeof(struct dump_hdr);
-
-	return regdump_len;
+	if (CHIP_IS_E1(bp))
+		return IS_E1_REG(wreg_info->chips);
+	else if (CHIP_IS_E1H(bp))
+		return IS_E1H_REG(wreg_info->chips);
+	else if (CHIP_IS_E2(bp))
+		return IS_E2_REG(wreg_info->chips);
+	else if (CHIP_IS_E3A0(bp))
+		return IS_E3A0_REG(wreg_info->chips);
+	else if (CHIP_IS_E3B0(bp))
+		return IS_E3B0_REG(wreg_info->chips);
+	else
+		return false;
 }
 
 /**
@@ -725,9 +756,10 @@
  * ("read address"). There may be more than one write address per "page" and
  * more than one read address per write address.
  */
-static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p)
+static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p, u32 preset)
 {
 	u32 i, j, k, n;
+
 	/* addresses of the paged registers */
 	const u32 *page_addr = __bnx2x_get_page_addr_ar(bp);
 	/* number of paged registers */
@@ -740,32 +772,100 @@
 	const struct reg_addr *read_addr = __bnx2x_get_page_read_ar(bp);
 	/* number of read addresses */
 	int read_num = __bnx2x_get_page_read_num(bp);
+	u32 addr, size;
 
 	for (i = 0; i < num_pages; i++) {
 		for (j = 0; j < write_num; j++) {
 			REG_WR(bp, write_addr[j], page_addr[i]);
-			for (k = 0; k < read_num; k++)
-				if (bnx2x_is_reg_online(bp, &read_addr[k]))
-					for (n = 0; n <
-					      read_addr[k].size; n++)
-						*p++ = REG_RD(bp,
-						       read_addr[k].addr + n*4);
+
+			for (k = 0; k < read_num; k++) {
+				if (IS_REG_IN_PRESET(read_addr[k].presets,
+						     preset)) {
+					size = read_addr[k].size;
+					for (n = 0; n < size; n++) {
+						addr = read_addr[k].addr + n*4;
+						*p++ = REG_RD(bp, addr);
+					}
+				}
+			}
 		}
 	}
 }
 
-static void __bnx2x_get_regs(struct bnx2x *bp, u32 *p)
+static int __bnx2x_get_preset_regs(struct bnx2x *bp, u32 *p, u32 preset)
 {
-	u32 i, j;
+	u32 i, j, addr;
+	const struct wreg_addr *wreg_addr_p = NULL;
+
+	if (CHIP_IS_E1(bp))
+		wreg_addr_p = &wreg_addr_e1;
+	else if (CHIP_IS_E1H(bp))
+		wreg_addr_p = &wreg_addr_e1h;
+	else if (CHIP_IS_E2(bp))
+		wreg_addr_p = &wreg_addr_e2;
+	else if (CHIP_IS_E3A0(bp))
+		wreg_addr_p = &wreg_addr_e3;
+	else if (CHIP_IS_E3B0(bp))
+		wreg_addr_p = &wreg_addr_e3b0;
+
+	/* Read the idle_chk registers */
+	for (i = 0; i < IDLE_REGS_COUNT; i++) {
+		if (bnx2x_is_reg_in_chip(bp, &idle_reg_addrs[i]) &&
+		    IS_REG_IN_PRESET(idle_reg_addrs[i].presets, preset)) {
+			for (j = 0; j < idle_reg_addrs[i].size; j++)
+				*p++ = REG_RD(bp, idle_reg_addrs[i].addr + j*4);
+		}
+	}
 
 	/* Read the regular registers */
-	for (i = 0; i < REGS_COUNT; i++)
-		if (bnx2x_is_reg_online(bp, &reg_addrs[i]))
+	for (i = 0; i < REGS_COUNT; i++) {
+		if (bnx2x_is_reg_in_chip(bp, &reg_addrs[i]) &&
+		    IS_REG_IN_PRESET(reg_addrs[i].presets, preset)) {
 			for (j = 0; j < reg_addrs[i].size; j++)
 				*p++ = REG_RD(bp, reg_addrs[i].addr + j*4);
+		}
+	}
 
-	/* Read "paged" registes */
-	bnx2x_read_pages_regs(bp, p);
+	/* Read the CAM registers */
+	if (bnx2x_is_wreg_in_chip(bp, wreg_addr_p) &&
+	    IS_REG_IN_PRESET(wreg_addr_p->presets, preset)) {
+		for (i = 0; i < wreg_addr_p->size; i++) {
+			*p++ = REG_RD(bp, wreg_addr_p->addr + i*4);
+
+			/* In case of wreg_addr register, read additional
+			   registers from read_regs array
+			*/
+			for (j = 0; j < wreg_addr_p->read_regs_count; j++) {
+				addr = *(wreg_addr_p->read_regs);
+				*p++ = REG_RD(bp, addr + j*4);
+			}
+		}
+	}
+
+	/* Paged registers are supported in E2 & E3 only */
+	if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) {
+		/* Read "paged" registes */
+		bnx2x_read_pages_regs(bp, p, preset);
+	}
+
+	return 0;
+}
+
+static void __bnx2x_get_regs(struct bnx2x *bp, u32 *p)
+{
+	u32 preset_idx;
+
+	/* Read all registers, by reading all preset registers */
+	for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++) {
+		/* Skip presets with IOR */
+		if ((preset_idx == 2) ||
+		    (preset_idx == 5) ||
+		    (preset_idx == 8) ||
+		    (preset_idx == 11))
+			continue;
+		__bnx2x_get_preset_regs(bp, p, preset_idx);
+		p += __bnx2x_get_preset_regs_len(bp, preset_idx);
+	}
 }
 
 static void bnx2x_get_regs(struct net_device *dev,
@@ -773,9 +873,9 @@
 {
 	u32 *p = _p;
 	struct bnx2x *bp = netdev_priv(dev);
-	struct dump_hdr dump_hdr = {0};
+	struct dump_header dump_hdr = {0};
 
-	regs->version = 1;
+	regs->version = 2;
 	memset(p, 0, regs->len);
 
 	if (!netif_running(bp->dev))
@@ -785,53 +885,173 @@
 	 * cause false alarms by reading never written registers. We
 	 * will re-enable parity attentions right after the dump.
 	 */
+
+	/* Disable parity on path 0 */
+	bnx2x_pretend_func(bp, 0);
 	bnx2x_disable_blocks_parity(bp);
 
-	dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
-	dump_hdr.dump_sign = dump_sign_all;
-	dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
-	dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
-	dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
-	dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
+	/* Disable parity on path 1 */
+	bnx2x_pretend_func(bp, 1);
+	bnx2x_disable_blocks_parity(bp);
 
-	if (CHIP_IS_E1(bp))
-		dump_hdr.info = RI_E1_ONLINE;
-	else if (CHIP_IS_E1H(bp))
-		dump_hdr.info = RI_E1H_ONLINE;
-	else if (!CHIP_IS_E1x(bp))
-		dump_hdr.info = RI_E2_ONLINE |
-		(BP_PATH(bp) ? RI_PATH1_DUMP : RI_PATH0_DUMP);
+	/* Return to current function */
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
 
-	memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
-	p += dump_hdr.hdr_size + 1;
+	dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
+	dump_hdr.preset = DUMP_ALL_PRESETS;
+	dump_hdr.version = BNX2X_DUMP_VERSION;
+
+	/* dump_meta_data presents OR of CHIP and PATH. */
+	if (CHIP_IS_E1(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E1;
+	} else if (CHIP_IS_E1H(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E1H;
+	} else if (CHIP_IS_E2(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E2 |
+		(BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+	} else if (CHIP_IS_E3A0(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 |
+		(BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+	} else if (CHIP_IS_E3B0(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 |
+		(BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+	}
+
+	memcpy(p, &dump_hdr, sizeof(struct dump_header));
+	p += dump_hdr.header_size + 1;
 
 	/* Actually read the registers */
 	__bnx2x_get_regs(bp, p);
 
-	/* Re-enable parity attentions */
+	/* Re-enable parity attentions on path 0 */
+	bnx2x_pretend_func(bp, 0);
 	bnx2x_clear_blocks_parity(bp);
 	bnx2x_enable_blocks_parity(bp);
+
+	/* Re-enable parity attentions on path 1 */
+	bnx2x_pretend_func(bp, 1);
+	bnx2x_clear_blocks_parity(bp);
+	bnx2x_enable_blocks_parity(bp);
+
+	/* Return to current function */
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static int bnx2x_get_preset_regs_len(struct net_device *dev, u32 preset)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int regdump_len = 0;
+
+	regdump_len = __bnx2x_get_preset_regs_len(bp, preset);
+	regdump_len *= 4;
+	regdump_len += sizeof(struct dump_header);
+
+	return regdump_len;
+}
+
+static int bnx2x_set_dump(struct net_device *dev, struct ethtool_dump *val)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	/* Use the ethtool_dump "flag" field as the dump preset index */
+	bp->dump_preset_idx = val->flag;
+	return 0;
+}
+
+static int bnx2x_get_dump_flag(struct net_device *dev,
+			       struct ethtool_dump *dump)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	/* Calculate the requested preset idx length */
+	dump->len = bnx2x_get_preset_regs_len(dev, bp->dump_preset_idx);
+	DP(BNX2X_MSG_ETHTOOL, "Get dump preset %d length=%d\n",
+	   bp->dump_preset_idx, dump->len);
+
+	dump->flag = ETHTOOL_GET_DUMP_DATA;
+	return 0;
+}
+
+static int bnx2x_get_dump_data(struct net_device *dev,
+			       struct ethtool_dump *dump,
+			       void *buffer)
+{
+	u32 *p = buffer;
+	struct bnx2x *bp = netdev_priv(dev);
+	struct dump_header dump_hdr = {0};
+
+	memset(p, 0, dump->len);
+
+	/* Disable parity attentions as long as following dump may
+	 * cause false alarms by reading never written registers. We
+	 * will re-enable parity attentions right after the dump.
+	 */
+
+	/* Disable parity on path 0 */
+	bnx2x_pretend_func(bp, 0);
+	bnx2x_disable_blocks_parity(bp);
+
+	/* Disable parity on path 1 */
+	bnx2x_pretend_func(bp, 1);
+	bnx2x_disable_blocks_parity(bp);
+
+	/* Return to current function */
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+	dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
+	dump_hdr.preset = bp->dump_preset_idx;
+	dump_hdr.version = BNX2X_DUMP_VERSION;
+
+	DP(BNX2X_MSG_ETHTOOL, "Get dump data of preset %d\n", dump_hdr.preset);
+
+	/* dump_meta_data presents OR of CHIP and PATH. */
+	if (CHIP_IS_E1(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E1;
+	} else if (CHIP_IS_E1H(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E1H;
+	} else if (CHIP_IS_E2(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E2 |
+		(BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+	} else if (CHIP_IS_E3A0(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 |
+		(BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+	} else if (CHIP_IS_E3B0(bp)) {
+		dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 |
+		(BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+	}
+
+	memcpy(p, &dump_hdr, sizeof(struct dump_header));
+	p += dump_hdr.header_size + 1;
+
+	/* Actually read the registers */
+	__bnx2x_get_preset_regs(bp, p, dump_hdr.preset);
+
+	/* Re-enable parity attentions on path 0 */
+	bnx2x_pretend_func(bp, 0);
+	bnx2x_clear_blocks_parity(bp);
+	bnx2x_enable_blocks_parity(bp);
+
+	/* Re-enable parity attentions on path 1 */
+	bnx2x_pretend_func(bp, 1);
+	bnx2x_clear_blocks_parity(bp);
+	bnx2x_enable_blocks_parity(bp);
+
+	/* Return to current function */
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+	return 0;
 }
 
 static void bnx2x_get_drvinfo(struct net_device *dev,
 			      struct ethtool_drvinfo *info)
 {
 	struct bnx2x *bp = netdev_priv(dev);
-	u8 phy_fw_ver[PHY_FW_VER_LEN];
 
 	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 
-	phy_fw_ver[0] = '\0';
-	bnx2x_get_ext_phy_fw_version(&bp->link_params,
-				     phy_fw_ver, PHY_FW_VER_LEN);
-	strlcpy(info->fw_version, bp->fw_ver, sizeof(info->fw_version));
-	snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
-		 "bc %d.%d.%d%s%s",
-		 (bp->common.bc_ver & 0xff0000) >> 16,
-		 (bp->common.bc_ver & 0xff00) >> 8,
-		 (bp->common.bc_ver & 0xff),
-		 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+	bnx2x_fill_fw_str(bp, info->fw_version, sizeof(info->fw_version));
+
 	strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
 	info->n_stats = BNX2X_NUM_STATS;
 	info->testinfo_len = BNX2X_NUM_TESTS(bp);
@@ -861,13 +1081,13 @@
 	struct bnx2x *bp = netdev_priv(dev);
 
 	if (wol->wolopts & ~WAKE_MAGIC) {
-		DP(BNX2X_MSG_ETHTOOL, "WOL not supproted\n");
+		DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n");
 		return -EINVAL;
 	}
 
 	if (wol->wolopts & WAKE_MAGIC) {
 		if (bp->flags & NO_WOL_FLAG) {
-			DP(BNX2X_MSG_ETHTOOL, "WOL not supproted\n");
+			DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n");
 			return -EINVAL;
 		}
 		bp->wol = 1;
@@ -890,7 +1110,7 @@
 
 	if (capable(CAP_NET_ADMIN)) {
 		/* dump MCP trace */
-		if (level & BNX2X_MSG_MCP)
+		if (IS_PF(bp) && (level & BNX2X_MSG_MCP))
 			bnx2x_fw_dump_lvl(bp, KERN_INFO);
 		bp->msg_enable = level;
 	}
@@ -940,7 +1160,7 @@
  * Pf B takes the lock and proceeds to perform it's own access.
  * pf A unlocks the per port lock, while pf B is still working (!).
  * mcp takes the per port lock and corrupts pf B's access (and/or has it's own
- * acess corrupted by pf B).*
+ * access corrupted by pf B)
  */
 static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
 {
@@ -1070,7 +1290,8 @@
 			val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
 			/* we read nvram data in cpu order
 			 * but ethtool sees it as an array of bytes
-			 * converting to big-endian will do the work */
+			 * converting to big-endian will do the work
+			 */
 			*ret_val = cpu_to_be32(val);
 			rc = 0;
 			break;
@@ -1297,7 +1518,8 @@
 		val |= (*data_buf << BYTE_OFFSET(offset));
 
 		/* nvram data is returned as an array of bytes
-		 * convert it back to cpu order */
+		 * convert it back to cpu order
+		 */
 		val = be32_to_cpu(val);
 
 		rc = bnx2x_nvram_write_dword(bp, align_offset, val,
@@ -1509,6 +1731,10 @@
 {
 	struct bnx2x *bp = netdev_priv(dev);
 
+	DP(BNX2X_MSG_ETHTOOL,
+	   "set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
+	   ering->rx_pending, ering->tx_pending);
+
 	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
 		DP(BNX2X_MSG_ETHTOOL,
 		   "Handling parity error recovery. Try again later\n");
@@ -1747,7 +1973,6 @@
 	return 0;
 }
 
-
 enum {
 	BNX2X_CHIP_E1_OFST = 0,
 	BNX2X_CHIP_E1H_OFST,
@@ -1875,7 +2100,8 @@
 		hw = BNX2X_CHIP_MASK_E3;
 
 	/* Repeat the test twice:
-	   First by writing 0x00000000, second by writing 0xffffffff */
+	 * First by writing 0x00000000, second by writing 0xffffffff
+	 */
 	for (idx = 0; idx < 2; idx++) {
 
 		switch (idx) {
@@ -2388,8 +2614,8 @@
 			    struct ethtool_test *etest, u64 *buf)
 {
 	struct bnx2x *bp = netdev_priv(dev);
-	u8 is_serdes;
-	int rc;
+	u8 is_serdes, link_up;
+	int rc, cnt = 0;
 
 	if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
 		netdev_err(bp->dev,
@@ -2397,6 +2623,7 @@
 		etest->flags |= ETH_TEST_FL_FAILED;
 		return;
 	}
+
 	DP(BNX2X_MSG_ETHTOOL,
 	   "Self-test command parameters: offline = %d, external_lb = %d\n",
 	   (etest->flags & ETH_TEST_FL_OFFLINE),
@@ -2411,20 +2638,17 @@
 	}
 
 	is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
-
+	link_up = bp->link_vars.link_up;
 	/* offline tests are not supported in MF mode */
 	if ((etest->flags & ETH_TEST_FL_OFFLINE) && !IS_MF(bp)) {
 		int port = BP_PORT(bp);
 		u32 val;
-		u8 link_up;
 
 		/* save current value of input enable for TX port IF */
 		val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
 		/* disable input for TX port IF */
 		REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
 
-		link_up = bp->link_vars.link_up;
-
 		bnx2x_nic_unload(bp, UNLOAD_NORMAL, false);
 		rc = bnx2x_nic_load(bp, LOAD_DIAG);
 		if (rc) {
@@ -2486,17 +2710,19 @@
 		etest->flags |= ETH_TEST_FL_FAILED;
 	}
 
-	if (bnx2x_link_test(bp, is_serdes) != 0) {
+	if (link_up) {
+		cnt = 100;
+		while (bnx2x_link_test(bp, is_serdes) && --cnt)
+			msleep(20);
+	}
+
+	if (!cnt) {
 		if (!IS_MF(bp))
 			buf[6] = 1;
 		else
 			buf[2] = 1;
 		etest->flags |= ETH_TEST_FL_FAILED;
 	}
-
-#ifdef BNX2X_EXTRA_DEBUG
-	bnx2x_panic_dump(bp);
-#endif
 }
 
 #define IS_PORT_STAT(i) \
@@ -2753,15 +2979,14 @@
 			DP(BNX2X_MSG_ETHTOOL,
 			   "Command parameters not supported\n");
 			return -EINVAL;
-		} else {
-			return 0;
 		}
+		return 0;
 
 	case UDP_V4_FLOW:
 	case UDP_V6_FLOW:
 		/* For UDP either 2-tupple hash or 4-tupple hash is supported */
 		if (info->data == (RXH_IP_SRC | RXH_IP_DST |
-				 RXH_L4_B_0_1 | RXH_L4_B_2_3))
+				   RXH_L4_B_0_1 | RXH_L4_B_2_3))
 			udp_rss_requested = 1;
 		else if (info->data == (RXH_IP_SRC | RXH_IP_DST))
 			udp_rss_requested = 0;
@@ -2781,9 +3006,9 @@
 			   "rss re-configured, UDP 4-tupple %s\n",
 			   udp_rss_requested ? "enabled" : "disabled");
 			return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
-		} else {
-			return 0;
 		}
+		return 0;
+
 	case IPV4_FLOW:
 	case IPV6_FLOW:
 		/* For IP only 2-tupple hash is supported */
@@ -2791,9 +3016,9 @@
 			DP(BNX2X_MSG_ETHTOOL,
 			   "Command parameters not supported\n");
 			return -EINVAL;
-		} else {
-			return 0;
 		}
+		return 0;
+
 	case SCTP_V4_FLOW:
 	case AH_ESP_V4_FLOW:
 	case AH_V4_FLOW:
@@ -2809,9 +3034,9 @@
 			DP(BNX2X_MSG_ETHTOOL,
 			   "Command parameters not supported\n");
 			return -EINVAL;
-		} else {
-			return 0;
 		}
+		return 0;
+
 	default:
 		return -EINVAL;
 	}
@@ -2964,6 +3189,9 @@
 	.get_drvinfo		= bnx2x_get_drvinfo,
 	.get_regs_len		= bnx2x_get_regs_len,
 	.get_regs		= bnx2x_get_regs,
+	.get_dump_flag		= bnx2x_get_dump_flag,
+	.get_dump_data		= bnx2x_get_dump_data,
+	.set_dump		= bnx2x_set_dump,
 	.get_wol		= bnx2x_get_wol,
 	.set_wol		= bnx2x_set_wol,
 	.get_msglevel		= bnx2x_get_msglevel,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index 60a83ad..e5f8083 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -1,6 +1,6 @@
 /* bnx2x_fw_defs.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -305,12 +305,10 @@
 #define MAX_VLAN_CREDIT_E1H 0 /* Per Chip */
 #define MAX_VLAN_CREDIT_E2 272 /* Per Path */
 
-
 /* Maximal aggregation queues supported */
 #define ETH_MAX_AGGREGATION_QUEUES_E1 32
 #define ETH_MAX_AGGREGATION_QUEUES_E1H_E2 64
 
-
 #define ETH_NUM_OF_MCAST_BINS 256
 #define ETH_NUM_OF_MCAST_ENGINES_E2 72
 
@@ -353,7 +351,6 @@
 /* max number of slow path commands per port */
 #define MAX_RAMRODS_PER_PORT 8
 
-
 /**** DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
 
 #define TIMERS_TICK_SIZE_CHIP (1e-3)
@@ -380,7 +377,6 @@
 	that is not mapped to priority*/
 #define LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED 0xFF
 
-
 #define C_ERES_PER_PAGE \
 	(PAGE_SIZE / BITS_TO_BYTES(STRUCT_SIZE(event_ring_elem)))
 #define C_ERE_PER_PAGE_MASK (C_ERES_PER_PAGE - 1)
@@ -391,8 +387,6 @@
 
 #define INVALID_VNIC_ID	0xFF
 
-
 #define UNDEF_IRO 0x80000000
 
-
 #endif /* BNX2X_FW_DEFS_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
index 4bed52b..f572ae1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
@@ -1,6 +1,6 @@
 /* bnx2x_fw_file_hdr.h: FW binary file header structure.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 3369a50..037860e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -1,6 +1,6 @@
 /* bnx2x_hsi.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -899,6 +899,10 @@
 		#define PORT_FEAT_CFG_DCBX_DISABLED                  0x00000000
 		#define PORT_FEAT_CFG_DCBX_ENABLED                   0x00000100
 
+		#define PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK        0x00000C00
+		#define PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE        0x00000400
+		#define PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI       0x00000800
+
 	#define PORT_FEATURE_EN_SIZE_MASK                   0x0f000000
 	#define PORT_FEATURE_EN_SIZE_SHIFT                           24
 	#define PORT_FEATURE_WOL_ENABLED                             0x01000000
@@ -3374,6 +3378,10 @@
 	__le32 hi;
 };
 
+struct regpair_native {
+	u32 lo;
+	u32 hi;
+};
 
 /*
  * Classify rule opcodes in E2/E3
@@ -4400,13 +4408,13 @@
  * MAC filtering configuration parameters per port in Tstorm
  */
 struct tstorm_eth_mac_filter_config {
-	__le32 ucast_drop_all;
-	__le32 ucast_accept_all;
-	__le32 mcast_drop_all;
-	__le32 mcast_accept_all;
-	__le32 bcast_accept_all;
-	__le32 vlan_filter[2];
-	__le32 unmatched_unicast;
+	u32 ucast_drop_all;
+	u32 ucast_accept_all;
+	u32 mcast_drop_all;
+	u32 mcast_accept_all;
+	u32 bcast_accept_all;
+	u32 vlan_filter[2];
+	u32 unmatched_unicast;
 };
 
 
@@ -4898,7 +4906,7 @@
  * per PF event ring data
  */
 struct event_ring_data {
-	struct regpair base_addr;
+	struct regpair_native base_addr;
 #if defined(__BIG_ENDIAN)
 	u8 index_id;
 	u8 sb_id;
@@ -5131,7 +5139,7 @@
  * The fast-path status block meta-data, common to all chips
  */
 struct hc_sb_data {
-	struct regpair host_sb_addr;
+	struct regpair_native host_sb_addr;
 	struct hc_status_block_sm state_machine[HC_SB_MAX_SM];
 	struct pci_entity p_func;
 #if defined(__BIG_ENDIAN)
@@ -5145,7 +5153,7 @@
 	u8 state;
 	u8 rsrv0;
 #endif
-	struct regpair rsrv1[2];
+	struct regpair_native rsrv1[2];
 };
 
 
@@ -5163,7 +5171,7 @@
  * The fast-path status block meta-data
  */
 struct hc_sp_status_block_data {
-	struct regpair host_sb_addr;
+	struct regpair_native host_sb_addr;
 #if defined(__BIG_ENDIAN)
 	u8 rsrv1;
 	u8 state;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
index c8f10f0..76df015 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
@@ -1,7 +1,7 @@
 /* bnx2x_init.h: Broadcom Everest network driver.
  *               Structures and macroes needed during the initialization.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
index d755acf..8ab0dd9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
@@ -2,7 +2,7 @@
  *               Static functions needed during the initialization.
  *               This file is "included" in bnx2x_main.c.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -218,7 +218,7 @@
 	/* gunzip_outlen is in dwords */
 	len = GUNZIP_OUTLEN(bp);
 	for (i = 0; i < len; i++)
-		((u32 *)GUNZIP_BUF(bp))[i] =
+		((u32 *)GUNZIP_BUF(bp))[i] = (__force u32)
 				cpu_to_le32(((u32 *)GUNZIP_BUF(bp))[i]);
 
 	bnx2x_write_big_buf_wb(bp, addr, len);
@@ -232,7 +232,7 @@
 	u16 op_end =
 		INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage,
 						     STAGE_END)];
-	union init_op *op;
+	const union init_op *op;
 	u32 op_idx, op_type, addr, len;
 	const u32 *data, *data_base;
 
@@ -244,7 +244,7 @@
 
 	for (op_idx = op_start; op_idx < op_end; op_idx++) {
 
-		op = (union init_op *)&(INIT_OPS(bp)[op_idx]);
+		op = (const union init_op *)&(INIT_OPS(bp)[op_idx]);
 		/* Get generic data */
 		op_type = op->raw.op;
 		addr = op->raw.offset;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 09096b4..c6da77f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -1,4 +1,4 @@
-/* Copyright 2008-2012 Broadcom Corporation
+/* Copyright 2008-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -3659,7 +3659,7 @@
 	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
 				 MDIO_WC_REG_CL49_USERB0_CTRL, (3<<6));
 
-	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
 		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
 				 reg_set[i].val);
 
@@ -3713,7 +3713,7 @@
 	};
 	DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
 	/* Set to default registers that may be overriden by 10G force */
-	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
 		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
 				 reg_set[i].val);
 
@@ -3854,7 +3854,7 @@
 		{MDIO_PMA_DEVAD, MDIO_WC_REG_PMD_KR_CONTROL, 0x2}
 	};
 
-	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
 		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
 				 reg_set[i].val);
 
@@ -4242,7 +4242,7 @@
 	bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
 				 MDIO_WC_REG_RX66_CONTROL, (3<<13));
 
-	for (i = 0; i < sizeof(wc_regs)/sizeof(struct bnx2x_reg_set); i++)
+	for (i = 0; i < ARRAY_SIZE(wc_regs); i++)
 		bnx2x_cl45_write(bp, phy, wc_regs[i].devad, wc_regs[i].reg,
 				 wc_regs[i].val);
 
@@ -4748,6 +4748,12 @@
 	vars->link_status = REG_RD(bp, params->shmem_base +
 				   offsetof(struct shmem_region,
 					    port_mb[port].link_status));
+
+	/* Force link UP in non LOOPBACK_EXT loopback mode(s) */
+	if (bp->link_params.loopback_mode != LOOPBACK_NONE &&
+	    bp->link_params.loopback_mode != LOOPBACK_EXT)
+		vars->link_status |= LINK_STATUS_LINK_UP;
+
 	if (bnx2x_eee_has_cap(params))
 		vars->eee_status = REG_RD(bp, params->shmem2_base +
 					  offsetof(struct shmem2_region,
@@ -9520,7 +9526,7 @@
 	} else {
 		/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
 		/* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
-		for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set);
+		for (i = 0; i < ARRAY_SIZE(reg_set);
 		      i++)
 			bnx2x_cl45_write(bp, phy, reg_set[i].devad,
 					 reg_set[i].reg, reg_set[i].val);
@@ -9592,7 +9598,7 @@
 			 MDIO_PMA_DEVAD,
 			 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
 
-	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
 		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
 				 reg_set[i].val);
 
@@ -13395,7 +13401,7 @@
 	};
 	DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
 
-	for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
 		bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
 				 reg_set[i].val);
 	vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index ee6e7ec..d25c7d7 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -1,4 +1,4 @@
-/* Copyright 2008-2012 Broadcom Corporation
+/* Copyright 2008-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 5523da3..c4daee1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -1,6 +1,6 @@
 /* bnx2x_main.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -59,6 +59,7 @@
 #include "bnx2x_init.h"
 #include "bnx2x_init_ops.h"
 #include "bnx2x_cmn.h"
+#include "bnx2x_vfpf.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_sp.h"
 
@@ -144,39 +145,49 @@
 	BCM57711E,
 	BCM57712,
 	BCM57712_MF,
+	BCM57712_VF,
 	BCM57800,
 	BCM57800_MF,
+	BCM57800_VF,
 	BCM57810,
 	BCM57810_MF,
-	BCM57840_O,
+	BCM57810_VF,
 	BCM57840_4_10,
 	BCM57840_2_20,
-	BCM57840_MFO,
 	BCM57840_MF,
+	BCM57840_VF,
 	BCM57811,
-	BCM57811_MF
+	BCM57811_MF,
+	BCM57840_O,
+	BCM57840_MFO,
+	BCM57811_VF
 };
 
 /* indexed by board_type, above */
 static struct {
 	char *name;
 } board_info[] = {
-	{ "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
-	{ "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
-	{ "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
-	{ "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
-	{ "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
-	{ "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
-	{ "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
-	{ "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
-	{ "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
-	{ "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
-	{ "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
-	{ "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
-	{ "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
-	{ "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
-	{ "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet"},
-	{ "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function"},
+	[BCM57710]	= { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
+	[BCM57711]	= { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
+	[BCM57711E]	= { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
+	[BCM57712]	= { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
+	[BCM57712_MF]	= { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
+	[BCM57712_VF]	= { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" },
+	[BCM57800]	= { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
+	[BCM57800_MF]	= { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
+	[BCM57800_VF]	= { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" },
+	[BCM57810]	= { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
+	[BCM57810_MF]	= { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
+	[BCM57810_VF]	= { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" },
+	[BCM57840_4_10]	= { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
+	[BCM57840_2_20]	= { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
+	[BCM57840_MF]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+	[BCM57840_VF]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" },
+	[BCM57811]	= { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" },
+	[BCM57811_MF]	= { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" },
+	[BCM57840_O]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
+	[BCM57840_MFO]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+	[BCM57811_VF]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }
 };
 
 #ifndef PCI_DEVICE_ID_NX2_57710
@@ -194,12 +205,18 @@
 #ifndef PCI_DEVICE_ID_NX2_57712_MF
 #define PCI_DEVICE_ID_NX2_57712_MF	CHIP_NUM_57712_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57712_VF
+#define PCI_DEVICE_ID_NX2_57712_VF	CHIP_NUM_57712_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57800
 #define PCI_DEVICE_ID_NX2_57800		CHIP_NUM_57800
 #endif
 #ifndef PCI_DEVICE_ID_NX2_57800_MF
 #define PCI_DEVICE_ID_NX2_57800_MF	CHIP_NUM_57800_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57800_VF
+#define PCI_DEVICE_ID_NX2_57800_VF	CHIP_NUM_57800_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57810
 #define PCI_DEVICE_ID_NX2_57810		CHIP_NUM_57810
 #endif
@@ -209,6 +226,9 @@
 #ifndef PCI_DEVICE_ID_NX2_57840_O
 #define PCI_DEVICE_ID_NX2_57840_O	CHIP_NUM_57840_OBSOLETE
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57810_VF
+#define PCI_DEVICE_ID_NX2_57810_VF	CHIP_NUM_57810_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57840_4_10
 #define PCI_DEVICE_ID_NX2_57840_4_10	CHIP_NUM_57840_4_10
 #endif
@@ -221,29 +241,41 @@
 #ifndef PCI_DEVICE_ID_NX2_57840_MF
 #define PCI_DEVICE_ID_NX2_57840_MF	CHIP_NUM_57840_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57840_VF
+#define PCI_DEVICE_ID_NX2_57840_VF	CHIP_NUM_57840_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57811
 #define PCI_DEVICE_ID_NX2_57811		CHIP_NUM_57811
 #endif
 #ifndef PCI_DEVICE_ID_NX2_57811_MF
 #define PCI_DEVICE_ID_NX2_57811_MF	CHIP_NUM_57811_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57811_VF
+#define PCI_DEVICE_ID_NX2_57811_VF	CHIP_NUM_57811_VF
+#endif
+
 static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_MF), BCM57712_MF },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_VF), BCM57712_VF },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800), BCM57800 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_VF), BCM57800_VF },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810), BCM57810 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 },
 	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF },
+	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF },
 	{ 0 }
 };
 
@@ -346,6 +378,65 @@
 #define DMAE_DP_DST_PCI		"pci dst_addr [%x:%08x]"
 #define DMAE_DP_DST_NONE	"dst_addr [none]"
 
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
+{
+	u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
+
+	switch (dmae->opcode & DMAE_COMMAND_DST) {
+	case DMAE_CMD_DST_PCI:
+		if (src_type == DMAE_CMD_SRC_PCI)
+			DP(msglvl, "DMAE: opcode 0x%08x\n"
+			   "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
+			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
+			   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+			   dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+			   dmae->comp_addr_hi, dmae->comp_addr_lo,
+			   dmae->comp_val);
+		else
+			DP(msglvl, "DMAE: opcode 0x%08x\n"
+			   "src [%08x], len [%d*4], dst [%x:%08x]\n"
+			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
+			   dmae->opcode, dmae->src_addr_lo >> 2,
+			   dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+			   dmae->comp_addr_hi, dmae->comp_addr_lo,
+			   dmae->comp_val);
+		break;
+	case DMAE_CMD_DST_GRC:
+		if (src_type == DMAE_CMD_SRC_PCI)
+			DP(msglvl, "DMAE: opcode 0x%08x\n"
+			   "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
+			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
+			   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+			   dmae->len, dmae->dst_addr_lo >> 2,
+			   dmae->comp_addr_hi, dmae->comp_addr_lo,
+			   dmae->comp_val);
+		else
+			DP(msglvl, "DMAE: opcode 0x%08x\n"
+			   "src [%08x], len [%d*4], dst [%08x]\n"
+			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
+			   dmae->opcode, dmae->src_addr_lo >> 2,
+			   dmae->len, dmae->dst_addr_lo >> 2,
+			   dmae->comp_addr_hi, dmae->comp_addr_lo,
+			   dmae->comp_val);
+		break;
+	default:
+		if (src_type == DMAE_CMD_SRC_PCI)
+			DP(msglvl, "DMAE: opcode 0x%08x\n"
+			   "src_addr [%x:%08x]  len [%d * 4]  dst_addr [none]\n"
+			   "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+			   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+			   dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+			   dmae->comp_val);
+		else
+			DP(msglvl, "DMAE: opcode 0x%08x\n"
+			   "src_addr [%08x]  len [%d * 4]  dst_addr [none]\n"
+			   "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+			   dmae->opcode, dmae->src_addr_lo >> 2,
+			   dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+			   dmae->comp_val);
+		break;
+	}
+}
 
 /* copy command into DMAE command memory and set DMAE command go */
 void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
@@ -396,7 +487,7 @@
 	return opcode;
 }
 
-static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
 				      struct dmae_command *dmae,
 				      u8 src_type, u8 dst_type)
 {
@@ -412,9 +503,8 @@
 	dmae->comp_val = DMAE_COMP_VAL;
 }
 
-/* issue a dmae command over the init-channel and wailt for completion */
-static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp,
-				      struct dmae_command *dmae)
+/* issue a dmae command over the init-channel and wait for completion */
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
 {
 	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
 	int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
@@ -692,12 +782,16 @@
 	printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
 
 	printk("%s", lvl);
+
+	/* dump buffer after the mark */
 	for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
 		for (word = 0; word < 8; word++)
 			data[word] = htonl(REG_RD(bp, offset + 4*word));
 		data[8] = 0x0;
 		pr_cont("%s", (char *)data);
 	}
+
+	/* dump buffer before the mark */
 	for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
 		for (word = 0; word < 8; word++)
 			data[word] = htonl(REG_RD(bp, offset + 4*word));
@@ -712,7 +806,71 @@
 	bnx2x_fw_dump_lvl(bp, KERN_ERR);
 }
 
-void bnx2x_panic_dump(struct bnx2x *bp)
+static void bnx2x_hc_int_disable(struct bnx2x *bp)
+{
+	int port = BP_PORT(bp);
+	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+	u32 val = REG_RD(bp, addr);
+
+	/* in E1 we must use only PCI configuration space to disable
+	 * MSI/MSIX capablility
+	 * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
+	 */
+	if (CHIP_IS_E1(bp)) {
+		/* Since IGU_PF_CONF_MSI_MSIX_EN still always on
+		 * Use mask register to prevent from HC sending interrupts
+		 * after we exit the function
+		 */
+		REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
+
+		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+			 HC_CONFIG_0_REG_INT_LINE_EN_0 |
+			 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+	} else
+		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+			 HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+			 HC_CONFIG_0_REG_INT_LINE_EN_0 |
+			 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+	DP(NETIF_MSG_IFDOWN,
+	   "write %x to HC %d (addr 0x%x)\n",
+	   val, port, addr);
+
+	/* flush all outstanding writes */
+	mmiowb();
+
+	REG_WR(bp, addr, val);
+	if (REG_RD(bp, addr) != val)
+		BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_igu_int_disable(struct bnx2x *bp)
+{
+	u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+
+	val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
+		 IGU_PF_CONF_INT_LINE_EN |
+		 IGU_PF_CONF_ATTN_BIT_EN);
+
+	DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
+
+	/* flush all outstanding writes */
+	mmiowb();
+
+	REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+	if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
+		BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_int_disable(struct bnx2x *bp)
+{
+	if (bp->common.int_block == INT_BLOCK_HC)
+		bnx2x_hc_int_disable(bp);
+	else
+		bnx2x_igu_int_disable(bp);
+}
+
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
 {
 	int i;
 	u16 j;
@@ -722,6 +880,8 @@
 	u16 start = 0, end = 0;
 	u8 cos;
 #endif
+	if (disable_int)
+		bnx2x_int_disable(bp);
 
 	bp->stats_state = STATS_STATE_DISABLED;
 	bp->eth_stats.unrecoverable_error++;
@@ -867,6 +1027,17 @@
 	}
 
 #ifdef BNX2X_STOP_ON_ERROR
+
+	/* event queue */
+	for (i = 0; i < NUM_EQ_DESC; i++) {
+		u32 *data = (u32 *)&bp->eq_ring[i].message.data;
+
+		BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
+			  i, bp->eq_ring[i].message.opcode,
+			  bp->eq_ring[i].message.error);
+		BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]);
+	}
+
 	/* Rings */
 	/* Rx */
 	for_each_valid_rx_queue(bp, i) {
@@ -1038,8 +1209,8 @@
 	return val;
 }
 
-static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
-					   char *msg, u32 poll_cnt)
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+				    char *msg, u32 poll_cnt)
 {
 	u32 val = bnx2x_flr_clnup_reg_poll(bp, reg, 0, poll_cnt);
 	if (val != 0) {
@@ -1049,7 +1220,8 @@
 	return 0;
 }
 
-static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
+/* Common routines with VF FLR cleanup */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
 {
 	/* adjust polling timeout */
 	if (CHIP_REV_IS_EMUL(bp))
@@ -1061,7 +1233,7 @@
 	return FLR_POLL_CNT;
 }
 
-static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
 {
 	struct pbf_pN_cmd_regs cmd_regs[] = {
 		{0, (CHIP_IS_E3B0(bp)) ?
@@ -1136,10 +1308,9 @@
 	(((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)
 
 
-static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
-					 u32 poll_cnt)
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
 {
-	struct sdm_op_gen op_gen = {0};
+	u32 op_gen_command = 0;
 
 	u32 comp_addr = BAR_CSTRORM_INTMEM +
 			CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);
@@ -1150,19 +1321,20 @@
 		return 1;
 	}
 
-	op_gen.command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
-	op_gen.command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
-	op_gen.command |= OP_GEN_AGG_VECT(clnup_func);
-	op_gen.command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
+	op_gen_command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
+	op_gen_command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
+	op_gen_command |= OP_GEN_AGG_VECT(clnup_func);
+	op_gen_command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
 
 	DP(BNX2X_MSG_SP, "sending FW Final cleanup\n");
-	REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen.command);
+	REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen_command);
 
 	if (bnx2x_flr_clnup_reg_poll(bp, comp_addr, 1, poll_cnt) != 1) {
 		BNX2X_ERR("FW final cleanup did not succeed\n");
 		DP(BNX2X_MSG_SP, "At timeout completion address contained %x\n",
 		   (REG_RD(bp, comp_addr)));
-		ret = 1;
+		bnx2x_panic();
+		return 1;
 	}
 	/* Zero completion for nxt FLR */
 	REG_WR(bp, comp_addr, 0);
@@ -1170,7 +1342,7 @@
 	return ret;
 }
 
-static u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
 {
 	u16 status;
 
@@ -1382,26 +1554,31 @@
 	if (msix) {
 		val &= ~(IGU_PF_CONF_INT_LINE_EN |
 			 IGU_PF_CONF_SINGLE_ISR_EN);
-		val |= (IGU_PF_CONF_FUNC_EN |
-			IGU_PF_CONF_MSI_MSIX_EN |
+		val |= (IGU_PF_CONF_MSI_MSIX_EN |
 			IGU_PF_CONF_ATTN_BIT_EN);
 
 		if (single_msix)
 			val |= IGU_PF_CONF_SINGLE_ISR_EN;
 	} else if (msi) {
 		val &= ~IGU_PF_CONF_INT_LINE_EN;
-		val |= (IGU_PF_CONF_FUNC_EN |
-			IGU_PF_CONF_MSI_MSIX_EN |
+		val |= (IGU_PF_CONF_MSI_MSIX_EN |
 			IGU_PF_CONF_ATTN_BIT_EN |
 			IGU_PF_CONF_SINGLE_ISR_EN);
 	} else {
 		val &= ~IGU_PF_CONF_MSI_MSIX_EN;
-		val |= (IGU_PF_CONF_FUNC_EN |
-			IGU_PF_CONF_INT_LINE_EN |
+		val |= (IGU_PF_CONF_INT_LINE_EN |
 			IGU_PF_CONF_ATTN_BIT_EN |
 			IGU_PF_CONF_SINGLE_ISR_EN);
 	}
 
+	/* Clean previous status - need to configure igu prior to ack*/
+	if ((!msix) || single_msix) {
+		REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+		bnx2x_ack_int(bp);
+	}
+
+	val |= IGU_PF_CONF_FUNC_EN;
+
 	DP(NETIF_MSG_IFUP, "write 0x%x to IGU  mode %s\n",
 	   val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 
@@ -1436,71 +1613,6 @@
 		bnx2x_igu_int_enable(bp);
 }
 
-static void bnx2x_hc_int_disable(struct bnx2x *bp)
-{
-	int port = BP_PORT(bp);
-	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
-	u32 val = REG_RD(bp, addr);
-
-	/*
-	 * in E1 we must use only PCI configuration space to disable
-	 * MSI/MSIX capablility
-	 * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
-	 */
-	if (CHIP_IS_E1(bp)) {
-		/*  Since IGU_PF_CONF_MSI_MSIX_EN still always on
-		 *  Use mask register to prevent from HC sending interrupts
-		 *  after we exit the function
-		 */
-		REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
-
-		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-			 HC_CONFIG_0_REG_INT_LINE_EN_0 |
-			 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-	} else
-		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-			 HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-			 HC_CONFIG_0_REG_INT_LINE_EN_0 |
-			 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-
-	DP(NETIF_MSG_IFDOWN,
-	   "write %x to HC %d (addr 0x%x)\n",
-	   val, port, addr);
-
-	/* flush all outstanding writes */
-	mmiowb();
-
-	REG_WR(bp, addr, val);
-	if (REG_RD(bp, addr) != val)
-		BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_igu_int_disable(struct bnx2x *bp)
-{
-	u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
-
-	val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
-		 IGU_PF_CONF_INT_LINE_EN |
-		 IGU_PF_CONF_ATTN_BIT_EN);
-
-	DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
-
-	/* flush all outstanding writes */
-	mmiowb();
-
-	REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
-	if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
-		BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_int_disable(struct bnx2x *bp)
-{
-	if (bp->common.int_block == INT_BLOCK_HC)
-		bnx2x_hc_int_disable(bp);
-	else
-		bnx2x_igu_int_disable(bp);
-}
-
 void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
 {
 	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
@@ -1586,11 +1698,11 @@
 }
 
 /**
- * bnx2x_trylock_leader_lock- try to aquire a leader lock.
+ * bnx2x_trylock_leader_lock- try to acquire a leader lock.
  *
  * @bp: driver handle
  *
- * Tries to aquire a leader lock for current engine.
+ * Tries to acquire a leader lock for current engine.
  */
 static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
 {
@@ -1599,6 +1711,24 @@
 
 static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err);
 
+/* schedule the sp task and mark that interrupt occurred (runs from ISR) */
+static int bnx2x_schedule_sp_task(struct bnx2x *bp)
+{
+	/* Set the interrupt occurred bit for the sp-task to recognize it
+	 * must ack the interrupt and transition according to the IGU
+	 * state machine.
+	 */
+	atomic_set(&bp->interrupt_occurred, 1);
+
+	/* The sp_task must execute only after this bit
+	 * is set, otherwise we will get out of sync and miss all
+	 * further interrupts. Hence, the barrier.
+	 */
+	smp_wmb();
+
+	/* schedule sp_task to workqueue */
+	return queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+}
 
 void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 {
@@ -1613,6 +1743,13 @@
 	   fp->index, cid, command, bp->state,
 	   rr_cqe->ramrod_cqe.ramrod_type);
 
+	/* If cid is within VF range, replace the slowpath object with the
+	 * one corresponding to this VF
+	 */
+	if (cid >= BNX2X_FIRST_VF_CID  &&
+	    cid < BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)
+		bnx2x_iov_set_queue_sp_obj(bp, cid, &q_obj);
+
 	switch (command) {
 	case (RAMROD_CMD_ID_ETH_CLIENT_UPDATE):
 		DP(BNX2X_MSG_SP, "got UPDATE ramrod. CID %d\n", cid);
@@ -1664,6 +1801,8 @@
 #else
 		return;
 #endif
+	/* SRIOV: reschedule any 'in_progress' operations */
+	bnx2x_iov_sp_event(bp, cid, true);
 
 	smp_mb__before_atomic_inc();
 	atomic_inc(&bp->cq_spq_left);
@@ -1680,7 +1819,7 @@
 		 * mark pending ACK to MCP bit.
 		 * prevent case that both bits are cleared.
 		 * At the end of load/unload driver checks that
-		 * sp_state is cleaerd, and this order prevents
+		 * sp_state is cleared, and this order prevents
 		 * races
 		 */
 		smp_mb__before_clear_bit();
@@ -1689,22 +1828,13 @@
 		clear_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state);
 		smp_mb__after_clear_bit();
 
-		/* schedule workqueue to send ack to MCP */
-		queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+		/* schedule the sp task as mcp ack is required */
+		bnx2x_schedule_sp_task(bp);
 	}
 
 	return;
 }
 
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-			u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod)
-{
-	u32 start = BAR_USTRORM_INTMEM + fp->ustorm_rx_prods_offset;
-
-	bnx2x_update_rx_prod_gen(bp, fp, bd_prod, rx_comp_prod, rx_sge_prod,
-				 start);
-}
-
 irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
 {
 	struct bnx2x *bp = netdev_priv(dev_instance);
@@ -1745,21 +1875,23 @@
 		if (status & (mask | 0x1)) {
 			struct cnic_ops *c_ops = NULL;
 
-			if (likely(bp->state == BNX2X_STATE_OPEN)) {
-				rcu_read_lock();
-				c_ops = rcu_dereference(bp->cnic_ops);
-				if (c_ops)
-					c_ops->cnic_handler(bp->cnic_data,
-							    NULL);
-				rcu_read_unlock();
-			}
+			rcu_read_lock();
+			c_ops = rcu_dereference(bp->cnic_ops);
+			if (c_ops && (bp->cnic_eth_dev.drv_state &
+				      CNIC_DRV_STATE_HANDLES_IRQ))
+				c_ops->cnic_handler(bp->cnic_data, NULL);
+			rcu_read_unlock();
 
 			status &= ~mask;
 		}
 	}
 
 	if (unlikely(status & 0x1)) {
-		queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+
+		/* schedule sp task to perform default status block work, ack
+		 * attentions and enable interrupts.
+		 */
+		bnx2x_schedule_sp_task(bp);
 
 		status &= ~0x1;
 		if (!status)
@@ -2459,23 +2591,55 @@
 		return;
 
 	/* read updated dcb configuration */
-	bnx2x_dcbx_pmf_update(bp);
+	if (IS_PF(bp)) {
+		bnx2x_dcbx_pmf_update(bp);
+		bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+		if (bp->link_vars.link_up)
+			bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+		else
+			bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+			/* indicate link status */
+		bnx2x_link_report(bp);
 
-	bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+	} else { /* VF */
+		bp->port.supported[0] |= (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_1000baseT_Full |
+					  SUPPORTED_2500baseX_Full |
+					  SUPPORTED_10000baseT_Full |
+					  SUPPORTED_TP |
+					  SUPPORTED_FIBRE |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_Pause |
+					  SUPPORTED_Asym_Pause);
+		bp->port.advertising[0] = bp->port.supported[0];
 
-	if (bp->link_vars.link_up)
+		bp->link_params.bp = bp;
+		bp->link_params.port = BP_PORT(bp);
+		bp->link_params.req_duplex[0] = DUPLEX_FULL;
+		bp->link_params.req_flow_ctrl[0] = BNX2X_FLOW_CTRL_NONE;
+		bp->link_params.req_line_speed[0] = SPEED_10000;
+		bp->link_params.speed_cap_mask[0] = 0x7f0000;
+		bp->link_params.switch_cfg = SWITCH_CFG_10G;
+		bp->link_vars.mac_type = MAC_TYPE_BMAC;
+		bp->link_vars.line_speed = SPEED_10000;
+		bp->link_vars.link_status =
+			(LINK_STATUS_LINK_UP |
+			 LINK_STATUS_SPEED_AND_DUPLEX_10GTFD);
+		bp->link_vars.link_up = 1;
+		bp->link_vars.duplex = DUPLEX_FULL;
+		bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+		__bnx2x_link_report(bp);
 		bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
-	else
-		bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-	/* indicate link status */
-	bnx2x_link_report(bp);
+	}
 }
 
 static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
 				  u16 vlan_val, u8 allowed_prio)
 {
-	struct bnx2x_func_state_params func_params = {0};
+	struct bnx2x_func_state_params func_params = {NULL};
 	struct bnx2x_func_afex_update_params *f_update_params =
 		&func_params.params.afex_update;
 
@@ -2500,7 +2664,7 @@
 static int bnx2x_afex_handle_vif_list_cmd(struct bnx2x *bp, u8 cmd_type,
 					  u16 vif_index, u8 func_bit_map)
 {
-	struct bnx2x_func_state_params func_params = {0};
+	struct bnx2x_func_state_params func_params = {NULL};
 	struct bnx2x_func_afex_viflists_params *update_params =
 		&func_params.params.afex_viflists;
 	int rc;
@@ -2516,7 +2680,7 @@
 
 	/* set parameters according to cmd_type */
 	update_params->afex_vif_list_command = cmd_type;
-	update_params->vif_list_index = cpu_to_le16(vif_index);
+	update_params->vif_list_index = vif_index;
 	update_params->func_bit_map =
 		(cmd_type == VIF_LIST_RULE_GET) ? 0 : func_bit_map;
 	update_params->func_to_clear = 0;
@@ -2800,6 +2964,10 @@
 		__set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
 
 
+#ifdef BNX2X_STOP_ON_ERROR
+	__set_bit(BNX2X_Q_FLG_TX_SEC, &flags);
+#endif
+
 	return flags;
 }
 
@@ -2875,15 +3043,12 @@
 				pause->sge_th_hi + FW_PREFETCH_CNT >
 				MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
 
-		tpa_agg_size = min_t(u32,
-			(min_t(u32, 8, MAX_SKB_FRAGS) *
-			SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
+		tpa_agg_size = TPA_AGG_SIZE;
 		max_sge = SGE_PAGE_ALIGN(bp->dev->mtu) >>
 			SGE_PAGE_SHIFT;
 		max_sge = ((max_sge + PAGES_PER_SGE - 1) &
 			  (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
-		sge_sz = (u16)min_t(u32, SGE_PAGE_SIZE * PAGES_PER_SGE,
-				    0xffff);
+		sge_sz = (u16)min_t(u32, SGE_PAGES, 0xffff);
 	}
 
 	/* pause - not for e1 */
@@ -2928,7 +3093,7 @@
 
 	/* Maximum number or simultaneous TPA aggregation for this Queue.
 	 *
-	 * For PF Clients it should be the maximum avaliable number.
+	 * For PF Clients it should be the maximum available number.
 	 * VF driver(s) may want to define it to a smaller value.
 	 */
 	rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
@@ -3022,7 +3187,7 @@
 	if (bp->port.pmf)
 		storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
 
-	/* init Event Queue */
+	/* init Event Queue - PCI bus guarantees correct endianity*/
 	eq_data.base_addr.hi = U64_HI(bp->eq_mapping);
 	eq_data.base_addr.lo = U64_LO(bp->eq_mapping);
 	eq_data.producer = bp->eq_prod;
@@ -3112,65 +3277,75 @@
 		struct fcoe_statistics_params *fw_fcoe_stat =
 			&bp->fw_stats_data->fcoe;
 
-		ADD_64(fcoe_stat->rx_bytes_hi, 0, fcoe_stat->rx_bytes_lo,
-		       fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
+		ADD_64_LE(fcoe_stat->rx_bytes_hi, LE32_0,
+			  fcoe_stat->rx_bytes_lo,
+			  fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
 
-		ADD_64(fcoe_stat->rx_bytes_hi,
-		       fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
-		       fcoe_stat->rx_bytes_lo,
-		       fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
+		ADD_64_LE(fcoe_stat->rx_bytes_hi,
+			  fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
+			  fcoe_stat->rx_bytes_lo,
+			  fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
 
-		ADD_64(fcoe_stat->rx_bytes_hi,
-		       fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
-		       fcoe_stat->rx_bytes_lo,
-		       fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
+		ADD_64_LE(fcoe_stat->rx_bytes_hi,
+			  fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
+			  fcoe_stat->rx_bytes_lo,
+			  fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
 
-		ADD_64(fcoe_stat->rx_bytes_hi,
-		       fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
-		       fcoe_stat->rx_bytes_lo,
-		       fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
+		ADD_64_LE(fcoe_stat->rx_bytes_hi,
+			  fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
+			  fcoe_stat->rx_bytes_lo,
+			  fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
 
-		ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-		       fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
+		ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+			  fcoe_stat->rx_frames_lo,
+			  fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
 
-		ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-		       fcoe_q_tstorm_stats->rcv_ucast_pkts);
+		ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+			  fcoe_stat->rx_frames_lo,
+			  fcoe_q_tstorm_stats->rcv_ucast_pkts);
 
-		ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-		       fcoe_q_tstorm_stats->rcv_bcast_pkts);
+		ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+			  fcoe_stat->rx_frames_lo,
+			  fcoe_q_tstorm_stats->rcv_bcast_pkts);
 
-		ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
-		       fcoe_q_tstorm_stats->rcv_mcast_pkts);
+		ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+			  fcoe_stat->rx_frames_lo,
+			  fcoe_q_tstorm_stats->rcv_mcast_pkts);
 
-		ADD_64(fcoe_stat->tx_bytes_hi, 0, fcoe_stat->tx_bytes_lo,
-		       fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
+		ADD_64_LE(fcoe_stat->tx_bytes_hi, LE32_0,
+			  fcoe_stat->tx_bytes_lo,
+			  fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
 
-		ADD_64(fcoe_stat->tx_bytes_hi,
-		       fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
-		       fcoe_stat->tx_bytes_lo,
-		       fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
+		ADD_64_LE(fcoe_stat->tx_bytes_hi,
+			  fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
+			  fcoe_stat->tx_bytes_lo,
+			  fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
 
-		ADD_64(fcoe_stat->tx_bytes_hi,
-		       fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
-		       fcoe_stat->tx_bytes_lo,
-		       fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
+		ADD_64_LE(fcoe_stat->tx_bytes_hi,
+			  fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
+			  fcoe_stat->tx_bytes_lo,
+			  fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
 
-		ADD_64(fcoe_stat->tx_bytes_hi,
-		       fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
-		       fcoe_stat->tx_bytes_lo,
-		       fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
+		ADD_64_LE(fcoe_stat->tx_bytes_hi,
+			  fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
+			  fcoe_stat->tx_bytes_lo,
+			  fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
 
-		ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-		       fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
+		ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+			  fcoe_stat->tx_frames_lo,
+			  fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
 
-		ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-		       fcoe_q_xstorm_stats->ucast_pkts_sent);
+		ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+			  fcoe_stat->tx_frames_lo,
+			  fcoe_q_xstorm_stats->ucast_pkts_sent);
 
-		ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-		       fcoe_q_xstorm_stats->bcast_pkts_sent);
+		ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+			  fcoe_stat->tx_frames_lo,
+			  fcoe_q_xstorm_stats->bcast_pkts_sent);
 
-		ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
-		       fcoe_q_xstorm_stats->mcast_pkts_sent);
+		ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+			  fcoe_stat->tx_frames_lo,
+			  fcoe_q_xstorm_stats->mcast_pkts_sent);
 	}
 
 	/* ask L5 driver to add data to the struct */
@@ -3641,7 +3816,7 @@
 			    "Please contact OEM Support for assistance\n");
 
 	/*
-	 * Scheudle device reset (unload)
+	 * Schedule device reset (unload)
 	 * This is due to some boards consuming sufficient power when driver is
 	 * up to overheat if fan fails.
 	 */
@@ -3791,6 +3966,10 @@
 
 			if (val & DRV_STATUS_DRV_INFO_REQ)
 				bnx2x_handle_drv_info_req(bp);
+
+			if (val & DRV_STATUS_VF_DISABLED)
+				bnx2x_vf_handle_flr_event(bp);
+
 			if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
 				bnx2x_pmf_update(bp);
 
@@ -4587,8 +4766,8 @@
 void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
 		      u16 index, u8 op, u8 update)
 {
-	u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
-
+	u32 igu_addr = bp->igu_base_addr;
+	igu_addr += (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
 	bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update,
 			     igu_addr);
 }
@@ -4616,7 +4795,7 @@
 
 		BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n",
 			  cid);
-		bnx2x_panic_dump(bp);
+		bnx2x_panic_dump(bp, false);
 	}
 	bnx2x_cnic_cfc_comp(bp, cid, err);
 	return 0;
@@ -4658,7 +4837,8 @@
 	/* Always push next commands out, don't wait here */
 	__set_bit(RAMROD_CONT, &ramrod_flags);
 
-	switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+	switch (le32_to_cpu((__force __le32)elem->message.data.eth_event.echo)
+			    >> BNX2X_SWCID_SHIFT) {
 	case BNX2X_FILTER_MAC_PENDING:
 		DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");
 		if (CNIC_LOADED(bp) && (cid == BNX2X_ISCSI_ETH_CID(bp)))
@@ -4735,7 +4915,7 @@
 	struct bnx2x_queue_update_params *q_update_params =
 		&queue_params.params.update;
 
-	/* Send Q update command with afex vlan removal values	for all Qs */
+	/* Send Q update command with afex vlan removal values for all Qs */
 	queue_params.cmd = BNX2X_Q_CMD_UPDATE;
 
 	/* set silent vlan removal values according to vlan mode */
@@ -4809,7 +4989,7 @@
 	u8 echo;
 	u32 cid;
 	u8 opcode;
-	int spqe_cnt = 0;
+	int rc, spqe_cnt = 0;
 	struct bnx2x_queue_sp_obj *q_obj;
 	struct bnx2x_func_sp_obj *f_obj = &bp->func_obj;
 	struct bnx2x_raw_obj *rss_raw = &bp->rss_conf_obj.raw;
@@ -4837,15 +5017,27 @@
 	for (; sw_cons != hw_cons;
 	      sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) {
 
-
 		elem = &bp->eq_ring[EQ_DESC(sw_cons)];
 
-		cid = SW_CID(elem->message.data.cfc_del_event.cid);
-		opcode = elem->message.opcode;
+		rc = bnx2x_iov_eq_sp_event(bp, elem);
+		if (!rc) {
+			DP(BNX2X_MSG_IOV, "bnx2x_iov_eq_sp_event returned %d\n",
+			   rc);
+			goto next_spqe;
+		}
 
+		/* elem CID originates from FW; actually LE */
+		cid = SW_CID((__force __le32)
+			     elem->message.data.cfc_del_event.cid);
+		opcode = elem->message.opcode;
 
 		/* handle eq element */
 		switch (opcode) {
+		case EVENT_RING_OPCODE_VF_PF_CHANNEL:
+			DP(BNX2X_MSG_IOV, "vf pf channel element on eq\n");
+			bnx2x_vf_mbx(bp, &elem->message.data.vf_pf_event);
+			continue;
+
 		case EVENT_RING_OPCODE_STAT_QUERY:
 			DP(BNX2X_MSG_SP | BNX2X_MSG_STATS,
 			   "got statistics comp event %d\n",
@@ -5011,50 +5203,65 @@
 static void bnx2x_sp_task(struct work_struct *work)
 {
 	struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
-	u16 status;
 
-	status = bnx2x_update_dsb_idx(bp);
-/*	if (status == 0)				     */
-/*		BNX2X_ERR("spurious slowpath interrupt!\n"); */
+	DP(BNX2X_MSG_SP, "sp task invoked\n");
 
-	DP(BNX2X_MSG_SP, "got a slowpath interrupt (status 0x%x)\n", status);
+	/* make sure the atomic interupt_occurred has been written */
+	smp_rmb();
+	if (atomic_read(&bp->interrupt_occurred)) {
 
-	/* HW attentions */
-	if (status & BNX2X_DEF_SB_ATT_IDX) {
-		bnx2x_attn_int(bp);
-		status &= ~BNX2X_DEF_SB_ATT_IDX;
-	}
+		/* what work needs to be performed? */
+		u16 status = bnx2x_update_dsb_idx(bp);
 
-	/* SP events: STAT_QUERY and others */
-	if (status & BNX2X_DEF_SB_IDX) {
-		struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
+		DP(BNX2X_MSG_SP, "status %x\n", status);
+		DP(BNX2X_MSG_SP, "setting interrupt_occurred to 0\n");
+		atomic_set(&bp->interrupt_occurred, 0);
 
-		if (FCOE_INIT(bp) &&
-		    (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
-			/*
-			 * Prevent local bottom-halves from running as
-			 * we are going to change the local NAPI list.
-			 */
-			local_bh_disable();
-			napi_schedule(&bnx2x_fcoe(bp, napi));
-			local_bh_enable();
+		/* HW attentions */
+		if (status & BNX2X_DEF_SB_ATT_IDX) {
+			bnx2x_attn_int(bp);
+			status &= ~BNX2X_DEF_SB_ATT_IDX;
 		}
 
-		/* Handle EQ completions */
-		bnx2x_eq_int(bp);
+		/* SP events: STAT_QUERY and others */
+		if (status & BNX2X_DEF_SB_IDX) {
+			struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
 
-		bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
-			le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+		if (FCOE_INIT(bp) &&
+			    (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+				/* Prevent local bottom-halves from running as
+				 * we are going to change the local NAPI list.
+				 */
+				local_bh_disable();
+				napi_schedule(&bnx2x_fcoe(bp, napi));
+				local_bh_enable();
+			}
 
-		status &= ~BNX2X_DEF_SB_IDX;
+			/* Handle EQ completions */
+			bnx2x_eq_int(bp);
+			bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
+				     le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+
+			status &= ~BNX2X_DEF_SB_IDX;
+		}
+
+		/* if status is non zero then perhaps something went wrong */
+		if (unlikely(status))
+			DP(BNX2X_MSG_SP,
+			   "got an unknown interrupt! (status 0x%x)\n", status);
+
+		/* ack status block only if something was actually handled */
+		bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
+			     le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
+
 	}
 
-	if (unlikely(status))
-		DP(BNX2X_MSG_SP, "got an unknown interrupt! (status 0x%x)\n",
-		   status);
-
-	bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
-	     le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
+	/* must be called after the EQ processing (since eq leads to sriov
+	 * ramrod completion flows).
+	 * This flow may have been scheduled by the arrival of a ramrod
+	 * completion, or by the sriov code rescheduling itself.
+	 */
+	bnx2x_iov_sp_task(bp);
 
 	/* afex - poll to check if VIFSET_ACK should be sent to MFW */
 	if (test_and_clear_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK,
@@ -5087,7 +5294,10 @@
 		rcu_read_unlock();
 	}
 
-	queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+	/* schedule sp task to perform default status block work, ack
+	 * attentions and enable interrupts.
+	 */
+	bnx2x_schedule_sp_task(bp);
 
 	return IRQ_HANDLED;
 }
@@ -5101,7 +5311,6 @@
 		 bp->fw_drv_pulse_wr_seq);
 }
 
-
 static void bnx2x_timer(unsigned long data)
 {
 	struct bnx2x *bp = (struct bnx2x *) data;
@@ -5109,7 +5318,8 @@
 	if (!netif_running(bp->dev))
 		return;
 
-	if (!BP_NOMCP(bp)) {
+	if (IS_PF(bp) &&
+	    !BP_NOMCP(bp)) {
 		int mb_idx = BP_FW_MB_IDX(bp);
 		u32 drv_pulse;
 		u32 mcp_pulse;
@@ -5136,6 +5346,10 @@
 	if (bp->state == BNX2X_STATE_OPEN)
 		bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
 
+	/* sample pf vf bulletin board for new posts from pf */
+	if (IS_VF(bp))
+		bnx2x_sample_bulletin(bp);
+
 	mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
 
@@ -5278,7 +5492,7 @@
 		SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
 }
 
-static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
 			  u8 vf_valid, int fw_sb_id, int igu_sb_id)
 {
 	int igu_seg_id;
@@ -5334,7 +5548,7 @@
 
 	DP(NETIF_MSG_IFUP, "Init FW SB %d\n", fw_sb_id);
 
-	/* write indecies to HW */
+	/* write indices to HW - PCI guarantees endianity of regpairs */
 	bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size);
 }
 
@@ -5422,6 +5636,7 @@
 
 	bnx2x_zero_sp_sb(bp);
 
+	/* PCI guarantees endianity of regpairs */
 	sp_sb_data.state		= SB_ENABLED;
 	sp_sb_data.host_sb_addr.lo	= U64_LO(section);
 	sp_sb_data.host_sb_addr.hi	= U64_HI(section);
@@ -5478,13 +5693,12 @@
 		min_t(int, MAX_SP_DESC_CNT - MAX_SPQ_PENDING, NUM_EQ_DESC) - 1);
 }
 
-
 /* called with netif_addr_lock_bh() */
-void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-			 unsigned long rx_mode_flags,
-			 unsigned long rx_accept_flags,
-			 unsigned long tx_accept_flags,
-			 unsigned long ramrod_flags)
+int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+			unsigned long rx_mode_flags,
+			unsigned long rx_accept_flags,
+			unsigned long tx_accept_flags,
+			unsigned long ramrod_flags)
 {
 	struct bnx2x_rx_mode_ramrod_params ramrod_param;
 	int rc;
@@ -5514,22 +5728,21 @@
 	rc = bnx2x_config_rx_mode(bp, &ramrod_param);
 	if (rc < 0) {
 		BNX2X_ERR("Set rx_mode %d failed\n", bp->rx_mode);
-		return;
+		return rc;
 	}
+
+	return 0;
 }
 
-/* called with netif_addr_lock_bh() */
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
+				   unsigned long *rx_accept_flags,
+				   unsigned long *tx_accept_flags)
 {
-	unsigned long rx_mode_flags = 0, ramrod_flags = 0;
-	unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
+	/* Clear the flags first */
+	*rx_accept_flags = 0;
+	*tx_accept_flags = 0;
 
-	if (!NO_FCOE(bp))
-
-		/* Configure rx_mode of FCoE Queue */
-		__set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags);
-
-	switch (bp->rx_mode) {
+	switch (rx_mode) {
 	case BNX2X_RX_MODE_NONE:
 		/*
 		 * 'drop all' supersedes any accept flags that may have been
@@ -5537,25 +5750,25 @@
 		 */
 		break;
 	case BNX2X_RX_MODE_NORMAL:
-		__set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_MULTICAST, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_MULTICAST, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
 
 		/* internal switching mode */
-		__set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_MULTICAST, &tx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_MULTICAST, tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
 
 		break;
 	case BNX2X_RX_MODE_ALLMULTI:
-		__set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
 
 		/* internal switching mode */
-		__set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
 
 		break;
 	case BNX2X_RX_MODE_PROMISC:
@@ -5563,36 +5776,57 @@
 		 * should receive matched and unmatched (in resolution of port)
 		 * unicast packets.
 		 */
-		__set_bit(BNX2X_ACCEPT_UNMATCHED, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_UNMATCHED, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
 
 		/* internal switching mode */
-		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
 
 		if (IS_MF_SI(bp))
-			__set_bit(BNX2X_ACCEPT_ALL_UNICAST, &tx_accept_flags);
+			__set_bit(BNX2X_ACCEPT_ALL_UNICAST, tx_accept_flags);
 		else
-			__set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
+			__set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
 
 		break;
 	default:
-		BNX2X_ERR("Unknown rx_mode: %d\n", bp->rx_mode);
-		return;
+		BNX2X_ERR("Unknown rx_mode: %d\n", rx_mode);
+		return -EINVAL;
 	}
 
+	/* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */
 	if (bp->rx_mode != BNX2X_RX_MODE_NONE) {
-		__set_bit(BNX2X_ACCEPT_ANY_VLAN, &rx_accept_flags);
-		__set_bit(BNX2X_ACCEPT_ANY_VLAN, &tx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
+		__set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
 	}
 
+	return 0;
+}
+
+/* called with netif_addr_lock_bh() */
+int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+{
+	unsigned long rx_mode_flags = 0, ramrod_flags = 0;
+	unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
+	int rc;
+
+	if (!NO_FCOE(bp))
+		/* Configure rx_mode of FCoE Queue */
+		__set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags);
+
+	rc = bnx2x_fill_accept_flags(bp, bp->rx_mode, &rx_accept_flags,
+				     &tx_accept_flags);
+	if (rc)
+		return rc;
+
 	__set_bit(RAMROD_RX, &ramrod_flags);
 	__set_bit(RAMROD_TX, &ramrod_flags);
 
-	bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags, rx_accept_flags,
-			    tx_accept_flags, ramrod_flags);
+	return bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags,
+				   rx_accept_flags, tx_accept_flags,
+				   ramrod_flags);
 }
 
 static void bnx2x_init_internal_common(struct bnx2x *bp)
@@ -5699,6 +5933,13 @@
 		cids[cos] = fp->txdata_ptr[cos]->cid;
 	}
 
+	/* nothing more for vf to do here */
+	if (IS_VF(bp))
+		return;
+
+	bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
+		      fp->fw_sb_id, fp->igu_sb_id);
+	bnx2x_update_fpsb_idx(fp);
 	bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, cids,
 			     fp->max_cos, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
 			     bnx2x_sp_mapping(bp, q_rdata), q_type);
@@ -5708,13 +5949,10 @@
 	 */
 	bnx2x_init_vlan_mac_fp_objs(fp, BNX2X_OBJ_TYPE_RX_TX);
 
-	DP(NETIF_MSG_IFUP, "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  fw_sb %d  igu_sb %d\n",
-		   fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
-		   fp->igu_sb_id);
-	bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
-		      fp->fw_sb_id, fp->igu_sb_id);
-
-	bnx2x_update_fpsb_idx(fp);
+	DP(NETIF_MSG_IFUP,
+	   "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  fw_sb %d  igu_sb %d\n",
+	   fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
+	   fp->igu_sb_id);
 }
 
 static void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata)
@@ -5786,17 +6024,22 @@
 
 	for_each_eth_queue(bp, i)
 		bnx2x_init_eth_fp(bp, i);
+
+	/* ensure status block indices were read */
+	rmb();
+	bnx2x_init_rx_rings(bp);
+	bnx2x_init_tx_rings(bp);
+
+	if (IS_VF(bp))
+		return;
+
 	/* Initialize MOD_ABS interrupts */
 	bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
 			       bp->common.shmem_base, bp->common.shmem2_base,
 			       BP_PORT(bp));
-	/* ensure status block indices were read */
-	rmb();
 
 	bnx2x_init_def_sb(bp);
 	bnx2x_update_dsb_idx(bp);
-	bnx2x_init_rx_rings(bp);
-	bnx2x_init_tx_rings(bp);
 	bnx2x_init_sp_ring(bp);
 	bnx2x_init_eq_ring(bp);
 	bnx2x_init_internal(bp, load_code);
@@ -6236,49 +6479,6 @@
 	REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
 }
 
-static void bnx2x_pretend_func(struct bnx2x *bp, u8 pretend_func_num)
-{
-	u32 offset = 0;
-
-	if (CHIP_IS_E1(bp))
-		return;
-	if (CHIP_IS_E1H(bp) && (pretend_func_num >= E1H_FUNC_MAX))
-		return;
-
-	switch (BP_ABS_FUNC(bp)) {
-	case 0:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F0;
-		break;
-	case 1:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F1;
-		break;
-	case 2:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F2;
-		break;
-	case 3:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F3;
-		break;
-	case 4:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F4;
-		break;
-	case 5:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F5;
-		break;
-	case 6:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F6;
-		break;
-	case 7:
-		offset = PXP2_REG_PGL_PRETEND_FUNC_F7;
-		break;
-	default:
-		return;
-	}
-
-	REG_WR(bp, offset, pretend_func_num);
-	REG_RD(bp, offset);
-	DP(NETIF_MSG_HW, "Pretending to func %d\n", pretend_func_num);
-}
-
 void bnx2x_pf_disable(struct bnx2x *bp)
 {
 	u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
@@ -6322,7 +6522,7 @@
 	DP(NETIF_MSG_HW, "starting common init  func %d\n", BP_ABS_FUNC(bp));
 
 	/*
-	 * take the UNDI lock to protect undi_unload flow from accessing
+	 * take the RESET lock to protect undi_unload flow from accessing
 	 * registers while we're resetting the chip
 	 */
 	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
@@ -6452,7 +6652,7 @@
  *		    queues with "old" ILT addresses.
  *		c.  PF enable in the PGLC.
  *		d.  Clear the was_error of the PF in the PGLC. (could have
- *		    occured while driver was down)
+ *		    occurred while driver was down)
  *		e.  PF enable in the CFC (WEAK + STRONG)
  *		f.  Timers scan enable
  *	3.  PF driver unload flow:
@@ -6493,7 +6693,7 @@
 		/* Step 1: set zeroes to all ilt page entries with valid bit on
 		 * Step 2: set the timers first/last ilt entry to point
 		 * to the entire range to prevent ILT range error for 3rd/4th
-		 * vnic	(this code assumes existance of the vnic)
+		 * vnic	(this code assumes existence of the vnic)
 		 *
 		 * both steps performed by call to bnx2x_ilt_client_init_op()
 		 * with dummy TM client
@@ -6510,7 +6710,6 @@
 		REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_SEL, 1);
 	}
 
-
 	REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
 	REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
 
@@ -6535,6 +6734,8 @@
 
 	bnx2x_init_block(bp, BLOCK_DMAE, PHASE_COMMON);
 
+	bnx2x_iov_init_dmae(bp);
+
 	/* clean the DMAE memory */
 	bp->dmae_ready = 1;
 	bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8, 1);
@@ -6991,7 +7192,6 @@
 		}
 	}
 
-
 	/* If SPIO5 is set to generate interrupts, enable it for this port */
 	val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
 	if (val & MISC_SPIO_SPIO5) {
@@ -7020,15 +7220,14 @@
 	REG_WR_DMAE(bp, reg, wb_write, 2);
 }
 
-static void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func,
-				   u8 idu_sb_id, bool is_Pf)
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf)
 {
 	u32 data, ctl, cnt = 100;
 	u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
 	u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
 	u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4;
 	u32 sb_bit =  1 << (idu_sb_id%32);
-	u32 func_encode = func | (is_Pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
+	u32 func_encode = func | (is_pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
 	u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id;
 
 	/* Not supported in BC mode */
@@ -7219,8 +7418,10 @@
 	/* FLR cleanup - hmmm */
 	if (!CHIP_IS_E1x(bp)) {
 		rc = bnx2x_pf_flr_clnup(bp);
-		if (rc)
+		if (rc) {
+			bnx2x_fw_dump(bp);
 			return rc;
+		}
 	}
 
 	/* set MSI reconfigure capability */
@@ -7237,12 +7438,21 @@
 	ilt = BP_ILT(bp);
 	cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
 
+	if (IS_SRIOV(bp))
+		cdu_ilt_start += BNX2X_FIRST_VF_CID/ILT_PAGE_CIDS;
+	cdu_ilt_start = bnx2x_iov_init_ilt(bp, cdu_ilt_start);
+
+	/* since BNX2X_FIRST_VF_CID > 0 the PF L2 cids precedes
+	 * those of the VFs, so start line should be reset
+	 */
+	cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
 	for (i = 0; i < L2_ILT_LINES(bp); i++) {
 		ilt->lines[cdu_ilt_start + i].page = bp->context[i].vcxt;
 		ilt->lines[cdu_ilt_start + i].page_mapping =
 			bp->context[i].cxt_mapping;
 		ilt->lines[cdu_ilt_start + i].size = bp->context[i].size;
 	}
+
 	bnx2x_ilt_init_op(bp, INITOP_SET);
 
 	if (!CONFIGURE_NIC_MODE(bp)) {
@@ -7315,6 +7525,9 @@
 
 	bnx2x_init_block(bp, BLOCK_TM, init_phase);
 	bnx2x_init_block(bp, BLOCK_DORQ, init_phase);
+
+	bnx2x_iov_init_dq(bp);
+
 	bnx2x_init_block(bp, BLOCK_BRB1, init_phase);
 	bnx2x_init_block(bp, BLOCK_PRS, init_phase);
 	bnx2x_init_block(bp, BLOCK_TSDM, init_phase);
@@ -7523,10 +7736,6 @@
 {
 	int i;
 
-	/* fastpath */
-	bnx2x_free_fp_mem(bp);
-	/* end of fastpath */
-
 	BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
 		       sizeof(struct host_sp_status_block));
 
@@ -7547,68 +7756,10 @@
 
 	BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping,
 		       BCM_PAGE_SIZE * NUM_EQ_PAGES);
+
+	bnx2x_iov_free_mem(bp);
 }
 
-static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
-{
-	int num_groups;
-	int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
-
-	/* number of queues for statistics is number of eth queues + FCoE */
-	u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
-
-	/* Total number of FW statistics requests =
-	 * 1 for port stats + 1 for PF stats + potential 1 for FCoE stats +
-	 * num of queues
-	 */
-	bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
-
-
-	/* Request is built from stats_query_header and an array of
-	 * stats_query_cmd_group each of which contains
-	 * STATS_QUERY_CMD_COUNT rules. The real number or requests is
-	 * configured in the stats_query_header.
-	 */
-	num_groups = ((bp->fw_stats_num) / STATS_QUERY_CMD_COUNT) +
-		     (((bp->fw_stats_num) % STATS_QUERY_CMD_COUNT) ? 1 : 0);
-
-	bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
-			num_groups * sizeof(struct stats_query_cmd_group);
-
-	/* Data for statistics requests + stats_conter
-	 *
-	 * stats_counter holds per-STORM counters that are incremented
-	 * when STORM has finished with the current request.
-	 *
-	 * memory for FCoE offloaded statistics are counted anyway,
-	 * even if they will not be sent.
-	 */
-	bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
-		sizeof(struct per_pf_stats) +
-		sizeof(struct fcoe_statistics_params) +
-		sizeof(struct per_queue_stats) * num_queue_stats +
-		sizeof(struct stats_counter);
-
-	BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
-			bp->fw_stats_data_sz + bp->fw_stats_req_sz);
-
-	/* Set shortcuts */
-	bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
-	bp->fw_stats_req_mapping = bp->fw_stats_mapping;
-
-	bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
-		((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
-
-	bp->fw_stats_data_mapping = bp->fw_stats_mapping +
-				   bp->fw_stats_req_sz;
-	return 0;
-
-alloc_mem_err:
-	BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
-		       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
-	BNX2X_ERR("Can't allocate memory\n");
-	return -ENOMEM;
-}
 
 int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
 {
@@ -7655,10 +7806,6 @@
 	BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
 			sizeof(struct bnx2x_slowpath));
 
-	/* Allocated memory for FW statistics  */
-	if (bnx2x_alloc_fw_stats_mem(bp))
-		goto alloc_mem_err;
-
 	/* Allocate memory for CDU context:
 	 * This memory is allocated separately and not in the generic ILT
 	 * functions because CDU differs in few aspects:
@@ -7687,6 +7834,9 @@
 	if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
 		goto alloc_mem_err;
 
+	if (bnx2x_iov_alloc_mem(bp))
+		goto alloc_mem_err;
+
 	/* Slow path ring */
 	BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
 
@@ -7694,13 +7844,6 @@
 	BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
 			BCM_PAGE_SIZE * NUM_EQ_PAGES);
 
-
-	/* fastpath */
-	/* need to be done at the end, since it's self adjusting to amount
-	 * of memory available for RSS queues
-	 */
-	if (bnx2x_alloc_fp_mem(bp))
-		goto alloc_mem_err;
 	return 0;
 
 alloc_mem_err:
@@ -7803,43 +7946,53 @@
  *
  * In case of MSI-X it will also try to enable MSI-X.
  */
-void bnx2x_set_int_mode(struct bnx2x *bp)
+int bnx2x_set_int_mode(struct bnx2x *bp)
 {
+	int rc = 0;
+
+	if (IS_VF(bp) && int_mode != BNX2X_INT_MODE_MSIX)
+		return -EINVAL;
+
 	switch (int_mode) {
-	case INT_MODE_MSI:
-		bnx2x_enable_msi(bp);
+	case BNX2X_INT_MODE_MSIX:
+		/* attempt to enable msix */
+		rc = bnx2x_enable_msix(bp);
+
+		/* msix attained */
+		if (!rc)
+			return 0;
+
+		/* vfs use only msix */
+		if (rc && IS_VF(bp))
+			return rc;
+
+		/* failed to enable multiple MSI-X */
+		BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
+			       bp->num_queues,
+			       1 + bp->num_cnic_queues);
+
 		/* falling through... */
-	case INT_MODE_INTx:
+	case BNX2X_INT_MODE_MSI:
+		bnx2x_enable_msi(bp);
+
+		/* falling through... */
+	case BNX2X_INT_MODE_INTX:
 		bp->num_ethernet_queues = 1;
 		bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
 		BNX2X_DEV_INFO("set number of queues to 1\n");
 		break;
 	default:
-		/* if we can't use MSI-X we only need one fp,
-		 * so try to enable MSI-X with the requested number of fp's
-		 * and fallback to MSI or legacy INTx with one fp
-		 */
-		if (bnx2x_enable_msix(bp) ||
-		    bp->flags & USING_SINGLE_MSIX_FLAG) {
-			/* failed to enable multiple MSI-X */
-			BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
-				       bp->num_queues,
-				       1 + bp->num_cnic_queues);
-
-			bp->num_queues = 1 + bp->num_cnic_queues;
-
-			/* Try to enable MSI */
-			if (!(bp->flags & USING_SINGLE_MSIX_FLAG) &&
-			    !(bp->flags & DISABLE_MSI_FLAG))
-				bnx2x_enable_msi(bp);
-		}
-		break;
+		BNX2X_DEV_INFO("unknown value in int_mode module parameter\n");
+		return -EINVAL;
 	}
+	return 0;
 }
 
-/* must be called prioir to any HW initializations */
+/* must be called prior to any HW initializations */
 static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp)
 {
+	if (IS_SRIOV(bp))
+		return (BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)/ILT_PAGE_CIDS;
 	return L2_ILT_LINES(bp);
 }
 
@@ -8222,8 +8375,8 @@
 
 	/* SP SB */
 	REG_WR8(bp, BAR_CSTRORM_INTMEM +
-		   CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func),
-		   SB_DISABLED);
+		CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func),
+		SB_DISABLED);
 
 	for (i = 0; i < XSTORM_SPQ_DATA_SIZE / 4; i++)
 		REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_DATA_OFFSET(func),
@@ -8524,7 +8677,7 @@
 	}
 
 	/* Give HW time to discard old tx messages */
-	usleep_range(1000, 1000);
+	usleep_range(1000, 2000);
 
 	/* Clean all ETH MACs */
 	rc = bnx2x_del_all_macs(bp, &bp->sp_objs[0].mac_obj, BNX2X_ETH_MAC,
@@ -8562,6 +8715,7 @@
 
 	netif_addr_unlock_bh(bp->dev);
 
+	bnx2x_iov_chip_cleanup(bp);
 
 
 	/*
@@ -8947,7 +9101,7 @@
 		if (pend_bits == 0)
 			break;
 
-		usleep_range(1000, 1000);
+		usleep_range(1000, 2000);
 	} while (cnt-- > 0);
 
 	if (cnt <= 0) {
@@ -8964,8 +9118,7 @@
 	int cnt = 1000;
 	u32 val = 0;
 	u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
-		u32 tags_63_32 = 0;
-
+	u32 tags_63_32 = 0;
 
 	/* Empty the Tetris buffer, wait for 1s */
 	do {
@@ -8983,7 +9136,7 @@
 		    (pgl_exp_rom2 == 0xffffffff) &&
 		    (!CHIP_IS_E3(bp) || (tags_63_32 == 0xffffffff)))
 			break;
-		usleep_range(1000, 1000);
+		usleep_range(1000, 2000);
 	} while (cnt-- > 0);
 
 	if (cnt <= 0) {
@@ -9016,7 +9169,7 @@
 	/* Wait for 1ms to empty GLUE and PCI-E core queues,
 	 * PSWHST, GRC and PSWRD Tetris buffer.
 	 */
-	usleep_range(1000, 1000);
+	usleep_range(1000, 2000);
 
 	/* Prepare to chip reset: */
 	/* MCP */
@@ -9299,8 +9452,10 @@
 
 	rtnl_lock();
 
-	if (!netif_running(bp->dev))
-		goto sp_rtnl_exit;
+	if (!netif_running(bp->dev)) {
+		rtnl_unlock();
+		return;
+	}
 
 	/* if stop on error is defined no recovery flows should be executed */
 #ifdef BNX2X_STOP_ON_ERROR
@@ -9319,7 +9474,8 @@
 
 		bnx2x_parity_recover(bp);
 
-		goto sp_rtnl_exit;
+		rtnl_unlock();
+		return;
 	}
 
 	if (test_and_clear_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state)) {
@@ -9333,7 +9489,8 @@
 		bnx2x_nic_unload(bp, UNLOAD_NORMAL, true);
 		bnx2x_nic_load(bp, LOAD_NORMAL);
 
-		goto sp_rtnl_exit;
+		rtnl_unlock();
+		return;
 	}
 #ifdef BNX2X_STOP_ON_ERROR
 sp_rtnl_not_reset:
@@ -9351,13 +9508,33 @@
 		DP(NETIF_MSG_HW, "fan failure detected. Unloading driver\n");
 		netif_device_detach(bp->dev);
 		bnx2x_close(bp->dev);
+		rtnl_unlock();
+		return;
 	}
 
-sp_rtnl_exit:
-	rtnl_unlock();
-}
+	if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_MCAST, &bp->sp_rtnl_state)) {
+		DP(BNX2X_MSG_SP,
+		   "sending set mcast vf pf channel message from rtnl sp-task\n");
+		bnx2x_vfpf_set_mcast(bp->dev);
+	}
 
-/* end of nic load/unload */
+	if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+			       &bp->sp_rtnl_state)) {
+		DP(BNX2X_MSG_SP,
+		   "sending set storm rx mode vf pf channel message from rtnl sp-task\n");
+		bnx2x_vfpf_storm_rx_mode(bp);
+	}
+
+	/* work which needs rtnl lock not-taken (as it takes the lock itself and
+	 * can be called from other contexts as well)
+	 */
+	rtnl_unlock();
+
+	/* enable SR-IOV if applicable */
+	if (IS_SRIOV(bp) && test_and_clear_bit(BNX2X_SP_RTNL_ENABLE_SRIOV,
+					       &bp->sp_rtnl_state))
+		bnx2x_enable_sriov(bp);
+}
 
 static void bnx2x_period_task(struct work_struct *work)
 {
@@ -9394,43 +9571,13 @@
  * Init service functions
  */
 
-static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
 {
 	u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0;
 	u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base;
 	return base + (BP_ABS_FUNC(bp)) * stride;
 }
 
-static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp)
-{
-	u32 reg = bnx2x_get_pretend_reg(bp);
-
-	/* Flush all outstanding writes */
-	mmiowb();
-
-	/* Pretend to be function 0 */
-	REG_WR(bp, reg, 0);
-	REG_RD(bp, reg);	/* Flush the GRC transaction (in the chip) */
-
-	/* From now we are in the "like-E1" mode */
-	bnx2x_int_disable(bp);
-
-	/* Flush all outstanding writes */
-	mmiowb();
-
-	/* Restore the original function */
-	REG_WR(bp, reg, BP_ABS_FUNC(bp));
-	REG_RD(bp, reg);
-}
-
-static inline void bnx2x_undi_int_disable(struct bnx2x *bp)
-{
-	if (CHIP_IS_E1(bp))
-		bnx2x_int_disable(bp);
-	else
-		bnx2x_undi_int_disable_e1h(bp);
-}
-
 static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
 					struct bnx2x_mac_vals *vals)
 {
@@ -9658,11 +9805,13 @@
 	if (bnx2x_prev_is_path_marked(bp))
 		return bnx2x_prev_mcp_done(bp);
 
+	BNX2X_DEV_INFO("Path is unmarked\n");
+
 	/* If function has FLR capabilities, and existing FW version matches
 	 * the one required, then FLR will be sufficient to clean any residue
 	 * left by previous driver
 	 */
-	rc = bnx2x_test_firmware_version(bp, false);
+	rc = bnx2x_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
 
 	if (!rc) {
 		/* fw version is good */
@@ -9718,7 +9867,6 @@
 		/* Check if the UNDI driver was previously loaded
 		 * UNDI driver initializes CID offset for normal bell to 0x7
 		 */
-		reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1);
 		if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_DORQ) {
 			tmp_reg = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
 			if (tmp_reg == 0x7) {
@@ -9726,6 +9874,8 @@
 				prev_undi = true;
 				/* clear the UNDI indication */
 				REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+				/* clear possible idle check errors */
+				REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);
 			}
 		}
 		/* wait until BRB is empty */
@@ -9792,7 +9942,8 @@
 	if (!CHIP_IS_E1x(bp)) {
 		u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
 		if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
-			BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing");
+			DP(BNX2X_MSG_SP,
+			   "'was error' bit was found to be set in pglueb upon startup. Clearing\n");
 			REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
 			       1 << BP_FUNC(bp));
 		}
@@ -9834,7 +9985,6 @@
 		REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0);
 	}
 
-
 	do {
 		/* Lock MCP using an unload request */
 		fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0);
@@ -10401,10 +10551,10 @@
 
 static void bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
 {
-	mac_hi = cpu_to_be16(mac_hi);
-	mac_lo = cpu_to_be32(mac_lo);
-	memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
-	memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+	__be16 mac_hi_be = cpu_to_be16(mac_hi);
+	__be32 mac_lo_be = cpu_to_be32(mac_lo);
+	memcpy(mac_buf, &mac_hi_be, sizeof(mac_hi_be));
+	memcpy(mac_buf + sizeof(mac_hi_be), &mac_lo_be, sizeof(mac_lo_be));
 }
 
 static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
@@ -10440,6 +10590,13 @@
 	bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
 		   (config & PORT_FEATURE_WOL_ENABLED));
 
+	if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+	    PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE && !IS_MF(bp))
+		bp->flags |= NO_ISCSI_FLAG;
+	if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+	    PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI && !(IS_MF(bp)))
+		bp->flags |= NO_FCOE_FLAG;
+
 	BNX2X_DEV_INFO("lane_config 0x%08x  speed_cap_mask0 0x%08x  link_config0 0x%08x\n",
 		       bp->link_params.lane_config,
 		       bp->link_params.speed_cap_mask[0],
@@ -10547,21 +10704,21 @@
 		/* Port info */
 		bp->cnic_eth_dev.fcoe_wwn_port_name_hi =
 			SHMEM_RD(bp,
-				dev_info.port_hw_config[port].
+				 dev_info.port_hw_config[port].
 				 fcoe_wwn_port_name_upper);
 		bp->cnic_eth_dev.fcoe_wwn_port_name_lo =
 			SHMEM_RD(bp,
-				dev_info.port_hw_config[port].
+				 dev_info.port_hw_config[port].
 				 fcoe_wwn_port_name_lower);
 
 		/* Node info */
 		bp->cnic_eth_dev.fcoe_wwn_node_name_hi =
 			SHMEM_RD(bp,
-				dev_info.port_hw_config[port].
+				 dev_info.port_hw_config[port].
 				 fcoe_wwn_node_name_upper);
 		bp->cnic_eth_dev.fcoe_wwn_node_name_lo =
 			SHMEM_RD(bp,
-				dev_info.port_hw_config[port].
+				 dev_info.port_hw_config[port].
 				 fcoe_wwn_node_name_lower);
 	} else if (!IS_MF_SD(bp)) {
 		/*
@@ -10659,7 +10816,7 @@
 			/* Zero primary MAC configuration */
 			memset(bp->dev->dev_addr, 0, ETH_ALEN);
 
-		if (IS_MF_FCOE_AFEX(bp))
+		if (IS_MF_FCOE_AFEX(bp) || IS_MF_FCOE_SD(bp))
 			/* use FIP MAC as primary MAC */
 			memcpy(bp->dev->dev_addr, fip_mac, ETH_ALEN);
 
@@ -10722,7 +10879,6 @@
 	}
 
 	memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
-	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
 
 	if (!bnx2x_is_valid_ether_addr(bp, bp->dev->dev_addr))
 		dev_err(&bp->pdev->dev,
@@ -10787,7 +10943,7 @@
 
 			while (tout && REG_RD(bp, IGU_REG_RESET_MEMORIES)) {
 				tout--;
-				usleep_range(1000, 1000);
+				usleep_range(1000, 2000);
 			}
 
 			if (REG_RD(bp, IGU_REG_RESET_MEMORIES)) {
@@ -11125,9 +11281,13 @@
 	INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
 	INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
 	INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
-	rc = bnx2x_get_hwinfo(bp);
-	if (rc)
-		return rc;
+	if (IS_PF(bp)) {
+		rc = bnx2x_get_hwinfo(bp);
+		if (rc)
+			return rc;
+	} else {
+		random_ether_addr(bp->dev->dev_addr);
+	}
 
 	bnx2x_set_modes_bitmap(bp);
 
@@ -11140,7 +11300,7 @@
 	func = BP_FUNC(bp);
 
 	/* need to reset chip if undi was active */
-	if (!BP_NOMCP(bp)) {
+	if (IS_PF(bp) && !BP_NOMCP(bp)) {
 		/* init fw_seq */
 		bp->fw_seq =
 			SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
@@ -11177,6 +11337,8 @@
 	bp->mrrs = mrrs;
 
 	bp->tx_ring_size = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL;
+	if (IS_VF(bp))
+		bp->rx_ring_size = MAX_RX_AVAIL;
 
 	/* make sure that the numbers are in the right granularity */
 	bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
@@ -11205,12 +11367,18 @@
 		bp->cnic_base_cl_id = FP_SB_MAX_E2;
 
 	/* multiple tx priority */
-	if (CHIP_IS_E1x(bp))
+	if (IS_VF(bp))
+		bp->max_cos = 1;
+	else if (CHIP_IS_E1x(bp))
 		bp->max_cos = BNX2X_MULTI_TX_COS_E1X;
-	if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
+	else if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
 		bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0;
-	if (CHIP_IS_E3B0(bp))
+	else if (CHIP_IS_E3B0(bp))
 		bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
+	else
+		BNX2X_ERR("unknown chip %x revision %x\n",
+			  CHIP_NUM(bp), CHIP_REV(bp));
+	BNX2X_DEV_INFO("set bp->max_cos to %d\n", bp->max_cos);
 
 	/* We need at least one default status block for slow-path events,
 	 * second status block for the L2 queue, and a third status block for
@@ -11234,6 +11402,26 @@
  * net_device service functions
  */
 
+static int bnx2x_open_epilog(struct bnx2x *bp)
+{
+	/* Enable sriov via delayed work. This must be done via delayed work
+	 * because it causes the probe of the vf devices to be run, which invoke
+	 * register_netdevice which must have rtnl lock taken. As we are holding
+	 * the lock right now, that could only work if the probe would not take
+	 * the lock. However, as the probe of the vf may be called from other
+	 * contexts as well (such as passthrough to vm failes) it can't assume
+	 * the lock is being held for it. Using delayed work here allows the
+	 * probe code to simply take the lock (i.e. wait for it to be released
+	 * if it is being held).
+	 */
+	smp_mb__before_clear_bit();
+	set_bit(BNX2X_SP_RTNL_ENABLE_SRIOV, &bp->sp_rtnl_state);
+	smp_mb__after_clear_bit();
+	schedule_delayed_work(&bp->sp_rtnl_task, 0);
+
+	return 0;
+}
+
 /* called with rtnl_lock */
 static int bnx2x_open(struct net_device *dev)
 {
@@ -11241,6 +11429,7 @@
 	bool global = false;
 	int other_engine = BP_PATH(bp) ? 0 : 1;
 	bool other_load_status, load_status;
+	int rc;
 
 	bp->stats_init = true;
 
@@ -11248,53 +11437,57 @@
 
 	bnx2x_set_power_state(bp, PCI_D0);
 
-	other_load_status = bnx2x_get_load_status(bp, other_engine);
-	load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
-
-	/*
-	 * If parity had happen during the unload, then attentions
+	/* If parity had happen during the unload, then attentions
 	 * and/or RECOVERY_IN_PROGRES may still be set. In this case we
 	 * want the first function loaded on the current engine to
 	 * complete the recovery.
+	 * Parity recovery is only relevant for PF driver.
 	 */
-	if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
-	    bnx2x_chk_parity_attn(bp, &global, true))
-		do {
-			/*
-			 * If there are attentions and they are in a global
-			 * blocks, set the GLOBAL_RESET bit regardless whether
-			 * it will be this function that will complete the
-			 * recovery or not.
-			 */
-			if (global)
-				bnx2x_set_reset_global(bp);
+	if (IS_PF(bp)) {
+		other_load_status = bnx2x_get_load_status(bp, other_engine);
+		load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
+		if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
+		    bnx2x_chk_parity_attn(bp, &global, true)) {
+			do {
+				/* If there are attentions and they are in a
+				 * global blocks, set the GLOBAL_RESET bit
+				 * regardless whether it will be this function
+				 * that will complete the recovery or not.
+				 */
+				if (global)
+					bnx2x_set_reset_global(bp);
 
-			/*
-			 * Only the first function on the current engine should
-			 * try to recover in open. In case of attentions in
-			 * global blocks only the first in the chip should try
-			 * to recover.
-			 */
-			if ((!load_status &&
-			     (!global || !other_load_status)) &&
-			    bnx2x_trylock_leader_lock(bp) &&
-			    !bnx2x_leader_reset(bp)) {
-				netdev_info(bp->dev, "Recovered in open\n");
-				break;
-			}
+				/* Only the first function on the current
+				 * engine should try to recover in open. In case
+				 * of attentions in global blocks only the first
+				 * in the chip should try to recover.
+				 */
+				if ((!load_status &&
+				     (!global || !other_load_status)) &&
+				      bnx2x_trylock_leader_lock(bp) &&
+				      !bnx2x_leader_reset(bp)) {
+					netdev_info(bp->dev,
+						    "Recovered in open\n");
+					break;
+				}
 
-			/* recovery has failed... */
-			bnx2x_set_power_state(bp, PCI_D3hot);
-			bp->recovery_state = BNX2X_RECOVERY_FAILED;
+				/* recovery has failed... */
+				bnx2x_set_power_state(bp, PCI_D3hot);
+				bp->recovery_state = BNX2X_RECOVERY_FAILED;
 
-			BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
-				  "If you still see this message after a few retries then power cycle is required.\n");
+				BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
+					  "If you still see this message after a few retries then power cycle is required.\n");
 
-			return -EAGAIN;
-		} while (0);
+				return -EAGAIN;
+			} while (0);
+		}
+	}
 
 	bp->recovery_state = BNX2X_RECOVERY_DONE;
-	return bnx2x_nic_load(bp, LOAD_OPEN);
+	rc = bnx2x_nic_load(bp, LOAD_OPEN);
+	if (rc)
+		return rc;
+	return bnx2x_open_epilog(bp);
 }
 
 /* called with rtnl_lock */
@@ -11428,7 +11621,6 @@
 	return rc;
 }
 
-
 /* If bp->state is OPEN, should be called with netif_addr_lock_bh() */
 void bnx2x_set_rx_mode(struct net_device *dev)
 {
@@ -11449,12 +11641,25 @@
 		  CHIP_IS_E1(bp)))
 		rx_mode = BNX2X_RX_MODE_ALLMULTI;
 	else {
-		/* some multicasts */
-		if (bnx2x_set_mc_list(bp) < 0)
-			rx_mode = BNX2X_RX_MODE_ALLMULTI;
+		if (IS_PF(bp)) {
+			/* some multicasts */
+			if (bnx2x_set_mc_list(bp) < 0)
+				rx_mode = BNX2X_RX_MODE_ALLMULTI;
 
-		if (bnx2x_set_uc_list(bp) < 0)
-			rx_mode = BNX2X_RX_MODE_PROMISC;
+			if (bnx2x_set_uc_list(bp) < 0)
+				rx_mode = BNX2X_RX_MODE_PROMISC;
+		} else {
+			/* configuring mcast to a vf involves sleeping (when we
+			 * wait for the pf's response). Since this function is
+			 * called from non sleepable context we must schedule
+			 * a work item for this purpose
+			 */
+			smp_mb__before_clear_bit();
+			set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
+				&bp->sp_rtnl_state);
+			smp_mb__after_clear_bit();
+			schedule_delayed_work(&bp->sp_rtnl_task, 0);
+		}
 	}
 
 	bp->rx_mode = rx_mode;
@@ -11468,7 +11673,20 @@
 		return;
 	}
 
-	bnx2x_set_storm_rx_mode(bp);
+	if (IS_PF(bp)) {
+		bnx2x_set_storm_rx_mode(bp);
+	} else {
+		/* configuring rx mode to storms in a vf involves sleeping (when
+		 * we wait for the pf's response). Since this function is
+		 * called from non sleepable context we must schedule
+		 * a work item for this purpose
+		 */
+		smp_mb__before_clear_bit();
+		set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+			&bp->sp_rtnl_state);
+		smp_mb__after_clear_bit();
+		schedule_delayed_work(&bp->sp_rtnl_task, 0);
+	}
 }
 
 /* called with rtnl_lock */
@@ -11571,7 +11789,9 @@
 	.ndo_poll_controller	= poll_bnx2x,
 #endif
 	.ndo_setup_tc		= bnx2x_setup_tc,
-
+#ifdef CONFIG_BNX2X_SRIOV
+	.ndo_set_vf_mac		= bnx2x_set_vf_mac,
+#endif
 #ifdef NETDEV_FCOE_WWNN
 	.ndo_fcoe_get_wwn	= bnx2x_fcoe_get_wwn,
 #endif
@@ -11595,10 +11815,9 @@
 	return 0;
 }
 
-static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
-			  unsigned long board_type)
+static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
+			  struct net_device *dev, unsigned long board_type)
 {
-	struct bnx2x *bp;
 	int rc;
 	u32 pci_cfg_dword;
 	bool chip_is_e1x = (board_type == BCM57710 ||
@@ -11606,11 +11825,9 @@
 			    board_type == BCM57711E);
 
 	SET_NETDEV_DEV(dev, &pdev->dev);
-	bp = netdev_priv(dev);
 
 	bp->dev = dev;
 	bp->pdev = pdev;
-	bp->flags = 0;
 
 	rc = pci_enable_device(pdev);
 	if (rc) {
@@ -11626,9 +11843,8 @@
 		goto err_out_disable;
 	}
 
-	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-		dev_err(&bp->pdev->dev, "Cannot find second PCI device"
-		       " base address, aborting\n");
+	if (IS_PF(bp) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+		dev_err(&bp->pdev->dev, "Cannot find second PCI device base address, aborting\n");
 		rc = -ENODEV;
 		goto err_out_disable;
 	}
@@ -11653,12 +11869,14 @@
 		pci_save_state(pdev);
 	}
 
-	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (bp->pm_cap == 0) {
-		dev_err(&bp->pdev->dev,
-			"Cannot find power management capability, aborting\n");
-		rc = -EIO;
-		goto err_out_release;
+	if (IS_PF(bp)) {
+		bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+		if (bp->pm_cap == 0) {
+			dev_err(&bp->pdev->dev,
+				"Cannot find power management capability, aborting\n");
+			rc = -EIO;
+			goto err_out_release;
+		}
 	}
 
 	if (!pci_is_pcie(pdev)) {
@@ -11690,13 +11908,14 @@
 	 * support Physical Device Assignment where kernel BDF maybe arbitrary
 	 * (depending on hypervisor).
 	 */
-	if (chip_is_e1x)
+	if (chip_is_e1x) {
 		bp->pf_num = PCI_FUNC(pdev->devfn);
-	else {/* chip is E2/3*/
+	} else {
+		/* chip is E2/3*/
 		pci_read_config_dword(bp->pdev,
 				      PCICFG_ME_REGISTER, &pci_cfg_dword);
 		bp->pf_num = (u8)((pci_cfg_dword & ME_REG_ABS_PF_NUM) >>
-		    ME_REG_ABS_PF_NUM_SHIFT);
+				  ME_REG_ABS_PF_NUM_SHIFT);
 	}
 	BNX2X_DEV_INFO("me reg PF num: %d\n", bp->pf_num);
 
@@ -11709,25 +11928,28 @@
 	 * Clean the following indirect addresses for all functions since it
 	 * is not used by the driver.
 	 */
-	REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
-	REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
-	REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
-	REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+	if (IS_PF(bp)) {
+		REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
+		REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
+		REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
+		REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
 
-	if (chip_is_e1x) {
-		REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
-		REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
-		REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
-		REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+		if (chip_is_e1x) {
+			REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+			REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+			REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+			REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+		}
+
+		/* Enable internal target-read (in case we are probed after PF
+		 * FLR). Must be done prior to any BAR read access. Only for
+		 * 57712 and up
+		 */
+		if (!chip_is_e1x)
+			REG_WR(bp,
+			       PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
 	}
 
-	/*
-	 * Enable internal target-read (in case we are probed after PF FLR).
-	 * Must be done prior to any BAR read access. Only for 57712 and up
-	 */
-	if (!chip_is_e1x)
-		REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
-
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 	dev->netdev_ops = &bnx2x_netdev_ops;
@@ -11778,8 +12000,9 @@
 
 static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed)
 {
-	u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+	u32 val = 0;
 
+	pci_read_config_dword(bp->pdev, PCICFG_LINK_CONTROL, &val);
 	*width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
 
 	/* return value of 1=2.5GHz 2=5GHz */
@@ -11792,7 +12015,7 @@
 	struct bnx2x_fw_file_hdr *fw_hdr;
 	struct bnx2x_fw_file_section *sections;
 	u32 offset, len, num_ops;
-	u16 *ops_offsets;
+	__be16 *ops_offsets;
 	int i;
 	const u8 *fw_ver;
 
@@ -11817,7 +12040,7 @@
 
 	/* Likewise for the init_ops offsets */
 	offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset);
-	ops_offsets = (u16 *)(firmware->data + offset);
+	ops_offsets = (__force __be16 *)(firmware->data + offset);
 	num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op);
 
 	for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
@@ -12044,8 +12267,12 @@
 {
 	int cid_count = BNX2X_L2_MAX_CID(bp);
 
+	if (IS_SRIOV(bp))
+		cid_count += BNX2X_VF_CIDS;
+
 	if (CNIC_SUPPORT(bp))
 		cid_count += CNIC_CID_MAX;
+
 	return roundup(cid_count, QM_CID_ROUND);
 }
 
@@ -12056,10 +12283,10 @@
  *
  */
 static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
-				     int cnic_cnt)
+				     int cnic_cnt, bool is_vf)
 {
-	int pos;
-	u16 control;
+	int pos, index;
+	u16 control = 0;
 
 	pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
 
@@ -12067,31 +12294,89 @@
 	 * If MSI-X is not supported - return number of SBs needed to support
 	 * one fast path queue: one FP queue + SB for CNIC
 	 */
-	if (!pos)
+	if (!pos) {
+		dev_info(&pdev->dev, "no msix capability found\n");
 		return 1 + cnic_cnt;
+	}
+	dev_info(&pdev->dev, "msix capability found\n");
 
 	/*
 	 * The value in the PCI configuration space is the index of the last
 	 * entry, namely one less than the actual size of the table, which is
 	 * exactly what we want to return from this function: number of all SBs
 	 * without the default SB.
+	 * For VFs there is no default SB, then we return (index+1).
 	 */
 	pci_read_config_word(pdev, pos  + PCI_MSI_FLAGS, &control);
-	return control & PCI_MSIX_FLAGS_QSIZE;
+
+	index = control & PCI_MSIX_FLAGS_QSIZE;
+
+	return is_vf ? index + 1 : index;
 }
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *);
+static int set_max_cos_est(int chip_id)
+{
+	switch (chip_id) {
+	case BCM57710:
+	case BCM57711:
+	case BCM57711E:
+		return BNX2X_MULTI_TX_COS_E1X;
+	case BCM57712:
+	case BCM57712_MF:
+	case BCM57712_VF:
+		return BNX2X_MULTI_TX_COS_E2_E3A0;
+	case BCM57800:
+	case BCM57800_MF:
+	case BCM57800_VF:
+	case BCM57810:
+	case BCM57810_MF:
+	case BCM57840_4_10:
+	case BCM57840_2_20:
+	case BCM57840_O:
+	case BCM57840_MFO:
+	case BCM57810_VF:
+	case BCM57840_MF:
+	case BCM57840_VF:
+	case BCM57811:
+	case BCM57811_MF:
+	case BCM57811_VF:
+		return BNX2X_MULTI_TX_COS_E3B0;
+		return 1;
+	default:
+		pr_err("Unknown board_type (%d), aborting\n", chip_id);
+		return -ENODEV;
+	}
+}
 
-static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int set_is_vf(int chip_id)
+{
+	switch (chip_id) {
+	case BCM57712_VF:
+	case BCM57800_VF:
+	case BCM57810_VF:
+	case BCM57840_VF:
+	case BCM57811_VF:
+		return true;
+	default:
+		return false;
+	}
+}
+
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
+
+static int bnx2x_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
 {
 	struct net_device *dev = NULL;
 	struct bnx2x *bp;
 	int pcie_width, pcie_speed;
 	int rc, max_non_def_sbs;
 	int rx_count, tx_count, rss_count, doorbell_size;
+	int max_cos_est;
+	bool is_vf;
 	int cnic_cnt;
-	/*
-	 * An estimated maximum supported CoS number according to the chip
+
+	/* An estimated maximum supported CoS number according to the chip
 	 * version.
 	 * We will try to roughly estimate the maximum number of CoSes this chip
 	 * may support in order to minimize the memory allocated for Tx
@@ -12099,53 +12384,24 @@
 	 * initialization of bp->max_cos based on the chip versions AND chip
 	 * revision in the bnx2x_init_bp().
 	 */
-	u8 max_cos_est = 0;
+	max_cos_est = set_max_cos_est(ent->driver_data);
+	if (max_cos_est < 0)
+		return max_cos_est;
+	is_vf = set_is_vf(ent->driver_data);
+	cnic_cnt = is_vf ? 0 : 1;
 
-	switch (ent->driver_data) {
-	case BCM57710:
-	case BCM57711:
-	case BCM57711E:
-		max_cos_est = BNX2X_MULTI_TX_COS_E1X;
-		break;
-
-	case BCM57712:
-	case BCM57712_MF:
-		max_cos_est = BNX2X_MULTI_TX_COS_E2_E3A0;
-		break;
-
-	case BCM57800:
-	case BCM57800_MF:
-	case BCM57810:
-	case BCM57810_MF:
-	case BCM57840_O:
-	case BCM57840_4_10:
-	case BCM57840_2_20:
-	case BCM57840_MFO:
-	case BCM57840_MF:
-	case BCM57811:
-	case BCM57811_MF:
-		max_cos_est = BNX2X_MULTI_TX_COS_E3B0;
-		break;
-
-	default:
-		pr_err("Unknown board_type (%ld), aborting\n",
-			   ent->driver_data);
-		return -ENODEV;
-	}
-
-	cnic_cnt = 1;
-	max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt);
-
-	WARN_ON(!max_non_def_sbs);
+	max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt, is_vf);
 
 	/* Maximum number of RSS queues: one IGU SB goes to CNIC */
-	rss_count = max_non_def_sbs - cnic_cnt;
+	rss_count = is_vf ? 1 : max_non_def_sbs - cnic_cnt;
+
+	if (rss_count < 1)
+		return -EINVAL;
 
 	/* Maximum number of netdev Rx queues: RSS + FCoE L2 */
 	rx_count = rss_count + cnic_cnt;
 
-	/*
-	 * Maximum number of netdev Tx queues:
+	/* Maximum number of netdev Tx queues:
 	 * Maximum TSS queues * Maximum supported number of CoS  + FCoE L2
 	 */
 	tx_count = rss_count * max_cos_est + cnic_cnt;
@@ -12157,42 +12413,55 @@
 
 	bp = netdev_priv(dev);
 
+	bp->flags = 0;
+	if (is_vf)
+		bp->flags |= IS_VF_FLAG;
+
 	bp->igu_sb_cnt = max_non_def_sbs;
+	bp->igu_base_addr = IS_VF(bp) ? PXP_VF_ADDR_IGU_START : BAR_IGU_INTMEM;
 	bp->msg_enable = debug;
 	bp->cnic_support = cnic_cnt;
 	bp->cnic_probe = bnx2x_cnic_probe;
 
 	pci_set_drvdata(pdev, dev);
 
-	rc = bnx2x_init_dev(pdev, dev, ent->driver_data);
+	rc = bnx2x_init_dev(bp, pdev, dev, ent->driver_data);
 	if (rc < 0) {
 		free_netdev(dev);
 		return rc;
 	}
 
+	BNX2X_DEV_INFO("This is a %s function\n",
+		       IS_PF(bp) ? "physical" : "virtual");
 	BNX2X_DEV_INFO("Cnic support is %s\n", CNIC_SUPPORT(bp) ? "on" : "off");
-	BNX2X_DEV_INFO("max_non_def_sbs %d\n", max_non_def_sbs);
-
+	BNX2X_DEV_INFO("Max num of status blocks %d\n", max_non_def_sbs);
 	BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
-			  tx_count, rx_count);
+		       tx_count, rx_count);
 
 	rc = bnx2x_init_bp(bp);
 	if (rc)
 		goto init_one_exit;
 
-	/*
-	 * Map doorbels here as we need the real value of bp->max_cos which
-	 * is initialized in bnx2x_init_bp().
+	/* Map doorbells here as we need the real value of bp->max_cos which
+	 * is initialized in bnx2x_init_bp() to determine the number of
+	 * l2 connections.
 	 */
-	doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
-	if (doorbell_size > pci_resource_len(pdev, 2)) {
-		dev_err(&bp->pdev->dev,
-			"Cannot map doorbells, bar size too small, aborting\n");
-		rc = -ENOMEM;
-		goto init_one_exit;
+	if (IS_VF(bp)) {
+		bnx2x_vf_map_doorbells(bp);
+		rc = bnx2x_vf_pci_alloc(bp);
+		if (rc)
+			goto init_one_exit;
+	} else {
+		doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
+		if (doorbell_size > pci_resource_len(pdev, 2)) {
+			dev_err(&bp->pdev->dev,
+				"Cannot map doorbells, bar size too small, aborting\n");
+			rc = -ENOMEM;
+			goto init_one_exit;
+		}
+		bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
+						doorbell_size);
 	}
-	bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
-					doorbell_size);
 	if (!bp->doorbells) {
 		dev_err(&bp->pdev->dev,
 			"Cannot map doorbell space, aborting\n");
@@ -12200,8 +12469,25 @@
 		goto init_one_exit;
 	}
 
+	if (IS_VF(bp)) {
+		rc = bnx2x_vfpf_acquire(bp, tx_count, rx_count);
+		if (rc)
+			goto init_one_exit;
+	}
+
+	/* Enable SRIOV if capability found in configuration space.
+	 * Once the generic SR-IOV framework makes it in from the
+	 * pci tree this will be revised, to allow dynamic control
+	 * over the number of VFs. Right now, change the num of vfs
+	 * param below to enable SR-IOV.
+	 */
+	rc = bnx2x_iov_init_one(bp, int_mode, 0/*num vfs*/);
+	if (rc)
+		goto init_one_exit;
+
 	/* calc qm_cid_count */
 	bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
+	BNX2X_DEV_INFO("qm_cid_count %d\n", bp->qm_cid_count);
 
 	/* disable FCOE L2 queue for E1x*/
 	if (CHIP_IS_E1x(bp))
@@ -12223,13 +12509,20 @@
 	/* Configure interrupt mode: try to enable MSI-X/MSI if
 	 * needed.
 	 */
-	bnx2x_set_int_mode(bp);
+	rc = bnx2x_set_int_mode(bp);
+	if (rc) {
+		dev_err(&pdev->dev, "Cannot set interrupts\n");
+		goto init_one_exit;
+	}
+	BNX2X_DEV_INFO("set interrupts successfully\n");
 
+	/* register the net device */
 	rc = register_netdev(dev);
 	if (rc) {
 		dev_err(&pdev->dev, "Cannot register net device\n");
 		goto init_one_exit;
 	}
+	BNX2X_DEV_INFO("device name after netdev register %s\n", dev->name);
 
 
 	if (!NO_FCOE(bp)) {
@@ -12240,6 +12533,8 @@
 	}
 
 	bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
+	BNX2X_DEV_INFO("got pcie width %d and speed %d\n",
+		       pcie_width, pcie_speed);
 
 	BNX2X_DEV_INFO(
 		"%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
@@ -12257,7 +12552,7 @@
 	if (bp->regview)
 		iounmap(bp->regview);
 
-	if (bp->doorbells)
+	if (IS_PF(bp) && bp->doorbells)
 		iounmap(bp->doorbells);
 
 	free_netdev(dev);
@@ -12297,25 +12592,37 @@
 	unregister_netdev(dev);
 
 	/* Power on: we can't let PCI layer write to us while we are in D3 */
-	bnx2x_set_power_state(bp, PCI_D0);
+	if (IS_PF(bp))
+		bnx2x_set_power_state(bp, PCI_D0);
 
 	/* Disable MSI/MSI-X */
 	bnx2x_disable_msi(bp);
 
 	/* Power off */
-	bnx2x_set_power_state(bp, PCI_D3hot);
+	if (IS_PF(bp))
+		bnx2x_set_power_state(bp, PCI_D3hot);
 
 	/* Make sure RESET task is not scheduled before continuing */
 	cancel_delayed_work_sync(&bp->sp_rtnl_task);
 
+	bnx2x_iov_remove_one(bp);
+
+	/* send message via vfpf channel to release the resources of this vf */
+	if (IS_VF(bp))
+		bnx2x_vfpf_release(bp);
+
 	if (bp->regview)
 		iounmap(bp->regview);
 
-	if (bp->doorbells)
-		iounmap(bp->doorbells);
+	/* for vf doorbells are part of the regview and were unmapped along with
+	 * it. FW is only loaded by PF.
+	 */
+	if (IS_PF(bp)) {
+		if (bp->doorbells)
+			iounmap(bp->doorbells);
 
-	bnx2x_release_firmware(bp);
-
+		bnx2x_release_firmware(bp);
+	}
 	bnx2x_free_mem_bp(bp);
 
 	free_netdev(dev);
@@ -13103,4 +13410,36 @@
 	return cp;
 }
 
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
+{
+	struct bnx2x *bp = fp->bp;
+	u32 offset = BAR_USTRORM_INTMEM;
 
+	if (IS_VF(bp))
+		return bnx2x_vf_ustorm_prods_offset(bp, fp);
+	else if (!CHIP_IS_E1x(bp))
+		offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
+	else
+		offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
+
+	return offset;
+}
+
+/* called only on E1H or E2.
+ * When pretending to be PF, the pretend value is the function number 0...7
+ * When pretending to be VF, the pretend val is the PF-num:VF-valid:ABS-VFID
+ * combination
+ */
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
+{
+	u32 pretend_reg;
+
+	if (CHIP_IS_E1H(bp) && pretend_func_val >= E1H_FUNC_MAX)
+		return -1;
+
+	/* get my own pretend register */
+	pretend_reg = bnx2x_get_pretend_reg(bp);
+	REG_WR(bp, pretend_reg, pretend_func_val);
+	REG_RD(bp, pretend_reg);
+	return 0;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
index ddd5106..caf1aef 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
@@ -1,6 +1,6 @@
 /* bnx2x_mfw_req.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012-2013 Broadcom Corporation
  *
  * 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
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index bc2f65b..791eb2d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -1,6 +1,6 @@
 /* bnx2x_reg.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -825,6 +825,7 @@
 /* [RW 28] The value sent to CM header in the case of CFC load error. */
 #define DORQ_REG_ERR_CMHEAD					 0x170058
 #define DORQ_REG_IF_EN						 0x170004
+#define DORQ_REG_MAX_RVFID_SIZE				 0x1701ec
 #define DORQ_REG_MODE_ACT					 0x170008
 /* [RW 5] The normal mode CID extraction offset. */
 #define DORQ_REG_NORM_CID_OFST					 0x17002c
@@ -847,6 +848,22 @@
    writes the same initial credit to the rspa_crd_cnt and rspb_crd_cnt. The
    read reads this written value. */
 #define DORQ_REG_RSP_INIT_CRD					 0x170048
+#define DORQ_REG_RSPB_CRD_CNT					 0x1700b0
+#define DORQ_REG_VF_NORM_CID_BASE				 0x1701a0
+#define DORQ_REG_VF_NORM_CID_OFST				 0x1701f4
+#define DORQ_REG_VF_NORM_CID_WND_SIZE				 0x1701a4
+#define DORQ_REG_VF_NORM_MAX_CID_COUNT				 0x1701e4
+#define DORQ_REG_VF_NORM_VF_BASE				 0x1701a8
+/* [RW 10] VF type validation mask value */
+#define DORQ_REG_VF_TYPE_MASK_0					 0x170218
+/* [RW 17] VF type validation Min MCID value */
+#define DORQ_REG_VF_TYPE_MAX_MCID_0				 0x1702d8
+/* [RW 17] VF type validation Max MCID value */
+#define DORQ_REG_VF_TYPE_MIN_MCID_0				 0x170298
+/* [RW 10] VF type validation comp value */
+#define DORQ_REG_VF_TYPE_VALUE_0				 0x170258
+#define DORQ_REG_VF_USAGE_CT_LIMIT				 0x170340
+
 /* [RW 4] Initial activity counter value on the load request; when the
    shortcut is done. */
 #define DORQ_REG_SHRT_ACT_CNT					 0x170070
@@ -859,6 +876,7 @@
 #define HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0			 (0x1<<2)
 #define HC_CONFIG_0_REG_SINGLE_ISR_EN_0				 (0x1<<1)
 #define HC_CONFIG_1_REG_BLOCK_DISABLE_1				 (0x1<<0)
+#define DORQ_REG_VF_USAGE_CNT					 0x170320
 #define HC_REG_AGG_INT_0					 0x108050
 #define HC_REG_AGG_INT_1					 0x108054
 #define HC_REG_ATTN_BIT 					 0x108120
@@ -2136,6 +2154,8 @@
 /* [R 32] Interrupt register #0 read */
 #define NIG_REG_NIG_INT_STS_0					 0x103b0
 #define NIG_REG_NIG_INT_STS_1					 0x103c0
+/* [RC 32] Interrupt register #0 read clear */
+#define NIG_REG_NIG_INT_STS_CLR_0				 0x103b4
 /* [R 32] Legacy E1 and E1H location for parity error mask register. */
 #define NIG_REG_NIG_PRTY_MASK					 0x103dc
 /* [RW 32] Parity mask register #0 read/write */
@@ -2571,6 +2591,7 @@
    current task in process). */
 #define PBF_REG_DISABLE_NEW_TASK_PROC_P4			 0x14006c
 #define PBF_REG_DISABLE_PF					 0x1402e8
+#define PBF_REG_DISABLE_VF					 0x1402ec
 /* [RW 18] For port 0: For each client that is subject to WFQ (the
  * corresponding bit is 1); indicates to which of the credit registers this
  * client is mapped. For clients which are not credit blocked; their mapping
@@ -3708,6 +3729,10 @@
 #define PXP_REG_HST_DISCARD_INTERNAL_WRITES_STATUS		 0x10309c
 /* [WB 160] Used for initialization of the inbound interrupts memory */
 #define PXP_REG_HST_INBOUND_INT 				 0x103800
+/* [RW 7] Indirect access to the permission table. The fields are : {Valid;
+ * VFID[5:0]}
+ */
+#define PXP_REG_HST_ZONE_PERMISSION_TABLE			 0x103400
 /* [RW 32] Interrupt mask register #0 read/write */
 #define PXP_REG_PXP_INT_MASK_0					 0x103074
 #define PXP_REG_PXP_INT_MASK_1					 0x103084
@@ -5966,6 +5991,7 @@
 #define HW_LOCK_RESOURCE_SPIO					 2
 #define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT			 (0x1<<4)
 #define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR			 (0x1<<5)
+#define AEU_INPUTS_ATTN_BITS_BRB_HW_INTERRUPT			 (0x1<<19)
 #define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR			 (0x1<<18)
 #define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT			 (0x1<<31)
 #define AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR			 (0x1<<30)
@@ -6305,6 +6331,15 @@
 #define PCI_PM_DATA_B					0x414
 #define PCI_ID_VAL1					0x434
 #define PCI_ID_VAL2					0x438
+#define GRC_CONFIG_REG_PF_INIT_VF		0x624
+#define GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK	0xf
+/* First VF_NUM for PF is encoded in this register.
+ * The number of VFs assigned to a PF is assumed to be a multiple of 8.
+ * Software should program these bits based on Total Number of VFs \
+ * programmed for each PF.
+ * Since registers from 0x000-0x7ff are split across functions, each PF will
+ * have the same location for the same 4 bits
+ */
 
 #define PXPCS_TL_CONTROL_5		    0x814
 #define PXPCS_TL_CONTROL_5_UNKNOWNTYPE_ERR_ATTN    (1 << 29) /*WC*/
@@ -6554,6 +6589,27 @@
 	(7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
 
 
+#define PXP_VF_ADDR_IGU_START				0
+#define PXP_VF_ADDR_IGU_SIZE				0x3000
+#define PXP_VF_ADDR_IGU_END\
+	((PXP_VF_ADDR_IGU_START) + (PXP_VF_ADDR_IGU_SIZE) - 1)
+
+#define PXP_VF_ADDR_USDM_QUEUES_START			0x3000
+#define PXP_VF_ADDR_USDM_QUEUES_SIZE\
+	(PXP_VF_ADRR_NUM_QUEUES * PXP_ADDR_QUEUE_SIZE)
+#define PXP_VF_ADDR_USDM_QUEUES_END\
+	((PXP_VF_ADDR_USDM_QUEUES_START) + (PXP_VF_ADDR_USDM_QUEUES_SIZE) - 1)
+
+#define PXP_VF_ADDR_CSDM_GLOBAL_START			0x7600
+#define PXP_VF_ADDR_CSDM_GLOBAL_SIZE			(PXP_ADDR_REG_SIZE)
+#define PXP_VF_ADDR_CSDM_GLOBAL_END\
+	((PXP_VF_ADDR_CSDM_GLOBAL_START) + (PXP_VF_ADDR_CSDM_GLOBAL_SIZE) - 1)
+
+#define PXP_VF_ADDR_DB_START				0x7c00
+#define PXP_VF_ADDR_DB_SIZE				0x200
+#define PXP_VF_ADDR_DB_END\
+	((PXP_VF_ADDR_DB_START) + (PXP_VF_ADDR_DB_SIZE) - 1)
+
 #define MDIO_REG_BANK_CL73_IEEEB0	0x0
 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL	0x0
 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN	0x0200
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 09b625e..7306416 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -1,6 +1,6 @@
 /* bnx2x_sp.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2011-2012 Broadcom Corporation
+ * Copyright (c) 2011-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -325,7 +325,7 @@
 			return 0;
 		}
 
-		usleep_range(1000, 1000);
+		usleep_range(1000, 2000);
 
 		if (bp->panic)
 			return -EIO;
@@ -707,7 +707,8 @@
 static inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type,
 				struct eth_classify_header *hdr, int rule_cnt)
 {
-	hdr->echo = (cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT);
+	hdr->echo = cpu_to_le32((cid & BNX2X_SWCID_MASK) |
+				(type << BNX2X_SWCID_SHIFT));
 	hdr->rule_cnt = (u8)rule_cnt;
 }
 
@@ -813,8 +814,9 @@
 
 	hdr->length = 1;
 	hdr->offset = (u8)cam_offset;
-	hdr->client_id = 0xff;
-	hdr->echo = ((r->cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT));
+	hdr->client_id = cpu_to_le16(0xff);
+	hdr->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+				(type << BNX2X_SWCID_SHIFT));
 }
 
 static inline void bnx2x_vlan_mac_set_cfg_entry_e1x(struct bnx2x *bp,
@@ -903,7 +905,7 @@
 		(struct eth_classify_rules_ramrod_data *)(raw->rdata);
 	int rule_cnt = rule_idx + 1;
 	union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
-	int cmd = elem->cmd_data.vlan_mac.cmd;
+	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
 	bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
 	u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan;
 
@@ -953,7 +955,7 @@
 		(struct eth_classify_rules_ramrod_data *)(raw->rdata);
 	int rule_cnt = rule_idx + 1;
 	union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
-	int cmd = elem->cmd_data.vlan_mac.cmd;
+	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
 	bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
 	u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
 	u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
@@ -1407,7 +1409,7 @@
 
 		/* Wait until there are no pending commands */
 		if (!bnx2x_exe_queue_empty(exeq))
-			usleep_range(1000, 1000);
+			usleep_range(1000, 2000);
 		else
 			return 0;
 	}
@@ -1442,7 +1444,7 @@
 	if (cqe->message.error)
 		return -EINVAL;
 
-	/* Run the next bulk of pending commands if requeted */
+	/* Run the next bulk of pending commands if requested */
 	if (test_bit(RAMROD_CONT, ramrod_flags)) {
 		rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
 		if (rc < 0)
@@ -1532,7 +1534,7 @@
 	bool restore,
 	struct bnx2x_vlan_mac_registry_elem **re)
 {
-	int cmd = elem->cmd_data.vlan_mac.cmd;
+	enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
 	struct bnx2x_vlan_mac_registry_elem *reg_elem;
 
 	/* Allocate a new registry element if needed. */
@@ -1591,7 +1593,7 @@
 	bool restore = test_bit(RAMROD_RESTORE, ramrod_flags);
 	bool drv_only = test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags);
 	struct bnx2x_vlan_mac_registry_elem *reg_elem;
-	int cmd;
+	enum bnx2x_vlan_mac_cmd cmd;
 
 	/*
 	 * If DRIVER_ONLY execution is requested, cleanup a registry
@@ -2103,7 +2105,7 @@
 static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
 				 struct bnx2x_rx_mode_ramrod_params *p)
 {
-	/* update the bp MAC filter structure  */
+	/* update the bp MAC filter structure */
 	u32 mask = (1 << p->cl_id);
 
 	struct tstorm_eth_mac_filter_config *mac_filters =
@@ -2166,7 +2168,7 @@
 		mac_filters->unmatched_unicast & ~mask;
 
 	DP(BNX2X_MSG_SP, "drop_ucast 0x%x\ndrop_mcast 0x%x\n accp_ucast 0x%x\n"
-					 "accp_mcast 0x%x\naccp_bcast 0x%x\n",
+			 "accp_mcast 0x%x\naccp_bcast 0x%x\n",
 	   mac_filters->ucast_drop_all, mac_filters->mcast_drop_all,
 	   mac_filters->ucast_accept_all, mac_filters->mcast_accept_all,
 	   mac_filters->bcast_accept_all);
@@ -2186,12 +2188,12 @@
 				struct eth_classify_header *hdr,
 				u8 rule_cnt)
 {
-	hdr->echo = cid;
+	hdr->echo = cpu_to_le32(cid);
 	hdr->rule_cnt = rule_cnt;
 }
 
 static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
-				unsigned long accept_flags,
+				unsigned long *accept_flags,
 				struct eth_filter_rules_cmd *cmd,
 				bool clear_accept_all)
 {
@@ -2201,33 +2203,33 @@
 	state = ETH_FILTER_RULES_CMD_UCAST_DROP_ALL |
 		ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
 
-	if (accept_flags) {
-		if (test_bit(BNX2X_ACCEPT_UNICAST, &accept_flags))
-			state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+	if (test_bit(BNX2X_ACCEPT_UNICAST, accept_flags))
+		state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
 
-		if (test_bit(BNX2X_ACCEPT_MULTICAST, &accept_flags))
-			state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
+	if (test_bit(BNX2X_ACCEPT_MULTICAST, accept_flags))
+		state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
 
-		if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept_flags)) {
-			state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
-			state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
-		}
-
-		if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept_flags)) {
-			state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
-			state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
-		}
-		if (test_bit(BNX2X_ACCEPT_BROADCAST, &accept_flags))
-			state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
-
-		if (test_bit(BNX2X_ACCEPT_UNMATCHED, &accept_flags)) {
-			state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
-			state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
-		}
-		if (test_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags))
-			state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
+	if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, accept_flags)) {
+		state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+		state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
 	}
 
+	if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, accept_flags)) {
+		state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
+		state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
+	}
+
+	if (test_bit(BNX2X_ACCEPT_BROADCAST, accept_flags))
+		state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
+
+	if (test_bit(BNX2X_ACCEPT_UNMATCHED, accept_flags)) {
+		state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+		state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
+	}
+
+	if (test_bit(BNX2X_ACCEPT_ANY_VLAN, accept_flags))
+		state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
+
 	/* Clear ACCEPT_ALL_XXX flags for FCoE L2 Queue */
 	if (clear_accept_all) {
 		state &= ~ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
@@ -2260,8 +2262,9 @@
 		data->rules[rule_idx].cmd_general_data =
 			ETH_FILTER_RULES_CMD_TX_CMD;
 
-		bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags,
-			&(data->rules[rule_idx++]), false);
+		bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
+					       &(data->rules[rule_idx++]),
+					       false);
 	}
 
 	/* Rx */
@@ -2272,8 +2275,9 @@
 		data->rules[rule_idx].cmd_general_data =
 			ETH_FILTER_RULES_CMD_RX_CMD;
 
-		bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags,
-			&(data->rules[rule_idx++]), false);
+		bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
+					       &(data->rules[rule_idx++]),
+					       false);
 	}
 
 
@@ -2293,9 +2297,10 @@
 			data->rules[rule_idx].cmd_general_data =
 						ETH_FILTER_RULES_CMD_TX_CMD;
 
-			bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags,
-						     &(data->rules[rule_idx++]),
+			bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
+						       &(data->rules[rule_idx]),
 						       true);
+			rule_idx++;
 		}
 
 		/* Rx */
@@ -2306,9 +2311,10 @@
 			data->rules[rule_idx].cmd_general_data =
 						ETH_FILTER_RULES_CMD_RX_CMD;
 
-			bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags,
-						     &(data->rules[rule_idx++]),
+			bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
+						       &(data->rules[rule_idx]),
 						       true);
+			rule_idx++;
 		}
 	}
 
@@ -2429,7 +2435,7 @@
 static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
 				   struct bnx2x_mcast_obj *o,
 				   struct bnx2x_mcast_ramrod_params *p,
-				   int cmd)
+				   enum bnx2x_mcast_cmd cmd)
 {
 	int total_sz;
 	struct bnx2x_pending_mcast_cmd *new_cmd;
@@ -2561,7 +2567,7 @@
 static void bnx2x_mcast_set_one_rule_e2(struct bnx2x *bp,
 					struct bnx2x_mcast_obj *o, int idx,
 					union bnx2x_mcast_config_data *cfg_data,
-					int cmd)
+					enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_raw_obj *r = &o->raw;
 	struct eth_multicast_rules_ramrod_data *data =
@@ -2625,7 +2631,7 @@
 	int *rdata_idx)
 {
 	int cur_bin, cnt = *rdata_idx;
-	union bnx2x_mcast_config_data cfg_data = {0};
+	union bnx2x_mcast_config_data cfg_data = {NULL};
 
 	/* go through the registry and configure the bins from it */
 	for (cur_bin = bnx2x_mcast_get_next_bin(o, start_bin); cur_bin >= 0;
@@ -2657,7 +2663,7 @@
 {
 	struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n;
 	int cnt = *line_idx;
-	union bnx2x_mcast_config_data cfg_data = {0};
+	union bnx2x_mcast_config_data cfg_data = {NULL};
 
 	list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head,
 				 link) {
@@ -2780,7 +2786,7 @@
 	int *line_idx)
 {
 	struct bnx2x_mcast_list_elem *mlist_pos;
-	union bnx2x_mcast_config_data cfg_data = {0};
+	union bnx2x_mcast_config_data cfg_data = {NULL};
 	int cnt = *line_idx;
 
 	list_for_each_entry(mlist_pos, &p->mcast_list, link) {
@@ -2790,7 +2796,7 @@
 		cnt++;
 
 		DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
-				 mlist_pos->mac);
+		   mlist_pos->mac);
 	}
 
 	*line_idx = cnt;
@@ -2827,7 +2833,8 @@
  * Returns number of lines filled in the ramrod data in total.
  */
 static inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp,
-			struct bnx2x_mcast_ramrod_params *p, int cmd,
+			struct bnx2x_mcast_ramrod_params *p,
+			enum bnx2x_mcast_cmd cmd,
 			int start_cnt)
 {
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -2861,7 +2868,7 @@
 
 static int bnx2x_mcast_validate_e2(struct bnx2x *bp,
 				   struct bnx2x_mcast_ramrod_params *p,
-				   int cmd)
+				   enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
 	int reg_sz = o->get_registry_size(o);
@@ -2930,8 +2937,9 @@
 	struct eth_multicast_rules_ramrod_data *data =
 		(struct eth_multicast_rules_ramrod_data *)(r->rdata);
 
-	data->header.echo = ((r->cid & BNX2X_SWCID_MASK) |
-			  (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT));
+	data->header.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+					(BNX2X_FILTER_MCAST_PENDING <<
+					 BNX2X_SWCID_SHIFT));
 	data->header.rule_cnt = len;
 }
 
@@ -2965,7 +2973,7 @@
 
 static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
 				struct bnx2x_mcast_ramrod_params *p,
-				int cmd)
+				enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_raw_obj *raw = &p->mcast_obj->raw;
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -3051,7 +3059,7 @@
 
 static int bnx2x_mcast_validate_e1h(struct bnx2x *bp,
 				    struct bnx2x_mcast_ramrod_params *p,
-				    int cmd)
+				    enum bnx2x_mcast_cmd cmd)
 {
 	/* Mark, that there is a work to do */
 	if ((cmd == BNX2X_MCAST_CMD_DEL) || (cmd == BNX2X_MCAST_CMD_RESTORE))
@@ -3085,7 +3093,7 @@
 		BNX2X_57711_SET_MC_FILTER(mc_filter, bit);
 
 		DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC, bin %d\n",
-				 mlist_pos->mac, bit);
+		   mlist_pos->mac, bit);
 
 		/* bookkeeping... */
 		BIT_VEC64_SET_BIT(o->registry.aprox_match.vec,
@@ -3113,7 +3121,7 @@
  */
 static int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
 				 struct bnx2x_mcast_ramrod_params *p,
-				 int cmd)
+				 enum bnx2x_mcast_cmd cmd)
 {
 	int i;
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -3167,7 +3175,7 @@
 
 static int bnx2x_mcast_validate_e1(struct bnx2x *bp,
 				   struct bnx2x_mcast_ramrod_params *p,
-				   int cmd)
+				   enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
 	int reg_sz = o->get_registry_size(o);
@@ -3240,7 +3248,7 @@
 static void bnx2x_mcast_set_one_rule_e1(struct bnx2x *bp,
 					struct bnx2x_mcast_obj *o, int idx,
 					union bnx2x_mcast_config_data *cfg_data,
-					int cmd)
+					enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_raw_obj *r = &o->raw;
 	struct mac_configuration_cmd *data =
@@ -3284,9 +3292,10 @@
 		     BNX2X_MAX_MULTICAST*(1 + r->func_id));
 
 	data->hdr.offset = offset;
-	data->hdr.client_id = 0xff;
-	data->hdr.echo = ((r->cid & BNX2X_SWCID_MASK) |
-			  (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT));
+	data->hdr.client_id = cpu_to_le16(0xff);
+	data->hdr.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+				     (BNX2X_FILTER_MCAST_PENDING <<
+				      BNX2X_SWCID_SHIFT));
 	data->hdr.length = len;
 }
 
@@ -3309,7 +3318,7 @@
 {
 	struct bnx2x_mcast_mac_elem *elem;
 	int i = 0;
-	union bnx2x_mcast_config_data cfg_data = {0};
+	union bnx2x_mcast_config_data cfg_data = {NULL};
 
 	/* go through the registry and configure the MACs from it. */
 	list_for_each_entry(elem, &o->registry.exact_match.macs, link) {
@@ -3319,7 +3328,7 @@
 		i++;
 
 		  DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
-				   cfg_data.mac);
+		     cfg_data.mac);
 	}
 
 	*rdata_idx = i;
@@ -3334,7 +3343,7 @@
 	struct bnx2x_pending_mcast_cmd *cmd_pos;
 	struct bnx2x_mcast_mac_elem *pmac_pos;
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
-	union bnx2x_mcast_config_data cfg_data = {0};
+	union bnx2x_mcast_config_data cfg_data = {NULL};
 	int cnt = 0;
 
 
@@ -3355,7 +3364,7 @@
 			cnt++;
 
 			DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
-					 pmac_pos->mac);
+			   pmac_pos->mac);
 		}
 		break;
 
@@ -3458,7 +3467,7 @@
 
 static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
 				struct bnx2x_mcast_ramrod_params *p,
-				int cmd)
+				enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
 	struct bnx2x_raw_obj *raw = &o->raw;
@@ -3562,7 +3571,7 @@
 
 int bnx2x_config_mcast(struct bnx2x *bp,
 		       struct bnx2x_mcast_ramrod_params *p,
-		       int cmd)
+		       enum bnx2x_mcast_cmd cmd)
 {
 	struct bnx2x_mcast_obj *o = p->mcast_obj;
 	struct bnx2x_raw_obj *r = &o->raw;
@@ -4085,8 +4094,8 @@
 	DP(BNX2X_MSG_SP, "Configuring RSS\n");
 
 	/* Set an echo field */
-	data->echo = (r->cid & BNX2X_SWCID_MASK) |
-		     (r->state << BNX2X_SWCID_SHIFT);
+	data->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+				 (r->state << BNX2X_SWCID_SHIFT));
 
 	/* RSS mode */
 	if (test_bit(BNX2X_RSS_MODE_DISABLED, &p->rss_flags))
@@ -4237,11 +4246,16 @@
 	unsigned long *pending = &o->pending;
 
 	/* Check that the requested transition is legal */
-	if (o->check_transition(bp, o, params))
+	rc = o->check_transition(bp, o, params);
+	if (rc) {
+		BNX2X_ERR("check transition returned an error. rc %d\n", rc);
 		return -EINVAL;
+	}
 
 	/* Set "pending" bit */
+	DP(BNX2X_MSG_SP, "pending bit was=%lx\n", o->pending);
 	pending_bit = o->set_pending(o, params);
+	DP(BNX2X_MSG_SP, "pending bit now=%lx\n", o->pending);
 
 	/* Don't send a command if only driver cleanup was requested */
 	if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags))
@@ -5025,8 +5039,11 @@
 	 * Don't allow a next state transition if we are in the middle of
 	 * the previous one.
 	 */
-	if (o->pending)
+	if (o->pending) {
+		BNX2X_ERR("Blocking transition since pending was %lx\n",
+			  o->pending);
 		return -EBUSY;
+	}
 
 	switch (state) {
 	case BNX2X_Q_STATE_RESET:
@@ -5199,6 +5216,27 @@
 	obj->set_pending = bnx2x_queue_set_pending;
 }
 
+/* return a queue object's logical state*/
+int bnx2x_get_q_logical_state(struct bnx2x *bp,
+			       struct bnx2x_queue_sp_obj *obj)
+{
+	switch (obj->state) {
+	case BNX2X_Q_STATE_ACTIVE:
+	case BNX2X_Q_STATE_MULTI_COS:
+		return BNX2X_Q_LOGICAL_STATE_ACTIVE;
+	case BNX2X_Q_STATE_RESET:
+	case BNX2X_Q_STATE_INITIALIZED:
+	case BNX2X_Q_STATE_MCOS_TERMINATED:
+	case BNX2X_Q_STATE_INACTIVE:
+	case BNX2X_Q_STATE_STOPPED:
+	case BNX2X_Q_STATE_TERMINATED:
+	case BNX2X_Q_STATE_FLRED:
+		return BNX2X_Q_LOGICAL_STATE_STOPPED;
+	default:
+		return -EINVAL;
+	}
+}
+
 /********************** Function state object *********************************/
 enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
 					   struct bnx2x_func_sp_obj *o)
@@ -5631,9 +5669,9 @@
 	memset(rdata, 0, sizeof(*rdata));
 
 	/* Fill the ramrod data with provided parameters */
-	rdata->function_mode = (u8)start_params->mf_mode;
-	rdata->sd_vlan_tag   = cpu_to_le16(start_params->sd_vlan_tag);
-	rdata->path_id       = BP_PATH(bp);
+	rdata->function_mode    = (u8)start_params->mf_mode;
+	rdata->sd_vlan_tag      = cpu_to_le16(start_params->sd_vlan_tag);
+	rdata->path_id          = BP_PATH(bp);
 	rdata->network_cos_mode = start_params->network_cos_mode;
 
 	/*
@@ -5716,21 +5754,20 @@
 	struct bnx2x_func_sp_obj *o = params->f_obj;
 	struct afex_vif_list_ramrod_data *rdata =
 		(struct afex_vif_list_ramrod_data *)o->afex_rdata;
-	struct bnx2x_func_afex_viflists_params *afex_viflist_params =
+	struct bnx2x_func_afex_viflists_params *afex_vif_params =
 		&params->params.afex_viflists;
 	u64 *p_rdata = (u64 *)rdata;
 
 	memset(rdata, 0, sizeof(*rdata));
 
 	/* Fill the ramrod data with provided parameters */
-	rdata->vif_list_index = afex_viflist_params->vif_list_index;
-	rdata->func_bit_map = afex_viflist_params->func_bit_map;
-	rdata->afex_vif_list_command =
-		afex_viflist_params->afex_vif_list_command;
-	rdata->func_to_clear = afex_viflist_params->func_to_clear;
+	rdata->vif_list_index = cpu_to_le16(afex_vif_params->vif_list_index);
+	rdata->func_bit_map          = afex_vif_params->func_bit_map;
+	rdata->afex_vif_list_command = afex_vif_params->afex_vif_list_command;
+	rdata->func_to_clear         = afex_vif_params->func_to_clear;
 
 	/* send in echo type of sub command */
-	rdata->echo = afex_viflist_params->afex_vif_list_command;
+	rdata->echo = afex_vif_params->afex_vif_list_command;
 
 	/*  No need for an explicit memory barrier here as long we would
 	 *  need to ensure the ordering of writing to the SPQ element
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index adbd91b..ff90760 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -1,6 +1,6 @@
 /* bnx2x_sp.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2011-2012 Broadcom Corporation
+ * Copyright (c) 2011-2013 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
@@ -54,7 +54,7 @@
 	BNX2X_OBJ_TYPE_RX_TX,
 } bnx2x_obj_type;
 
-/* Filtering states */
+/* Public slow path states */
 enum {
 	BNX2X_FILTER_MAC_PENDING,
 	BNX2X_FILTER_VLAN_PENDING,
@@ -524,7 +524,7 @@
 	int mcast_list_len;
 };
 
-enum {
+enum bnx2x_mcast_cmd {
 	BNX2X_MCAST_CMD_ADD,
 	BNX2X_MCAST_CMD_CONT,
 	BNX2X_MCAST_CMD_DEL,
@@ -573,7 +573,8 @@
 	 * @param cmd command to execute (BNX2X_MCAST_CMD_X, see above)
 	 */
 	int (*config_mcast)(struct bnx2x *bp,
-				struct bnx2x_mcast_ramrod_params *p, int cmd);
+			    struct bnx2x_mcast_ramrod_params *p,
+			    enum bnx2x_mcast_cmd cmd);
 
 	/**
 	 * Fills the ramrod data during the RESTORE flow.
@@ -590,11 +591,13 @@
 			   int start_bin, int *rdata_idx);
 
 	int (*enqueue_cmd)(struct bnx2x *bp, struct bnx2x_mcast_obj *o,
-			   struct bnx2x_mcast_ramrod_params *p, int cmd);
+			   struct bnx2x_mcast_ramrod_params *p,
+			   enum bnx2x_mcast_cmd cmd);
 
 	void (*set_one_rule)(struct bnx2x *bp,
 			     struct bnx2x_mcast_obj *o, int idx,
-			     union bnx2x_mcast_config_data *cfg_data, int cmd);
+			     union bnx2x_mcast_config_data *cfg_data,
+			     enum bnx2x_mcast_cmd cmd);
 
 	/** Checks if there are more mcast MACs to be set or a previous
 	 *  command is still pending.
@@ -617,7 +620,8 @@
 	 * feasible.
 	 */
 	int (*validate)(struct bnx2x *bp,
-			struct bnx2x_mcast_ramrod_params *p, int cmd);
+			struct bnx2x_mcast_ramrod_params *p,
+			enum bnx2x_mcast_cmd cmd);
 
 	/**
 	 * Restore the values of internal counters in case of a failure.
@@ -776,6 +780,12 @@
 	BNX2X_Q_STATE_MAX,
 };
 
+/* Allowed Queue states */
+enum bnx2x_q_logical_state {
+	BNX2X_Q_LOGICAL_STATE_ACTIVE,
+	BNX2X_Q_LOGICAL_STATE_STOPPED,
+};
+
 /* Allowed commands */
 enum bnx2x_queue_cmd {
 	BNX2X_Q_CMD_INIT,
@@ -1261,6 +1271,9 @@
 int bnx2x_queue_state_change(struct bnx2x *bp,
 			     struct bnx2x_queue_state_params *params);
 
+int bnx2x_get_q_logical_state(struct bnx2x *bp,
+			       struct bnx2x_queue_sp_obj *obj);
+
 /********************* VLAN-MAC ****************/
 void bnx2x_init_mac_obj(struct bnx2x *bp,
 			struct bnx2x_vlan_mac_obj *mac_obj,
@@ -1338,7 +1351,8 @@
  *         completions.
  */
 int bnx2x_config_mcast(struct bnx2x *bp,
-		       struct bnx2x_mcast_ramrod_params *p, int cmd);
+		       struct bnx2x_mcast_ramrod_params *p,
+		       enum bnx2x_mcast_cmd cmd);
 
 /****************** CREDIT POOL ****************/
 void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
new file mode 100644
index 0000000..6adfa20
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -0,0 +1,3198 @@
+/* bnx2x_sriov.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ *	       Ariel Elior <ariele@broadcom.com>
+ *
+ */
+#include "bnx2x.h"
+#include "bnx2x_init.h"
+#include "bnx2x_cmn.h"
+#include <linux/crc32.h>
+
+/* General service functions */
+static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
+					 u16 pf_id)
+{
+	REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
+		pf_id);
+	REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
+		pf_id);
+	REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
+		pf_id);
+	REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
+		pf_id);
+}
+
+static void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
+					u8 enable)
+{
+	REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
+		enable);
+	REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
+		enable);
+	REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
+		enable);
+	REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
+		enable);
+}
+
+int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
+{
+	int idx;
+
+	for_each_vf(bp, idx)
+		if (bnx2x_vf(bp, idx, abs_vfid) == abs_vfid)
+			break;
+	return idx;
+}
+
+static
+struct bnx2x_virtf *bnx2x_vf_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
+{
+	u16 idx =  (u16)bnx2x_vf_idx_by_abs_fid(bp, abs_vfid);
+	return (idx < BNX2X_NR_VIRTFN(bp)) ? BP_VF(bp, idx) : NULL;
+}
+
+static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				u8 igu_sb_id, u8 segment, u16 index, u8 op,
+				u8 update)
+{
+	/* acking a VF sb through the PF - use the GRC */
+	u32 ctl;
+	u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
+	u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
+	u32 func_encode = vf->abs_vfid;
+	u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + igu_sb_id;
+	struct igu_regular cmd_data = {0};
+
+	cmd_data.sb_id_and_flags =
+			((index << IGU_REGULAR_SB_INDEX_SHIFT) |
+			 (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) |
+			 (update << IGU_REGULAR_BUPDATE_SHIFT) |
+			 (op << IGU_REGULAR_ENABLE_INT_SHIFT));
+
+	ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT		|
+	      func_encode << IGU_CTRL_REG_FID_SHIFT		|
+	      IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT;
+
+	DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+	   cmd_data.sb_id_and_flags, igu_addr_data);
+	REG_WR(bp, igu_addr_data, cmd_data.sb_id_and_flags);
+	mmiowb();
+	barrier();
+
+	DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+	   ctl, igu_addr_ctl);
+	REG_WR(bp, igu_addr_ctl, ctl);
+	mmiowb();
+	barrier();
+}
+/* VFOP - VF slow-path operation support */
+
+#define BNX2X_VFOP_FILTER_ADD_CNT_MAX		0x10000
+
+/* VFOP operations states */
+enum bnx2x_vfop_qctor_state {
+	   BNX2X_VFOP_QCTOR_INIT,
+	   BNX2X_VFOP_QCTOR_SETUP,
+	   BNX2X_VFOP_QCTOR_INT_EN
+};
+
+enum bnx2x_vfop_qdtor_state {
+	   BNX2X_VFOP_QDTOR_HALT,
+	   BNX2X_VFOP_QDTOR_TERMINATE,
+	   BNX2X_VFOP_QDTOR_CFCDEL,
+	   BNX2X_VFOP_QDTOR_DONE
+};
+
+enum bnx2x_vfop_vlan_mac_state {
+	   BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
+	   BNX2X_VFOP_VLAN_MAC_CLEAR,
+	   BNX2X_VFOP_VLAN_MAC_CHK_DONE,
+	   BNX2X_VFOP_MAC_CONFIG_LIST,
+	   BNX2X_VFOP_VLAN_CONFIG_LIST,
+	   BNX2X_VFOP_VLAN_CONFIG_LIST_0
+};
+
+enum bnx2x_vfop_qsetup_state {
+	   BNX2X_VFOP_QSETUP_CTOR,
+	   BNX2X_VFOP_QSETUP_VLAN0,
+	   BNX2X_VFOP_QSETUP_DONE
+};
+
+enum bnx2x_vfop_mcast_state {
+	   BNX2X_VFOP_MCAST_DEL,
+	   BNX2X_VFOP_MCAST_ADD,
+	   BNX2X_VFOP_MCAST_CHK_DONE
+};
+enum bnx2x_vfop_qflr_state {
+	   BNX2X_VFOP_QFLR_CLR_VLAN,
+	   BNX2X_VFOP_QFLR_CLR_MAC,
+	   BNX2X_VFOP_QFLR_TERMINATE,
+	   BNX2X_VFOP_QFLR_DONE
+};
+
+enum bnx2x_vfop_flr_state {
+	   BNX2X_VFOP_FLR_QUEUES,
+	   BNX2X_VFOP_FLR_HW
+};
+
+enum bnx2x_vfop_close_state {
+	   BNX2X_VFOP_CLOSE_QUEUES,
+	   BNX2X_VFOP_CLOSE_HW
+};
+
+enum bnx2x_vfop_rxmode_state {
+	   BNX2X_VFOP_RXMODE_CONFIG,
+	   BNX2X_VFOP_RXMODE_DONE
+};
+
+enum bnx2x_vfop_qteardown_state {
+	   BNX2X_VFOP_QTEARDOWN_RXMODE,
+	   BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
+	   BNX2X_VFOP_QTEARDOWN_CLR_MAC,
+	   BNX2X_VFOP_QTEARDOWN_QDTOR,
+	   BNX2X_VFOP_QTEARDOWN_DONE
+};
+
+#define bnx2x_vfop_reset_wq(vf)	atomic_set(&vf->op_in_progress, 0)
+
+void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			      struct bnx2x_queue_init_params *init_params,
+			      struct bnx2x_queue_setup_params *setup_params,
+			      u16 q_idx, u16 sb_idx)
+{
+	DP(BNX2X_MSG_IOV,
+	   "VF[%d] Q_SETUP: txq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, flags=0x%lx, traffic-type=%d",
+	   vf->abs_vfid,
+	   q_idx,
+	   sb_idx,
+	   init_params->tx.sb_cq_index,
+	   init_params->tx.hc_rate,
+	   setup_params->flags,
+	   setup_params->txq_params.traffic_type);
+}
+
+void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			    struct bnx2x_queue_init_params *init_params,
+			    struct bnx2x_queue_setup_params *setup_params,
+			    u16 q_idx, u16 sb_idx)
+{
+	struct bnx2x_rxq_setup_params *rxq_params = &setup_params->rxq_params;
+
+	DP(BNX2X_MSG_IOV, "VF[%d] Q_SETUP: rxq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, mtu=%d, buf-size=%d\n"
+	   "sge-size=%d, max_sge_pkt=%d, tpa-agg-size=%d, flags=0x%lx, drop-flags=0x%x, cache-log=%d\n",
+	   vf->abs_vfid,
+	   q_idx,
+	   sb_idx,
+	   init_params->rx.sb_cq_index,
+	   init_params->rx.hc_rate,
+	   setup_params->gen_params.mtu,
+	   rxq_params->buf_sz,
+	   rxq_params->sge_buf_sz,
+	   rxq_params->max_sges_pkt,
+	   rxq_params->tpa_agg_sz,
+	   setup_params->flags,
+	   rxq_params->drop_flags,
+	   rxq_params->cache_line_log);
+}
+
+void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
+			   struct bnx2x_virtf *vf,
+			   struct bnx2x_vf_queue *q,
+			   struct bnx2x_vfop_qctor_params *p,
+			   unsigned long q_type)
+{
+	struct bnx2x_queue_init_params *init_p = &p->qstate.params.init;
+	struct bnx2x_queue_setup_params *setup_p = &p->prep_qsetup;
+
+	/* INIT */
+
+	/* Enable host coalescing in the transition to INIT state */
+	if (test_bit(BNX2X_Q_FLG_HC, &init_p->rx.flags))
+		__set_bit(BNX2X_Q_FLG_HC_EN, &init_p->rx.flags);
+
+	if (test_bit(BNX2X_Q_FLG_HC, &init_p->tx.flags))
+		__set_bit(BNX2X_Q_FLG_HC_EN, &init_p->tx.flags);
+
+	/* FW SB ID */
+	init_p->rx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+	init_p->tx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+
+	/* context */
+	init_p->cxts[0] = q->cxt;
+
+	/* SETUP */
+
+	/* Setup-op general parameters */
+	setup_p->gen_params.spcl_id = vf->sp_cl_id;
+	setup_p->gen_params.stat_id = vfq_stat_id(vf, q);
+
+	/* Setup-op pause params:
+	 * Nothing to do, the pause thresholds are set by default to 0 which
+	 * effectively turns off the feature for this queue. We don't want
+	 * one queue (VF) to interfering with another queue (another VF)
+	 */
+	if (vf->cfg_flags & VF_CFG_FW_FC)
+		BNX2X_ERR("No support for pause to VFs (abs_vfid: %d)\n",
+			  vf->abs_vfid);
+	/* Setup-op flags:
+	 * collect statistics, zero statistics, local-switching, security,
+	 * OV for Flex10, RSS and MCAST for leading
+	 */
+	if (test_bit(BNX2X_Q_FLG_STATS, &setup_p->flags))
+		__set_bit(BNX2X_Q_FLG_ZERO_STATS, &setup_p->flags);
+
+	/* for VFs, enable tx switching, bd coherency, and mac address
+	 * anti-spoofing
+	 */
+	__set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags);
+	__set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags);
+	__set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
+
+	if (vfq_is_leading(q)) {
+		__set_bit(BNX2X_Q_FLG_LEADING_RSS, &setup_p->flags);
+		__set_bit(BNX2X_Q_FLG_MCAST, &setup_p->flags);
+	}
+
+	/* Setup-op rx parameters */
+	if (test_bit(BNX2X_Q_TYPE_HAS_RX, &q_type)) {
+		struct bnx2x_rxq_setup_params *rxq_p = &setup_p->rxq_params;
+
+		rxq_p->cl_qzone_id = vfq_qzone_id(vf, q);
+		rxq_p->fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+		rxq_p->rss_engine_id = FW_VF_HANDLE(vf->abs_vfid);
+
+		if (test_bit(BNX2X_Q_FLG_TPA, &setup_p->flags))
+			rxq_p->max_tpa_queues = BNX2X_VF_MAX_TPA_AGG_QUEUES;
+	}
+
+	/* Setup-op tx parameters */
+	if (test_bit(BNX2X_Q_TYPE_HAS_TX, &q_type)) {
+		setup_p->txq_params.tss_leading_cl_id = vf->leading_rss;
+		setup_p->txq_params.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+	}
+}
+
+/* VFOP queue construction */
+static void bnx2x_vfop_qctor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_vfop_args_qctor *args = &vfop->args.qctor;
+	struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+	enum bnx2x_vfop_qctor_state state = vfop->state;
+
+	bnx2x_vfop_reset_wq(vf);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_QCTOR_INIT:
+
+		/* has this queue already been opened? */
+		if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+		    BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+			DP(BNX2X_MSG_IOV,
+			   "Entered qctor but queue was already up. Aborting gracefully\n");
+			goto op_done;
+		}
+
+		/* next state */
+		vfop->state = BNX2X_VFOP_QCTOR_SETUP;
+
+		q_params->cmd = BNX2X_Q_CMD_INIT;
+		vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+	case BNX2X_VFOP_QCTOR_SETUP:
+		/* next state */
+		vfop->state = BNX2X_VFOP_QCTOR_INT_EN;
+
+		/* copy pre-prepared setup params to the queue-state params */
+		vfop->op_p->qctor.qstate.params.setup =
+			vfop->op_p->qctor.prep_qsetup;
+
+		q_params->cmd = BNX2X_Q_CMD_SETUP;
+		vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+	case BNX2X_VFOP_QCTOR_INT_EN:
+
+		/* enable interrupts */
+		bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, args->sb_idx),
+				    USTORM_ID, 0, IGU_INT_ENABLE, 0);
+		goto op_done;
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_err:
+	BNX2X_ERR("QCTOR[%d:%d] error: cmd %d, rc %d\n",
+		  vf->abs_vfid, args->qid, q_params->cmd, vfop->rc);
+op_done:
+	bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+	return;
+}
+
+static int bnx2x_vfop_qctor_cmd(struct bnx2x *bp,
+				struct bnx2x_virtf *vf,
+				struct bnx2x_vfop_cmd *cmd,
+				int qid)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		vf->op_params.qctor.qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+		vfop->args.qctor.qid = qid;
+		vfop->args.qctor.sb_idx = bnx2x_vfq(vf, qid, sb_idx);
+
+		bnx2x_vfop_opset(BNX2X_VFOP_QCTOR_INIT,
+				 bnx2x_vfop_qctor, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qctor,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VFOP queue destruction */
+static void bnx2x_vfop_qdtor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_vfop_args_qdtor *qdtor = &vfop->args.qdtor;
+	struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+	enum bnx2x_vfop_qdtor_state state = vfop->state;
+
+	bnx2x_vfop_reset_wq(vf);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_QDTOR_HALT:
+
+		/* has this queue already been stopped? */
+		if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+		    BNX2X_Q_LOGICAL_STATE_STOPPED) {
+			DP(BNX2X_MSG_IOV,
+			   "Entered qdtor but queue was already stopped. Aborting gracefully\n");
+			goto op_done;
+		}
+
+		/* next state */
+		vfop->state = BNX2X_VFOP_QDTOR_TERMINATE;
+
+		q_params->cmd = BNX2X_Q_CMD_HALT;
+		vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+	case BNX2X_VFOP_QDTOR_TERMINATE:
+		/* next state */
+		vfop->state = BNX2X_VFOP_QDTOR_CFCDEL;
+
+		q_params->cmd = BNX2X_Q_CMD_TERMINATE;
+		vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+	case BNX2X_VFOP_QDTOR_CFCDEL:
+		/* next state */
+		vfop->state = BNX2X_VFOP_QDTOR_DONE;
+
+		q_params->cmd = BNX2X_Q_CMD_CFC_DEL;
+		vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+	BNX2X_ERR("QDTOR[%d:%d] error: cmd %d, rc %d\n",
+		  vf->abs_vfid, qdtor->qid, q_params->cmd, vfop->rc);
+op_done:
+	case BNX2X_VFOP_QDTOR_DONE:
+		/* invalidate the context */
+		qdtor->cxt->ustorm_ag_context.cdu_usage = 0;
+		qdtor->cxt->xstorm_ag_context.cdu_reserved = 0;
+		bnx2x_vfop_end(bp, vf, vfop);
+		return;
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_pending:
+	return;
+}
+
+static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
+				struct bnx2x_virtf *vf,
+				struct bnx2x_vfop_cmd *cmd,
+				int qid)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_queue_state_params *qstate =
+			&vf->op_params.qctor.qstate;
+
+		memset(qstate, 0, sizeof(*qstate));
+		qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+		vfop->args.qdtor.qid = qid;
+		vfop->args.qdtor.cxt = bnx2x_vfq(vf, qid, cxt);
+
+		bnx2x_vfop_opset(BNX2X_VFOP_QDTOR_HALT,
+				 bnx2x_vfop_qdtor, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
+					     cmd->block);
+	}
+	DP(BNX2X_MSG_IOV, "VF[%d] failed to add a vfop.\n", vf->abs_vfid);
+	return -ENOMEM;
+}
+
+static void
+bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
+{
+	struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+	if (vf) {
+		if (!vf_sb_count(vf))
+			vf->igu_base_id = igu_sb_id;
+		++vf_sb_count(vf);
+	}
+}
+
+/* VFOP MAC/VLAN helpers */
+static inline void bnx2x_vfop_credit(struct bnx2x *bp,
+				     struct bnx2x_vfop *vfop,
+				     struct bnx2x_vlan_mac_obj *obj)
+{
+	struct bnx2x_vfop_args_filters *args = &vfop->args.filters;
+
+	/* update credit only if there is no error
+	 * and a valid credit counter
+	 */
+	if (!vfop->rc && args->credit) {
+		int cnt = 0;
+		struct list_head *pos;
+
+		list_for_each(pos, &obj->head)
+			cnt++;
+
+		atomic_set(args->credit, cnt);
+	}
+}
+
+static int bnx2x_vfop_set_user_req(struct bnx2x *bp,
+				    struct bnx2x_vfop_filter *pos,
+				    struct bnx2x_vlan_mac_data *user_req)
+{
+	user_req->cmd = pos->add ? BNX2X_VLAN_MAC_ADD :
+		BNX2X_VLAN_MAC_DEL;
+
+	switch (pos->type) {
+	case BNX2X_VFOP_FILTER_MAC:
+		memcpy(user_req->u.mac.mac, pos->mac, ETH_ALEN);
+		break;
+	case BNX2X_VFOP_FILTER_VLAN:
+		user_req->u.vlan.vlan = pos->vid;
+		break;
+	default:
+		BNX2X_ERR("Invalid filter type, skipping\n");
+		return 1;
+	}
+	return 0;
+}
+
+static int
+bnx2x_vfop_config_vlan0(struct bnx2x *bp,
+			struct bnx2x_vlan_mac_ramrod_params *vlan_mac,
+			bool add)
+{
+	int rc;
+
+	vlan_mac->user_req.cmd = add ? BNX2X_VLAN_MAC_ADD :
+		BNX2X_VLAN_MAC_DEL;
+	vlan_mac->user_req.u.vlan.vlan = 0;
+
+	rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+	if (rc == -EEXIST)
+		rc = 0;
+	return rc;
+}
+
+static int bnx2x_vfop_config_list(struct bnx2x *bp,
+				  struct bnx2x_vfop_filters *filters,
+				  struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
+{
+	struct bnx2x_vfop_filter *pos, *tmp;
+	struct list_head rollback_list, *filters_list = &filters->head;
+	struct bnx2x_vlan_mac_data *user_req = &vlan_mac->user_req;
+	int rc = 0, cnt = 0;
+
+	INIT_LIST_HEAD(&rollback_list);
+
+	list_for_each_entry_safe(pos, tmp, filters_list, link) {
+		if (bnx2x_vfop_set_user_req(bp, pos, user_req))
+			continue;
+
+		rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+		if (rc >= 0) {
+			cnt += pos->add ? 1 : -1;
+			list_del(&pos->link);
+			list_add(&pos->link, &rollback_list);
+			rc = 0;
+		} else if (rc == -EEXIST) {
+			rc = 0;
+		} else {
+			BNX2X_ERR("Failed to add a new vlan_mac command\n");
+			break;
+		}
+	}
+
+	/* rollback if error or too many rules added */
+	if (rc || cnt > filters->add_cnt) {
+		BNX2X_ERR("error or too many rules added. Performing rollback\n");
+		list_for_each_entry_safe(pos, tmp, &rollback_list, link) {
+			pos->add = !pos->add;	/* reverse op */
+			bnx2x_vfop_set_user_req(bp, pos, user_req);
+			bnx2x_config_vlan_mac(bp, vlan_mac);
+			list_del(&pos->link);
+		}
+		cnt = 0;
+		if (!rc)
+			rc = -EINVAL;
+	}
+	filters->add_cnt = cnt;
+	return rc;
+}
+
+/* VFOP set VLAN/MAC */
+static void bnx2x_vfop_vlan_mac(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_vlan_mac_ramrod_params *vlan_mac = &vfop->op_p->vlan_mac;
+	struct bnx2x_vlan_mac_obj *obj = vlan_mac->vlan_mac_obj;
+	struct bnx2x_vfop_filters *filters = vfop->args.filters.multi_filter;
+
+	enum bnx2x_vfop_vlan_mac_state state = vfop->state;
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	bnx2x_vfop_reset_wq(vf);
+
+	switch (state) {
+	case BNX2X_VFOP_VLAN_MAC_CLEAR:
+		/* next state */
+		vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+		/* do delete */
+		vfop->rc = obj->delete_all(bp, obj,
+					   &vlan_mac->user_req.vlan_mac_flags,
+					   &vlan_mac->ramrod_flags);
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+	case BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE:
+		/* next state */
+		vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+		/* do config */
+		vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+		if (vfop->rc == -EEXIST)
+			vfop->rc = 0;
+
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+	case BNX2X_VFOP_VLAN_MAC_CHK_DONE:
+		vfop->rc = !!obj->raw.check_pending(&obj->raw);
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+	case BNX2X_VFOP_MAC_CONFIG_LIST:
+		/* next state */
+		vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+		/* do list config */
+		vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
+		if (vfop->rc)
+			goto op_err;
+
+		set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
+		vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+	case BNX2X_VFOP_VLAN_CONFIG_LIST:
+		/* next state */
+		vfop->state = BNX2X_VFOP_VLAN_CONFIG_LIST_0;
+
+		/* remove vlan0 - could be no-op */
+		vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, false);
+		if (vfop->rc)
+			goto op_err;
+
+		/* Do vlan list config. if this operation fails we try to
+		 * restore vlan0 to keep the queue is working order
+		 */
+		vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
+		if (!vfop->rc) {
+			set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
+			vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+		}
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); /* fall-through */
+
+	case BNX2X_VFOP_VLAN_CONFIG_LIST_0:
+		/* next state */
+		vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+		if (list_empty(&obj->head))
+			/* add vlan0 */
+			vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, true);
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_err:
+	BNX2X_ERR("VLAN-MAC error: rc %d\n", vfop->rc);
+op_done:
+	kfree(filters);
+	bnx2x_vfop_credit(bp, vfop, obj);
+	bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+	return;
+}
+
+struct bnx2x_vfop_vlan_mac_flags {
+	bool drv_only;
+	bool dont_consume;
+	bool single_cmd;
+	bool add;
+};
+
+static void
+bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+				struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+	struct bnx2x_vlan_mac_data *ureq = &ramrod->user_req;
+
+	memset(ramrod, 0, sizeof(*ramrod));
+
+	/* ramrod flags */
+	if (flags->drv_only)
+		set_bit(RAMROD_DRV_CLR_ONLY, &ramrod->ramrod_flags);
+	if (flags->single_cmd)
+		set_bit(RAMROD_EXEC, &ramrod->ramrod_flags);
+
+	/* mac_vlan flags */
+	if (flags->dont_consume)
+		set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, &ureq->vlan_mac_flags);
+
+	/* cmd */
+	ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
+}
+
+static inline void
+bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+			   struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+	bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
+	set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
+}
+
+static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp,
+				     struct bnx2x_virtf *vf,
+				     struct bnx2x_vfop_cmd *cmd,
+				     int qid, bool drv_only)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_vfop_args_filters filters = {
+			.multi_filter = NULL,	/* single */
+			.credit = NULL,		/* consume credit */
+		};
+		struct bnx2x_vfop_vlan_mac_flags flags = {
+			.drv_only = drv_only,
+			.dont_consume = (filters.credit != NULL),
+			.single_cmd = true,
+			.add = false /* don't care */,
+		};
+		struct bnx2x_vlan_mac_ramrod_params *ramrod =
+			&vf->op_params.vlan_mac;
+
+		/* set ramrod params */
+		bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+		/* set object */
+		ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+		/* set extra args */
+		vfop->args.filters = filters;
+
+		bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+				 bnx2x_vfop_vlan_mac, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+			    struct bnx2x_virtf *vf,
+			    struct bnx2x_vfop_cmd *cmd,
+			    struct bnx2x_vfop_filters *macs,
+			    int qid, bool drv_only)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_vfop_args_filters filters = {
+			.multi_filter = macs,
+			.credit = NULL,		/* consume credit */
+		};
+		struct bnx2x_vfop_vlan_mac_flags flags = {
+			.drv_only = drv_only,
+			.dont_consume = (filters.credit != NULL),
+			.single_cmd = false,
+			.add = false, /* don't care since only the items in the
+				       * filters list affect the sp operation,
+				       * not the list itself
+				       */
+		};
+		struct bnx2x_vlan_mac_ramrod_params *ramrod =
+			&vf->op_params.vlan_mac;
+
+		/* set ramrod params */
+		bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+		/* set object */
+		ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+		/* set extra args */
+		filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
+		vfop->args.filters = filters;
+
+		bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
+				 bnx2x_vfop_vlan_mac, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+			    struct bnx2x_virtf *vf,
+			    struct bnx2x_vfop_cmd *cmd,
+			    int qid, u16 vid, bool add)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_vfop_args_filters filters = {
+			.multi_filter = NULL, /* single command */
+			.credit = &bnx2x_vfq(vf, qid, vlan_count),
+		};
+		struct bnx2x_vfop_vlan_mac_flags flags = {
+			.drv_only = false,
+			.dont_consume = (filters.credit != NULL),
+			.single_cmd = true,
+			.add = add,
+		};
+		struct bnx2x_vlan_mac_ramrod_params *ramrod =
+			&vf->op_params.vlan_mac;
+
+		/* set ramrod params */
+		bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+		ramrod->user_req.u.vlan.vlan = vid;
+
+		/* set object */
+		ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+		/* set extra args */
+		vfop->args.filters = filters;
+
+		bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
+				 bnx2x_vfop_vlan_mac, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp,
+			       struct bnx2x_virtf *vf,
+			       struct bnx2x_vfop_cmd *cmd,
+			       int qid, bool drv_only)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_vfop_args_filters filters = {
+			.multi_filter = NULL, /* single command */
+			.credit = &bnx2x_vfq(vf, qid, vlan_count),
+		};
+		struct bnx2x_vfop_vlan_mac_flags flags = {
+			.drv_only = drv_only,
+			.dont_consume = (filters.credit != NULL),
+			.single_cmd = true,
+			.add = false, /* don't care */
+		};
+		struct bnx2x_vlan_mac_ramrod_params *ramrod =
+			&vf->op_params.vlan_mac;
+
+		/* set ramrod params */
+		bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+		/* set object */
+		ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+		/* set extra args */
+		vfop->args.filters = filters;
+
+		bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+				 bnx2x_vfop_vlan_mac, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+			     struct bnx2x_virtf *vf,
+			     struct bnx2x_vfop_cmd *cmd,
+			     struct bnx2x_vfop_filters *vlans,
+			     int qid, bool drv_only)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_vfop_args_filters filters = {
+			.multi_filter = vlans,
+			.credit = &bnx2x_vfq(vf, qid, vlan_count),
+		};
+		struct bnx2x_vfop_vlan_mac_flags flags = {
+			.drv_only = drv_only,
+			.dont_consume = (filters.credit != NULL),
+			.single_cmd = false,
+			.add = false, /* don't care */
+		};
+		struct bnx2x_vlan_mac_ramrod_params *ramrod =
+			&vf->op_params.vlan_mac;
+
+		/* set ramrod params */
+		bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+		/* set object */
+		ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+		/* set extra args */
+		filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
+			atomic_read(filters.credit);
+
+		vfop->args.filters = filters;
+
+		bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
+				 bnx2x_vfop_vlan_mac, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VFOP queue setup (queue constructor + set vlan 0) */
+static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	int qid = vfop->args.qctor.qid;
+	enum bnx2x_vfop_qsetup_state state = vfop->state;
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vfop_qsetup,
+		.block = false,
+	};
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_QSETUP_CTOR:
+		/* init the queue ctor command */
+		vfop->state = BNX2X_VFOP_QSETUP_VLAN0;
+		vfop->rc = bnx2x_vfop_qctor_cmd(bp, vf, &cmd, qid);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_QSETUP_VLAN0:
+		/* skip if non-leading or FPGA/EMU*/
+		if (qid)
+			goto op_done;
+
+		/* init the queue set-vlan command (for vlan 0) */
+		vfop->state = BNX2X_VFOP_QSETUP_DONE;
+		vfop->rc = bnx2x_vfop_vlan_set_cmd(bp, vf, &cmd, qid, 0, true);
+		if (vfop->rc)
+			goto op_err;
+		return;
+op_err:
+	BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
+op_done:
+	case BNX2X_VFOP_QSETUP_DONE:
+		bnx2x_vfop_end(bp, vf, vfop);
+		return;
+	default:
+		bnx2x_vfop_default(state);
+	}
+}
+
+int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
+			  struct bnx2x_virtf *vf,
+			  struct bnx2x_vfop_cmd *cmd,
+			  int qid)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		vfop->args.qctor.qid = qid;
+
+		bnx2x_vfop_opset(BNX2X_VFOP_QSETUP_CTOR,
+				 bnx2x_vfop_qsetup, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qsetup,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VFOP queue FLR handling (clear vlans, clear macs, queue destructor) */
+static void bnx2x_vfop_qflr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	int qid = vfop->args.qx.qid;
+	enum bnx2x_vfop_qflr_state state = vfop->state;
+	struct bnx2x_queue_state_params *qstate;
+	struct bnx2x_vfop_cmd cmd;
+
+	bnx2x_vfop_reset_wq(vf);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "VF[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	cmd.done = bnx2x_vfop_qflr;
+	cmd.block = false;
+
+	switch (state) {
+	case BNX2X_VFOP_QFLR_CLR_VLAN:
+		/* vlan-clear-all: driver-only, don't consume credit */
+		vfop->state = BNX2X_VFOP_QFLR_CLR_MAC;
+		vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, true);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_QFLR_CLR_MAC:
+		/* mac-clear-all: driver only consume credit */
+		vfop->state = BNX2X_VFOP_QFLR_TERMINATE;
+		vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, true);
+		DP(BNX2X_MSG_IOV,
+		   "VF[%d] vfop->rc after bnx2x_vfop_mac_delall_cmd was %d",
+		   vf->abs_vfid, vfop->rc);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_QFLR_TERMINATE:
+		qstate = &vfop->op_p->qctor.qstate;
+		memset(qstate , 0, sizeof(*qstate));
+		qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+		vfop->state = BNX2X_VFOP_QFLR_DONE;
+
+		DP(BNX2X_MSG_IOV, "VF[%d] qstate during flr was %d\n",
+		   vf->abs_vfid, qstate->q_obj->state);
+
+		if (qstate->q_obj->state != BNX2X_Q_STATE_RESET) {
+			qstate->q_obj->state = BNX2X_Q_STATE_STOPPED;
+			qstate->cmd = BNX2X_Q_CMD_TERMINATE;
+			vfop->rc = bnx2x_queue_state_change(bp, qstate);
+			bnx2x_vfop_finalize(vf, vfop->rc, VFOP_VERIFY_PEND);
+		} else {
+			goto op_done;
+		}
+
+op_err:
+	BNX2X_ERR("QFLR[%d:%d] error: rc %d\n",
+		  vf->abs_vfid, qid, vfop->rc);
+op_done:
+	case BNX2X_VFOP_QFLR_DONE:
+		bnx2x_vfop_end(bp, vf, vfop);
+		return;
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_pending:
+	return;
+}
+
+static int bnx2x_vfop_qflr_cmd(struct bnx2x *bp,
+			       struct bnx2x_virtf *vf,
+			       struct bnx2x_vfop_cmd *cmd,
+			       int qid)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		vfop->args.qx.qid = qid;
+		bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN,
+				 bnx2x_vfop_qflr, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qflr,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VFOP multi-casts */
+static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
+	struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
+	struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
+	enum bnx2x_vfop_mcast_state state = vfop->state;
+	int i;
+
+	bnx2x_vfop_reset_wq(vf);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_MCAST_DEL:
+		/* clear existing mcasts */
+		vfop->state = BNX2X_VFOP_MCAST_ADD;
+		vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+	case BNX2X_VFOP_MCAST_ADD:
+		if (raw->check_pending(raw))
+			goto op_pending;
+
+		if (args->mc_num) {
+			/* update mcast list on the ramrod params */
+			INIT_LIST_HEAD(&mcast->mcast_list);
+			for (i = 0; i < args->mc_num; i++)
+				list_add_tail(&(args->mc[i].link),
+					      &mcast->mcast_list);
+			/* add new mcasts */
+			vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
+			vfop->rc = bnx2x_config_mcast(bp, mcast,
+						      BNX2X_MCAST_CMD_ADD);
+		}
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+	case BNX2X_VFOP_MCAST_CHK_DONE:
+		vfop->rc = raw->check_pending(raw) ? 1 : 0;
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_err:
+	BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
+op_done:
+	kfree(args->mc);
+	bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+	return;
+}
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+			 struct bnx2x_virtf *vf,
+			 struct bnx2x_vfop_cmd *cmd,
+			 bnx2x_mac_addr_t *mcasts,
+			 int mcast_num, bool drv_only)
+{
+	struct bnx2x_vfop *vfop = NULL;
+	size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
+	struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
+					   NULL;
+
+	if (!mc_sz || mc) {
+		vfop = bnx2x_vfop_add(bp, vf);
+		if (vfop) {
+			int i;
+			struct bnx2x_mcast_ramrod_params *ramrod =
+				&vf->op_params.mcast;
+
+			/* set ramrod params */
+			memset(ramrod, 0, sizeof(*ramrod));
+			ramrod->mcast_obj = &vf->mcast_obj;
+			if (drv_only)
+				set_bit(RAMROD_DRV_CLR_ONLY,
+					&ramrod->ramrod_flags);
+
+			/* copy mcasts pointers */
+			vfop->args.mc_list.mc_num = mcast_num;
+			vfop->args.mc_list.mc = mc;
+			for (i = 0; i < mcast_num; i++)
+				mc[i].mac = mcasts[i];
+
+			bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
+					 bnx2x_vfop_mcast, cmd->done);
+			return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
+						     cmd->block);
+		} else {
+			kfree(mc);
+		}
+	}
+	return -ENOMEM;
+}
+
+/* VFOP rx-mode */
+static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
+	enum bnx2x_vfop_rxmode_state state = vfop->state;
+
+	bnx2x_vfop_reset_wq(vf);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_RXMODE_CONFIG:
+		/* next state */
+		vfop->state = BNX2X_VFOP_RXMODE_DONE;
+
+		vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
+		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+		BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
+op_done:
+	case BNX2X_VFOP_RXMODE_DONE:
+		bnx2x_vfop_end(bp, vf, vfop);
+		return;
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_pending:
+	return;
+}
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+			  struct bnx2x_virtf *vf,
+			  struct bnx2x_vfop_cmd *cmd,
+			  int qid, unsigned long accept_flags)
+{
+	struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		struct bnx2x_rx_mode_ramrod_params *ramrod =
+			&vf->op_params.rx_mode;
+
+		memset(ramrod, 0, sizeof(*ramrod));
+
+		/* Prepare ramrod parameters */
+		ramrod->cid = vfq->cid;
+		ramrod->cl_id = vfq_cl_id(vf, vfq);
+		ramrod->rx_mode_obj = &bp->rx_mode_obj;
+		ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
+
+		ramrod->rx_accept_flags = accept_flags;
+		ramrod->tx_accept_flags = accept_flags;
+		ramrod->pstate = &vf->filter_state;
+		ramrod->state = BNX2X_FILTER_RX_MODE_PENDING;
+
+		set_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+		set_bit(RAMROD_RX, &ramrod->ramrod_flags);
+		set_bit(RAMROD_TX, &ramrod->ramrod_flags);
+
+		ramrod->rdata =
+			bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
+		ramrod->rdata_mapping =
+			bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
+
+		bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
+				 bnx2x_vfop_rxmode, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VFOP queue tear-down ('drop all' rx-mode, clear vlans, clear macs,
+ * queue destructor)
+ */
+static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	int qid = vfop->args.qx.qid;
+	enum bnx2x_vfop_qteardown_state state = vfop->state;
+	struct bnx2x_vfop_cmd cmd;
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	cmd.done = bnx2x_vfop_qdown;
+	cmd.block = false;
+
+	switch (state) {
+	case BNX2X_VFOP_QTEARDOWN_RXMODE:
+		/* Drop all */
+		vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN;
+		vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_QTEARDOWN_CLR_VLAN:
+		/* vlan-clear-all: don't consume credit */
+		vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MAC;
+		vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, false);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
+		/* mac-clear-all: consume credit */
+		vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
+		vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_QTEARDOWN_QDTOR:
+		/* run the queue destruction flow */
+		DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
+		vfop->state = BNX2X_VFOP_QTEARDOWN_DONE;
+		DP(BNX2X_MSG_IOV, "new state: BNX2X_VFOP_QTEARDOWN_DONE\n");
+		vfop->rc = bnx2x_vfop_qdtor_cmd(bp, vf, &cmd, qid);
+		DP(BNX2X_MSG_IOV, "returned from cmd\n");
+		if (vfop->rc)
+			goto op_err;
+		return;
+op_err:
+	BNX2X_ERR("QTEARDOWN[%d:%d] error: rc %d\n",
+		  vf->abs_vfid, qid, vfop->rc);
+
+	case BNX2X_VFOP_QTEARDOWN_DONE:
+		bnx2x_vfop_end(bp, vf, vfop);
+		return;
+	default:
+		bnx2x_vfop_default(state);
+	}
+}
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+			 struct bnx2x_virtf *vf,
+			 struct bnx2x_vfop_cmd *cmd,
+			 int qid)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+	if (vfop) {
+		vfop->args.qx.qid = qid;
+		bnx2x_vfop_opset(BNX2X_VFOP_QTEARDOWN_RXMODE,
+				 bnx2x_vfop_qdown, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdown,
+					     cmd->block);
+	}
+
+	return -ENOMEM;
+}
+
+/* VF enable primitives
+ * when pretend is required the caller is responsible
+ * for calling pretend prior to calling these routines
+ */
+
+/* internal vf enable - until vf is enabled internally all transactions
+ * are blocked. this routine should always be called last with pretend.
+ */
+static void bnx2x_vf_enable_internal(struct bnx2x *bp, u8 enable)
+{
+	REG_WR(bp, PGLUE_B_REG_INTERNAL_VFID_ENABLE, enable ? 1 : 0);
+}
+
+/* clears vf error in all semi blocks */
+static void bnx2x_vf_semi_clear_err(struct bnx2x *bp, u8 abs_vfid)
+{
+	REG_WR(bp, TSEM_REG_VFPF_ERR_NUM, abs_vfid);
+	REG_WR(bp, USEM_REG_VFPF_ERR_NUM, abs_vfid);
+	REG_WR(bp, CSEM_REG_VFPF_ERR_NUM, abs_vfid);
+	REG_WR(bp, XSEM_REG_VFPF_ERR_NUM, abs_vfid);
+}
+
+static void bnx2x_vf_pglue_clear_err(struct bnx2x *bp, u8 abs_vfid)
+{
+	u32 was_err_group = (2 * BP_PATH(bp) + abs_vfid) >> 5;
+	u32 was_err_reg = 0;
+
+	switch (was_err_group) {
+	case 0:
+	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR;
+	    break;
+	case 1:
+	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_63_32_CLR;
+	    break;
+	case 2:
+	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_95_64_CLR;
+	    break;
+	case 3:
+	    was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_127_96_CLR;
+	    break;
+	}
+	REG_WR(bp, was_err_reg, 1 << (abs_vfid & 0x1f));
+}
+
+static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	int i;
+	u32 val;
+
+	/* Set VF masks and configuration - pretend */
+	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+
+	REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0);
+	REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0);
+	REG_WR(bp, IGU_REG_SB_MASK_LSB, 0);
+	REG_WR(bp, IGU_REG_SB_MASK_MSB, 0);
+	REG_WR(bp, IGU_REG_PBA_STATUS_LSB, 0);
+	REG_WR(bp, IGU_REG_PBA_STATUS_MSB, 0);
+
+	val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
+	val |= (IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_MSI_MSIX_EN);
+	if (vf->cfg_flags & VF_CFG_INT_SIMD)
+		val |= IGU_VF_CONF_SINGLE_ISR_EN;
+	val &= ~IGU_VF_CONF_PARENT_MASK;
+	val |= BP_FUNC(bp) << IGU_VF_CONF_PARENT_SHIFT;	/* parent PF */
+	REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
+
+	DP(BNX2X_MSG_IOV,
+	   "value in IGU_REG_VF_CONFIGURATION of vf %d after write %x\n",
+	   vf->abs_vfid, REG_RD(bp, IGU_REG_VF_CONFIGURATION));
+
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+	/* iterate over all queues, clear sb consumer */
+	for (i = 0; i < vf_sb_count(vf); i++) {
+		u8 igu_sb_id = vf_igu_sb(vf, i);
+
+		/* zero prod memory */
+		REG_WR(bp, IGU_REG_PROD_CONS_MEMORY + igu_sb_id * 4, 0);
+
+		/* clear sb state machine */
+		bnx2x_igu_clear_sb_gen(bp, vf->abs_vfid, igu_sb_id,
+				       false /* VF */);
+
+		/* disable + update */
+		bnx2x_vf_igu_ack_sb(bp, vf, igu_sb_id, USTORM_ID, 0,
+				    IGU_INT_DISABLE, 1);
+	}
+}
+
+void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid)
+{
+	/* set the VF-PF association in the FW */
+	storm_memset_vf_to_pf(bp, FW_VF_HANDLE(abs_vfid), BP_FUNC(bp));
+	storm_memset_func_en(bp, FW_VF_HANDLE(abs_vfid), 1);
+
+	/* clear vf errors*/
+	bnx2x_vf_semi_clear_err(bp, abs_vfid);
+	bnx2x_vf_pglue_clear_err(bp, abs_vfid);
+
+	/* internal vf-enable - pretend */
+	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, abs_vfid));
+	DP(BNX2X_MSG_IOV, "enabling internal access for vf %x\n", abs_vfid);
+	bnx2x_vf_enable_internal(bp, true);
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static void bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	/* Reset vf in IGU  interrupts are still disabled */
+	bnx2x_vf_igu_reset(bp, vf);
+
+	/* pretend to enable the vf with the PBF */
+	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+	REG_WR(bp, PBF_REG_DISABLE_VF, 0);
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
+{
+	struct pci_dev *dev;
+	struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+
+	if (!vf)
+		goto unknown_dev;
+
+	dev = pci_get_bus_and_slot(vf->bus, vf->devfn);
+	if (dev)
+		return bnx2x_is_pcie_pending(dev);
+
+unknown_dev:
+	BNX2X_ERR("Unknown device\n");
+	return false;
+}
+
+int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
+{
+	/* Wait 100ms */
+	msleep(100);
+
+	/* Verify no pending pci transactions */
+	if (bnx2x_vf_is_pcie_pending(bp, abs_vfid))
+		BNX2X_ERR("PCIE Transactions still pending\n");
+
+	return 0;
+}
+
+/* must be called after the number of PF queues and the number of VFs are
+ * both known
+ */
+static void
+bnx2x_iov_static_resc(struct bnx2x *bp, struct vf_pf_resc_request *resc)
+{
+	u16 vlan_count = 0;
+
+	/* will be set only during VF-ACQUIRE */
+	resc->num_rxqs = 0;
+	resc->num_txqs = 0;
+
+	/* no credit calculcis for macs (just yet) */
+	resc->num_mac_filters = 1;
+
+	/* divvy up vlan rules */
+	vlan_count = bp->vlans_pool.check(&bp->vlans_pool);
+	vlan_count = 1 << ilog2(vlan_count);
+	resc->num_vlan_filters = vlan_count / BNX2X_NR_VIRTFN(bp);
+
+	/* no real limitation */
+	resc->num_mc_filters = 0;
+
+	/* num_sbs already set */
+}
+
+/* FLR routines: */
+static void bnx2x_vf_free_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	/* reset the state variables */
+	bnx2x_iov_static_resc(bp, &vf->alloc_resc);
+	vf->state = VF_FREE;
+}
+
+static void bnx2x_vf_flr_clnup_hw(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);
+
+	/* DQ usage counter */
+	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+	bnx2x_flr_clnup_poll_hw_counter(bp, DORQ_REG_VF_USAGE_CNT,
+					"DQ VF usage counter timed out",
+					poll_cnt);
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+	/* FW cleanup command - poll for the results */
+	if (bnx2x_send_final_clnup(bp, (u8)FW_VF_HANDLE(vf->abs_vfid),
+				   poll_cnt))
+		BNX2X_ERR("VF[%d] Final cleanup timed-out\n", vf->abs_vfid);
+
+	/* verify TX hw is flushed */
+	bnx2x_tx_hw_flushed(bp, poll_cnt);
+}
+
+static void bnx2x_vfop_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
+	enum bnx2x_vfop_flr_state state = vfop->state;
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vfop_flr,
+		.block = false,
+	};
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_FLR_QUEUES:
+		/* the cleanup operations are valid if and only if the VF
+		 * was first acquired.
+		 */
+		if (++(qx->qid) < vf_rxq_count(vf)) {
+			vfop->rc = bnx2x_vfop_qflr_cmd(bp, vf, &cmd,
+						       qx->qid);
+			if (vfop->rc)
+				goto op_err;
+			return;
+		}
+		/* remove multicasts */
+		vfop->state = BNX2X_VFOP_FLR_HW;
+		vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL,
+						0, true);
+		if (vfop->rc)
+			goto op_err;
+		return;
+	case BNX2X_VFOP_FLR_HW:
+
+		/* dispatch final cleanup and wait for HW queues to flush */
+		bnx2x_vf_flr_clnup_hw(bp, vf);
+
+		/* release VF resources */
+		bnx2x_vf_free_resc(bp, vf);
+
+		/* re-open the mailbox */
+		bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+
+		goto op_done;
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_err:
+	BNX2X_ERR("VF[%d] FLR error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+	vf->flr_clnup_stage = VF_FLR_ACK;
+	bnx2x_vfop_end(bp, vf, vfop);
+	bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
+}
+
+static int bnx2x_vfop_flr_cmd(struct bnx2x *bp,
+			      struct bnx2x_virtf *vf,
+			      vfop_handler_t done)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+	if (vfop) {
+		vfop->args.qx.qid = -1; /* loop */
+		bnx2x_vfop_opset(BNX2X_VFOP_FLR_QUEUES,
+				 bnx2x_vfop_flr, done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_flr, false);
+	}
+	return -ENOMEM;
+}
+
+static void bnx2x_vf_flr_clnup(struct bnx2x *bp, struct bnx2x_virtf *prev_vf)
+{
+	int i = prev_vf ? prev_vf->index + 1 : 0;
+	struct bnx2x_virtf *vf;
+
+	/* find next VF to cleanup */
+next_vf_to_clean:
+	for (;
+	     i < BNX2X_NR_VIRTFN(bp) &&
+	     (bnx2x_vf(bp, i, state) != VF_RESET ||
+	      bnx2x_vf(bp, i, flr_clnup_stage) != VF_FLR_CLN);
+	     i++)
+		;
+
+	DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. num of vfs: %d\n", i,
+	   BNX2X_NR_VIRTFN(bp));
+
+	if (i < BNX2X_NR_VIRTFN(bp)) {
+		vf = BP_VF(bp, i);
+
+		/* lock the vf pf channel */
+		bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
+
+		/* invoke the VF FLR SM */
+		if (bnx2x_vfop_flr_cmd(bp, vf, bnx2x_vf_flr_clnup)) {
+			BNX2X_ERR("VF[%d]: FLR cleanup failed -ENOMEM\n",
+				  vf->abs_vfid);
+
+			/* mark the VF to be ACKED and continue */
+			vf->flr_clnup_stage = VF_FLR_ACK;
+			goto next_vf_to_clean;
+		}
+		return;
+	}
+
+	/* we are done, update vf records */
+	for_each_vf(bp, i) {
+		vf = BP_VF(bp, i);
+
+		if (vf->flr_clnup_stage != VF_FLR_ACK)
+			continue;
+
+		vf->flr_clnup_stage = VF_FLR_EPILOG;
+	}
+
+	/* Acknowledge the handled VFs.
+	 * we are acknowledge all the vfs which an flr was requested for, even
+	 * if amongst them there are such that we never opened, since the mcp
+	 * will interrupt us immediately again if we only ack some of the bits,
+	 * resulting in an endless loop. This can happen for example in KVM
+	 * where an 'all ones' flr request is sometimes given by hyper visor
+	 */
+	DP(BNX2X_MSG_MCP, "DRV_STATUS_VF_DISABLED ACK for vfs 0x%x 0x%x\n",
+	   bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
+	for (i = 0; i < FLRD_VFS_DWORDS; i++)
+		SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i],
+			  bp->vfdb->flrd_vfs[i]);
+
+	bnx2x_fw_command(bp, DRV_MSG_CODE_VF_DISABLED_DONE, 0);
+
+	/* clear the acked bits - better yet if the MCP implemented
+	 * write to clear semantics
+	 */
+	for (i = 0; i < FLRD_VFS_DWORDS; i++)
+		SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i], 0);
+}
+
+void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
+{
+	int i;
+
+	/* Read FLR'd VFs */
+	for (i = 0; i < FLRD_VFS_DWORDS; i++)
+		bp->vfdb->flrd_vfs[i] = SHMEM2_RD(bp, mcp_vf_disabled[i]);
+
+	DP(BNX2X_MSG_MCP,
+	   "DRV_STATUS_VF_DISABLED received for vfs 0x%x 0x%x\n",
+	   bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
+
+	for_each_vf(bp, i) {
+		struct bnx2x_virtf *vf = BP_VF(bp, i);
+		u32 reset = 0;
+
+		if (vf->abs_vfid < 32)
+			reset = bp->vfdb->flrd_vfs[0] & (1 << vf->abs_vfid);
+		else
+			reset = bp->vfdb->flrd_vfs[1] &
+				(1 << (vf->abs_vfid - 32));
+
+		if (reset) {
+			/* set as reset and ready for cleanup */
+			vf->state = VF_RESET;
+			vf->flr_clnup_stage = VF_FLR_CLN;
+
+			DP(BNX2X_MSG_IOV,
+			   "Initiating Final cleanup for VF %d\n",
+			   vf->abs_vfid);
+		}
+	}
+
+	/* do the FLR cleanup for all marked VFs*/
+	bnx2x_vf_flr_clnup(bp, NULL);
+}
+
+/* IOV global initialization routines  */
+void bnx2x_iov_init_dq(struct bnx2x *bp)
+{
+	if (!IS_SRIOV(bp))
+		return;
+
+	/* Set the DQ such that the CID reflect the abs_vfid */
+	REG_WR(bp, DORQ_REG_VF_NORM_VF_BASE, 0);
+	REG_WR(bp, DORQ_REG_MAX_RVFID_SIZE, ilog2(BNX2X_MAX_NUM_OF_VFS));
+
+	/* Set VFs starting CID. If its > 0 the preceding CIDs are belong to
+	 * the PF L2 queues
+	 */
+	REG_WR(bp, DORQ_REG_VF_NORM_CID_BASE, BNX2X_FIRST_VF_CID);
+
+	/* The VF window size is the log2 of the max number of CIDs per VF */
+	REG_WR(bp, DORQ_REG_VF_NORM_CID_WND_SIZE, BNX2X_VF_CID_WND);
+
+	/* The VF doorbell size  0 - *B, 4 - 128B. We set it here to match
+	 * the Pf doorbell size although the 2 are independent.
+	 */
+	REG_WR(bp, DORQ_REG_VF_NORM_CID_OFST,
+	       BNX2X_DB_SHIFT - BNX2X_DB_MIN_SHIFT);
+
+	/* No security checks for now -
+	 * configure single rule (out of 16) mask = 0x1, value = 0x0,
+	 * CID range 0 - 0x1ffff
+	 */
+	REG_WR(bp, DORQ_REG_VF_TYPE_MASK_0, 1);
+	REG_WR(bp, DORQ_REG_VF_TYPE_VALUE_0, 0);
+	REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
+	REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
+
+	/* set the number of VF alllowed doorbells to the full DQ range */
+	REG_WR(bp, DORQ_REG_VF_NORM_MAX_CID_COUNT, 0x20000);
+
+	/* set the VF doorbell threshold */
+	REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 4);
+}
+
+void bnx2x_iov_init_dmae(struct bnx2x *bp)
+{
+	DP(BNX2X_MSG_IOV, "SRIOV is %s\n", IS_SRIOV(bp) ? "ON" : "OFF");
+	if (!IS_SRIOV(bp))
+		return;
+
+	REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
+}
+
+static int bnx2x_vf_bus(struct bnx2x *bp, int vfid)
+{
+	struct pci_dev *dev = bp->pdev;
+	struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+	return dev->bus->number + ((dev->devfn + iov->offset +
+				    iov->stride * vfid) >> 8);
+}
+
+static int bnx2x_vf_devfn(struct bnx2x *bp, int vfid)
+{
+	struct pci_dev *dev = bp->pdev;
+	struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+	return (dev->devfn + iov->offset + iov->stride * vfid) & 0xff;
+}
+
+static void bnx2x_vf_set_bars(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	int i, n;
+	struct pci_dev *dev = bp->pdev;
+	struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+	for (i = 0, n = 0; i < PCI_SRIOV_NUM_BARS; i += 2, n++) {
+		u64 start = pci_resource_start(dev, PCI_IOV_RESOURCES + i);
+		u32 size = pci_resource_len(dev, PCI_IOV_RESOURCES + i);
+
+		size /= iov->total;
+		vf->bars[n].bar = start + size * vf->abs_vfid;
+		vf->bars[n].size = size;
+	}
+}
+
+static int bnx2x_ari_enabled(struct pci_dev *dev)
+{
+	return dev->bus->self && dev->bus->self->ari_enabled;
+}
+
+static void
+bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
+{
+	int sb_id;
+	u32 val;
+	u8 fid;
+
+	/* IGU in normal mode - read CAM */
+	for (sb_id = 0; sb_id < IGU_REG_MAPPING_MEMORY_SIZE; sb_id++) {
+		val = REG_RD(bp, IGU_REG_MAPPING_MEMORY + sb_id * 4);
+		if (!(val & IGU_REG_MAPPING_MEMORY_VALID))
+			continue;
+		fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
+		if (!(fid & IGU_FID_ENCODE_IS_PF))
+			bnx2x_vf_set_igu_info(bp, sb_id,
+					      (fid & IGU_FID_VF_NUM_MASK));
+
+		DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
+		   ((fid & IGU_FID_ENCODE_IS_PF) ? "PF" : "VF"),
+		   ((fid & IGU_FID_ENCODE_IS_PF) ? (fid & IGU_FID_PF_NUM_MASK) :
+		   (fid & IGU_FID_VF_NUM_MASK)), sb_id,
+		   GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR));
+	}
+}
+
+static void __bnx2x_iov_free_vfdb(struct bnx2x *bp)
+{
+	if (bp->vfdb) {
+		kfree(bp->vfdb->vfqs);
+		kfree(bp->vfdb->vfs);
+		kfree(bp->vfdb);
+	}
+	bp->vfdb = NULL;
+}
+
+static int bnx2x_sriov_pci_cfg_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
+{
+	int pos;
+	struct pci_dev *dev = bp->pdev;
+
+	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos) {
+		BNX2X_ERR("failed to find SRIOV capability in device\n");
+		return -ENODEV;
+	}
+
+	iov->pos = pos;
+	DP(BNX2X_MSG_IOV, "sriov ext pos %d\n", pos);
+	pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &iov->ctrl);
+	pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &iov->total);
+	pci_read_config_word(dev, pos + PCI_SRIOV_INITIAL_VF, &iov->initial);
+	pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &iov->offset);
+	pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &iov->stride);
+	pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz);
+	pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
+	pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
+
+	return 0;
+}
+
+static int bnx2x_sriov_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
+{
+	u32 val;
+
+	/* read the SRIOV capability structure
+	 * The fields can be read via configuration read or
+	 * directly from the device (starting at offset PCICFG_OFFSET)
+	 */
+	if (bnx2x_sriov_pci_cfg_info(bp, iov))
+		return -ENODEV;
+
+	/* get the number of SRIOV bars */
+	iov->nres = 0;
+
+	/* read the first_vfid */
+	val = REG_RD(bp, PCICFG_OFFSET + GRC_CONFIG_REG_PF_INIT_VF);
+	iov->first_vf_in_pf = ((val & GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK)
+			       * 8) - (BNX2X_MAX_NUM_OF_VFS * BP_PATH(bp));
+
+	DP(BNX2X_MSG_IOV,
+	   "IOV info[%d]: first vf %d, nres %d, cap 0x%x, ctrl 0x%x, total %d, initial %d, num vfs %d, offset %d, stride %d, page size 0x%x\n",
+	   BP_FUNC(bp),
+	   iov->first_vf_in_pf, iov->nres, iov->cap, iov->ctrl, iov->total,
+	   iov->initial, iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz);
+
+	return 0;
+}
+
+static u8 bnx2x_iov_get_max_queue_count(struct bnx2x *bp)
+{
+	int i;
+	u8 queue_count = 0;
+
+	if (IS_SRIOV(bp))
+		for_each_vf(bp, i)
+			queue_count += bnx2x_vf(bp, i, alloc_resc.num_sbs);
+
+	return queue_count;
+}
+
+/* must be called after PF bars are mapped */
+int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+			int num_vfs_param)
+{
+	int err, i, qcount;
+	struct bnx2x_sriov *iov;
+	struct pci_dev *dev = bp->pdev;
+
+	bp->vfdb = NULL;
+
+	/* verify is pf */
+	if (IS_VF(bp))
+		return 0;
+
+	/* verify sriov capability is present in configuration space */
+	if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV))
+		return 0;
+
+	/* verify chip revision */
+	if (CHIP_IS_E1x(bp))
+		return 0;
+
+	/* check if SRIOV support is turned off */
+	if (!num_vfs_param)
+		return 0;
+
+	/* SRIOV assumes that num of PF CIDs < BNX2X_FIRST_VF_CID */
+	if (BNX2X_L2_MAX_CID(bp) >= BNX2X_FIRST_VF_CID) {
+		BNX2X_ERR("PF cids %d are overspilling into vf space (starts at %d). Abort SRIOV\n",
+			  BNX2X_L2_MAX_CID(bp), BNX2X_FIRST_VF_CID);
+		return 0;
+	}
+
+	/* SRIOV can be enabled only with MSIX */
+	if (int_mode_param == BNX2X_INT_MODE_MSI ||
+	    int_mode_param == BNX2X_INT_MODE_INTX)
+		BNX2X_ERR("Forced MSI/INTx mode is incompatible with SRIOV\n");
+
+	err = -EIO;
+	/* verify ari is enabled */
+	if (!bnx2x_ari_enabled(bp->pdev)) {
+		BNX2X_ERR("ARI not supported, SRIOV can not be enabled\n");
+		return err;
+	}
+
+	/* verify igu is in normal mode */
+	if (CHIP_INT_MODE_IS_BC(bp)) {
+		BNX2X_ERR("IGU not normal mode,  SRIOV can not be enabled\n");
+		return err;
+	}
+
+	/* allocate the vfs database */
+	bp->vfdb = kzalloc(sizeof(*(bp->vfdb)), GFP_KERNEL);
+	if (!bp->vfdb) {
+		BNX2X_ERR("failed to allocate vf database\n");
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	/* get the sriov info - Linux already collected all the pertinent
+	 * information, however the sriov structure is for the private use
+	 * of the pci module. Also we want this information regardless
+	 * of the hyper-visor.
+	 */
+	iov = &(bp->vfdb->sriov);
+	err = bnx2x_sriov_info(bp, iov);
+	if (err)
+		goto failed;
+
+	/* SR-IOV capability was enabled but there are no VFs*/
+	if (iov->total == 0)
+		goto failed;
+
+	/* calculate the actual number of VFs */
+	iov->nr_virtfn = min_t(u16, iov->total, (u16)num_vfs_param);
+
+	/* allocate the vf array */
+	bp->vfdb->vfs = kzalloc(sizeof(struct bnx2x_virtf) *
+				BNX2X_NR_VIRTFN(bp), GFP_KERNEL);
+	if (!bp->vfdb->vfs) {
+		BNX2X_ERR("failed to allocate vf array\n");
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	/* Initial VF init - index and abs_vfid - nr_virtfn must be set */
+	for_each_vf(bp, i) {
+		bnx2x_vf(bp, i, index) = i;
+		bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
+		bnx2x_vf(bp, i, state) = VF_FREE;
+		INIT_LIST_HEAD(&bnx2x_vf(bp, i, op_list_head));
+		mutex_init(&bnx2x_vf(bp, i, op_mutex));
+		bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
+	}
+
+	/* re-read the IGU CAM for VFs - index and abs_vfid must be set */
+	bnx2x_get_vf_igu_cam_info(bp);
+
+	/* get the total queue count and allocate the global queue arrays */
+	qcount = bnx2x_iov_get_max_queue_count(bp);
+
+	/* allocate the queue arrays for all VFs */
+	bp->vfdb->vfqs = kzalloc(qcount * sizeof(struct bnx2x_vf_queue),
+				 GFP_KERNEL);
+	if (!bp->vfdb->vfqs) {
+		BNX2X_ERR("failed to allocate vf queue array\n");
+		err = -ENOMEM;
+		goto failed;
+	}
+
+	return 0;
+failed:
+	DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
+	__bnx2x_iov_free_vfdb(bp);
+	return err;
+}
+
+void bnx2x_iov_remove_one(struct bnx2x *bp)
+{
+	/* if SRIOV is not enabled there's nothing to do */
+	if (!IS_SRIOV(bp))
+		return;
+
+	DP(BNX2X_MSG_IOV, "about to call disable sriov\n");
+	pci_disable_sriov(bp->pdev);
+	DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+	/* free vf database */
+	__bnx2x_iov_free_vfdb(bp);
+}
+
+void bnx2x_iov_free_mem(struct bnx2x *bp)
+{
+	int i;
+
+	if (!IS_SRIOV(bp))
+		return;
+
+	/* free vfs hw contexts */
+	for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+		struct hw_dma *cxt = &bp->vfdb->context[i];
+		BNX2X_PCI_FREE(cxt->addr, cxt->mapping, cxt->size);
+	}
+
+	BNX2X_PCI_FREE(BP_VFDB(bp)->sp_dma.addr,
+		       BP_VFDB(bp)->sp_dma.mapping,
+		       BP_VFDB(bp)->sp_dma.size);
+
+	BNX2X_PCI_FREE(BP_VF_MBX_DMA(bp)->addr,
+		       BP_VF_MBX_DMA(bp)->mapping,
+		       BP_VF_MBX_DMA(bp)->size);
+
+	BNX2X_PCI_FREE(BP_VF_BULLETIN_DMA(bp)->addr,
+		       BP_VF_BULLETIN_DMA(bp)->mapping,
+		       BP_VF_BULLETIN_DMA(bp)->size);
+}
+
+int bnx2x_iov_alloc_mem(struct bnx2x *bp)
+{
+	size_t tot_size;
+	int i, rc = 0;
+
+	if (!IS_SRIOV(bp))
+		return rc;
+
+	/* allocate vfs hw contexts */
+	tot_size = (BP_VFDB(bp)->sriov.first_vf_in_pf + BNX2X_NR_VIRTFN(bp)) *
+		BNX2X_CIDS_PER_VF * sizeof(union cdu_context);
+
+	for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+		struct hw_dma *cxt = BP_VF_CXT_PAGE(bp, i);
+		cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ);
+
+		if (cxt->size) {
+			BNX2X_PCI_ALLOC(cxt->addr, &cxt->mapping, cxt->size);
+		} else {
+			cxt->addr = NULL;
+			cxt->mapping = 0;
+		}
+		tot_size -= cxt->size;
+	}
+
+	/* allocate vfs ramrods dma memory - client_init and set_mac */
+	tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp);
+	BNX2X_PCI_ALLOC(BP_VFDB(bp)->sp_dma.addr, &BP_VFDB(bp)->sp_dma.mapping,
+			tot_size);
+	BP_VFDB(bp)->sp_dma.size = tot_size;
+
+	/* allocate mailboxes */
+	tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE;
+	BNX2X_PCI_ALLOC(BP_VF_MBX_DMA(bp)->addr, &BP_VF_MBX_DMA(bp)->mapping,
+			tot_size);
+	BP_VF_MBX_DMA(bp)->size = tot_size;
+
+	/* allocate local bulletin boards */
+	tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
+	BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr,
+			&BP_VF_BULLETIN_DMA(bp)->mapping, tot_size);
+	BP_VF_BULLETIN_DMA(bp)->size = tot_size;
+
+	return 0;
+
+alloc_mem_err:
+	return -ENOMEM;
+}
+
+static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			   struct bnx2x_vf_queue *q)
+{
+	u8 cl_id = vfq_cl_id(vf, q);
+	u8 func_id = FW_VF_HANDLE(vf->abs_vfid);
+	unsigned long q_type = 0;
+
+	set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+	set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+
+	/* Queue State object */
+	bnx2x_init_queue_obj(bp, &q->sp_obj,
+			     cl_id, &q->cid, 1, func_id,
+			     bnx2x_vf_sp(bp, vf, q_data),
+			     bnx2x_vf_sp_map(bp, vf, q_data),
+			     q_type);
+
+	DP(BNX2X_MSG_IOV,
+	   "initialized vf %d's queue object. func id set to %d\n",
+	   vf->abs_vfid, q->sp_obj.func_id);
+
+	/* mac/vlan objects are per queue, but only those
+	 * that belong to the leading queue are initialized
+	 */
+	if (vfq_is_leading(q)) {
+		/* mac */
+		bnx2x_init_mac_obj(bp, &q->mac_obj,
+				   cl_id, q->cid, func_id,
+				   bnx2x_vf_sp(bp, vf, mac_rdata),
+				   bnx2x_vf_sp_map(bp, vf, mac_rdata),
+				   BNX2X_FILTER_MAC_PENDING,
+				   &vf->filter_state,
+				   BNX2X_OBJ_TYPE_RX_TX,
+				   &bp->macs_pool);
+		/* vlan */
+		bnx2x_init_vlan_obj(bp, &q->vlan_obj,
+				    cl_id, q->cid, func_id,
+				    bnx2x_vf_sp(bp, vf, vlan_rdata),
+				    bnx2x_vf_sp_map(bp, vf, vlan_rdata),
+				    BNX2X_FILTER_VLAN_PENDING,
+				    &vf->filter_state,
+				    BNX2X_OBJ_TYPE_RX_TX,
+				    &bp->vlans_pool);
+
+		/* mcast */
+		bnx2x_init_mcast_obj(bp, &vf->mcast_obj, cl_id,
+				     q->cid, func_id, func_id,
+				     bnx2x_vf_sp(bp, vf, mcast_rdata),
+				     bnx2x_vf_sp_map(bp, vf, mcast_rdata),
+				     BNX2X_FILTER_MCAST_PENDING,
+				     &vf->filter_state,
+				     BNX2X_OBJ_TYPE_RX_TX);
+
+		vf->leading_rss = cl_id;
+	}
+}
+
+/* called by bnx2x_nic_load */
+int bnx2x_iov_nic_init(struct bnx2x *bp)
+{
+	int vfid, qcount, i;
+
+	if (!IS_SRIOV(bp)) {
+		DP(BNX2X_MSG_IOV, "vfdb was not allocated\n");
+		return 0;
+	}
+
+	DP(BNX2X_MSG_IOV, "num of vfs: %d\n", (bp)->vfdb->sriov.nr_virtfn);
+
+	/* initialize vf database */
+	for_each_vf(bp, vfid) {
+		struct bnx2x_virtf *vf = BP_VF(bp, vfid);
+
+		int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vfid) *
+			BNX2X_CIDS_PER_VF;
+
+		union cdu_context *base_cxt = (union cdu_context *)
+			BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
+			(base_vf_cid & (ILT_PAGE_CIDS-1));
+
+		DP(BNX2X_MSG_IOV,
+		   "VF[%d] Max IGU SBs: %d, base vf cid 0x%x, base cid 0x%x, base cxt %p\n",
+		   vf->abs_vfid, vf_sb_count(vf), base_vf_cid,
+		   BNX2X_FIRST_VF_CID + base_vf_cid, base_cxt);
+
+		/* init statically provisioned resources */
+		bnx2x_iov_static_resc(bp, &vf->alloc_resc);
+
+		/* queues are initialized during VF-ACQUIRE */
+
+		/* reserve the vf vlan credit */
+		bp->vlans_pool.get(&bp->vlans_pool, vf_vlan_rules_cnt(vf));
+
+		vf->filter_state = 0;
+		vf->sp_cl_id = bnx2x_fp(bp, 0, cl_id);
+
+		/*  init mcast object - This object will be re-initialized
+		 *  during VF-ACQUIRE with the proper cl_id and cid.
+		 *  It needs to be initialized here so that it can be safely
+		 *  handled by a subsequent FLR flow.
+		 */
+		bnx2x_init_mcast_obj(bp, &vf->mcast_obj, 0xFF,
+				     0xFF, 0xFF, 0xFF,
+				     bnx2x_vf_sp(bp, vf, mcast_rdata),
+				     bnx2x_vf_sp_map(bp, vf, mcast_rdata),
+				     BNX2X_FILTER_MCAST_PENDING,
+				     &vf->filter_state,
+				     BNX2X_OBJ_TYPE_RX_TX);
+
+		/* set the mailbox message addresses */
+		BP_VF_MBX(bp, vfid)->msg = (struct bnx2x_vf_mbx_msg *)
+			(((u8 *)BP_VF_MBX_DMA(bp)->addr) + vfid *
+			MBX_MSG_ALIGNED_SIZE);
+
+		BP_VF_MBX(bp, vfid)->msg_mapping = BP_VF_MBX_DMA(bp)->mapping +
+			vfid * MBX_MSG_ALIGNED_SIZE;
+
+		/* Enable vf mailbox */
+		bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+	}
+
+	/* Final VF init */
+	qcount = 0;
+	for_each_vf(bp, i) {
+		struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+		/* fill in the BDF and bars */
+		vf->bus = bnx2x_vf_bus(bp, i);
+		vf->devfn = bnx2x_vf_devfn(bp, i);
+		bnx2x_vf_set_bars(bp, vf);
+
+		DP(BNX2X_MSG_IOV,
+		   "VF info[%d]: bus 0x%x, devfn 0x%x, bar0 [0x%x, %d], bar1 [0x%x, %d], bar2 [0x%x, %d]\n",
+		   vf->abs_vfid, vf->bus, vf->devfn,
+		   (unsigned)vf->bars[0].bar, vf->bars[0].size,
+		   (unsigned)vf->bars[1].bar, vf->bars[1].size,
+		   (unsigned)vf->bars[2].bar, vf->bars[2].size);
+
+		/* set local queue arrays */
+		vf->vfqs = &bp->vfdb->vfqs[qcount];
+		qcount += bnx2x_vf(bp, i, alloc_resc.num_sbs);
+	}
+
+	return 0;
+}
+
+/* called by bnx2x_chip_cleanup */
+int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
+{
+	int i;
+
+	if (!IS_SRIOV(bp))
+		return 0;
+
+	/* release all the VFs */
+	for_each_vf(bp, i)
+		bnx2x_vf_release(bp, BP_VF(bp, i), true); /* blocking */
+
+	return 0;
+}
+
+/* called by bnx2x_init_hw_func, returns the next ilt line */
+int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line)
+{
+	int i;
+	struct bnx2x_ilt *ilt = BP_ILT(bp);
+
+	if (!IS_SRIOV(bp))
+		return line;
+
+	/* set vfs ilt lines */
+	for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+		struct hw_dma *hw_cxt = BP_VF_CXT_PAGE(bp, i);
+
+		ilt->lines[line+i].page = hw_cxt->addr;
+		ilt->lines[line+i].page_mapping = hw_cxt->mapping;
+		ilt->lines[line+i].size = hw_cxt->size; /* doesn't matter */
+	}
+	return line + i;
+}
+
+static u8 bnx2x_iov_is_vf_cid(struct bnx2x *bp, u16 cid)
+{
+	return ((cid >= BNX2X_FIRST_VF_CID) &&
+		((cid - BNX2X_FIRST_VF_CID) < BNX2X_VF_CIDS));
+}
+
+static
+void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
+					struct bnx2x_vf_queue *vfq,
+					union event_ring_elem *elem)
+{
+	unsigned long ramrod_flags = 0;
+	int rc = 0;
+
+	/* Always push next commands out, don't wait here */
+	set_bit(RAMROD_CONT, &ramrod_flags);
+
+	switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+	case BNX2X_FILTER_MAC_PENDING:
+		rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,
+					   &ramrod_flags);
+		break;
+	case BNX2X_FILTER_VLAN_PENDING:
+		rc = vfq->vlan_obj.complete(bp, &vfq->vlan_obj, elem,
+					    &ramrod_flags);
+		break;
+	default:
+		BNX2X_ERR("Unsupported classification command: %d\n",
+			  elem->message.data.eth_event.echo);
+		return;
+	}
+	if (rc < 0)
+		BNX2X_ERR("Failed to schedule new commands: %d\n", rc);
+	else if (rc > 0)
+		DP(BNX2X_MSG_IOV, "Scheduled next pending commands...\n");
+}
+
+static
+void bnx2x_vf_handle_mcast_eqe(struct bnx2x *bp,
+			       struct bnx2x_virtf *vf)
+{
+	struct bnx2x_mcast_ramrod_params rparam = {NULL};
+	int rc;
+
+	rparam.mcast_obj = &vf->mcast_obj;
+	vf->mcast_obj.raw.clear_pending(&vf->mcast_obj.raw);
+
+	/* If there are pending mcast commands - send them */
+	if (vf->mcast_obj.check_pending(&vf->mcast_obj)) {
+		rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
+		if (rc < 0)
+			BNX2X_ERR("Failed to send pending mcast commands: %d\n",
+				  rc);
+	}
+}
+
+static
+void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp,
+				 struct bnx2x_virtf *vf)
+{
+	smp_mb__before_clear_bit();
+	clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+	smp_mb__after_clear_bit();
+}
+
+int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
+{
+	struct bnx2x_virtf *vf;
+	int qidx = 0, abs_vfid;
+	u8 opcode;
+	u16 cid = 0xffff;
+
+	if (!IS_SRIOV(bp))
+		return 1;
+
+	/* first get the cid - the only events we handle here are cfc-delete
+	 * and set-mac completion
+	 */
+	opcode = elem->message.opcode;
+
+	switch (opcode) {
+	case EVENT_RING_OPCODE_CFC_DEL:
+		cid = SW_CID((__force __le32)
+			     elem->message.data.cfc_del_event.cid);
+		DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);
+		break;
+	case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
+	case EVENT_RING_OPCODE_MULTICAST_RULES:
+	case EVENT_RING_OPCODE_FILTERS_RULES:
+		cid = (elem->message.data.eth_event.echo &
+		       BNX2X_SWCID_MASK);
+		DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
+		break;
+	case EVENT_RING_OPCODE_VF_FLR:
+		abs_vfid = elem->message.data.vf_flr_event.vf_id;
+		DP(BNX2X_MSG_IOV, "Got VF FLR notification abs_vfid=%d\n",
+		   abs_vfid);
+		goto get_vf;
+	case EVENT_RING_OPCODE_MALICIOUS_VF:
+		abs_vfid = elem->message.data.malicious_vf_event.vf_id;
+		DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d\n",
+		   abs_vfid);
+		goto get_vf;
+	default:
+		return 1;
+	}
+
+	/* check if the cid is the VF range */
+	if (!bnx2x_iov_is_vf_cid(bp, cid)) {
+		DP(BNX2X_MSG_IOV, "cid is outside vf range: %d\n", cid);
+		return 1;
+	}
+
+	/* extract vf and rxq index from vf_cid - relies on the following:
+	 * 1. vfid on cid reflects the true abs_vfid
+	 * 2. the max number of VFs (per path) is 64
+	 */
+	qidx = cid & ((1 << BNX2X_VF_CID_WND)-1);
+	abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
+get_vf:
+	vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+
+	if (!vf) {
+		BNX2X_ERR("EQ completion for unknown VF, cid %d, abs_vfid %d\n",
+			  cid, abs_vfid);
+		return 0;
+	}
+
+	switch (opcode) {
+	case EVENT_RING_OPCODE_CFC_DEL:
+		DP(BNX2X_MSG_IOV, "got VF [%d:%d] cfc delete ramrod\n",
+		   vf->abs_vfid, qidx);
+		vfq_get(vf, qidx)->sp_obj.complete_cmd(bp,
+						       &vfq_get(vf,
+								qidx)->sp_obj,
+						       BNX2X_Q_CMD_CFC_DEL);
+		break;
+	case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
+		DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mac/vlan ramrod\n",
+		   vf->abs_vfid, qidx);
+		bnx2x_vf_handle_classification_eqe(bp, vfq_get(vf, qidx), elem);
+		break;
+	case EVENT_RING_OPCODE_MULTICAST_RULES:
+		DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mcast ramrod\n",
+		   vf->abs_vfid, qidx);
+		bnx2x_vf_handle_mcast_eqe(bp, vf);
+		break;
+	case EVENT_RING_OPCODE_FILTERS_RULES:
+		DP(BNX2X_MSG_IOV, "got VF [%d:%d] set rx-mode ramrod\n",
+		   vf->abs_vfid, qidx);
+		bnx2x_vf_handle_filters_eqe(bp, vf);
+		break;
+	case EVENT_RING_OPCODE_VF_FLR:
+		DP(BNX2X_MSG_IOV, "got VF [%d] FLR notification\n",
+		   vf->abs_vfid);
+		/* Do nothing for now */
+		break;
+	case EVENT_RING_OPCODE_MALICIOUS_VF:
+		DP(BNX2X_MSG_IOV, "got VF [%d] MALICIOUS notification\n",
+		   vf->abs_vfid);
+		/* Do nothing for now */
+		break;
+	}
+	/* SRIOV: reschedule any 'in_progress' operations */
+	bnx2x_iov_sp_event(bp, cid, false);
+
+	return 0;
+}
+
+static struct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid)
+{
+	/* extract the vf from vf_cid - relies on the following:
+	 * 1. vfid on cid reflects the true abs_vfid
+	 * 2. the max number of VFs (per path) is 64
+	 */
+	int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
+	return bnx2x_vf_by_abs_fid(bp, abs_vfid);
+}
+
+void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+				struct bnx2x_queue_sp_obj **q_obj)
+{
+	struct bnx2x_virtf *vf;
+
+	if (!IS_SRIOV(bp))
+		return;
+
+	vf = bnx2x_vf_by_cid(bp, vf_cid);
+
+	if (vf) {
+		/* extract queue index from vf_cid - relies on the following:
+		 * 1. vfid on cid reflects the true abs_vfid
+		 * 2. the max number of VFs (per path) is 64
+		 */
+		int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1);
+		*q_obj = &bnx2x_vfq(vf, q_index, sp_obj);
+	} else {
+		BNX2X_ERR("No vf matching cid %d\n", vf_cid);
+	}
+}
+
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
+{
+	struct bnx2x_virtf *vf;
+
+	/* check if the cid is the VF range */
+	if (!IS_SRIOV(bp) || !bnx2x_iov_is_vf_cid(bp, vf_cid))
+		return;
+
+	vf = bnx2x_vf_by_cid(bp, vf_cid);
+	if (vf) {
+		/* set in_progress flag */
+		atomic_set(&vf->op_in_progress, 1);
+		if (queue_work)
+			queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+	}
+}
+
+void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
+{
+	int i;
+	int first_queue_query_index, num_queues_req;
+	dma_addr_t cur_data_offset;
+	struct stats_query_entry *cur_query_entry;
+	u8 stats_count = 0;
+	bool is_fcoe = false;
+
+	if (!IS_SRIOV(bp))
+		return;
+
+	if (!NO_FCOE(bp))
+		is_fcoe = true;
+
+	/* fcoe adds one global request and one queue request */
+	num_queues_req = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe;
+	first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
+		(is_fcoe ? 0 : 1);
+
+	DP(BNX2X_MSG_IOV,
+	   "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
+	   BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
+	   first_queue_query_index + num_queues_req);
+
+	cur_data_offset = bp->fw_stats_data_mapping +
+		offsetof(struct bnx2x_fw_stats_data, queue_stats) +
+		num_queues_req * sizeof(struct per_queue_stats);
+
+	cur_query_entry = &bp->fw_stats_req->
+		query[first_queue_query_index + num_queues_req];
+
+	for_each_vf(bp, i) {
+		int j;
+		struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+		if (vf->state != VF_ENABLED) {
+			DP(BNX2X_MSG_IOV,
+			   "vf %d not enabled so no stats for it\n",
+			   vf->abs_vfid);
+			continue;
+		}
+
+		DP(BNX2X_MSG_IOV, "add addresses for vf %d\n", vf->abs_vfid);
+		for_each_vfq(vf, j) {
+			struct bnx2x_vf_queue *rxq = vfq_get(vf, j);
+
+			/* collect stats fro active queues only */
+			if (bnx2x_get_q_logical_state(bp, &rxq->sp_obj) ==
+			    BNX2X_Q_LOGICAL_STATE_STOPPED)
+				continue;
+
+			/* create stats query entry for this queue */
+			cur_query_entry->kind = STATS_TYPE_QUEUE;
+			cur_query_entry->index = vfq_cl_id(vf, rxq);
+			cur_query_entry->funcID =
+				cpu_to_le16(FW_VF_HANDLE(vf->abs_vfid));
+			cur_query_entry->address.hi =
+				cpu_to_le32(U64_HI(vf->fw_stat_map));
+			cur_query_entry->address.lo =
+				cpu_to_le32(U64_LO(vf->fw_stat_map));
+			DP(BNX2X_MSG_IOV,
+			   "added address %x %x for vf %d queue %d client %d\n",
+			   cur_query_entry->address.hi,
+			   cur_query_entry->address.lo, cur_query_entry->funcID,
+			   j, cur_query_entry->index);
+			cur_query_entry++;
+			cur_data_offset += sizeof(struct per_queue_stats);
+			stats_count++;
+		}
+	}
+	bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
+}
+
+void bnx2x_iov_sp_task(struct bnx2x *bp)
+{
+	int i;
+
+	if (!IS_SRIOV(bp))
+		return;
+	/* Iterate over all VFs and invoke state transition for VFs with
+	 * 'in-progress' slow-path operations
+	 */
+	DP(BNX2X_MSG_IOV, "searching for pending vf operations\n");
+	for_each_vf(bp, i) {
+		struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+		if (!list_empty(&vf->op_list_head) &&
+		    atomic_read(&vf->op_in_progress)) {
+			DP(BNX2X_MSG_IOV, "running pending op for vf %d\n", i);
+			bnx2x_vfop_cur(bp, vf)->transition(bp, vf);
+		}
+	}
+}
+
+static inline
+struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
+{
+	int i;
+	struct bnx2x_virtf *vf = NULL;
+
+	for_each_vf(bp, i) {
+		vf = BP_VF(bp, i);
+		if (stat_id >= vf->igu_base_id &&
+		    stat_id < vf->igu_base_id + vf_sb_count(vf))
+			break;
+	}
+	return vf;
+}
+
+/* VF API helpers */
+static void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
+				u8 enable)
+{
+	u32 reg = PXP_REG_HST_ZONE_PERMISSION_TABLE + qid * 4;
+	u32 val = enable ? (abs_vfid | (1 << 6)) : 0;
+
+	REG_WR(bp, reg, val);
+}
+
+static void bnx2x_vf_clr_qtbl(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	int i;
+
+	for_each_vfq(vf, i)
+		bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
+				    vfq_qzone_id(vf, vfq_get(vf, i)), false);
+}
+
+static void bnx2x_vf_igu_disable(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	u32 val;
+
+	/* clear the VF configuration - pretend */
+	bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+	val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
+	val &= ~(IGU_VF_CONF_MSI_MSIX_EN | IGU_VF_CONF_SINGLE_ISR_EN |
+		 IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_PARENT_MASK);
+	REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
+	bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	return min_t(u8, min_t(u8, vf_sb_count(vf), BNX2X_CIDS_PER_VF),
+		     BNX2X_VF_MAX_QUEUES);
+}
+
+static
+int bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			    struct vf_pf_resc_request *req_resc)
+{
+	u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
+	u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
+
+	return ((req_resc->num_rxqs <= rxq_cnt) &&
+		(req_resc->num_txqs <= txq_cnt) &&
+		(req_resc->num_sbs <= vf_sb_count(vf))   &&
+		(req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) &&
+		(req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf)));
+}
+
+/* CORE VF API */
+int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+		     struct vf_pf_resc_request *resc)
+{
+	int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vf->index) *
+		BNX2X_CIDS_PER_VF;
+
+	union cdu_context *base_cxt = (union cdu_context *)
+		BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
+		(base_vf_cid & (ILT_PAGE_CIDS-1));
+	int i;
+
+	/* if state is 'acquired' the VF was not released or FLR'd, in
+	 * this case the returned resources match the acquired already
+	 * acquired resources. Verify that the requested numbers do
+	 * not exceed the already acquired numbers.
+	 */
+	if (vf->state == VF_ACQUIRED) {
+		DP(BNX2X_MSG_IOV, "VF[%d] Trying to re-acquire resources (VF was not released or FLR'd)\n",
+		   vf->abs_vfid);
+
+		if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
+			BNX2X_ERR("VF[%d] When re-acquiring resources, requested numbers must be <= then previously acquired numbers\n",
+				  vf->abs_vfid);
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	/* Otherwise vf state must be 'free' or 'reset' */
+	if (vf->state != VF_FREE && vf->state != VF_RESET) {
+		BNX2X_ERR("VF[%d] Can not acquire a VF with state %d\n",
+			  vf->abs_vfid, vf->state);
+		return -EINVAL;
+	}
+
+	/* static allocation:
+	 * the global maximum number are fixed per VF. fail the request if
+	 * requested number exceed these globals
+	 */
+	if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
+		DP(BNX2X_MSG_IOV,
+		   "cannot fulfill vf resource request. Placing maximal available values in response\n");
+		/* set the max resource in the vf */
+		return -ENOMEM;
+	}
+
+	/* Set resources counters - 0 request means max available */
+	vf_sb_count(vf) = resc->num_sbs;
+	vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
+	vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
+	if (resc->num_mac_filters)
+		vf_mac_rules_cnt(vf) = resc->num_mac_filters;
+	if (resc->num_vlan_filters)
+		vf_vlan_rules_cnt(vf) = resc->num_vlan_filters;
+
+	DP(BNX2X_MSG_IOV,
+	   "Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n",
+	   vf_sb_count(vf), vf_rxq_count(vf),
+	   vf_txq_count(vf), vf_mac_rules_cnt(vf),
+	   vf_vlan_rules_cnt(vf));
+
+	/* Initialize the queues */
+	if (!vf->vfqs) {
+		DP(BNX2X_MSG_IOV, "vf->vfqs was not allocated\n");
+		return -EINVAL;
+	}
+
+	for_each_vfq(vf, i) {
+		struct bnx2x_vf_queue *q = vfq_get(vf, i);
+
+		if (!q) {
+			DP(BNX2X_MSG_IOV, "q number %d was not allocated\n", i);
+			return -EINVAL;
+		}
+
+		q->index = i;
+		q->cxt = &((base_cxt + i)->eth);
+		q->cid = BNX2X_FIRST_VF_CID + base_vf_cid + i;
+
+		DP(BNX2X_MSG_IOV, "VFQ[%d:%d]: index %d, cid 0x%x, cxt %p\n",
+		   vf->abs_vfid, i, q->index, q->cid, q->cxt);
+
+		/* init SP objects */
+		bnx2x_vfq_init(bp, vf, q);
+	}
+	vf->state = VF_ACQUIRED;
+	return 0;
+}
+
+int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)
+{
+	struct bnx2x_func_init_params func_init = {0};
+	u16 flags = 0;
+	int i;
+
+	/* the sb resources are initialized at this point, do the
+	 * FW/HW initializations
+	 */
+	for_each_vf_sb(vf, i)
+		bnx2x_init_sb(bp, (dma_addr_t)sb_map[i], vf->abs_vfid, true,
+			      vf_igu_sb(vf, i), vf_igu_sb(vf, i));
+
+	/* Sanity checks */
+	if (vf->state != VF_ACQUIRED) {
+		DP(BNX2X_MSG_IOV, "VF[%d] is not in VF_ACQUIRED, but %d\n",
+		   vf->abs_vfid, vf->state);
+		return -EINVAL;
+	}
+	/* FLR cleanup epilogue */
+	if (bnx2x_vf_flr_clnup_epilog(bp, vf->abs_vfid))
+		return -EBUSY;
+
+	/* reset IGU VF statistics: MSIX */
+	REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + vf->abs_vfid * 4 , 0);
+
+	/* vf init */
+	if (vf->cfg_flags & VF_CFG_STATS)
+		flags |= (FUNC_FLG_STATS | FUNC_FLG_SPQ);
+
+	if (vf->cfg_flags & VF_CFG_TPA)
+		flags |= FUNC_FLG_TPA;
+
+	if (is_vf_multi(vf))
+		flags |= FUNC_FLG_RSS;
+
+	/* function setup */
+	func_init.func_flgs = flags;
+	func_init.pf_id = BP_FUNC(bp);
+	func_init.func_id = FW_VF_HANDLE(vf->abs_vfid);
+	func_init.fw_stat_map = vf->fw_stat_map;
+	func_init.spq_map = vf->spq_map;
+	func_init.spq_prod = 0;
+	bnx2x_func_init(bp, &func_init);
+
+	/* Enable the vf */
+	bnx2x_vf_enable_access(bp, vf->abs_vfid);
+	bnx2x_vf_enable_traffic(bp, vf);
+
+	/* queue protection table */
+	for_each_vfq(vf, i)
+		bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
+				    vfq_qzone_id(vf, vfq_get(vf, i)), true);
+
+	vf->state = VF_ENABLED;
+
+	/* update vf bulletin board */
+	bnx2x_post_vf_bulletin(bp, vf->index);
+
+	return 0;
+}
+
+/* VFOP close (teardown the queues, delete mcasts and close HW) */
+static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
+	enum bnx2x_vfop_close_state state = vfop->state;
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vfop_close,
+		.block = false,
+	};
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+	switch (state) {
+	case BNX2X_VFOP_CLOSE_QUEUES:
+
+		if (++(qx->qid) < vf_rxq_count(vf)) {
+			vfop->rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qx->qid);
+			if (vfop->rc)
+				goto op_err;
+			return;
+		}
+
+		/* remove multicasts */
+		vfop->state = BNX2X_VFOP_CLOSE_HW;
+		vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case BNX2X_VFOP_CLOSE_HW:
+
+		/* disable the interrupts */
+		DP(BNX2X_MSG_IOV, "disabling igu\n");
+		bnx2x_vf_igu_disable(bp, vf);
+
+		/* disable the VF */
+		DP(BNX2X_MSG_IOV, "clearing qtbl\n");
+		bnx2x_vf_clr_qtbl(bp, vf);
+
+		goto op_done;
+	default:
+		bnx2x_vfop_default(state);
+	}
+op_err:
+	BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+	vf->state = VF_ACQUIRED;
+	DP(BNX2X_MSG_IOV, "set state to acquired\n");
+	bnx2x_vfop_end(bp, vf, vfop);
+}
+
+int bnx2x_vfop_close_cmd(struct bnx2x *bp,
+			 struct bnx2x_virtf *vf,
+			 struct bnx2x_vfop_cmd *cmd)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+	if (vfop) {
+		vfop->args.qx.qid = -1; /* loop */
+		bnx2x_vfop_opset(BNX2X_VFOP_CLOSE_QUEUES,
+				 bnx2x_vfop_close, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_close,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VF release can be called either: 1. the VF was acquired but
+ * not enabled 2. the vf was enabled or in the process of being
+ * enabled
+ */
+static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vfop_release,
+		.block = false,
+	};
+
+	DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	DP(BNX2X_MSG_IOV, "VF[%d] STATE: %s\n", vf->abs_vfid,
+	   vf->state == VF_FREE ? "Free" :
+	   vf->state == VF_ACQUIRED ? "Acquired" :
+	   vf->state == VF_ENABLED ? "Enabled" :
+	   vf->state == VF_RESET ? "Reset" :
+	   "Unknown");
+
+	switch (vf->state) {
+	case VF_ENABLED:
+		vfop->rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
+		if (vfop->rc)
+			goto op_err;
+		return;
+
+	case VF_ACQUIRED:
+		DP(BNX2X_MSG_IOV, "about to free resources\n");
+		bnx2x_vf_free_resc(bp, vf);
+		DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
+		goto op_done;
+
+	case VF_FREE:
+	case VF_RESET:
+		/* do nothing */
+		goto op_done;
+	default:
+		bnx2x_vfop_default(vf->state);
+	}
+op_err:
+	BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+	bnx2x_vfop_end(bp, vf, vfop);
+}
+
+int bnx2x_vfop_release_cmd(struct bnx2x *bp,
+			   struct bnx2x_virtf *vf,
+			   struct bnx2x_vfop_cmd *cmd)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+	if (vfop) {
+		bnx2x_vfop_opset(-1, /* use vf->state */
+				 bnx2x_vfop_release, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_release,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+/* VF release ~ VF close + VF release-resources
+ * Release is the ultimate SW shutdown and is called whenever an
+ * irrecoverable error is encountered.
+ */
+void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block)
+{
+	struct bnx2x_vfop_cmd cmd = {
+		.done = NULL,
+		.block = block,
+	};
+	int rc;
+	bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+
+	rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+	if (rc)
+		WARN(rc,
+		     "VF[%d] Failed to allocate resources for release op- rc=%d\n",
+		     vf->abs_vfid, rc);
+}
+
+static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
+			      struct bnx2x_virtf *vf, u32 *sbdf)
+{
+	*sbdf = vf->devfn | (vf->bus << 8);
+}
+
+static inline void bnx2x_vf_get_bars(struct bnx2x *bp, struct bnx2x_virtf *vf,
+		       struct bnx2x_vf_bar_info *bar_info)
+{
+	int n;
+
+	bar_info->nr_bars = bp->vfdb->sriov.nres;
+	for (n = 0; n < bar_info->nr_bars; n++)
+		bar_info->bars[n] = vf->bars[n];
+}
+
+void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			      enum channel_tlvs tlv)
+{
+	/* lock the channel */
+	mutex_lock(&vf->op_mutex);
+
+	/* record the locking op */
+	vf->op_current = tlv;
+
+	/* log the lock */
+	DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel locked by %d\n",
+	   vf->abs_vfid, tlv);
+}
+
+void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				enum channel_tlvs expected_tlv)
+{
+	WARN(expected_tlv != vf->op_current,
+	     "lock mismatch: expected %d found %d", expected_tlv,
+	     vf->op_current);
+
+	/* lock the channel */
+	mutex_unlock(&vf->op_mutex);
+
+	/* log the unlock */
+	DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
+	   vf->abs_vfid, vf->op_current);
+
+	/* record the locking op */
+	vf->op_current = CHANNEL_TLV_NONE;
+}
+
+void bnx2x_enable_sriov(struct bnx2x *bp)
+{
+	int rc = 0;
+
+	/* disbale sriov in case it is still enabled */
+	pci_disable_sriov(bp->pdev);
+	DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+	/* enable sriov */
+	DP(BNX2X_MSG_IOV, "vf num (%d)\n", (bp->vfdb->sriov.nr_virtfn));
+	rc = pci_enable_sriov(bp->pdev, (bp->vfdb->sriov.nr_virtfn));
+	if (rc)
+		BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
+	else
+		DP(BNX2X_MSG_IOV, "sriov enabled\n");
+}
+
+/* New mac for VF. Consider these cases:
+ * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
+ *    supply at acquire.
+ * 2. VF has already been acquired but has not yet initialized - store in local
+ *    bulletin board. mac will be posted on VF bulletin board after VF init. VF
+ *    will configure this mac when it is ready.
+ * 3. VF has already initialized but has not yet setup a queue - post the new
+ *    mac on VF's bulletin board right now. VF will configure this mac when it
+ *    is ready.
+ * 4. VF has already set a queue - delete any macs already configured for this
+ *    queue and manually config the new mac.
+ * In any event, once this function has been called refuse any attempts by the
+ * VF to configure any mac for itself except for this mac. In case of a race
+ * where the VF fails to see the new post on its bulletin board before sending a
+ * mac configuration request, the PF will simply fail the request and VF can try
+ * again after consulting its bulletin board
+ */
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc, q_logical_state, vfidx = queue;
+	struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+	struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+	/* if SRIOV is disabled there is nothing to do (and somewhere, someone
+	 * has erred).
+	 */
+	if (!IS_SRIOV(bp)) {
+		BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
+		return -EINVAL;
+	}
+
+	if (!is_valid_ether_addr(mac)) {
+		BNX2X_ERR("mac address invalid\n");
+		return -EINVAL;
+	}
+
+	/* update PF's copy of the VF's bulletin. will no longer accept mac
+	 * configuration requests from vf unless match this mac
+	 */
+	bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
+	memcpy(bulletin->mac, mac, ETH_ALEN);
+
+	/* Post update on VF's bulletin board */
+	rc = bnx2x_post_vf_bulletin(bp, vfidx);
+	if (rc) {
+		BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
+		return rc;
+	}
+
+	/* is vf initialized and queue set up? */
+	q_logical_state =
+		bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
+	if (vf->state == VF_ENABLED &&
+	    q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+		/* configure the mac in device on this vf's queue */
+		unsigned long flags = 0;
+		struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+
+		/* must lock vfpf channel to protect against vf flows */
+		bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+
+		/* remove existing eth macs */
+		rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
+		if (rc) {
+			BNX2X_ERR("failed to delete eth macs\n");
+			return -EINVAL;
+		}
+
+		/* remove existing uc list macs */
+		rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
+		if (rc) {
+			BNX2X_ERR("failed to delete uc_list macs\n");
+			return -EINVAL;
+		}
+
+		/* configure the new mac to device */
+		__set_bit(RAMROD_COMP_WAIT, &flags);
+		bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
+				  BNX2X_ETH_MAC, &flags);
+
+		bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+	}
+
+	return rc;
+}
+
+/* crc is the first field in the bulletin board. compute the crc over the
+ * entire bulletin board excluding the crc field itself
+ */
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+			  struct pf_vf_bulletin_content *bulletin)
+{
+	return crc32(BULLETIN_CRC_SEED,
+		 ((u8 *)bulletin) + sizeof(bulletin->crc),
+		 bulletin->length - sizeof(bulletin->crc));
+}
+
+/* Check for new posts on the bulletin board */
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+	struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
+	int attempts;
+
+	/* bulletin board hasn't changed since last sample */
+	if (bp->old_bulletin.version == bulletin.version)
+		return PFVF_BULLETIN_UNCHANGED;
+
+	/* validate crc of new bulletin board */
+	if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
+		/* sampling structure in mid post may result with corrupted data
+		 * validate crc to ensure coherency.
+		 */
+		for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
+			bulletin = bp->pf2vf_bulletin->content;
+			if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
+								  &bulletin))
+				break;
+			BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
+				  bulletin.crc,
+				  bnx2x_crc_vf_bulletin(bp, &bulletin));
+		}
+		if (attempts >= BULLETIN_ATTEMPTS) {
+			BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
+				  attempts);
+			return PFVF_BULLETIN_CRC_ERR;
+		}
+	}
+
+	/* the mac address in bulletin board is valid and is new */
+	if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
+	    memcmp(bulletin.mac, bp->old_bulletin.mac, ETH_ALEN)) {
+		/* update new mac to net device */
+		memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+	}
+
+	/* copy new bulletin board to bp */
+	bp->old_bulletin = bulletin;
+
+	return PFVF_BULLETIN_UPDATED;
+}
+
+void bnx2x_vf_map_doorbells(struct bnx2x *bp)
+{
+	/* vf doorbells are embedded within the regview */
+	bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
+}
+
+int bnx2x_vf_pci_alloc(struct bnx2x *bp)
+{
+	/* allocate vf2pf mailbox for vf to pf channel */
+	BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
+			sizeof(struct bnx2x_vf_mbx_msg));
+
+	/* allocate pf 2 vf bulletin board */
+	BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
+			sizeof(union pf_vf_bulletin));
+
+	return 0;
+
+alloc_mem_err:
+	BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+		       sizeof(struct bnx2x_vf_mbx_msg));
+	BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+		       sizeof(union pf_vf_bulletin));
+	return -ENOMEM;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
new file mode 100644
index 0000000..b405017
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -0,0 +1,809 @@
+/* bnx2x_sriov.h: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ *	       Ariel Elior <ariele@broadcom.com>
+ */
+#ifndef BNX2X_SRIOV_H
+#define BNX2X_SRIOV_H
+
+#include "bnx2x_vfpf.h"
+#include "bnx2x.h"
+
+enum sample_bulletin_result {
+	   PFVF_BULLETIN_UNCHANGED,
+	   PFVF_BULLETIN_UPDATED,
+	   PFVF_BULLETIN_CRC_ERR
+};
+
+#ifdef CONFIG_BNX2X_SRIOV
+
+/* The bnx2x device structure holds vfdb structure described below.
+ * The VF array is indexed by the relative vfid.
+ */
+#define BNX2X_VF_MAX_QUEUES		16
+#define BNX2X_VF_MAX_TPA_AGG_QUEUES	8
+
+struct bnx2x_sriov {
+	u32 first_vf_in_pf;
+
+	/* standard SRIOV capability fields, mostly for debugging */
+	int pos;		/* capability position */
+	int nres;		/* number of resources */
+	u32 cap;		/* SR-IOV Capabilities */
+	u16 ctrl;		/* SR-IOV Control */
+	u16 total;		/* total VFs associated with the PF */
+	u16 initial;		/* initial VFs associated with the PF */
+	u16 nr_virtfn;		/* number of VFs available */
+	u16 offset;		/* first VF Routing ID offset */
+	u16 stride;		/* following VF stride */
+	u32 pgsz;		/* page size for BAR alignment */
+	u8 link;		/* Function Dependency Link */
+};
+
+/* bars */
+struct bnx2x_vf_bar {
+	u64 bar;
+	u32 size;
+};
+
+struct bnx2x_vf_bar_info {
+	struct bnx2x_vf_bar bars[PCI_SRIOV_NUM_BARS];
+	u8 nr_bars;
+};
+
+/* vf queue (used both for rx or tx) */
+struct bnx2x_vf_queue {
+	struct eth_context		*cxt;
+
+	/* MACs object */
+	struct bnx2x_vlan_mac_obj	mac_obj;
+
+	/* VLANs object */
+	struct bnx2x_vlan_mac_obj	vlan_obj;
+	atomic_t vlan_count;		/* 0 means vlan-0 is set  ~ untagged */
+
+	/* Queue Slow-path State object */
+	struct bnx2x_queue_sp_obj	sp_obj;
+
+	u32 cid;
+	u16 index;
+	u16 sb_idx;
+};
+
+/* struct bnx2x_vfop_qctor_params - prepare queue construction parameters:
+ * q-init, q-setup and SB index
+ */
+struct bnx2x_vfop_qctor_params {
+	struct bnx2x_queue_state_params		qstate;
+	struct bnx2x_queue_setup_params		prep_qsetup;
+};
+
+/* VFOP parameters (one copy per VF) */
+union bnx2x_vfop_params {
+	struct bnx2x_vlan_mac_ramrod_params	vlan_mac;
+	struct bnx2x_rx_mode_ramrod_params	rx_mode;
+	struct bnx2x_mcast_ramrod_params	mcast;
+	struct bnx2x_config_rss_params		rss;
+	struct bnx2x_vfop_qctor_params		qctor;
+};
+
+/* forward */
+struct bnx2x_virtf;
+
+/* VFOP definitions */
+typedef void (*vfop_handler_t)(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+struct bnx2x_vfop_cmd {
+	vfop_handler_t done;
+	bool block;
+};
+
+/* VFOP queue filters command additional arguments */
+struct bnx2x_vfop_filter {
+	struct list_head link;
+	int type;
+#define BNX2X_VFOP_FILTER_MAC	1
+#define BNX2X_VFOP_FILTER_VLAN	2
+
+	bool add;
+	u8 *mac;
+	u16 vid;
+};
+
+struct bnx2x_vfop_filters {
+	int add_cnt;
+	struct list_head head;
+	struct bnx2x_vfop_filter filters[];
+};
+
+/* transient list allocated, built and saved until its
+ * passed to the SP-VERBs layer.
+ */
+struct bnx2x_vfop_args_mcast {
+	int mc_num;
+	struct bnx2x_mcast_list_elem *mc;
+};
+
+struct bnx2x_vfop_args_qctor {
+	int	qid;
+	u16	sb_idx;
+};
+
+struct bnx2x_vfop_args_qdtor {
+	int	qid;
+	struct eth_context *cxt;
+};
+
+struct bnx2x_vfop_args_defvlan {
+	int	qid;
+	bool	enable;
+	u16	vid;
+	u8	prio;
+};
+
+struct bnx2x_vfop_args_qx {
+	int	qid;
+	bool	en_add;
+};
+
+struct bnx2x_vfop_args_filters {
+	struct bnx2x_vfop_filters *multi_filter;
+	atomic_t *credit;	/* non NULL means 'don't consume credit' */
+};
+
+union bnx2x_vfop_args {
+	struct bnx2x_vfop_args_mcast	mc_list;
+	struct bnx2x_vfop_args_qctor	qctor;
+	struct bnx2x_vfop_args_qdtor	qdtor;
+	struct bnx2x_vfop_args_defvlan	defvlan;
+	struct bnx2x_vfop_args_qx	qx;
+	struct bnx2x_vfop_args_filters	filters;
+};
+
+struct bnx2x_vfop {
+	struct list_head link;
+	int			rc;		/* return code */
+	int			state;		/* next state */
+	union bnx2x_vfop_args	args;		/* extra arguments */
+	union bnx2x_vfop_params *op_p;		/* ramrod params */
+
+	/* state machine callbacks */
+	vfop_handler_t transition;
+	vfop_handler_t done;
+};
+
+/* vf context */
+struct bnx2x_virtf {
+	u16 cfg_flags;
+#define VF_CFG_STATS		0x0001
+#define VF_CFG_FW_FC		0x0002
+#define VF_CFG_TPA		0x0004
+#define VF_CFG_INT_SIMD		0x0008
+#define VF_CACHE_LINE		0x0010
+
+	u8 state;
+#define VF_FREE		0	/* VF ready to be acquired holds no resc */
+#define VF_ACQUIRED	1	/* VF aquired, but not initalized */
+#define VF_ENABLED	2	/* VF Enabled */
+#define VF_RESET	3	/* VF FLR'd, pending cleanup */
+
+	/* non 0 during flr cleanup */
+	u8 flr_clnup_stage;
+#define VF_FLR_CLN	1	/* reclaim resources and do 'final cleanup'
+				 * sans the end-wait
+				 */
+#define VF_FLR_ACK	2	/* ACK flr notification */
+#define VF_FLR_EPILOG	3	/* wait for VF remnants to dissipate in the HW
+				 * ~ final cleanup' end wait
+				 */
+
+	/* dma */
+	dma_addr_t fw_stat_map;		/* valid iff VF_CFG_STATS */
+	dma_addr_t spq_map;
+	dma_addr_t bulletin_map;
+
+	/* Allocated resources counters. Before the VF is acquired, the
+	 * counters hold the following values:
+	 *
+	 * - xxq_count = 0 as the queues memory is not allocated yet.
+	 *
+	 * - sb_count  = The number of status blocks configured for this VF in
+	 *		 the IGU CAM. Initially read during probe.
+	 *
+	 * - xx_rules_count = The number of rules statically and equally
+	 *		      allocated for each VF, during PF load.
+	 */
+	struct vf_pf_resc_request	alloc_resc;
+#define vf_rxq_count(vf)		((vf)->alloc_resc.num_rxqs)
+#define vf_txq_count(vf)		((vf)->alloc_resc.num_txqs)
+#define vf_sb_count(vf)			((vf)->alloc_resc.num_sbs)
+#define vf_mac_rules_cnt(vf)		((vf)->alloc_resc.num_mac_filters)
+#define vf_vlan_rules_cnt(vf)		((vf)->alloc_resc.num_vlan_filters)
+#define vf_mc_rules_cnt(vf)		((vf)->alloc_resc.num_mc_filters)
+
+	u8 sb_count;	/* actual number of SBs */
+	u8 igu_base_id;	/* base igu status block id */
+
+	struct bnx2x_vf_queue	*vfqs;
+#define bnx2x_vfq(vf, nr, var)	((vf)->vfqs[(nr)].var)
+
+	u8 index;	/* index in the vf array */
+	u8 abs_vfid;
+	u8 sp_cl_id;
+	u32 error;	/* 0 means all's-well */
+
+	/* BDF */
+	unsigned int bus;
+	unsigned int devfn;
+
+	/* bars */
+	struct bnx2x_vf_bar bars[PCI_SRIOV_NUM_BARS];
+
+	/* set-mac ramrod state 1-pending, 0-done */
+	unsigned long	filter_state;
+
+	/* leading rss client id ~~ the client id of the first rxq, must be
+	 * set for each txq.
+	 */
+	int leading_rss;
+
+	/* MCAST object */
+	struct bnx2x_mcast_obj		mcast_obj;
+
+	/* RSS configuration object */
+	struct bnx2x_rss_config_obj     rss_conf_obj;
+
+	/* slow-path operations */
+	atomic_t			op_in_progress;
+	int				op_rc;
+	bool				op_wait_blocking;
+	struct list_head		op_list_head;
+	union bnx2x_vfop_params		op_params;
+	struct mutex			op_mutex; /* one vfop at a time mutex */
+	enum channel_tlvs		op_current;
+};
+
+#define BNX2X_NR_VIRTFN(bp)	((bp)->vfdb->sriov.nr_virtfn)
+
+#define for_each_vf(bp, var) \
+		for ((var) = 0; (var) < BNX2X_NR_VIRTFN(bp); (var)++)
+
+#define for_each_vfq(vf, var) \
+		for ((var) = 0; (var) < vf_rxq_count(vf); (var)++)
+
+#define for_each_vf_sb(vf, var) \
+		for ((var) = 0; (var) < vf_sb_count(vf); (var)++)
+
+#define is_vf_multi(vf)	(vf_rxq_count(vf) > 1)
+
+#define HW_VF_HANDLE(bp, abs_vfid) \
+	(u16)(BP_ABS_FUNC((bp)) | (1<<3) |  ((u16)(abs_vfid) << 4))
+
+#define FW_PF_MAX_HANDLE	8
+
+#define FW_VF_HANDLE(abs_vfid)	\
+	(abs_vfid + FW_PF_MAX_HANDLE)
+
+/* locking and unlocking the channel mutex */
+void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			      enum channel_tlvs tlv);
+
+void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				enum channel_tlvs expected_tlv);
+
+/* VF mail box (aka vf-pf channel) */
+
+/* a container for the bi-directional vf<-->pf messages.
+ *  The actual response will be placed according to the offset parameter
+ *  provided in the request
+ */
+
+#define MBX_MSG_ALIGN	8
+#define MBX_MSG_ALIGNED_SIZE	(roundup(sizeof(struct bnx2x_vf_mbx_msg), \
+				MBX_MSG_ALIGN))
+
+struct bnx2x_vf_mbx_msg {
+	union vfpf_tlvs req;
+	union pfvf_tlvs resp;
+};
+
+struct bnx2x_vf_mbx {
+	struct bnx2x_vf_mbx_msg *msg;
+	dma_addr_t msg_mapping;
+
+	/* VF GPA address */
+	u32 vf_addr_lo;
+	u32 vf_addr_hi;
+
+	struct vfpf_first_tlv first_tlv;	/* saved VF request header */
+
+	u8 flags;
+#define VF_MSG_INPROCESS	0x1	/* failsafe - the FW should prevent
+					 * more then one pending msg
+					 */
+};
+
+struct bnx2x_vf_sp {
+	union {
+		struct eth_classify_rules_ramrod_data	e2;
+	} mac_rdata;
+
+	union {
+		struct eth_classify_rules_ramrod_data	e2;
+	} vlan_rdata;
+
+	union {
+		struct eth_filter_rules_ramrod_data	e2;
+	} rx_mode_rdata;
+
+	union {
+		struct eth_multicast_rules_ramrod_data  e2;
+	} mcast_rdata;
+
+	union {
+		struct client_init_ramrod_data  init_data;
+		struct client_update_ramrod_data update_data;
+	} q_data;
+};
+
+struct hw_dma {
+	void *addr;
+	dma_addr_t mapping;
+	size_t size;
+};
+
+struct bnx2x_vfdb {
+#define BP_VFDB(bp)		((bp)->vfdb)
+	/* vf array */
+	struct bnx2x_virtf	*vfs;
+#define BP_VF(bp, idx)		(&((bp)->vfdb->vfs[(idx)]))
+#define bnx2x_vf(bp, idx, var)	((bp)->vfdb->vfs[(idx)].var)
+
+	/* queue array - for all vfs */
+	struct bnx2x_vf_queue *vfqs;
+
+	/* vf HW contexts */
+	struct hw_dma		context[BNX2X_VF_CIDS/ILT_PAGE_CIDS];
+#define	BP_VF_CXT_PAGE(bp, i)	(&(bp)->vfdb->context[(i)])
+
+	/* SR-IOV information */
+	struct bnx2x_sriov	sriov;
+	struct hw_dma		mbx_dma;
+#define BP_VF_MBX_DMA(bp)	(&((bp)->vfdb->mbx_dma))
+	struct bnx2x_vf_mbx	mbxs[BNX2X_MAX_NUM_OF_VFS];
+#define BP_VF_MBX(bp, vfid)	(&((bp)->vfdb->mbxs[(vfid)]))
+
+	struct hw_dma		bulletin_dma;
+#define BP_VF_BULLETIN_DMA(bp)	(&((bp)->vfdb->bulletin_dma))
+#define	BP_VF_BULLETIN(bp, vf) \
+	(((struct pf_vf_bulletin_content *)(BP_VF_BULLETIN_DMA(bp)->addr)) \
+	 + (vf))
+
+	struct hw_dma		sp_dma;
+#define bnx2x_vf_sp(bp, vf, field) ((bp)->vfdb->sp_dma.addr +		\
+		(vf)->index * sizeof(struct bnx2x_vf_sp) +		\
+		offsetof(struct bnx2x_vf_sp, field))
+#define bnx2x_vf_sp_map(bp, vf, field) ((bp)->vfdb->sp_dma.mapping +	\
+		(vf)->index * sizeof(struct bnx2x_vf_sp) +		\
+		offsetof(struct bnx2x_vf_sp, field))
+
+#define FLRD_VFS_DWORDS (BNX2X_MAX_NUM_OF_VFS / 32)
+	u32 flrd_vfs[FLRD_VFS_DWORDS];
+};
+
+/* queue access */
+static inline struct bnx2x_vf_queue *vfq_get(struct bnx2x_virtf *vf, u8 index)
+{
+	return &(vf->vfqs[index]);
+}
+
+static inline bool vfq_is_leading(struct bnx2x_vf_queue *vfq)
+{
+	return (vfq->index == 0);
+}
+
+/* FW ids */
+static inline u8 vf_igu_sb(struct bnx2x_virtf *vf, u16 sb_idx)
+{
+	return vf->igu_base_id + sb_idx;
+}
+
+static inline u8 vf_hc_qzone(struct bnx2x_virtf *vf, u16 sb_idx)
+{
+	return vf_igu_sb(vf, sb_idx);
+}
+
+static u8 vfq_cl_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+	return vf->igu_base_id + q->index;
+}
+
+static inline u8 vfq_stat_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+	return vfq_cl_id(vf, q);
+}
+
+static inline u8 vfq_qzone_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+	return vfq_cl_id(vf, q);
+}
+
+/* global iov routines */
+int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line);
+int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, int num_vfs_param);
+void bnx2x_iov_remove_one(struct bnx2x *bp);
+void bnx2x_iov_free_mem(struct bnx2x *bp);
+int bnx2x_iov_alloc_mem(struct bnx2x *bp);
+int bnx2x_iov_nic_init(struct bnx2x *bp);
+int bnx2x_iov_chip_cleanup(struct bnx2x *bp);
+void bnx2x_iov_init_dq(struct bnx2x *bp);
+void bnx2x_iov_init_dmae(struct bnx2x *bp);
+void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+				struct bnx2x_queue_sp_obj **q_obj);
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work);
+int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem);
+void bnx2x_iov_adjust_stats_req(struct bnx2x *bp);
+void bnx2x_iov_storm_stats_update(struct bnx2x *bp);
+void bnx2x_iov_sp_task(struct bnx2x *bp);
+/* global vf mailbox routines */
+void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
+void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
+
+/* CORE VF API */
+typedef u8 bnx2x_mac_addr_t[ETH_ALEN];
+
+/* acquire */
+int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+		     struct vf_pf_resc_request *resc);
+/* init */
+int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
+		  dma_addr_t *sb_map);
+
+/* VFOP generic helpers */
+#define bnx2x_vfop_default(state) do {				\
+		BNX2X_ERR("Bad state %d\n", (state));		\
+		vfop->rc = -EINVAL;				\
+		goto op_err;					\
+	} while (0)
+
+enum {
+	VFOP_DONE,
+	VFOP_CONT,
+	VFOP_VERIFY_PEND,
+};
+
+#define bnx2x_vfop_finalize(vf, rc, next) do {				\
+		if ((rc) < 0)						\
+			goto op_err;					\
+		else if ((rc) > 0)					\
+			goto op_pending;				\
+		else if ((next) == VFOP_DONE)				\
+			goto op_done;					\
+		else if ((next) == VFOP_VERIFY_PEND)			\
+			BNX2X_ERR("expected pending\n");		\
+		else {							\
+			DP(BNX2X_MSG_IOV, "no ramrod. scheduling\n");	\
+			atomic_set(&vf->op_in_progress, 1);		\
+			queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);  \
+			return;						\
+		}							\
+	} while (0)
+
+#define bnx2x_vfop_opset(first_state, trans_hndlr, done_hndlr)		\
+	do {								\
+		vfop->state = first_state;				\
+		vfop->op_p = &vf->op_params;				\
+		vfop->transition = trans_hndlr;				\
+		vfop->done = done_hndlr;				\
+	} while (0)
+
+static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
+						struct bnx2x_virtf *vf)
+{
+	WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
+	WARN_ON(list_empty(&vf->op_list_head));
+	return list_first_entry(&vf->op_list_head, struct bnx2x_vfop, link);
+}
+
+static inline struct bnx2x_vfop *bnx2x_vfop_add(struct bnx2x *bp,
+						struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vfop *vfop = kzalloc(sizeof(*vfop), GFP_KERNEL);
+
+	WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
+	if (vfop) {
+		INIT_LIST_HEAD(&vfop->link);
+		list_add(&vfop->link, &vf->op_list_head);
+	}
+	return vfop;
+}
+
+static inline void bnx2x_vfop_end(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				  struct bnx2x_vfop *vfop)
+{
+	/* rc < 0 - error, otherwise set to 0 */
+	DP(BNX2X_MSG_IOV, "rc was %d\n", vfop->rc);
+	if (vfop->rc >= 0)
+		vfop->rc = 0;
+	DP(BNX2X_MSG_IOV, "rc is now %d\n", vfop->rc);
+
+	/* unlink the current op context and propagate error code
+	 * must be done before invoking the 'done()' handler
+	 */
+	WARN(!mutex_is_locked(&vf->op_mutex),
+	     "about to access vf op linked list but mutex was not locked!");
+	list_del(&vfop->link);
+
+	if (list_empty(&vf->op_list_head)) {
+		DP(BNX2X_MSG_IOV, "list was empty %d\n", vfop->rc);
+		vf->op_rc = vfop->rc;
+		DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d,  vfop->rc %d\n",
+		   vf->op_rc, vfop->rc);
+	} else {
+		struct bnx2x_vfop *cur_vfop;
+
+		DP(BNX2X_MSG_IOV, "list not empty %d\n", vfop->rc);
+		cur_vfop = bnx2x_vfop_cur(bp, vf);
+		cur_vfop->rc = vfop->rc;
+		DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
+		   vf->op_rc, vfop->rc);
+	}
+
+	/* invoke done handler */
+	if (vfop->done) {
+		DP(BNX2X_MSG_IOV, "calling done handler\n");
+		vfop->done(bp, vf);
+	} else {
+		/* there is no done handler for the operation to unlock
+		 * the mutex. Must have gotten here from PF initiated VF RELEASE
+		 */
+		bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+	}
+
+	DP(BNX2X_MSG_IOV, "done handler complete. vf->op_rc %d, vfop->rc %d\n",
+	   vf->op_rc, vfop->rc);
+
+	/* if this is the last nested op reset the wait_blocking flag
+	 * to release any blocking wrappers, only after 'done()' is invoked
+	 */
+	if (list_empty(&vf->op_list_head)) {
+		DP(BNX2X_MSG_IOV, "list was empty after done %d\n", vfop->rc);
+		vf->op_wait_blocking = false;
+	}
+
+	kfree(vfop);
+}
+
+static inline int bnx2x_vfop_wait_blocking(struct bnx2x *bp,
+					   struct bnx2x_virtf *vf)
+{
+	/* can take a while if any port is running */
+	int cnt = 5000;
+
+	might_sleep();
+	while (cnt--) {
+		if (vf->op_wait_blocking == false) {
+#ifdef BNX2X_STOP_ON_ERROR
+			DP(BNX2X_MSG_IOV, "exit  (cnt %d)\n", 5000 - cnt);
+#endif
+			return 0;
+		}
+		usleep_range(1000, 2000);
+
+		if (bp->panic)
+			return -EIO;
+	}
+
+	/* timeout! */
+#ifdef BNX2X_STOP_ON_ERROR
+	bnx2x_panic();
+#endif
+
+	return -EBUSY;
+}
+
+static inline int bnx2x_vfop_transition(struct bnx2x *bp,
+					struct bnx2x_virtf *vf,
+					vfop_handler_t transition,
+					bool block)
+{
+	if (block)
+		vf->op_wait_blocking = true;
+	transition(bp, vf);
+	if (block)
+		return bnx2x_vfop_wait_blocking(bp, vf);
+	return 0;
+}
+
+/* VFOP queue construction helpers */
+void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			    struct bnx2x_queue_init_params *init_params,
+			    struct bnx2x_queue_setup_params *setup_params,
+			    u16 q_idx, u16 sb_idx);
+
+void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			    struct bnx2x_queue_init_params *init_params,
+			    struct bnx2x_queue_setup_params *setup_params,
+			    u16 q_idx, u16 sb_idx);
+
+void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
+			   struct bnx2x_virtf *vf,
+			   struct bnx2x_vf_queue *q,
+			   struct bnx2x_vfop_qctor_params *p,
+			   unsigned long q_type);
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+			    struct bnx2x_virtf *vf,
+			    struct bnx2x_vfop_cmd *cmd,
+			    struct bnx2x_vfop_filters *macs,
+			    int qid, bool drv_only);
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+			    struct bnx2x_virtf *vf,
+			    struct bnx2x_vfop_cmd *cmd,
+			    int qid, u16 vid, bool add);
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+			     struct bnx2x_virtf *vf,
+			     struct bnx2x_vfop_cmd *cmd,
+			     struct bnx2x_vfop_filters *vlans,
+			     int qid, bool drv_only);
+
+int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
+			  struct bnx2x_virtf *vf,
+			  struct bnx2x_vfop_cmd *cmd,
+			  int qid);
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+			 struct bnx2x_virtf *vf,
+			 struct bnx2x_vfop_cmd *cmd,
+			 int qid);
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+			 struct bnx2x_virtf *vf,
+			 struct bnx2x_vfop_cmd *cmd,
+			 bnx2x_mac_addr_t *mcasts,
+			 int mcast_num, bool drv_only);
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+			  struct bnx2x_virtf *vf,
+			  struct bnx2x_vfop_cmd *cmd,
+			  int qid, unsigned long accept_flags);
+
+int bnx2x_vfop_close_cmd(struct bnx2x *bp,
+			 struct bnx2x_virtf *vf,
+			 struct bnx2x_vfop_cmd *cmd);
+
+int bnx2x_vfop_release_cmd(struct bnx2x *bp,
+			   struct bnx2x_virtf *vf,
+			   struct bnx2x_vfop_cmd *cmd);
+
+/* VF release ~ VF close + VF release-resources
+ *
+ * Release is the ultimate SW shutdown and is called whenever an
+ * irrecoverable error is encountered.
+ */
+void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block);
+int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
+u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+/* FLR routines */
+
+/* VF FLR helpers */
+int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid);
+void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid);
+
+/* Handles an FLR (or VF_DISABLE) notification form the MCP */
+void bnx2x_vf_handle_flr_event(struct bnx2x *bp);
+
+void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
+		   u16 length);
+void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+		     u16 type, u16 length);
+void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
+
+bool bnx2x_tlv_supported(u16 tlvtype);
+
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+			  struct pf_vf_bulletin_content *bulletin);
+int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
+
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+
+/* VF side vfpf channel functions */
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_init(struct bnx2x *bp);
+void bnx2x_vfpf_close_vf(struct bnx2x *bp);
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx);
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
+int bnx2x_vfpf_set_mac(struct bnx2x *bp);
+int bnx2x_vfpf_set_mcast(struct net_device *dev);
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp);
+
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+					size_t buf_len)
+{
+	strlcpy(buf, bp->acquire_resp.pfdev_info.fw_ver, buf_len);
+}
+
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+					       struct bnx2x_fastpath *fp)
+{
+	return PXP_VF_ADDR_USDM_QUEUES_START +
+		bp->acquire_resp.resc.hw_qid[fp->index] *
+		sizeof(struct ustorm_queue_zone_data);
+}
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+void bnx2x_vf_map_doorbells(struct bnx2x *bp);
+int bnx2x_vf_pci_alloc(struct bnx2x *bp);
+void bnx2x_enable_sriov(struct bnx2x *bp);
+static inline int bnx2x_vf_headroom(struct bnx2x *bp)
+{
+	return bp->vfdb->sriov.nr_virtfn * BNX2X_CLIENTS_PER_VF;
+}
+
+#else /* CONFIG_BNX2X_SRIOV */
+
+static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+				struct bnx2x_queue_sp_obj **q_obj) {}
+static inline void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid,
+				      bool queue_work) {}
+static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {}
+static inline int bnx2x_iov_eq_sp_event(struct bnx2x *bp,
+					union event_ring_elem *elem) {return 1; }
+static inline void bnx2x_iov_sp_task(struct bnx2x *bp) {}
+static inline void bnx2x_vf_mbx(struct bnx2x *bp,
+				struct vf_pf_event_data *vfpf_event) {}
+static inline int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) {return line; }
+static inline void bnx2x_iov_init_dq(struct bnx2x *bp) {}
+static inline int bnx2x_iov_alloc_mem(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_free_mem(struct bnx2x *bp) {}
+static inline int bnx2x_iov_chip_cleanup(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_init_dmae(struct bnx2x *bp) {}
+static inline int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+				     int num_vfs_param) {return 0; }
+static inline void bnx2x_iov_remove_one(struct bnx2x *bp) {}
+static inline void bnx2x_enable_sriov(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_acquire(struct bnx2x *bp,
+				     u8 tx_count, u8 rx_count) {return 0; }
+static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) {return 0; }
+static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
+static inline int bnx2x_vfpf_set_mac(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; }
+static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_headroom(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_adjust_stats_req(struct bnx2x *bp) {}
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+					size_t buf_len) {}
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+					       struct bnx2x_fastpath *fp) {return 0; }
+static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+	return PFVF_BULLETIN_UNCHANGED;
+}
+
+static inline int bnx2x_vf_map_doorbells(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
+
+#endif /* CONFIG_BNX2X_SRIOV */
+#endif /* bnx2x_sriov.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 89ec066..4397f8b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -1,6 +1,6 @@
 /* bnx2x_stats.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -19,7 +19,7 @@
 
 #include "bnx2x_stats.h"
 #include "bnx2x_cmn.h"
-
+#include "bnx2x_sriov.h"
 
 /* Statistics */
 
@@ -79,6 +79,42 @@
  * Init service functions
  */
 
+static void bnx2x_dp_stats(struct bnx2x *bp)
+{
+	int i;
+
+	DP(BNX2X_MSG_STATS, "dumping stats:\n"
+	   "fw_stats_req\n"
+	   "    hdr\n"
+	   "        cmd_num %d\n"
+	   "        reserved0 %d\n"
+	   "        drv_stats_counter %d\n"
+	   "        reserved1 %d\n"
+	   "        stats_counters_addrs %x %x\n",
+	   bp->fw_stats_req->hdr.cmd_num,
+	   bp->fw_stats_req->hdr.reserved0,
+	   bp->fw_stats_req->hdr.drv_stats_counter,
+	   bp->fw_stats_req->hdr.reserved1,
+	   bp->fw_stats_req->hdr.stats_counters_addrs.hi,
+	   bp->fw_stats_req->hdr.stats_counters_addrs.lo);
+
+	for (i = 0; i < bp->fw_stats_req->hdr.cmd_num; i++) {
+		DP(BNX2X_MSG_STATS,
+		   "query[%d]\n"
+		   "              kind %d\n"
+		   "              index %d\n"
+		   "              funcID %d\n"
+		   "              reserved %d\n"
+		   "              address %x %x\n",
+		   i, bp->fw_stats_req->query[i].kind,
+		   bp->fw_stats_req->query[i].index,
+		   bp->fw_stats_req->query[i].funcID,
+		   bp->fw_stats_req->query[i].reserved,
+		   bp->fw_stats_req->query[i].address.hi,
+		   bp->fw_stats_req->query[i].address.lo);
+	}
+}
+
 /* Post the next statistics ramrod. Protect it with the spin in
  * order to ensure the strict order between statistics ramrods
  * (each ramrod has a sequence number passed in a
@@ -103,7 +139,9 @@
 		DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
 			bp->fw_stats_req->hdr.drv_stats_counter);
 
-
+		/* adjust the ramrod to include VF queues statistics */
+		bnx2x_iov_adjust_stats_req(bp);
+		bnx2x_dp_stats(bp);
 
 		/* send FW stats ramrod */
 		rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
@@ -174,7 +212,7 @@
 			break;
 		}
 		cnt--;
-		usleep_range(1000, 1000);
+		usleep_range(1000, 2000);
 	}
 	return 1;
 }
@@ -482,6 +520,12 @@
 
 static void bnx2x_stats_start(struct bnx2x *bp)
 {
+	/* vfs travel through here as part of the statistics FSM, but no action
+	 * is required
+	 */
+	if (IS_VF(bp))
+		return;
+
 	if (bp->port.pmf)
 		bnx2x_port_stats_init(bp);
 
@@ -501,6 +545,11 @@
 
 static void bnx2x_stats_restart(struct bnx2x *bp)
 {
+	/* vfs travel through here as part of the statistics FSM, but no action
+	 * is required
+	 */
+	if (IS_VF(bp))
+		return;
 	bnx2x_stats_comp(bp);
 	bnx2x_stats_start(bp);
 }
@@ -832,19 +881,10 @@
 	return 0;
 }
 
-static int bnx2x_storm_stats_update(struct bnx2x *bp)
+static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp)
 {
-	struct tstorm_per_port_stats *tport =
-				&bp->fw_stats_data->port.tstorm_port_statistics;
-	struct tstorm_per_pf_stats *tfunc =
-				&bp->fw_stats_data->pf.tstorm_pf_statistics;
-	struct host_func_stats *fstats = &bp->func_stats;
-	struct bnx2x_eth_stats *estats = &bp->eth_stats;
-	struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old;
 	struct stats_counter *counters = &bp->fw_stats_data->storm_counters;
-	int i;
 	u16 cur_stats_counter;
-
 	/* Make sure we use the value of the counter
 	 * used for sending the last stats ramrod.
 	 */
@@ -880,6 +920,23 @@
 		   le16_to_cpu(counters->tstats_counter), bp->stats_counter);
 		return -EAGAIN;
 	}
+	return 0;
+}
+
+static int bnx2x_storm_stats_update(struct bnx2x *bp)
+{
+	struct tstorm_per_port_stats *tport =
+				&bp->fw_stats_data->port.tstorm_port_statistics;
+	struct tstorm_per_pf_stats *tfunc =
+				&bp->fw_stats_data->pf.tstorm_pf_statistics;
+	struct host_func_stats *fstats = &bp->func_stats;
+	struct bnx2x_eth_stats *estats = &bp->eth_stats;
+	struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old;
+	int i;
+
+	/* vfs stat counter is managed by pf */
+	if (IS_PF(bp) && bnx2x_storm_stats_validate_counters(bp))
+		return -EAGAIN;
 
 	estats->error_bytes_received_hi = 0;
 	estats->error_bytes_received_lo = 0;
@@ -953,8 +1010,8 @@
 		UPDATE_EXTEND_TSTAT(rcv_bcast_pkts,
 					total_broadcast_packets_received);
 		UPDATE_EXTEND_E_TSTAT(pkts_too_big_discard,
-				      etherstatsoverrsizepkts);
-		UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard);
+				      etherstatsoverrsizepkts, 32);
+		UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard, 16);
 
 		SUB_EXTEND_USTAT(ucast_no_buff_pkts,
 					total_unicast_packets_received);
@@ -1033,15 +1090,15 @@
 	       estats->total_bytes_received_lo,
 	       estats->rx_stat_ifhcinbadoctets_lo);
 
-	ADD_64(estats->total_bytes_received_hi,
-	       le32_to_cpu(tfunc->rcv_error_bytes.hi),
-	       estats->total_bytes_received_lo,
-	       le32_to_cpu(tfunc->rcv_error_bytes.lo));
+	ADD_64_LE(estats->total_bytes_received_hi,
+		  tfunc->rcv_error_bytes.hi,
+		  estats->total_bytes_received_lo,
+		  tfunc->rcv_error_bytes.lo);
 
-	ADD_64(estats->error_bytes_received_hi,
-	       le32_to_cpu(tfunc->rcv_error_bytes.hi),
-	       estats->error_bytes_received_lo,
-	       le32_to_cpu(tfunc->rcv_error_bytes.lo));
+	ADD_64_LE(estats->error_bytes_received_hi,
+		  tfunc->rcv_error_bytes.hi,
+		  estats->error_bytes_received_lo,
+		  tfunc->rcv_error_bytes.lo);
 
 	UPDATE_ESTAT(etherstatsoverrsizepkts, rx_stat_dot3statsframestoolong);
 
@@ -1174,23 +1231,34 @@
 	if (bnx2x_edebug_stats_stopped(bp))
 		return;
 
-	if (*stats_comp != DMAE_COMP_VAL)
-		return;
+	if (IS_PF(bp)) {
+		if (*stats_comp != DMAE_COMP_VAL)
+			return;
 
-	if (bp->port.pmf)
-		bnx2x_hw_stats_update(bp);
+		if (bp->port.pmf)
+			bnx2x_hw_stats_update(bp);
 
-	if (bnx2x_storm_stats_update(bp)) {
-		if (bp->stats_pending++ == 3) {
-			BNX2X_ERR("storm stats were not updated for 3 times\n");
-			bnx2x_panic();
+		if (bnx2x_storm_stats_update(bp)) {
+			if (bp->stats_pending++ == 3) {
+				BNX2X_ERR("storm stats were not updated for 3 times\n");
+				bnx2x_panic();
+			}
+			return;
 		}
-		return;
+	} else {
+		/* vf doesn't collect HW statistics, and doesn't get completions
+		 * perform only update
+		 */
+		bnx2x_storm_stats_update(bp);
 	}
 
 	bnx2x_net_stats_update(bp);
 	bnx2x_drv_stats_update(bp);
 
+	/* vf is done */
+	if (IS_VF(bp))
+		return;
+
 	if (netif_msg_timer(bp)) {
 		struct bnx2x_eth_stats *estats = &bp->eth_stats;
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index b4d7b26..364e37e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -1,6 +1,6 @@
 /* bnx2x_stats.h: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * 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
@@ -421,16 +421,19 @@
 			      new->s); \
 	} while (0)
 
-#define UPDATE_EXTEND_TSTAT(s, t) \
+#define UPDATE_EXTEND_TSTAT_X(s, t, size) \
 	do { \
-		diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
+		diff = le##size##_to_cpu(tclient->s) - \
+		       le##size##_to_cpu(old_tclient->s); \
 		old_tclient->s = tclient->s; \
 		ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
 	} while (0)
 
-#define UPDATE_EXTEND_E_TSTAT(s, t) \
+#define UPDATE_EXTEND_TSTAT(s, t) UPDATE_EXTEND_TSTAT_X(s, t, 32)
+
+#define UPDATE_EXTEND_E_TSTAT(s, t, size) \
 	do { \
-		UPDATE_EXTEND_TSTAT(s, t); \
+		UPDATE_EXTEND_TSTAT_X(s, t, size); \
 		ADD_EXTEND_64(estats->t##_hi, estats->t##_lo, diff); \
 	} while (0)
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
new file mode 100644
index 0000000..3624612
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -0,0 +1,1651 @@
+/* bnx2x_vfpf.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ *	       Ariel Elior <ariele@broadcom.com>
+ */
+
+#include "bnx2x.h"
+#include "bnx2x_cmn.h"
+#include <linux/crc32.h>
+
+/* place a given tlv on the tlv buffer at a given offset */
+void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
+		   u16 length)
+{
+	struct channel_tlv *tl =
+		(struct channel_tlv *)(tlvs_list + offset);
+
+	tl->type = type;
+	tl->length = length;
+}
+
+/* Clear the mailbox and init the header of the first tlv */
+void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+		     u16 type, u16 length)
+{
+	DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
+	   type);
+
+	/* Clear mailbox */
+	memset(bp->vf2pf_mbox, 0, sizeof(struct bnx2x_vf_mbx_msg));
+
+	/* init type and length */
+	bnx2x_add_tlv(bp, &first_tlv->tl, 0, type, length);
+
+	/* init first tlv header */
+	first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req);
+}
+
+/* list the types and lengths of the tlvs on the buffer */
+void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
+{
+	int i = 1;
+	struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
+
+	while (tlv->type != CHANNEL_TLV_LIST_END) {
+		/* output tlv */
+		DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
+		   tlv->type, tlv->length);
+
+		/* advance to next tlv */
+		tlvs_list += tlv->length;
+
+		/* cast general tlv list pointer to channel tlv header*/
+		tlv = (struct channel_tlv *)tlvs_list;
+
+		i++;
+
+		/* break condition for this loop */
+		if (i > MAX_TLVS_IN_LIST) {
+			WARN(true, "corrupt tlvs");
+			return;
+		}
+	}
+
+	/* output last tlv */
+	DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
+	   tlv->type, tlv->length);
+}
+
+/* test whether we support a tlv type */
+bool bnx2x_tlv_supported(u16 tlvtype)
+{
+	return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX;
+}
+
+static inline int bnx2x_pfvf_status_codes(int rc)
+{
+	switch (rc) {
+	case 0:
+		return PFVF_STATUS_SUCCESS;
+	case -ENOMEM:
+		return PFVF_STATUS_NO_RESOURCE;
+	default:
+		return PFVF_STATUS_FAILURE;
+	}
+}
+
+int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
+{
+	struct cstorm_vf_zone_data __iomem *zone_data =
+		REG_ADDR(bp, PXP_VF_ADDR_CSDM_GLOBAL_START);
+	int tout = 600, interval = 100; /* wait for 60 seconds */
+
+	if (*done) {
+		BNX2X_ERR("done was non zero before message to pf was sent\n");
+		WARN_ON(true);
+		return -EINVAL;
+	}
+
+	/* Write message address */
+	writel(U64_LO(msg_mapping),
+	       &zone_data->non_trigger.vf_pf_channel.msg_addr_lo);
+	writel(U64_HI(msg_mapping),
+	       &zone_data->non_trigger.vf_pf_channel.msg_addr_hi);
+
+	/* make sure the address is written before FW accesses it */
+	wmb();
+
+	/* Trigger the PF FW */
+	writeb(1, &zone_data->trigger.vf_pf_channel.addr_valid);
+
+	/* Wait for PF to complete */
+	while ((tout >= 0) && (!*done)) {
+		msleep(interval);
+		tout -= 1;
+
+		/* progress indicator - HV can take its own sweet time in
+		 * answering VFs...
+		 */
+		DP_CONT(BNX2X_MSG_IOV, ".");
+	}
+
+	if (!*done) {
+		BNX2X_ERR("PF response has timed out\n");
+		return -EAGAIN;
+	}
+	DP(BNX2X_MSG_SP, "Got a response from PF\n");
+	return 0;
+}
+
+int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id)
+{
+	u32 me_reg;
+	int tout = 10, interval = 100; /* Wait for 1 sec */
+
+	do {
+		/* pxp traps vf read of doorbells and returns me reg value */
+		me_reg = readl(bp->doorbells);
+		if (GOOD_ME_REG(me_reg))
+			break;
+
+		msleep(interval);
+
+		BNX2X_ERR("Invalid ME register value: 0x%08x\n. Is pf driver up?",
+			  me_reg);
+	} while (tout-- > 0);
+
+	if (!GOOD_ME_REG(me_reg)) {
+		BNX2X_ERR("Invalid ME register value: 0x%08x\n", me_reg);
+		return -EINVAL;
+	}
+
+	BNX2X_ERR("valid ME register value: 0x%08x\n", me_reg);
+
+	*vf_id = (me_reg & ME_REG_VF_NUM_MASK) >> ME_REG_VF_NUM_SHIFT;
+
+	return 0;
+}
+
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
+{
+	int rc = 0, attempts = 0;
+	struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire;
+	struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp;
+	u32 vf_id;
+	bool resources_acquired = false;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
+
+	if (bnx2x_get_vf_id(bp, &vf_id))
+		return -EAGAIN;
+
+	req->vfdev_info.vf_id = vf_id;
+	req->vfdev_info.vf_os = 0;
+
+	req->resc_request.num_rxqs = rx_count;
+	req->resc_request.num_txqs = tx_count;
+	req->resc_request.num_sbs = bp->igu_sb_cnt;
+	req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
+	req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;
+
+	/* pf 2 vf bulletin board address */
+	req->bulletin_addr = bp->pf2vf_bulletin_mapping;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	while (!resources_acquired) {
+		DP(BNX2X_MSG_SP, "attempting to acquire resources\n");
+
+		/* send acquire request */
+		rc = bnx2x_send_msg2pf(bp,
+				       &resp->hdr.status,
+				       bp->vf2pf_mbox_mapping);
+
+		/* PF timeout */
+		if (rc)
+			return rc;
+
+		/* copy acquire response from buffer to bp */
+		memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
+
+		attempts++;
+
+		/* test whether the PF accepted our request. If not, humble the
+		 * the request and try again.
+		 */
+		if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
+			DP(BNX2X_MSG_SP, "resources acquired\n");
+			resources_acquired = true;
+		} else if (bp->acquire_resp.hdr.status ==
+			   PFVF_STATUS_NO_RESOURCE &&
+			   attempts < VF_ACQUIRE_THRESH) {
+			DP(BNX2X_MSG_SP,
+			   "PF unwilling to fulfill resource request. Try PF recommended amount\n");
+
+			/* humble our request */
+			req->resc_request.num_txqs =
+				bp->acquire_resp.resc.num_txqs;
+			req->resc_request.num_rxqs =
+				bp->acquire_resp.resc.num_rxqs;
+			req->resc_request.num_sbs =
+				bp->acquire_resp.resc.num_sbs;
+			req->resc_request.num_mac_filters =
+				bp->acquire_resp.resc.num_mac_filters;
+			req->resc_request.num_vlan_filters =
+				bp->acquire_resp.resc.num_vlan_filters;
+			req->resc_request.num_mc_filters =
+				bp->acquire_resp.resc.num_mc_filters;
+
+			/* Clear response buffer */
+			memset(&bp->vf2pf_mbox->resp, 0,
+			       sizeof(union pfvf_tlvs));
+		} else {
+			/* PF reports error */
+			BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
+				  bp->acquire_resp.hdr.status);
+			return -EAGAIN;
+		}
+	}
+
+	/* get HW info */
+	bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
+	bp->link_params.chip_id = bp->common.chip_id;
+	bp->db_size = bp->acquire_resp.pfdev_info.db_size;
+	bp->common.int_block = INT_BLOCK_IGU;
+	bp->common.chip_port_mode = CHIP_2_PORT_MODE;
+	bp->igu_dsb_id = -1;
+	bp->mf_ov = 0;
+	bp->mf_mode = 0;
+	bp->common.flash_size = 0;
+	bp->flags |=
+		NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG;
+	bp->igu_sb_cnt = 1;
+	bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id;
+	strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver,
+		sizeof(bp->fw_ver));
+
+	if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr))
+		memcpy(bp->dev->dev_addr,
+		       bp->acquire_resp.resc.current_mac_addr,
+		       ETH_ALEN);
+
+	return 0;
+}
+
+int bnx2x_vfpf_release(struct bnx2x *bp)
+{
+	struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	u32 rc = 0, vf_id;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
+
+	if (bnx2x_get_vf_id(bp, &vf_id))
+		return -EAGAIN;
+
+	req->vf_id = vf_id;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	/* send release request */
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+	if (rc)
+		/* PF timeout */
+		return rc;
+	if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
+		/* PF released us */
+		DP(BNX2X_MSG_SP, "vf released\n");
+	} else {
+		/* PF reports error */
+		BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
+			  resp->hdr.status);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/* Tell PF about SB addresses */
+int bnx2x_vfpf_init(struct bnx2x *bp)
+{
+	struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	int rc, i;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req));
+
+	/* status blocks */
+	for_each_eth_queue(bp, i)
+		req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i,
+						       status_blk_mapping);
+
+	/* statistics - requests only supports single queue for now */
+	req->stats_addr = bp->fw_stats_data_mapping +
+			  offsetof(struct bnx2x_fw_stats_data, queue_stats);
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+	if (rc)
+		return rc;
+
+	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+		BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
+			  resp->hdr.status);
+		return -EAGAIN;
+	}
+
+	DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
+	return 0;
+}
+
+/* CLOSE VF - opposite to INIT_VF */
+void bnx2x_vfpf_close_vf(struct bnx2x *bp)
+{
+	struct vfpf_close_tlv *req = &bp->vf2pf_mbox->req.close;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	int i, rc;
+	u32 vf_id;
+
+	/* If we haven't got a valid VF id, there is no sense to
+	 * continue with sending messages
+	 */
+	if (bnx2x_get_vf_id(bp, &vf_id))
+		goto free_irq;
+
+	/* Close the queues */
+	for_each_queue(bp, i)
+		bnx2x_vfpf_teardown_queue(bp, i);
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req));
+
+	req->vf_id = vf_id;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+	if (rc)
+		BNX2X_ERR("Sending CLOSE failed. rc was: %d\n", rc);
+
+	else if (resp->hdr.status != PFVF_STATUS_SUCCESS)
+		BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
+			  resp->hdr.status);
+
+free_irq:
+	/* Disable HW interrupts, NAPI */
+	bnx2x_netif_stop(bp, 0);
+	/* Delete all NAPI objects */
+	bnx2x_del_all_napi(bp);
+
+	/* Release IRQs */
+	bnx2x_free_irq(bp);
+}
+
+/* ask the pf to open a queue for the vf */
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
+{
+	struct vfpf_setup_q_tlv *req = &bp->vf2pf_mbox->req.setup_q;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	struct bnx2x_fastpath *fp = &bp->fp[fp_idx];
+	u16 tpa_agg_size = 0, flags = 0;
+	int rc;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req));
+
+	/* select tpa mode to request */
+	if (!fp->disable_tpa) {
+		flags |= VFPF_QUEUE_FLG_TPA;
+		flags |= VFPF_QUEUE_FLG_TPA_IPV6;
+		if (fp->mode == TPA_MODE_GRO)
+			flags |= VFPF_QUEUE_FLG_TPA_GRO;
+		tpa_agg_size = TPA_AGG_SIZE;
+	}
+
+	/* calculate queue flags */
+	flags |= VFPF_QUEUE_FLG_STATS;
+	flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
+	flags |= IS_MF_SD(bp) ? VFPF_QUEUE_FLG_OV : 0;
+	flags |= VFPF_QUEUE_FLG_VLAN;
+	DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+
+	/* Common */
+	req->vf_qid = fp_idx;
+	req->param_valid = VFPF_RXQ_VALID | VFPF_TXQ_VALID;
+
+	/* Rx */
+	req->rxq.rcq_addr = fp->rx_comp_mapping;
+	req->rxq.rcq_np_addr = fp->rx_comp_mapping + BCM_PAGE_SIZE;
+	req->rxq.rxq_addr = fp->rx_desc_mapping;
+	req->rxq.sge_addr = fp->rx_sge_mapping;
+	req->rxq.vf_sb = fp_idx;
+	req->rxq.sb_index = HC_INDEX_ETH_RX_CQ_CONS;
+	req->rxq.hc_rate = bp->rx_ticks ? 1000000/bp->rx_ticks : 0;
+	req->rxq.mtu = bp->dev->mtu;
+	req->rxq.buf_sz = fp->rx_buf_size;
+	req->rxq.sge_buf_sz = BCM_PAGE_SIZE * PAGES_PER_SGE;
+	req->rxq.tpa_agg_sz = tpa_agg_size;
+	req->rxq.max_sge_pkt = SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
+	req->rxq.max_sge_pkt = ((req->rxq.max_sge_pkt + PAGES_PER_SGE - 1) &
+			  (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
+	req->rxq.flags = flags;
+	req->rxq.drop_flags = 0;
+	req->rxq.cache_line_log = BNX2X_RX_ALIGN_SHIFT;
+	req->rxq.stat_id = -1; /* No stats at the moment */
+
+	/* Tx */
+	req->txq.txq_addr = fp->txdata_ptr[FIRST_TX_COS_INDEX]->tx_desc_mapping;
+	req->txq.vf_sb = fp_idx;
+	req->txq.sb_index = HC_INDEX_ETH_TX_CQ_CONS_COS0;
+	req->txq.hc_rate = bp->tx_ticks ? 1000000/bp->tx_ticks : 0;
+	req->txq.flags = flags;
+	req->txq.traffic_type = LLFC_TRAFFIC_TYPE_NW;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+	if (rc)
+		BNX2X_ERR("Sending SETUP_Q message for queue[%d] failed!\n",
+			  fp_idx);
+
+	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+		BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
+			  fp_idx, resp->hdr.status);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
+{
+	struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	int rc;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_TEARDOWN_Q,
+			sizeof(*req));
+
+	req->vf_qid = qidx;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+	if (rc) {
+		BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
+			  rc);
+		return rc;
+	}
+
+	/* PF failed the transaction */
+	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+		BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
+			  resp->hdr.status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* request pf to add a mac for the vf */
+int bnx2x_vfpf_set_mac(struct bnx2x *bp)
+{
+	struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	int rc;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+			sizeof(*req));
+
+	req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED;
+	req->vf_qid = 0;
+	req->n_mac_vlan_filters = 1;
+	req->filters[0].flags =
+		VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;
+
+	/* sample bulletin board for new mac */
+	bnx2x_sample_bulletin(bp);
+
+	/* copy mac from device to request */
+	memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	/* send message to pf */
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+	if (rc) {
+		BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
+		return rc;
+	}
+
+	/* failure may mean PF was configured with a new mac for us */
+	while (resp->hdr.status == PFVF_STATUS_FAILURE) {
+		DP(BNX2X_MSG_IOV,
+		   "vfpf SET MAC failed. Check bulletin board for new posts\n");
+
+		/* check if bulletin board was updated */
+		if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
+			/* copy mac from device to request */
+			memcpy(req->filters[0].mac, bp->dev->dev_addr,
+			       ETH_ALEN);
+
+			/* send message to pf */
+			rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
+					       bp->vf2pf_mbox_mapping);
+		} else {
+			/* no new info in bulletin */
+			break;
+		}
+	}
+
+	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+		BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int bnx2x_vfpf_set_mcast(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	int rc, i = 0;
+	struct netdev_hw_addr *ha;
+
+	if (bp->state != BNX2X_STATE_OPEN) {
+		DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
+		return -EINVAL;
+	}
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+			sizeof(*req));
+
+	/* Get Rx mode requested */
+	DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
+
+	netdev_for_each_mc_addr(ha, dev) {
+		DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
+		   bnx2x_mc_addr(ha));
+		memcpy(req->multicast[i], bnx2x_mc_addr(ha), ETH_ALEN);
+		i++;
+	}
+
+	/* We support four PFVF_MAX_MULTICAST_PER_VF mcast
+	  * addresses tops
+	  */
+	if (i >= PFVF_MAX_MULTICAST_PER_VF) {
+		DP(NETIF_MSG_IFUP,
+		   "VF supports not more than %d multicast MAC addresses\n",
+		   PFVF_MAX_MULTICAST_PER_VF);
+		return -EINVAL;
+	}
+
+	req->n_multicast = i;
+	req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED;
+	req->vf_qid = 0;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+	if (rc) {
+		BNX2X_ERR("Sending a message failed: %d\n", rc);
+		return rc;
+	}
+
+	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+		BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
+			  resp->hdr.status);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
+{
+	int mode = bp->rx_mode;
+	struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+	struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+	int rc;
+
+	/* clear mailbox and prep first tlv */
+	bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+			sizeof(*req));
+
+	DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
+
+	switch (mode) {
+	case BNX2X_RX_MODE_NONE: /* no Rx */
+		req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
+		break;
+	case BNX2X_RX_MODE_NORMAL:
+		req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
+		req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+		req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+		break;
+	case BNX2X_RX_MODE_ALLMULTI:
+		req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+		req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+		req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+		break;
+	case BNX2X_RX_MODE_PROMISC:
+		req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
+		req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+		req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+		break;
+	default:
+		BNX2X_ERR("BAD rx mode (%d)\n", mode);
+		return -EINVAL;
+	}
+
+	req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
+	req->vf_qid = 0;
+
+	/* add list termination tlv */
+	bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+
+	/* output tlvs list */
+	bnx2x_dp_tlv_list(bp, req);
+
+	rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+	if (rc)
+		BNX2X_ERR("Sending a message failed: %d\n", rc);
+
+	if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+		BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+/* General service functions */
+static void storm_memset_vf_mbx_ack(struct bnx2x *bp, u16 abs_fid)
+{
+	u32 addr = BAR_CSTRORM_INTMEM +
+		   CSTORM_VF_PF_CHANNEL_STATE_OFFSET(abs_fid);
+
+	REG_WR8(bp, addr, VF_PF_CHANNEL_STATE_READY);
+}
+
+static void storm_memset_vf_mbx_valid(struct bnx2x *bp, u16 abs_fid)
+{
+	u32 addr = BAR_CSTRORM_INTMEM +
+		   CSTORM_VF_PF_CHANNEL_VALID_OFFSET(abs_fid);
+
+	REG_WR8(bp, addr, 1);
+}
+
+static inline void bnx2x_set_vf_mbxs_valid(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_vf(bp, i)
+		storm_memset_vf_mbx_valid(bp, bnx2x_vf(bp, i, abs_vfid));
+}
+
+/* enable vf_pf mailbox (aka vf-pf-chanell) */
+void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid)
+{
+	bnx2x_vf_flr_clnup_epilog(bp, abs_vfid);
+
+	/* enable the mailbox in the FW */
+	storm_memset_vf_mbx_ack(bp, abs_vfid);
+	storm_memset_vf_mbx_valid(bp, abs_vfid);
+
+	/* enable the VF access to the mailbox */
+	bnx2x_vf_enable_access(bp, abs_vfid);
+}
+
+/* this works only on !E1h */
+static int bnx2x_copy32_vf_dmae(struct bnx2x *bp, u8 from_vf,
+				dma_addr_t pf_addr, u8 vfid, u32 vf_addr_hi,
+				u32 vf_addr_lo, u32 len32)
+{
+	struct dmae_command dmae;
+
+	if (CHIP_IS_E1x(bp)) {
+		BNX2X_ERR("Chip revision does not support VFs\n");
+		return DMAE_NOT_RDY;
+	}
+
+	if (!bp->dmae_ready) {
+		BNX2X_ERR("DMAE is not ready, can not copy\n");
+		return DMAE_NOT_RDY;
+	}
+
+	/* set opcode and fixed command fields */
+	bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_PCI);
+
+	if (from_vf) {
+		dmae.opcode_iov = (vfid << DMAE_COMMAND_SRC_VFID_SHIFT) |
+			(DMAE_SRC_VF << DMAE_COMMAND_SRC_VFPF_SHIFT) |
+			(DMAE_DST_PF << DMAE_COMMAND_DST_VFPF_SHIFT);
+
+		dmae.opcode |= (DMAE_C_DST << DMAE_COMMAND_C_FUNC_SHIFT);
+
+		dmae.src_addr_lo = vf_addr_lo;
+		dmae.src_addr_hi = vf_addr_hi;
+		dmae.dst_addr_lo = U64_LO(pf_addr);
+		dmae.dst_addr_hi = U64_HI(pf_addr);
+	} else {
+		dmae.opcode_iov = (vfid << DMAE_COMMAND_DST_VFID_SHIFT) |
+			(DMAE_DST_VF << DMAE_COMMAND_DST_VFPF_SHIFT) |
+			(DMAE_SRC_PF << DMAE_COMMAND_SRC_VFPF_SHIFT);
+
+		dmae.opcode |= (DMAE_C_SRC << DMAE_COMMAND_C_FUNC_SHIFT);
+
+		dmae.src_addr_lo = U64_LO(pf_addr);
+		dmae.src_addr_hi = U64_HI(pf_addr);
+		dmae.dst_addr_lo = vf_addr_lo;
+		dmae.dst_addr_hi = vf_addr_hi;
+	}
+	dmae.len = len32;
+	bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_DMAE);
+
+	/* issue the command and wait for completion */
+	return bnx2x_issue_dmae_with_comp(bp, &dmae);
+}
+
+static void bnx2x_vf_mbx_resp(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
+	u64 vf_addr;
+	dma_addr_t pf_addr;
+	u16 length, type;
+	int rc;
+	struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
+
+	/* prepare response */
+	type = mbx->first_tlv.tl.type;
+	length = type == CHANNEL_TLV_ACQUIRE ?
+		sizeof(struct pfvf_acquire_resp_tlv) :
+		sizeof(struct pfvf_general_resp_tlv);
+	bnx2x_add_tlv(bp, resp, 0, type, length);
+	resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
+	bnx2x_add_tlv(bp, resp, length, CHANNEL_TLV_LIST_END,
+		      sizeof(struct channel_list_end_tlv));
+	bnx2x_dp_tlv_list(bp, resp);
+	DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
+	   mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+
+	/* send response */
+	vf_addr = HILO_U64(mbx->vf_addr_hi, mbx->vf_addr_lo) +
+		  mbx->first_tlv.resp_msg_offset;
+	pf_addr = mbx->msg_mapping +
+		  offsetof(struct bnx2x_vf_mbx_msg, resp);
+
+	/* copy the response body, if there is one, before the header, as the vf
+	 * is sensitive to the header being written
+	 */
+	if (resp->hdr.tl.length > sizeof(u64)) {
+		length = resp->hdr.tl.length - sizeof(u64);
+		vf_addr += sizeof(u64);
+		pf_addr += sizeof(u64);
+		rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
+					  U64_HI(vf_addr),
+					  U64_LO(vf_addr),
+					  length/4);
+		if (rc) {
+			BNX2X_ERR("Failed to copy response body to VF %d\n",
+				  vf->abs_vfid);
+			goto mbx_error;
+		}
+		vf_addr -= sizeof(u64);
+		pf_addr -= sizeof(u64);
+	}
+
+	/* ack the FW */
+	storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+	mmiowb();
+
+	/* initiate dmae to send the response */
+	mbx->flags &= ~VF_MSG_INPROCESS;
+
+	/* copy the response header including status-done field,
+	 * must be last dmae, must be after FW is acked
+	 */
+	rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
+				  U64_HI(vf_addr),
+				  U64_LO(vf_addr),
+				  sizeof(u64)/4);
+
+	/* unlock channel mutex */
+	bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
+
+	if (rc) {
+		BNX2X_ERR("Failed to copy response status to VF %d\n",
+			  vf->abs_vfid);
+		goto mbx_error;
+	}
+	return;
+
+mbx_error:
+	bnx2x_vf_release(bp, vf, false); /* non blocking */
+}
+
+static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				      struct bnx2x_vf_mbx *mbx, int vfop_status)
+{
+	int i;
+	struct pfvf_acquire_resp_tlv *resp = &mbx->msg->resp.acquire_resp;
+	struct pf_vf_resc *resc = &resp->resc;
+	u8 status = bnx2x_pfvf_status_codes(vfop_status);
+
+	memset(resp, 0, sizeof(*resp));
+
+	/* fill in pfdev info */
+	resp->pfdev_info.chip_num = bp->common.chip_id;
+	resp->pfdev_info.db_size = (1 << BNX2X_DB_SHIFT);
+	resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2;
+	resp->pfdev_info.pf_cap = (PFVF_CAP_RSS |
+				   /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA);
+	bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver,
+			  sizeof(resp->pfdev_info.fw_ver));
+
+	if (status == PFVF_STATUS_NO_RESOURCE ||
+	    status == PFVF_STATUS_SUCCESS) {
+		/* set resources numbers, if status equals NO_RESOURCE these
+		 * are max possible numbers
+		 */
+		resc->num_rxqs = vf_rxq_count(vf) ? :
+			bnx2x_vf_max_queue_cnt(bp, vf);
+		resc->num_txqs = vf_txq_count(vf) ? :
+			bnx2x_vf_max_queue_cnt(bp, vf);
+		resc->num_sbs = vf_sb_count(vf);
+		resc->num_mac_filters = vf_mac_rules_cnt(vf);
+		resc->num_vlan_filters = vf_vlan_rules_cnt(vf);
+		resc->num_mc_filters = 0;
+
+		if (status == PFVF_STATUS_SUCCESS) {
+			/* fill in the allocated resources */
+			struct pf_vf_bulletin_content *bulletin =
+				BP_VF_BULLETIN(bp, vf->index);
+
+			for_each_vfq(vf, i)
+				resc->hw_qid[i] =
+					vfq_qzone_id(vf, vfq_get(vf, i));
+
+			for_each_vf_sb(vf, i) {
+				resc->hw_sbs[i].hw_sb_id = vf_igu_sb(vf, i);
+				resc->hw_sbs[i].sb_qid = vf_hc_qzone(vf, i);
+			}
+
+			/* if a mac has been set for this vf, supply it */
+			if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
+				memcpy(resc->current_mac_addr, bulletin->mac,
+				       ETH_ALEN);
+			}
+		}
+	}
+
+	DP(BNX2X_MSG_IOV, "VF[%d] ACQUIRE_RESPONSE: pfdev_info- chip_num=0x%x, db_size=%d, idx_per_sb=%d, pf_cap=0x%x\n"
+	   "resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d, n_mcs-%d, fw_ver: '%s'\n",
+	   vf->abs_vfid,
+	   resp->pfdev_info.chip_num,
+	   resp->pfdev_info.db_size,
+	   resp->pfdev_info.indices_per_sb,
+	   resp->pfdev_info.pf_cap,
+	   resc->num_rxqs,
+	   resc->num_txqs,
+	   resc->num_sbs,
+	   resc->num_mac_filters,
+	   resc->num_vlan_filters,
+	   resc->num_mc_filters,
+	   resp->pfdev_info.fw_ver);
+
+	DP_CONT(BNX2X_MSG_IOV, "hw_qids- [ ");
+	for (i = 0; i < vf_rxq_count(vf); i++)
+		DP_CONT(BNX2X_MSG_IOV, "%d ", resc->hw_qid[i]);
+	DP_CONT(BNX2X_MSG_IOV, "], sb_info- [ ");
+	for (i = 0; i < vf_sb_count(vf); i++)
+		DP_CONT(BNX2X_MSG_IOV, "%d:%d ",
+			resc->hw_sbs[i].hw_sb_id,
+			resc->hw_sbs[i].sb_qid);
+	DP_CONT(BNX2X_MSG_IOV, "]\n");
+
+	/* send the response */
+	vf->op_rc = vfop_status;
+	bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				 struct bnx2x_vf_mbx *mbx)
+{
+	int rc;
+	struct vfpf_acquire_tlv *acquire = &mbx->msg->req.acquire;
+
+	/* log vfdef info */
+	DP(BNX2X_MSG_IOV,
+	   "VF[%d] ACQUIRE: vfdev_info- vf_id %d, vf_os %d resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d, n_mcs-%d\n",
+	   vf->abs_vfid, acquire->vfdev_info.vf_id, acquire->vfdev_info.vf_os,
+	   acquire->resc_request.num_rxqs, acquire->resc_request.num_txqs,
+	   acquire->resc_request.num_sbs, acquire->resc_request.num_mac_filters,
+	   acquire->resc_request.num_vlan_filters,
+	   acquire->resc_request.num_mc_filters);
+
+	/* acquire the resources */
+	rc = bnx2x_vf_acquire(bp, vf, &acquire->resc_request);
+
+	/* store address of vf's bulletin board */
+	vf->bulletin_map = acquire->bulletin_addr;
+
+	/* response */
+	bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc);
+}
+
+static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+			      struct bnx2x_vf_mbx *mbx)
+{
+	struct vfpf_init_tlv *init = &mbx->msg->req.init;
+
+	/* record ghost addresses from vf message */
+	vf->spq_map = init->spq_addr;
+	vf->fw_stat_map = init->stats_addr;
+	vf->op_rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
+
+	/* response */
+	bnx2x_vf_mbx_resp(bp, vf);
+}
+
+/* convert MBX queue-flags to standard SP queue-flags */
+static void bnx2x_vf_mbx_set_q_flags(u32 mbx_q_flags,
+				     unsigned long *sp_q_flags)
+{
+	if (mbx_q_flags & VFPF_QUEUE_FLG_TPA)
+		__set_bit(BNX2X_Q_FLG_TPA, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_TPA_IPV6)
+		__set_bit(BNX2X_Q_FLG_TPA_IPV6, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_TPA_GRO)
+		__set_bit(BNX2X_Q_FLG_TPA_GRO, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_STATS)
+		__set_bit(BNX2X_Q_FLG_STATS, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_OV)
+		__set_bit(BNX2X_Q_FLG_OV, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_VLAN)
+		__set_bit(BNX2X_Q_FLG_VLAN, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_COS)
+		__set_bit(BNX2X_Q_FLG_COS, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_HC)
+		__set_bit(BNX2X_Q_FLG_HC, sp_q_flags);
+	if (mbx_q_flags & VFPF_QUEUE_FLG_DHC)
+		__set_bit(BNX2X_Q_FLG_DHC, sp_q_flags);
+}
+
+static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				 struct bnx2x_vf_mbx *mbx)
+{
+	struct vfpf_setup_q_tlv *setup_q = &mbx->msg->req.setup_q;
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vf_mbx_resp,
+		.block = false,
+	};
+
+	/* verify vf_qid */
+	if (setup_q->vf_qid >= vf_rxq_count(vf)) {
+		BNX2X_ERR("vf_qid %d invalid, max queue count is %d\n",
+			  setup_q->vf_qid, vf_rxq_count(vf));
+		vf->op_rc = -EINVAL;
+		goto response;
+	}
+
+	/* tx queues must be setup alongside rx queues thus if the rx queue
+	 * is not marked as valid there's nothing to do.
+	 */
+	if (setup_q->param_valid & (VFPF_RXQ_VALID|VFPF_TXQ_VALID)) {
+		struct bnx2x_vf_queue *q = vfq_get(vf, setup_q->vf_qid);
+		unsigned long q_type = 0;
+
+		struct bnx2x_queue_init_params *init_p;
+		struct bnx2x_queue_setup_params *setup_p;
+
+		/* reinit the VF operation context */
+		memset(&vf->op_params.qctor, 0 , sizeof(vf->op_params.qctor));
+		setup_p = &vf->op_params.qctor.prep_qsetup;
+		init_p =  &vf->op_params.qctor.qstate.params.init;
+
+		/* activate immediately */
+		__set_bit(BNX2X_Q_FLG_ACTIVE, &setup_p->flags);
+
+		if (setup_q->param_valid & VFPF_TXQ_VALID) {
+			struct bnx2x_txq_setup_params *txq_params =
+				&setup_p->txq_params;
+
+			__set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+
+			/* save sb resource index */
+			q->sb_idx = setup_q->txq.vf_sb;
+
+			/* tx init */
+			init_p->tx.hc_rate = setup_q->txq.hc_rate;
+			init_p->tx.sb_cq_index = setup_q->txq.sb_index;
+
+			bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+						 &init_p->tx.flags);
+
+			/* tx setup - flags */
+			bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+						 &setup_p->flags);
+
+			/* tx setup - general, nothing */
+
+			/* tx setup - tx */
+			txq_params->dscr_map = setup_q->txq.txq_addr;
+			txq_params->sb_cq_index = setup_q->txq.sb_index;
+			txq_params->traffic_type = setup_q->txq.traffic_type;
+
+			bnx2x_vfop_qctor_dump_tx(bp, vf, init_p, setup_p,
+						 q->index, q->sb_idx);
+		}
+
+		if (setup_q->param_valid & VFPF_RXQ_VALID) {
+			struct bnx2x_rxq_setup_params *rxq_params =
+							&setup_p->rxq_params;
+
+			__set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+
+			/* Note: there is no support for different SBs
+			 * for TX and RX
+			 */
+			q->sb_idx = setup_q->rxq.vf_sb;
+
+			/* rx init */
+			init_p->rx.hc_rate = setup_q->rxq.hc_rate;
+			init_p->rx.sb_cq_index = setup_q->rxq.sb_index;
+			bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+						 &init_p->rx.flags);
+
+			/* rx setup - flags */
+			bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+						 &setup_p->flags);
+
+			/* rx setup - general */
+			setup_p->gen_params.mtu = setup_q->rxq.mtu;
+
+			/* rx setup - rx */
+			rxq_params->drop_flags = setup_q->rxq.drop_flags;
+			rxq_params->dscr_map = setup_q->rxq.rxq_addr;
+			rxq_params->sge_map = setup_q->rxq.sge_addr;
+			rxq_params->rcq_map = setup_q->rxq.rcq_addr;
+			rxq_params->rcq_np_map = setup_q->rxq.rcq_np_addr;
+			rxq_params->buf_sz = setup_q->rxq.buf_sz;
+			rxq_params->tpa_agg_sz = setup_q->rxq.tpa_agg_sz;
+			rxq_params->max_sges_pkt = setup_q->rxq.max_sge_pkt;
+			rxq_params->sge_buf_sz = setup_q->rxq.sge_buf_sz;
+			rxq_params->cache_line_log =
+				setup_q->rxq.cache_line_log;
+			rxq_params->sb_cq_index = setup_q->rxq.sb_index;
+
+			bnx2x_vfop_qctor_dump_rx(bp, vf, init_p, setup_p,
+						 q->index, q->sb_idx);
+		}
+		/* complete the preparations */
+		bnx2x_vfop_qctor_prep(bp, vf, q, &vf->op_params.qctor, q_type);
+
+		vf->op_rc = bnx2x_vfop_qsetup_cmd(bp, vf, &cmd, q->index);
+		if (vf->op_rc)
+			goto response;
+		return;
+	}
+response:
+	bnx2x_vf_mbx_resp(bp, vf);
+}
+
+enum bnx2x_vfop_filters_state {
+	   BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+	   BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
+	   BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
+	   BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
+	   BNX2X_VFOP_MBX_Q_FILTERS_DONE
+};
+
+static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
+				     struct bnx2x_virtf *vf,
+				     struct vfpf_set_q_filters_tlv *tlv,
+				     struct bnx2x_vfop_filters **pfl,
+				     u32 type_flag)
+{
+	int i, j;
+	struct bnx2x_vfop_filters *fl = NULL;
+	size_t fsz;
+
+	fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
+		sizeof(struct bnx2x_vfop_filters);
+
+	fl = kzalloc(fsz, GFP_KERNEL);
+	if (!fl)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&fl->head);
+
+	for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
+		struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
+
+		if ((msg_filter->flags & type_flag) != type_flag)
+			continue;
+		if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
+			fl->filters[j].mac = msg_filter->mac;
+			fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
+		} else {
+			fl->filters[j].vid = msg_filter->vlan_tag;
+			fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
+		}
+		fl->filters[j].add =
+			(msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
+			true : false;
+		list_add_tail(&fl->filters[j++].link, &fl->head);
+	}
+	if (list_empty(&fl->head))
+		kfree(fl);
+	else
+		*pfl = fl;
+
+	return 0;
+}
+
+static void bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx,
+				       struct vfpf_q_mac_vlan_filter *filter)
+{
+	DP(msglvl, "MAC-VLAN[%d] -- flags=0x%x\n", idx, filter->flags);
+	if (filter->flags & VFPF_Q_FILTER_VLAN_TAG_VALID)
+		DP_CONT(msglvl, ", vlan=%d", filter->vlan_tag);
+	if (filter->flags & VFPF_Q_FILTER_DEST_MAC_VALID)
+		DP_CONT(msglvl, ", MAC=%pM", filter->mac);
+	DP_CONT(msglvl, "\n");
+}
+
+static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
+				       struct vfpf_set_q_filters_tlv *filters)
+{
+	int i;
+
+	if (filters->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED)
+		for (i = 0; i < filters->n_mac_vlan_filters; i++)
+			bnx2x_vf_mbx_dp_q_filter(bp, msglvl, i,
+						 &filters->filters[i]);
+
+	if (filters->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED)
+		DP(msglvl, "RX-MASK=0x%x\n", filters->rx_mask);
+
+	if (filters->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED)
+		for (i = 0; i < filters->n_multicast; i++)
+			DP(msglvl, "MULTICAST=%pM\n", filters->multicast[i]);
+}
+
+#define VFPF_MAC_FILTER		VFPF_Q_FILTER_DEST_MAC_VALID
+#define VFPF_VLAN_FILTER	VFPF_Q_FILTER_VLAN_TAG_VALID
+
+static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+	int rc;
+
+	struct vfpf_set_q_filters_tlv *msg =
+		&BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
+
+	struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+	enum bnx2x_vfop_filters_state state = vfop->state;
+
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vfop_mbx_qfilters,
+		.block = false,
+	};
+
+	DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
+
+	if (vfop->rc < 0)
+		goto op_err;
+
+	switch (state) {
+	case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
+		/* next state */
+		vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
+
+		/* check for any vlan/mac changes */
+		if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+			/* build mac list */
+			struct bnx2x_vfop_filters *fl = NULL;
+
+			vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+							     VFPF_MAC_FILTER);
+			if (vfop->rc)
+				goto op_err;
+
+			if (fl) {
+				/* set mac list */
+				rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
+							     msg->vf_qid,
+							     false);
+				if (rc) {
+					vfop->rc = rc;
+					goto op_err;
+				}
+				return;
+			}
+		}
+		/* fall through */
+
+	case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
+		/* next state */
+		vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
+
+		/* check for any vlan/mac changes */
+		if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+			/* build vlan list */
+			struct bnx2x_vfop_filters *fl = NULL;
+
+			vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+							     VFPF_VLAN_FILTER);
+			if (vfop->rc)
+				goto op_err;
+
+			if (fl) {
+				/* set vlan list */
+				rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
+							      msg->vf_qid,
+							      false);
+				if (rc) {
+					vfop->rc = rc;
+					goto op_err;
+				}
+				return;
+			}
+		}
+		/* fall through */
+
+	case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
+		/* next state */
+		vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
+
+		if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
+			unsigned long accept = 0;
+
+			/* covert VF-PF if mask to bnx2x accept flags */
+			if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
+				__set_bit(BNX2X_ACCEPT_UNICAST, &accept);
+
+			if (msg->rx_mask &
+					VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
+				__set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
+
+			if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
+				__set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
+
+			if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
+				__set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
+
+			if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
+				__set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
+
+			/* A packet arriving the vf's mac should be accepted
+			 * with any vlan
+			 */
+			__set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
+
+			/* set rx-mode */
+			rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
+						   msg->vf_qid, accept);
+			if (rc) {
+				vfop->rc = rc;
+				goto op_err;
+			}
+			return;
+		}
+		/* fall through */
+
+	case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
+		/* next state */
+		vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
+
+		if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
+			/* set mcasts */
+			rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
+						  msg->n_multicast, false);
+			if (rc) {
+				vfop->rc = rc;
+				goto op_err;
+			}
+			return;
+		}
+		/* fall through */
+op_done:
+	case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
+		bnx2x_vfop_end(bp, vf, vfop);
+		return;
+op_err:
+	BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
+		  vf->abs_vfid, msg->vf_qid, vfop->rc);
+	goto op_done;
+
+	default:
+		bnx2x_vfop_default(state);
+	}
+}
+
+static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp,
+					struct bnx2x_virtf *vf,
+					struct bnx2x_vfop_cmd *cmd)
+{
+	struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+	if (vfop) {
+		bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+				 bnx2x_vfop_mbx_qfilters, cmd->done);
+		return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters,
+					     cmd->block);
+	}
+	return -ENOMEM;
+}
+
+static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
+				       struct bnx2x_virtf *vf,
+				       struct bnx2x_vf_mbx *mbx)
+{
+	struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
+	struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vf_mbx_resp,
+		.block = false,
+	};
+
+	/* if a mac was already set for this VF via the set vf mac ndo, we only
+	 * accept mac configurations of that mac. Why accept them at all?
+	 * because PF may have been unable to configure the mac at the time
+	 * since queue was not set up.
+	 */
+	if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
+		/* once a mac was set by ndo can only accept a single mac... */
+		if (filters->n_mac_vlan_filters > 1) {
+			BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n",
+				  vf->abs_vfid);
+			vf->op_rc = -EPERM;
+			goto response;
+		}
+
+		/* ...and only the mac set by the ndo */
+		if (filters->n_mac_vlan_filters == 1 &&
+		    memcmp(filters->filters->mac, bulletin->mac, ETH_ALEN)) {
+			BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n",
+				  vf->abs_vfid);
+
+			vf->op_rc = -EPERM;
+			goto response;
+		}
+	}
+
+	/* verify vf_qid */
+	if (filters->vf_qid > vf_rxq_count(vf))
+		goto response;
+
+	DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n",
+	   vf->abs_vfid,
+	   filters->vf_qid);
+
+	/* print q_filter message */
+	bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters);
+
+	vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd);
+	if (vf->op_rc)
+		goto response;
+	return;
+
+response:
+	bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_teardown_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				    struct bnx2x_vf_mbx *mbx)
+{
+	int qid = mbx->msg->req.q_op.vf_qid;
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vf_mbx_resp,
+		.block = false,
+	};
+
+	DP(BNX2X_MSG_IOV, "VF[%d] Q_TEARDOWN: vf_qid=%d\n",
+	   vf->abs_vfid, qid);
+
+	vf->op_rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qid);
+	if (vf->op_rc)
+		bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_close_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				  struct bnx2x_vf_mbx *mbx)
+{
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vf_mbx_resp,
+		.block = false,
+	};
+
+	DP(BNX2X_MSG_IOV, "VF[%d] VF_CLOSE\n", vf->abs_vfid);
+
+	vf->op_rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
+	if (vf->op_rc)
+		bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_release_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				    struct bnx2x_vf_mbx *mbx)
+{
+	struct bnx2x_vfop_cmd cmd = {
+		.done = bnx2x_vf_mbx_resp,
+		.block = false,
+	};
+
+	DP(BNX2X_MSG_IOV, "VF[%d] VF_RELEASE\n", vf->abs_vfid);
+
+	vf->op_rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+	if (vf->op_rc)
+		bnx2x_vf_mbx_resp(bp, vf);
+}
+
+/* dispatch request */
+static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
+				  struct bnx2x_vf_mbx *mbx)
+{
+	int i;
+
+	/* check if tlv type is known */
+	if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) {
+		/* Lock the per vf op mutex and note the locker's identity.
+		 * The unlock will take place in mbx response.
+		 */
+		bnx2x_lock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
+
+		/* switch on the opcode */
+		switch (mbx->first_tlv.tl.type) {
+		case CHANNEL_TLV_ACQUIRE:
+			bnx2x_vf_mbx_acquire(bp, vf, mbx);
+			break;
+		case CHANNEL_TLV_INIT:
+			bnx2x_vf_mbx_init_vf(bp, vf, mbx);
+			break;
+		case CHANNEL_TLV_SETUP_Q:
+			bnx2x_vf_mbx_setup_q(bp, vf, mbx);
+			break;
+		case CHANNEL_TLV_SET_Q_FILTERS:
+			bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
+			break;
+		case CHANNEL_TLV_TEARDOWN_Q:
+			bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
+			break;
+		case CHANNEL_TLV_CLOSE:
+			bnx2x_vf_mbx_close_vf(bp, vf, mbx);
+			break;
+		case CHANNEL_TLV_RELEASE:
+			bnx2x_vf_mbx_release_vf(bp, vf, mbx);
+			break;
+		}
+
+	} else {
+		/* unknown TLV - this may belong to a VF driver from the future
+		 * - a version written after this PF driver was written, which
+		 * supports features unknown as of yet. Too bad since we don't
+		 * support them. Or this may be because someone wrote a crappy
+		 * VF driver and is sending garbage over the channel.
+		 */
+		BNX2X_ERR("unknown TLV. type %d length %d. first 20 bytes of mailbox buffer:\n",
+			  mbx->first_tlv.tl.type, mbx->first_tlv.tl.length);
+		for (i = 0; i < 20; i++)
+			DP_CONT(BNX2X_MSG_IOV, "%x ",
+				mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
+
+		/* test whether we can respond to the VF (do we have an address
+		 * for it?)
+		 */
+		if (vf->state == VF_ACQUIRED) {
+			/* mbx_resp uses the op_rc of the VF */
+			vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
+
+			/* notify the VF that we do not support this request */
+			bnx2x_vf_mbx_resp(bp, vf);
+		} else {
+			/* can't send a response since this VF is unknown to us
+			 * just unlock the channel and be done with.
+			 */
+			bnx2x_unlock_vf_pf_channel(bp, vf,
+						   mbx->first_tlv.tl.type);
+		}
+	}
+}
+
+/* handle new vf-pf message */
+void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
+{
+	struct bnx2x_virtf *vf;
+	struct bnx2x_vf_mbx *mbx;
+	u8 vf_idx;
+	int rc;
+
+	DP(BNX2X_MSG_IOV,
+	   "vf pf event received: vfid %d, address_hi %x, address lo %x",
+	   vfpf_event->vf_id, vfpf_event->msg_addr_hi, vfpf_event->msg_addr_lo);
+	/* Sanity checks consider removing later */
+
+	/* check if the vf_id is valid */
+	if (vfpf_event->vf_id - BP_VFDB(bp)->sriov.first_vf_in_pf >
+	    BNX2X_NR_VIRTFN(bp)) {
+		BNX2X_ERR("Illegal vf_id %d max allowed: %d\n",
+			  vfpf_event->vf_id, BNX2X_NR_VIRTFN(bp));
+		goto mbx_done;
+	}
+	vf_idx = bnx2x_vf_idx_by_abs_fid(bp, vfpf_event->vf_id);
+	mbx = BP_VF_MBX(bp, vf_idx);
+
+	/* verify an event is not currently being processed -
+	 * debug failsafe only
+	 */
+	if (mbx->flags & VF_MSG_INPROCESS) {
+		BNX2X_ERR("Previous message is still being processed, vf_id %d\n",
+			  vfpf_event->vf_id);
+		goto mbx_done;
+	}
+	vf = BP_VF(bp, vf_idx);
+
+	/* save the VF message address */
+	mbx->vf_addr_hi = vfpf_event->msg_addr_hi;
+	mbx->vf_addr_lo = vfpf_event->msg_addr_lo;
+	DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
+	   mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+
+	/* dmae to get the VF request */
+	rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping, vf->abs_vfid,
+				  mbx->vf_addr_hi, mbx->vf_addr_lo,
+				  sizeof(union vfpf_tlvs)/4);
+	if (rc) {
+		BNX2X_ERR("Failed to copy request VF %d\n", vf->abs_vfid);
+		goto mbx_error;
+	}
+
+	/* process the VF message header */
+	mbx->first_tlv = mbx->msg->req.first_tlv;
+
+	/* dispatch the request (will prepare the response) */
+	bnx2x_vf_mbx_request(bp, vf, mbx);
+	goto mbx_done;
+
+mbx_error:
+	bnx2x_vf_release(bp, vf, false); /* non blocking */
+mbx_done:
+	return;
+}
+
+/* propagate local bulletin board to vf */
+int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
+{
+	struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf);
+	dma_addr_t pf_addr = BP_VF_BULLETIN_DMA(bp)->mapping +
+		vf * BULLETIN_CONTENT_SIZE;
+	dma_addr_t vf_addr = bnx2x_vf(bp, vf, bulletin_map);
+	int rc;
+
+	/* can only update vf after init took place */
+	if (bnx2x_vf(bp, vf, state) != VF_ENABLED &&
+	    bnx2x_vf(bp, vf, state) != VF_ACQUIRED)
+		return 0;
+
+	/* increment bulletin board version and compute crc */
+	bulletin->version++;
+	bulletin->length = BULLETIN_CONTENT_SIZE;
+	bulletin->crc = bnx2x_crc_vf_bulletin(bp, bulletin);
+
+	/* propagate bulletin board via dmae to vm memory */
+	rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr,
+				  bnx2x_vf(bp, vf, abs_vfid), U64_HI(vf_addr),
+				  U64_LO(vf_addr), bulletin->length / 4);
+	return rc;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
new file mode 100644
index 0000000..bfc80ba
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
@@ -0,0 +1,360 @@
+/* bnx2x_vfpf.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2011-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Ariel Elior <ariele@broadcom.com>
+ */
+#ifndef VF_PF_IF_H
+#define VF_PF_IF_H
+
+#ifdef CONFIG_BNX2X_SRIOV
+
+/* Common definitions for all HVs */
+struct vf_pf_resc_request {
+	u8  num_rxqs;
+	u8  num_txqs;
+	u8  num_sbs;
+	u8  num_mac_filters;
+	u8  num_vlan_filters;
+	u8  num_mc_filters; /* No limit  so superfluous */
+};
+
+struct hw_sb_info {
+	u8 hw_sb_id;	/* aka absolute igu id, used to ack the sb */
+	u8 sb_qid;	/* used to update DHC for sb */
+};
+
+/* HW VF-PF channel definitions
+ * A.K.A VF-PF mailbox
+ */
+#define TLV_BUFFER_SIZE			1024
+#define PF_VF_BULLETIN_SIZE		512
+
+#define VFPF_QUEUE_FLG_TPA		0x0001
+#define VFPF_QUEUE_FLG_TPA_IPV6		0x0002
+#define VFPF_QUEUE_FLG_TPA_GRO		0x0004
+#define VFPF_QUEUE_FLG_CACHE_ALIGN	0x0008
+#define VFPF_QUEUE_FLG_STATS		0x0010
+#define VFPF_QUEUE_FLG_OV		0x0020
+#define VFPF_QUEUE_FLG_VLAN		0x0040
+#define VFPF_QUEUE_FLG_COS		0x0080
+#define VFPF_QUEUE_FLG_HC		0x0100
+#define VFPF_QUEUE_FLG_DHC		0x0200
+
+#define VFPF_QUEUE_DROP_IP_CS_ERR	(1 << 0)
+#define VFPF_QUEUE_DROP_TCP_CS_ERR	(1 << 1)
+#define VFPF_QUEUE_DROP_TTL0		(1 << 2)
+#define VFPF_QUEUE_DROP_UDP_CS_ERR	(1 << 3)
+
+#define VFPF_RX_MASK_ACCEPT_NONE		0x00000000
+#define VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST	0x00000001
+#define VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST	0x00000002
+#define VFPF_RX_MASK_ACCEPT_ALL_UNICAST		0x00000004
+#define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST	0x00000008
+#define VFPF_RX_MASK_ACCEPT_BROADCAST		0x00000010
+#define BULLETIN_CONTENT_SIZE		(sizeof(struct pf_vf_bulletin_content))
+#define BULLETIN_ATTEMPTS	5 /* crc failures before throwing towel */
+#define BULLETIN_CRC_SEED	0
+
+enum {
+	PFVF_STATUS_WAITING = 0,
+	PFVF_STATUS_SUCCESS,
+	PFVF_STATUS_FAILURE,
+	PFVF_STATUS_NOT_SUPPORTED,
+	PFVF_STATUS_NO_RESOURCE
+};
+
+/* vf pf channel tlvs */
+/* general tlv header (used for both vf->pf request and pf->vf response) */
+struct channel_tlv {
+	u16 type;
+	u16 length;
+};
+
+/* header of first vf->pf tlv carries the offset used to calculate response
+ * buffer address
+ */
+struct vfpf_first_tlv {
+	struct channel_tlv tl;
+	u32 resp_msg_offset;
+};
+
+/* header of pf->vf tlvs, carries the status of handling the request */
+struct pfvf_tlv {
+	struct channel_tlv tl;
+	u8 status;
+	u8 padding[3];
+};
+
+/* response tlv used for most tlvs */
+struct pfvf_general_resp_tlv {
+	struct pfvf_tlv hdr;
+};
+
+/* used to terminate and pad a tlv list */
+struct channel_list_end_tlv {
+	struct channel_tlv tl;
+	u8 padding[4];
+};
+
+/* Acquire */
+struct vfpf_acquire_tlv {
+	struct vfpf_first_tlv first_tlv;
+
+	struct vf_pf_vfdev_info {
+		/* the following fields are for debug purposes */
+		u8  vf_id;		/* ME register value */
+		u8  vf_os;		/* e.g. Linux, W2K8 */
+		u8 padding[2];
+	} vfdev_info;
+
+	struct vf_pf_resc_request resc_request;
+
+	aligned_u64 bulletin_addr;
+};
+
+/* simple operation request on queue */
+struct vfpf_q_op_tlv {
+	struct vfpf_first_tlv	first_tlv;
+	u8 vf_qid;
+	u8 padding[3];
+};
+
+/* acquire response tlv - carries the allocated resources */
+struct pfvf_acquire_resp_tlv {
+	struct pfvf_tlv hdr;
+	struct pf_vf_pfdev_info {
+		u32 chip_num;
+		u32 pf_cap;
+#define PFVF_CAP_RSS		0x00000001
+#define PFVF_CAP_DHC		0x00000002
+#define PFVF_CAP_TPA		0x00000004
+		char fw_ver[32];
+		u16 db_size;
+		u8  indices_per_sb;
+		u8  padding;
+	} pfdev_info;
+	struct pf_vf_resc {
+		/* in case of status NO_RESOURCE in message hdr, pf will fill
+		 * this struct with suggested amount of resources for next
+		 * acquire request
+		 */
+#define PFVF_MAX_QUEUES_PER_VF         16
+#define PFVF_MAX_SBS_PER_VF            16
+		struct hw_sb_info hw_sbs[PFVF_MAX_SBS_PER_VF];
+		u8	hw_qid[PFVF_MAX_QUEUES_PER_VF];
+		u8	num_rxqs;
+		u8	num_txqs;
+		u8	num_sbs;
+		u8	num_mac_filters;
+		u8	num_vlan_filters;
+		u8	num_mc_filters;
+		u8	permanent_mac_addr[ETH_ALEN];
+		u8	current_mac_addr[ETH_ALEN];
+		u8	padding[2];
+	} resc;
+};
+
+/* Init VF */
+struct vfpf_init_tlv {
+	struct vfpf_first_tlv first_tlv;
+	aligned_u64 sb_addr[PFVF_MAX_SBS_PER_VF]; /* vf_sb based */
+	aligned_u64 spq_addr;
+	aligned_u64 stats_addr;
+};
+
+/* Setup Queue */
+struct vfpf_setup_q_tlv {
+	struct vfpf_first_tlv first_tlv;
+
+	struct vf_pf_rxq_params {
+		/* physical addresses */
+		aligned_u64 rcq_addr;
+		aligned_u64 rcq_np_addr;
+		aligned_u64 rxq_addr;
+		aligned_u64 sge_addr;
+
+		/* sb + hc info */
+		u8  vf_sb;		/* index in hw_sbs[] */
+		u8  sb_index;		/* Index in the SB */
+		u16 hc_rate;		/* desired interrupts per sec. */
+					/* valid iff VFPF_QUEUE_FLG_HC */
+		/* rx buffer info */
+		u16 mtu;
+		u16 buf_sz;
+		u16 flags;		/* VFPF_QUEUE_FLG_X flags */
+		u16 stat_id;		/* valid iff VFPF_QUEUE_FLG_STATS */
+
+		/* valid iff VFPF_QUEUE_FLG_TPA */
+		u16 sge_buf_sz;
+		u16 tpa_agg_sz;
+		u8 max_sge_pkt;
+
+		u8 drop_flags;		/* VFPF_QUEUE_DROP_X, for Linux VMs
+					 * all the flags are turned off
+					 */
+
+		u8 cache_line_log;	/* VFPF_QUEUE_FLG_CACHE_ALIGN */
+		u8 padding;
+	} rxq;
+
+	struct vf_pf_txq_params {
+		/* physical addresses */
+		aligned_u64 txq_addr;
+
+		/* sb + hc info */
+		u8  vf_sb;		/* index in hw_sbs[] */
+		u8  sb_index;		/* Index in the SB */
+		u16 hc_rate;		/* desired interrupts per sec. */
+					/* valid iff VFPF_QUEUE_FLG_HC */
+		u32 flags;		/* VFPF_QUEUE_FLG_X flags */
+		u16 stat_id;		/* valid iff VFPF_QUEUE_FLG_STATS */
+		u8  traffic_type;	/* see in setup_context() */
+		u8  padding;
+	} txq;
+
+	u8 vf_qid;			/* index in hw_qid[] */
+	u8 param_valid;
+#define VFPF_RXQ_VALID		0x01
+#define VFPF_TXQ_VALID		0x02
+	u8 padding[2];
+};
+
+/* Set Queue Filters */
+struct vfpf_q_mac_vlan_filter {
+	u32 flags;
+#define VFPF_Q_FILTER_DEST_MAC_VALID	0x01
+#define VFPF_Q_FILTER_VLAN_TAG_VALID	0x02
+#define VFPF_Q_FILTER_SET_MAC		0x100	/* set/clear */
+	u8  mac[ETH_ALEN];
+	u16 vlan_tag;
+};
+
+/* configure queue filters */
+struct vfpf_set_q_filters_tlv {
+	struct vfpf_first_tlv first_tlv;
+
+	u32 flags;
+#define VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED	0x01
+#define VFPF_SET_Q_FILTERS_MULTICAST_CHANGED	0x02
+#define VFPF_SET_Q_FILTERS_RX_MASK_CHANGED	0x04
+
+	u8 vf_qid;			/* index in hw_qid[] */
+	u8 n_mac_vlan_filters;
+	u8 n_multicast;
+	u8 padding;
+
+#define PFVF_MAX_MAC_FILTERS                   16
+#define PFVF_MAX_VLAN_FILTERS                  16
+#define PFVF_MAX_FILTERS               (PFVF_MAX_MAC_FILTERS +\
+					 PFVF_MAX_VLAN_FILTERS)
+	struct vfpf_q_mac_vlan_filter filters[PFVF_MAX_FILTERS];
+
+#define PFVF_MAX_MULTICAST_PER_VF              32
+	u8  multicast[PFVF_MAX_MULTICAST_PER_VF][ETH_ALEN];
+
+	u32 rx_mask;	/* see mask constants at the top of the file */
+};
+
+/* close VF (disable VF) */
+struct vfpf_close_tlv {
+	struct vfpf_first_tlv   first_tlv;
+	u16			vf_id;  /* for debug */
+	u8 padding[2];
+};
+
+/* release the VF's acquired resources */
+struct vfpf_release_tlv {
+	struct vfpf_first_tlv	first_tlv;
+	u16			vf_id;
+	u8 padding[2];
+};
+
+struct tlv_buffer_size {
+	u8 tlv_buffer[TLV_BUFFER_SIZE];
+};
+
+union vfpf_tlvs {
+	struct vfpf_first_tlv		first_tlv;
+	struct vfpf_acquire_tlv		acquire;
+	struct vfpf_init_tlv		init;
+	struct vfpf_close_tlv		close;
+	struct vfpf_q_op_tlv		q_op;
+	struct vfpf_setup_q_tlv		setup_q;
+	struct vfpf_set_q_filters_tlv	set_q_filters;
+	struct vfpf_release_tlv         release;
+	struct channel_list_end_tlv     list_end;
+	struct tlv_buffer_size		tlv_buf_size;
+};
+
+union pfvf_tlvs {
+	struct pfvf_general_resp_tlv    general_resp;
+	struct pfvf_acquire_resp_tlv	acquire_resp;
+	struct channel_list_end_tlv	list_end;
+	struct tlv_buffer_size		tlv_buf_size;
+};
+
+/* This is a structure which is allocated in the VF, which the PF may update
+ * when it deems it necessary to do so. The bulletin board is sampled
+ * periodically by the VF. A copy per VF is maintained in the PF (to prevent
+ * loss of data upon multiple updates (or the need for read modify write)).
+ */
+struct pf_vf_bulletin_size {
+	u8 size[PF_VF_BULLETIN_SIZE];
+};
+
+struct pf_vf_bulletin_content {
+	u32 crc;			/* crc of structure to ensure is not in
+					 * mid-update
+					 */
+	u16 version;
+	u16 length;
+
+	aligned_u64 valid_bitmap;	/* bitmap indicating which fields
+					 * hold valid values
+					 */
+
+#define MAC_ADDR_VALID		0	/* alert the vf that a new mac address
+					 * is available for it
+					 */
+
+	u8 mac[ETH_ALEN];
+	u8 padding[2];
+};
+
+union pf_vf_bulletin {
+	struct pf_vf_bulletin_content content;
+	struct pf_vf_bulletin_size size;
+};
+
+#define MAX_TLVS_IN_LIST 50
+
+enum channel_tlvs {
+	CHANNEL_TLV_NONE,
+	CHANNEL_TLV_ACQUIRE,
+	CHANNEL_TLV_INIT,
+	CHANNEL_TLV_SETUP_Q,
+	CHANNEL_TLV_SET_Q_FILTERS,
+	CHANNEL_TLV_TEARDOWN_Q,
+	CHANNEL_TLV_CLOSE,
+	CHANNEL_TLV_RELEASE,
+	CHANNEL_TLV_PF_RELEASE_VF,
+	CHANNEL_TLV_LIST_END,
+	CHANNEL_TLV_FLR,
+	CHANNEL_TLV_PF_SET_MAC,
+	CHANNEL_TLV_MAX
+};
+
+#endif /* CONFIG_BNX2X_SRIOV */
+#endif /* VF_PF_IF_H */
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index df8c30d..149a3a0 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -4816,6 +4816,8 @@
 		return err;
 	}
 
+	ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
+
 	return 0;
 }
 
@@ -5136,6 +5138,7 @@
 	if (ret)
 		return ret;
 
+	ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
 	return 0;
 }
 
@@ -5387,6 +5390,7 @@
 		}
 		cnic_shutdown_rings(dev);
 		cp->stop_cm(dev);
+		cp->ethdev->drv_state &= ~CNIC_DRV_STATE_HANDLES_IRQ;
 		clear_bit(CNIC_F_CNIC_UP, &dev->flags);
 		RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
 		synchronize_rcu();
@@ -5421,11 +5425,9 @@
 
 	alloc_size = sizeof(struct cnic_dev) + sizeof(struct cnic_local);
 
-	cdev = kzalloc(alloc_size , GFP_KERNEL);
-	if (cdev == NULL) {
-		netdev_err(dev, "allocate dev struct failure\n");
+	cdev = kzalloc(alloc_size, GFP_KERNEL);
+	if (cdev == NULL)
 		return NULL;
-	}
 
 	cdev->netdev = dev;
 	cdev->cnic_priv = (char *)cdev + sizeof(struct cnic_dev);
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 2a35436..0c9367a 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -179,6 +179,7 @@
 #define CNIC_DRV_STATE_NO_ISCSI_OOO	0x00000004
 #define CNIC_DRV_STATE_NO_ISCSI		0x00000008
 #define CNIC_DRV_STATE_NO_FCOE		0x00000010
+#define CNIC_DRV_STATE_HANDLES_IRQ	0x00000020
 	u32		chip_id;
 	u32		max_kwqe_pending;
 	struct pci_dev	*pdev;
diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index 3a1c8a3..e9b35da 100644
--- a/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -2385,7 +2385,7 @@
 		return -ENXIO;
 	}
 
-	phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll, 0,
+	phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll,
 			      PHY_INTERFACE_MODE_GMII);
 	if (IS_ERR(phy_dev)) {
 		printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index bdb0869..fdb9b56 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2012 Broadcom Corporation.
+ * Copyright (C) 2005-2013 Broadcom Corporation.
  *
  * Firmware is:
  *	Derived from proprietary unpublished source code,
@@ -44,6 +44,7 @@
 #include <linux/prefetch.h>
 #include <linux/dma-mapping.h>
 #include <linux/firmware.h>
+#include <linux/ssb/ssb_driver_gige.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 
@@ -93,10 +94,10 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define TG3_MAJ_NUM			3
-#define TG3_MIN_NUM			128
+#define TG3_MIN_NUM			130
 #define DRV_MODULE_VERSION	\
 	__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE	"December 03, 2012"
+#define DRV_MODULE_RELDATE	"February 14, 2013"
 
 #define RESET_KIND_SHUTDOWN	0
 #define RESET_KIND_INIT		1
@@ -263,6 +264,7 @@
 			TG3_DRV_DATA_FLAG_5705_10_100},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F),
@@ -330,6 +332,10 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57762)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57766)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5762)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5725)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5727)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -570,7 +576,9 @@
 static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
 {
 	tp->write32_mbox(tp, off, val);
-	if (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND))
+	if (tg3_flag(tp, FLUSH_POSTED_WRITES) ||
+	    (!tg3_flag(tp, MBOX_WRITE_REORDER) &&
+	     !tg3_flag(tp, ICH_WORKAROUND)))
 		tp->read32_mbox(tp, off);
 }
 
@@ -580,7 +588,8 @@
 	writel(val, mbox);
 	if (tg3_flag(tp, TXD_MBOX_HWBUG))
 		writel(val, mbox);
-	if (tg3_flag(tp, MBOX_WRITE_REORDER))
+	if (tg3_flag(tp, MBOX_WRITE_REORDER) ||
+	    tg3_flag(tp, FLUSH_POSTED_WRITES))
 		readl(mbox);
 }
 
@@ -609,7 +618,7 @@
 {
 	unsigned long flags;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5906 &&
 	    (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
 		return;
 
@@ -634,7 +643,7 @@
 {
 	unsigned long flags;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5906 &&
 	    (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
 		*val = 0;
 		return;
@@ -662,7 +671,7 @@
 	int i;
 	u32 regbase, bit;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+	if (tg3_asic_rev(tp) == ASIC_REV_5761)
 		regbase = TG3_APE_LOCK_GRANT;
 	else
 		regbase = TG3_APE_PER_LOCK_GRANT;
@@ -698,7 +707,7 @@
 
 	switch (locknum) {
 	case TG3_APE_LOCK_GPIO:
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		if (tg3_asic_rev(tp) == ASIC_REV_5761)
 			return 0;
 	case TG3_APE_LOCK_GRC:
 	case TG3_APE_LOCK_MEM:
@@ -717,7 +726,7 @@
 		return -EINVAL;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5761) {
 		req = TG3_APE_LOCK_REQ;
 		gnt = TG3_APE_LOCK_GRANT;
 	} else {
@@ -755,7 +764,7 @@
 
 	switch (locknum) {
 	case TG3_APE_LOCK_GPIO:
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		if (tg3_asic_rev(tp) == ASIC_REV_5761)
 			return;
 	case TG3_APE_LOCK_GRC:
 	case TG3_APE_LOCK_MEM:
@@ -774,7 +783,7 @@
 		return;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+	if (tg3_asic_rev(tp) == ASIC_REV_5761)
 		gnt = TG3_APE_LOCK_GRANT;
 	else
 		gnt = TG3_APE_PER_LOCK_GRANT;
@@ -1088,7 +1097,8 @@
 
 #define PHY_BUSY_LOOPS	5000
 
-static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+static int __tg3_readphy(struct tg3 *tp, unsigned int phy_addr, int reg,
+			 u32 *val)
 {
 	u32 frame_val;
 	unsigned int loops;
@@ -1104,7 +1114,7 @@
 
 	*val = 0x0;
 
-	frame_val  = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+	frame_val  = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
 		      MI_COM_PHY_ADDR_MASK);
 	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
 		      MI_COM_REG_ADDR_MASK);
@@ -1141,7 +1151,13 @@
 	return ret;
 }
 
-static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+{
+	return __tg3_readphy(tp, tp->phy_addr, reg, val);
+}
+
+static int __tg3_writephy(struct tg3 *tp, unsigned int phy_addr, int reg,
+			  u32 val)
 {
 	u32 frame_val;
 	unsigned int loops;
@@ -1159,7 +1175,7 @@
 
 	tg3_ape_lock(tp, tp->phy_ape_lock);
 
-	frame_val  = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+	frame_val  = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
 		      MI_COM_PHY_ADDR_MASK);
 	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
 		      MI_COM_REG_ADDR_MASK);
@@ -1194,6 +1210,11 @@
 	return ret;
 }
 
+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+{
+	return __tg3_writephy(tp, tp->phy_addr, reg, val);
+}
+
 static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val)
 {
 	int err;
@@ -1458,7 +1479,7 @@
 	udelay(80);
 
 	if (tg3_flag(tp, MDIOBUS_INITED) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	    tg3_asic_rev(tp) == ASIC_REV_5785)
 		tg3_mdio_config_5785(tp);
 }
 
@@ -1473,7 +1494,7 @@
 
 		tp->phy_addr = tp->pci_fn + 1;
 
-		if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
+		if (tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0)
 			is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES;
 		else
 			is_serdes = tr32(TG3_CPMU_PHY_STRAP) &
@@ -1561,7 +1582,7 @@
 
 	tg3_flag_set(tp, MDIOBUS_INITED);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	if (tg3_asic_rev(tp) == ASIC_REV_5785)
 		tg3_mdio_config_5785(tp);
 
 	return 0;
@@ -1778,7 +1799,12 @@
 	int i;
 	u32 val;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* We don't use firmware. */
+		return 0;
+	}
+
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		/* Wait up to 20ms for init done. */
 		for (i = 0; i < 200; i++) {
 			if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
@@ -1807,7 +1833,7 @@
 		netdev_info(tp->dev, "No firmware running\n");
 	}
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0) {
 		/* The 57765 A0 needs a little more
 		 * time to do some important work.
 		 */
@@ -1937,7 +1963,7 @@
 		if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10)
 			mac_mode |= MAC_MODE_PORT_MODE_MII;
 		else if (phydev->speed == SPEED_1000 ||
-			 GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785)
+			 tg3_asic_rev(tp) != ASIC_REV_5785)
 			mac_mode |= MAC_MODE_PORT_MODE_GMII;
 		else
 			mac_mode |= MAC_MODE_PORT_MODE_MII;
@@ -1964,7 +1990,7 @@
 		udelay(40);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5785) {
 		if (phydev->speed == SPEED_10)
 			tw32(MAC_MI_STAT,
 			     MAC_MI_STAT_10MBPS_MODE |
@@ -2013,8 +2039,8 @@
 	phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 
 	/* Attach the MAC to the PHY. */
-	phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link,
-			     phydev->dev_flags, phydev->interface);
+	phydev = phy_connect(tp->dev, dev_name(&phydev->dev),
+			     tg3_adjust_link, phydev->interface);
 	if (IS_ERR(phydev)) {
 		dev_err(&tp->pdev->dev, "Could not attach to PHY\n");
 		return PTR_ERR(phydev);
@@ -2156,7 +2182,7 @@
 	      MII_TG3_MISC_SHDW_SCR5_DLPTLM |
 	      MII_TG3_MISC_SHDW_SCR5_SDTL |
 	      MII_TG3_MISC_SHDW_SCR5_C125OE;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 || !enable)
+	if (tg3_asic_rev(tp) != ASIC_REV_5784 || !enable)
 		reg |= MII_TG3_MISC_SHDW_SCR5_DLLAPD;
 
 	tg3_writephy(tp, MII_TG3_MISC_SHDW, reg);
@@ -2311,8 +2337,8 @@
 	u32 val;
 
 	if (tp->link_config.active_speed == SPEED_1000 &&
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+	    (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5719 ||
 	     tg3_flag(tp, 57765_CLASS)) &&
 	    !tg3_phy_toggle_auxctl_smdsp(tp, true)) {
 		val = MII_TG3_DSP_TAP26_ALNOKO |
@@ -2516,7 +2542,7 @@
 	u32 val, cpmuctrl;
 	int err;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		val = tr32(GRC_MISC_CFG);
 		tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ);
 		udelay(40);
@@ -2531,9 +2557,9 @@
 		tg3_link_report(tp);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5704 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5705) {
 		err = tg3_phy_reset_5703_4_5(tp);
 		if (err)
 			return err;
@@ -2541,8 +2567,8 @@
 	}
 
 	cpmuctrl = 0;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
-	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+	    tg3_chip_rev(tp) != CHIPREV_5784_AX) {
 		cpmuctrl = tr32(TG3_CPMU_CTRL);
 		if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY)
 			tw32(TG3_CPMU_CTRL,
@@ -2560,8 +2586,8 @@
 		tw32(TG3_CPMU_CTRL, cpmuctrl);
 	}
 
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
-	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
+	if (tg3_chip_rev(tp) == CHIPREV_5784_AX ||
+	    tg3_chip_rev(tp) == CHIPREV_5761_AX) {
 		val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
 		if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
 		    CPMU_LSPD_1000MB_MACCLK_12_5) {
@@ -2639,11 +2665,14 @@
 				     val | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		/* adjust output voltage */
 		tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12);
 	}
 
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5762_A0)
+		tg3_phydsp_write(tp, 0xffb, 0x4000);
+
 	tg3_phy_toggle_automdix(tp, 1);
 	tg3_phy_set_wirespeed(tp);
 	return 0;
@@ -2669,8 +2698,8 @@
 {
 	u32 status, shift;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719)
 		status = tg3_ape_read32(tp, TG3_APE_GPIO_MSG);
 	else
 		status = tr32(TG3_CPMU_DRV_STATUS);
@@ -2679,8 +2708,8 @@
 	status &= ~(TG3_GPIO_MSG_MASK << shift);
 	status |= (newstat << shift);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719)
 		tg3_ape_write32(tp, TG3_APE_GPIO_MSG, status);
 	else
 		tw32(TG3_CPMU_DRV_STATUS, status);
@@ -2693,9 +2722,9 @@
 	if (!tg3_flag(tp, IS_NIC))
 		return 0;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720) {
 		if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
 			return -EIO;
 
@@ -2718,8 +2747,8 @@
 	u32 grc_local_ctrl;
 
 	if (!tg3_flag(tp, IS_NIC) ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+	    tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5701)
 		return;
 
 	grc_local_ctrl = tp->grc_local_ctrl | GRC_LCLCTRL_GPIO_OE1;
@@ -2742,8 +2771,8 @@
 	if (!tg3_flag(tp, IS_NIC))
 		return;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5701) {
 		tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
 			    (GRC_LCLCTRL_GPIO_OE0 |
 			     GRC_LCLCTRL_GPIO_OE1 |
@@ -2775,7 +2804,7 @@
 		u32 grc_local_ctrl = 0;
 
 		/* Workaround to prevent overdrawing Amps. */
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5714) {
 			grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
 			tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
 				    grc_local_ctrl,
@@ -2847,9 +2876,9 @@
 	if (!tg3_flag(tp, IS_NIC) || tg3_flag(tp, 57765_CLASS))
 		return;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720) {
 		tg3_frob_aux_power_5717(tp, include_wol ?
 					tg3_flag(tp, WOL_ENABLE) != 0 : 0);
 		return;
@@ -2901,7 +2930,7 @@
 	u32 val;
 
 	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5704) {
 			u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
 			u32 serdes_cfg = tr32(MAC_SERDES_CFG);
 
@@ -2913,7 +2942,7 @@
 		return;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		tg3_bmcr_reset(tp);
 		val = tr32(GRC_MISC_CFG);
 		tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
@@ -2952,16 +2981,16 @@
 	/* The PHY should not be powered down on some chips because
 	 * of bugs.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5704 ||
+	    (tg3_asic_rev(tp) == ASIC_REV_5780 &&
 	     (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+	    (tg3_asic_rev(tp) == ASIC_REV_5717 &&
 	     !tp->pci_fn))
 		return;
 
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
-	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
+	if (tg3_chip_rev(tp) == CHIPREV_5784_AX ||
+	    tg3_chip_rev(tp) == CHIPREV_5761_AX) {
 		val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
 		val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
 		val |= CPMU_LSPD_1000MB_MACCLK_12_5;
@@ -3344,7 +3373,7 @@
 		    !tg3_flag(tp, 57765_PLUS))
 			tw32(NVRAM_ADDR, phy_addr);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
+		if (tg3_asic_rev(tp) != ASIC_REV_5752 &&
 		    !tg3_flag(tp, 5755_PLUS) &&
 		    (tp->nvram_jedecnum == JEDEC_ST) &&
 		    (nvram_cmd & NVRAM_CMD_FIRST)) {
@@ -3429,7 +3458,7 @@
 
 	BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		u32 val = tr32(GRC_VCPU_EXT_CTRL);
 
 		tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
@@ -3447,6 +3476,13 @@
 		tw32_f(offset + CPU_MODE,  CPU_MODE_HALT);
 		udelay(10);
 	} else {
+		/*
+		 * There is only an Rx CPU for the 5750 derivative in the
+		 * BCM4785.
+		 */
+		if (tg3_flag(tp, IS_SSB_CORE))
+			return 0;
+
 		for (i = 0; i < 10000; i++) {
 			tw32(offset + CPU_STATE, 0xffffffff);
 			tw32(offset + CPU_MODE,  CPU_MODE_HALT);
@@ -3600,7 +3636,7 @@
 	info.fw_len = tp->fw->size - 12;
 	info.fw_data = &fw_data[3];
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5705) {
 		cpu_base = RX_CPU_BASE;
 		cpu_scratch_base = NIC_SRAM_MBUF_POOL_BASE5705;
 	} else {
@@ -3658,8 +3694,8 @@
 		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5704) {
 		for (i = 0; i < 12; i++) {
 			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
 			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
@@ -3778,7 +3814,7 @@
 			tg3_setup_phy(tp, 0);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		u32 val;
 
 		val = tr32(GRC_VCPU_EXT_CTRL);
@@ -3820,8 +3856,7 @@
 				mac_mode = MAC_MODE_PORT_MODE_MII;
 
 			mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY;
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
-			    ASIC_REV_5700) {
+			if (tg3_asic_rev(tp) == ASIC_REV_5700) {
 				u32 speed = tg3_flag(tp, WOL_SPEED_100MB) ?
 					     SPEED_100 : SPEED_10;
 				if (tg3_5700_link_polarity(tp, speed))
@@ -3854,8 +3889,8 @@
 	}
 
 	if (!tg3_flag(tp, WOL_SPEED_100MB) &&
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
+	    (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5701)) {
 		u32 base_val;
 
 		base_val = tp->pci_clock_ctrl;
@@ -3866,13 +3901,13 @@
 			    CLOCK_CTRL_PWRDOWN_PLL133, 40);
 	} else if (tg3_flag(tp, 5780_CLASS) ||
 		   tg3_flag(tp, CPMU_PRESENT) ||
-		   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		   tg3_asic_rev(tp) == ASIC_REV_5906) {
 		/* do nothing */
 	} else if (!(tg3_flag(tp, 5750_PLUS) && tg3_flag(tp, ENABLE_ASF))) {
 		u32 newbits1, newbits2;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5701) {
 			newbits1 = (CLOCK_CTRL_RXCLK_DISABLE |
 				    CLOCK_CTRL_TXCLK_DISABLE |
 				    CLOCK_CTRL_ALTCLK);
@@ -3894,8 +3929,8 @@
 		if (!tg3_flag(tp, 5705_PLUS)) {
 			u32 newbits3;
 
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+			if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+			    tg3_asic_rev(tp) == ASIC_REV_5701) {
 				newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
 					    CLOCK_CTRL_TXCLK_DISABLE |
 					    CLOCK_CTRL_44MHZ_CORE);
@@ -3914,8 +3949,9 @@
 	tg3_frob_aux_power(tp, true);
 
 	/* Workaround for unstable PLL clock */
-	if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
-	    (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
+	if ((!tg3_flag(tp, IS_SSB_CORE)) &&
+	    ((tg3_chip_rev(tp) == CHIPREV_5750_AX) ||
+	     (tg3_chip_rev(tp) == CHIPREV_5750_BX))) {
 		u32 val = tr32(0x7d00);
 
 		val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
@@ -4006,8 +4042,8 @@
 	if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
 		new_adv = ethtool_adv_to_mii_ctrl1000_t(advertise);
 
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+		    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0)
 			new_adv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
 
 		err = tg3_writephy(tp, MII_CTRL1000, new_adv);
@@ -4036,7 +4072,7 @@
 		if (err)
 			val = 0;
 
-		switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
+		switch (tg3_asic_rev(tp)) {
 		case ASIC_REV_5717:
 		case ASIC_REV_57765:
 		case ASIC_REV_57766:
@@ -4049,6 +4085,7 @@
 			tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
 			/* Fall through */
 		case ASIC_REV_5720:
+		case ASIC_REV_5762:
 			if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
 				tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, val |
 						 MII_TG3_DSP_CH34TP2_HIBW01);
@@ -4183,8 +4220,8 @@
 			return false;
 
 		if (tgtadv &&
-		    (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-		     tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
+		    (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+		     tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0)) {
 			tgtadv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
 			tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL |
 				     CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
@@ -4268,9 +4305,9 @@
 	/* Some third-party PHYs need to be reset on link going
 	 * down.
 	 */
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+	if ((tg3_asic_rev(tp) == ASIC_REV_5703 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5704 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5705) &&
 	    tp->link_up) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
@@ -4312,8 +4349,8 @@
 					return err;
 			}
 		}
-	} else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
+	} else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+		   tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0) {
 		/* 5701 {A0,B0} CRC bug workaround */
 		tg3_writephy(tp, 0x15, 0x0a75);
 		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
@@ -4330,8 +4367,8 @@
 	else if (!(tp->phy_flags & TG3_PHYFLG_IS_FET))
 		tg3_writephy(tp, MII_TG3_IMASK, ~0);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5701) {
 		if (tp->led_ctrl == LED_CTRL_MODE_PHY_1)
 			tg3_writephy(tp, MII_TG3_EXT_CTRL,
 				     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
@@ -4435,6 +4472,15 @@
 	if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
 		tg3_phy_copper_begin(tp);
 
+		if (tg3_flag(tp, ROBOSWITCH)) {
+			current_link_up = 1;
+			/* FIXME: when BCM5325 switch is used use 100 MBit/s */
+			current_speed = SPEED_1000;
+			current_duplex = DUPLEX_FULL;
+			tp->link_config.active_speed = current_speed;
+			tp->link_config.active_duplex = current_duplex;
+		}
+
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
 		    (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
@@ -4453,11 +4499,31 @@
 	else
 		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
 
+	/* In order for the 5750 core in BCM4785 chip to work properly
+	 * in RGMII mode, the Led Control Register must be set up.
+	 */
+	if (tg3_flag(tp, RGMII_MODE)) {
+		u32 led_ctrl = tr32(MAC_LED_CTRL);
+		led_ctrl &= ~(LED_CTRL_1000MBPS_ON | LED_CTRL_100MBPS_ON);
+
+		if (tp->link_config.active_speed == SPEED_10)
+			led_ctrl |= LED_CTRL_LNKLED_OVERRIDE;
+		else if (tp->link_config.active_speed == SPEED_100)
+			led_ctrl |= (LED_CTRL_LNKLED_OVERRIDE |
+				     LED_CTRL_100MBPS_ON);
+		else if (tp->link_config.active_speed == SPEED_1000)
+			led_ctrl |= (LED_CTRL_LNKLED_OVERRIDE |
+				     LED_CTRL_1000MBPS_ON);
+
+		tw32(MAC_LED_CTRL, led_ctrl);
+		udelay(40);
+	}
+
 	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
 	if (tp->link_config.active_duplex == DUPLEX_HALF)
 		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5700) {
 		if (current_link_up == 1 &&
 		    tg3_5700_link_polarity(tp, tp->link_config.active_speed))
 			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
@@ -4469,7 +4535,7 @@
 	 * ??? send/receive packets...
 	 */
 	if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411 &&
-	    tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5700_ALTIMA) {
 		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
 		tw32_f(MAC_MI_MODE, tp->mi_mode);
 		udelay(80);
@@ -4488,7 +4554,7 @@
 	}
 	udelay(40);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 &&
 	    current_link_up == 1 &&
 	    tp->link_config.active_speed == SPEED_1000 &&
 	    (tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) {
@@ -4943,8 +5009,8 @@
 	port_a = 1;
 	current_link_up = 0;
 
-	if (tp->pci_chip_rev_id != CHIPREV_ID_5704_A0 &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5704_A1) {
+	if (tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A0 &&
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A1) {
 		workaround = 1;
 		if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
 			port_a = 0;
@@ -5273,7 +5339,7 @@
 
 	err |= tg3_readphy(tp, MII_BMSR, &bmsr);
 	err |= tg3_readphy(tp, MII_BMSR, &bmsr);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5714) {
 		if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
 			bmsr |= BMSR_LSTATUS;
 		else
@@ -5342,8 +5408,7 @@
 			bmcr = new_bmcr;
 			err |= tg3_readphy(tp, MII_BMSR, &bmsr);
 			err |= tg3_readphy(tp, MII_BMSR, &bmsr);
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
-			    ASIC_REV_5714) {
+			if (tg3_asic_rev(tp) == ASIC_REV_5714) {
 				if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
 					bmsr |= BMSR_LSTATUS;
 				else
@@ -5478,7 +5543,7 @@
 	else
 		err = tg3_setup_copper_phy(tp, force_reset);
 
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
+	if (tg3_chip_rev(tp) == CHIPREV_5784_AX) {
 		u32 scale;
 
 		val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK;
@@ -5496,7 +5561,8 @@
 
 	val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
 	      (6 << TX_LENGTHS_IPG_SHIFT);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762)
 		val |= tr32(MAC_TX_LENGTHS) &
 		       (TX_LENGTHS_JMB_FRM_LEN_MSK |
 			TX_LENGTHS_CNT_DWN_VAL_MSK);
@@ -5785,10 +5851,8 @@
 	u32 *regs;
 
 	regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC);
-	if (!regs) {
-		netdev_err(tp->dev, "Failed allocating register dump buffer\n");
+	if (!regs)
 		return;
-	}
 
 	if (tg3_flag(tp, PCI_EXPRESS)) {
 		/* Read up to but not including private PCI registers */
@@ -7122,7 +7186,7 @@
 	dma_addr_t new_addr = 0;
 	int ret = 0;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+	if (tg3_asic_rev(tp) != ASIC_REV_5701)
 		new_skb = skb_copy(skb, GFP_ATOMIC);
 	else {
 		int more_headroom = 4 - ((unsigned long)skb->data & 3);
@@ -7296,7 +7360,7 @@
 		} else if (tg3_flag(tp, HW_TSO_2))
 			mss |= hdr_len << 9;
 		else if (tg3_flag(tp, HW_TSO_1) ||
-			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			 tg3_asic_rev(tp) == ASIC_REV_5705) {
 			if (tcp_opt_len || iph->ihl > 5) {
 				int tsflags;
 
@@ -7452,7 +7516,7 @@
 
 		if (tg3_flag(tp, 5705_PLUS) ||
 		    (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+		    tg3_asic_rev(tp) == ASIC_REV_5700)
 			tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
 	}
 
@@ -7511,7 +7575,7 @@
 	udelay(40);
 
 	if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+	    tg3_asic_rev(tp) == ASIC_REV_5785) {
 		tg3_writephy(tp, MII_TG3_FET_PTEST, ptest |
 			     MII_TG3_FET_PTEST_FRC_TX_LINK |
 			     MII_TG3_FET_PTEST_FRC_TX_LOCK);
@@ -7535,7 +7599,7 @@
 	else
 		mac_mode |= MAC_MODE_PORT_MODE_MII;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5700) {
 		u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
 
 		if (masked_phy_id == TG3_PHY_ID_BCM5401)
@@ -8213,7 +8277,7 @@
 
 	/* Set MAX PCI retry to zero. */
 	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0 &&
 	    tg3_flag(tp, PCIX_MODE))
 		val |= PCISTATE_RETRY_SAME_DMA;
 	/* Allow reads and writes to the APE register and memory space. */
@@ -8285,7 +8349,7 @@
 	 */
 	tg3_save_pci_state(tp);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5752 ||
 	    tg3_flag(tp, 5755_PLUS))
 		tw32(GRC_FASTBOOT_PC, 0);
 
@@ -8320,7 +8384,7 @@
 	for (i = 0; i < tp->irq_cnt; i++)
 		synchronize_irq(tp->napi[i].irq_vec);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+	if (tg3_asic_rev(tp) == ASIC_REV_57780) {
 		val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
 		tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
 	}
@@ -8330,19 +8394,19 @@
 
 	if (tg3_flag(tp, PCI_EXPRESS)) {
 		/* Force PCIe 1.0a mode */
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+		if (tg3_asic_rev(tp) != ASIC_REV_5785 &&
 		    !tg3_flag(tp, 57765_PLUS) &&
 		    tr32(TG3_PCIE_PHY_TSTCTL) ==
 		    (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM))
 			tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM);
 
-		if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
+		if (tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0) {
 			tw32(GRC_MISC_CFG, (1 << 29));
 			val |= (1 << 29);
 		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
 		tw32(GRC_VCPU_EXT_CTRL,
 		     tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
@@ -8385,7 +8449,7 @@
 	if (tg3_flag(tp, PCI_EXPRESS) && pci_is_pcie(tp->pdev)) {
 		u16 val16;
 
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) {
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5750_A0) {
 			int j;
 			u32 cfg_val;
 
@@ -8426,23 +8490,33 @@
 		val = tr32(MEMARB_MODE);
 	tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5750_A3) {
 		tg3_stop_fw(tp);
 		tw32(0x5000, 0x400);
 	}
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/*
+		 * BCM4785: In order to avoid repercussions from using
+		 * potentially defective internal ROM, stop the Rx RISC CPU,
+		 * which is not required.
+		 */
+		tg3_stop_fw(tp);
+		tg3_halt_cpu(tp, RX_CPU_BASE);
+	}
+
 	tw32(GRC_MODE, tp->grc_mode);
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A0) {
 		val = tr32(0xc4);
 
 		tw32(0xc4, val | (1 << 15));
 	}
 
 	if ((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+	    tg3_asic_rev(tp) == ASIC_REV_5705) {
 		tp->pci_clock_ctrl |= CLOCK_CTRL_CLKRUN_OENABLE;
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A0)
 			tp->pci_clock_ctrl |= CLOCK_CTRL_FORCE_CLKRUN;
 		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
 	}
@@ -8468,15 +8542,15 @@
 	tg3_mdio_start(tp);
 
 	if (tg3_flag(tp, PCI_EXPRESS) &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0 &&
+	    tg3_asic_rev(tp) != ASIC_REV_5785 &&
 	    !tg3_flag(tp, 57765_PLUS)) {
 		val = tr32(0x7c00);
 
 		tw32(0x7c00, val | (1 << 25));
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5720) {
 		val = tr32(TG3_CPMU_CLCK_ORIDE);
 		tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN);
 	}
@@ -8687,7 +8761,8 @@
 		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16;
 	else if (tg3_flag(tp, 5717_PLUS))
 		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4;
-	else if (tg3_flag(tp, 57765_CLASS))
+	else if (tg3_flag(tp, 57765_CLASS) ||
+		 tg3_asic_rev(tp) == ASIC_REV_5762)
 		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2;
 	else
 		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE;
@@ -8703,7 +8778,8 @@
 		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
 	else if (!tg3_flag(tp, 5705_PLUS))
 		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
-	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+	else if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+		 tg3_asic_rev(tp) == ASIC_REV_5762 ||
 		 tg3_flag(tp, 57765_CLASS))
 		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4;
 	else
@@ -8809,12 +8885,12 @@
 
 	if (!tg3_flag(tp, 5750_PLUS) ||
 	    tg3_flag(tp, 5780_CLASS) ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5750 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5752 ||
 	    tg3_flag(tp, 57765_PLUS))
 		bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700;
-	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+	else if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+		 tg3_asic_rev(tp) == ASIC_REV_5787)
 		bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5755;
 	else
 		bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5906;
@@ -8994,9 +9070,12 @@
 
 	/* Enable MAC control of LPI */
 	if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
-		tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
-		       TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
-		       TG3_CPMU_EEE_LNKIDL_UART_IDL);
+		val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+		      TG3_CPMU_EEE_LNKIDL_UART_IDL;
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
+			val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
+
+		tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
 
 		tw32_f(TG3_CPMU_EEE_CTRL,
 		       TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
@@ -9006,7 +9085,7 @@
 		      TG3_CPMU_EEEMD_LPI_IN_RX |
 		      TG3_CPMU_EEEMD_EEE_ENABLE;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+		if (tg3_asic_rev(tp) != ASIC_REV_5717)
 			val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
 
 		if (tg3_flag(tp, ENABLE_APE))
@@ -9032,7 +9111,7 @@
 
 	tg3_write_sig_legacy(tp, RESET_KIND_INIT);
 
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
+	if (tg3_chip_rev(tp) == CHIPREV_5784_AX) {
 		val = tr32(TG3_CPMU_CTRL);
 		val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
 		tw32(TG3_CPMU_CTRL, val);
@@ -9053,7 +9132,7 @@
 		tw32(TG3_CPMU_HST_ACC, val);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+	if (tg3_asic_rev(tp) == ASIC_REV_57780) {
 		val = tr32(PCIE_PWR_MGMT_THRESH) & ~PCIE_PWR_MGMT_L1_THRESH_MSK;
 		val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN |
 		       PCIE_PWR_MGMT_L1_THRESH_4MS;
@@ -9083,7 +9162,7 @@
 	}
 
 	if (tg3_flag(tp, 57765_CLASS)) {
-		if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0) {
 			u32 grc_mode = tr32(GRC_MODE);
 
 			/* Access the lower 1K of PL PCIE block registers. */
@@ -9098,8 +9177,15 @@
 			tw32(GRC_MODE, grc_mode);
 		}
 
-		if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_57765_AX) {
-			u32 grc_mode = tr32(GRC_MODE);
+		if (tg3_chip_rev(tp) != CHIPREV_57765_AX) {
+			u32 grc_mode;
+
+			/* Fix transmit hangs */
+			val = tr32(TG3_CPMU_PADRNG_CTL);
+			val |= TG3_CPMU_PADRNG_CTL_RDIV2;
+			tw32(TG3_CPMU_PADRNG_CTL, val);
+
+			grc_mode = tr32(GRC_MODE);
 
 			/* Access the lower 1K of DL PCIE block registers. */
 			val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
@@ -9131,7 +9217,7 @@
 		tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
 	}
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0 &&
 	    tg3_flag(tp, PCIX_MODE)) {
 		val = tr32(TG3PCI_PCISTATE);
 		val |= PCISTATE_RETRY_SAME_DMA;
@@ -9149,7 +9235,7 @@
 		tw32(TG3PCI_PCISTATE, val);
 	}
 
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
+	if (tg3_chip_rev(tp) == CHIPREV_5704_BX) {
 		/* Enable some hw fixes.  */
 		val = tr32(TG3PCI_MSI_DATA);
 		val |= (1 << 26) | (1 << 28) | (1 << 29);
@@ -9168,14 +9254,15 @@
 	if (tg3_flag(tp, 57765_PLUS)) {
 		val = tr32(TG3PCI_DMA_RW_CTRL) &
 		      ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
-		if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
 			val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK;
 		if (!tg3_flag(tp, 57765_CLASS) &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+		    tg3_asic_rev(tp) != ASIC_REV_5717 &&
+		    tg3_asic_rev(tp) != ASIC_REV_5762)
 			val |= DMA_RWCTRL_TAGGED_STAT_WA;
 		tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl);
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
-		   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+	} else if (tg3_asic_rev(tp) != ASIC_REV_5784 &&
+		   tg3_asic_rev(tp) != ASIC_REV_5761) {
 		/* This value is determined during the probe time DMA
 		 * engine test, tg3_test_dma.
 		 */
@@ -9215,9 +9302,9 @@
 	/* Initialize MBUF/DESC pool. */
 	if (tg3_flag(tp, 5750_PLUS)) {
 		/* Do nothing.  */
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+	} else if (tg3_asic_rev(tp) != ASIC_REV_5705) {
 		tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+		if (tg3_asic_rev(tp) == ASIC_REV_5704)
 			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
 		else
 			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
@@ -9255,11 +9342,11 @@
 	     tp->bufmgr_config.dma_high_water);
 
 	val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+	if (tg3_asic_rev(tp) == ASIC_REV_5719)
 		val |= BUFMGR_MODE_NO_TX_UNDERRUN;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5720_A0)
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5720_A0)
 		val |= BUFMGR_MODE_MBLOW_ATTN_ENAB;
 	tw32(BUFMGR_MODE, val);
 	for (i = 0; i < 2000; i++) {
@@ -9272,7 +9359,7 @@
 		return -ENODEV;
 	}
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5906_A1)
 		tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
 
 	tg3_setup_rxbd_thresholds(tp);
@@ -9310,7 +9397,7 @@
 	/* Program the jumbo buffer descriptor ring control
 	 * blocks on those devices that have them.
 	 */
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
 	    (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) {
 
 		if (tg3_flag(tp, JUMBO_RING_ENABLE)) {
@@ -9323,7 +9410,8 @@
 			tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
 			     val | BDINFO_FLAGS_USE_EXT_RECV);
 			if (!tg3_flag(tp, USE_JUMBO_BDFLAG) ||
-			    tg3_flag(tp, 57765_CLASS))
+			    tg3_flag(tp, 57765_CLASS) ||
+			    tg3_asic_rev(tp) == ASIC_REV_5762)
 				tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
 				     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
 		} else {
@@ -9365,7 +9453,8 @@
 	      (6 << TX_LENGTHS_IPG_SHIFT) |
 	      (32 << TX_LENGTHS_SLOT_TIME_SHIFT);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762)
 		val |= tr32(MAC_TX_LENGTHS) &
 		       (TX_LENGTHS_JMB_FRM_LEN_MSK |
 			TX_LENGTHS_CNT_DWN_VAL_MSK);
@@ -9385,20 +9474,20 @@
 		      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
 		      RDMAC_MODE_LNGREAD_ENAB);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+	if (tg3_asic_rev(tp) == ASIC_REV_5717)
 		rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+	if (tg3_asic_rev(tp) == ASIC_REV_5784 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5785 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57780)
 		rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
 			      RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
 			      RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5705 &&
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
 		if (tg3_flag(tp, TSO_CAPABLE) &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		    tg3_asic_rev(tp) == ASIC_REV_5705) {
 			rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
 		} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
 			   !tg3_flag(tp, IS_5788)) {
@@ -9409,26 +9498,43 @@
 	if (tg3_flag(tp, PCI_EXPRESS))
 		rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
 
+	if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+		tp->dma_limit = 0;
+		if (tp->dev->mtu <= ETH_DATA_LEN) {
+			rdmac_mode |= RDMAC_MODE_JMB_2K_MMRR;
+			tp->dma_limit = TG3_TX_BD_DMA_MAX_2K;
+		}
+	}
+
 	if (tg3_flag(tp, HW_TSO_1) ||
 	    tg3_flag(tp, HW_TSO_2) ||
 	    tg3_flag(tp, HW_TSO_3))
 		rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN;
 
 	if (tg3_flag(tp, 57765_PLUS) ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+	    tg3_asic_rev(tp) == ASIC_REV_5785 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57780)
 		rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762)
 		rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5761 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5784 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5785 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57780 ||
 	    tg3_flag(tp, 57765_PLUS)) {
-		val = tr32(TG3_RDMA_RSRVCTRL_REG);
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
+		u32 tgtreg;
+
+		if (tg3_asic_rev(tp) == ASIC_REV_5762)
+			tgtreg = TG3_RDMA_RSRVCTRL_REG2;
+		else
+			tgtreg = TG3_RDMA_RSRVCTRL_REG;
+
+		val = tr32(tgtreg);
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5762) {
 			val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK |
 				 TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK |
 				 TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK);
@@ -9436,14 +9542,21 @@
 			       TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K |
 			       TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K;
 		}
-		tw32(TG3_RDMA_RSRVCTRL_REG,
-		     val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
+		tw32(tgtreg, val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
-		val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
-		tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val |
+	if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762) {
+		u32 tgtreg;
+
+		if (tg3_asic_rev(tp) == ASIC_REV_5762)
+			tgtreg = TG3_LSO_RD_DMA_CRPTEN_CTRL2;
+		else
+			tgtreg = TG3_LSO_RD_DMA_CRPTEN_CTRL;
+
+		val = tr32(tgtreg);
+		tw32(tgtreg, val |
 		     TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K |
 		     TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K);
 	}
@@ -9520,7 +9633,7 @@
 		tp->mac_mode |= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
 	if (!tg3_flag(tp, 5705_PLUS) &&
 	    !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+	    tg3_asic_rev(tp) != ASIC_REV_5700)
 		tp->mac_mode |= MAC_MODE_LINK_POLARITY;
 	tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
 	udelay(40);
@@ -9538,11 +9651,11 @@
 			    GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 |
 			    GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+		if (tg3_asic_rev(tp) == ASIC_REV_5752)
 			gpio_mask |= GRC_LCLCTRL_GPIO_OE3 |
 				     GRC_LCLCTRL_GPIO_OUTPUT3;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+		if (tg3_asic_rev(tp) == ASIC_REV_5755)
 			gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL;
 
 		tp->grc_local_ctrl &= ~gpio_mask;
@@ -9577,11 +9690,11 @@
 	       WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
 	       WDMAC_MODE_LNGREAD_ENAB);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5705 &&
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
 		if (tg3_flag(tp, TSO_CAPABLE) &&
-		    (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 ||
-		     tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) {
+		    (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A1 ||
+		     tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A2)) {
 			/* nothing */
 		} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
 			   !tg3_flag(tp, IS_5788)) {
@@ -9593,7 +9706,7 @@
 	if (tg3_flag(tp, 5755_PLUS))
 		val |= WDMAC_MODE_STATUS_TAG_FIX;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+	if (tg3_asic_rev(tp) == ASIC_REV_5785)
 		val |= WDMAC_MODE_BURST_ALL_DATA;
 
 	tw32_f(WDMAC_MODE, val);
@@ -9604,10 +9717,10 @@
 
 		pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
 				     &pcix_cmd);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5703) {
 			pcix_cmd &= ~PCI_X_CMD_MAX_READ;
 			pcix_cmd |= PCI_X_CMD_READ_2K;
-		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		} else if (tg3_asic_rev(tp) == ASIC_REV_5704) {
 			pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ);
 			pcix_cmd |= PCI_X_CMD_READ_2K;
 		}
@@ -9618,7 +9731,7 @@
 	tw32_f(RDMAC_MODE, rdmac_mode);
 	udelay(40);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5719) {
 		for (i = 0; i < TG3_NUM_RDMA_CHANNELS; i++) {
 			if (tr32(TG3_RDMA_LENGTH + (i << 2)) > TG3_MAX_MTU(tp))
 				break;
@@ -9635,7 +9748,7 @@
 	if (!tg3_flag(tp, 5705_PLUS))
 		tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+	if (tg3_asic_rev(tp) == ASIC_REV_5761)
 		tw32(SNDDATAC_MODE,
 		     SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
 	else
@@ -9658,7 +9771,7 @@
 	tw32(SNDBDI_MODE, val);
 	tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
 		err = tg3_load_5701_a0_firmware_fix(tp);
 		if (err)
 			return err;
@@ -9673,10 +9786,11 @@
 	tp->tx_mode = TX_MODE_ENABLE;
 
 	if (tg3_flag(tp, 5755_PLUS) ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+	    tg3_asic_rev(tp) == ASIC_REV_5906)
 		tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762) {
 		val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE;
 		tp->tx_mode &= ~val;
 		tp->tx_mode |= tr32(MAC_TX_MODE) & val;
@@ -9727,8 +9841,8 @@
 	udelay(10);
 
 	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
-		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
-			!(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
+		if ((tg3_asic_rev(tp) == ASIC_REV_5704) &&
+		    !(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
 			/* Set drive transmission level to 1.2V  */
 			/* only if the signal pre-emphasis bit is not set  */
 			val = tr32(MAC_SERDES_CFG);
@@ -9736,7 +9850,7 @@
 			val |= 0x880;
 			tw32(MAC_SERDES_CFG, val);
 		}
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5703_A1)
 			tw32(MAC_SERDES_CFG, 0x616000);
 	}
 
@@ -9749,14 +9863,14 @@
 		val = 2;
 	tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5704 &&
 	    (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
 		/* Use hardware link auto-negotiation */
 		tg3_flag_set(tp, HW_AUTONEG);
 	}
 
 	if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+	    tg3_asic_rev(tp) == ASIC_REV_5714) {
 		u32 tmp;
 
 		tmp = tr32(SERDES_RX_CTRL);
@@ -10010,9 +10124,9 @@
 	TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE);
 
 	TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5719_A0 &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5720_A0) {
+	if (tg3_asic_rev(tp) != ASIC_REV_5717 &&
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5719_A0 &&
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5720_A0) {
 		TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT);
 	} else {
 		u32 val = tr32(HOSTCC_FLOW_ATTN);
@@ -10060,10 +10174,15 @@
 
 	spin_lock(&tp->lock);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
 	    tg3_flag(tp, 57765_CLASS))
 		tg3_chk_missed_msi(tp);
 
+	if (tg3_flag(tp, FLUSH_POSTED_WRITES)) {
+		/* BCM4785: Flush posted writes from GbE to host memory. */
+		tr32(HOSTCC_MODE);
+	}
+
 	if (!tg3_flag(tp, TAGGED_STATUS)) {
 		/* All of this garbage is because when using non-tagged
 		 * IRQ status the mailbox/status_block protocol the chip
@@ -10181,7 +10300,7 @@
 static void tg3_timer_init(struct tg3 *tp)
 {
 	if (tg3_flag(tp, TAGGED_STATUS) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+	    tg3_asic_rev(tp) != ASIC_REV_5717 &&
 	    !tg3_flag(tp, 57765_CLASS))
 		tp->timer_offset = HZ;
 	else
@@ -10762,7 +10881,7 @@
 
 	if (tp->fw_needed) {
 		err = tg3_request_firmware(tp);
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
 			if (err)
 				return err;
 		} else if (err) {
@@ -10832,8 +10951,8 @@
 	struct tg3_hw_stats *hw_stats = tp->hw_stats;
 
 	if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
+	    (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5701)) {
 		u32 val;
 
 		if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
@@ -12357,11 +12476,12 @@
 
 	if (tg3_flag(tp, 5717_PLUS))
 		mem_tbl = mem_tbl_5717;
-	else if (tg3_flag(tp, 57765_CLASS))
+	else if (tg3_flag(tp, 57765_CLASS) ||
+		 tg3_asic_rev(tp) == ASIC_REV_5762)
 		mem_tbl = mem_tbl_57765;
 	else if (tg3_flag(tp, 5755_PLUS))
 		mem_tbl = mem_tbl_5755;
-	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+	else if (tg3_asic_rev(tp) == ASIC_REV_5906)
 		mem_tbl = mem_tbl_5906;
 	else if (tg3_flag(tp, 5705_PLUS))
 		mem_tbl = mem_tbl_5705;
@@ -12473,7 +12593,7 @@
 		} else if (tg3_flag(tp, HW_TSO_2))
 			mss |= hdr_len << 9;
 		else if (tg3_flag(tp, HW_TSO_1) ||
-			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			 tg3_asic_rev(tp) == ASIC_REV_5705) {
 			mss |= (TG3_TSO_TCP_OPT_LEN << 9);
 		} else {
 			base_flags |= (TG3_TSO_TCP_OPT_LEN << 10);
@@ -12659,7 +12779,7 @@
 	 * errata.  Also, the MAC loopback test is deprecated for
 	 * all newer ASIC revisions.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 &&
+	if (tg3_asic_rev(tp) != ASIC_REV_5780 &&
 	    !tg3_flag(tp, CPMU_PRESENT)) {
 		tg3_mac_loopback(tp, true);
 
@@ -12937,7 +13057,8 @@
 			return -EAGAIN;
 
 		spin_lock_bh(&tp->lock);
-		err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
+		err = __tg3_readphy(tp, data->phy_id & 0x1f,
+				    data->reg_num & 0x1f, &mii_regval);
 		spin_unlock_bh(&tp->lock);
 
 		data->val_out = mii_regval;
@@ -12953,7 +13074,8 @@
 			return -EAGAIN;
 
 		spin_lock_bh(&tp->lock);
-		err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
+		err = __tg3_writephy(tp, data->phy_id & 0x1f,
+				     data->reg_num & 0x1f, data->val_in);
 		spin_unlock_bh(&tp->lock);
 
 		return err;
@@ -13144,7 +13266,7 @@
 	/* Reset PHY, otherwise the read DMA engine will be in a mode that
 	 * breaks all requests to 256 bytes.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+	if (tg3_asic_rev(tp) == ASIC_REV_57766)
 		reset_phy = 1;
 
 	err = tg3_restart_hw(tp, reset_phy);
@@ -13257,7 +13379,7 @@
 		tw32(NVRAM_CFG1, nvcfg1);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5750 ||
 	    tg3_flag(tp, 5780_CLASS)) {
 		switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
 		case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
@@ -13698,6 +13820,22 @@
 	nvcfg1 = tr32(NVRAM_CFG1);
 	nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK;
 
+	if (tg3_asic_rev(tp) == ASIC_REV_5762) {
+		if (!(nvcfg1 & NVRAM_CFG1_5762VENDOR_MASK)) {
+			tg3_flag_set(tp, NO_NVRAM);
+			return;
+		}
+
+		switch (nvmpinstrp) {
+		case FLASH_5762_EEPROM_HD:
+			nvmpinstrp = FLASH_5720_EEPROM_HD;
+			break;
+		case FLASH_5762_EEPROM_LD:
+			nvmpinstrp = FLASH_5720_EEPROM_LD;
+			break;
+		}
+	}
+
 	switch (nvmpinstrp) {
 	case FLASH_5720_EEPROM_HD:
 	case FLASH_5720_EEPROM_LD:
@@ -13743,7 +13881,8 @@
 			tp->nvram_size = TG3_NVRAM_SIZE_1MB;
 			break;
 		default:
-			tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+			if (tg3_asic_rev(tp) != ASIC_REV_5762)
+				tp->nvram_size = TG3_NVRAM_SIZE_128KB;
 			break;
 		}
 		break;
@@ -13789,7 +13928,8 @@
 			tp->nvram_size = TG3_NVRAM_SIZE_1MB;
 			break;
 		default:
-			tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+			if (tg3_asic_rev(tp) != ASIC_REV_5762)
+				tp->nvram_size = TG3_NVRAM_SIZE_128KB;
 			break;
 		}
 		break;
@@ -13801,11 +13941,30 @@
 	tg3_nvram_get_pagesize(tp, nvcfg1);
 	if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528)
 		tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
+
+	if (tg3_asic_rev(tp) == ASIC_REV_5762) {
+		u32 val;
+
+		if (tg3_nvram_read(tp, 0, &val))
+			return;
+
+		if (val != TG3_EEPROM_MAGIC &&
+		    (val & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW)
+			tg3_flag_set(tp, NO_NVRAM);
+	}
 }
 
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void tg3_nvram_init(struct tg3 *tp)
 {
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		/* No NVRAM and EEPROM on the SSB Broadcom GigE core. */
+		tg3_flag_clear(tp, NVRAM);
+		tg3_flag_clear(tp, NVRAM_BUFFERED);
+		tg3_flag_set(tp, NO_NVRAM);
+		return;
+	}
+
 	tw32_f(GRC_EEPROM_ADDR,
 	     (EEPROM_ADDR_FSM_RESET |
 	      (EEPROM_DEFAULT_CLOCK_PERIOD <<
@@ -13818,8 +13977,8 @@
 	     tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
 	udelay(100);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
+	if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+	    tg3_asic_rev(tp) != ASIC_REV_5701) {
 		tg3_flag_set(tp, NVRAM);
 
 		if (tg3_nvram_lock(tp)) {
@@ -13832,25 +13991,26 @@
 
 		tp->nvram_size = 0;
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+		if (tg3_asic_rev(tp) == ASIC_REV_5752)
 			tg3_get_5752_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+		else if (tg3_asic_rev(tp) == ASIC_REV_5755)
 			tg3_get_5755_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+		else if (tg3_asic_rev(tp) == ASIC_REV_5787 ||
+			 tg3_asic_rev(tp) == ASIC_REV_5784 ||
+			 tg3_asic_rev(tp) == ASIC_REV_5785)
 			tg3_get_5787_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		else if (tg3_asic_rev(tp) == ASIC_REV_5761)
 			tg3_get_5761_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		else if (tg3_asic_rev(tp) == ASIC_REV_5906)
 			tg3_get_5906_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+		else if (tg3_asic_rev(tp) == ASIC_REV_57780 ||
 			 tg3_flag(tp, 57765_CLASS))
 			tg3_get_57780_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+		else if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+			 tg3_asic_rev(tp) == ASIC_REV_5719)
 			tg3_get_5717_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		else if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+			 tg3_asic_rev(tp) == ASIC_REV_5762)
 			tg3_get_5720_nvram_info(tp);
 		else
 			tg3_get_nvram_info(tp);
@@ -13963,7 +14123,7 @@
 	tg3_flag_set(tp, EEPROM_WRITE_PROT);
 	tg3_flag_set(tp, WOL_CAP);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) {
 			tg3_flag_clear(tp, EEPROM_WRITE_PROT);
 			tg3_flag_set(tp, IS_NIC);
@@ -13990,13 +14150,13 @@
 
 		tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver);
 		ver >>= NIC_SRAM_DATA_VER_SHIFT;
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703 &&
+		if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+		    tg3_asic_rev(tp) != ASIC_REV_5701 &&
+		    tg3_asic_rev(tp) != ASIC_REV_5703 &&
 		    (ver > 0) && (ver < 0x100))
 			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+		if (tg3_asic_rev(tp) == ASIC_REV_5785)
 			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4);
 
 		if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
@@ -14044,18 +14204,16 @@
 			/* Default to PHY_1_MODE if 0 (MAC_MODE) is
 			 * read on some older 5700/5701 bootcode.
 			 */
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
-			    ASIC_REV_5700 ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) ==
-			    ASIC_REV_5701)
+			if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+			    tg3_asic_rev(tp) == ASIC_REV_5701)
 				tp->led_ctrl = LED_CTRL_MODE_PHY_1;
 
 			break;
 
 		case SHASTA_EXT_LED_SHARED:
 			tp->led_ctrl = LED_CTRL_MODE_SHARED;
-			if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
-			    tp->pci_chip_rev_id != CHIPREV_ID_5750_A1)
+			if (tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0 &&
+			    tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A1)
 				tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
 						 LED_CTRL_MODE_PHY_2);
 			break;
@@ -14066,19 +14224,19 @@
 
 		case SHASTA_EXT_LED_COMBO:
 			tp->led_ctrl = LED_CTRL_MODE_COMBO;
-			if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)
+			if (tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0)
 				tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
 						 LED_CTRL_MODE_PHY_2);
 			break;
 
 		}
 
-		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-		     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) &&
+		if ((tg3_asic_rev(tp) == ASIC_REV_5700 ||
+		     tg3_asic_rev(tp) == ASIC_REV_5701) &&
 		    tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
 			tp->led_ctrl = LED_CTRL_MODE_PHY_2;
 
-		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX)
+		if (tg3_chip_rev(tp) == CHIPREV_5784_AX)
 			tp->led_ctrl = LED_CTRL_MODE_PHY_1;
 
 		if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
@@ -14122,13 +14280,13 @@
 			tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS;
 
 		if ((tg3_flag(tp, 57765_PLUS) ||
-		     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
-		      GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) &&
+		     (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+		      tg3_chip_rev(tp) != CHIPREV_5784_AX)) &&
 		    (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
 			tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
 
 		if (tg3_flag(tp, PCI_EXPRESS) &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+		    tg3_asic_rev(tp) != ASIC_REV_5785 &&
 		    !tg3_flag(tp, 57765_PLUS)) {
 			u32 cfg3;
 
@@ -14152,6 +14310,39 @@
 		device_set_wakeup_capable(&tp->pdev->dev, false);
 }
 
+static int tg3_ape_otp_read(struct tg3 *tp, u32 offset, u32 *val)
+{
+	int i, err;
+	u32 val2, off = offset * 8;
+
+	err = tg3_nvram_lock(tp);
+	if (err)
+		return err;
+
+	tg3_ape_write32(tp, TG3_APE_OTP_ADDR, off | APE_OTP_ADDR_CPU_ENABLE);
+	tg3_ape_write32(tp, TG3_APE_OTP_CTRL, APE_OTP_CTRL_PROG_EN |
+			APE_OTP_CTRL_CMD_RD | APE_OTP_CTRL_START);
+	tg3_ape_read32(tp, TG3_APE_OTP_CTRL);
+	udelay(10);
+
+	for (i = 0; i < 100; i++) {
+		val2 = tg3_ape_read32(tp, TG3_APE_OTP_STATUS);
+		if (val2 & APE_OTP_STATUS_CMD_DONE) {
+			*val = tg3_ape_read32(tp, TG3_APE_OTP_RD_DATA);
+			break;
+		}
+		udelay(10);
+	}
+
+	tg3_ape_write32(tp, TG3_APE_OTP_CTRL, 0);
+
+	tg3_nvram_unlock(tp);
+	if (val2 & APE_OTP_STATUS_CMD_DONE)
+		return 0;
+
+	return -EBUSY;
+}
+
 static int tg3_issue_otp_command(struct tg3 *tp, u32 cmd)
 {
 	int i;
@@ -14298,10 +14489,19 @@
 			 * subsys device table.
 			 */
 			p = tg3_lookup_by_subsys(tp);
-			if (!p)
+			if (p) {
+				tp->phy_id = p->phy_id;
+			} else if (!tg3_flag(tp, IS_SSB_CORE)) {
+				/* For now we saw the IDs 0xbc050cd0,
+				 * 0xbc050f80 and 0xbc050c30 on devices
+				 * connected to an BCM4785 and there are
+				 * probably more. Just assume that the phy is
+				 * supported when it is connected to a SSB core
+				 * for now.
+				 */
 				return -ENODEV;
+			}
 
-			tp->phy_id = p->phy_id;
 			if (!tp->phy_id ||
 			    tp->phy_id == TG3_PHY_ID_BCM8002)
 				tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
@@ -14309,12 +14509,13 @@
 	}
 
 	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
-	     (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
-	      tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
-	     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
-	      tp->pci_chip_rev_id != CHIPREV_ID_57765_A0)))
+	    (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	     tg3_asic_rev(tp) == ASIC_REV_5762 ||
+	     (tg3_asic_rev(tp) == ASIC_REV_5717 &&
+	      tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
+	     (tg3_asic_rev(tp) == ASIC_REV_57765 &&
+	      tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0)))
 		tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
 
 	tg3_phy_init_link_config(tp);
@@ -14424,7 +14625,7 @@
 		return;
 
 out_no_vpd:
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5717) {
 		if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
 		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C)
 			strcpy(tp->board_part_number, "BCM5717");
@@ -14432,7 +14633,7 @@
 			strcpy(tp->board_part_number, "BCM5718");
 		else
 			goto nomatch;
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+	} else if (tg3_asic_rev(tp) == ASIC_REV_57780) {
 		if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780)
 			strcpy(tp->board_part_number, "BCM57780");
 		else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760)
@@ -14443,7 +14644,7 @@
 			strcpy(tp->board_part_number, "BCM57788");
 		else
 			goto nomatch;
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+	} else if (tg3_asic_rev(tp) == ASIC_REV_57765) {
 		if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761)
 			strcpy(tp->board_part_number, "BCM57761");
 		else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765)
@@ -14458,7 +14659,7 @@
 			strcpy(tp->board_part_number, "BCM57795");
 		else
 			goto nomatch;
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) {
+	} else if (tg3_asic_rev(tp) == ASIC_REV_57766) {
 		if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762)
 			strcpy(tp->board_part_number, "BCM57762");
 		else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766)
@@ -14469,7 +14670,7 @@
 			strcpy(tp->board_part_number, "BCM57786");
 		else
 			goto nomatch;
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	} else if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		strcpy(tp->board_part_number, "BCM95906");
 	} else {
 nomatch:
@@ -14691,6 +14892,8 @@
 
 	if (tg3_flag(tp, APE_HAS_NCSI))
 		fwtype = "NCSI";
+	else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725)
+		fwtype = "SMASH";
 	else
 		fwtype = "DASH";
 
@@ -14704,6 +14907,31 @@
 		 (apedata & APE_FW_VERSION_BLDMSK));
 }
 
+static void tg3_read_otp_ver(struct tg3 *tp)
+{
+	u32 val, val2;
+
+	if (tg3_asic_rev(tp) != ASIC_REV_5762)
+		return;
+
+	if (!tg3_ape_otp_read(tp, OTP_ADDRESS_MAGIC0, &val) &&
+	    !tg3_ape_otp_read(tp, OTP_ADDRESS_MAGIC0 + 4, &val2) &&
+	    TG3_OTP_MAGIC0_VALID(val)) {
+		u64 val64 = (u64) val << 32 | val2;
+		u32 ver = 0;
+		int i, vlen;
+
+		for (i = 0; i < 7; i++) {
+			if ((val64 & 0xff) == 0)
+				break;
+			ver = val64 & 0xff;
+			val64 >>= 8;
+		}
+		vlen = strlen(tp->fw_ver);
+		snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " .%02d", ver);
+	}
+}
+
 static void tg3_read_fw_ver(struct tg3 *tp)
 {
 	u32 val;
@@ -14714,6 +14942,7 @@
 
 	if (tg3_flag(tp, NO_NVRAM)) {
 		strcat(tp->fw_ver, "sb");
+		tg3_read_otp_ver(tp);
 		return;
 	}
 
@@ -14788,7 +15017,7 @@
 static void tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
 {
 	tp->pci_chip_rev_id = misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+	if (tg3_asic_rev(tp) == ASIC_REV_USE_PROD_ID_REG) {
 		u32 reg;
 
 		/* All devices that use the alternate
@@ -14800,7 +15029,10 @@
 		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C ||
 		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
 		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
-		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5762 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5727)
 			reg = TG3PCI_GEN2_PRODID_ASICREV;
 		else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
 			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
@@ -14822,46 +15054,47 @@
 	/* Wrong chip ID in 5752 A0. This code can be removed later
 	 * as A0 is not in production.
 	 */
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5752_A0_HW)
 		tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5717_C0)
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5717_C0)
 		tp->pci_chip_rev_id = CHIPREV_ID_5720_A0;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720)
 		tg3_flag_set(tp, 5717_PLUS);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+	if (tg3_asic_rev(tp) == ASIC_REV_57765 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57766)
 		tg3_flag_set(tp, 57765_CLASS);
 
-	if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
+	if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS) ||
+	     tg3_asic_rev(tp) == ASIC_REV_5762)
 		tg3_flag_set(tp, 57765_PLUS);
 
 	/* Intentionally exclude ASIC_REV_5906 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5787 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5784 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5761 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5785 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57780 ||
 	    tg3_flag(tp, 57765_PLUS))
 		tg3_flag_set(tp, 5755_PLUS);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
+	if (tg3_asic_rev(tp) == ASIC_REV_5780 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5714)
 		tg3_flag_set(tp, 5780_CLASS);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5750 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5752 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5906 ||
 	    tg3_flag(tp, 5755_PLUS) ||
 	    tg3_flag(tp, 5780_CLASS))
 		tg3_flag_set(tp, 5750_PLUS);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5705 ||
 	    tg3_flag(tp, 5750_PLUS))
 		tg3_flag_set(tp, 5705_PLUS);
 }
@@ -14871,13 +15104,13 @@
 {
 	u32 grc_misc_cfg = tr32(GRC_MISC_CFG) & GRC_MISC_CFG_BOARD_ID_MASK;
 
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
-	    (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
+	if ((tg3_asic_rev(tp) == ASIC_REV_5703 &&
+	     (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
 	    (tp->phy_flags & TG3_PHYFLG_IS_FET))
 		return true;
 
 	if (ent->driver_data & TG3_DRV_DATA_FLAG_10_100_ONLY) {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5705) {
 			if (ent->driver_data & TG3_DRV_DATA_FLAG_5705_10_100)
 				return true;
 		} else {
@@ -14938,8 +15171,8 @@
 	 * enable this workaround if the 5703 is on the secondary
 	 * bus of these ICH bridges.
 	 */
-	if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) ||
-	    (tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)) {
+	if ((tg3_chip_rev_id(tp) == CHIPREV_ID_5703_A1) ||
+	    (tg3_chip_rev_id(tp) == CHIPREV_ID_5703_A2)) {
 		static struct tg3_dev_id {
 			u32	vendor;
 			u32	device;
@@ -14979,7 +15212,7 @@
 		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5701) {
 		static struct tg3_dev_id {
 			u32	vendor;
 			u32	device;
@@ -15039,29 +15272,29 @@
 		} while (bridge);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
+	if (tg3_asic_rev(tp) == ASIC_REV_5704 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5714)
 		tp->pdev_peer = tg3_find_peer(tp);
 
 	/* Determine TSO capabilities */
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0)
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0)
 		; /* Do nothing. HW bug. */
 	else if (tg3_flag(tp, 57765_PLUS))
 		tg3_flag_set(tp, HW_TSO_3);
 	else if (tg3_flag(tp, 5755_PLUS) ||
-		 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		 tg3_asic_rev(tp) == ASIC_REV_5906)
 		tg3_flag_set(tp, HW_TSO_2);
 	else if (tg3_flag(tp, 5750_PLUS)) {
 		tg3_flag_set(tp, HW_TSO_1);
 		tg3_flag_set(tp, TSO_BUG);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 &&
-		    tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
+		if (tg3_asic_rev(tp) == ASIC_REV_5750 &&
+		    tg3_chip_rev_id(tp) >= CHIPREV_ID_5750_C2)
 			tg3_flag_clear(tp, TSO_BUG);
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-		   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
-		   tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+	} else if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+		   tg3_asic_rev(tp) != ASIC_REV_5701 &&
+		   tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
 			tg3_flag_set(tp, TSO_BUG);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+		if (tg3_asic_rev(tp) == ASIC_REV_5705)
 			tp->fw_needed = FIRMWARE_TG3TSO5;
 		else
 			tp->fw_needed = FIRMWARE_TG3TSO;
@@ -15083,22 +15316,22 @@
 		tp->fw_needed = NULL;
 	}
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0)
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0)
 		tp->fw_needed = FIRMWARE_TG3;
 
 	tp->irq_max = 1;
 
 	if (tg3_flag(tp, 5750_PLUS)) {
 		tg3_flag_set(tp, SUPPORT_MSI);
-		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX ||
-		    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX ||
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 &&
-		     tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 &&
+		if (tg3_chip_rev(tp) == CHIPREV_5750_AX ||
+		    tg3_chip_rev(tp) == CHIPREV_5750_BX ||
+		    (tg3_asic_rev(tp) == ASIC_REV_5714 &&
+		     tg3_chip_rev_id(tp) <= CHIPREV_ID_5714_A2 &&
 		     tp->pdev_peer == tp->pdev))
 			tg3_flag_clear(tp, SUPPORT_MSI);
 
 		if (tg3_flag(tp, 5755_PLUS) ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		    tg3_asic_rev(tp) == ASIC_REV_5906) {
 			tg3_flag_set(tp, 1SHOT_MSI);
 		}
 
@@ -15114,25 +15347,26 @@
 		tp->rxq_max = TG3_RSS_MAX_NUM_QS;
 		tg3_rss_init_dflt_indir_tbl(tp, TG3_RSS_MAX_NUM_QS);
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5720)
 			tp->txq_max = tp->irq_max - 1;
 	}
 
 	if (tg3_flag(tp, 5755_PLUS) ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+	    tg3_asic_rev(tp) == ASIC_REV_5906)
 		tg3_flag_set(tp, SHORT_DMA_BUG);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+	if (tg3_asic_rev(tp) == ASIC_REV_5719)
 		tp->dma_limit = TG3_TX_BD_DMA_MAX_4K;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762)
 		tg3_flag_set(tp, LRG_PROD_RING_CAP);
 
 	if (tg3_flag(tp, 57765_PLUS) &&
-	    tp->pci_chip_rev_id != CHIPREV_ID_5719_A0)
+	    tg3_chip_rev_id(tp) != CHIPREV_ID_5719_A0)
 		tg3_flag_set(tp, USE_JUMBO_BDFLAG);
 
 	if (!tg3_flag(tp, 5705_PLUS) ||
@@ -15150,20 +15384,19 @@
 
 		pcie_capability_read_word(tp->pdev, PCI_EXP_LNKCTL, &lnkctl);
 		if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) {
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
-			    ASIC_REV_5906) {
+			if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 				tg3_flag_clear(tp, HW_TSO_2);
 				tg3_flag_clear(tp, TSO_CAPABLE);
 			}
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-			    tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 ||
-			    tp->pci_chip_rev_id == CHIPREV_ID_57780_A1)
+			if (tg3_asic_rev(tp) == ASIC_REV_5784 ||
+			    tg3_asic_rev(tp) == ASIC_REV_5761 ||
+			    tg3_chip_rev_id(tp) == CHIPREV_ID_57780_A0 ||
+			    tg3_chip_rev_id(tp) == CHIPREV_ID_57780_A1)
 				tg3_flag_set(tp, CLKREQ_BUG);
-		} else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) {
+		} else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5717_A0) {
 			tg3_flag_set(tp, L1PLLPD_EN);
 		}
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+	} else if (tg3_asic_rev(tp) == ASIC_REV_5785) {
 		/* BCM5785 devices are effectively PCIe devices, and should
 		 * follow PCIe codepaths, but do not have a PCIe capabilities
 		 * section.
@@ -15196,7 +15429,7 @@
 			     &tp->pci_cacheline_sz);
 	pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER,
 			     &tp->pci_lat_timer);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5703 &&
 	    tp->pci_lat_timer < 64) {
 		tp->pci_lat_timer = 64;
 		pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
@@ -15206,7 +15439,7 @@
 	/* Important! -- It is critical that the PCI-X hw workaround
 	 * situation is decided before the first MMIO register access.
 	 */
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
+	if (tg3_chip_rev(tp) == CHIPREV_5700_BX) {
 		/* 5700 BX chips need to have their TX producer index
 		 * mailboxes written twice to workaround a bug.
 		 */
@@ -15248,7 +15481,7 @@
 		tg3_flag_set(tp, PCI_32BIT);
 
 	/* Chip-specific fixup from Broadcom driver */
-	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+	if ((tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0) &&
 	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
 		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
 		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
@@ -15265,9 +15498,9 @@
 	/* Various workaround register access methods */
 	if (tg3_flag(tp, PCIX_TARGET_HWBUG))
 		tp->write32 = tg3_write_indirect_reg32;
-	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
+	else if (tg3_asic_rev(tp) == ASIC_REV_5701 ||
 		 (tg3_flag(tp, PCI_EXPRESS) &&
-		  tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) {
+		  tg3_chip_rev_id(tp) == CHIPREV_ID_5750_A0)) {
 		/*
 		 * Back to back register writes can cause problems on these
 		 * chips, the workaround is to read back all reg writes
@@ -15299,7 +15532,7 @@
 		pci_cmd &= ~PCI_COMMAND_MEMORY;
 		pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 	}
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 		tp->read32_mbox = tg3_read32_mbox_5906;
 		tp->write32_mbox = tg3_write32_mbox_5906;
 		tp->write32_tx_mbox = tg3_write32_mbox_5906;
@@ -15308,8 +15541,8 @@
 
 	if (tp->write32 == tg3_write_indirect_reg32 ||
 	    (tg3_flag(tp, PCIX_MODE) &&
-	     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	      GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
+	     (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	      tg3_asic_rev(tp) == ASIC_REV_5701)))
 		tg3_flag_set(tp, SRAM_USE_CONFIG);
 
 	/* The memory arbiter has to be enabled in order for SRAM accesses
@@ -15321,7 +15554,7 @@
 	tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
 
 	tp->pci_fn = PCI_FUNC(tp->pdev->devfn) & 3;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5704 ||
 	    tg3_flag(tp, 5780_CLASS)) {
 		if (tg3_flag(tp, PCIX_MODE)) {
 			pci_read_config_dword(tp->pdev,
@@ -15329,21 +15562,23 @@
 					      &val);
 			tp->pci_fn = val & 0x7;
 		}
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
+	} else if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+		   tg3_asic_rev(tp) == ASIC_REV_5719 ||
+		   tg3_asic_rev(tp) == ASIC_REV_5720) {
 		tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val);
-		if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) ==
-		    NIC_SRAM_CPMUSTAT_SIG) {
-			tp->pci_fn = val & TG3_CPMU_STATUS_FMSK_5717;
-			tp->pci_fn = tp->pci_fn ? 1 : 0;
-		}
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-		   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
-		tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val);
-		if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) ==
-		    NIC_SRAM_CPMUSTAT_SIG) {
+		if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) != NIC_SRAM_CPMUSTAT_SIG)
+			val = tr32(TG3_CPMU_STATUS);
+
+		if (tg3_asic_rev(tp) == ASIC_REV_5717)
+			tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5717) ? 1 : 0;
+		else
 			tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5719) >>
 				     TG3_CPMU_STATUS_FSHFT_5719;
-		}
+	}
+
+	if (tg3_flag(tp, FLUSH_POSTED_WRITES)) {
+		tp->write32_tx_mbox = tg3_write_flush_reg32;
+		tp->write32_rx_mbox = tg3_write_flush_reg32;
 	}
 
 	/* Get eeprom hw config before calling tg3_set_power_state().
@@ -15381,18 +15616,18 @@
 	 * It is also used as eeprom write protect on LOMs.
 	 */
 	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
 	    tg3_flag(tp, EEPROM_WRITE_PROT))
 		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
 				       GRC_LCLCTRL_GPIO_OUTPUT1);
 	/* Unused GPIO3 must be driven as output on 5752 because there
 	 * are no pull-up resistors on unused GPIO pins.
 	 */
-	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+	else if (tg3_asic_rev(tp) == ASIC_REV_5752)
 		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57780 ||
 	    tg3_flag(tp, 57765_CLASS))
 		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
 
@@ -15406,6 +15641,10 @@
 					      GRC_LCLCTRL_GPIO_OUTPUT0;
 	}
 
+	if (tg3_asic_rev(tp) == ASIC_REV_5762)
+		tp->grc_local_ctrl |=
+			tr32(GRC_LOCAL_CTRL) & GRC_LCLCTRL_GPIO_UART_SEL;
+
 	/* Switch out of Vaux if it is a NIC */
 	tg3_pwrsrc_switch_to_vmain(tp);
 
@@ -15416,42 +15655,42 @@
 		tg3_flag_set(tp, JUMBO_RING_ENABLE);
 
 	/* Determine WakeOnLan speed to use. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B2) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B2) {
 		tg3_flag_clear(tp, WOL_SPEED_100MB);
 	} else {
 		tg3_flag_set(tp, WOL_SPEED_100MB);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+	if (tg3_asic_rev(tp) == ASIC_REV_5906)
 		tp->phy_flags |= TG3_PHYFLG_IS_FET;
 
 	/* A few boards don't want Ethernet@WireSpeed phy feature */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
-	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
-	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    (tg3_asic_rev(tp) == ASIC_REV_5705 &&
+	     (tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) &&
+	     (tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A1)) ||
 	    (tp->phy_flags & TG3_PHYFLG_IS_FET) ||
 	    (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
 		tp->phy_flags |= TG3_PHYFLG_NO_ETH_WIRE_SPEED;
 
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
-	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
+	if (tg3_chip_rev(tp) == CHIPREV_5703_AX ||
+	    tg3_chip_rev(tp) == CHIPREV_5704_AX)
 		tp->phy_flags |= TG3_PHYFLG_ADC_BUG;
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0)
 		tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG;
 
 	if (tg3_flag(tp, 5705_PLUS) &&
 	    !(tp->phy_flags & TG3_PHYFLG_IS_FET) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 &&
+	    tg3_asic_rev(tp) != ASIC_REV_5785 &&
+	    tg3_asic_rev(tp) != ASIC_REV_57780 &&
 	    !tg3_flag(tp, 57765_PLUS)) {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5787 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5784 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5761) {
 			if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
 			    tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
 				tp->phy_flags |= TG3_PHYFLG_JITTER_BUG;
@@ -15461,8 +15700,8 @@
 			tp->phy_flags |= TG3_PHYFLG_BER_BUG;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
-	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+	    tg3_chip_rev(tp) != CHIPREV_5784_AX) {
 		tp->phy_otp = tg3_read_otp_phycfg(tp);
 		if (tp->phy_otp == 0)
 			tp->phy_otp = TG3_OTP_DEFAULT;
@@ -15474,20 +15713,20 @@
 		tp->mi_mode = MAC_MI_MODE_BASE;
 
 	tp->coalesce_mode = 0;
-	if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
-	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
+	if (tg3_chip_rev(tp) != CHIPREV_5700_AX &&
+	    tg3_chip_rev(tp) != CHIPREV_5700_BX)
 		tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
 
 	/* Set these bits to enable statistics workaround. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
+	    tg3_chip_rev_id(tp) == CHIPREV_ID_5720_A0) {
 		tp->coalesce_mode |= HOSTCC_MODE_ATTN;
 		tp->grc_mode |= GRC_MODE_IRQ_ON_FLOW_ATTN;
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+	if (tg3_asic_rev(tp) == ASIC_REV_5785 ||
+	    tg3_asic_rev(tp) == ASIC_REV_57780)
 		tg3_flag_set(tp, USE_PHYLIB);
 
 	err = tg3_mdio_init(tp);
@@ -15496,7 +15735,8 @@
 
 	/* Initialize data/descriptor byte/word swapping. */
 	val = tr32(GRC_MODE);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762)
 		val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA |
 			GRC_MODE_WORD_SWAP_B2HRX_DATA |
 			GRC_MODE_B2HRX_ENABLE |
@@ -15516,12 +15756,10 @@
 			      &pci_state_reg);
 	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 &&
 	    !tg3_flag(tp, PCIX_TARGET_HWBUG)) {
-		u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl);
-
-		if (chiprevid == CHIPREV_ID_5701_A0 ||
-		    chiprevid == CHIPREV_ID_5701_B0 ||
-		    chiprevid == CHIPREV_ID_5701_B2 ||
-		    chiprevid == CHIPREV_ID_5701_B5) {
+		if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+		    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0 ||
+		    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B2 ||
+		    tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B5) {
 			void __iomem *sram_base;
 
 			/* Write some dummy words into the SRAM status block
@@ -15544,13 +15782,13 @@
 	grc_misc_cfg = tr32(GRC_MISC_CFG);
 	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5705 &&
 	    (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
 	     grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
 		tg3_flag_set(tp, IS_5788);
 
 	if (!tg3_flag(tp, IS_5788) &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+	    tg3_asic_rev(tp) != ASIC_REV_5700)
 		tg3_flag_set(tp, TAGGED_STATUS);
 	if (tg3_flag(tp, TAGGED_STATUS)) {
 		tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD |
@@ -15583,7 +15821,7 @@
 	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
 		tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
 	} else {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+		if (tg3_asic_rev(tp) == ASIC_REV_5700)
 			tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
 		else
 			tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
@@ -15593,7 +15831,7 @@
 	 * change bit implementation, so we must use the
 	 * status register in those cases.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+	if (tg3_asic_rev(tp) == ASIC_REV_5700)
 		tg3_flag_set(tp, USE_LINKCHG_REG);
 	else
 		tg3_flag_clear(tp, USE_LINKCHG_REG);
@@ -15603,7 +15841,7 @@
 	 * upon subsystem IDs.
 	 */
 	if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
+	    tg3_asic_rev(tp) == ASIC_REV_5701 &&
 	    !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
 		tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
 		tg3_flag_set(tp, USE_LINKCHG_REG);
@@ -15617,7 +15855,7 @@
 
 	tp->rx_offset = NET_SKB_PAD + NET_IP_ALIGN;
 	tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
+	if (tg3_asic_rev(tp) == ASIC_REV_5701 &&
 	    tg3_flag(tp, PCIX_MODE)) {
 		tp->rx_offset = NET_SKB_PAD;
 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
@@ -15634,9 +15872,9 @@
 	/* Increment the rx prod index on the rx std ring by at most
 	 * 8 for these chips to workaround hw errata.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+	if (tg3_asic_rev(tp) == ASIC_REV_5750 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5752 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5755)
 		tp->rx_std_max_post = 8;
 
 	if (tg3_flag(tp, ASPM_WORKAROUND))
@@ -15658,7 +15896,6 @@
 	addr = of_get_property(dp, "local-mac-address", &len);
 	if (addr && len == 6) {
 		memcpy(dev->dev_addr, addr, 6);
-		memcpy(dev->perm_addr, dev->dev_addr, 6);
 		return 0;
 	}
 	return -ENODEV;
@@ -15669,7 +15906,6 @@
 	struct net_device *dev = tp->dev;
 
 	memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-	memcpy(dev->perm_addr, idprom->id_ethaddr, 6);
 	return 0;
 }
 #endif
@@ -15679,14 +15915,21 @@
 	struct net_device *dev = tp->dev;
 	u32 hi, lo, mac_offset;
 	int addr_ok = 0;
+	int err;
 
 #ifdef CONFIG_SPARC
 	if (!tg3_get_macaddr_sparc(tp))
 		return 0;
 #endif
 
+	if (tg3_flag(tp, IS_SSB_CORE)) {
+		err = ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
+		if (!err && is_valid_ether_addr(&dev->dev_addr[0]))
+			return 0;
+	}
+
 	mac_offset = 0x7c;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	if (tg3_asic_rev(tp) == ASIC_REV_5704 ||
 	    tg3_flag(tp, 5780_CLASS)) {
 		if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
 			mac_offset = 0xcc;
@@ -15699,7 +15942,7 @@
 			mac_offset = 0xcc;
 		if (tp->pci_fn > 1)
 			mac_offset += 0x18c;
-	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+	} else if (tg3_asic_rev(tp) == ASIC_REV_5906)
 		mac_offset = 0x10;
 
 	/* First try to get it from MAC address mailbox. */
@@ -15746,7 +15989,6 @@
 #endif
 		return -EINVAL;
 	}
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 	return 0;
 }
 
@@ -15768,8 +16010,8 @@
 	/* On 5703 and later chips, the boundary bits have no
 	 * effect.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+	if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+	    tg3_asic_rev(tp) != ASIC_REV_5701 &&
 	    !tg3_flag(tp, PCI_EXPRESS))
 		goto out;
 
@@ -16007,14 +16249,14 @@
 		/* DMA read watermark not used on PCIE */
 		tp->dma_rwctrl |= 0x00180000;
 	} else if (!tg3_flag(tp, PCIX_MODE)) {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+		if (tg3_asic_rev(tp) == ASIC_REV_5705 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5750)
 			tp->dma_rwctrl |= 0x003f0000;
 		else
 			tp->dma_rwctrl |= 0x003f000f;
 	} else {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+		    tg3_asic_rev(tp) == ASIC_REV_5704) {
 			u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
 			u32 read_water = 0x7;
 
@@ -16023,35 +16265,37 @@
 			 * better performance.
 			 */
 			if (tg3_flag(tp, 40BIT_DMA_BUG) &&
-			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			    tg3_asic_rev(tp) == ASIC_REV_5704)
 				tp->dma_rwctrl |= 0x8000;
 			else if (ccval == 0x6 || ccval == 0x7)
 				tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
 
-			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703)
+			if (tg3_asic_rev(tp) == ASIC_REV_5703)
 				read_water = 4;
 			/* Set bit 23 to enable PCIX hw bug fix */
 			tp->dma_rwctrl |=
 				(read_water << DMA_RWCTRL_READ_WATER_SHIFT) |
 				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
 				(1 << 23);
-		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
+		} else if (tg3_asic_rev(tp) == ASIC_REV_5780) {
 			/* 5780 always in PCIX mode */
 			tp->dma_rwctrl |= 0x00144000;
-		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+		} else if (tg3_asic_rev(tp) == ASIC_REV_5714) {
 			/* 5714 always in PCIX mode */
 			tp->dma_rwctrl |= 0x00148000;
 		} else {
 			tp->dma_rwctrl |= 0x001b000f;
 		}
 	}
+	if (tg3_flag(tp, ONE_DMA_AT_ONCE))
+		tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+	if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5704)
 		tp->dma_rwctrl &= 0xfffffff0;
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+	if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5701) {
 		/* Remove this if it causes problems for some boards. */
 		tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
 
@@ -16075,8 +16319,8 @@
 	tg3_switch_clocks(tp);
 #endif
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+	if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+	    tg3_asic_rev(tp) != ASIC_REV_5701)
 		goto out;
 
 	/* It is best to perform DMA test with maximum write burst size
@@ -16195,7 +16439,7 @@
 			DEFAULT_MB_MACRX_LOW_WATER_5705;
 		tp->bufmgr_config.mbuf_high_water =
 			DEFAULT_MB_HIGH_WATER_5705;
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		if (tg3_asic_rev(tp) == ASIC_REV_5906) {
 			tp->bufmgr_config.mbuf_mac_rx_low_water =
 				DEFAULT_MB_MACRX_LOW_WATER_5906;
 			tp->bufmgr_config.mbuf_high_water =
@@ -16253,6 +16497,7 @@
 	case TG3_PHY_ID_BCM57765:	return "57765";
 	case TG3_PHY_ID_BCM5719C:	return "5719C";
 	case TG3_PHY_ID_BCM5720C:	return "5720C";
+	case TG3_PHY_ID_BCM5762:	return "5762C";
 	case TG3_PHY_ID_BCM8002:	return "8002/serdes";
 	case 0:			return "serdes";
 	default:		return "unknown";
@@ -16389,6 +16634,18 @@
 	else
 		tp->msg_enable = TG3_DEF_MSG_ENABLE;
 
+	if (pdev_is_ssb_gige_core(pdev)) {
+		tg3_flag_set(tp, IS_SSB_CORE);
+		if (ssb_gige_must_flush_posted_writes(pdev))
+			tg3_flag_set(tp, FLUSH_POSTED_WRITES);
+		if (ssb_gige_one_dma_at_once(pdev))
+			tg3_flag_set(tp, ONE_DMA_AT_ONCE);
+		if (ssb_gige_have_roboswitch(pdev))
+			tg3_flag_set(tp, ROBOSWITCH);
+		if (ssb_gige_is_rgmii(pdev))
+			tg3_flag_set(tp, RGMII_MODE);
+	}
+
 	/* The word/byte swap controls here control register access byte
 	 * swapping.  DMA data byte swapping is controlled in the GRC_MODE
 	 * setting below.
@@ -16429,7 +16686,10 @@
 	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C ||
 	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
 	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
-	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) {
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720 ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5762 ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725 ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5727) {
 		tg3_flag_set(tp, ENABLE_APE);
 		tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
 		if (!tp->aperegs) {
@@ -16501,7 +16761,7 @@
 	/* 5700 B0 chips do not support checksumming correctly due
 	 * to hardware bugs.
 	 */
-	if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) {
+	if (tg3_chip_rev_id(tp) != CHIPREV_ID_5700_B0) {
 		features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
 
 		if (tg3_flag(tp, 5755_PLUS))
@@ -16521,11 +16781,11 @@
 		if (features & NETIF_F_IPV6_CSUM)
 			features |= NETIF_F_TSO6;
 		if (tg3_flag(tp, HW_TSO_3) ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
-		     GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+		    tg3_asic_rev(tp) == ASIC_REV_5761 ||
+		    (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+		     tg3_chip_rev(tp) != CHIPREV_5784_AX) ||
+		    tg3_asic_rev(tp) == ASIC_REV_5785 ||
+		    tg3_asic_rev(tp) == ASIC_REV_57780)
 			features |= NETIF_F_TSO_ECN;
 	}
 
@@ -16537,14 +16797,14 @@
 	 * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY
 	 * loopback for the remaining devices.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 &&
+	if (tg3_asic_rev(tp) != ASIC_REV_5780 &&
 	    !tg3_flag(tp, CPMU_PRESENT))
 		/* Add the loopback capability */
 		features |= NETIF_F_LOOPBACK;
 
 	dev->hw_features |= features;
 
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
+	if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A1 &&
 	    !tg3_flag(tp, TSO_CAPABLE) &&
 	    !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) {
 		tg3_flag_set(tp, MAX_RXPEND_64);
@@ -16623,8 +16883,9 @@
 
 	pci_set_drvdata(pdev, dev);
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+	if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5720 ||
+	    tg3_asic_rev(tp) == ASIC_REV_5762)
 		tg3_flag_set(tp, PTP_CAPABLE);
 
 	if (tg3_flag(tp, 5717_PLUS)) {
@@ -16634,6 +16895,8 @@
 
 	tg3_timer_init(tp);
 
+	tg3_carrier_off(tp);
+
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting\n");
@@ -16642,7 +16905,7 @@
 
 	netdev_info(dev, "Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n",
 		    tp->board_part_number,
-		    tp->pci_chip_rev_id,
+		    tg3_chip_rev_id(tp),
 		    tg3_bus_string(tp, str),
 		    dev->dev_addr);
 
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index d330e81..8d7d4c2 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2007-2012 Broadcom Corporation.
+ * Copyright (C) 2007-2013 Broadcom Corporation.
  */
 
 #ifndef _T3_H
@@ -65,6 +65,9 @@
 #define  TG3PCI_DEVICE_TIGON3_57766	 0x1686
 #define  TG3PCI_DEVICE_TIGON3_57786	 0x16b3
 #define  TG3PCI_DEVICE_TIGON3_57782	 0x16b7
+#define  TG3PCI_DEVICE_TIGON3_5762	 0x1687
+#define  TG3PCI_DEVICE_TIGON3_5725	 0x1643
+#define  TG3PCI_DEVICE_TIGON3_5727	 0x16f3
 /* 0x04 --> 0x2c unused */
 #define TG3PCI_SUBVENDOR_ID_BROADCOM		PCI_VENDOR_ID_BROADCOM
 #define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6	0x1644
@@ -117,9 +120,7 @@
 #define  MISC_HOST_CTRL_TAGGED_STATUS	 0x00000200
 #define  MISC_HOST_CTRL_CHIPREV		 0xffff0000
 #define  MISC_HOST_CTRL_CHIPREV_SHIFT	 16
-#define  GET_CHIP_REV_ID(MISC_HOST_CTRL) \
-	 (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \
-	  MISC_HOST_CTRL_CHIPREV_SHIFT)
+
 #define  CHIPREV_ID_5700_A0		 0x7000
 #define  CHIPREV_ID_5700_A1		 0x7001
 #define  CHIPREV_ID_5700_B0		 0x7100
@@ -159,7 +160,8 @@
 #define  CHIPREV_ID_57765_A0		 0x57785000
 #define  CHIPREV_ID_5719_A0		 0x05719000
 #define  CHIPREV_ID_5720_A0		 0x05720000
-#define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
+#define  CHIPREV_ID_5762_A0		 0x05762000
+
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
 #define   ASIC_REV_5703			 0x01
@@ -182,7 +184,7 @@
 #define   ASIC_REV_5719			 0x5719
 #define   ASIC_REV_5720			 0x5720
 #define   ASIC_REV_57766		 0x57766
-#define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
+#define   ASIC_REV_5762			 0x5762
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
 #define   CHIPREV_5700_CX		 0x72
@@ -195,7 +197,6 @@
 #define   CHIPREV_5784_AX		 0x57840
 #define   CHIPREV_5761_AX		 0x57610
 #define   CHIPREV_57765_AX		 0x577650
-#define  GET_METAL_REV(CHIP_REV_ID)	((CHIP_REV_ID) & 0xff)
 #define   METAL_REV_A0			 0x00
 #define   METAL_REV_A1			 0x01
 #define   METAL_REV_B0			 0x00
@@ -774,7 +775,7 @@
 #define  SG_DIG_AUTONEG_ERROR		 0x00000001
 #define TG3_TX_TSTAMP_LSB		0x000005c0
 #define TG3_TX_TSTAMP_MSB		0x000005c4
-#define  TG3_TSTAMP_MASK		 0x7fffffffffffffff
+#define  TG3_TSTAMP_MASK		 0x7fffffffffffffffLL
 /* 0x5c8 --> 0x600 unused */
 #define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
 #define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
@@ -1159,6 +1160,8 @@
 #define  CPMU_MUTEX_GNT_DRIVER		 0x00001000
 #define TG3_CPMU_PHY_STRAP		0x00003664
 #define TG3_CPMU_PHY_STRAP_IS_SERDES	 0x00000020
+#define TG3_CPMU_PADRNG_CTL		0x00003668
+#define  TG3_CPMU_PADRNG_CTL_RDIV2	 0x00040000
 /* 0x3664 --> 0x36b0 unused */
 
 #define TG3_CPMU_EEE_MODE		0x000036b0
@@ -1178,6 +1181,7 @@
 #define TG3_CPMU_EEE_LNKIDL_CTRL	0x000036bc
 #define  TG3_CPMU_EEE_LNKIDL_PCIE_NL0	 0x01000000
 #define  TG3_CPMU_EEE_LNKIDL_UART_IDL	 0x00000004
+#define  TG3_CPMU_EEE_LNKIDL_APE_TX_MT	 0x00000002
 /* 0x36c0 --> 0x36d0 unused */
 
 #define TG3_CPMU_EEE_CTRL		0x000036d0
@@ -1400,7 +1404,10 @@
 #define  RDMAC_STATUS_FIFOURUN		 0x00000080
 #define  RDMAC_STATUS_FIFOOREAD		 0x00000100
 #define  RDMAC_STATUS_LNGREAD		 0x00000200
-/* 0x4808 --> 0x4900 unused */
+/* 0x4808 --> 0x4890 unused */
+
+#define TG3_RDMA_RSRVCTRL_REG2		0x00004890
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL2	0x000048a0
 
 #define TG3_RDMA_RSRVCTRL_REG		0x00004900
 #define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX	 0x00000004
@@ -1850,6 +1857,7 @@
 #define  FLASH_VENDOR_SST_SMALL		 0x00000001
 #define  FLASH_VENDOR_SST_LARGE		 0x02000001
 #define  NVRAM_CFG1_5752VENDOR_MASK	 0x03c00003
+#define  NVRAM_CFG1_5762VENDOR_MASK	 0x03e00003
 #define  FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ	 0x00000000
 #define  FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ	 0x02000000
 #define  FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED	 0x02000003
@@ -1910,6 +1918,8 @@
 #define  FLASH_5717VENDOR_ST_45USPT	 0x03400001
 #define  FLASH_5720_EEPROM_HD		 0x00000001
 #define  FLASH_5720_EEPROM_LD		 0x00000003
+#define  FLASH_5762_EEPROM_HD		 0x02000001
+#define  FLASH_5762_EEPROM_LD		 0x02000003
 #define  FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000
 #define  FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002
 #define  FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001
@@ -2365,6 +2375,20 @@
 #define  APE_LOCK_REQ_DRIVER		 0x00001000
 #define TG3_APE_LOCK_GRANT		0x004c
 #define  APE_LOCK_GRANT_DRIVER		 0x00001000
+#define TG3_APE_OTP_CTRL		0x00e8
+#define  APE_OTP_CTRL_PROG_EN		 0x200000
+#define  APE_OTP_CTRL_CMD_RD		 0x000000
+#define  APE_OTP_CTRL_START		 0x000001
+#define TG3_APE_OTP_STATUS		0x00ec
+#define  APE_OTP_STATUS_CMD_DONE	 0x000001
+#define TG3_APE_OTP_ADDR		0x00f0
+#define  APE_OTP_ADDR_CPU_ENABLE	 0x80000000
+#define TG3_APE_OTP_RD_DATA		0x00f8
+
+#define OTP_ADDRESS_MAGIC0		 0x00000050
+#define TG3_OTP_MAGIC0_VALID(val)		\
+	((((val) & 0xf0000000) == 0xa0000000) ||\
+	 (((val) & 0x0f000000) == 0x0a000000))
 
 /* APE shared memory.  Accessible through BAR1 */
 #define TG3_APE_SHMEM_BASE		0x4000
@@ -3030,6 +3054,11 @@
 	TG3_FLAG_57765_PLUS,
 	TG3_FLAG_57765_CLASS,
 	TG3_FLAG_5717_PLUS,
+	TG3_FLAG_IS_SSB_CORE,
+	TG3_FLAG_FLUSH_POSTED_WRITES,
+	TG3_FLAG_ROBOSWITCH,
+	TG3_FLAG_ONE_DMA_AT_ONCE,
+	TG3_FLAG_RGMII_MODE,
 
 	/* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */
 	TG3_FLAG_NUMBER_OF_FLAGS,	/* Last entry in enum TG3_FLAGS */
@@ -3206,6 +3235,7 @@
 #define TG3_PHY_ID_BCM57765		0x5c0d8a40
 #define TG3_PHY_ID_BCM5719C		0x5c0d8a20
 #define TG3_PHY_ID_BCM5720C		0x5c0d8b60
+#define TG3_PHY_ID_BCM5762		0x85803780
 #define TG3_PHY_ID_BCM5906		0xdc00ac40
 #define TG3_PHY_ID_BCM8002		0x60010140
 #define TG3_PHY_ID_INVALID		0xffffffff
@@ -3230,6 +3260,7 @@
 	 (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
 	 (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
 	 (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+	 (X) == TG3_PHY_ID_BCM5720C || (X) == TG3_PHY_ID_BCM5762 || \
 	 (X) == TG3_PHY_ID_BCM8002)
 
 	u32				phy_flags;
@@ -3320,10 +3351,22 @@
 	const struct firmware		*fw;
 	u32				fw_len; /* includes BSS */
 
-#if IS_ENABLED(CONFIG_HWMON)
 	struct device			*hwmon_dev;
-#endif
 	bool				link_up;
 };
 
+/* Accessor macros for chip and asic attributes
+ *
+ * nb: Using static inlines equivalent to the accessor macros generates
+ *     larger object code with gcc 4.7.
+ *     Using statement expression macros to check tp with
+ *     typecheck(struct tg3 *, tp) also creates larger objects.
+ */
+#define tg3_chip_rev_id(tp)					\
+	((tp)->pci_chip_rev_id)
+#define tg3_asic_rev(tp)					\
+	((tp)->pci_chip_rev_id >> 12)
+#define tg3_chip_rev(tp)					\
+	((tp)->pci_chip_rev_id >> 8)
+
 #endif /* !(_T3_H) */
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index a9b0830..7903943 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -287,7 +287,7 @@
 	}
 
 	/* attach the mac to the phy */
-	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
+	ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
 				 bp->phy_interface);
 	if (ret) {
 		netdev_err(dev, "Could not attach to PHY\n");
@@ -693,6 +693,11 @@
 		 * get notified when new packets arrive.
 		 */
 		macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+
+		/* Packets received while interrupts were disabled */
+		status = macb_readl(bp, RSR);
+		if (unlikely(status))
+			napi_reschedule(napi);
 	}
 
 	/* TODO: Handle errors */
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index f7f0290..a170065 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1463,7 +1463,6 @@
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 	xgmac_set_mac_addr(ioaddr, dev->dev_addr, 0);
diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
index c8fdeaa..20d2085 100644
--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -131,7 +131,7 @@
 static void link_report(struct port_info *p)
 {
 	if (!netif_carrier_ok(p->dev))
-		printk(KERN_INFO "%s: link down\n", p->dev->name);
+		netdev_info(p->dev, "link down\n");
 	else {
 		const char *s = "10Mbps";
 
@@ -141,9 +141,9 @@
 			case SPEED_100:   s = "100Mbps"; break;
 		}
 
-		printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
-		       p->dev->name, s,
-		       p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+		netdev_info(p->dev, "link up, %s, %s-duplex\n",
+			    s, p->link_config.duplex == DUPLEX_FULL
+			    ? "full" : "half");
 	}
 }
 
@@ -976,19 +976,13 @@
 
 static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int version_printed;
-
 	int i, err, pci_using_dac = 0;
 	unsigned long mmio_start, mmio_len;
 	const struct board_info *bi;
 	struct adapter *adapter = NULL;
 	struct port_info *pi;
 
-	if (!version_printed) {
-		printk(KERN_INFO "%s - version %s\n", DRV_DESCRIPTION,
-		       DRV_VERSION);
-		++version_printed;
-	}
+	pr_info_once("%s - version %s\n", DRV_DESCRIPTION, DRV_VERSION);
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -1124,8 +1118,8 @@
 	for (i = 0; i < bi->port_number; ++i) {
 		err = register_netdev(adapter->port[i].dev);
 		if (err)
-			pr_warning("%s: cannot register net device %s, skipping\n",
-				   pci_name(pdev), adapter->port[i].dev->name);
+			pr_warn("%s: cannot register net device %s, skipping\n",
+				pci_name(pdev), adapter->port[i].dev->name);
 		else {
 			/*
 			 * Change the name we use for messages to the name of
@@ -1143,10 +1137,10 @@
 		goto out_release_adapter_res;
 	}
 
-	printk(KERN_INFO "%s: %s (rev %d), %s %dMHz/%d-bit\n", adapter->name,
-	       bi->desc, adapter->params.chip_revision,
-	       adapter->params.pci.is_pcix ? "PCIX" : "PCI",
-	       adapter->params.pci.speed, adapter->params.pci.width);
+	pr_info("%s: %s (rev %d), %s %dMHz/%d-bit\n",
+		adapter->name, bi->desc, adapter->params.chip_revision,
+		adapter->params.pci.is_pcix ? "PCIX" : "PCI",
+		adapter->params.pci.speed, adapter->params.pci.width);
 
 	/*
 	 * Set the T1B ASIC and memory clocks.
diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c
index d84872e..4829769 100644
--- a/drivers/net/ethernet/chelsio/cxgb/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
@@ -1822,8 +1822,8 @@
 		 */
 		if (unlikely(skb->len < ETH_HLEN ||
 			     skb->len > dev->mtu + eth_hdr_len(skb->data))) {
-			pr_debug("%s: packet size %d hdr %d mtu%d\n", dev->name,
-				 skb->len, eth_hdr_len(skb->data), dev->mtu);
+			netdev_dbg(dev, "packet size %d hdr %d mtu%d\n",
+				   skb->len, eth_hdr_len(skb->data), dev->mtu);
 			dev_kfree_skb_any(skb);
 			return NETDEV_TX_OK;
 		}
@@ -1831,7 +1831,7 @@
 		if (skb->ip_summed == CHECKSUM_PARTIAL &&
 		    ip_hdr(skb)->protocol == IPPROTO_UDP) {
 			if (unlikely(skb_checksum_help(skb))) {
-				pr_debug("%s: unable to do udp checksum\n", dev->name);
+				netdev_dbg(dev, "unable to do udp checksum\n");
 				dev_kfree_skb_any(skb);
 				return NETDEV_TX_OK;
 			}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index f15ee32..2b5e621 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -29,6 +29,9 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -153,7 +156,7 @@
 static void link_report(struct net_device *dev)
 {
 	if (!netif_carrier_ok(dev))
-		printk(KERN_INFO "%s: link down\n", dev->name);
+		netdev_info(dev, "link down\n");
 	else {
 		const char *s = "10Mbps";
 		const struct port_info *p = netdev_priv(dev);
@@ -170,8 +173,9 @@
 			break;
 		}
 
-		printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
-		       p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+		netdev_info(dev, "link up, %s, %s-duplex\n",
+			    s, p->link_config.duplex == DUPLEX_FULL
+			    ? "full" : "half");
 	}
 }
 
@@ -318,10 +322,10 @@
 	const struct port_info *pi = netdev_priv(dev);
 
 	if (pi->phy.modtype == phy_modtype_none)
-		printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
+		netdev_info(dev, "PHY module unplugged\n");
 	else
-		printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
-		       mod_str[pi->phy.modtype]);
+		netdev_info(dev, "%s PHY module inserted\n",
+			    mod_str[pi->phy.modtype]);
 }
 
 static void cxgb_set_rxmode(struct net_device *dev)
@@ -1422,8 +1426,7 @@
 	if (is_offload(adapter) && !ofld_disable) {
 		err = offload_open(dev);
 		if (err)
-			printk(KERN_WARNING
-			       "Could not initialize offload capabilities\n");
+			pr_warn("Could not initialize offload capabilities\n");
 	}
 
 	netif_set_real_num_tx_queues(dev, pi->nqsets);
@@ -3132,14 +3135,13 @@
 
 		if (!test_bit(i, &adap->registered_device_map))
 			continue;
-		printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
-		       dev->name, ai->desc, pi->phy.desc,
-		       is_offload(adap) ? "R" : "", adap->params.rev, buf,
-		       (adap->flags & USING_MSIX) ? " MSI-X" :
-		       (adap->flags & USING_MSI) ? " MSI" : "");
+		netdev_info(dev, "%s %s %sNIC (rev %d) %s%s\n",
+			    ai->desc, pi->phy.desc,
+			    is_offload(adap) ? "R" : "", adap->params.rev, buf,
+			    (adap->flags & USING_MSIX) ? " MSI-X" :
+			    (adap->flags & USING_MSI) ? " MSI" : "");
 		if (adap->name == dev->name && adap->params.vpd.mclk)
-			printk(KERN_INFO
-			       "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
+			pr_info("%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
 			       adap->name, t3_mc7_size(&adap->cm) >> 20,
 			       t3_mc7_size(&adap->pmtx) >> 20,
 			       t3_mc7_size(&adap->pmrx) >> 20,
@@ -3177,24 +3179,18 @@
 			NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
 static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int version_printed;
-
 	int i, err, pci_using_dac = 0;
 	resource_size_t mmio_start, mmio_len;
 	const struct adapter_info *ai;
 	struct adapter *adapter = NULL;
 	struct port_info *pi;
 
-	if (!version_printed) {
-		printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
-		++version_printed;
-	}
+	pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION);
 
 	if (!cxgb3_wq) {
 		cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
 		if (!cxgb3_wq) {
-			printk(KERN_ERR DRV_NAME
-			       ": cannot initialize work queue\n");
+			pr_err("cannot initialize work queue\n");
 			return -ENOMEM;
 		}
 	}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 942dace..4232767 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -30,6 +30,8 @@
  * SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <net/neighbour.h>
@@ -62,9 +64,8 @@
 static const unsigned int ATID_BASE = 0x10000;
 
 static void cxgb_neigh_update(struct neighbour *neigh);
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
-			  struct dst_entry *new, struct neighbour *new_neigh,
-			  const void *daddr);
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+			  struct neighbour *neigh, const void *daddr);
 
 static inline int offload_activated(struct t3cdev *tdev)
 {
@@ -182,14 +183,17 @@
 		struct net_device *dev = adapter->port[i];
 
 		if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+			rcu_read_lock();
 			if (vlan && vlan != VLAN_VID_MASK) {
-				rcu_read_lock();
 				dev = __vlan_find_dev_deep(dev, vlan);
-				rcu_read_unlock();
 			} else if (netif_is_bond_slave(dev)) {
-				while (dev->master)
-					dev = dev->master;
+				struct net_device *upper_dev;
+
+				while ((upper_dev =
+					netdev_master_upper_dev_get_rcu(dev)))
+					dev = upper_dev;
 			}
+			rcu_read_unlock();
 			return dev;
 		}
 	}
@@ -232,8 +236,7 @@
 		if ((val >> S_MAXRXDATA) != 0x3f60) {
 			val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE);
 			val |= V_MAXRXDATA(0x3f60);
-			printk(KERN_INFO
-				"%s, iscsi set MaxRxData to 16224 (0x%x).\n",
+			pr_info("%s, iscsi set MaxRxData to 16224 (0x%x)\n",
 				adapter->name, val);
 			t3_write_reg(adapter, A_TP_PARA_REG2, val);
 		}
@@ -253,8 +256,7 @@
 		for (i = 0; i < 4; i++)
 			val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
 		if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) {
-			printk(KERN_INFO
-				"%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n",
+			pr_info("%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u\n",
 				adapter->name, val, uiip->pgsz_factor[0],
 				uiip->pgsz_factor[1], uiip->pgsz_factor[2],
 				uiip->pgsz_factor[3]);
@@ -706,8 +708,7 @@
 	struct cpl_smt_write_rpl *rpl = cplhdr(skb);
 
 	if (rpl->status != CPL_ERR_NONE)
-		printk(KERN_ERR
-		       "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+		pr_err("Unexpected SMT_WRITE_RPL status %u for entry %u\n",
 		       rpl->status, GET_TID(rpl));
 
 	return CPL_RET_BUF_DONE;
@@ -718,8 +719,7 @@
 	struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
 
 	if (rpl->status != CPL_ERR_NONE)
-		printk(KERN_ERR
-		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+		pr_err("Unexpected L2T_WRITE_RPL status %u for entry %u\n",
 		       rpl->status, GET_TID(rpl));
 
 	return CPL_RET_BUF_DONE;
@@ -730,8 +730,7 @@
 	struct cpl_rte_write_rpl *rpl = cplhdr(skb);
 
 	if (rpl->status != CPL_ERR_NONE)
-		printk(KERN_ERR
-		       "Unexpected RTE_WRITE_RPL status %u for entry %u\n",
+		pr_err("Unexpected RTE_WRITE_RPL status %u for entry %u\n",
 		       rpl->status, GET_TID(rpl));
 
 	return CPL_RET_BUF_DONE;
@@ -751,7 +750,7 @@
 								    t3c_tid->
 								    ctx);
 	} else {
-		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		pr_err("%s: received clientless CPL command 0x%x\n",
 		       dev->name, CPL_ACT_OPEN_RPL);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
@@ -769,7 +768,7 @@
 		return t3c_tid->client->handlers[p->opcode] (dev, skb,
 							     t3c_tid->ctx);
 	} else {
-		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		pr_err("%s: received clientless CPL command 0x%x\n",
 		       dev->name, p->opcode);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
@@ -787,7 +786,7 @@
 		return t3c_tid->client->handlers[p->opcode]
 		    (dev, skb, t3c_tid->ctx);
 	} else {
-		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		pr_err("%s: received clientless CPL command 0x%x\n",
 		       dev->name, p->opcode);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
@@ -814,7 +813,7 @@
 		return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
 		    (dev, skb, t3c_tid->ctx);
 	} else {
-		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		pr_err("%s: received clientless CPL command 0x%x\n",
 		       dev->name, CPL_PASS_ACCEPT_REQ);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
@@ -908,7 +907,7 @@
 		return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
 		    (dev, skb, t3c_tid->ctx);
 	} else {
-		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		pr_err("%s: received clientless CPL command 0x%x\n",
 		       dev->name, CPL_ACT_ESTABLISH);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
@@ -954,7 +953,7 @@
 		return t3c_tid->client->handlers[opcode] (dev, skb,
 							  t3c_tid->ctx);
 	} else {
-		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+		pr_err("%s: received clientless CPL command 0x%x\n",
 		       dev->name, opcode);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
@@ -970,10 +969,9 @@
 	}
 	case (NETEVENT_REDIRECT):{
 		struct netevent_redirect *nr = ctx;
-		cxgb_redirect(nr->old, nr->old_neigh,
-			      nr->new, nr->new_neigh,
+		cxgb_redirect(nr->old, nr->new, nr->neigh,
 			      nr->daddr);
-		cxgb_neigh_update(nr->new_neigh);
+		cxgb_neigh_update(nr->neigh);
 		break;
 	}
 	default:
@@ -991,8 +989,7 @@
  */
 static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
 {
-	printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
-	       *skb->data);
+	pr_err("%s: received bad CPL command 0x%x\n", dev->name, *skb->data);
 	return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 }
 
@@ -1010,8 +1007,8 @@
 	if (opcode < NUM_CPL_CMDS)
 		cpl_handlers[opcode] = h ? h : do_bad_cpl;
 	else
-		printk(KERN_ERR "T3C: handler registration for "
-		       "opcode %x failed\n", opcode);
+		pr_err("T3C: handler registration for opcode %x failed\n",
+		       opcode);
 }
 
 EXPORT_SYMBOL(t3_register_cpl_handler);
@@ -1030,9 +1027,8 @@
 		if (ret & CPL_RET_UNKNOWN_TID) {
 			union opcode_tid *p = cplhdr(skb);
 
-			printk(KERN_ERR "%s: CPL message (opcode %u) had "
-			       "unknown TID %u\n", dev->name, opcode,
-			       G_TID(ntohl(p->opcode_tid)));
+			pr_err("%s: CPL message (opcode %u) had unknown TID %u\n",
+			       dev->name, opcode, G_TID(ntohl(p->opcode_tid)));
 		}
 #endif
 		if (ret & CPL_RET_BUF_DONE)
@@ -1096,7 +1092,7 @@
 
 	skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_ERR "%s: cannot allocate skb!\n", __func__);
+		pr_err("%s: cannot allocate skb!\n", __func__);
 		return;
 	}
 	skb->priority = CPL_PRIORITY_CONTROL;
@@ -1111,11 +1107,11 @@
 	tdev->send(tdev, skb);
 }
 
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
-			  struct dst_entry *new, struct neighbour *new_neigh,
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+			  struct neighbour *neigh,
 			  const void *daddr)
 {
-	struct net_device *olddev, *newdev;
+	struct net_device *dev;
 	struct tid_info *ti;
 	struct t3cdev *tdev;
 	u32 tid;
@@ -1123,29 +1119,17 @@
 	struct l2t_entry *e;
 	struct t3c_tid_entry *te;
 
-	olddev = old_neigh->dev;
-	newdev = new_neigh->dev;
+	dev = neigh->dev;
 
-	if (!is_offloading(olddev))
+	if (!is_offloading(dev))
 		return;
-	if (!is_offloading(newdev)) {
-		printk(KERN_WARNING "%s: Redirect to non-offload "
-		       "device ignored.\n", __func__);
-		return;
-	}
-	tdev = dev2t3cdev(olddev);
+	tdev = dev2t3cdev(dev);
 	BUG_ON(!tdev);
-	if (tdev != dev2t3cdev(newdev)) {
-		printk(KERN_WARNING "%s: Redirect to different "
-		       "offload device ignored.\n", __func__);
-		return;
-	}
 
 	/* Add new L2T entry */
-	e = t3_l2t_get(tdev, new, newdev, daddr);
+	e = t3_l2t_get(tdev, new, dev, daddr);
 	if (!e) {
-		printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
-		       __func__);
+		pr_err("%s: couldn't allocate new l2t entry!\n", __func__);
 		return;
 	}
 
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index dd901c5..9d67eb7 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -1278,7 +1278,7 @@
 	}
 
 	/* update port statistics */
-	if (skb->ip_summed == CHECKSUM_COMPLETE)
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
 		qs->port_stats[SGE_PSTAT_TX_CSUM]++;
 	if (skb_shinfo(skb)->gso_size)
 		qs->port_stats[SGE_PSTAT_TSO]++;
@@ -2130,8 +2130,10 @@
 
 	skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]);
 
-	if (cpl->vlan_valid)
+	if (cpl->vlan_valid) {
+		qs->port_stats[SGE_PSTAT_VLANEX]++;
 		__vlan_hwaccel_put_tag(skb, ntohs(cpl->vlan));
+	}
 	napi_gro_frags(&qs->napi);
 }
 
diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
index 3dee686..c74a898 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
@@ -3725,8 +3725,6 @@
 
 		memcpy(adapter->port[i]->dev_addr, hw_addr,
 		       ETH_ALEN);
-		memcpy(adapter->port[i]->perm_addr, hw_addr,
-		       ETH_ALEN);
 		init_link_config(&p->link_config, p->phy.caps);
 		p->phy.ops->power_down(&p->phy, 1);
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index c306df7..c6c05bf 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -4027,8 +4027,7 @@
 						  VFRES_NEQ, VFRES_NETHCTRL,
 						  VFRES_NIQFLINT, VFRES_NIQ,
 						  VFRES_TC, VFRES_NVI,
-						  FW_PFVF_CMD_CMASK_GET(
-						  FW_PFVF_CMD_CMASK_MASK),
+						  FW_PFVF_CMD_CMASK_MASK,
 						  pfvfres_pmask(
 						  adapter, pf, vf),
 						  VFRES_NEXACTF,
@@ -5142,7 +5141,7 @@
 	/* Debugfs support is optional, just warn if this fails */
 	cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
 	if (!cxgb4_debugfs_root)
-		pr_warning("could not create debugfs entry, continuing\n");
+		pr_warn("could not create debugfs entry, continuing\n");
 
 	ret = pci_register_driver(&cxgb4_driver);
 	if (ret < 0)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 22f3af5..4ce6203 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -3603,7 +3603,6 @@
 		p->lport = j;
 		p->rss_size = rss_size;
 		memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
-		memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN);
 		adap->port[i]->dev_id = j;
 
 		ret = ntohl(c.u.info.lstatus_to_modtype);
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
index 611396c..68eaa9c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
@@ -466,7 +466,6 @@
 				     u8 hw_addr[])
 {
 	memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN);
-	memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN);
 }
 
 /**
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 0188df7..56b46ab 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -33,6 +33,8 @@
  * SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -196,11 +198,10 @@
 			break;
 		}
 
-		printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n",
-		       dev->name, s, fc);
+		netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, fc);
 	} else {
 		netif_carrier_off(dev);
-		printk(KERN_INFO "%s: link down\n", dev->name);
+		netdev_info(dev, "link down\n");
 	}
 }
 
@@ -2465,8 +2466,6 @@
 static int cxgb4vf_pci_probe(struct pci_dev *pdev,
 			     const struct pci_device_id *ent)
 {
-	static int version_printed;
-
 	int pci_using_dac;
 	int err, pidx;
 	unsigned int pmask;
@@ -2478,10 +2477,7 @@
 	 * Print our driver banner the first time we're called to initialize a
 	 * device.
 	 */
-	if (version_printed == 0) {
-		printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
-		version_printed = 1;
-	}
+	pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION);
 
 	/*
 	 * Initialize generic PCI device state.
@@ -2920,18 +2916,15 @@
 	 * Vet our module parameters.
 	 */
 	if (msi != MSI_MSIX && msi != MSI_MSI) {
-		printk(KERN_WARNING KBUILD_MODNAME
-		       ": bad module parameter msi=%d; must be %d"
-		       " (MSI-X or MSI) or %d (MSI)\n",
-		       msi, MSI_MSIX, MSI_MSI);
+		pr_warn("bad module parameter msi=%d; must be %d (MSI-X or MSI) or %d (MSI)\n",
+			msi, MSI_MSIX, MSI_MSI);
 		return -EINVAL;
 	}
 
 	/* Debugfs support is optional, just warn if this fails */
 	cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
 	if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
-		printk(KERN_WARNING KBUILD_MODNAME ": could not create"
-		       " debugfs entry, continuing\n");
+		pr_warn("could not create debugfs entry, continuing\n");
 
 	ret = pci_register_driver(&cxgb4vf_driver);
 	if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 92170d5..9488032 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -1477,8 +1477,10 @@
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 	skb_record_rx_queue(skb, rxq->rspq.idx);
 
-	if (pkt->vlan_ex)
+	if (pkt->vlan_ex) {
 		__vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan));
+		rxq->stats.vlan_ex++;
+	}
 	ret = napi_gro_frags(&rxq->rspq.napi);
 
 	if (ret == GRO_HELD)
@@ -1501,7 +1503,7 @@
 		       const struct pkt_gl *gl)
 {
 	struct sk_buff *skb;
-	const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
+	const struct cpl_rx_pkt *pkt = (void *)rsp;
 	bool csum_ok = pkt->csum_calc && !pkt->err_vec;
 	struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
 
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 78c5521..354cbb7 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -710,8 +710,8 @@
 
 static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_MODULE_NAME);
-	strcpy(info->version, DRV_MODULE_VERSION);
+	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 64866ff..ec1a233 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -865,7 +865,6 @@
 	}
 
 	memcpy(netdev->dev_addr, addr, netdev->addr_len);
-	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	return 0;
 }
@@ -1491,7 +1490,8 @@
 
 		for (i = 0; i < enic->rq_count; i++) {
 			intr = enic_msix_rq_intr(enic, i);
-			sprintf(enic->msix[intr].devname,
+			snprintf(enic->msix[intr].devname,
+				sizeof(enic->msix[intr].devname),
 				"%.11s-rx-%d", netdev->name, i);
 			enic->msix[intr].isr = enic_isr_msix_rq;
 			enic->msix[intr].devid = &enic->napi[i];
@@ -1499,20 +1499,23 @@
 
 		for (i = 0; i < enic->wq_count; i++) {
 			intr = enic_msix_wq_intr(enic, i);
-			sprintf(enic->msix[intr].devname,
+			snprintf(enic->msix[intr].devname,
+				sizeof(enic->msix[intr].devname),
 				"%.11s-tx-%d", netdev->name, i);
 			enic->msix[intr].isr = enic_isr_msix_wq;
 			enic->msix[intr].devid = enic;
 		}
 
 		intr = enic_msix_err_intr(enic);
-		sprintf(enic->msix[intr].devname,
+		snprintf(enic->msix[intr].devname,
+			sizeof(enic->msix[intr].devname),
 			"%.11s-err", netdev->name);
 		enic->msix[intr].isr = enic_isr_msix_err;
 		enic->msix[intr].devid = enic;
 
 		intr = enic_msix_notify_intr(enic);
-		sprintf(enic->msix[intr].devname,
+		snprintf(enic->msix[intr].devname,
+			sizeof(enic->msix[intr].devname),
 			"%.11s-notify", netdev->name);
 		enic->msix[intr].isr = enic_isr_msix_notify;
 		enic->msix[intr].devid = enic;
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index c73472c..8cdf025 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -434,9 +434,10 @@
 {
 	board_info_t *dm = to_dm9000_board(dev);
 
-	strcpy(info->driver, CARDNAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, to_platform_device(dm->dev)->name);
+	strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, to_platform_device(dm->dev)->name,
+		sizeof(info->bus_info));
 }
 
 static u32 dm9000_get_msglevel(struct net_device *dev)
diff --git a/drivers/net/ethernet/dec/Kconfig b/drivers/net/ethernet/dec/Kconfig
index 3794027..68262aa 100644
--- a/drivers/net/ethernet/dec/Kconfig
+++ b/drivers/net/ethernet/dec/Kconfig
@@ -17,21 +17,5 @@
 	  your specific card in the following questions.
 
 if NET_VENDOR_DEC
-
-config EWRK3
-	tristate "EtherWORKS 3 (DE203, DE204, DE205) support"
-	depends on ISA
-	select CRC32
-	---help---
-	  This driver supports the DE203, DE204 and DE205 network (Ethernet)
-	  cards. If this is for you, say Y and read
-	  <file:Documentation/networking/ewrk3.txt> in the kernel source as
-	  well as the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called ewrk3.
-
 source "drivers/net/ethernet/dec/tulip/Kconfig"
-
 endif # NET_VENDOR_DEC
diff --git a/drivers/net/ethernet/dec/Makefile b/drivers/net/ethernet/dec/Makefile
index 1b01ed8..32993fc 100644
--- a/drivers/net/ethernet/dec/Makefile
+++ b/drivers/net/ethernet/dec/Makefile
@@ -2,5 +2,4 @@
 # Makefile for the Digital Equipment Inc. network device drivers.
 #
 
-obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_NET_TULIP) += tulip/
diff --git a/drivers/net/ethernet/dec/ewrk3.c b/drivers/net/ethernet/dec/ewrk3.c
deleted file mode 100644
index 9f992b9..0000000
--- a/drivers/net/ethernet/dec/ewrk3.c
+++ /dev/null
@@ -1,1961 +0,0 @@
-/*  ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for Linux.
-
-   Written 1994 by David C. Davies.
-
-   Copyright 1994 Digital Equipment Corporation.
-
-   This software may be used and distributed according to the terms of
-   the GNU General Public License, incorporated herein by reference.
-
-   This driver is written for the Digital Equipment Corporation series
-   of EtherWORKS ethernet cards:
-
-   DE203 Turbo (BNC)
-   DE204 Turbo (TP)
-   DE205 Turbo (TP BNC)
-
-   The driver has been tested on a relatively busy  network using the DE205
-   card and benchmarked with 'ttcp': it transferred 16M  of data at 975kB/s
-   (7.8Mb/s) to a DECstation 5000/200.
-
-   The author may be reached at davies@maniac.ultranet.com.
-
-   =========================================================================
-   This driver has been written  substantially  from scratch, although  its
-   inheritance of style and stack interface from 'depca.c' and in turn from
-   Donald Becker's 'lance.c' should be obvious.
-
-   The  DE203/4/5 boards  all  use a new proprietary   chip in place of the
-   LANCE chip used in prior cards  (DEPCA, DE100, DE200/1/2, DE210, DE422).
-   Use the depca.c driver in the standard distribution  for the LANCE based
-   cards from DIGITAL; this driver will not work with them.
-
-   The DE203/4/5 cards have 2  main modes: shared memory  and I/O only. I/O
-   only makes  all the card accesses through  I/O transactions and  no high
-   (shared)  memory is used. This  mode provides a >48% performance penalty
-   and  is deprecated in this  driver,  although allowed to provide initial
-   setup when hardstrapped.
-
-   The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is
-   no point in using any mode other than the 2kB  mode - their performances
-   are virtually identical, although the driver has  been tested in the 2kB
-   and 32kB modes. I would suggest you uncomment the line:
-
-   FORCE_2K_MODE;
-
-   to allow the driver to configure the card as a  2kB card at your current
-   base  address, thus leaving more  room to clutter  your  system box with
-   other memory hungry boards.
-
-   As many ISA  and EISA cards  can be supported  under this driver  as you
-   wish, limited primarily  by the available IRQ lines,  rather than by the
-   available I/O addresses  (24 ISA,  16 EISA).   I have  checked different
-   configurations of  multiple  depca cards and  ewrk3 cards  and have  not
-   found a problem yet (provided you have at least depca.c v0.38) ...
-
-   The board IRQ setting   must be at  an unused  IRQ which is  auto-probed
-   using  Donald  Becker's autoprobe  routines.   All  these cards   are at
-   {5,10,11,15}.
-
-   No 16MB memory  limitation should exist with this  driver as DMA is  not
-   used and the common memory area is in low memory on the network card (my
-   current system has 20MB and I've not had problems yet).
-
-   The ability to load  this driver as a  loadable module has been included
-   and used  extensively during the  driver development (to save those long
-   reboot sequences). To utilise this ability, you have to do 8 things:
-
-   0) have a copy of the loadable modules code installed on your system.
-   1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
-   temporary directory.
-   2) edit the  source code near  line 1898 to reflect  the I/O address and
-   IRQ you're using.
-   3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
-   that the correct bits are compiled (see end of source code).
-   4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
-   kernel with the ewrk3 configuration turned off and reboot.
-   5) insmod ewrk3.o
-   [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
-   [Adam Kropelin: now accepts irq=x1,x2 io=y1,y2 for multiple cards]
-   6) run the net startup bits for your new eth?? interface manually
-   (usually /etc/rc.inet[12] at boot time).
-   7) enjoy!
-
-   Note that autoprobing is not allowed in loadable modules - the system is
-   already up and running and you're messing with interrupts.
-
-   To unload a module, turn off the associated interface
-   'ifconfig eth?? down' then 'rmmod ewrk3'.
-
-   Promiscuous   mode has been  turned  off  in this driver,   but  all the
-   multicast  address bits  have been   turned on. This  improved the  send
-   performance on a busy network by about 13%.
-
-   Ioctl's have now been provided (primarily because  I wanted to grab some
-   packet size statistics). They  are patterned after 'plipconfig.c' from a
-   suggestion by Alan Cox.  Using these  ioctls, you can enable promiscuous
-   mode, add/delete multicast  addresses, change the hardware address,  get
-   packet size distribution statistics and muck around with the control and
-   status register. I'll add others if and when the need arises.
-
-   TO DO:
-   ------
-
-
-   Revision History
-   ----------------
-
-   Version   Date        Description
-
-   0.1     26-aug-94   Initial writing. ALPHA code release.
-   0.11    31-aug-94   Fixed: 2k mode memory base calc.,
-   LeMAC version calc.,
-   IRQ vector assignments during autoprobe.
-   0.12    31-aug-94   Tested working on LeMAC2 (DE20[345]-AC) card.
-   Fixed up MCA hash table algorithm.
-   0.20     4-sep-94   Added IOCTL functionality.
-   0.21    14-sep-94   Added I/O mode.
-   0.21axp 15-sep-94   Special version for ALPHA AXP Linux V1.0.
-   0.22    16-sep-94   Added more IOCTLs & tidied up.
-   0.23    21-sep-94   Added transmit cut through.
-   0.24    31-oct-94   Added uid checks in some ioctls.
-   0.30     1-nov-94   BETA code release.
-   0.31     5-dec-94   Added check/allocate region code.
-   0.32    16-jan-95   Broadcast packet fix.
-   0.33    10-Feb-95   Fix recognition bug reported by <bkm@star.rl.ac.uk>.
-   0.40    27-Dec-95   Rationalise MODULE and autoprobe code.
-   Rewrite for portability & updated.
-   ALPHA support from <jestabro@amt.tay1.dec.com>
-   Added verify_area() calls in ewrk3_ioctl() from
-   suggestion by <heiko@colossus.escape.de>.
-   Add new multicasting code.
-   0.41    20-Jan-96   Fix IRQ set up problem reported by
-   <kenneth@bbs.sas.ntu.ac.sg>.
-   0.42    22-Apr-96   Fix alloc_device() bug <jari@markkus2.fimr.fi>
-   0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
-   0.44    08-Nov-01   use library crc32 functions <Matt_Domsch@dell.com>
-   0.45    19-Jul-02   fix unaligned access on alpha <martin@bruli.net>
-   0.46    10-Oct-02   Multiple NIC support when module <akropel1@rochester.rr.com>
-   0.47    18-Oct-02   ethtool support <akropel1@rochester.rr.com>
-   0.48    18-Oct-02   cli/sti removal for 2.5 <vda@port.imtp.ilyichevsk.odessa.ua>
-   ioctl locking, signature search cleanup <akropel1@rochester.rr.com>
-
-   =========================================================================
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "ewrk3.h"
-
-#define DRV_NAME	"ewrk3"
-#define DRV_VERSION	"0.48"
-
-static char version[] __initdata =
-DRV_NAME ":v" DRV_VERSION " 2002/10/18 davies@maniac.ultranet.com\n";
-
-#ifdef EWRK3_DEBUG
-static int ewrk3_debug = EWRK3_DEBUG;
-#else
-static int ewrk3_debug = 1;
-#endif
-
-#define EWRK3_NDA 0xffe0	/* No Device Address */
-
-#define PROBE_LENGTH    32
-#define ETH_PROM_SIG    0xAA5500FFUL
-
-#ifndef EWRK3_SIGNATURE
-#define EWRK3_SIGNATURE {"DE203","DE204","DE205",""}
-#define EWRK3_STRLEN 8
-#endif
-
-#ifndef EWRK3_RAM_BASE_ADDRESSES
-#define EWRK3_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0x00000}
-#endif
-
-/*
-   ** Sets up the I/O area for the autoprobe.
- */
-#define EWRK3_IO_BASE 0x100	/* Start address for probe search */
-#define EWRK3_IOP_INC 0x20	/* I/O address increment */
-#define EWRK3_TOTAL_SIZE 0x20	/* required I/O address length */
-
-#ifndef MAX_NUM_EWRK3S
-#define MAX_NUM_EWRK3S 21
-#endif
-
-#ifndef EWRK3_EISA_IO_PORTS
-#define EWRK3_EISA_IO_PORTS 0x0c00	/* I/O port base address, slot 0 */
-#endif
-
-#ifndef MAX_EISA_SLOTS
-#define MAX_EISA_SLOTS 16
-#define EISA_SLOT_INC 0x1000
-#endif
-
-#define QUEUE_PKT_TIMEOUT (1*HZ)	/* Jiffies */
-
-/*
-   ** EtherWORKS 3 shared memory window sizes
- */
-#define IO_ONLY         0x00
-#define SHMEM_2K        0x800
-#define SHMEM_32K       0x8000
-#define SHMEM_64K       0x10000
-
-/*
-   ** EtherWORKS 3 IRQ ENABLE/DISABLE
- */
-#define ENABLE_IRQs { \
-  icr |= lp->irq_mask;\
-  outb(icr, EWRK3_ICR);                     /* Enable the IRQs */\
-}
-
-#define DISABLE_IRQs { \
-  icr = inb(EWRK3_ICR);\
-  icr &= ~lp->irq_mask;\
-  outb(icr, EWRK3_ICR);                     /* Disable the IRQs */\
-}
-
-/*
-   ** EtherWORKS 3 START/STOP
- */
-#define START_EWRK3 { \
-  csr = inb(EWRK3_CSR);\
-  csr &= ~(CSR_TXD|CSR_RXD);\
-  outb(csr, EWRK3_CSR);                     /* Enable the TX and/or RX */\
-}
-
-#define STOP_EWRK3 { \
-  csr = (CSR_TXD|CSR_RXD);\
-  outb(csr, EWRK3_CSR);                     /* Disable the TX and/or RX */\
-}
-
-/*
-   ** The EtherWORKS 3 private structure
- */
-#define EWRK3_PKT_STAT_SZ 16
-#define EWRK3_PKT_BIN_SZ  128	/* Should be >=100 unless you
-				   increase EWRK3_PKT_STAT_SZ */
-
-struct ewrk3_stats {
-	u32 bins[EWRK3_PKT_STAT_SZ];
-	u32 unicast;
-	u32 multicast;
-	u32 broadcast;
-	u32 excessive_collisions;
-	u32 tx_underruns;
-	u32 excessive_underruns;
-};
-
-struct ewrk3_private {
-	char adapter_name[80];	/* Name exported to /proc/ioports */
-	u_long shmem_base;	/* Shared memory start address */
-	void __iomem *shmem;
-	u_long shmem_length;	/* Shared memory window length */
-	struct ewrk3_stats pktStats; /* Private stats counters */
-	u_char irq_mask;	/* Adapter IRQ mask bits */
-	u_char mPage;		/* Maximum 2kB Page number */
-	u_char lemac;		/* Chip rev. level */
-	u_char hard_strapped;	/* Don't allow a full open */
-	u_char txc;		/* Transmit cut through */
-	void __iomem *mctbl;	/* Pointer to the multicast table */
-	u_char led_mask;	/* Used to reserve LED access for ethtool */
-	spinlock_t hw_lock;
-};
-
-/*
-   ** Force the EtherWORKS 3 card to be in 2kB MODE
- */
-#define FORCE_2K_MODE { \
-  shmem_length = SHMEM_2K;\
-  outb(((mem_start - 0x80000) >> 11), EWRK3_MBR);\
-}
-
-/*
-   ** Public Functions
- */
-static int ewrk3_open(struct net_device *dev);
-static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
-static int ewrk3_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops ethtool_ops_203;
-static const struct ethtool_ops ethtool_ops;
-
-/*
-   ** Private functions
- */
-static int ewrk3_hw_init(struct net_device *dev, u_long iobase);
-static void ewrk3_init(struct net_device *dev);
-static int ewrk3_rx(struct net_device *dev);
-static int ewrk3_tx(struct net_device *dev);
-static void ewrk3_timeout(struct net_device *dev);
-
-static void EthwrkSignature(char *name, char *eeprom_image);
-static int DevicePresent(u_long iobase);
-static void SetMulticastFilter(struct net_device *dev);
-static int EISA_signature(char *name, s32 eisa_id);
-
-static int Read_EEPROM(u_long iobase, u_char eaddr);
-static int Write_EEPROM(short data, u_long iobase, u_char eaddr);
-static u_char get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType);
-
-static int ewrk3_probe1(struct net_device *dev, u_long iobase, int irq);
-static int isa_probe(struct net_device *dev, u_long iobase);
-static int eisa_probe(struct net_device *dev, u_long iobase);
-
-static u_char irq[MAX_NUM_EWRK3S+1] = {5, 0, 10, 3, 11, 9, 15, 12};
-
-static char name[EWRK3_STRLEN + 1];
-static int num_ewrks3s;
-
-/*
-   ** Miscellaneous defines...
- */
-#define INIT_EWRK3 {\
-    outb(EEPROM_INIT, EWRK3_IOPR);\
-    mdelay(1);\
-}
-
-#ifndef MODULE
-struct net_device * __init ewrk3_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private));
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-	}
-
-	err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-
-}
-#endif
-
-static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq)
-{
-	int err;
-
-	dev->base_addr = iobase;
-	dev->irq = irq;
-
-	/* Address PROM pattern */
-	err = isa_probe(dev, iobase);
-	if (err != 0)
-		err = eisa_probe(dev, iobase);
-
-	if (err)
-		return err;
-
-	err = register_netdev(dev);
-	if (err)
-		release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
-
-	return err;
-}
-
-static const struct net_device_ops ewrk3_netdev_ops = {
-	.ndo_open		= ewrk3_open,
-	.ndo_start_xmit		= ewrk3_queue_pkt,
-	.ndo_stop		= ewrk3_close,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_do_ioctl		= ewrk3_ioctl,
-	.ndo_tx_timeout		= ewrk3_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init
-ewrk3_hw_init(struct net_device *dev, u_long iobase)
-{
-	struct ewrk3_private *lp;
-	int i, status = 0;
-	u_long mem_start, shmem_length;
-	u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
-	u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
-
-	/*
-	** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
-	** This also disables the EISA_ENABLE bit in the EISA Control Register.
-	 */
-	if (iobase > 0x400)
-		eisa_cr = inb(EISA_CR);
-	INIT_EWRK3;
-
-	nicsr = inb(EWRK3_CSR);
-
-	icr = inb(EWRK3_ICR);
-	icr &= 0x70;
-	outb(icr, EWRK3_ICR);	/* Disable all the IRQs */
-
-	if (nicsr != (CSR_TXD | CSR_RXD))
-		return -ENXIO;
-
-	/* Check that the EEPROM is alive and well and not living on Pluto... */
-	for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) {
-		union {
-			short val;
-			char c[2];
-		} tmp;
-
-		tmp.val = (short) Read_EEPROM(iobase, (i >> 1));
-		eeprom_image[i] = tmp.c[0];
-		eeprom_image[i + 1] = tmp.c[1];
-		chksum += eeprom_image[i] + eeprom_image[i + 1];
-	}
-
-	if (chksum != 0) {	/* Bad EEPROM Data! */
-		printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
-		return -ENXIO;
-	}
-
-	EthwrkSignature(name, eeprom_image);
-	if (*name == '\0')
-		return -ENXIO;
-
-	dev->base_addr = iobase;
-
-	if (iobase > 0x400) {
-		outb(eisa_cr, EISA_CR);		/* Rewrite the EISA CR */
-	}
-	lemac = eeprom_image[EEPROM_CHIPVER];
-	cmr = inb(EWRK3_CMR);
-
-	if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) ||
-	    ((lemac == LeMAC2) && !(cmr & CMR_HS))) {
-		printk("%s: %s at %#4lx", dev->name, name, iobase);
-		hard_strapped = 1;
-	} else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) {
-		/* EISA slot address */
-		printk("%s: %s at %#4lx (EISA slot %ld)",
-		       dev->name, name, iobase, ((iobase >> 12) & 0x0f));
-	} else {	/* ISA port address */
-		printk("%s: %s at %#4lx", dev->name, name, iobase);
-	}
-
-	printk(", h/w address ");
-	if (lemac != LeMAC2)
-		DevicePresent(iobase);	/* need after EWRK3_INIT */
-	status = get_hw_addr(dev, eeprom_image, lemac);
-	printk("%pM\n", dev->dev_addr);
-
-	if (status) {
-		printk("      which has an EEPROM CRC error.\n");
-		return -ENXIO;
-	}
-
-	if (lemac == LeMAC2) {	/* Special LeMAC2 CMR things */
-		cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS);
-		if (eeprom_image[EEPROM_MISC0] & READ_AHEAD)
-			cmr |= CMR_RA;
-		if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND)
-			cmr |= CMR_WB;
-		if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL)
-			cmr |= CMR_POLARITY;
-		if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK)
-			cmr |= CMR_LINK;
-		if (eeprom_image[EEPROM_MISC0] & _0WS_ENA)
-			cmr |= CMR_0WS;
-	}
-	if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)
-		cmr |= CMR_DRAM;
-	outb(cmr, EWRK3_CMR);
-
-	cr = inb(EWRK3_CR);	/* Set up the Control Register */
-	cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
-	if (cr & SETUP_APD)
-		cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS;
-	cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS;
-	cr |= eeprom_image[EEPROM_MISC0] & ENA_16;
-	outb(cr, EWRK3_CR);
-
-	/*
-	** Determine the base address and window length for the EWRK3
-	** RAM from the memory base register.
-	*/
-	mem_start = inb(EWRK3_MBR);
-	shmem_length = 0;
-	if (mem_start != 0) {
-		if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {
-			mem_start *= SHMEM_64K;
-			shmem_length = SHMEM_64K;
-		} else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {
-			mem_start *= SHMEM_32K;
-			shmem_length = SHMEM_32K;
-		} else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {
-			mem_start = mem_start * SHMEM_2K + 0x80000;
-			shmem_length = SHMEM_2K;
-		} else {
-			return -ENXIO;
-		}
-	}
-	/*
-	** See the top of this source code for comments about
-	** uncommenting this line.
-	*/
-/*          FORCE_2K_MODE; */
-
-	if (hard_strapped) {
-		printk("      is hard strapped.\n");
-	} else if (mem_start) {
-		printk("      has a %dk RAM window", (int) (shmem_length >> 10));
-		printk(" at 0x%.5lx", mem_start);
-	} else {
-		printk("      is in I/O only mode");
-	}
-
-	lp = netdev_priv(dev);
-	lp->shmem_base = mem_start;
-	lp->shmem = ioremap(mem_start, shmem_length);
-	if (!lp->shmem)
-		return -ENOMEM;
-	lp->shmem_length = shmem_length;
-	lp->lemac = lemac;
-	lp->hard_strapped = hard_strapped;
-	lp->led_mask = CR_LED;
-	spin_lock_init(&lp->hw_lock);
-
-	lp->mPage = 64;
-	if (cmr & CMR_DRAM)
-		lp->mPage <<= 1;	/* 2 DRAMS on module */
-
-	sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
-
-	lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM;
-
-	if (!hard_strapped) {
-		/*
-		** Enable EWRK3 board interrupts for autoprobing
-		*/
-		icr |= ICR_IE;	/* Enable interrupts */
-		outb(icr, EWRK3_ICR);
-
-		/* The DMA channel may be passed in on this parameter. */
-		dev->dma = 0;
-
-		/* To auto-IRQ we enable the initialization-done and DMA err,
-		   interrupts. For now we will always get a DMA error. */
-		if (dev->irq < 2) {
-#ifndef MODULE
-			u_char irqnum;
-			unsigned long irq_mask;
-
-
-			irq_mask = probe_irq_on();
-
-			/*
-			** Trigger a TNE interrupt.
-			*/
-			icr |= ICR_TNEM;
-			outb(1, EWRK3_TDQ);	/* Write to the TX done queue */
-			outb(icr, EWRK3_ICR);	/* Unmask the TXD interrupt */
-
-			irqnum = irq[((icr & IRQ_SEL) >> 4)];
-
-			mdelay(20);
-			dev->irq = probe_irq_off(irq_mask);
-			if ((dev->irq) && (irqnum == dev->irq)) {
-				printk(" and uses IRQ%d.\n", dev->irq);
-			} else {
-				if (!dev->irq) {
-					printk(" and failed to detect IRQ line.\n");
-				} else if ((irqnum == 1) && (lemac == LeMAC2)) {
-					printk(" and an illegal IRQ line detected.\n");
-				} else {
-					printk(", but incorrect IRQ line detected.\n");
-				}
-				iounmap(lp->shmem);
-				return -ENXIO;
-			}
-
-			DISABLE_IRQs;	/* Mask all interrupts */
-
-#endif				/* MODULE */
-		} else {
-			printk(" and requires IRQ%d.\n", dev->irq);
-		}
-	}
-
-	if (ewrk3_debug > 1) {
-		printk(version);
-	}
-	/* The EWRK3-specific entries in the device structure. */
-	dev->netdev_ops = &ewrk3_netdev_ops;
-	if (lp->adapter_name[4] == '3')
-		SET_ETHTOOL_OPS(dev, &ethtool_ops_203);
-	else
-		SET_ETHTOOL_OPS(dev, &ethtool_ops);
-	dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
-
-	dev->mem_start = 0;
-
-	return 0;
-}
-
-
-static int ewrk3_open(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_long iobase = dev->base_addr;
-	int status = 0;
-	u_char icr, csr;
-
-	/*
-	   ** Stop the TX and RX...
-	 */
-	STOP_EWRK3;
-
-	if (!lp->hard_strapped) {
-		if (request_irq(dev->irq, (void *) ewrk3_interrupt, 0, "ewrk3", dev)) {
-			printk("ewrk3_open(): Requested IRQ%d is busy\n", dev->irq);
-			status = -EAGAIN;
-		} else {
-
-			/*
-			   ** Re-initialize the EWRK3...
-			 */
-			ewrk3_init(dev);
-
-			if (ewrk3_debug > 1) {
-				printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
-				printk("  physical address: %pM\n", dev->dev_addr);
-				if (lp->shmem_length == 0) {
-					printk("  no shared memory, I/O only mode\n");
-				} else {
-					printk("  start of shared memory: 0x%08lx\n", lp->shmem_base);
-					printk("  window length: 0x%04lx\n", lp->shmem_length);
-				}
-				printk("  # of DRAMS: %d\n", ((inb(EWRK3_CMR) & 0x02) ? 2 : 1));
-				printk("  csr:  0x%02x\n", inb(EWRK3_CSR));
-				printk("  cr:   0x%02x\n", inb(EWRK3_CR));
-				printk("  icr:  0x%02x\n", inb(EWRK3_ICR));
-				printk("  cmr:  0x%02x\n", inb(EWRK3_CMR));
-				printk("  fmqc: 0x%02x\n", inb(EWRK3_FMQC));
-			}
-			netif_start_queue(dev);
-			/*
-			   ** Unmask EWRK3 board interrupts
-			 */
-			icr = inb(EWRK3_ICR);
-			ENABLE_IRQs;
-
-		}
-	} else {
-		printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name);
-		printk(KERN_ERR "      Run the 'ewrk3setup' utility or remove the hard straps.\n");
-		return -EINVAL;
-	}
-
-	return status;
-}
-
-/*
-   ** Initialize the EtherWORKS 3 operating conditions
- */
-static void ewrk3_init(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_char csr, page;
-	u_long iobase = dev->base_addr;
-	int i;
-
-	/*
-	   ** Enable any multicasts
-	 */
-	set_multicast_list(dev);
-
-	/*
-	** Set hardware MAC address. Address is initialized from the EEPROM
-	** during startup but may have since been changed by the user.
-	*/
-	for (i=0; i<ETH_ALEN; i++)
-		outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-
-	/*
-	   ** Clean out any remaining entries in all the queues here
-	 */
-	while (inb(EWRK3_TQ));
-	while (inb(EWRK3_TDQ));
-	while (inb(EWRK3_RQ));
-	while (inb(EWRK3_FMQ));
-
-	/*
-	   ** Write a clean free memory queue
-	 */
-	for (page = 1; page < lp->mPage; page++) {	/* Write the free page numbers */
-		outb(page, EWRK3_FMQ);	/* to the Free Memory Queue */
-	}
-
-	START_EWRK3;		/* Enable the TX and/or RX */
-}
-
-/*
- *  Transmit timeout
- */
-
-static void ewrk3_timeout(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_char icr, csr;
-	u_long iobase = dev->base_addr;
-
-	if (!lp->hard_strapped)
-	{
-		printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
-		       dev->name, inb(EWRK3_CSR));
-
-		/*
-		   ** Mask all board interrupts
-		 */
-		DISABLE_IRQs;
-
-		/*
-		   ** Stop the TX and RX...
-		 */
-		STOP_EWRK3;
-
-		ewrk3_init(dev);
-
-		/*
-		   ** Unmask EWRK3 board interrupts
-		 */
-		ENABLE_IRQs;
-
-		dev->trans_start = jiffies; /* prevent tx timeout */
-		netif_wake_queue(dev);
-	}
-}
-
-/*
-   ** Writes a socket buffer to the free page queue
- */
-static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_long iobase = dev->base_addr;
-	void __iomem *buf = NULL;
-	u_char icr;
-	u_char page;
-
-	spin_lock_irq (&lp->hw_lock);
-	DISABLE_IRQs;
-
-	/* if no resources available, exit, request packet be queued */
-	if (inb (EWRK3_FMQC) == 0) {
-		printk (KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n",
-			dev->name);
-		printk (KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",
-			dev->name, inb (EWRK3_CSR), inb (EWRK3_ICR),
-			inb (EWRK3_FMQC));
-		goto err_out;
-	}
-
-	/*
-	 ** Get a free page from the FMQ
-	 */
-	if ((page = inb (EWRK3_FMQ)) >= lp->mPage) {
-		printk ("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
-		     (u_char) page);
-		goto err_out;
-	}
-
-
-	/*
-	 ** Set up shared memory window and pointer into the window
-	 */
-	if (lp->shmem_length == IO_ONLY) {
-		outb (page, EWRK3_IOPR);
-	} else if (lp->shmem_length == SHMEM_2K) {
-		buf = lp->shmem;
-		outb (page, EWRK3_MPR);
-	} else if (lp->shmem_length == SHMEM_32K) {
-		buf = (((short) page << 11) & 0x7800) + lp->shmem;
-		outb ((page >> 4), EWRK3_MPR);
-	} else if (lp->shmem_length == SHMEM_64K) {
-		buf = (((short) page << 11) & 0xf800) + lp->shmem;
-		outb ((page >> 5), EWRK3_MPR);
-	} else {
-		printk (KERN_ERR "%s: Oops - your private data area is hosed!\n",
-			dev->name);
-		BUG ();
-	}
-
-	/*
-	 ** Set up the buffer control structures and copy the data from
-	 ** the socket buffer to the shared memory .
-	 */
-	if (lp->shmem_length == IO_ONLY) {
-		int i;
-		u_char *p = skb->data;
-		outb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
-		outb ((char) (skb->len & 0xff), EWRK3_DATA);
-		outb ((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
-		outb ((char) 0x04, EWRK3_DATA);
-		for (i = 0; i < skb->len; i++) {
-			outb (*p++, EWRK3_DATA);
-		}
-		outb (page, EWRK3_TQ);	/* Start sending pkt */
-	} else {
-		writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf);	/* ctrl byte */
-		buf += 1;
-		writeb ((char) (skb->len & 0xff), buf);	/* length (16 bit xfer) */
-		buf += 1;
-		if (lp->txc) {
-			writeb(((skb->len >> 8) & 0xff) | XCT, buf);
-			buf += 1;
-			writeb (0x04, buf);	/* index byte */
-			buf += 1;
-			writeb (0x00, (buf + skb->len));	/* Write the XCT flag */
-			memcpy_toio (buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
-			outb (page, EWRK3_TQ);	/* Start sending pkt */
-			memcpy_toio (buf + PRELOAD,
-					 skb->data + PRELOAD,
-					 skb->len - PRELOAD);
-			writeb (0xff, (buf + skb->len));	/* Write the XCT flag */
-		} else {
-			writeb ((skb->len >> 8) & 0xff, buf);
-			buf += 1;
-			writeb (0x04, buf);	/* index byte */
-			buf += 1;
-			memcpy_toio (buf, skb->data, skb->len);	/* Write data bytes */
-			outb (page, EWRK3_TQ);	/* Start sending pkt */
-		}
-	}
-
-	ENABLE_IRQs;
-	spin_unlock_irq (&lp->hw_lock);
-
-	dev->stats.tx_bytes += skb->len;
-	dev_kfree_skb (skb);
-
-	/* Check for free resources: stop Tx queue if there are none */
-	if (inb (EWRK3_FMQC) == 0)
-		netif_stop_queue (dev);
-
-	return NETDEV_TX_OK;
-
-err_out:
-	ENABLE_IRQs;
-	spin_unlock_irq (&lp->hw_lock);
-	return NETDEV_TX_BUSY;
-}
-
-/*
-   ** The EWRK3 interrupt handler.
- */
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct ewrk3_private *lp;
-	u_long iobase;
-	u_char icr, cr, csr;
-
-	lp = netdev_priv(dev);
-	iobase = dev->base_addr;
-
-	/* get the interrupt information */
-	csr = inb(EWRK3_CSR);
-
-	/*
-	 ** Mask the EWRK3 board interrupts and turn on the LED
-	 */
-	spin_lock(&lp->hw_lock);
-	DISABLE_IRQs;
-
-	cr = inb(EWRK3_CR);
-	cr |= lp->led_mask;
-	outb(cr, EWRK3_CR);
-
-	if (csr & CSR_RNE)	/* Rx interrupt (packet[s] arrived) */
-		ewrk3_rx(dev);
-
-	if (csr & CSR_TNE)	/* Tx interrupt (packet sent) */
-		ewrk3_tx(dev);
-
-	/*
-	 ** Now deal with the TX/RX disable flags. These are set when there
-	 ** are no more resources. If resources free up then enable these
-	 ** interrupts, otherwise mask them - failure to do this will result
-	 ** in the system hanging in an interrupt loop.
-	 */
-	if (inb(EWRK3_FMQC)) {	/* any resources available? */
-		lp->irq_mask |= ICR_TXDM | ICR_RXDM;	/* enable the interrupt source */
-		csr &= ~(CSR_TXD | CSR_RXD);	/* ensure restart of a stalled TX or RX */
-		outb(csr, EWRK3_CSR);
-		netif_wake_queue(dev);
-	} else {
-		lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM);		/* disable the interrupt source */
-	}
-
-	/* Unmask the EWRK3 board interrupts and turn off the LED */
-	cr &= ~(lp->led_mask);
-	outb(cr, EWRK3_CR);
-	ENABLE_IRQs;
-	spin_unlock(&lp->hw_lock);
-	return IRQ_HANDLED;
-}
-
-/* Called with lp->hw_lock held */
-static int ewrk3_rx(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_long iobase = dev->base_addr;
-	int i, status = 0;
-	u_char page;
-	void __iomem *buf = NULL;
-
-	while (inb(EWRK3_RQC) && !status) {	/* Whilst there's incoming data */
-		if ((page = inb(EWRK3_RQ)) < lp->mPage) {	/* Get next entry's buffer page */
-			/*
-			   ** Set up shared memory window and pointer into the window
-			 */
-			if (lp->shmem_length == IO_ONLY) {
-				outb(page, EWRK3_IOPR);
-			} else if (lp->shmem_length == SHMEM_2K) {
-				buf = lp->shmem;
-				outb(page, EWRK3_MPR);
-			} else if (lp->shmem_length == SHMEM_32K) {
-				buf = (((short) page << 11) & 0x7800) + lp->shmem;
-				outb((page >> 4), EWRK3_MPR);
-			} else if (lp->shmem_length == SHMEM_64K) {
-				buf = (((short) page << 11) & 0xf800) + lp->shmem;
-				outb((page >> 5), EWRK3_MPR);
-			} else {
-				status = -1;
-				printk("%s: Oops - your private data area is hosed!\n", dev->name);
-			}
-
-			if (!status) {
-				char rx_status;
-				int pkt_len;
-
-				if (lp->shmem_length == IO_ONLY) {
-					rx_status = inb(EWRK3_DATA);
-					pkt_len = inb(EWRK3_DATA);
-					pkt_len |= ((u_short) inb(EWRK3_DATA) << 8);
-				} else {
-					rx_status = readb(buf);
-					buf += 1;
-					pkt_len = readw(buf);
-					buf += 3;
-				}
-
-				if (!(rx_status & R_ROK)) {	/* There was an error. */
-					dev->stats.rx_errors++;	/* Update the error stats. */
-					if (rx_status & R_DBE)
-						dev->stats.rx_frame_errors++;
-					if (rx_status & R_CRC)
-						dev->stats.rx_crc_errors++;
-					if (rx_status & R_PLL)
-						dev->stats.rx_fifo_errors++;
-				} else {
-					struct sk_buff *skb;
-					skb = netdev_alloc_skb(dev,
-							pkt_len + 2);
-
-					if (skb != NULL) {
-						unsigned char *p;
-						skb_reserve(skb, 2);	/* Align to 16 bytes */
-						p = skb_put(skb, pkt_len);
-
-						if (lp->shmem_length == IO_ONLY) {
-							*p = inb(EWRK3_DATA);	/* dummy read */
-							for (i = 0; i < pkt_len; i++) {
-								*p++ = inb(EWRK3_DATA);
-							}
-						} else {
-							memcpy_fromio(p, buf, pkt_len);
-						}
-
-						for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) {
-							if (pkt_len < i * EWRK3_PKT_BIN_SZ) {
-								lp->pktStats.bins[i]++;
-								i = EWRK3_PKT_STAT_SZ;
-							}
-						}
-						p = skb->data;	/* Look at the dest addr */
-						if (is_multicast_ether_addr(p)) {
-							if (is_broadcast_ether_addr(p)) {
-								lp->pktStats.broadcast++;
-							} else {
-								lp->pktStats.multicast++;
-							}
-						} else if (ether_addr_equal(p,
-									    dev->dev_addr)) {
-							lp->pktStats.unicast++;
-						}
-						lp->pktStats.bins[0]++;		/* Duplicates stats.rx_packets */
-						if (lp->pktStats.bins[0] == 0) {	/* Reset counters */
-							memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-						}
-						/*
-						   ** Notify the upper protocol layers that there is another
-						   ** packet to handle
-						 */
-						skb->protocol = eth_type_trans(skb, dev);
-						netif_rx(skb);
-
-						/*
-						   ** Update stats
-						 */
-						dev->stats.rx_packets++;
-						dev->stats.rx_bytes += pkt_len;
-					} else {
-						printk("%s: Insufficient memory; nuking packet.\n", dev->name);
-						dev->stats.rx_dropped++;		/* Really, deferred. */
-						break;
-					}
-				}
-			}
-			/*
-			   ** Return the received buffer to the free memory queue
-			 */
-			outb(page, EWRK3_FMQ);
-		} else {
-			printk("ewrk3_rx(): Illegal page number, page %d\n", page);
-			printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
-		}
-	}
-	return status;
-}
-
-/*
-** Buffer sent - check for TX buffer errors.
-** Called with lp->hw_lock held
-*/
-static int ewrk3_tx(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_long iobase = dev->base_addr;
-	u_char tx_status;
-
-	while ((tx_status = inb(EWRK3_TDQ)) > 0) {	/* Whilst there's old buffers */
-		if (tx_status & T_VSTS) {	/* The status is valid */
-			if (tx_status & T_TXE) {
-				dev->stats.tx_errors++;
-				if (tx_status & T_NCL)
-					dev->stats.tx_carrier_errors++;
-				if (tx_status & T_LCL)
-					dev->stats.tx_window_errors++;
-				if (tx_status & T_CTU) {
-					if ((tx_status & T_COLL) ^ T_XUR) {
-						lp->pktStats.tx_underruns++;
-					} else {
-						lp->pktStats.excessive_underruns++;
-					}
-				} else if (tx_status & T_COLL) {
-					if ((tx_status & T_COLL) ^ T_XCOLL) {
-						dev->stats.collisions++;
-					} else {
-						lp->pktStats.excessive_collisions++;
-					}
-				}
-			} else {
-				dev->stats.tx_packets++;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int ewrk3_close(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_long iobase = dev->base_addr;
-	u_char icr, csr;
-
-	netif_stop_queue(dev);
-
-	if (ewrk3_debug > 1) {
-		printk("%s: Shutting down ethercard, status was %2.2x.\n",
-		       dev->name, inb(EWRK3_CSR));
-	}
-	/*
-	   ** We stop the EWRK3 here... mask interrupts and stop TX & RX
-	 */
-	DISABLE_IRQs;
-
-	STOP_EWRK3;
-
-	/*
-	   ** Clean out the TX and RX queues here (note that one entry
-	   ** may get added to either the TXD or RX queues if the TX or RX
-	   ** just starts processing a packet before the STOP_EWRK3 command
-	   ** is received. This will be flushed in the ewrk3_open() call).
-	 */
-	while (inb(EWRK3_TQ));
-	while (inb(EWRK3_TDQ));
-	while (inb(EWRK3_RQ));
-
-	if (!lp->hard_strapped) {
-		free_irq(dev->irq, dev);
-	}
-	return 0;
-}
-
-/*
-   ** Set or clear the multicast filter for this adapter.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	u_long iobase = dev->base_addr;
-	u_char csr;
-
-	csr = inb(EWRK3_CSR);
-
-	if (lp->shmem_length == IO_ONLY) {
-		lp->mctbl = NULL;
-	} else {
-		lp->mctbl = lp->shmem + PAGE0_HTE;
-	}
-
-	csr &= ~(CSR_PME | CSR_MCE);
-	if (dev->flags & IFF_PROMISC) {		/* set promiscuous mode */
-		csr |= CSR_PME;
-		outb(csr, EWRK3_CSR);
-	} else {
-		SetMulticastFilter(dev);
-		csr |= CSR_MCE;
-		outb(csr, EWRK3_CSR);
-	}
-}
-
-/*
-   ** Calculate the hash code and update the logical address filter
-   ** from a list of ethernet multicast addresses.
-   ** Little endian crc one liner from Matt Thomas, DEC.
-   **
-   ** Note that when clearing the table, the broadcast bit must remain asserted
-   ** to receive broadcast messages.
- */
-static void SetMulticastFilter(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	struct netdev_hw_addr *ha;
-	u_long iobase = dev->base_addr;
-	int i;
-	char bit, byte;
-	short __iomem *p = lp->mctbl;
-	u16 hashcode;
-	u32 crc;
-
-	spin_lock_irq(&lp->hw_lock);
-
-	if (lp->shmem_length == IO_ONLY) {
-		outb(0, EWRK3_IOPR);
-		outw(PAGE0_HTE, EWRK3_PIR1);
-	} else {
-		outb(0, EWRK3_MPR);
-	}
-
-	if (dev->flags & IFF_ALLMULTI) {
-		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-			if (lp->shmem_length == IO_ONLY) {
-				outb(0xff, EWRK3_DATA);
-			} else {	/* memset didn't work here */
-				writew(0xffff, p);
-				p++;
-				i++;
-			}
-		}
-	} else {
-		/* Clear table except for broadcast bit */
-		if (lp->shmem_length == IO_ONLY) {
-			for (i = 0; i < (HASH_TABLE_LEN >> 4) - 1; i++) {
-				outb(0x00, EWRK3_DATA);
-			}
-			outb(0x80, EWRK3_DATA);
-			i++;	/* insert the broadcast bit */
-			for (; i < (HASH_TABLE_LEN >> 3); i++) {
-				outb(0x00, EWRK3_DATA);
-			}
-		} else {
-			memset_io(lp->mctbl, 0, HASH_TABLE_LEN >> 3);
-			writeb(0x80, lp->mctbl + (HASH_TABLE_LEN >> 4) - 1);
-		}
-
-		/* Update table */
-		netdev_for_each_mc_addr(ha, dev) {
-			crc = ether_crc_le(ETH_ALEN, ha->addr);
-			hashcode = crc & ((1 << 9) - 1);	/* hashcode is 9 LSb of CRC */
-
-			byte = hashcode >> 3;	/* bit[3-8] -> byte in filter */
-			bit = 1 << (hashcode & 0x07);	/* bit[0-2] -> bit in byte */
-
-			if (lp->shmem_length == IO_ONLY) {
-				u_char tmp;
-
-				outw(PAGE0_HTE + byte, EWRK3_PIR1);
-				tmp = inb(EWRK3_DATA);
-				tmp |= bit;
-				outw(PAGE0_HTE + byte, EWRK3_PIR1);
-				outb(tmp, EWRK3_DATA);
-			} else {
-				writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte);
-			}
-		}
-	}
-
-	spin_unlock_irq(&lp->hw_lock);
-}
-
-/*
-   ** ISA bus I/O device probe
- */
-static int __init isa_probe(struct net_device *dev, u_long ioaddr)
-{
-	int i = num_ewrks3s, maxSlots;
-	int ret = -ENODEV;
-
-	u_long iobase;
-
-	if (ioaddr >= 0x400)
-		goto out;
-
-	if (ioaddr == 0) {	/* Autoprobing */
-		iobase = EWRK3_IO_BASE;		/* Get the first slot address */
-		maxSlots = 24;
-	} else {		/* Probe a specific location */
-		iobase = ioaddr;
-		maxSlots = i + 1;
-	}
-
-	for (; (i < maxSlots) && (dev != NULL);
-	     iobase += EWRK3_IOP_INC, i++)
-	{
-		if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME)) {
-			if (DevicePresent(iobase) == 0) {
-				int irq = dev->irq;
-				ret = ewrk3_hw_init(dev, iobase);
-				if (!ret)
-					break;
-				dev->irq = irq;
-			}
-			release_region(iobase, EWRK3_TOTAL_SIZE);
-		}
-	}
- out:
-
-	return ret;
-}
-
-/*
-   ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-   ** the motherboard.
- */
-static int __init eisa_probe(struct net_device *dev, u_long ioaddr)
-{
-	int i, maxSlots;
-	u_long iobase;
-	int ret = -ENODEV;
-
-	if (ioaddr < 0x1000)
-		goto out;
-
-	iobase = ioaddr;
-	i = (ioaddr >> 12);
-	maxSlots = i + 1;
-
-	for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
-		if (EISA_signature(name, EISA_ID) == 0) {
-			if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME) &&
-			    DevicePresent(iobase) == 0) {
-				int irq = dev->irq;
-				ret = ewrk3_hw_init(dev, iobase);
-				if (!ret)
-					break;
-				dev->irq = irq;
-			}
-			release_region(iobase, EWRK3_TOTAL_SIZE);
-		}
-	}
-
- out:
-	return ret;
-}
-
-
-/*
-   ** Read the EWRK3 EEPROM using this routine
- */
-static int Read_EEPROM(u_long iobase, u_char eaddr)
-{
-	int i;
-
-	outb((eaddr & 0x3f), EWRK3_PIR1);	/* set up 6 bits of address info */
-	outb(EEPROM_RD, EWRK3_IOPR);	/* issue read command */
-	for (i = 0; i < 5000; i++)
-		inb(EWRK3_CSR);	/* wait 1msec */
-
-	return inw(EWRK3_EPROM1);	/* 16 bits data return */
-}
-
-/*
-   ** Write the EWRK3 EEPROM using this routine
- */
-static int Write_EEPROM(short data, u_long iobase, u_char eaddr)
-{
-	int i;
-
-	outb(EEPROM_WR_EN, EWRK3_IOPR);		/* issue write enable command */
-	for (i = 0; i < 5000; i++)
-		inb(EWRK3_CSR);	/* wait 1msec */
-	outw(data, EWRK3_EPROM1);	/* write data to register */
-	outb((eaddr & 0x3f), EWRK3_PIR1);	/* set up 6 bits of address info */
-	outb(EEPROM_WR, EWRK3_IOPR);	/* issue write command */
-	for (i = 0; i < 75000; i++)
-		inb(EWRK3_CSR);	/* wait 15msec */
-	outb(EEPROM_WR_DIS, EWRK3_IOPR);	/* issue write disable command */
-	for (i = 0; i < 5000; i++)
-		inb(EWRK3_CSR);	/* wait 1msec */
-
-	return 0;
-}
-
-/*
-   ** Look for a particular board name in the on-board EEPROM.
- */
-static void __init EthwrkSignature(char *name, char *eeprom_image)
-{
-	int i;
-	char *signatures[] = EWRK3_SIGNATURE;
-
-	for (i=0; *signatures[i] != '\0'; i++)
-		if( !strncmp(eeprom_image+EEPROM_PNAME7, signatures[i], strlen(signatures[i])) )
-			break;
-
-	if (*signatures[i] != '\0') {
-		memcpy(name, eeprom_image+EEPROM_PNAME7, EWRK3_STRLEN);
-		name[EWRK3_STRLEN] = '\0';
-	} else
-		name[0] = '\0';
-}
-
-/*
-   ** Look for a special sequence in the Ethernet station address PROM that
-   ** is common across all EWRK3 products.
-   **
-   ** Search the Ethernet address ROM for the signature. Since the ROM address
-   ** counter can start at an arbitrary point, the search must include the entire
-   ** probe sequence length plus the (length_of_the_signature - 1).
-   ** Stop the search IMMEDIATELY after the signature is found so that the
-   ** PROM address counter is correctly positioned at the start of the
-   ** ethernet address for later read out.
- */
-
-static int __init DevicePresent(u_long iobase)
-{
-	union {
-		struct {
-			u32 a;
-			u32 b;
-		} llsig;
-		char Sig[sizeof(u32) << 1];
-	}
-	dev;
-	short sigLength;
-	char data;
-	int i, j, status = 0;
-
-	dev.llsig.a = ETH_PROM_SIG;
-	dev.llsig.b = ETH_PROM_SIG;
-	sigLength = sizeof(u32) << 1;
-
-	for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
-		data = inb(EWRK3_APROM);
-		if (dev.Sig[j] == data) {	/* track signature */
-			j++;
-		} else {	/* lost signature; begin search again */
-			if (data == dev.Sig[0]) {
-				j = 1;
-			} else {
-				j = 0;
-			}
-		}
-	}
-
-	if (j != sigLength) {
-		status = -ENODEV;	/* search failed */
-	}
-	return status;
-}
-
-static u_char __init get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType)
-{
-	int i, j, k;
-	u_short chksum;
-	u_char crc, lfsr, sd, status = 0;
-	u_long iobase = dev->base_addr;
-	u16 tmp;
-
-	if (chipType == LeMAC2) {
-		for (crc = 0x6a, j = 0; j < ETH_ALEN; j++) {
-			sd = dev->dev_addr[j] = eeprom_image[EEPROM_PADDR0 + j];
-			outb(dev->dev_addr[j], EWRK3_PAR0 + j);
-			for (k = 0; k < 8; k++, sd >>= 1) {
-				lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7;
-				crc = (crc >> 1) + lfsr;
-			}
-		}
-		if (crc != eeprom_image[EEPROM_PA_CRC])
-			status = -1;
-	} else {
-		for (i = 0, k = 0; i < ETH_ALEN;) {
-			k <<= 1;
-			if (k > 0xffff)
-				k -= 0xffff;
-
-			k += (u_char) (tmp = inb(EWRK3_APROM));
-			dev->dev_addr[i] = (u_char) tmp;
-			outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-			i++;
-			k += (u_short) ((tmp = inb(EWRK3_APROM)) << 8);
-			dev->dev_addr[i] = (u_char) tmp;
-			outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-			i++;
-
-			if (k > 0xffff)
-				k -= 0xffff;
-		}
-		if (k == 0xffff)
-			k = 0;
-		chksum = inb(EWRK3_APROM);
-		chksum |= (inb(EWRK3_APROM) << 8);
-		if (k != chksum)
-			status = -1;
-	}
-
-	return status;
-}
-
-/*
-   ** Look for a particular board name in the EISA configuration space
- */
-static int __init EISA_signature(char *name, s32 eisa_id)
-{
-	u_long i;
-	char *signatures[] = EWRK3_SIGNATURE;
-	char ManCode[EWRK3_STRLEN];
-	union {
-		s32 ID;
-		char Id[4];
-	} Eisa;
-	int status = 0;
-
-	*name = '\0';
-	for (i = 0; i < 4; i++) {
-		Eisa.Id[i] = inb(eisa_id + i);
-	}
-
-	ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
-	ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
-	ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
-	ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
-	ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
-	ManCode[5] = '\0';
-
-	for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) {
-		if (strstr(ManCode, signatures[i]) != NULL) {
-			strcpy(name, ManCode);
-			status = 1;
-		}
-	}
-
-	return status;		/* return the device name string */
-}
-
-static void ewrk3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-	int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
-
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	sprintf(info->fw_version, "%d", fwrev);
-	strcpy(info->bus_info, "N/A");
-	info->eedump_len = EEPROM_MAX;
-}
-
-static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	unsigned long iobase = dev->base_addr;
-	u8 cr = inb(EWRK3_CR);
-
-	switch (lp->adapter_name[4]) {
-	case '3': /* DE203 */
-		ecmd->supported = SUPPORTED_BNC;
-		ecmd->port = PORT_BNC;
-		break;
-
-	case '4': /* DE204 */
-		ecmd->supported = SUPPORTED_TP;
-		ecmd->port = PORT_TP;
-		break;
-
-	case '5': /* DE205 */
-		ecmd->supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
-		ecmd->autoneg = !(cr & CR_APD);
-		/*
-		** Port is only valid if autoneg is disabled
-		** and even then we don't know if AUI is jumpered.
-		*/
-		if (!ecmd->autoneg)
-			ecmd->port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
-		break;
-	}
-
-	ecmd->supported |= SUPPORTED_10baseT_Half;
-	ethtool_cmd_speed_set(ecmd, SPEED_10);
-	ecmd->duplex = DUPLEX_HALF;
-	return 0;
-}
-
-static int ewrk3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	unsigned long iobase = dev->base_addr;
-	unsigned long flags;
-	u8 cr;
-
-	/* DE205 is the only card with anything to set */
-	if (lp->adapter_name[4] != '5')
-		return -EOPNOTSUPP;
-
-	/* Sanity-check parameters */
-	if (ecmd->speed != SPEED_10)
-		return -EINVAL;
-	if (ecmd->port != PORT_TP && ecmd->port != PORT_BNC)
-		return -EINVAL; /* AUI is not software-selectable */
-	if (ecmd->transceiver != XCVR_INTERNAL)
-		return -EINVAL;
-	if (ecmd->duplex != DUPLEX_HALF)
-		return -EINVAL;
-	if (ecmd->phy_address != 0)
-		return -EINVAL;
-
-	spin_lock_irqsave(&lp->hw_lock, flags);
-	cr = inb(EWRK3_CR);
-
-	/* If Autoneg is set, change to Auto Port mode */
-	/* Otherwise, disable Auto Port and set port explicitly */
-	if (ecmd->autoneg) {
-		cr &= ~CR_APD;
-	} else {
-		cr |= CR_APD;
-		if (ecmd->port == PORT_TP)
-			cr &= ~CR_PSEL;		/* Force TP */
-		else
-			cr |= CR_PSEL;		/* Force BNC */
-	}
-
-	/* Commit the changes */
-	outb(cr, EWRK3_CR);
-	spin_unlock_irqrestore(&lp->hw_lock, flags);
-	return 0;
-}
-
-static u32 ewrk3_get_link(struct net_device *dev)
-{
-	unsigned long iobase = dev->base_addr;
-	u8 cmr = inb(EWRK3_CMR);
-	/* DE203 has BNC only and link status does not apply */
-	/* On DE204 this is always valid since TP is the only port. */
-	/* On DE205 this reflects TP status even if BNC or AUI is selected. */
-	return !(cmr & CMR_LINK);
-}
-
-static int ewrk3_set_phys_id(struct net_device *dev,
-			     enum ethtool_phys_id_state state)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	unsigned long iobase = dev->base_addr;
-	u8 cr;
-
-	spin_lock_irq(&lp->hw_lock);
-
-	switch (state) {
-	case ETHTOOL_ID_ACTIVE:
-		/* Prevent ISR from twiddling the LED */
-		lp->led_mask = 0;
-		spin_unlock_irq(&lp->hw_lock);
-		return 2;	/* cycle on/off twice per second */
-
-	case ETHTOOL_ID_ON:
-		cr = inb(EWRK3_CR);
-		outb(cr | CR_LED, EWRK3_CR);
-		break;
-
-	case ETHTOOL_ID_OFF:
-		cr = inb(EWRK3_CR);
-		outb(cr & ~CR_LED, EWRK3_CR);
-		break;
-
-	case ETHTOOL_ID_INACTIVE:
-		lp->led_mask = CR_LED;
-		cr = inb(EWRK3_CR);
-		outb(cr & ~CR_LED, EWRK3_CR);
-	}
-	spin_unlock_irq(&lp->hw_lock);
-
-	return 0;
-}
-
-static const struct ethtool_ops ethtool_ops_203 = {
-	.get_drvinfo = ewrk3_get_drvinfo,
-	.get_settings = ewrk3_get_settings,
-	.set_settings = ewrk3_set_settings,
-	.set_phys_id = ewrk3_set_phys_id,
-};
-
-static const struct ethtool_ops ethtool_ops = {
-	.get_drvinfo = ewrk3_get_drvinfo,
-	.get_settings = ewrk3_get_settings,
-	.set_settings = ewrk3_set_settings,
-	.get_link = ewrk3_get_link,
-	.set_phys_id = ewrk3_set_phys_id,
-};
-
-/*
-   ** Perform IOCTL call functions here. Some are privileged operations and the
-   ** effective uid is checked in those cases.
- */
-static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-	struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru;
-	u_long iobase = dev->base_addr;
-	int i, j, status = 0;
-	u_char csr;
-	unsigned long flags;
-	union ewrk3_addr {
-		u_char addr[HASH_TABLE_LEN * ETH_ALEN];
-		u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-	};
-
-	union ewrk3_addr *tmp;
-
-	/* All we handle are private IOCTLs */
-	if (cmd != EWRK3IOCTL)
-		return -EOPNOTSUPP;
-
-	tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
-	if(tmp==NULL)
-		return -ENOMEM;
-
-	switch (ioc->cmd) {
-	case EWRK3_GET_HWADDR:	/* Get the hardware address */
-		for (i = 0; i < ETH_ALEN; i++) {
-			tmp->addr[i] = dev->dev_addr[i];
-		}
-		ioc->len = ETH_ALEN;
-		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-			status = -EFAULT;
-		break;
-
-	case EWRK3_SET_HWADDR:	/* Set the hardware address */
-		if (capable(CAP_NET_ADMIN)) {
-			spin_lock_irqsave(&lp->hw_lock, flags);
-			csr = inb(EWRK3_CSR);
-			csr |= (CSR_TXD | CSR_RXD);
-			outb(csr, EWRK3_CSR);	/* Disable the TX and RX */
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-
-			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
-				status = -EFAULT;
-				break;
-			}
-			spin_lock_irqsave(&lp->hw_lock, flags);
-			for (i = 0; i < ETH_ALEN; i++) {
-				dev->dev_addr[i] = tmp->addr[i];
-				outb(tmp->addr[i], EWRK3_PAR0 + i);
-			}
-
-			csr = inb(EWRK3_CSR);
-			csr &= ~(CSR_TXD | CSR_RXD);	/* Enable the TX and RX */
-			outb(csr, EWRK3_CSR);
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_SET_PROM:	/* Set Promiscuous Mode */
-		if (capable(CAP_NET_ADMIN)) {
-			spin_lock_irqsave(&lp->hw_lock, flags);
-			csr = inb(EWRK3_CSR);
-			csr |= CSR_PME;
-			csr &= ~CSR_MCE;
-			outb(csr, EWRK3_CSR);
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_CLR_PROM:	/* Clear Promiscuous Mode */
-		if (capable(CAP_NET_ADMIN)) {
-			spin_lock_irqsave(&lp->hw_lock, flags);
-			csr = inb(EWRK3_CSR);
-			csr &= ~CSR_PME;
-			outb(csr, EWRK3_CSR);
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_GET_MCA:	/* Get the multicast address table */
-		spin_lock_irqsave(&lp->hw_lock, flags);
-		if (lp->shmem_length == IO_ONLY) {
-			outb(0, EWRK3_IOPR);
-			outw(PAGE0_HTE, EWRK3_PIR1);
-			for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-				tmp->addr[i] = inb(EWRK3_DATA);
-			}
-		} else {
-			outb(0, EWRK3_MPR);
-			memcpy_fromio(tmp->addr, lp->shmem + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
-		}
-		spin_unlock_irqrestore(&lp->hw_lock, flags);
-
-		ioc->len = (HASH_TABLE_LEN >> 3);
-		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-			status = -EFAULT;
-
-		break;
-	case EWRK3_SET_MCA:	/* Set a multicast address */
-		if (capable(CAP_NET_ADMIN)) {
-			if (ioc->len > HASH_TABLE_LEN) {
-				status = -EINVAL;
-				break;
-			}
-			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
-				status = -EFAULT;
-				break;
-			}
-			set_multicast_list(dev);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_CLR_MCA:	/* Clear all multicast addresses */
-		if (capable(CAP_NET_ADMIN)) {
-			set_multicast_list(dev);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_MCA_EN:	/* Enable multicast addressing */
-		if (capable(CAP_NET_ADMIN)) {
-			spin_lock_irqsave(&lp->hw_lock, flags);
-			csr = inb(EWRK3_CSR);
-			csr |= CSR_MCE;
-			csr &= ~CSR_PME;
-			outb(csr, EWRK3_CSR);
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_GET_STATS: { /* Get the driver statistics */
-		struct ewrk3_stats *tmp_stats =
-        		kmalloc(sizeof(lp->pktStats), GFP_KERNEL);
-		if (!tmp_stats) {
-			status = -ENOMEM;
-			break;
-		}
-
-		spin_lock_irqsave(&lp->hw_lock, flags);
-		memcpy(tmp_stats, &lp->pktStats, sizeof(lp->pktStats));
-		spin_unlock_irqrestore(&lp->hw_lock, flags);
-
-		ioc->len = sizeof(lp->pktStats);
-		if (copy_to_user(ioc->data, tmp_stats, sizeof(lp->pktStats)))
-    			status = -EFAULT;
-		kfree(tmp_stats);
-		break;
-	}
-	case EWRK3_CLR_STATS:	/* Zero out the driver statistics */
-		if (capable(CAP_NET_ADMIN)) {
-			spin_lock_irqsave(&lp->hw_lock, flags);
-			memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-			spin_unlock_irqrestore(&lp->hw_lock,flags);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_GET_CSR:	/* Get the CSR Register contents */
-		tmp->addr[0] = inb(EWRK3_CSR);
-		ioc->len = 1;
-		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-			status = -EFAULT;
-		break;
-	case EWRK3_SET_CSR:	/* Set the CSR Register contents */
-		if (capable(CAP_NET_ADMIN)) {
-			if (copy_from_user(tmp->addr, ioc->data, 1)) {
-				status = -EFAULT;
-				break;
-			}
-			outb(tmp->addr[0], EWRK3_CSR);
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_GET_EEPROM:	/* Get the EEPROM contents */
-		if (capable(CAP_NET_ADMIN)) {
-			for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-				tmp->val[i] = (short) Read_EEPROM(iobase, i);
-			}
-			i = EEPROM_MAX;
-			tmp->addr[i++] = inb(EWRK3_CMR);		/* Config/Management Reg. */
-			for (j = 0; j < ETH_ALEN; j++) {
-				tmp->addr[i++] = inb(EWRK3_PAR0 + j);
-			}
-			ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
-			if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-				status = -EFAULT;
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_SET_EEPROM:	/* Set the EEPROM contents */
-		if (capable(CAP_NET_ADMIN)) {
-			if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) {
-				status = -EFAULT;
-				break;
-			}
-			for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-				Write_EEPROM(tmp->val[i], iobase, i);
-			}
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_GET_CMR:	/* Get the CMR Register contents */
-		tmp->addr[0] = inb(EWRK3_CMR);
-		ioc->len = 1;
-		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
-			status = -EFAULT;
-		break;
-	case EWRK3_SET_TX_CUT_THRU:	/* Set TX cut through mode */
-		if (capable(CAP_NET_ADMIN)) {
-			lp->txc = 1;
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	case EWRK3_CLR_TX_CUT_THRU:	/* Clear TX cut through mode */
-		if (capable(CAP_NET_ADMIN)) {
-			lp->txc = 0;
-		} else {
-			status = -EPERM;
-		}
-
-		break;
-	default:
-		status = -EOPNOTSUPP;
-	}
-	kfree(tmp);
-	return status;
-}
-
-#ifdef MODULE
-static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
-static int ndevs;
-static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, byte, NULL, 0);
-MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");
-
-static __exit void ewrk3_exit_module(void)
-{
-	int i;
-
-	for( i=0; i<ndevs; i++ ) {
-		struct net_device *dev = ewrk3_devs[i];
-		struct ewrk3_private *lp = netdev_priv(dev);
-		ewrk3_devs[i] = NULL;
-		unregister_netdev(dev);
-		release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
-		iounmap(lp->shmem);
-		free_netdev(dev);
-	}
-}
-
-static __init int ewrk3_init_module(void)
-{
-	int i=0;
-
-	while( io[i] && irq[i] ) {
-		struct net_device *dev
-			= alloc_etherdev(sizeof(struct ewrk3_private));
-
-		if (!dev)
-			break;
-
-		if (ewrk3_probe1(dev, io[i], irq[i]) != 0) {
-			free_netdev(dev);
-			break;
-		}
-
-		ewrk3_devs[ndevs++] = dev;
-		i++;
-	}
-
-	return ndevs ? 0 : -EIO;
-}
-
-
-/* Hack for breakage in new module stuff */
-module_exit(ewrk3_exit_module);
-module_init(ewrk3_init_module);
-#endif				/* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dec/ewrk3.h b/drivers/net/ethernet/dec/ewrk3.h
deleted file mode 100644
index 8e0ee90..0000000
--- a/drivers/net/ethernet/dec/ewrk3.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
-    Written 1994 by David C. Davies.
-
-    Copyright 1994 Digital Equipment Corporation.
-
-    This software may be used and distributed according to  the terms of the
-    GNU General Public License, incorporated herein by reference.
-
-    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
-    Equipment Corporation, 550 King Street, Littleton MA 01460.
-
-    =========================================================================
-*/
-
-/*
-** I/O Address Register Map
-*/
-#define EWRK3_CSR    iobase+0x00   /* Control and Status Register */
-#define EWRK3_CR     iobase+0x01   /* Control Register */
-#define EWRK3_ICR    iobase+0x02   /* Interrupt Control Register */
-#define EWRK3_TSR    iobase+0x03   /* Transmit Status Register */
-#define EWRK3_RSVD1  iobase+0x04   /* RESERVED */
-#define EWRK3_RSVD2  iobase+0x05   /* RESERVED */
-#define EWRK3_FMQ    iobase+0x06   /* Free Memory Queue */
-#define EWRK3_FMQC   iobase+0x07   /* Free Memory Queue Counter */
-#define EWRK3_RQ     iobase+0x08   /* Receive Queue */
-#define EWRK3_RQC    iobase+0x09   /* Receive Queue Counter */
-#define EWRK3_TQ     iobase+0x0a   /* Transmit Queue */
-#define EWRK3_TQC    iobase+0x0b   /* Transmit Queue Counter */
-#define EWRK3_TDQ    iobase+0x0c   /* Transmit Done Queue */
-#define EWRK3_TDQC   iobase+0x0d   /* Transmit Done Queue Counter */
-#define EWRK3_PIR1   iobase+0x0e   /* Page Index Register 1 */
-#define EWRK3_PIR2   iobase+0x0f   /* Page Index Register 2 */
-#define EWRK3_DATA   iobase+0x10   /* Data Register */
-#define EWRK3_IOPR   iobase+0x11   /* I/O Page Register */
-#define EWRK3_IOBR   iobase+0x12   /* I/O Base Register */
-#define EWRK3_MPR    iobase+0x13   /* Memory Page Register */
-#define EWRK3_MBR    iobase+0x14   /* Memory Base Register */
-#define EWRK3_APROM  iobase+0x15   /* Address PROM */
-#define EWRK3_EPROM1 iobase+0x16   /* EEPROM Data Register 1 */
-#define EWRK3_EPROM2 iobase+0x17   /* EEPROM Data Register 2 */
-#define EWRK3_PAR0   iobase+0x18   /* Physical Address Register 0 */
-#define EWRK3_PAR1   iobase+0x19   /* Physical Address Register 1 */
-#define EWRK3_PAR2   iobase+0x1a   /* Physical Address Register 2 */
-#define EWRK3_PAR3   iobase+0x1b   /* Physical Address Register 3 */
-#define EWRK3_PAR4   iobase+0x1c   /* Physical Address Register 4 */
-#define EWRK3_PAR5   iobase+0x1d   /* Physical Address Register 5 */
-#define EWRK3_CMR    iobase+0x1e   /* Configuration/Management Register */
-
-/*
-** Control Page Map
-*/
-#define PAGE0_FMQ     0x000         /* Free Memory Queue */
-#define PAGE0_RQ      0x080         /* Receive Queue */
-#define PAGE0_TQ      0x100         /* Transmit Queue */
-#define PAGE0_TDQ     0x180         /* Transmit Done Queue */
-#define PAGE0_HTE     0x200         /* Hash Table Entries */
-#define PAGE0_RSVD    0x240         /* RESERVED */
-#define PAGE0_USRD    0x600         /* User Data */
-
-/*
-** Control and Status Register bit definitions (EWRK3_CSR)
-*/
-#define CSR_RA		0x80	    /* Runt Accept */
-#define CSR_PME		0x40	    /* Promiscuous Mode Enable */
-#define CSR_MCE		0x20	    /* Multicast Enable */
-#define CSR_TNE		0x08	    /* TX Done Queue Not Empty */
-#define CSR_RNE		0x04	    /* RX Queue Not Empty */
-#define CSR_TXD		0x02	    /* TX Disable */
-#define CSR_RXD		0x01	    /* RX Disable */
-
-/*
-** Control Register bit definitions (EWRK3_CR)
-*/
-#define CR_APD		0x80	/* Auto Port Disable */
-#define CR_PSEL		0x40	/* Port Select (0->TP port) */
-#define CR_LBCK		0x20	/* LoopBaCK enable */
-#define CR_FDUP		0x10	/* Full DUPlex enable */
-#define CR_FBUS		0x08	/* Fast BUS enable (ISA clk > 8.33MHz) */
-#define CR_EN_16	0x04	/* ENable 16 bit memory accesses */
-#define CR_LED		0x02	/* LED (1-> turn on) */
-
-/*
-** Interrupt Control Register bit definitions (EWRK3_ICR)
-*/
-#define ICR_IE		0x80	/* Interrupt Enable */
-#define ICR_IS		0x60	/* Interrupt Selected */
-#define ICR_TNEM	0x08	/* TNE Mask (0->mask) */
-#define ICR_RNEM	0x04	/* RNE Mask (0->mask) */
-#define ICR_TXDM	0x02	/* TXD Mask (0->mask) */
-#define ICR_RXDM	0x01	/* RXD Mask (0->mask) */
-
-/*
-** Transmit Status Register bit definitions (EWRK3_TSR)
-*/
-#define TSR_NCL		0x80	/* No Carrier Loopback */
-#define TSR_ID		0x40	/* Initially Deferred */
-#define TSR_LCL		0x20	/* Late CoLlision */
-#define TSR_ECL		0x10	/* Excessive CoLlisions */
-#define TSR_RCNTR	0x0f	/* Retries CouNTeR */
-
-/*
-** I/O Page Register bit definitions (EWRK3_IOPR)
-*/
-#define EEPROM_INIT	0xc0	/* EEPROM INIT command */
-#define EEPROM_WR_EN	0xc8	/* EEPROM WRITE ENABLE command */
-#define EEPROM_WR	0xd0	/* EEPROM WRITE command */
-#define EEPROM_WR_DIS	0xd8	/* EEPROM WRITE DISABLE command */
-#define EEPROM_RD	0xe0	/* EEPROM READ command */
-
-/*
-** I/O Base Register bit definitions (EWRK3_IOBR)
-*/
-#define EISA_REGS_EN	0x20	/* Enable EISA ID and Control Registers */
-#define EISA_IOB        0x1f	/* Compare bits for I/O Base Address */
-
-/*
-** I/O Configuration/Management Register bit definitions (EWRK3_CMR)
-*/
-#define CMR_RA          0x80    /* Read Ahead */
-#define CMR_WB          0x40    /* Write Behind */
-#define CMR_LINK        0x20	/* 0->TP */
-#define CMR_POLARITY    0x10	/* Informational */
-#define CMR_NO_EEPROM	0x0c	/* NO_EEPROM<1:0> pin status */
-#define CMR_HS          0x08	/* Hard Strapped pin status (LeMAC2) */
-#define CMR_PNP         0x04    /* Plug 'n Play */
-#define CMR_DRAM        0x02	/* 0-> 1DRAM, 1-> 2 DRAM on board */
-#define CMR_0WS         0x01    /* Zero Wait State */
-
-/*
-** MAC Receive Status Register bit definitions
-*/
-
-#define R_ROK     	0x80 	/* Receive OK summary */
-#define R_IAM     	0x10 	/* Individual Address Match */
-#define R_MCM     	0x08 	/* MultiCast Match */
-#define R_DBE     	0x04 	/* Dribble Bit Error */
-#define R_CRC     	0x02 	/* CRC error */
-#define R_PLL     	0x01 	/* Phase Lock Lost */
-
-/*
-** MAC Transmit Control Register bit definitions
-*/
-
-#define TCR_SQEE    	0x40 	/* SQE Enable - look for heartbeat  */
-#define TCR_SED     	0x20 	/* Stop when Error Detected */
-#define TCR_QMODE     	0x10 	/* Q_MODE */
-#define TCR_LAB         0x08 	/* Less Aggressive Backoff */
-#define TCR_PAD     	0x04 	/* PAD Runt Packets */
-#define TCR_IFC     	0x02 	/* Insert Frame Check */
-#define TCR_ISA     	0x01 	/* Insert Source Address */
-
-/*
-** MAC Transmit Status Register bit definitions
-*/
-
-#define T_VSTS    	0x80 	/* Valid STatuS */
-#define T_CTU     	0x40 	/* Cut Through Used */
-#define T_SQE     	0x20 	/* Signal Quality Error */
-#define T_NCL     	0x10 	/* No Carrier Loopback */
-#define T_LCL           0x08 	/* Late Collision */
-#define T_ID      	0x04 	/* Initially Deferred */
-#define T_COLL     	0x03 	/* COLLision status */
-#define T_XCOLL         0x03    /* Excessive Collisions */
-#define T_MCOLL         0x02    /* Multiple Collisions */
-#define T_OCOLL         0x01    /* One Collision */
-#define T_NOCOLL        0x00    /* No Collisions */
-#define T_XUR           0x03    /* Excessive Underruns */
-#define T_TXE           0x7f    /* TX Errors */
-
-/*
-** EISA Configuration Register bit definitions
-*/
-
-#define EISA_ID       iobase + 0x0c80  /* EISA ID Registers */
-#define EISA_ID0      iobase + 0x0c80  /* EISA ID Register 0 */
-#define EISA_ID1      iobase + 0x0c81  /* EISA ID Register 1 */
-#define EISA_ID2      iobase + 0x0c82  /* EISA ID Register 2 */
-#define EISA_ID3      iobase + 0x0c83  /* EISA ID Register 3 */
-#define EISA_CR       iobase + 0x0c84  /* EISA Control Register */
-
-/*
-** EEPROM BYTES
-*/
-#define EEPROM_MEMB     0x00
-#define EEPROM_IOB      0x01
-#define EEPROM_EISA_ID0 0x02
-#define EEPROM_EISA_ID1 0x03
-#define EEPROM_EISA_ID2 0x04
-#define EEPROM_EISA_ID3 0x05
-#define EEPROM_MISC0    0x06
-#define EEPROM_MISC1    0x07
-#define EEPROM_PNAME7   0x08
-#define EEPROM_PNAME6   0x09
-#define EEPROM_PNAME5   0x0a
-#define EEPROM_PNAME4   0x0b
-#define EEPROM_PNAME3   0x0c
-#define EEPROM_PNAME2   0x0d
-#define EEPROM_PNAME1   0x0e
-#define EEPROM_PNAME0   0x0f
-#define EEPROM_SWFLAGS  0x10
-#define EEPROM_HWCAT    0x11
-#define EEPROM_NETMAN2  0x12
-#define EEPROM_REVLVL   0x13
-#define EEPROM_NETMAN0  0x14
-#define EEPROM_NETMAN1  0x15
-#define EEPROM_CHIPVER  0x16
-#define EEPROM_SETUP    0x17
-#define EEPROM_PADDR0   0x18
-#define EEPROM_PADDR1   0x19
-#define EEPROM_PADDR2   0x1a
-#define EEPROM_PADDR3   0x1b
-#define EEPROM_PADDR4   0x1c
-#define EEPROM_PADDR5   0x1d
-#define EEPROM_PA_CRC   0x1e
-#define EEPROM_CHKSUM   0x1f
-
-/*
-** EEPROM bytes for checksumming
-*/
-#define EEPROM_MAX      32             /* bytes */
-
-/*
-** EEPROM MISCELLANEOUS FLAGS
-*/
-#define RBE_SHADOW	0x0100	/* Remote Boot Enable Shadow */
-#define READ_AHEAD      0x0080  /* Read Ahead feature */
-#define IRQ_SEL2        0x0070  /* IRQ line selection (LeMAC2) */
-#define IRQ_SEL         0x0060  /* IRQ line selection */
-#define FAST_BUS        0x0008  /* ISA Bus speeds > 8.33MHz */
-#define ENA_16          0x0004  /* Enables 16 bit memory transfers */
-#define WRITE_BEHIND    0x0002  /* Write Behind feature */
-#define _0WS_ENA        0x0001  /* Zero Wait State Enable */
-
-/*
-** EEPROM NETWORK MANAGEMENT FLAGS
-*/
-#define NETMAN_POL      0x04    /* Polarity defeat */
-#define NETMAN_LINK     0x02    /* Link defeat */
-#define NETMAN_CCE      0x01    /* Custom Counters Enable */
-
-/*
-** EEPROM SW FLAGS
-*/
-#define SW_SQE		0x10	/* Signal Quality Error */
-#define SW_LAB		0x08	/* Less Aggressive Backoff */
-#define SW_INIT		0x04	/* Initialized */
-#define SW_TIMEOUT     	0x02	/* 0:2.5 mins, 1: 30 secs */
-#define SW_REMOTE      	0x01    /* Remote Boot Enable -> 1 */
-
-/*
-** EEPROM SETUP FLAGS
-*/
-#define SETUP_APD	0x80	/* AutoPort Disable */
-#define SETUP_PS	0x40	/* Port Select */
-#define SETUP_MP	0x20	/* MultiPort */
-#define SETUP_1TP	0x10	/* 1 port, TP */
-#define SETUP_1COAX	0x00	/* 1 port, Coax */
-#define SETUP_DRAM	0x02	/* Number of DRAMS on board */
-
-/*
-** EEPROM MANAGEMENT FLAGS
-*/
-#define MGMT_CCE	0x01	/* Custom Counters Enable */
-
-/*
-** EEPROM VERSIONS
-*/
-#define LeMAC           0x11
-#define LeMAC2          0x12
-
-/*
-** Miscellaneous
-*/
-
-#define EEPROM_WAIT_TIME 1000    /* Number of microseconds */
-#define EISA_EN         0x0001   /* Enable EISA bus buffers */
-
-#define HASH_TABLE_LEN   512     /* Bits */
-
-#define XCT 0x80                 /* Transmit Cut Through */
-#define PRELOAD 16               /* 4 long words */
-
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
-
-#define EEPROM_OFFSET(a) ((u_short)((u_long)(a)))
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-#define	EWRK3IOCTL	SIOCDEVPRIVATE
-
-struct ewrk3_ioctl {
-	unsigned short cmd;                /* Command to run */
-	unsigned short len;                /* Length of the data buffer */
-	unsigned char  __user *data;       /* Pointer to the data buffer */
-};
-
-/*
-** Recognised commands for the driver
-*/
-#define EWRK3_GET_HWADDR	0x01 /* Get the hardware address */
-#define EWRK3_SET_HWADDR	0x02 /* Get the hardware address */
-#define EWRK3_SET_PROM  	0x03 /* Set Promiscuous Mode */
-#define EWRK3_CLR_PROM  	0x04 /* Clear Promiscuous Mode */
-#define EWRK3_SAY_BOO	        0x05 /* Say "Boo!" to the kernel log file */
-#define EWRK3_GET_MCA   	0x06 /* Get a multicast address */
-#define EWRK3_SET_MCA   	0x07 /* Set a multicast address */
-#define EWRK3_CLR_MCA    	0x08 /* Clear a multicast address */
-#define EWRK3_MCA_EN    	0x09 /* Enable a multicast address group */
-#define EWRK3_GET_STATS  	0x0a /* Get the driver statistics */
-#define EWRK3_CLR_STATS 	0x0b /* Zero out the driver statistics */
-#define EWRK3_GET_CSR   	0x0c /* Get the CSR Register contents */
-#define EWRK3_SET_CSR   	0x0d /* Set the CSR Register contents */
-#define EWRK3_GET_EEPROM   	0x0e /* Get the EEPROM contents */
-#define EWRK3_SET_EEPROM	0x0f /* Set the EEPROM contents */
-#define EWRK3_GET_CMR   	0x10 /* Get the CMR Register contents */
-#define EWRK3_CLR_TX_CUT_THRU  	0x11 /* Clear the TX cut through mode */
-#define EWRK3_SET_TX_CUT_THRU	0x12 /* Set the TX cut through mode */
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
index b5afe21..ee26ce7 100644
--- a/drivers/net/ethernet/dlink/Kconfig
+++ b/drivers/net/ethernet/dlink/Kconfig
@@ -5,7 +5,7 @@
 config NET_VENDOR_DLINK
 	bool "D-Link devices"
 	default y
-	depends on PCI || PARPORT
+	depends on PCI
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y
 	  and read the Ethernet-HOWTO, available from
@@ -18,36 +18,6 @@
 
 if NET_VENDOR_DLINK
 
-config DE600
-	tristate "D-Link DE600 pocket adapter support"
-	depends on PARPORT
-	---help---
-	  This is a network (Ethernet) device which attaches to your parallel
-	  port. Read <file:Documentation/networking/DLINK.txt> as well as the
-	  Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>, if you want to use
-	  this. It is possible to have several devices share a single parallel
-	  port and it is safe to compile the corresponding drivers into the
-	  kernel.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called de600.
-
-config DE620
-	tristate "D-Link DE620 pocket adapter support"
-	depends on PARPORT
-	---help---
-	  This is a network (Ethernet) device which attaches to your parallel
-	  port. Read <file:Documentation/networking/DLINK.txt> as well as the
-	  Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>, if you want to use
-	  this. It is possible to have several devices share a single parallel
-	  port and it is safe to compile the corresponding drivers into the
-	  kernel.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called de620.
-
 config DL2K
 	tristate "DL2000/TC902x-based Gigabit Ethernet support"
 	depends on PCI
diff --git a/drivers/net/ethernet/dlink/Makefile b/drivers/net/ethernet/dlink/Makefile
index c705eaa..40085f6 100644
--- a/drivers/net/ethernet/dlink/Makefile
+++ b/drivers/net/ethernet/dlink/Makefile
@@ -2,7 +2,5 @@
 # Makefile for the D-Link network device drivers.
 #
 
-obj-$(CONFIG_DE600) += de600.o
-obj-$(CONFIG_DE620) += de620.o
 obj-$(CONFIG_DL2K) += dl2k.o
 obj-$(CONFIG_SUNDANCE) += sundance.o
diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c
deleted file mode 100644
index 414f0ee..0000000
--- a/drivers/net/ethernet/dlink/de600.c
+++ /dev/null
@@ -1,529 +0,0 @@
-static const char version[] = "de600.c: $Revision: 1.41-2.5 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
-/*
- *	de600.c
- *
- *	Linux driver for the D-Link DE-600 Ethernet pocket adapter.
- *
- *	Portions (C) Copyright 1993, 1994 by Bjorn Ekwall
- *	The Author may be reached as bj0rn@blox.se
- *
- *	Based on adapter information gathered from DE600.ASM by D-Link Inc.,
- *	as included on disk C in the v.2.11 of PC/TCP from FTP Software.
- *	For DE600.asm:
- *		Portions (C) Copyright 1990 D-Link, Inc.
- *		Copyright, 1988-1992, Russell Nelson, Crynwr Software
- *
- *	Adapted to the sample network driver core for linux,
- *	written by: Donald Becker <becker@super.org>
- *		(Now at <becker@scyld.com>)
- *
- **************************************************************/
-/*
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2, or (at your option)
- *	any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License
- *	along with this program; if not, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************/
-
-/* Add more time here if your adapter won't work OK: */
-#define DE600_SLOW_DOWN	udelay(delay_time)
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "de600.h"
-
-static bool check_lost = true;
-module_param(check_lost, bool, 0);
-MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600");
-
-static unsigned int delay_time = 10;
-module_param(delay_time, int, 0);
-MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
-
-
-/*
- * D-Link driver variables:
- */
-
-static volatile int		rx_page;
-
-#define TX_PAGES 2
-static volatile int		tx_fifo[TX_PAGES];
-static volatile int		tx_fifo_in;
-static volatile int		tx_fifo_out;
-static volatile int		free_tx_pages = TX_PAGES;
-static int			was_down;
-static DEFINE_SPINLOCK(de600_lock);
-
-static inline u8 de600_read_status(struct net_device *dev)
-{
-	u8 status;
-
-	outb_p(STATUS, DATA_PORT);
-	status = inb(STATUS_PORT);
-	outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
-
-	return status;
-}
-
-static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
-{
-	/* dev used by macros */
-	u8 lo;
-	outb_p((type), DATA_PORT);
-	lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
-	outb_p((type) | HI_NIBBLE, DATA_PORT);
-	return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-
-static int de600_open(struct net_device *dev)
-{
-	unsigned long flags;
-	int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
-	if (ret) {
-		printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
-		return ret;
-	}
-	spin_lock_irqsave(&de600_lock, flags);
-	ret = adapter_init(dev);
-	spin_unlock_irqrestore(&de600_lock, flags);
-	return ret;
-}
-
-/*
- * The inverse routine to de600_open().
- */
-
-static int de600_close(struct net_device *dev)
-{
-	select_nic();
-	rx_page = 0;
-	de600_put_command(RESET);
-	de600_put_command(STOP_RESET);
-	de600_put_command(0);
-	select_prn();
-	free_irq(DE600_IRQ, dev);
-	return 0;
-}
-
-static inline void trigger_interrupt(struct net_device *dev)
-{
-	de600_put_command(FLIP_IRQ);
-	select_prn();
-	DE600_SLOW_DOWN;
-	select_nic();
-	de600_put_command(0);
-}
-
-/*
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-
-static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	unsigned long flags;
-	int	transmit_from;
-	int	len;
-	int	tickssofar;
-	u8	*buffer = skb->data;
-	int	i;
-
-	if (free_tx_pages <= 0) {	/* Do timeouts, to avoid hangs. */
-		tickssofar = jiffies - dev_trans_start(dev);
-		if (tickssofar < HZ/20)
-			return NETDEV_TX_BUSY;
-		/* else */
-		printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
-		/* Restart the adapter. */
-		spin_lock_irqsave(&de600_lock, flags);
-		if (adapter_init(dev)) {
-			spin_unlock_irqrestore(&de600_lock, flags);
-			return NETDEV_TX_BUSY;
-		}
-		spin_unlock_irqrestore(&de600_lock, flags);
-	}
-
-	/* Start real output */
-	pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages);
-
-	if ((len = skb->len) < RUNT)
-		len = RUNT;
-
-	spin_lock_irqsave(&de600_lock, flags);
-	select_nic();
-	tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
-	tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
-
-	if(check_lost)
-	{
-		/* This costs about 40 instructions per packet... */
-		de600_setup_address(NODE_ADDRESS, RW_ADDR);
-		de600_read_byte(READ_DATA, dev);
-		if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
-			if (adapter_init(dev)) {
-				spin_unlock_irqrestore(&de600_lock, flags);
-				return NETDEV_TX_BUSY;
-			}
-		}
-	}
-
-	de600_setup_address(transmit_from, RW_ADDR);
-	for (i = 0;  i < skb->len ; ++i, ++buffer)
-		de600_put_byte(*buffer);
-	for (; i < len; ++i)
-		de600_put_byte(0);
-
-	if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
-		dev->trans_start = jiffies;
-		netif_start_queue(dev); /* allow more packets into adapter */
-		/* Send page and generate a faked interrupt */
-		de600_setup_address(transmit_from, TX_ADDR);
-		de600_put_command(TX_ENABLE);
-	}
-	else {
-		if (free_tx_pages)
-			netif_start_queue(dev);
-		else
-			netif_stop_queue(dev);
-		select_prn();
-	}
-	spin_unlock_irqrestore(&de600_lock, flags);
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-
-static irqreturn_t de600_interrupt(int irq, void *dev_id)
-{
-	struct net_device	*dev = dev_id;
-	u8		irq_status;
-	int		retrig = 0;
-	int		boguscount = 0;
-
-	spin_lock(&de600_lock);
-
-	select_nic();
-	irq_status = de600_read_status(dev);
-
-	do {
-		pr_debug("de600_interrupt (%02X)\n", irq_status);
-
-		if (irq_status & RX_GOOD)
-			de600_rx_intr(dev);
-		else if (!(irq_status & RX_BUSY))
-			de600_put_command(RX_ENABLE);
-
-		/* Any transmission in progress? */
-		if (free_tx_pages < TX_PAGES)
-			retrig = de600_tx_intr(dev, irq_status);
-		else
-			retrig = 0;
-
-		irq_status = de600_read_status(dev);
-	} while ( (irq_status & RX_GOOD) || ((++boguscount < 100) && retrig) );
-	/*
-	 * Yeah, it _looks_ like busy waiting, smells like busy waiting
-	 * and I know it's not PC, but please, it will only occur once
-	 * in a while and then only for a loop or so (< 1ms for sure!)
-	 */
-
-	/* Enable adapter interrupts */
-	select_prn();
-	if (retrig)
-		trigger_interrupt(dev);
-	spin_unlock(&de600_lock);
-	return IRQ_HANDLED;
-}
-
-static int de600_tx_intr(struct net_device *dev, int irq_status)
-{
-	/*
-	 * Returns 1 if tx still not done
-	 */
-
-	/* Check if current transmission is done yet */
-	if (irq_status & TX_BUSY)
-		return 1; /* tx not done, try again */
-
-	/* else */
-	/* If last transmission OK then bump fifo index */
-	if (!(irq_status & TX_FAILED16)) {
-		tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
-		++free_tx_pages;
-		dev->stats.tx_packets++;
-		netif_wake_queue(dev);
-	}
-
-	/* More to send, or resend last packet? */
-	if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
-		dev->trans_start = jiffies;
-		de600_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
-		de600_put_command(TX_ENABLE);
-		return 1;
-	}
-	/* else */
-
-	return 0;
-}
-
-/*
- * We have a good packet, get it out of the adapter.
- */
-static void de600_rx_intr(struct net_device *dev)
-{
-	struct sk_buff	*skb;
-	int		i;
-	int		read_from;
-	int		size;
-	unsigned char	*buffer;
-
-	/* Get size of received packet */
-	size = de600_read_byte(RX_LEN, dev);	/* low byte */
-	size += (de600_read_byte(RX_LEN, dev) << 8);	/* high byte */
-	size -= 4;	/* Ignore trailing 4 CRC-bytes */
-
-	/* Tell adapter where to store next incoming packet, enable receiver */
-	read_from = rx_page_adr();
-	next_rx_page();
-	de600_put_command(RX_ENABLE);
-
-	if ((size < 32)  ||  (size > 1535)) {
-		printk(KERN_WARNING "%s: Bogus packet size %d.\n", dev->name, size);
-		if (size > 10000)
-			adapter_init(dev);
-		return;
-	}
-
-	skb = netdev_alloc_skb(dev, size + 2);
-	if (skb == NULL) {
-		printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-		return;
-	}
-	/* else */
-
-	skb_reserve(skb,2);	/* Align */
-
-	/* 'skb->data' points to the start of sk_buff data area. */
-	buffer = skb_put(skb,size);
-
-	/* copy the packet into the buffer */
-	de600_setup_address(read_from, RW_ADDR);
-	for (i = size; i > 0; --i, ++buffer)
-		*buffer = de600_read_byte(READ_DATA, dev);
-
-	skb->protocol=eth_type_trans(skb,dev);
-
-	netif_rx(skb);
-
-	/* update stats */
-	dev->stats.rx_packets++; /* count all receives */
-	dev->stats.rx_bytes += size; /* count all received bytes */
-
-	/*
-	 * If any worth-while packets have been received, netif_rx()
-	 * will work on them when we get to the tasklets.
-	 */
-}
-
-static const struct net_device_ops de600_netdev_ops = {
-	.ndo_open		= de600_open,
-	.ndo_stop		= de600_close,
-	.ndo_start_xmit		= de600_start_xmit,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-
-static struct net_device * __init de600_probe(void)
-{
-	int	i;
-	struct net_device *dev;
-	int err;
-
-	dev = alloc_etherdev(0);
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-
-	if (!request_region(DE600_IO, 3, "de600")) {
-		printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
-		err = -EBUSY;
-		goto out;
-	}
-
-	printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name);
-	/* Alpha testers must have the version number to report bugs. */
-	pr_debug("%s", version);
-
-	/* probe for adapter */
-	err = -ENODEV;
-	rx_page = 0;
-	select_nic();
-	(void)de600_read_status(dev);
-	de600_put_command(RESET);
-	de600_put_command(STOP_RESET);
-	if (de600_read_status(dev) & 0xf0) {
-		printk(": not at I/O %#3x.\n", DATA_PORT);
-		goto out1;
-	}
-
-	/*
-	 * Maybe we found one,
-	 * have to check if it is a D-Link DE-600 adapter...
-	 */
-
-	/* Get the adapter ethernet address from the ROM */
-	de600_setup_address(NODE_ADDRESS, RW_ADDR);
-	for (i = 0; i < ETH_ALEN; i++) {
-		dev->dev_addr[i] = de600_read_byte(READ_DATA, dev);
-		dev->broadcast[i] = 0xff;
-	}
-
-	/* Check magic code */
-	if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) {
-		/* OK, install real address */
-		dev->dev_addr[0] = 0x00;
-		dev->dev_addr[1] = 0x80;
-		dev->dev_addr[2] = 0xc8;
-		dev->dev_addr[3] &= 0x0f;
-		dev->dev_addr[3] |= 0x70;
-	} else {
-		printk(" not identified in the printer port\n");
-		goto out1;
-	}
-
-	printk(", Ethernet Address: %pM\n", dev->dev_addr);
-
-	dev->netdev_ops = &de600_netdev_ops;
-
-	dev->flags&=~IFF_MULTICAST;
-
-	select_prn();
-
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-
-	return dev;
-
-out1:
-	release_region(DE600_IO, 3);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static int adapter_init(struct net_device *dev)
-{
-	int	i;
-
-	select_nic();
-	rx_page = 0; /* used by RESET */
-	de600_put_command(RESET);
-	de600_put_command(STOP_RESET);
-
-	/* Check if it is still there... */
-	/* Get the some bytes of the adapter ethernet address from the ROM */
-	de600_setup_address(NODE_ADDRESS, RW_ADDR);
-	de600_read_byte(READ_DATA, dev);
-	if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
-	    (de600_read_byte(READ_DATA, dev) != 0x15)) {
-	/* was: if (de600_read_status(dev) & 0xf0) { */
-		printk("Something has happened to the DE-600!  Please check it and do a new ifconfig!\n");
-		/* Goodbye, cruel world... */
-		dev->flags &= ~IFF_UP;
-		de600_close(dev);
-		was_down = 1;
-		netif_stop_queue(dev); /* Transmit busy...  */
-		return 1; /* failed */
-	}
-
-	if (was_down) {
-		printk(KERN_INFO "%s: Thanks, I feel much better now!\n", dev->name);
-		was_down = 0;
-	}
-
-	tx_fifo_in = 0;
-	tx_fifo_out = 0;
-	free_tx_pages = TX_PAGES;
-
-
-	/* set the ether address. */
-	de600_setup_address(NODE_ADDRESS, RW_ADDR);
-	for (i = 0; i < ETH_ALEN; i++)
-		de600_put_byte(dev->dev_addr[i]);
-
-	/* where to start saving incoming packets */
-	rx_page = RX_BP | RX_BASE_PAGE;
-	de600_setup_address(MEM_4K, RW_ADDR);
-	/* Enable receiver */
-	de600_put_command(RX_ENABLE);
-	select_prn();
-
-	netif_start_queue(dev);
-
-	return 0; /* OK */
-}
-
-static struct net_device *de600_dev;
-
-static int __init de600_init(void)
-{
-	de600_dev = de600_probe();
-	if (IS_ERR(de600_dev))
-		return PTR_ERR(de600_dev);
-	return 0;
-}
-
-static void __exit de600_exit(void)
-{
-	unregister_netdev(de600_dev);
-	release_region(DE600_IO, 3);
-	free_netdev(de600_dev);
-}
-
-module_init(de600_init);
-module_exit(de600_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de600.h b/drivers/net/ethernet/dlink/de600.h
deleted file mode 100644
index e80ecba..0000000
--- a/drivers/net/ethernet/dlink/de600.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/**************************************************
- *                                                *
- * Definition of D-Link Ethernet Pocket adapter   *
- *                                                *
- **************************************************/
-/*
- * D-Link Ethernet pocket adapter ports
- */
-/*
- * OK, so I'm cheating, but there are an awful lot of
- * reads and writes in order to get anything in and out
- * of the DE-600 with 4 bits at a time in the parallel port,
- * so every saved instruction really helps :-)
- */
-
-#ifndef DE600_IO
-#define DE600_IO	0x378
-#endif
-
-#define DATA_PORT	(DE600_IO)
-#define STATUS_PORT	(DE600_IO + 1)
-#define COMMAND_PORT	(DE600_IO + 2)
-
-#ifndef DE600_IRQ
-#define DE600_IRQ	7
-#endif
-/*
- * It really should look like this, and autoprobing as well...
- *
-#define DATA_PORT	(dev->base_addr + 0)
-#define STATUS_PORT	(dev->base_addr + 1)
-#define COMMAND_PORT	(dev->base_addr + 2)
-#define DE600_IRQ	dev->irq
- */
-
-/*
- * D-Link COMMAND_PORT commands
- */
-#define SELECT_NIC	0x04 /* select Network Interface Card */
-#define SELECT_PRN	0x1c /* select Printer */
-#define NML_PRN		0xec /* normal Printer situation */
-#define IRQEN		0x10 /* enable IRQ line */
-
-/*
- * D-Link STATUS_PORT
- */
-#define RX_BUSY		0x80
-#define RX_GOOD		0x40
-#define TX_FAILED16	0x10
-#define TX_BUSY		0x08
-
-/*
- * D-Link DATA_PORT commands
- * command in low 4 bits
- * data in high 4 bits
- * select current data nibble with HI_NIBBLE bit
- */
-#define WRITE_DATA	0x00 /* write memory */
-#define READ_DATA	0x01 /* read memory */
-#define STATUS		0x02 /* read  status register */
-#define COMMAND		0x03 /* write command register (see COMMAND below) */
-#define NULL_COMMAND	0x04 /* null command */
-#define RX_LEN		0x05 /* read  received packet length */
-#define TX_ADDR		0x06 /* set adapter transmit memory address */
-#define RW_ADDR		0x07 /* set adapter read/write memory address */
-#define HI_NIBBLE	0x08 /* read/write the high nibble of data,
-				or-ed with rest of command */
-
-/*
- * command register, accessed through DATA_PORT with low bits = COMMAND
- */
-#define RX_ALL		0x01 /* PROMISCUOUS */
-#define RX_BP		0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
-#define RX_MBP		0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
-
-#define TX_ENABLE	0x04 /* bit 2 */
-#define RX_ENABLE	0x08 /* bit 3 */
-
-#define RESET		0x80 /* set bit 7 high */
-#define STOP_RESET	0x00 /* set bit 7 low */
-
-/*
- * data to command register
- * (high 4 bits in write to DATA_PORT)
- */
-#define RX_PAGE2_SELECT	0x10 /* bit 4, only 2 pages to select */
-#define RX_BASE_PAGE	0x20 /* bit 5, always set when specifying RX_ADDR */
-#define FLIP_IRQ	0x40 /* bit 6 */
-
-/*
- * D-Link adapter internal memory:
- *
- * 0-2K 1:st transmit page (send from pointer up to 2K)
- * 2-4K	2:nd transmit page (send from pointer up to 4K)
- *
- * 4-6K 1:st receive page (data from 4K upwards)
- * 6-8K 2:nd receive page (data from 6K upwards)
- *
- * 8K+	Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
- */
-#define MEM_2K		0x0800 /* 2048 */
-#define MEM_4K		0x1000 /* 4096 */
-#define MEM_6K		0x1800 /* 6144 */
-#define NODE_ADDRESS	0x2000 /* 8192 */
-
-#define RUNT 60		/* Too small Ethernet packet */
-
-/**************************************************
- *                                                *
- *             End of definition                  *
- *                                                *
- **************************************************/
-
-/*
- * Index to functions, as function prototypes.
- */
-/* Routines used internally. (See "convenience macros") */
-static u8	de600_read_status(struct net_device *dev);
-static u8	de600_read_byte(unsigned char type, struct net_device *dev);
-
-/* Put in the device structure. */
-static int	de600_open(struct net_device *dev);
-static int	de600_close(struct net_device *dev);
-static int	de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de600_interrupt(int irq, void *dev_id);
-static int	de600_tx_intr(struct net_device *dev, int irq_status);
-static void	de600_rx_intr(struct net_device *dev);
-
-/* Initialization */
-static void	trigger_interrupt(struct net_device *dev);
-static int	adapter_init(struct net_device *dev);
-
-/*
- * Convenience macros/functions for D-Link adapter
- */
-
-#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
-#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
-
-/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
-#define de600_put_byte(data) ( \
-	outb_p(((data) << 4)   | WRITE_DATA            , DATA_PORT), \
-	outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
-
-/*
- * The first two outb_p()'s below could perhaps be deleted if there
- * would be more delay in the last two. Not certain about it yet...
- */
-#define de600_put_command(cmd) ( \
-	outb_p(( rx_page        << 4)   | COMMAND            , DATA_PORT), \
-	outb_p(( rx_page        & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
-	outb_p(((rx_page | cmd) << 4)   | COMMAND            , DATA_PORT), \
-	outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-
-#define de600_setup_address(addr,type) ( \
-	outb_p((((addr) << 4) & 0xf0) | type            , DATA_PORT), \
-	outb_p(( (addr)       & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
-	outb_p((((addr) >> 4) & 0xf0) | type            , DATA_PORT), \
-	outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
-
-#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
-
-/* Flip bit, only 2 pages */
-#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
-
-#define tx_page_adr(a) (((a) + 1) * MEM_2K)
diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c
deleted file mode 100644
index 2e2bc60..0000000
--- a/drivers/net/ethernet/dlink/de620.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- *	de620.c $Revision: 1.40 $ BETA
- *
- *
- *	Linux driver for the D-Link DE-620 Ethernet pocket adapter.
- *
- *	Portions (C) Copyright 1993, 1994 by Bjorn Ekwall <bj0rn@blox.se>
- *
- *	Based on adapter information gathered from DOS packetdriver
- *	sources from D-Link Inc:  (Special thanks to Henry Ngai of D-Link.)
- *		Portions (C) Copyright D-Link SYSTEM Inc. 1991, 1992
- *		Copyright, 1988, Russell Nelson, Crynwr Software
- *
- *	Adapted to the sample network driver core for linux,
- *	written by: Donald Becker <becker@super.org>
- *		(Now at <becker@scyld.com>)
- *
- *	Valuable assistance from:
- *		J. Joshua Kopper <kopper@rtsg.mot.com>
- *		Olav Kvittem <Olav.Kvittem@uninett.no>
- *		Germano Caronni <caronni@nessie.cs.id.ethz.ch>
- *		Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
- *
- *****************************************************************************/
-/*
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2, or (at your option)
- *	any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License
- *	along with this program; if not, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *****************************************************************************/
-static const char version[] =
-	"de620.c: $Revision: 1.40 $,  Bjorn Ekwall <bj0rn@blox.se>\n";
-
-/***********************************************************************
- *
- * "Tuning" section.
- *
- * Compile-time options: (see below for descriptions)
- * -DDE620_IO=0x378	(lpt1)
- * -DDE620_IRQ=7	(lpt1)
- * -DSHUTDOWN_WHEN_LOST
- * -DCOUNT_LOOPS
- * -DLOWSPEED
- * -DREAD_DELAY
- * -DWRITE_DELAY
- */
-
-/*
- * This driver assumes that the printer port is a "normal",
- * dumb, uni-directional port!
- * If your port is "fancy" in any way, please try to set it to "normal"
- * with your BIOS setup.  I have no access to machines with bi-directional
- * ports, so I can't test such a driver :-(
- * (Yes, I _know_ it is possible to use DE620 with bidirectional ports...)
- *
- * There are some clones of DE620 out there, with different names.
- * If the current driver does not recognize a clone, try to change
- * the following #define to:
- *
- * #define DE620_CLONE 1
- */
-#define DE620_CLONE 0
-
-/*
- * If the adapter has problems with high speeds, enable this #define
- * otherwise full printerport speed will be attempted.
- *
- * You can tune the READ_DELAY/WRITE_DELAY below if you enable LOWSPEED
- *
-#define LOWSPEED
- */
-
-#ifndef READ_DELAY
-#define READ_DELAY 100	/* adapter internal read delay in 100ns units */
-#endif
-
-#ifndef WRITE_DELAY
-#define WRITE_DELAY 100	/* adapter internal write delay in 100ns units */
-#endif
-
-/*
- * Enable this #define if you want the adapter to do a "ifconfig down" on
- * itself when we have detected that something is possibly wrong with it.
- * The default behaviour is to retry with "adapter_init()" until success.
- * This should be used for debugging purposes only.
- *
-#define SHUTDOWN_WHEN_LOST
- */
-
-#ifdef LOWSPEED
-/*
- * Enable this #define if you want to see debugging output that show how long
- * we have to wait before the DE-620 is ready for the next read/write/command.
- *
-#define COUNT_LOOPS
- */
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-/* Constant definitions for the DE-620 registers, commands and bits */
-#include "de620.h"
-
-typedef unsigned char byte;
-
-/*******************************************************
- *                                                     *
- * Definition of D-Link DE-620 Ethernet Pocket adapter *
- * See also "de620.h"                                  *
- *                                                     *
- *******************************************************/
-#ifndef DE620_IO /* Compile-time configurable */
-#define DE620_IO 0x378
-#endif
-
-#ifndef DE620_IRQ /* Compile-time configurable */
-#define DE620_IRQ	7
-#endif
-
-#define DATA_PORT	(dev->base_addr)
-#define STATUS_PORT	(dev->base_addr + 1)
-#define COMMAND_PORT	(dev->base_addr + 2)
-
-#define RUNT 60		/* Too small Ethernet packet */
-#define GIANT 1514	/* largest legal size packet, no fcs */
-
-/*
- * Force media with insmod:
- *	insmod de620.o bnc=1
- * or
- *	insmod de620.o utp=1
- *
- * Force io and/or irq with insmod:
- *	insmod de620.o io=0x378 irq=7
- *
- * Make a clone skip the Ethernet-address range check:
- *	insmod de620.o clone=1
- */
-static int bnc;
-static int utp;
-static int io  = DE620_IO;
-static int irq = DE620_IRQ;
-static int clone = DE620_CLONE;
-
-static spinlock_t de620_lock;
-
-module_param(bnc, int, 0);
-module_param(utp, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(clone, int, 0);
-MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)");
-MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)");
-MODULE_PARM_DESC(io, "DE-620 I/O base address,required");
-MODULE_PARM_DESC(irq, "DE-620 IRQ number,required");
-MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)");
-
-/***********************************************
- *                                             *
- * Index to functions, as function prototypes. *
- *                                             *
- ***********************************************/
-
-/*
- * Routines used internally. (See also "convenience macros.. below")
- */
-
-/* Put in the device structure. */
-static int	de620_open(struct net_device *);
-static int	de620_close(struct net_device *);
-static void	de620_set_multicast_list(struct net_device *);
-static int	de620_start_xmit(struct sk_buff *, struct net_device *);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de620_interrupt(int, void *);
-static int	de620_rx_intr(struct net_device *);
-
-/* Initialization */
-static int	adapter_init(struct net_device *);
-static int	read_eeprom(struct net_device *);
-
-
-/*
- * D-Link driver variables:
- */
-#define SCR_DEF NIBBLEMODE |INTON | SLEEP | AUTOTX
-#define	TCR_DEF RXPB			/* not used: | TXSUCINT | T16INT */
-#define DE620_RX_START_PAGE 12		/* 12 pages (=3k) reserved for tx */
-#define DEF_NIC_CMD IRQEN | ICEN | DS1
-
-static volatile byte	NIC_Cmd;
-static volatile byte	next_rx_page;
-static byte		first_rx_page;
-static byte		last_rx_page;
-static byte		EIPRegister;
-
-static struct nic {
-	byte	NodeID[6];
-	byte	RAM_Size;
-	byte	Model;
-	byte	Media;
-	byte	SCR;
-} nic_data;
-
-/**********************************************************
- *                                                        *
- * Convenience macros/functions for D-Link DE-620 adapter *
- *                                                        *
- **********************************************************/
-#define de620_tx_buffs(dd) (inb(STATUS_PORT) & (TXBF0 | TXBF1))
-#define de620_flip_ds(dd) NIC_Cmd ^= DS0 | DS1; outb(NIC_Cmd, COMMAND_PORT);
-
-/* Check for ready-status, and return a nibble (high 4 bits) for data input */
-#ifdef COUNT_LOOPS
-static int tot_cnt;
-#endif
-static inline byte
-de620_ready(struct net_device *dev)
-{
-	byte value;
-	register short int cnt = 0;
-
-	while ((((value = inb(STATUS_PORT)) & READY) == 0) && (cnt <= 1000))
-		++cnt;
-
-#ifdef COUNT_LOOPS
-	tot_cnt += cnt;
-#endif
-	return value & 0xf0; /* nibble */
-}
-
-static inline void
-de620_send_command(struct net_device *dev, byte cmd)
-{
-	de620_ready(dev);
-	if (cmd == W_DUMMY)
-		outb(NIC_Cmd, COMMAND_PORT);
-
-	outb(cmd, DATA_PORT);
-
-	outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-	de620_ready(dev);
-	outb(NIC_Cmd, COMMAND_PORT);
-}
-
-static inline void
-de620_put_byte(struct net_device *dev, byte value)
-{
-	/* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
-	de620_ready(dev);
-	outb(value, DATA_PORT);
-	de620_flip_ds(dev);
-}
-
-static inline byte
-de620_read_byte(struct net_device *dev)
-{
-	byte value;
-
-	/* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
-	value = de620_ready(dev); /* High nibble */
-	de620_flip_ds(dev);
-	value |= de620_ready(dev) >> 4; /* Low nibble */
-	return value;
-}
-
-static inline void
-de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
-{
-#ifndef LOWSPEED
-	byte uflip = NIC_Cmd ^ (DS0 | DS1);
-	byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
-	int bytes = count;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-#ifdef COUNT_LOOPS
-	tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-	/* No further optimization useful, the limit is in the adapter. */
-	for ( ; count > 0; --count, ++buffer) {
-		de620_put_byte(dev,*buffer);
-	}
-	for ( count = pad ; count > 0; --count, ++buffer) {
-		de620_put_byte(dev, 0);
-	}
-	de620_send_command(dev,W_DUMMY);
-#ifdef COUNT_LOOPS
-	/* trial debug output: loops per byte in de620_ready() */
-	printk("WRITE(%d)\n", tot_cnt/((bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
-	for ( ; count > 0; count -=2) {
-		outb(*buffer++, DATA_PORT);
-		outb(uflip, COMMAND_PORT);
-		outb(*buffer++, DATA_PORT);
-		outb(dflip, COMMAND_PORT);
-	}
-	de620_send_command(dev,W_DUMMY);
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_read_block(struct net_device *dev, byte *data, int count)
-{
-#ifndef LOWSPEED
-	byte value;
-	byte uflip = NIC_Cmd ^ (DS0 | DS1);
-	byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
-	int bytes = count;
-
-	tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-	/* No further optimization useful, the limit is in the adapter. */
-	while (count-- > 0) {
-		*data++ = de620_read_byte(dev);
-		de620_flip_ds(dev);
-	}
-#ifdef COUNT_LOOPS
-	/* trial debug output: loops per byte in de620_ready() */
-	printk("READ(%d)\n", tot_cnt/(2*(bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
-	while (count-- > 0) {
-		value = inb(STATUS_PORT) & 0xf0; /* High nibble */
-		outb(uflip, COMMAND_PORT);
-		*data++ = value | inb(STATUS_PORT) >> 4; /* Low nibble */
-		outb(dflip , COMMAND_PORT);
-	}
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_set_delay(struct net_device *dev)
-{
-	de620_ready(dev);
-	outb(W_DFR, DATA_PORT);
-	outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
-	de620_ready(dev);
-#ifdef LOWSPEED
-	outb(WRITE_DELAY, DATA_PORT);
-#else
-	outb(0, DATA_PORT);
-#endif
-	de620_flip_ds(dev);
-
-	de620_ready(dev);
-#ifdef LOWSPEED
-	outb(READ_DELAY, DATA_PORT);
-#else
-	outb(0, DATA_PORT);
-#endif
-	de620_flip_ds(dev);
-}
-
-static inline void
-de620_set_register(struct net_device *dev, byte reg, byte value)
-{
-	de620_ready(dev);
-	outb(reg, DATA_PORT);
-	outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
-	de620_put_byte(dev, value);
-}
-
-static inline byte
-de620_get_register(struct net_device *dev, byte reg)
-{
-	byte value;
-
-	de620_send_command(dev,reg);
-	value = de620_read_byte(dev);
-	de620_send_command(dev,W_DUMMY);
-
-	return value;
-}
-
-/*********************************************************************
- *
- * Open/initialize the board.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- *
- */
-static int de620_open(struct net_device *dev)
-{
-	int ret = request_irq(dev->irq, de620_interrupt, 0, dev->name, dev);
-	if (ret) {
-		printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
-		return ret;
-	}
-
-	if (adapter_init(dev)) {
-		ret = -EIO;
-		goto out_free_irq;
-	}
-
-	netif_start_queue(dev);
-	return 0;
-
-out_free_irq:
-	free_irq(dev->irq, dev);
-	return ret;
-}
-
-/************************************************
- *
- * The inverse routine to de620_open().
- *
- */
-
-static int de620_close(struct net_device *dev)
-{
-	netif_stop_queue(dev);
-	/* disable recv */
-	de620_set_register(dev, W_TCR, RXOFF);
-	free_irq(dev->irq, dev);
-	return 0;
-}
-
-/*********************************************
- *
- * Set or clear the multicast filter for this adaptor.
- * (no real multicast implemented for the DE-620, but she can be promiscuous...)
- *
- */
-
-static void de620_set_multicast_list(struct net_device *dev)
-{
-	if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-	{ /* Enable promiscuous mode */
-		de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
-	}
-	else
-	{ /* Disable promiscuous mode, use normal mode */
-		de620_set_register(dev, W_TCR, TCR_DEF);
-	}
-}
-
-/*******************************************************
- *
- * Handle timeouts on transmit
- */
-
-static void de620_timeout(struct net_device *dev)
-{
-	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
-	/* Restart the adapter. */
-	if (!adapter_init(dev)) /* maybe close it */
-		netif_wake_queue(dev);
-}
-
-/*******************************************************
- *
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	unsigned long flags;
-	int len;
-	byte *buffer = skb->data;
-	byte using_txbuf;
-
-	using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
-
-	netif_stop_queue(dev);
-
-
-	if ((len = skb->len) < RUNT)
-		len = RUNT;
-	if (len & 1) /* send an even number of bytes */
-		++len;
-
-	/* Start real output */
-
-	spin_lock_irqsave(&de620_lock, flags);
-	pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n",
-		(int)skb->len, using_txbuf);
-
-	/* select a free tx buffer. if there is one... */
-	switch (using_txbuf) {
-	default: /* both are free: use TXBF0 */
-	case TXBF1: /* use TXBF0 */
-		de620_send_command(dev,W_CR | RW0);
-		using_txbuf |= TXBF0;
-		break;
-
-	case TXBF0: /* use TXBF1 */
-		de620_send_command(dev,W_CR | RW1);
-		using_txbuf |= TXBF1;
-		break;
-
-	case (TXBF0 | TXBF1): /* NONE!!! */
-		printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
-		spin_unlock_irqrestore(&de620_lock, flags);
-		return NETDEV_TX_BUSY;
-	}
-	de620_write_block(dev, buffer, skb->len, len-skb->len);
-
-	if(!(using_txbuf == (TXBF0 | TXBF1)))
-		netif_wake_queue(dev);
-
-	dev->stats.tx_packets++;
-	spin_unlock_irqrestore(&de620_lock, flags);
-	dev_kfree_skb (skb);
-	return NETDEV_TX_OK;
-}
-
-/*****************************************************
- *
- * Handle the network interface interrupts.
- *
- */
-static irqreturn_t
-de620_interrupt(int irq_in, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	byte irq_status;
-	int bogus_count = 0;
-	int again = 0;
-
-	spin_lock(&de620_lock);
-
-	/* Read the status register (_not_ the status port) */
-	irq_status = de620_get_register(dev, R_STS);
-
-	pr_debug("de620_interrupt (%2.2X)\n", irq_status);
-
-	if (irq_status & RXGOOD) {
-		do {
-			again = de620_rx_intr(dev);
-			pr_debug("again=%d\n", again);
-		}
-		while (again && (++bogus_count < 100));
-	}
-
-	if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
-		netif_wake_queue(dev);
-
-	spin_unlock(&de620_lock);
-	return IRQ_HANDLED;
-}
-
-/**************************************
- *
- * Get a packet from the adapter
- *
- * Send it "upstairs"
- *
- */
-static int de620_rx_intr(struct net_device *dev)
-{
-	struct header_buf {
-		byte		status;
-		byte		Rx_NextPage;
-		unsigned short	Rx_ByteCount;
-	} header_buf;
-	struct sk_buff *skb;
-	int size;
-	byte *buffer;
-	byte pagelink;
-	byte curr_page;
-
-	pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page);
-
-	/* Tell the adapter that we are going to read data, and from where */
-	de620_send_command(dev, W_CR | RRN);
-	de620_set_register(dev, W_RSA1, next_rx_page);
-	de620_set_register(dev, W_RSA0, 0);
-
-	/* Deep breath, and away we goooooo */
-	de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf));
-	pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n",
-		header_buf.status, header_buf.Rx_NextPage,
-		header_buf.Rx_ByteCount);
-
-	/* Plausible page header? */
-	pagelink = header_buf.Rx_NextPage;
-	if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
-		/* Ouch... Forget it! Skip all and start afresh... */
-		printk(KERN_WARNING "%s: Ring overrun? Restoring...\n", dev->name);
-		/* You win some, you lose some. And sometimes plenty... */
-		adapter_init(dev);
-		netif_wake_queue(dev);
-		dev->stats.rx_over_errors++;
-		return 0;
-	}
-
-	/* OK, this look good, so far. Let's see if it's consistent... */
-	/* Let's compute the start of the next packet, based on where we are */
-	pagelink = next_rx_page +
-		((header_buf.Rx_ByteCount + (4 - 1 + 0x100)) >> 8);
-
-	/* Are we going to wrap around the page counter? */
-	if (pagelink > last_rx_page)
-		pagelink -= (last_rx_page - first_rx_page + 1);
-
-	/* Is the _computed_ next page number equal to what the adapter says? */
-	if (pagelink != header_buf.Rx_NextPage) {
-		/* Naah, we'll skip this packet. Probably bogus data as well */
-		printk(KERN_WARNING "%s: Page link out of sync! Restoring...\n", dev->name);
-		next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
-		de620_send_command(dev, W_DUMMY);
-		de620_set_register(dev, W_NPRF, next_rx_page);
-		dev->stats.rx_over_errors++;
-		return 0;
-	}
-	next_rx_page = pagelink;
-
-	size = header_buf.Rx_ByteCount - 4;
-	if ((size < RUNT) || (GIANT < size)) {
-		printk(KERN_WARNING "%s: Illegal packet size: %d!\n", dev->name, size);
-	}
-	else { /* Good packet? */
-		skb = netdev_alloc_skb(dev, size + 2);
-		if (skb == NULL) { /* Yeah, but no place to put it... */
-			printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-			dev->stats.rx_dropped++;
-		}
-		else { /* Yep! Go get it! */
-			skb_reserve(skb,2);	/* Align */
-			/* skb->data points to the start of sk_buff data area */
-			buffer = skb_put(skb,size);
-			/* copy the packet into the buffer */
-			de620_read_block(dev, buffer, size);
-			pr_debug("Read %d bytes\n", size);
-			skb->protocol=eth_type_trans(skb,dev);
-			netif_rx(skb); /* deliver it "upstairs" */
-			/* count all receives */
-			dev->stats.rx_packets++;
-			dev->stats.rx_bytes += size;
-		}
-	}
-
-	/* Let's peek ahead to see if we have read the last current packet */
-	/* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */
-	curr_page = de620_get_register(dev, R_CPR);
-	de620_set_register(dev, W_NPRF, next_rx_page);
-	pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page);
-
-	return next_rx_page != curr_page; /* That was slightly tricky... */
-}
-
-/*********************************************
- *
- * Reset the adapter to a known state
- *
- */
-static int adapter_init(struct net_device *dev)
-{
-	int i;
-	static int was_down;
-
-	if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
-		EIPRegister = NCTL0;
-		if (nic_data.Media != 1)
-			EIPRegister |= NIS0;	/* not BNC */
-	}
-	else if (nic_data.Model == 2) { /* UTP */
-		EIPRegister = NCTL0 | NIS0;
-	}
-
-	if (utp)
-		EIPRegister = NCTL0 | NIS0;
-	if (bnc)
-		EIPRegister = NCTL0;
-
-	de620_send_command(dev, W_CR | RNOP | CLEAR);
-	de620_send_command(dev, W_CR | RNOP);
-
-	de620_set_register(dev, W_SCR, SCR_DEF);
-	/* disable recv to wait init */
-	de620_set_register(dev, W_TCR, RXOFF);
-
-	/* Set the node ID in the adapter */
-	for (i = 0; i < 6; ++i) { /* W_PARn = 0xaa + n */
-		de620_set_register(dev, W_PAR0 + i, dev->dev_addr[i]);
-	}
-
-	de620_set_register(dev, W_EIP, EIPRegister);
-
-	next_rx_page = first_rx_page = DE620_RX_START_PAGE;
-	if (nic_data.RAM_Size)
-		last_rx_page = nic_data.RAM_Size - 1;
-	else /* 64k RAM */
-		last_rx_page = 255;
-
-	de620_set_register(dev, W_SPR, first_rx_page); /* Start Page Register*/
-	de620_set_register(dev, W_EPR, last_rx_page);  /* End Page Register */
-	de620_set_register(dev, W_CPR, first_rx_page);/*Current Page Register*/
-	de620_send_command(dev, W_NPR | first_rx_page); /* Next Page Register*/
-	de620_send_command(dev, W_DUMMY);
-	de620_set_delay(dev);
-
-	/* Final sanity check: Anybody out there? */
-	/* Let's hope some bits from the statusregister make a good check */
-#define CHECK_MASK (  0 | TXSUC |  T16  |  0  | RXCRC | RXSHORT |  0  |  0  )
-#define CHECK_OK   (  0 |   0   |  0    |  0  |   0   |   0     |  0  |  0  )
-        /* success:   X     0      0       X      0       0        X     X  */
-        /* ignore:   EEDI                RXGOOD                   COLS  LNKS*/
-
-	if (((i = de620_get_register(dev, R_STS)) & CHECK_MASK) != CHECK_OK) {
-		printk(KERN_ERR "%s: Something has happened to the DE-620!  Please check it"
-#ifdef SHUTDOWN_WHEN_LOST
-			" and do a new ifconfig"
-#endif
-			"! (%02x)\n", dev->name, i);
-#ifdef SHUTDOWN_WHEN_LOST
-		/* Goodbye, cruel world... */
-		dev->flags &= ~IFF_UP;
-		de620_close(dev);
-#endif
-		was_down = 1;
-		return 1; /* failed */
-	}
-	if (was_down) {
-		printk(KERN_WARNING "%s: Thanks, I feel much better now!\n", dev->name);
-		was_down = 0;
-	}
-
-	/* All OK, go ahead... */
-	de620_set_register(dev, W_TCR, TCR_DEF);
-
-	return 0; /* all ok */
-}
-
-static const struct net_device_ops de620_netdev_ops = {
-	.ndo_open 		= de620_open,
-	.ndo_stop 		= de620_close,
-	.ndo_start_xmit 	= de620_start_xmit,
-	.ndo_tx_timeout 	= de620_timeout,
-	.ndo_set_rx_mode	= de620_set_multicast_list,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/******************************************************************************
- *
- * Only start-up code below
- *
- */
-/****************************************
- *
- * Check if there is a DE-620 connected
- */
-struct net_device * __init de620_probe(int unit)
-{
-	byte checkbyte = 0xa5;
-	struct net_device *dev;
-	int err = -ENOMEM;
-	int i;
-
-	dev = alloc_etherdev(0);
-	if (!dev)
-		goto out;
-
-	spin_lock_init(&de620_lock);
-
-	/*
-	 * This is where the base_addr and irq gets set.
-	 * Tunable at compile-time and insmod-time
-	 */
-	dev->base_addr = io;
-	dev->irq       = irq;
-
-	/* allow overriding parameters on command line */
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-	}
-
-	pr_debug("%s", version);
-
-	printk(KERN_INFO "D-Link DE-620 pocket adapter");
-
-	if (!request_region(dev->base_addr, 3, "de620")) {
-		printk(" io 0x%3lX, which is busy.\n", dev->base_addr);
-		err = -EBUSY;
-		goto out1;
-	}
-
-	/* Initially, configure basic nibble mode, so we can read the EEPROM */
-	NIC_Cmd = DEF_NIC_CMD;
-	de620_set_register(dev, W_EIP, EIPRegister);
-
-	/* Anybody out there? */
-	de620_set_register(dev, W_CPR, checkbyte);
-	checkbyte = de620_get_register(dev, R_CPR);
-
-	if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) {
-		printk(" not identified in the printer port\n");
-		err = -ENODEV;
-		goto out2;
-	}
-
-	/* else, got it! */
-	dev->dev_addr[0] = nic_data.NodeID[0];
-	for (i = 1; i < ETH_ALEN; i++) {
-		dev->dev_addr[i] = nic_data.NodeID[i];
-		dev->broadcast[i] = 0xff;
-	}
-
-	printk(", Ethernet Address: %pM", dev->dev_addr);
-
-	printk(" (%dk RAM,",
-		(nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
-
-	if (nic_data.Media == 1)
-		printk(" BNC)\n");
-	else
-		printk(" UTP)\n");
-
-	dev->netdev_ops = &de620_netdev_ops;
-	dev->watchdog_timeo	= HZ*2;
-
-	/* base_addr and irq are already set, see above! */
-
-	/* dump eeprom */
-	pr_debug("\nEEPROM contents:\n"
-		"RAM_Size = 0x%02X\n"
-		"NodeID = %pM\n"
-		"Model = %d\n"
-		"Media = %d\n"
-		"SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID,
-		nic_data.Model, nic_data.Media, nic_data.SCR);
-
-	err = register_netdev(dev);
-	if (err)
-		goto out2;
-	return dev;
-
-out2:
-	release_region(dev->base_addr, 3);
-out1:
-	free_netdev(dev);
-out:
-	return ERR_PTR(err);
-}
-
-/**********************************
- *
- * Read info from on-board EEPROM
- *
- * Note: Bitwise serial I/O to/from the EEPROM vi the status _register_!
- */
-#define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
-
-static unsigned short __init ReadAWord(struct net_device *dev, int from)
-{
-	unsigned short data;
-	int nbits;
-
-	/* cs   [__~~] SET SEND STATE */
-	/* di   [____]                */
-	/* sck  [_~~_]                */
-	sendit(dev, 0); sendit(dev, 1); sendit(dev, 5); sendit(dev, 4);
-
-	/* Send the 9-bit address from where we want to read the 16-bit word */
-	for (nbits = 9; nbits > 0; --nbits, from <<= 1) {
-		if (from & 0x0100) { /* bit set? */
-			/* cs    [~~~~] SEND 1 */
-			/* di    [~~~~]        */
-			/* sck   [_~~_]        */
-			sendit(dev, 6); sendit(dev, 7); sendit(dev, 7); sendit(dev, 6);
-		}
-		else {
-			/* cs    [~~~~] SEND 0 */
-			/* di    [____]        */
-			/* sck   [_~~_]        */
-			sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
-		}
-	}
-
-	/* Shift in the 16-bit word. The bits appear serially in EEDI (=0x80) */
-	for (data = 0, nbits = 16; nbits > 0; --nbits) {
-		/* cs    [~~~~] SEND 0 */
-		/* di    [____]        */
-		/* sck   [_~~_]        */
-		sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
-		data = (data << 1) | ((de620_get_register(dev, R_STS) & EEDI) >> 7);
-	}
-	/* cs    [____] RESET SEND STATE */
-	/* di    [____]                  */
-	/* sck   [_~~_]                  */
-	sendit(dev, 0); sendit(dev, 1); sendit(dev, 1); sendit(dev, 0);
-
-	return data;
-}
-
-static int __init read_eeprom(struct net_device *dev)
-{
-	unsigned short wrd;
-
-	/* D-Link Ethernet addresses are in the series  00:80:c8:7X:XX:XX:XX */
-	wrd = ReadAWord(dev, 0x1aa);	/* bytes 0 + 1 of NodeID */
-	if (!clone && (wrd != htons(0x0080))) /* Valid D-Link ether sequence? */
-		return -1; /* Nope, not a DE-620 */
-	nic_data.NodeID[0] = wrd & 0xff;
-	nic_data.NodeID[1] = wrd >> 8;
-
-	wrd = ReadAWord(dev, 0x1ab);	/* bytes 2 + 3 of NodeID */
-	if (!clone && ((wrd & 0xff) != 0xc8)) /* Valid D-Link ether sequence? */
-		return -1; /* Nope, not a DE-620 */
-	nic_data.NodeID[2] = wrd & 0xff;
-	nic_data.NodeID[3] = wrd >> 8;
-
-	wrd = ReadAWord(dev, 0x1ac);	/* bytes 4 + 5 of NodeID */
-	nic_data.NodeID[4] = wrd & 0xff;
-	nic_data.NodeID[5] = wrd >> 8;
-
-	wrd = ReadAWord(dev, 0x1ad);	/* RAM size in pages (256 bytes). 0 = 64k */
-	nic_data.RAM_Size = (wrd >> 8);
-
-	wrd = ReadAWord(dev, 0x1ae);	/* hardware model (CT = 3) */
-	nic_data.Model = (wrd & 0xff);
-
-	wrd = ReadAWord(dev, 0x1af); /* media (indicates BNC/UTP) */
-	nic_data.Media = (wrd & 0xff);
-
-	wrd = ReadAWord(dev, 0x1a8); /* System Configuration Register */
-	nic_data.SCR = (wrd >> 8);
-
-	return 0; /* no errors */
-}
-
-/******************************************************************************
- *
- * Loadable module skeleton
- *
- */
-#ifdef MODULE
-static struct net_device *de620_dev;
-
-int __init init_module(void)
-{
-	de620_dev = de620_probe(-1);
-	if (IS_ERR(de620_dev))
-		return PTR_ERR(de620_dev);
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unregister_netdev(de620_dev);
-	release_region(de620_dev->base_addr, 3);
-	free_netdev(de620_dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de620.h b/drivers/net/ethernet/dlink/de620.h
deleted file mode 100644
index e8d9a88..0000000
--- a/drivers/net/ethernet/dlink/de620.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*********************************************************
- *                                                       *
- * Definition of D-Link DE-620 Ethernet Pocket adapter   *
- *                                                       *
- *********************************************************/
-
-/* DE-620's CMD port Command */
-#define CS0		0x08	/* 1->0 command strobe */
-#define ICEN		0x04	/* 0=enable DL3520 host interface */
-#define DS0		0x02	/* 1->0 data strobe 0 */
-#define DS1		0x01	/* 1->0 data strobe 1 */
-
-#define WDIR		0x20	/* general 0=read  1=write */
-#define RDIR		0x00	/*  (not 100% confirm ) */
-#define PS2WDIR		0x00	/* ps/2 mode 1=read, 0=write */
-#define PS2RDIR		0x20
-
-#define IRQEN		0x10	/* 1 = enable printer IRQ line */
-#define SELECTIN	0x08	/* 1 = select printer */
-#define INITP		0x04	/* 0 = initial printer */
-#define AUTOFEED	0x02	/* 1 = printer auto form feed */
-#define STROBE		0x01	/* 0->1 data strobe */
-
-#define RESET		0x08
-#define NIS0		0x20	/* 0 = BNC, 1 = UTP */
-#define NCTL0		0x10
-
-/* DE-620 DIC Command */
-#define W_DUMMY		0x00	/* DIC reserved command */
-#define W_CR		0x20	/* DIC write command register */
-#define W_NPR		0x40	/* DIC write Next Page Register */
-#define W_TBR		0x60	/* DIC write Tx Byte Count 1 reg */
-#define W_RSA		0x80	/* DIC write Remote Start Addr 1 */
-
-/* DE-620's STAT port bits 7-4 */
-#define EMPTY		0x80	/* 1 = receive buffer empty */
-#define INTLEVEL	0x40	/* 1 = interrupt level is high */
-#define TXBF1		0x20	/* 1 = transmit buffer 1 is in use */
-#define TXBF0		0x10	/* 1 = transmit buffer 0 is in use */
-#define READY		0x08	/* 1 = h/w ready to accept cmd/data */
-
-/* IDC 1 Command */
-#define	W_RSA1		0xa0	/* write remote start address 1 */
-#define	W_RSA0		0xa1	/* write remote start address 0 */
-#define	W_NPRF		0xa2	/* write next page register NPR15-NPR8 */
-#define	W_DFR		0xa3	/* write delay factor register */
-#define	W_CPR		0xa4	/* write current page register */
-#define	W_SPR		0xa5	/* write start page register */
-#define	W_EPR		0xa6	/* write end page register */
-#define	W_SCR		0xa7	/* write system configuration register */
-#define	W_TCR		0xa8	/* write Transceiver Configuration reg */
-#define	W_EIP		0xa9	/* write EEPM Interface port */
-#define	W_PAR0		0xaa	/* write physical address register 0 */
-#define	W_PAR1		0xab	/* write physical address register 1 */
-#define	W_PAR2		0xac	/* write physical address register 2 */
-#define	W_PAR3		0xad	/* write physical address register 3 */
-#define	W_PAR4		0xae	/* write physical address register 4 */
-#define	W_PAR5		0xaf	/* write physical address register 5 */
-
-/* IDC 2 Command */
-#define	R_STS		0xc0	/* read status register */
-#define	R_CPR		0xc1	/* read current page register */
-#define	R_BPR		0xc2	/* read boundary page register */
-#define	R_TDR		0xc3	/* read time domain reflectometry reg */
-
-/* STATUS Register */
-#define EEDI		0x80	/* EEPM DO pin */
-#define TXSUC		0x40	/* tx success */
-#define T16		0x20	/* tx fail 16 times */
-#define TS1		0x40	/* 0=Tx success, 1=T16 */
-#define TS0		0x20	/* 0=Tx success, 1=T16 */
-#define RXGOOD		0x10	/* rx a good packet */
-#define RXCRC		0x08	/* rx a CRC error packet */
-#define RXSHORT		0x04	/* rx a short packet */
-#define COLS		0x02	/* coaxial collision status */
-#define LNKS		0x01	/* UTP link status */
-
-/* Command Register */
-#define CLEAR		0x10	/* reset part of hardware */
-#define NOPER		0x08	/* No Operation */
-#define RNOP		0x08
-#define RRA		0x06	/* After RR then auto-advance NPR & BPR(=NPR-1) */
-#define RRN		0x04	/* Normal Remote Read mode */
-#define RW1		0x02	/* Remote Write tx buffer 1  ( page 6 - 11 ) */
-#define RW0		0x00	/* Remote Write tx buffer 0  ( page 0 - 5 ) */
-#define TXEN		0x01	/* 0->1 tx enable */
-
-/* System Configuration Register */
-#define TESTON		0x80	/* test host data transfer reliability */
-#define SLEEP		0x40	/* sleep mode */
-#if 0
-#define FASTMODE	0x04	/* fast mode for intel 82360SL fast mode */
-#define BYTEMODE	0x02	/* byte mode */
-#else
-#define FASTMODE	0x20	/* fast mode for intel 82360SL fast mode */
-#define BYTEMODE	0x10	/* byte mode */
-#endif
-#define NIBBLEMODE	0x00	/* nibble mode */
-#define IRQINV		0x08	/* turn off IRQ line inverter */
-#define IRQNML		0x00	/* turn on IRQ line inverter */
-#define INTON		0x04
-#define AUTOFFSET	0x02	/* auto shift address to TPR+12 */
-#define AUTOTX		0x01	/* auto tx when leave RW mode */
-
-/* Transceiver Configuration Register */
-#define JABBER		0x80	/* generate jabber condition */
-#define TXSUCINT	0x40	/* enable tx success interrupt */
-#define T16INT		0x20	/* enable T16 interrupt */
-#define RXERRPKT	0x10	/* accept CRC error or short packet */
-#define EXTERNALB2	0x0C	/* external loopback 2 */
-#define EXTERNALB1	0x08	/* external loopback 1 */
-#define INTERNALB	0x04	/* internal loopback */
-#define NMLOPERATE	0x00	/* normal operation */
-#define RXPBM		0x03	/* rx physical, broadcast, multicast */
-#define RXPB		0x02	/* rx physical, broadcast */
-#define RXALL		0x01	/* rx all packet */
-#define RXOFF		0x00	/* rx disable */
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index 1d342d3..110d26f 100644
--- a/drivers/net/ethernet/dlink/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -1156,9 +1156,10 @@
 static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct netdev_private *np = netdev_priv(dev);
-	strcpy(info->driver, "dl2k");
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pci_name(np->pdev));
+
+	strlcpy(info->driver, "dl2k", sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
 }
 
 static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index 28fc11b..50d9c63 100644
--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -530,7 +530,6 @@
 	for (i = 0; i < 3; i++)
 		((__le16 *)dev->dev_addr)[i] =
 			cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	np = netdev_priv(dev);
 	np->base = ioaddr;
diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c
index 2c177b3..f3d60eb 100644
--- a/drivers/net/ethernet/dnet.c
+++ b/drivers/net/ethernet/dnet.c
@@ -281,11 +281,11 @@
 	/* attach the mac to the phy */
 	if (bp->capabilities & DNET_HAS_RMII) {
 		phydev = phy_connect(dev, dev_name(&phydev->dev),
-				     &dnet_handle_link_change, 0,
+				     &dnet_handle_link_change,
 				     PHY_INTERFACE_MODE_RMII);
 	} else {
 		phydev = phy_connect(dev, dev_name(&phydev->dev),
-				     &dnet_handle_link_change, 0,
+				     &dnet_handle_link_change,
 				     PHY_INTERFACE_MODE_MII);
 	}
 
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index f1b3df1..28ceb84 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -34,7 +34,7 @@
 #include "be_hw.h"
 #include "be_roce.h"
 
-#define DRV_VER			"4.4.161.0u"
+#define DRV_VER			"4.6.62.0u"
 #define DRV_NAME		"be2net"
 #define BE_NAME			"Emulex BladeEngine2"
 #define BE3_NAME		"Emulex BladeEngine3"
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 8a250c3..071aea7 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -93,13 +93,16 @@
  * little endian) */
 static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
 {
+	u32 flags;
+
 	if (compl->flags != 0) {
-		compl->flags = le32_to_cpu(compl->flags);
-		BUG_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
-		return true;
-	} else {
-		return false;
+		flags = le32_to_cpu(compl->flags);
+		if (flags & CQE_FLAGS_VALID_MASK) {
+			compl->flags = flags;
+			return true;
+		}
 	}
+	return false;
 }
 
 /* Need to reset the entire word that houses the valid bit */
@@ -3138,6 +3141,39 @@
 	return status;
 }
 
+int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
+		     int vf_num)
+{
+	struct be_mcc_wrb *wrb;
+	struct be_cmd_req_get_iface_list *req;
+	struct be_cmd_resp_get_iface_list *resp;
+	int status;
+
+	spin_lock_bh(&adapter->mcc_lock);
+
+	wrb = wrb_from_mccq(adapter);
+	if (!wrb) {
+		status = -EBUSY;
+		goto err;
+	}
+	req = embedded_payload(wrb);
+
+	be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+			       OPCODE_COMMON_GET_IFACE_LIST, sizeof(*resp),
+			       wrb, NULL);
+	req->hdr.domain = vf_num + 1;
+
+	status = be_mcc_notify_wait(adapter);
+	if (!status) {
+		resp = (struct be_cmd_resp_get_iface_list *)req;
+		vf_cfg->if_handle = le32_to_cpu(resp->if_desc.if_id);
+	}
+
+err:
+	spin_unlock_bh(&adapter->mcc_lock);
+	return status;
+}
+
 /* Uses sync mcc */
 int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain)
 {
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index d6552e1..9697086 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -203,6 +203,7 @@
 #define OPCODE_COMMON_GET_FN_PRIVILEGES			170
 #define OPCODE_COMMON_READ_OBJECT			171
 #define OPCODE_COMMON_WRITE_OBJECT			172
+#define OPCODE_COMMON_GET_IFACE_LIST			194
 #define OPCODE_COMMON_ENABLE_DISABLE_VF			196
 
 #define OPCODE_ETH_RSS_CONFIG				1
@@ -1795,6 +1796,23 @@
 	return flags & adapter->cmd_privileges ? true : false;
 }
 
+/************** Get IFACE LIST *******************/
+struct be_if_desc {
+	u32 if_id;
+	u32 cap_flags;
+	u32 en_flags;
+};
+
+struct be_cmd_req_get_iface_list {
+	struct be_cmd_req_hdr hdr;
+};
+
+struct be_cmd_resp_get_iface_list {
+	struct be_cmd_req_hdr hdr;
+	u32 if_cnt;
+	struct be_if_desc if_desc;
+};
+
 extern int be_pci_fnum_get(struct be_adapter *adapter);
 extern int be_fw_wait_ready(struct be_adapter *adapter);
 extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -1917,4 +1935,6 @@
 
 extern int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
 				     u8 domain);
+extern int be_cmd_get_if_id(struct be_adapter *adapter,
+			    struct be_vf_cfg *vf_cfg, int vf_num);
 extern int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 00454a1..76b302f 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -183,12 +183,12 @@
 
 	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
 	strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
-	strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
-	if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
-		strcat(drvinfo->fw_version, " [");
-		strcat(drvinfo->fw_version, fw_on_flash);
-		strcat(drvinfo->fw_version, "]");
-	}
+	if (!memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN))
+		strlcpy(drvinfo->fw_version, adapter->fw_ver,
+			sizeof(drvinfo->fw_version));
+	else
+		snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+			 "%s [%s]", adapter->fw_ver, fw_on_flash);
 
 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
 		sizeof(drvinfo->bus_info));
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 4d6f3c5..3860888 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2597,7 +2597,7 @@
  * These addresses are programmed in the ASIC by the PF and the VF driver
  * queries for the MAC address during its probe.
  */
-static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+static int be_vf_eth_addr_config(struct be_adapter *adapter)
 {
 	u32 vf;
 	int status = 0;
@@ -2626,13 +2626,34 @@
 	return status;
 }
 
+static int be_vfs_mac_query(struct be_adapter *adapter)
+{
+	int status, vf;
+	u8 mac[ETH_ALEN];
+	struct be_vf_cfg *vf_cfg;
+	bool active;
+
+	for_all_vfs(adapter, vf_cfg, vf) {
+		be_cmd_get_mac_from_list(adapter, mac, &active,
+					 &vf_cfg->pmac_id, 0);
+
+		status = be_cmd_mac_addr_query(adapter, mac, false,
+					       vf_cfg->if_handle, 0);
+		if (status)
+			return status;
+		memcpy(vf_cfg->mac_addr, mac, ETH_ALEN);
+	}
+	return 0;
+}
+
 static void be_vf_clear(struct be_adapter *adapter)
 {
 	struct be_vf_cfg *vf_cfg;
 	u32 vf;
 
 	if (be_find_vfs(adapter, ASSIGNED)) {
-		dev_warn(&adapter->pdev->dev, "VFs are assigned to VMs\n");
+		dev_warn(&adapter->pdev->dev,
+			 "VFs are assigned to VMs: not disabling VFs\n");
 		goto done;
 	}
 
@@ -2681,21 +2702,29 @@
 	return 0;
 }
 
-static void be_get_vf_if_cap_flags(struct be_adapter *adapter,
-				   u32 *cap_flags, u8 domain)
+static int be_vfs_if_create(struct be_adapter *adapter)
 {
-	bool profile_present = false;
+	struct be_vf_cfg *vf_cfg;
+	u32 cap_flags, en_flags, vf;
 	int status;
 
-	if (lancer_chip(adapter)) {
-		status = be_cmd_get_profile_config(adapter, cap_flags, domain);
-		if (!status)
-			profile_present = true;
-	}
+	cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+		    BE_IF_FLAGS_MULTICAST;
 
-	if (!profile_present)
-		*cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-			     BE_IF_FLAGS_MULTICAST;
+	for_all_vfs(adapter, vf_cfg, vf) {
+		if (!BE3_chip(adapter))
+			be_cmd_get_profile_config(adapter, &cap_flags, vf + 1);
+
+		/* If a FW profile exists, then cap_flags are updated */
+		en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
+			   BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST);
+		status = be_cmd_if_create(adapter, cap_flags, en_flags,
+					  &vf_cfg->if_handle, vf + 1);
+		if (status)
+			goto err;
+	}
+err:
+	return status;
 }
 
 static int be_vf_setup_init(struct be_adapter *adapter)
@@ -2718,65 +2747,70 @@
 static int be_vf_setup(struct be_adapter *adapter)
 {
 	struct be_vf_cfg *vf_cfg;
-	struct device *dev = &adapter->pdev->dev;
-	u32 cap_flags, en_flags, vf;
 	u16 def_vlan, lnk_speed;
-	int status, enabled_vfs;
+	int status, old_vfs, vf;
+	struct device *dev = &adapter->pdev->dev;
 
-	enabled_vfs = be_find_vfs(adapter, ENABLED);
-	if (enabled_vfs) {
-		dev_warn(dev, "%d VFs are already enabled\n", enabled_vfs);
-		dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
-		return 0;
-	}
-
-	if (num_vfs > adapter->dev_num_vfs) {
-		dev_warn(dev, "Device supports %d VFs and not %d\n",
-			 adapter->dev_num_vfs, num_vfs);
-		num_vfs = adapter->dev_num_vfs;
-	}
-
-	status = pci_enable_sriov(adapter->pdev, num_vfs);
-	if (!status) {
-		adapter->num_vfs = num_vfs;
+	old_vfs = be_find_vfs(adapter, ENABLED);
+	if (old_vfs) {
+		dev_info(dev, "%d VFs are already enabled\n", old_vfs);
+		if (old_vfs != num_vfs)
+			dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
+		adapter->num_vfs = old_vfs;
 	} else {
-		/* Platform doesn't support SRIOV though device supports it */
-		dev_warn(dev, "SRIOV enable failed\n");
-		return 0;
+		if (num_vfs > adapter->dev_num_vfs)
+			dev_info(dev, "Device supports %d VFs and not %d\n",
+				 adapter->dev_num_vfs, num_vfs);
+		adapter->num_vfs = min_t(u16, num_vfs, adapter->dev_num_vfs);
+
+		status = pci_enable_sriov(adapter->pdev, num_vfs);
+		if (status) {
+			dev_err(dev, "SRIOV enable failed\n");
+			adapter->num_vfs = 0;
+			return 0;
+		}
 	}
 
 	status = be_vf_setup_init(adapter);
 	if (status)
 		goto err;
 
-	for_all_vfs(adapter, vf_cfg, vf) {
-		be_get_vf_if_cap_flags(adapter, &cap_flags, vf + 1);
-
-		en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
-					BE_IF_FLAGS_BROADCAST |
-					BE_IF_FLAGS_MULTICAST);
-
-		status = be_cmd_if_create(adapter, cap_flags, en_flags,
-					  &vf_cfg->if_handle, vf + 1);
+	if (old_vfs) {
+		for_all_vfs(adapter, vf_cfg, vf) {
+			status = be_cmd_get_if_id(adapter, vf_cfg, vf);
+			if (status)
+				goto err;
+		}
+	} else {
+		status = be_vfs_if_create(adapter);
 		if (status)
 			goto err;
 	}
 
-	if (!enabled_vfs) {
+	if (old_vfs) {
+		status = be_vfs_mac_query(adapter);
+		if (status)
+			goto err;
+	} else {
 		status = be_vf_eth_addr_config(adapter);
 		if (status)
 			goto err;
 	}
 
 	for_all_vfs(adapter, vf_cfg, vf) {
-		lnk_speed = 1000;
-		status = be_cmd_set_qos(adapter, lnk_speed, vf + 1);
-		if (status)
-			goto err;
-		vf_cfg->tx_rate = lnk_speed * 10;
+		/* BE3 FW, by default, caps VF TX-rate to 100mbps.
+		 * Allow full available bandwidth
+		 */
+		if (BE3_chip(adapter) && !old_vfs)
+			be_cmd_set_qos(adapter, 1000, vf+1);
+
+		status = be_cmd_link_status_query(adapter, &lnk_speed,
+						  NULL, vf + 1);
+		if (!status)
+			vf_cfg->tx_rate = lnk_speed;
 
 		status = be_cmd_get_hsw_config(adapter, &def_vlan,
-				vf + 1, vf_cfg->if_handle);
+					       vf + 1, vf_cfg->if_handle);
 		if (status)
 			goto err;
 		vf_cfg->def_vid = def_vlan;
@@ -2785,6 +2819,8 @@
 	}
 	return 0;
 err:
+	dev_err(dev, "VF setup failed\n");
+	be_vf_clear(adapter);
 	return status;
 }
 
@@ -2838,12 +2874,12 @@
 
 static void be_get_resources(struct be_adapter *adapter)
 {
-	int status;
+	u16 dev_num_vfs;
+	int pos, status;
 	bool profile_present = false;
 
-	if (lancer_chip(adapter)) {
+	if (!BEx_chip(adapter)) {
 		status = be_cmd_get_func_config(adapter);
-
 		if (!status)
 			profile_present = true;
 	}
@@ -2899,13 +2935,21 @@
 		if (adapter->function_caps & BE_FUNCTION_CAPS_RSS)
 			adapter->if_cap_flags |= BE_IF_FLAGS_RSS;
 	}
+
+	pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (pos) {
+		pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF,
+				     &dev_num_vfs);
+		if (BE3_chip(adapter))
+			dev_num_vfs = min_t(u16, dev_num_vfs, MAX_VFS);
+		adapter->dev_num_vfs = dev_num_vfs;
+	}
 }
 
 /* Routine to query per function resource limits */
 static int be_get_config(struct be_adapter *adapter)
 {
-	int pos, status;
-	u16 dev_num_vfs;
+	int status;
 
 	status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
 				     &adapter->function_mode,
@@ -2923,14 +2967,6 @@
 		goto err;
 	}
 
-	pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV);
-	if (pos) {
-		pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF,
-				     &dev_num_vfs);
-		if (!lancer_chip(adapter))
-			dev_num_vfs = min_t(u16, dev_num_vfs, MAX_VFS);
-		adapter->dev_num_vfs = dev_num_vfs;
-	}
 err:
 	return status;
 }
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 8db1c06..5722bc6 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -206,7 +206,7 @@
 	unsigned int num_rx;
 	unsigned int cur_rx;
 
-	void** vma;
+	void **vma;
 
 	struct net_device *netdev;
 	struct napi_struct napi;
@@ -292,7 +292,7 @@
 {
 	struct ethoc_bd bd;
 	int i;
-	void* vma;
+	void *vma;
 
 	dev->cur_tx = 0;
 	dev->dty_tx = 0;
@@ -447,8 +447,8 @@
 				netif_receive_skb(skb);
 			} else {
 				if (net_ratelimit())
-					dev_warn(&dev->dev, "low on memory - "
-							"packet dropped\n");
+					dev_warn(&dev->dev,
+					    "low on memory - packet dropped\n");
 
 				dev->stats.rx_dropped++;
 				break;
@@ -555,9 +555,8 @@
 	pending = ethoc_read(priv, INT_SOURCE);
 	pending &= mask;
 
-	if (unlikely(pending == 0)) {
+	if (unlikely(pending == 0))
 		return IRQ_NONE;
-	}
 
 	ethoc_ack_irq(priv, pending);
 
@@ -620,7 +619,7 @@
 	ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
 	ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ);
 
-	for (i=0; i < 5; i++) {
+	for (i = 0; i < 5; i++) {
 		u32 status = ethoc_read(priv, MIISTATUS);
 		if (!(status & MIISTATUS_BUSY)) {
 			u32 data = ethoc_read(priv, MIIRX_DATA);
@@ -628,7 +627,7 @@
 			ethoc_write(priv, MIICOMMAND, 0);
 			return data;
 		}
-		usleep_range(100,200);
+		usleep_range(100, 200);
 	}
 
 	return -EBUSY;
@@ -643,14 +642,14 @@
 	ethoc_write(priv, MIITX_DATA, val);
 	ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE);
 
-	for (i=0; i < 5; i++) {
+	for (i = 0; i < 5; i++) {
 		u32 stat = ethoc_read(priv, MIISTATUS);
 		if (!(stat & MIISTATUS_BUSY)) {
 			/* reset MII command register */
 			ethoc_write(priv, MIICOMMAND, 0);
 			return 0;
 		}
-		usleep_range(100,200);
+		usleep_range(100, 200);
 	}
 
 	return -EBUSY;
@@ -671,19 +670,18 @@
 	struct phy_device *phy;
 	int err;
 
-	if (priv->phy_id != -1) {
+	if (priv->phy_id != -1)
 		phy = priv->mdio->phy_map[priv->phy_id];
-	} else {
+	else
 		phy = phy_find_first(priv->mdio);
-	}
 
 	if (!phy) {
 		dev_err(&dev->dev, "no PHY found\n");
 		return -ENXIO;
 	}
 
-	err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
-			PHY_INTERFACE_MODE_GMII);
+	err = phy_connect_direct(dev, phy, ethoc_mdio_poll,
+				 PHY_INTERFACE_MODE_GMII);
 	if (err) {
 		dev_err(&dev->dev, "could not attach to PHY\n");
 		return err;
@@ -771,21 +769,24 @@
 	return -ENOSYS;
 }
 
-static int ethoc_set_mac_address(struct net_device *dev, void *addr)
+static void ethoc_do_set_mac_address(struct net_device *dev)
 {
 	struct ethoc *priv = netdev_priv(dev);
-	u8 *mac = (u8 *)addr;
-
-	if (!is_valid_ether_addr(mac))
-		return -EADDRNOTAVAIL;
+	unsigned char *mac = dev->dev_addr;
 
 	ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
 				     (mac[4] <<  8) | (mac[5] <<  0));
 	ethoc_write(priv, MAC_ADDR1, (mac[0] <<  8) | (mac[1] <<  0));
+}
 
-	memcpy(dev->dev_addr, mac, ETH_ALEN);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
+static int ethoc_set_mac_address(struct net_device *dev, void *p)
+{
+	const struct sockaddr *addr = p;
 
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+	ethoc_do_set_mac_address(dev);
 	return 0;
 }
 
@@ -1022,7 +1023,7 @@
 	dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n",
 		priv->num_tx, priv->num_rx);
 
-	priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
+	priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void *), GFP_KERNEL);
 	if (!priv->vma) {
 		ret = -ENOMEM;
 		goto error;
@@ -1038,7 +1039,7 @@
 
 #ifdef CONFIG_OF
 		{
-		const uint8_t* mac;
+		const uint8_t *mac;
 
 		mac = of_get_property(pdev->dev.of_node,
 				      "local-mac-address",
@@ -1050,25 +1051,23 @@
 	}
 
 	/* Check that the given MAC address is valid. If it isn't, read the
-	 * current MAC from the controller. */
+	 * current MAC from the controller.
+	 */
 	if (!is_valid_ether_addr(netdev->dev_addr))
 		ethoc_get_mac_address(netdev, netdev->dev_addr);
 
 	/* Check the MAC again for validity, if it still isn't choose and
-	 * program a random one. */
+	 * program a random one.
+	 */
 	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		eth_random_addr(netdev->dev_addr);
 		random_mac = true;
 	}
 
-	ret = ethoc_set_mac_address(netdev, netdev->dev_addr);
-	if (ret) {
-		dev_err(&netdev->dev, "failed to set MAC address\n");
-		goto error;
-	}
+	ethoc_do_set_mac_address(netdev);
 
 	if (random_mac)
-		netdev->addr_assign_type |= NET_ADDR_RANDOM;
+		netdev->addr_assign_type = NET_ADDR_RANDOM;
 
 	/* register MII bus */
 	priv->mdio = mdiobus_alloc();
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 74d749e..7c361d1 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -858,8 +858,7 @@
 	}
 
 	phydev = phy_connect(netdev, dev_name(&phydev->dev),
-			     &ftgmac100_adjust_link, 0,
-			     PHY_INTERFACE_MODE_GMII);
+			     &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
 
 	if (IS_ERR(phydev)) {
 		netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
@@ -955,9 +954,9 @@
 static void ftgmac100_get_drvinfo(struct net_device *netdev,
 				  struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, dev_name(&netdev->dev));
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
 }
 
 static int ftgmac100_get_settings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index b901a01..b5ea8fb 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -820,9 +820,9 @@
 static void ftmac100_get_drvinfo(struct net_device *netdev,
 				 struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, dev_name(&netdev->dev));
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
 }
 
 static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index ec490d7..6048dc8 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -26,6 +26,7 @@
 		   ARCH_MXC || SOC_IMX28)
 	default ARCH_MXC || SOC_IMX28 if ARM
 	select PHYLIB
+	select PTP_1588_CLOCK
 	---help---
 	  Say Y here if you want to use the built-in 10/100 Fast ethernet
 	  controller on some Motorola ColdFire and Freescale i.MX processors.
@@ -92,12 +93,4 @@
 	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
 	  and MPC86xx family of chips, and the FEC on the 8540.
 
-config FEC_PTP
-	bool "PTP Hardware Clock (PHC)"
-	depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5
-	select PTP_1588_CLOCK
-	--help---
-	  Say Y here if you want to use PTP Hardware Clock (PHC) in the
-	  driver.  Only the basic clock operations have been implemented.
-
 endif # NET_VENDOR_FREESCALE
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index d4d19b3..b7d58fe 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -2,8 +2,7 @@
 # Makefile for the Freescale network device drivers.
 #
 
-obj-$(CONFIG_FEC) += fec.o
-obj-$(CONFIG_FEC_PTP) += fec_ptp.o
+obj-$(CONFIG_FEC) += fec.o fec_ptp.o
 obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
 ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
 	obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 0704bca..29d82cf 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -67,6 +67,15 @@
 #endif
 
 #define DRIVER_NAME	"fec"
+#define FEC_NAPI_WEIGHT	64
+
+/* Pause frame feild and FIFO threshold */
+#define FEC_ENET_FCE	(1 << 5)
+#define FEC_ENET_RSEM_V	0x84
+#define FEC_ENET_RSFL_V	16
+#define FEC_ENET_RAEM_V	0x8
+#define FEC_ENET_RAFL_V	0x8
+#define FEC_ENET_OPD_V	0xFFF0
 
 /* Controller is ENET-MAC */
 #define FEC_QUIRK_ENET_MAC		(1 << 0)
@@ -76,6 +85,8 @@
 #define FEC_QUIRK_USE_GASKET		(1 << 2)
 /* Controller has GBIT support */
 #define FEC_QUIRK_HAS_GBIT		(1 << 3)
+/* Controller has extend desc buffer */
+#define FEC_QUIRK_HAS_BUFDESC_EX	(1 << 4)
 
 static struct platform_device_id fec_devtype[] = {
 	{
@@ -93,7 +104,8 @@
 		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
 	}, {
 		.name = "imx6q-fec",
-		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
+		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+				FEC_QUIRK_HAS_BUFDESC_EX,
 	}, {
 		/* sentinel */
 	}
@@ -140,7 +152,7 @@
 #endif
 #endif /* CONFIG_M5272 */
 
-#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
+#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE)
 #error "FEC: descriptor ring size constants too large"
 #endif
 
@@ -157,6 +169,7 @@
 #define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
 
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
@@ -190,8 +203,29 @@
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
+#define FEC_PAUSE_FLAG_AUTONEG	0x1
+#define FEC_PAUSE_FLAG_ENABLE	0x2
+
 static int mii_cnt;
 
+static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex)
+{
+	struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp;
+	if (is_ex)
+		return (struct bufdesc *)(ex + 1);
+	else
+		return bdp + 1;
+}
+
+static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, int is_ex)
+{
+	struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp;
+	if (is_ex)
+		return (struct bufdesc *)(ex - 1);
+	else
+		return bdp - 1;
+}
+
 static void *swap_buffer(void *bufaddr, int len)
 {
 	int i;
@@ -248,7 +282,11 @@
 	 */
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
 		unsigned int index;
-		index = bdp - fep->tx_bd_base;
+		if (fep->bufdesc_ex)
+			index = (struct bufdesc_ex *)bdp -
+				(struct bufdesc_ex *)fep->tx_bd_base;
+		else
+			index = bdp - fep->tx_bd_base;
 		memcpy(fep->tx_bounce[index], skb->data, skb->len);
 		bufaddr = fep->tx_bounce[index];
 	}
@@ -280,17 +318,19 @@
 			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
 	bdp->cbd_sc = status;
 
-#ifdef CONFIG_FEC_PTP
-	bdp->cbd_bdu = 0;
-	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
-			fep->hwts_tx_en)) {
-			bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
-			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-	} else {
+	if (fep->bufdesc_ex) {
 
-		bdp->cbd_esc = BD_ENET_TX_INT;
+		struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+		ebdp->cbd_bdu = 0;
+		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+			fep->hwts_tx_en)) {
+			ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
+			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+		} else {
+
+			ebdp->cbd_esc = BD_ENET_TX_INT;
+		}
 	}
-#endif
 	/* Trigger transmission start */
 	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
@@ -298,7 +338,7 @@
 	if (status & BD_ENET_TX_WRAP)
 		bdp = fep->tx_bd_base;
 	else
-		bdp++;
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 
 	if (bdp == fep->dirty_tx) {
 		fep->tx_full = 1;
@@ -359,8 +399,12 @@
 
 	/* Set receive and transmit descriptor base. */
 	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
-	writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
-			fep->hwp + FEC_X_DES_START);
+	if (fep->bufdesc_ex)
+		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
+			* RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
+	else
+		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
+			* RX_RING_SIZE,	fep->hwp + FEC_X_DES_START);
 
 	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
 	fep->cur_rx = fep->rx_bd_base;
@@ -439,6 +483,25 @@
 		}
 #endif
 	}
+
+	/* enable pause frame*/
+	if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
+	    ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
+	     fep->phy_dev && fep->phy_dev->pause)) {
+		rcntl |= FEC_ENET_FCE;
+
+		/* set FIFO thresh hold parameter to reduce overrun */
+		writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
+		writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
+		writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
+		writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
+
+		/* OPD */
+		writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
+	} else {
+		rcntl &= ~FEC_ENET_FCE;
+	}
+
 	writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
 	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
@@ -448,17 +511,16 @@
 		writel(1 << 8, fep->hwp + FEC_X_WMRK);
 	}
 
-#ifdef CONFIG_FEC_PTP
-	ecntl |= (1 << 4);
-#endif
+	if (fep->bufdesc_ex)
+		ecntl |= (1 << 4);
 
 	/* And last, enable the transmit and receive processing */
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
 	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
-#ifdef CONFIG_FEC_PTP
-	fec_ptp_start_cyclecounter(ndev);
-#endif
+	if (fep->bufdesc_ex)
+		fec_ptp_start_cyclecounter(ndev);
+
 	/* Enable interrupts we wish to service */
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
@@ -544,19 +606,20 @@
 			ndev->stats.tx_packets++;
 		}
 
-#ifdef CONFIG_FEC_PTP
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
+			fep->bufdesc_ex) {
 			struct skb_shared_hwtstamps shhwtstamps;
 			unsigned long flags;
+			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
 
 			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 			spin_lock_irqsave(&fep->tmreg_lock, flags);
 			shhwtstamps.hwtstamp = ns_to_ktime(
-				timecounter_cyc2time(&fep->tc, bdp->ts));
+				timecounter_cyc2time(&fep->tc, ebdp->ts));
 			spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 			skb_tstamp_tx(skb, &shhwtstamps);
 		}
-#endif
+
 		if (status & BD_ENET_TX_READY)
 			printk("HEY! Enet xmit interrupt and TX_READY.\n");
 
@@ -575,7 +638,7 @@
 		if (status & BD_ENET_TX_WRAP)
 			bdp = fep->tx_bd_base;
 		else
-			bdp++;
+			bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 
 		/* Since we have freed up a buffer, the ring is no longer full
 		 */
@@ -595,8 +658,8 @@
  * not been given to the system, we just set the empty indicator,
  * effectively tossing the packet.
  */
-static void
-fec_enet_rx(struct net_device *ndev)
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -606,13 +669,12 @@
 	struct	sk_buff	*skb;
 	ushort	pkt_len;
 	__u8 *data;
+	int	pkt_received = 0;
 
 #ifdef CONFIG_M532x
 	flush_cache_all();
 #endif
 
-	spin_lock(&fep->hw_lock);
-
 	/* First, grab all of the stats for the incoming packet.
 	 * These get messed up if we get called due to a busy condition.
 	 */
@@ -620,6 +682,10 @@
 
 	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
+		if (pkt_received >= budget)
+			break;
+		pkt_received++;
+
 		/* Since we have allocated space to hold a complete frame,
 		 * the last indicator should be set.
 		 */
@@ -683,23 +749,25 @@
 			skb_put(skb, pkt_len - 4);	/* Make room */
 			skb_copy_to_linear_data(skb, data, pkt_len - 4);
 			skb->protocol = eth_type_trans(skb, ndev);
-#ifdef CONFIG_FEC_PTP
+
 			/* Get receive timestamp from the skb */
-			if (fep->hwts_rx_en) {
+			if (fep->hwts_rx_en && fep->bufdesc_ex) {
 				struct skb_shared_hwtstamps *shhwtstamps =
 							    skb_hwtstamps(skb);
 				unsigned long flags;
+				struct bufdesc_ex *ebdp =
+					(struct bufdesc_ex *)bdp;
 
 				memset(shhwtstamps, 0, sizeof(*shhwtstamps));
 
 				spin_lock_irqsave(&fep->tmreg_lock, flags);
 				shhwtstamps->hwtstamp = ns_to_ktime(
-				    timecounter_cyc2time(&fep->tc, bdp->ts));
+				    timecounter_cyc2time(&fep->tc, ebdp->ts));
 				spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 			}
-#endif
+
 			if (!skb_defer_rx_timestamp(skb))
-				netif_rx(skb);
+				napi_gro_receive(&fep->napi, skb);
 		}
 
 		bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
@@ -712,17 +780,19 @@
 		status |= BD_ENET_RX_EMPTY;
 		bdp->cbd_sc = status;
 
-#ifdef CONFIG_FEC_PTP
-		bdp->cbd_esc = BD_ENET_RX_INT;
-		bdp->cbd_prot = 0;
-		bdp->cbd_bdu = 0;
-#endif
+		if (fep->bufdesc_ex) {
+			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+
+			ebdp->cbd_esc = BD_ENET_RX_INT;
+			ebdp->cbd_prot = 0;
+			ebdp->cbd_bdu = 0;
+		}
 
 		/* Update BD pointer to next entry */
 		if (status & BD_ENET_RX_WRAP)
 			bdp = fep->rx_bd_base;
 		else
-			bdp++;
+			bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 		/* Doing this here will keep the FEC running while we process
 		 * incoming frames.  On a heavily loaded network, we should be
 		 * able to keep up at the expense of system resources.
@@ -731,7 +801,7 @@
 	}
 	fep->cur_rx = bdp;
 
-	spin_unlock(&fep->hw_lock);
+	return pkt_received;
 }
 
 static irqreturn_t
@@ -748,7 +818,13 @@
 
 		if (int_events & FEC_ENET_RXF) {
 			ret = IRQ_HANDLED;
-			fec_enet_rx(ndev);
+
+			/* Disable the RX interrupt */
+			if (napi_schedule_prep(&fep->napi)) {
+				writel(FEC_RX_DISABLED_IMASK,
+					fep->hwp + FEC_IMASK);
+				__napi_schedule(&fep->napi);
+			}
 		}
 
 		/* Transmit OK, or non-fatal error. Update the buffer
@@ -769,10 +845,21 @@
 	return ret;
 }
 
+static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
+{
+	struct net_device *ndev = napi->dev;
+	int pkts = fec_enet_rx(ndev, budget);
+	struct fec_enet_private *fep = netdev_priv(ndev);
 
+	if (pkts < budget) {
+		napi_complete(napi);
+		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+	}
+	return pkts;
+}
 
 /* ------------------------------------------------------------------------- */
-static void __inline__ fec_get_mac(struct net_device *ndev)
+static void fec_get_mac(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
@@ -973,7 +1060,7 @@
 	}
 
 	snprintf(phy_name, sizeof(phy_name), PHY_ID_FMT, mdio_bus_id, phy_id);
-	phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
+	phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
 			      fep->phy_interface);
 	if (IS_ERR(phy_dev)) {
 		printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
@@ -981,8 +1068,10 @@
 	}
 
 	/* mask with MAC supported features */
-	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
 		phy_dev->supported &= PHY_GBIT_FEATURES;
+		phy_dev->supported |= SUPPORTED_Pause;
+	}
 	else
 		phy_dev->supported &= PHY_BASIC_FEATURES;
 
@@ -1133,17 +1222,95 @@
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 
-	strcpy(info->driver, fep->pdev->dev.driver->name);
-	strcpy(info->version, "Revision: 1.0");
-	strcpy(info->bus_info, dev_name(&ndev->dev));
+	strlcpy(info->driver, fep->pdev->dev.driver->name,
+		sizeof(info->driver));
+	strlcpy(info->version, "Revision: 1.0", sizeof(info->version));
+	strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info));
+}
+
+static int fec_enet_get_ts_info(struct net_device *ndev,
+				struct ethtool_ts_info *info)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	if (fep->bufdesc_ex) {
+
+		info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+					SOF_TIMESTAMPING_RX_SOFTWARE |
+					SOF_TIMESTAMPING_SOFTWARE |
+					SOF_TIMESTAMPING_TX_HARDWARE |
+					SOF_TIMESTAMPING_RX_HARDWARE |
+					SOF_TIMESTAMPING_RAW_HARDWARE;
+		if (fep->ptp_clock)
+			info->phc_index = ptp_clock_index(fep->ptp_clock);
+		else
+			info->phc_index = -1;
+
+		info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+				 (1 << HWTSTAMP_TX_ON);
+
+		info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+				   (1 << HWTSTAMP_FILTER_ALL);
+		return 0;
+	} else {
+		return ethtool_op_get_ts_info(ndev, info);
+	}
+}
+
+static void fec_enet_get_pauseparam(struct net_device *ndev,
+				    struct ethtool_pauseparam *pause)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
+	pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
+	pause->rx_pause = pause->tx_pause;
+}
+
+static int fec_enet_set_pauseparam(struct net_device *ndev,
+				   struct ethtool_pauseparam *pause)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	if (pause->tx_pause != pause->rx_pause) {
+		netdev_info(ndev,
+			"hardware only support enable/disable both tx and rx");
+		return -EINVAL;
+	}
+
+	fep->pause_flag = 0;
+
+	/* tx pause must be same as rx pause */
+	fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
+	fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
+
+	if (pause->rx_pause || pause->autoneg) {
+		fep->phy_dev->supported |= ADVERTISED_Pause;
+		fep->phy_dev->advertising |= ADVERTISED_Pause;
+	} else {
+		fep->phy_dev->supported &= ~ADVERTISED_Pause;
+		fep->phy_dev->advertising &= ~ADVERTISED_Pause;
+	}
+
+	if (pause->autoneg) {
+		if (netif_running(ndev))
+			fec_stop(ndev);
+		phy_start_aneg(fep->phy_dev);
+	}
+	if (netif_running(ndev))
+		fec_restart(ndev, 0);
+
+	return 0;
 }
 
 static const struct ethtool_ops fec_enet_ethtool_ops = {
+	.get_pauseparam		= fec_enet_get_pauseparam,
+	.set_pauseparam		= fec_enet_set_pauseparam,
 	.get_settings		= fec_enet_get_settings,
 	.set_settings		= fec_enet_set_settings,
 	.get_drvinfo		= fec_enet_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
-	.get_ts_info		= ethtool_op_get_ts_info,
+	.get_ts_info		= fec_enet_get_ts_info,
 };
 
 static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1157,10 +1324,9 @@
 	if (!phydev)
 		return -ENODEV;
 
-#ifdef CONFIG_FEC_PTP
-	if (cmd == SIOCSHWTSTAMP)
+	if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex)
 		return fec_ptp_ioctl(ndev, rq, cmd);
-#endif
+
 	return phy_mii_ioctl(phydev, rq, cmd);
 }
 
@@ -1180,7 +1346,7 @@
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 		if (skb)
 			dev_kfree_skb(skb);
-		bdp++;
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 	}
 
 	bdp = fep->tx_bd_base;
@@ -1207,14 +1373,17 @@
 		bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
 				FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 		bdp->cbd_sc = BD_ENET_RX_EMPTY;
-#ifdef CONFIG_FEC_PTP
-		bdp->cbd_esc = BD_ENET_RX_INT;
-#endif
-		bdp++;
+
+		if (fep->bufdesc_ex) {
+			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+			ebdp->cbd_esc = BD_ENET_RX_INT;
+		}
+
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 	}
 
 	/* Set the last buffer to wrap. */
-	bdp--;
+	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	bdp = fep->tx_bd_base;
@@ -1224,14 +1393,16 @@
 		bdp->cbd_sc = 0;
 		bdp->cbd_bufaddr = 0;
 
-#ifdef CONFIG_FEC_PTP
-		bdp->cbd_esc = BD_ENET_RX_INT;
-#endif
-		bdp++;
+		if (fep->bufdesc_ex) {
+			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+			ebdp->cbd_esc = BD_ENET_RX_INT;
+		}
+
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 	}
 
 	/* Set the last buffer to wrap. */
-	bdp--;
+	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	return 0;
@@ -1243,6 +1414,8 @@
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int ret;
 
+	napi_enable(&fep->napi);
+
 	/* I should reset the ring buffers here, but I don't yet know
 	 * a simple way to do that.
 	 */
@@ -1444,24 +1617,31 @@
 
 	/* Set receive and transmit descriptor base. */
 	fep->rx_bd_base = cbd_base;
-	fep->tx_bd_base = cbd_base + RX_RING_SIZE;
+	if (fep->bufdesc_ex)
+		fep->tx_bd_base = (struct bufdesc *)
+			(((struct bufdesc_ex *)cbd_base) + RX_RING_SIZE);
+	else
+		fep->tx_bd_base = cbd_base + RX_RING_SIZE;
 
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
 	ndev->netdev_ops = &fec_netdev_ops;
 	ndev->ethtool_ops = &fec_enet_ethtool_ops;
 
+	writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
+	netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
+
 	/* Initialize the receive buffer descriptors. */
 	bdp = fep->rx_bd_base;
 	for (i = 0; i < RX_RING_SIZE; i++) {
 
 		/* Initialize the BD for every fragment in the page. */
 		bdp->cbd_sc = 0;
-		bdp++;
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 	}
 
 	/* Set the last buffer to wrap */
-	bdp--;
+	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	/* ...and the same for transmit */
@@ -1471,11 +1651,11 @@
 		/* Initialize the BD for every fragment in the page. */
 		bdp->cbd_sc = 0;
 		bdp->cbd_bufaddr = 0;
-		bdp++;
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 	}
 
 	/* Set the last buffer to wrap */
-	bdp--;
+	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	fec_restart(ndev, 0);
@@ -1509,22 +1689,25 @@
 		msec = 1;
 
 	phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
+	if (!gpio_is_valid(phy_reset))
+		return;
+
 	err = devm_gpio_request_one(&pdev->dev, phy_reset,
 				    GPIOF_OUT_INIT_LOW, "phy-reset");
 	if (err) {
-		pr_debug("FEC: failed to get gpio phy-reset: %d\n", err);
+		dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
 		return;
 	}
 	msleep(msec);
 	gpio_set_value(phy_reset, 1);
 }
 #else /* CONFIG_OF */
-static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
+static int fec_get_phy_mode_dt(struct platform_device *pdev)
 {
 	return -ENODEV;
 }
 
-static inline void fec_reset_phy(struct platform_device *pdev)
+static void fec_reset_phy(struct platform_device *pdev)
 {
 	/*
 	 * In case of platform probe, the reset has been done
@@ -1570,10 +1753,17 @@
 	/* setup board info structure */
 	fep = netdev_priv(ndev);
 
+	/* default enable pause frame auto negotiation */
+	if (pdev->id_entry &&
+	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+		fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+
 	fep->hwp = ioremap(r->start, resource_size(r));
 	fep->pdev = pdev;
 	fep->dev_id = dev_id++;
 
+	fep->bufdesc_ex = 0;
+
 	if (!fep->hwp) {
 		ret = -ENOMEM;
 		goto failed_ioremap;
@@ -1628,19 +1818,19 @@
 		goto failed_clk;
 	}
 
-#ifdef CONFIG_FEC_PTP
 	fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
+	fep->bufdesc_ex =
+		pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
 	if (IS_ERR(fep->clk_ptp)) {
 		ret = PTR_ERR(fep->clk_ptp);
-		goto failed_clk;
+		fep->bufdesc_ex = 0;
 	}
-#endif
 
 	clk_prepare_enable(fep->clk_ahb);
 	clk_prepare_enable(fep->clk_ipg);
-#ifdef CONFIG_FEC_PTP
-	clk_prepare_enable(fep->clk_ptp);
-#endif
+	if (!IS_ERR(fep->clk_ptp))
+		clk_prepare_enable(fep->clk_ptp);
+
 	reg_phy = devm_regulator_get(&pdev->dev, "phy");
 	if (!IS_ERR(reg_phy)) {
 		ret = regulator_enable(reg_phy);
@@ -1653,6 +1843,9 @@
 
 	fec_reset_phy(pdev);
 
+	if (fep->bufdesc_ex)
+		fec_ptp_init(ndev, pdev);
+
 	ret = fec_enet_init(ndev);
 	if (ret)
 		goto failed_init;
@@ -1668,10 +1861,6 @@
 	if (ret)
 		goto failed_register;
 
-#ifdef CONFIG_FEC_PTP
-	fec_ptp_init(ndev, pdev);
-#endif
-
 	return 0;
 
 failed_register:
@@ -1681,9 +1870,8 @@
 failed_regulator:
 	clk_disable_unprepare(fep->clk_ahb);
 	clk_disable_unprepare(fep->clk_ipg);
-#ifdef CONFIG_FEC_PTP
-	clk_disable_unprepare(fep->clk_ptp);
-#endif
+	if (!IS_ERR(fep->clk_ptp))
+		clk_disable_unprepare(fep->clk_ptp);
 failed_pin:
 failed_clk:
 	for (i = 0; i < FEC_IRQ_NUM; i++) {
@@ -1716,12 +1904,10 @@
 		if (irq > 0)
 			free_irq(irq, ndev);
 	}
-#ifdef CONFIG_FEC_PTP
 	del_timer_sync(&fep->time_keep);
 	clk_disable_unprepare(fep->clk_ptp);
 	if (fep->ptp_clock)
 		ptp_clock_unregister(fep->ptp_clock);
-#endif
 	clk_disable_unprepare(fep->clk_ahb);
 	clk_disable_unprepare(fep->clk_ipg);
 	iounmap(fep->hwp);
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index c5a3bc1..01579b8 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -13,11 +13,9 @@
 #define	FEC_H
 /****************************************************************************/
 
-#ifdef CONFIG_FEC_PTP
 #include <linux/clocksource.h>
 #include <linux/net_tstamp.h>
 #include <linux/ptp_clock_kernel.h>
-#endif
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
     defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
@@ -50,6 +48,10 @@
 #define FEC_R_DES_START		0x180 /* Receive descriptor ring */
 #define FEC_X_DES_START		0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */
+#define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */
+#define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */
+#define FEC_R_FIFO_RAEM		0x198 /* Receive FIFO almost empty threshold */
+#define FEC_R_FIFO_RAFL		0x19c /* Receive FIFO almost full threshold */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -94,14 +96,17 @@
 	unsigned short cbd_datlen;	/* Data length */
 	unsigned short cbd_sc;	/* Control and status info */
 	unsigned long cbd_bufaddr;	/* Buffer address */
-#ifdef CONFIG_FEC_PTP
+};
+
+struct bufdesc_ex {
+	struct bufdesc desc;
 	unsigned long cbd_esc;
 	unsigned long cbd_prot;
 	unsigned long cbd_bdu;
 	unsigned long ts;
 	unsigned short res0[4];
-#endif
 };
+
 #else
 struct bufdesc {
 	unsigned short	cbd_sc;			/* Control and status info */
@@ -203,9 +208,7 @@
 
 	struct clk *clk_ipg;
 	struct clk *clk_ahb;
-#ifdef CONFIG_FEC_PTP
 	struct clk *clk_ptp;
-#endif
 
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	unsigned char *tx_bounce[TX_RING_SIZE];
@@ -243,8 +246,11 @@
 	int	full_duplex;
 	struct	completion mdio_done;
 	int	irq[FEC_IRQ_NUM];
+	int	bufdesc_ex;
+	int	pause_flag;
 
-#ifdef CONFIG_FEC_PTP
+	struct	napi_struct napi;
+
 	struct ptp_clock *ptp_clock;
 	struct ptp_clock_info ptp_caps;
 	unsigned long last_overflow_check;
@@ -257,15 +263,12 @@
 	int hwts_rx_en;
 	int hwts_tx_en;
 	struct timer_list time_keep;
-#endif
 
 };
 
-#ifdef CONFIG_FEC_PTP
 void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
-#endif
 
 /****************************************************************************/
 #endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index 817d081..7f91b0c 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -29,6 +29,7 @@
 #include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_mdio.h>
+#include <linux/of_net.h>
 #include <linux/of_platform.h>
 
 #include <linux/netdevice.h>
@@ -76,10 +77,6 @@
 static void mpc52xx_fec_start(struct net_device *dev);
 static void mpc52xx_fec_reset(struct net_device *dev);
 
-static u8 mpc52xx_fec_mac_addr[6];
-module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0);
-MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe");
-
 #define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \
 		NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP)
 static int debug = -1;	/* the above default */
@@ -110,15 +107,6 @@
 	out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
 }
 
-static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac)
-{
-	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
-	struct mpc52xx_fec __iomem *fec = priv->fec;
-
-	*(u32 *)(&mac[0]) = in_be32(&fec->paddr1);
-	*(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
-}
-
 static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
 {
 	struct sockaddr *sock = addr;
@@ -853,6 +841,8 @@
 	struct resource mem;
 	const u32 *prop;
 	int prop_size;
+	struct device_node *np = op->dev.of_node;
+	const char *mac_addr;
 
 	phys_addr_t rx_fifo;
 	phys_addr_t tx_fifo;
@@ -866,7 +856,7 @@
 	priv->ndev = ndev;
 
 	/* Reserve FEC control zone */
-	rv = of_address_to_resource(op->dev.of_node, 0, &mem);
+	rv = of_address_to_resource(np, 0, &mem);
 	if (rv) {
 		printk(KERN_ERR DRIVER_NAME ": "
 				"Error while parsing device node resource\n" );
@@ -919,7 +909,7 @@
 
 	/* Get the IRQ we need one by one */
 		/* Control */
-	ndev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+	ndev->irq = irq_of_parse_and_map(np, 0);
 
 		/* RX */
 	priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
@@ -927,11 +917,33 @@
 		/* TX */
 	priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
 
-	/* MAC address init */
-	if (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
-		memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
-	else
-		mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
+	/*
+	 * MAC address init:
+	 *
+	 * First try to read MAC address from DT
+	 */
+	mac_addr = of_get_mac_address(np);
+	if (mac_addr) {
+		memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+	} else {
+		struct mpc52xx_fec __iomem *fec = priv->fec;
+
+		/*
+		 * If the MAC addresse is not provided via DT then read
+		 * it back from the controller regs
+		 */
+		*(u32 *)(&ndev->dev_addr[0]) = in_be32(&fec->paddr1);
+		*(u16 *)(&ndev->dev_addr[4]) = in_be32(&fec->paddr2) >> 16;
+	}
+
+	/*
+	 * Check if the MAC address is valid, if not get a random one
+	 */
+	if (!is_valid_ether_addr(ndev->dev_addr)) {
+		eth_hw_addr_random(ndev);
+		dev_warn(&ndev->dev, "using random MAC address %pM\n",
+			 ndev->dev_addr);
+	}
 
 	priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
 
@@ -942,20 +954,20 @@
 	/* Start with safe defaults for link connection */
 	priv->speed = 100;
 	priv->duplex = DUPLEX_HALF;
-	priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->dev.of_node) >> 20) / 5) << 1;
+	priv->mdio_speed = ((mpc5xxx_get_bus_frequency(np) >> 20) / 5) << 1;
 
 	/* The current speed preconfigures the speed of the MII link */
-	prop = of_get_property(op->dev.of_node, "current-speed", &prop_size);
+	prop = of_get_property(np, "current-speed", &prop_size);
 	if (prop && (prop_size >= sizeof(u32) * 2)) {
 		priv->speed = prop[0];
 		priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
 	}
 
 	/* If there is a phy handle, then get the PHY node */
-	priv->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
+	priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
 
 	/* the 7-wire property means don't use MII mode */
-	if (of_find_property(op->dev.of_node, "fsl,7-wire-mode", NULL)) {
+	if (of_find_property(np, "fsl,7-wire-mode", NULL)) {
 		priv->seven_wire_mode = 1;
 		dev_info(&ndev->dev, "using 7-wire PHY mode\n");
 	}
@@ -970,6 +982,8 @@
 
 	/* We're done ! */
 	dev_set_drvdata(&op->dev, ndev);
+	printk(KERN_INFO "%s: %s MAC %pM\n",
+	       ndev->name, op->dev.of_node->full_name, ndev->dev_addr);
 
 	return 0;
 
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index c40526c..1f17ca0 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -104,7 +104,7 @@
 	unsigned long flags;
 	int inc;
 
-	inc = 1000000000 / clk_get_rate(fep->clk_ptp);
+	inc = 1000000000 / fep->cycle_speed;
 
 	/* grab the ptp lock */
 	spin_lock_irqsave(&fep->tmreg_lock, flags);
@@ -363,6 +363,8 @@
 	fep->ptp_caps.settime = fec_ptp_settime;
 	fep->ptp_caps.enable = fec_ptp_enable;
 
+	fep->cycle_speed = clk_get_rate(fep->clk_ptp);
+
 	spin_lock_init(&fep->tmreg_lock);
 
 	fec_ptp_start_cyclecounter(ndev);
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index e9879c5..46df288 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -888,8 +888,8 @@
 static void fs_get_drvinfo(struct net_device *dev,
 			    struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_MODULE_NAME);
-	strcpy(info->version, DRV_MODULE_VERSION);
+	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int fs_get_regs_len(struct net_device *dev)
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index bffb2ed..4b5e8a6 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -133,8 +133,8 @@
 #endif
 int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
 static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
-static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
-			      int amount_pull, struct napi_struct *napi);
+static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
+			       int amount_pull, struct napi_struct *napi);
 void gfar_halt(struct net_device *dev);
 static void gfar_halt_nodisable(struct net_device *dev);
 void gfar_start(struct net_device *dev);
@@ -231,7 +231,7 @@
 	dma_addr_t addr;
 	int i, j, k;
 	struct gfar_private *priv = netdev_priv(ndev);
-	struct device *dev = &priv->ofdev->dev;
+	struct device *dev = priv->dev;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 
@@ -277,14 +277,12 @@
 	/* Setup the skbuff rings */
 	for (i = 0; i < priv->num_tx_queues; i++) {
 		tx_queue = priv->tx_queue[i];
-		tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) *
-					      tx_queue->tx_ring_size,
-					      GFP_KERNEL);
-		if (!tx_queue->tx_skbuff) {
-			netif_err(priv, ifup, ndev,
-				  "Could not allocate tx_skbuff\n");
+		tx_queue->tx_skbuff =
+			kmalloc_array(tx_queue->tx_ring_size,
+				      sizeof(*tx_queue->tx_skbuff),
+				      GFP_KERNEL);
+		if (!tx_queue->tx_skbuff)
 			goto cleanup;
-		}
 
 		for (k = 0; k < tx_queue->tx_ring_size; k++)
 			tx_queue->tx_skbuff[k] = NULL;
@@ -292,15 +290,12 @@
 
 	for (i = 0; i < priv->num_rx_queues; i++) {
 		rx_queue = priv->rx_queue[i];
-		rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) *
-					      rx_queue->rx_ring_size,
-					      GFP_KERNEL);
-
-		if (!rx_queue->rx_skbuff) {
-			netif_err(priv, ifup, ndev,
-				  "Could not allocate rx_skbuff\n");
+		rx_queue->rx_skbuff =
+			kmalloc_array(rx_queue->rx_ring_size,
+				      sizeof(*rx_queue->rx_skbuff),
+				      GFP_KERNEL);
+		if (!rx_queue->rx_skbuff)
 			goto cleanup;
-		}
 
 		for (j = 0; j < rx_queue->rx_ring_size; j++)
 			rx_queue->rx_skbuff[j] = NULL;
@@ -349,14 +344,23 @@
 	/* Configure the coalescing support */
 	gfar_configure_coalescing(priv, 0xFF, 0xFF);
 
+	/* set this when rx hw offload (TOE) functions are being used */
+	priv->uses_rxfcb = 0;
+
 	if (priv->rx_filer_enable) {
 		rctrl |= RCTRL_FILREN;
 		/* Program the RIR0 reg with the required distribution */
 		gfar_write(&regs->rir0, DEFAULT_RIR0);
 	}
 
-	if (ndev->features & NETIF_F_RXCSUM)
+	/* Restore PROMISC mode */
+	if (ndev->flags & IFF_PROMISC)
+		rctrl |= RCTRL_PROM;
+
+	if (ndev->features & NETIF_F_RXCSUM) {
 		rctrl |= RCTRL_CHECKSUMMING;
+		priv->uses_rxfcb = 1;
+	}
 
 	if (priv->extended_hash) {
 		rctrl |= RCTRL_EXTHASH;
@@ -378,11 +382,15 @@
 	}
 
 	/* Enable HW time stamping if requested from user space */
-	if (priv->hwts_rx_en)
+	if (priv->hwts_rx_en) {
 		rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
+		priv->uses_rxfcb = 1;
+	}
 
-	if (ndev->features & NETIF_F_HW_VLAN_RX)
+	if (ndev->features & NETIF_F_HW_VLAN_RX) {
 		rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
+		priv->uses_rxfcb = 1;
+	}
 
 	/* Init rctrl based on our settings */
 	gfar_write(&regs->rctrl, rctrl);
@@ -501,20 +509,6 @@
 		spin_unlock(&priv->tx_queue[i]->txlock);
 }
 
-static bool gfar_is_vlan_on(struct gfar_private *priv)
-{
-	return (priv->ndev->features & NETIF_F_HW_VLAN_RX) ||
-	       (priv->ndev->features & NETIF_F_HW_VLAN_TX);
-}
-
-/* Returns 1 if incoming frames use an FCB */
-static inline int gfar_uses_fcb(struct gfar_private *priv)
-{
-	return gfar_is_vlan_on(priv) ||
-	       (priv->ndev->features & NETIF_F_RXCSUM) ||
-	       (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
-}
-
 static void free_tx_pointers(struct gfar_private *priv)
 {
 	int i;
@@ -540,6 +534,19 @@
 			iounmap(priv->gfargrp[i].regs);
 }
 
+static void free_gfar_dev(struct gfar_private *priv)
+{
+	int i, j;
+
+	for (i = 0; i < priv->num_grps; i++)
+		for (j = 0; j < GFAR_NUM_IRQS; j++) {
+			kfree(priv->gfargrp[i].irqinfo[j]);
+			priv->gfargrp[i].irqinfo[j] = NULL;
+		}
+
+	free_netdev(priv->ndev);
+}
+
 static void disable_napi(struct gfar_private *priv)
 {
 	int i;
@@ -559,40 +566,46 @@
 static int gfar_parse_group(struct device_node *np,
 			    struct gfar_private *priv, const char *model)
 {
+	struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
 	u32 *queue_mask;
+	int i;
 
-	priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0);
-	if (!priv->gfargrp[priv->num_grps].regs)
+	for (i = 0; i < GFAR_NUM_IRQS; i++) {
+		grp->irqinfo[i] = kzalloc(sizeof(struct gfar_irqinfo),
+					  GFP_KERNEL);
+		if (!grp->irqinfo[i])
+			return -ENOMEM;
+	}
+
+	grp->regs = of_iomap(np, 0);
+	if (!grp->regs)
 		return -ENOMEM;
 
-	priv->gfargrp[priv->num_grps].interruptTransmit =
-			irq_of_parse_and_map(np, 0);
+	gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);
 
 	/* If we aren't the FEC we have multiple interrupts */
 	if (model && strcasecmp(model, "FEC")) {
-		priv->gfargrp[priv->num_grps].interruptReceive =
-			irq_of_parse_and_map(np, 1);
-		priv->gfargrp[priv->num_grps].interruptError =
-			irq_of_parse_and_map(np,2);
-		if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ ||
-		    priv->gfargrp[priv->num_grps].interruptReceive  == NO_IRQ ||
-		    priv->gfargrp[priv->num_grps].interruptError    == NO_IRQ)
+		gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
+		gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
+		if (gfar_irq(grp, TX)->irq == NO_IRQ ||
+		    gfar_irq(grp, RX)->irq == NO_IRQ ||
+		    gfar_irq(grp, ER)->irq == NO_IRQ)
 			return -EINVAL;
 	}
 
-	priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
-	priv->gfargrp[priv->num_grps].priv = priv;
-	spin_lock_init(&priv->gfargrp[priv->num_grps].grplock);
+	grp->grp_id = priv->num_grps;
+	grp->priv = priv;
+	spin_lock_init(&grp->grplock);
 	if (priv->mode == MQ_MG_MODE) {
 		queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
-		priv->gfargrp[priv->num_grps].rx_bit_map = queue_mask ?
+		grp->rx_bit_map = queue_mask ?
 			*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
 		queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
-		priv->gfargrp[priv->num_grps].tx_bit_map = queue_mask ?
+		grp->tx_bit_map = queue_mask ?
 			*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
 	} else {
-		priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF;
-		priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF;
+		grp->rx_bit_map = 0xFF;
+		grp->tx_bit_map = 0xFF;
 	}
 	priv->num_grps++;
 
@@ -645,7 +658,6 @@
 		return -ENOMEM;
 
 	priv = netdev_priv(dev);
-	priv->node = ofdev->dev.of_node;
 	priv->ndev = dev;
 
 	priv->num_tx_queues = num_tx_qs;
@@ -777,7 +789,7 @@
 	free_tx_pointers(priv);
 err_grp_init:
 	unmap_group_regs(priv);
-	free_netdev(dev);
+	free_gfar_dev(priv);
 	return err;
 }
 
@@ -983,7 +995,7 @@
 	priv = netdev_priv(dev);
 	priv->ndev = dev;
 	priv->ofdev = ofdev;
-	priv->node = ofdev->dev.of_node;
+	priv->dev = &ofdev->dev;
 	SET_NETDEV_DEV(dev, &ofdev->dev);
 
 	spin_lock_init(&priv->bflock);
@@ -1020,8 +1032,6 @@
 	/* Set the dev->base_addr to the gfar reg region */
 	dev->base_addr = (unsigned long) regs;
 
-	SET_NETDEV_DEV(dev, &ofdev->dev);
-
 	/* Fill in the dev structure */
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->mtu = 1500;
@@ -1182,15 +1192,16 @@
 
 	/* fill out IRQ number and name fields */
 	for (i = 0; i < priv->num_grps; i++) {
+		struct gfar_priv_grp *grp = &priv->gfargrp[i];
 		if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-			sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s",
+			sprintf(gfar_irq(grp, TX)->name, "%s%s%c%s",
 				dev->name, "_g", '0' + i, "_tx");
-			sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s",
+			sprintf(gfar_irq(grp, RX)->name, "%s%s%c%s",
 				dev->name, "_g", '0' + i, "_rx");
-			sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s",
+			sprintf(gfar_irq(grp, ER)->name, "%s%s%c%s",
 				dev->name, "_g", '0' + i, "_er");
 		} else
-			strcpy(priv->gfargrp[i].int_name_tx, dev->name);
+			strcpy(gfar_irq(grp, TX)->name, dev->name);
 	}
 
 	/* Initialize the filer table */
@@ -1223,7 +1234,7 @@
 		of_node_put(priv->phy_node);
 	if (priv->tbi_node)
 		of_node_put(priv->tbi_node);
-	free_netdev(dev);
+	free_gfar_dev(priv);
 	return err;
 }
 
@@ -1240,7 +1251,7 @@
 
 	unregister_netdev(priv->ndev);
 	unmap_group_regs(priv);
-	free_netdev(priv->ndev);
+	free_gfar_dev(priv);
 
 	return 0;
 }
@@ -1648,9 +1659,9 @@
 
 static void free_grp_irqs(struct gfar_priv_grp *grp)
 {
-	free_irq(grp->interruptError, grp);
-	free_irq(grp->interruptTransmit, grp);
-	free_irq(grp->interruptReceive, grp);
+	free_irq(gfar_irq(grp, TX)->irq, grp);
+	free_irq(gfar_irq(grp, RX)->irq, grp);
+	free_irq(gfar_irq(grp, ER)->irq, grp);
 }
 
 void stop_gfar(struct net_device *dev)
@@ -1679,7 +1690,7 @@
 			free_grp_irqs(&priv->gfargrp[i]);
 	} else {
 		for (i = 0; i < priv->num_grps; i++)
-			free_irq(priv->gfargrp[i].interruptTransmit,
+			free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
 				 &priv->gfargrp[i]);
 	}
 
@@ -1698,13 +1709,13 @@
 		if (!tx_queue->tx_skbuff[i])
 			continue;
 
-		dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr,
+		dma_unmap_single(priv->dev, txbdp->bufPtr,
 				 txbdp->length, DMA_TO_DEVICE);
 		txbdp->lstatus = 0;
 		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags;
 		     j++) {
 			txbdp++;
-			dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr,
+			dma_unmap_page(priv->dev, txbdp->bufPtr,
 				       txbdp->length, DMA_TO_DEVICE);
 		}
 		txbdp++;
@@ -1725,8 +1736,8 @@
 
 	for (i = 0; i < rx_queue->rx_ring_size; i++) {
 		if (rx_queue->rx_skbuff[i]) {
-			dma_unmap_single(&priv->ofdev->dev,
-					 rxbdp->bufPtr, priv->rx_buffer_size,
+			dma_unmap_single(priv->dev, rxbdp->bufPtr,
+					 priv->rx_buffer_size,
 					 DMA_FROM_DEVICE);
 			dev_kfree_skb_any(rx_queue->rx_skbuff[i]);
 			rx_queue->rx_skbuff[i] = NULL;
@@ -1765,7 +1776,7 @@
 			free_skb_rx_queue(rx_queue);
 	}
 
-	dma_free_coherent(&priv->ofdev->dev,
+	dma_free_coherent(priv->dev,
 			  sizeof(struct txbd8) * priv->total_tx_ring_size +
 			  sizeof(struct rxbd8) * priv->total_rx_ring_size,
 			  priv->tx_queue[0]->tx_bd_base,
@@ -1854,32 +1865,34 @@
 		/* Install our interrupt handlers for Error,
 		 * Transmit, and Receive
 		 */
-		if ((err = request_irq(grp->interruptError, gfar_error,
-				       0, grp->int_name_er, grp)) < 0) {
+		err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0,
+				  gfar_irq(grp, ER)->name, grp);
+		if (err < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-				  grp->interruptError);
+				  gfar_irq(grp, ER)->irq);
 
 			goto err_irq_fail;
 		}
-
-		if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
-				       0, grp->int_name_tx, grp)) < 0) {
+		err = request_irq(gfar_irq(grp, TX)->irq, gfar_transmit, 0,
+				  gfar_irq(grp, TX)->name, grp);
+		if (err < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-				  grp->interruptTransmit);
+				  gfar_irq(grp, TX)->irq);
 			goto tx_irq_fail;
 		}
-
-		if ((err = request_irq(grp->interruptReceive, gfar_receive,
-				       0, grp->int_name_rx, grp)) < 0) {
+		err = request_irq(gfar_irq(grp, RX)->irq, gfar_receive, 0,
+				  gfar_irq(grp, RX)->name, grp);
+		if (err < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-				  grp->interruptReceive);
+				  gfar_irq(grp, RX)->irq);
 			goto rx_irq_fail;
 		}
 	} else {
-		if ((err = request_irq(grp->interruptTransmit, gfar_interrupt,
-				       0, grp->int_name_tx, grp)) < 0) {
+		err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
+				  gfar_irq(grp, TX)->name, grp);
+		if (err < 0) {
 			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
-				  grp->interruptTransmit);
+				  gfar_irq(grp, TX)->irq);
 			goto err_irq_fail;
 		}
 	}
@@ -1887,9 +1900,9 @@
 	return 0;
 
 rx_irq_fail:
-	free_irq(grp->interruptTransmit, grp);
+	free_irq(gfar_irq(grp, TX)->irq, grp);
 tx_irq_fail:
-	free_irq(grp->interruptError, grp);
+	free_irq(gfar_irq(grp, ER)->irq, grp);
 err_irq_fail:
 	return err;
 
@@ -2143,7 +2156,7 @@
 			if (i == nr_frags - 1)
 				lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
 
-			bufaddr = skb_frag_dma_map(&priv->ofdev->dev,
+			bufaddr = skb_frag_dma_map(priv->dev,
 						   &skb_shinfo(skb)->frags[i],
 						   0,
 						   length,
@@ -2195,7 +2208,7 @@
 		lstatus |= BD_LFLAG(TXBD_TOE);
 	}
 
-	txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
+	txbdp_start->bufPtr = dma_map_single(priv->dev, skb->data,
 					     skb_headlen(skb), DMA_TO_DEVICE);
 
 	/* If time stamping is requested one additional TxBD must be set up. The
@@ -2308,10 +2321,13 @@
 
 	tempval = gfar_read(&regs->rctrl);
 	/* If parse is no longer required, then disable parser */
-	if (tempval & RCTRL_REQ_PARSER)
+	if (tempval & RCTRL_REQ_PARSER) {
 		tempval |= RCTRL_PRSDEP_INIT;
-	else
+		priv->uses_rxfcb = 1;
+	} else {
 		tempval &= ~RCTRL_PRSDEP_INIT;
+		priv->uses_rxfcb = 0;
+	}
 	gfar_write(&regs->rctrl, tempval);
 }
 
@@ -2344,6 +2360,7 @@
 		tempval = gfar_read(&regs->rctrl);
 		tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
 		gfar_write(&regs->rctrl, tempval);
+		priv->uses_rxfcb = 1;
 	} else {
 		/* Disable VLAN tag extraction */
 		tempval = gfar_read(&regs->rctrl);
@@ -2367,15 +2384,12 @@
 	int oldsize = priv->rx_buffer_size;
 	int frame_size = new_mtu + ETH_HLEN;
 
-	if (gfar_is_vlan_on(priv))
-		frame_size += VLAN_HLEN;
-
 	if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
 		netif_err(priv, drv, dev, "Invalid MTU setting\n");
 		return -EINVAL;
 	}
 
-	if (gfar_uses_fcb(priv))
+	if (priv->uses_rxfcb)
 		frame_size += GMAC_FCB_LEN;
 
 	frame_size += priv->padding;
@@ -2508,7 +2522,7 @@
 		} else
 			buflen = bdp->length;
 
-		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
+		dma_unmap_single(priv->dev, bdp->bufPtr,
 				 buflen, DMA_TO_DEVICE);
 
 		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
@@ -2527,7 +2541,7 @@
 		bdp = next_txbd(bdp, base, tx_ring_size);
 
 		for (i = 0; i < frags; i++) {
-			dma_unmap_page(&priv->ofdev->dev, bdp->bufPtr,
+			dma_unmap_page(priv->dev, bdp->bufPtr,
 				       bdp->length, DMA_TO_DEVICE);
 			bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
 			bdp = next_txbd(bdp, base, tx_ring_size);
@@ -2593,7 +2607,7 @@
 	struct gfar_private *priv = netdev_priv(dev);
 	dma_addr_t buf;
 
-	buf = dma_map_single(&priv->ofdev->dev, skb->data,
+	buf = dma_map_single(priv->dev, skb->data,
 			     priv->rx_buffer_size, DMA_FROM_DEVICE);
 	gfar_init_rxbdp(rx_queue, bdp, buf);
 }
@@ -2627,7 +2641,7 @@
 	if (status & RXBD_TRUNCATED) {
 		stats->rx_length_errors++;
 
-		estats->rx_trunc++;
+		atomic64_inc(&estats->rx_trunc);
 
 		return;
 	}
@@ -2636,20 +2650,20 @@
 		stats->rx_length_errors++;
 
 		if (status & RXBD_LARGE)
-			estats->rx_large++;
+			atomic64_inc(&estats->rx_large);
 		else
-			estats->rx_short++;
+			atomic64_inc(&estats->rx_short);
 	}
 	if (status & RXBD_NONOCTET) {
 		stats->rx_frame_errors++;
-		estats->rx_nonoctet++;
+		atomic64_inc(&estats->rx_nonoctet);
 	}
 	if (status & RXBD_CRCERR) {
-		estats->rx_crcerr++;
+		atomic64_inc(&estats->rx_crcerr);
 		stats->rx_crc_errors++;
 	}
 	if (status & RXBD_OVERRUN) {
-		estats->rx_overrun++;
+		atomic64_inc(&estats->rx_overrun);
 		stats->rx_crc_errors++;
 	}
 }
@@ -2674,8 +2688,8 @@
 
 
 /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */
-static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
-			      int amount_pull, struct napi_struct *napi)
+static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
+			       int amount_pull, struct napi_struct *napi)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct rxfcb *fcb = NULL;
@@ -2722,10 +2736,8 @@
 	/* Send the packet up the stack */
 	ret = napi_gro_receive(napi, skb);
 
-	if (GRO_DROP == ret)
-		priv->extra_stats.kernel_dropped++;
-
-	return 0;
+	if (unlikely(GRO_DROP == ret))
+		atomic64_inc(&priv->extra_stats.kernel_dropped);
 }
 
 /* gfar_clean_rx_ring() -- Processes each frame in the rx ring
@@ -2746,7 +2758,7 @@
 	bdp = rx_queue->cur_rx;
 	base = rx_queue->rx_bd_base;
 
-	amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0);
+	amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0;
 
 	while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
 		struct sk_buff *newskb;
@@ -2758,7 +2770,7 @@
 
 		skb = rx_queue->rx_skbuff[rx_queue->skb_currx];
 
-		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
+		dma_unmap_single(priv->dev, bdp->bufPtr,
 				 priv->rx_buffer_size, DMA_FROM_DEVICE);
 
 		if (unlikely(!(bdp->status & RXBD_ERR) &&
@@ -2791,7 +2803,7 @@
 			} else {
 				netif_warn(priv, rx_err, dev, "Missing skb!\n");
 				rx_queue->stats.rx_dropped++;
-				priv->extra_stats.rx_skbmissing++;
+				atomic64_inc(&priv->extra_stats.rx_skbmissing);
 			}
 
 		}
@@ -3224,7 +3236,7 @@
 			netif_dbg(priv, tx_err, dev,
 				  "TX FIFO underrun, packet dropped\n");
 			dev->stats.tx_dropped++;
-			priv->extra_stats.tx_underrun++;
+			atomic64_inc(&priv->extra_stats.tx_underrun);
 
 			local_irq_save(flags);
 			lock_tx_qs(priv);
@@ -3239,7 +3251,7 @@
 	}
 	if (events & IEVENT_BSY) {
 		dev->stats.rx_errors++;
-		priv->extra_stats.rx_bsy++;
+		atomic64_inc(&priv->extra_stats.rx_bsy);
 
 		gfar_receive(irq, grp_id);
 
@@ -3248,19 +3260,19 @@
 	}
 	if (events & IEVENT_BABR) {
 		dev->stats.rx_errors++;
-		priv->extra_stats.rx_babr++;
+		atomic64_inc(&priv->extra_stats.rx_babr);
 
 		netif_dbg(priv, rx_err, dev, "babbling RX error\n");
 	}
 	if (events & IEVENT_EBERR) {
-		priv->extra_stats.eberr++;
+		atomic64_inc(&priv->extra_stats.eberr);
 		netif_dbg(priv, rx_err, dev, "bus error\n");
 	}
 	if (events & IEVENT_RXC)
 		netif_dbg(priv, rx_status, dev, "control frame\n");
 
 	if (events & IEVENT_BABT) {
-		priv->extra_stats.tx_babt++;
+		atomic64_inc(&priv->extra_stats.tx_babt);
 		netif_dbg(priv, tx_err, dev, "babbling TX error\n");
 	}
 	return IRQ_HANDLED;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 22eabc1..63a28d2 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -627,36 +627,29 @@
 };
 
 struct gfar_extra_stats {
-	u64 kernel_dropped;
-	u64 rx_large;
-	u64 rx_short;
-	u64 rx_nonoctet;
-	u64 rx_crcerr;
-	u64 rx_overrun;
-	u64 rx_bsy;
-	u64 rx_babr;
-	u64 rx_trunc;
-	u64 eberr;
-	u64 tx_babt;
-	u64 tx_underrun;
-	u64 rx_skbmissing;
-	u64 tx_timeout;
+	atomic64_t kernel_dropped;
+	atomic64_t rx_large;
+	atomic64_t rx_short;
+	atomic64_t rx_nonoctet;
+	atomic64_t rx_crcerr;
+	atomic64_t rx_overrun;
+	atomic64_t rx_bsy;
+	atomic64_t rx_babr;
+	atomic64_t rx_trunc;
+	atomic64_t eberr;
+	atomic64_t tx_babt;
+	atomic64_t tx_underrun;
+	atomic64_t rx_skbmissing;
+	atomic64_t tx_timeout;
 };
 
 #define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32))
-#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64))
+#define GFAR_EXTRA_STATS_LEN \
+	(sizeof(struct gfar_extra_stats)/sizeof(atomic64_t))
 
-/* Number of stats in the stats structure (ignore car and cam regs)*/
+/* Number of stats exported via ethtool */
 #define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN)
 
-#define GFAR_INFOSTR_LEN 32
-
-struct gfar_stats {
-	u64 extra[GFAR_EXTRA_STATS_LEN];
-	u64 rmon[GFAR_RMON_LEN];
-};
-
-
 struct gfar {
 	u32	tsec_id;	/* 0x.000 - Controller ID register */
 	u32	tsec_id2;	/* 0x.004 - Controller ID2 register */
@@ -937,26 +930,25 @@
  *	@txtime: coalescing value if based on time
  */
 struct gfar_priv_tx_q {
+	/* cacheline 1 */
 	spinlock_t txlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
-	struct sk_buff ** tx_skbuff;
-	/* Buffer descriptor pointers */
-	dma_addr_t tx_bd_dma_base;
 	struct	txbd8 *tx_bd_base;
 	struct	txbd8 *cur_tx;
-	struct	txbd8 *dirty_tx;
-	struct tx_q_stats stats;
-	struct	net_device *dev;
-	struct gfar_priv_grp *grp;
-	u16	skb_curtx;
-	u16	skb_dirtytx;
-	u16	qindex;
-	unsigned int tx_ring_size;
 	unsigned int num_txbdfree;
+	unsigned short skb_curtx;
+	unsigned short tx_ring_size;
+	struct tx_q_stats stats;
+	struct gfar_priv_grp *grp;
+	/* cacheline 2 */
+	struct net_device *dev;
+	struct sk_buff **tx_skbuff;
+	struct	txbd8 *dirty_tx;
+	unsigned short skb_dirtytx;
+	unsigned short qindex;
 	/* Configuration info for the coalescing features */
-	unsigned char txcoalescing;
+	unsigned int txcoalescing;
 	unsigned long txic;
-	unsigned short txcount;
-	unsigned short txtime;
+	dma_addr_t tx_bd_dma_base;
 };
 
 /*
@@ -999,18 +991,25 @@
 	unsigned long rxic;
 };
 
+enum gfar_irqinfo_id {
+	GFAR_TX = 0,
+	GFAR_RX = 1,
+	GFAR_ER = 2,
+	GFAR_NUM_IRQS = 3
+};
+
+struct gfar_irqinfo {
+	unsigned int irq;
+	char name[GFAR_INT_NAME_MAX];
+};
+
 /**
  *	struct gfar_priv_grp - per group structure
  *	@napi: the napi poll function
  *	@priv: back pointer to the priv structure
  *	@regs: the ioremapped register space for this group
  *	@grp_id: group id for this group
- *	@interruptTransmit: The TX interrupt number for this group
- *	@interruptReceive: The RX interrupt number for this group
- *	@interruptError: The ERROR interrupt number for this group
- *	@int_name_tx: tx interrupt name for this group
- *	@int_name_rx: rx interrupt name for this group
- *	@int_name_er: er interrupt name for this group
+ *	@irqinfo: TX/RX/ER irq data for this group
  */
 
 struct gfar_priv_grp {
@@ -1019,23 +1018,20 @@
 	struct gfar_private *priv;
 	struct gfar __iomem *regs;
 	unsigned int grp_id;
-	unsigned long rx_bit_map;
-	unsigned long tx_bit_map;
-	unsigned long num_tx_queues;
 	unsigned long num_rx_queues;
+	unsigned long rx_bit_map;
+	/* cacheline 3 */
 	unsigned int rstat;
 	unsigned int tstat;
-	unsigned int imask;
-	unsigned int ievent;
-	unsigned int interruptTransmit;
-	unsigned int interruptReceive;
-	unsigned int interruptError;
+	unsigned long num_tx_queues;
+	unsigned long tx_bit_map;
 
-	char int_name_tx[GFAR_INT_NAME_MAX];
-	char int_name_rx[GFAR_INT_NAME_MAX];
-	char int_name_er[GFAR_INT_NAME_MAX];
+	struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];
 };
 
+#define gfar_irq(grp, ID) \
+	((grp)->irqinfo[GFAR_##ID])
+
 enum gfar_errata {
 	GFAR_ERRATA_74		= 0x01,
 	GFAR_ERRATA_76		= 0x02,
@@ -1053,28 +1049,65 @@
  * the buffer descriptor determines the actual condition.
  */
 struct gfar_private {
-
-	/* Indicates how many tx, rx queues are enabled */
-	unsigned int num_tx_queues;
 	unsigned int num_rx_queues;
-	unsigned int num_grps;
+
+	struct device *dev;
+	struct net_device *ndev;
+	enum gfar_errata errata;
+	unsigned int rx_buffer_size;
+
+	u16 uses_rxfcb;
+	u16 padding;
+
+	/* HW time stamping enabled flag */
+	int hwts_rx_en;
+	int hwts_tx_en;
+
+	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
+	struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
+	struct gfar_priv_grp gfargrp[MAXGROUPS];
+
+	u32 device_flags;
+
 	unsigned int mode;
+	unsigned int num_tx_queues;
+	unsigned int num_grps;
+
+	/* Network Statistics */
+	struct gfar_extra_stats extra_stats;
+
+	/* PHY stuff */
+	phy_interface_t interface;
+	struct device_node *phy_node;
+	struct device_node *tbi_node;
+	struct phy_device *phydev;
+	struct mii_bus *mii_bus;
+	int oldspeed;
+	int oldduplex;
+	int oldlink;
+
+	/* Bitfield update lock */
+	spinlock_t bflock;
+
+	uint32_t msg_enable;
+
+	struct work_struct reset_task;
+
+	struct platform_device *ofdev;
+	unsigned char
+		extended_hash:1,
+		bd_stash_en:1,
+		rx_filer_enable:1,
+		/* Wake-on-LAN enabled */
+		wol_en:1,
+		/* Enable priorty based Tx scheduling in Hw */
+		prio_sched_en:1;
 
 	/* The total tx and rx ring size for the enabled queues */
 	unsigned int total_tx_ring_size;
 	unsigned int total_rx_ring_size;
 
-	struct device_node *node;
-	struct net_device *ndev;
-	struct platform_device *ofdev;
-	enum gfar_errata errata;
-
-	struct gfar_priv_grp gfargrp[MAXGROUPS];
-	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
-	struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
-
 	/* RX per device parameters */
-	unsigned int rx_buffer_size;
 	unsigned int rx_stash_size;
 	unsigned int rx_stash_index;
 
@@ -1093,39 +1126,6 @@
 	unsigned int fifo_starve;
 	unsigned int fifo_starve_off;
 
-	/* Bitfield update lock */
-	spinlock_t bflock;
-
-	phy_interface_t interface;
-	struct device_node *phy_node;
-	struct device_node *tbi_node;
-	u32 device_flags;
-	unsigned char
-		extended_hash:1,
-		bd_stash_en:1,
-		rx_filer_enable:1,
-		wol_en:1, /* Wake-on-LAN enabled */
-		prio_sched_en:1; /* Enable priorty based Tx scheduling in Hw */
-	unsigned short padding;
-
-	/* PHY stuff */
-	struct phy_device *phydev;
-	struct mii_bus *mii_bus;
-	int oldspeed;
-	int oldduplex;
-	int oldlink;
-
-	uint32_t msg_enable;
-
-	struct work_struct reset_task;
-
-	/* Network Statistics */
-	struct gfar_extra_stats extra_stats;
-
-	/* HW time stamping enabled flag */
-	int hwts_rx_en;
-	int hwts_tx_en;
-
 	/*Filer table*/
 	unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
 	unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
@@ -1138,16 +1138,16 @@
 	return priv->errata & err;
 }
 
-static inline u32 gfar_read(volatile unsigned __iomem *addr)
+static inline u32 gfar_read(unsigned __iomem *addr)
 {
 	u32 val;
-	val = in_be32(addr);
+	val = ioread32be(addr);
 	return val;
 }
 
-static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
+static inline void gfar_write(unsigned __iomem *addr, u32 val)
 {
-	out_be32(addr, val);
+	iowrite32be(val, addr);
 }
 
 static inline void gfar_write_filer(struct gfar_private *priv,
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index ab6762c..75e89ac 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -149,20 +149,17 @@
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar __iomem *regs = priv->gfargrp[0].regs;
-	u64 *extra = (u64 *) & priv->extra_stats;
+	atomic64_t *extra = (atomic64_t *)&priv->extra_stats;
+
+	for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+		buf[i] = atomic64_read(&extra[i]);
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
 		u32 __iomem *rmon = (u32 __iomem *) &regs->rmon;
-		struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-		for (i = 0; i < GFAR_RMON_LEN; i++)
-			stats->rmon[i] = (u64) gfar_read(&rmon[i]);
-
-		for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
-			stats->extra[i] = extra[i];
-	} else
-		for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
-			buf[i] = extra[i];
+		for (; i < GFAR_STATS_LEN; i++, rmon++)
+			buf[i] = (u64) gfar_read(rmon);
+	}
 }
 
 static int gfar_sset_count(struct net_device *dev, int sset)
@@ -184,10 +181,11 @@
 static void gfar_gdrvinfo(struct net_device *dev,
 			  struct ethtool_drvinfo *drvinfo)
 {
-	strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
-	strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
-	strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
-	strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
+	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, gfar_driver_version,
+		sizeof(drvinfo->version));
+	strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+	strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
 	drvinfo->regdump_len = 0;
 	drvinfo->eedump_len = 0;
 }
@@ -715,12 +713,11 @@
 	int j = MAX_FILER_IDX, l = 0x0;
 	int ret = 1;
 
-	local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
-			      GFP_KERNEL);
-	local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
-			      GFP_KERNEL);
+	local_rqfpr = kmalloc_array(MAX_FILER_IDX + 1, sizeof(unsigned int),
+				    GFP_KERNEL);
+	local_rqfcr = kmalloc_array(MAX_FILER_IDX + 1, sizeof(unsigned int),
+				    GFP_KERNEL);
 	if (!local_rqfpr || !local_rqfcr) {
-		pr_err("Out of memory\n");
 		ret = 0;
 		goto err;
 	}
diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
index 37b0353..1ebf712 100644
--- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
+++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
@@ -350,10 +350,10 @@
 uec_get_drvinfo(struct net_device *netdev,
                        struct ethtool_drvinfo *drvinfo)
 {
-	strncpy(drvinfo->driver, DRV_NAME, 32);
-	strncpy(drvinfo->version, DRV_VERSION, 32);
-	strncpy(drvinfo->fw_version, "N/A", 32);
-	strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
+	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+	strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+	strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
 	drvinfo->eedump_len = 0;
 	drvinfo->regdump_len = uec_get_regs_len(netdev);
 }
diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig
index dffee9d44..c6a8762 100644
--- a/drivers/net/ethernet/fujitsu/Kconfig
+++ b/drivers/net/ethernet/fujitsu/Kconfig
@@ -5,7 +5,7 @@
 config NET_VENDOR_FUJITSU
 	bool "Fujitsu devices"
 	default y
-	depends on ISA || PCMCIA || ((ISA || MCA_LEGACY) && EXPERIMENTAL)
+	depends on ISA || PCMCIA || (ISA && EXPERIMENTAL)
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y
 	  and read the Ethernet-HOWTO, available from
@@ -17,18 +17,6 @@
 
 if NET_VENDOR_FUJITSU
 
-config AT1700
-	tristate "AT1700/1720 support (EXPERIMENTAL)"
-	depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
-	select CRC32
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called at1700.
-
 config PCMCIA_FMVJ18X
 	tristate "Fujitsu FMV-J18x PCMCIA support"
 	depends on PCMCIA
@@ -40,15 +28,4 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called fmvj18x_cs.  If unsure, say N.
 
-config ETH16I
-	tristate "ICL EtherTeam 16i/32 support"
-	depends on ISA
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called eth16i.
-
 endif # NET_VENDOR_FUJITSU
diff --git a/drivers/net/ethernet/fujitsu/Makefile b/drivers/net/ethernet/fujitsu/Makefile
index 2730ae6..21561fd 100644
--- a/drivers/net/ethernet/fujitsu/Makefile
+++ b/drivers/net/ethernet/fujitsu/Makefile
@@ -2,6 +2,4 @@
 # Makefile for the Fujitsu network device drivers.
 #
 
-obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_ETH16I) += eth16i.o
 obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
diff --git a/drivers/net/ethernet/fujitsu/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c
deleted file mode 100644
index 4b80dc4..0000000
--- a/drivers/net/ethernet/fujitsu/at1700.c
+++ /dev/null
@@ -1,791 +0,0 @@
-/* at1700.c: A network device driver for  the Allied Telesis AT1700.
-
-	Written 1993-98 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This is a device driver for the Allied Telesis AT1700, and
-        Fujitsu FMV-181/182/181A/182A/183/184/183A/184A, which are
-	straight-forward Fujitsu MB86965 implementations.
-
-	Modification for Fujitsu FMV-18X cards is done by Yutaka Tamiya
-	(tamy@flab.fujitsu.co.jp).
-
-  Sources:
-    The Fujitsu MB86965 datasheet.
-
-	After the initial version of this driver was written Gerry Sawkins of
-	ATI provided their EEPROM configuration code header file.
-    Thanks to NIIBE Yutaka <gniibe@mri.co.jp> for bug fixes.
-
-    MCA bus (AT1720) support (now deleted) by Rene Schmit <rene@bss.lu>
-
-  Bugs:
-	The MB86965 has a design flaw that makes all probes unreliable.  Not
-	only is it difficult to detect, it also moves around in I/O space in
-	response to inb()s from other device probes!
-*/
-
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-static char version[] __initdata =
-	"at1700.c:v1.16 9/11/06  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#define DRV_NAME "at1700"
-
-/* Tunable parameters. */
-
-/* When to switch from the 64-entry multicast filter to Rx-all-multicast. */
-#define MC_FILTERBREAK 64
-
-/* These unusual address orders are used to verify the CONFIG register. */
-
-static int fmv18x_probe_list[] __initdata = {
-	0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
-};
-
-/*
- *	ISA
- */
-
-static unsigned at1700_probe_list[] __initdata = {
-	0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-typedef unsigned char uchar;
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	spinlock_t lock;
-	unsigned char mc_filter[8];
-	uint jumpered:1;			/* Set iff the board has jumper config. */
-	uint tx_started:1;			/* Packets are on the Tx queue. */
-	uint tx_queue_ready:1;			/* Tx queue is ready to be sent. */
-	uint rx_started:1;			/* Packets are Rxing. */
-	uchar tx_queue;				/* Number of packet on the Tx queue. */
-	ushort tx_queue_len;			/* Current length of the Tx queue. */
-};
-
-
-/* Offsets from the base address. */
-#define STATUS			0
-#define TX_STATUS		0
-#define RX_STATUS		1
-#define TX_INTR			2		/* Bit-mapped interrupt enable registers. */
-#define RX_INTR			3
-#define TX_MODE			4
-#define RX_MODE			5
-#define CONFIG_0		6		/* Misc. configuration settings. */
-#define CONFIG_1		7
-/* Run-time register bank 2 definitions. */
-#define DATAPORT		8		/* Word-wide DMA or programmed-I/O dataport. */
-#define TX_START		10
-#define COL16CNTL		11		/* Control Reg for 16 collisions */
-#define MODE13			13
-#define RX_CTRL			14
-/* Configuration registers only on the '865A/B chips. */
-#define EEPROM_Ctrl 	16
-#define EEPROM_Data 	17
-#define CARDSTATUS	16			/* FMV-18x Card Status */
-#define CARDSTATUS1	17			/* FMV-18x Card Status */
-#define IOCONFIG		18		/* Either read the jumper, or move the I/O. */
-#define IOCONFIG1		19
-#define	SAPROM			20		/* The station address PROM, if no EEPROM. */
-#define MODE24			24
-#define RESET			31		/* Write to reset some parts of the chip. */
-#define AT1700_IO_EXTENT	32
-#define PORT_OFFSET(o) (o)
-
-
-#define TX_TIMEOUT		(HZ/10)
-
-
-/* Index to functions, as function prototypes. */
-
-static int at1700_probe1(struct net_device *dev, int ioaddr);
-static int read_eeprom(long ioaddr, int location);
-static int net_open(struct net_device *dev);
-static netdev_tx_t net_send_packet(struct sk_buff *skb,
-				   struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static void net_tx_timeout (struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
-   */
-
-static int io = 0x260;
-
-static int irq;
-
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, NULL);
-	release_region(dev->base_addr, AT1700_IO_EXTENT);
-}
-
-struct net_device * __init at1700_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	unsigned *port;
-	int err = 0;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-	} else {
-		dev->base_addr = io;
-		dev->irq = irq;
-	}
-
-	if (io > 0x1ff) {	/* Check a single specified location. */
-		err = at1700_probe1(dev, io);
-	} else if (io != 0) {	/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (port = at1700_probe_list; *port; port++) {
-			if (at1700_probe1(dev, *port) == 0)
-				break;
-			dev->irq = irq;
-		}
-		if (!*port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	cleanup_card(dev);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static const struct net_device_ops at1700_netdev_ops = {
-	.ndo_open		= net_open,
-	.ndo_stop		= net_close,
-	.ndo_start_xmit 	= net_send_packet,
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_tx_timeout 	= net_tx_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
-   "signature", the default bit pattern after a reset.  This *doesn't* work --
-   there is no way to reset the bus interface without a complete power-cycle!
-
-   It turns out that ATI came to the same conclusion I did: the only thing
-   that can be done is checking a few bits and then diving right into an
-   EEPROM read. */
-
-static int __init at1700_probe1(struct net_device *dev, int ioaddr)
-{
-	static const char fmv_irqmap[4] = {3, 7, 10, 15};
-	static const char fmv_irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
-	static const char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
-	unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
-	int ret = -ENODEV;
-	struct net_local *lp = netdev_priv(dev);
-
-	if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
-	   That means we have to be careful with the register values we probe
-	   for.
-	 */
-#ifdef notdef
-	printk("at1700 probe at %#x, eeprom is %4.4x %4.4x %4.4x ctrl %4.4x.\n",
-		   ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5),
-		   read_eeprom(ioaddr, 6), inw(ioaddr + EEPROM_Ctrl));
-#endif
-	/* We must check for the EEPROM-config boards first, else accessing
-	   IOCONFIG0 will move the board! */
-	if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr &&
-	    read_eeprom(ioaddr, 4) == 0x0000 &&
-	    (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400)
-		is_at1700 = 1;
-	else if (inb(ioaddr + SAPROM    ) == 0x00 &&
-		 inb(ioaddr + SAPROM + 1) == 0x00 &&
-		 inb(ioaddr + SAPROM + 2) == 0x0e)
-		is_fmv18x = 1;
-	else {
-		goto err_out;
-	}
-
-	/* Reset the internal state machines. */
-	outb(0, ioaddr + RESET);
-
-	if (is_at1700) {
-		irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
-						   | (read_eeprom(ioaddr, 0)>>14)];
-	} else {
-		/* Check PnP mode for FMV-183/184/183A/184A. */
-		/* This PnP routine is very poor. IO and IRQ should be known. */
-		if (inb(ioaddr + CARDSTATUS1) & 0x20) {
-			irq = dev->irq;
-			for (i = 0; i < 8; i++) {
-				if (irq == fmv_irqmap_pnp[i])
-					break;
-			}
-			if (i == 8) {
-				goto err_out;
-			}
-		} else {
-			if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-				goto err_out;
-			irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
-		}
-	}
-
-	printk("%s: %s found at %#3x, IRQ %d, address ", dev->name,
-		   is_at1700 ? "AT1700" : "FMV-18X", ioaddr, irq);
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	if (is_at1700) {
-		for(i = 0; i < 3; i++) {
-			unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
-			((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val);
-		}
-	} else {
-		for(i = 0; i < 6; i++) {
-			unsigned char val = inb(ioaddr + SAPROM + i);
-			dev->dev_addr[i] = val;
-		}
-	}
-	printk("%pM", dev->dev_addr);
-
-	/* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
-	   rather than 150 ohm shielded twisted pair compensation.
-	   0x0000 == auto-sense the interface
-	   0x0800 == use TP interface
-	   0x1800 == use coax interface
-	   */
-	{
-		const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2"};
-		if (is_at1700) {
-			ushort setup_value = read_eeprom(ioaddr, 12);
-			dev->if_port = setup_value >> 8;
-		} else {
-			ushort setup_value = inb(ioaddr + CARDSTATUS);
-			switch (setup_value & 0x07) {
-			case 0x01: /* 10base5 */
-			case 0x02: /* 10base2 */
-				dev->if_port = 0x18; break;
-			case 0x04: /* 10baseT */
-				dev->if_port = 0x08; break;
-			default:   /* auto-sense */
-				dev->if_port = 0x00; break;
-			}
-		}
-		printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]);
-	}
-
-	/* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
-	   bus access, two 4K Tx queues, and disabled Tx and Rx. */
-	outb(0xda, ioaddr + CONFIG_0);
-
-	/* Set the station address in bank zero. */
-	outb(0x00, ioaddr + CONFIG_1);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i));
-
-	/* Switch to bank 1 and set the multicast table to accept none. */
-	outb(0x04, ioaddr + CONFIG_1);
-	for (i = 0; i < 8; i++)
-		outb(0x00, ioaddr + PORT_OFFSET(8 + i));
-
-
-	/* Switch to bank 2 */
-	/* Lock our I/O address, and set manual processing mode for 16 collisions. */
-	outb(0x08, ioaddr + CONFIG_1);
-	outb(dev->if_port, ioaddr + MODE13);
-	outb(0x00, ioaddr + COL16CNTL);
-
-	if (net_debug)
-		printk(version);
-
-	dev->netdev_ops = &at1700_netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	spin_lock_init(&lp->lock);
-
-	lp->jumpered = is_fmv18x;
-	/* Snarf the interrupt vector now. */
-	ret = request_irq(irq, net_interrupt, 0, DRV_NAME, dev);
-	if (ret) {
-		printk(KERN_ERR "AT1700 at %#3x is unusable due to a "
-		       "conflict on IRQ %d.\n",
-		       ioaddr, irq);
-		goto err_out;
-	}
-
-	return 0;
-
-err_out:
-	release_region(ioaddr, AT1700_IO_EXTENT);
-	return ret;
-}
-
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK	0x40	/* EEPROM shift clock, in reg. 16. */
-#define EE_CS			0x20	/* EEPROM chip select, in reg. 16. */
-#define EE_DATA_WRITE	0x80	/* EEPROM chip data in, in reg. 17. */
-#define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD	(5 << 6)
-#define EE_READ_CMD		(6 << 6)
-#define EE_ERASE_CMD	(7 << 6)
-
-static int __init read_eeprom(long ioaddr, int location)
-{
-	int i;
-	unsigned short retval = 0;
-	long ee_addr = ioaddr + EEPROM_Ctrl;
-	long ee_daddr = ioaddr + EEPROM_Data;
-	int read_cmd = location | EE_READ_CMD;
-
-	/* Shift the read command bits out. */
-	for (i = 9; i >= 0; i--) {
-		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-		outb(EE_CS, ee_addr);
-		outb(dataval, ee_daddr);
-		outb(EE_CS | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
-	}
-	outb(EE_DATA_WRITE, ee_daddr);
-	for (i = 16; i > 0; i--) {
-		outb(EE_CS, ee_addr);
-		outb(EE_CS | EE_SHIFT_CLK, ee_addr);
-		retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
-	}
-
-	/* Terminate the EEPROM access. */
-	outb(EE_CS, ee_addr);
-	outb(EE_SHIFT_CLK, ee_addr);
-	outb(0, ee_addr);
-	return retval;
-}
-
-
-
-static int net_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	/* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
-	   bus access, and two 4K Tx queues. */
-	outb(0x5a, ioaddr + CONFIG_0);
-
-	/* Powerup, switch to register bank 2, and enable the Rx and Tx. */
-	outb(0xe8, ioaddr + CONFIG_1);
-
-	lp->tx_started = 0;
-	lp->tx_queue_ready = 1;
-	lp->rx_started = 0;
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-
-	/* Turn on hardware Tx and Rx interrupts. */
-	outb(0x82, ioaddr + TX_INTR);
-	outb(0x81, ioaddr + RX_INTR);
-
-	/* Enable the IRQ on boards of fmv18x it is feasible. */
-	if (lp->jumpered) {
-		outb(0x80, ioaddr + IOCONFIG1);
-	}
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-static void net_tx_timeout (struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
-		inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
-		? "IRQ conflict" : "network cable problem");
-	printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
-	 dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
-		inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
-		inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
-	dev->stats.tx_errors++;
-	/* ToDo: We should try to restart the adaptor... */
-	outw(0xffff, ioaddr + MODE24);
-	outw (0xffff, ioaddr + TX_STATUS);
-	outb (0x5a, ioaddr + CONFIG_0);
-	outb (0xe8, ioaddr + CONFIG_1);
-	outw (0x8182, ioaddr + TX_INTR);
-	outb (0x00, ioaddr + TX_START);
-	outb (0x03, ioaddr + COL16CNTL);
-
-	dev->trans_start = jiffies; /* prevent tx timeout */
-
-	lp->tx_started = 0;
-	lp->tx_queue_ready = 1;
-	lp->rx_started = 0;
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-
-	netif_wake_queue(dev);
-}
-
-
-static netdev_tx_t net_send_packet (struct sk_buff *skb,
-				    struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	short len = skb->len;
-	unsigned char *buf = skb->data;
-	static u8 pad[ETH_ZLEN];
-
-	netif_stop_queue (dev);
-
-	/* We may not start transmitting unless we finish transferring
-	   a packet into the Tx queue. During executing the following
-	   codes we possibly catch a Tx interrupt. Thus we flag off
-	   tx_queue_ready, so that we prevent the interrupt routine
-	   (net_interrupt) to start transmitting. */
-	lp->tx_queue_ready = 0;
-	{
-		outw (length, ioaddr + DATAPORT);
-		/* Packet data */
-		outsw (ioaddr + DATAPORT, buf, len >> 1);
-		/* Check for dribble byte */
-		if (len & 1) {
-			outw(skb->data[skb->len-1], ioaddr + DATAPORT);
-			len++;
-		}
-		/* Check for packet padding */
-		if (length != skb->len)
-			outsw(ioaddr + DATAPORT, pad, (length - len + 1) >> 1);
-
-		lp->tx_queue++;
-		lp->tx_queue_len += length + 2;
-	}
-	lp->tx_queue_ready = 1;
-
-	if (lp->tx_started == 0) {
-		/* If the Tx is idle, always trigger a transmit. */
-		outb (0x80 | lp->tx_queue, ioaddr + TX_START);
-		lp->tx_queue = 0;
-		lp->tx_queue_len = 0;
-		lp->tx_started = 1;
-		netif_start_queue (dev);
-	} else if (lp->tx_queue_len < 4096 - 1502)
-		/* Yes, there is room for one more packet. */
-		netif_start_queue (dev);
-	dev_kfree_skb (skb);
-
-	return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr, status;
-	int handled = 0;
-
-	if (dev == NULL) {
-		printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
-		return IRQ_NONE;
-	}
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	spin_lock (&lp->lock);
-
-	status = inw(ioaddr + TX_STATUS);
-	outw(status, ioaddr + TX_STATUS);
-
-	if (net_debug > 4)
-		printk("%s: Interrupt with status %04x.\n", dev->name, status);
-	if (lp->rx_started == 0 &&
-	    (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
-		/* Got a packet(s).
-		   We cannot execute net_rx more than once at the same time for
-		   the same device. During executing net_rx, we possibly catch a
-		   Tx interrupt. Thus we flag on rx_started, so that we prevent
-		   the interrupt routine (net_interrupt) to dive into net_rx
-		   again. */
-		handled = 1;
-		lp->rx_started = 1;
-		outb(0x00, ioaddr + RX_INTR);	/* Disable RX intr. */
-		net_rx(dev);
-		outb(0x81, ioaddr + RX_INTR);	/* Enable  RX intr. */
-		lp->rx_started = 0;
-	}
-	if (status & 0x00ff) {
-		handled = 1;
-		if (status & 0x02) {
-			/* More than 16 collisions occurred */
-			if (net_debug > 4)
-				printk("%s: 16 Collision occur during Txing.\n", dev->name);
-			/* Cancel sending a packet. */
-			outb(0x03, ioaddr + COL16CNTL);
-			dev->stats.collisions++;
-		}
-		if (status & 0x82) {
-			dev->stats.tx_packets++;
-			/* The Tx queue has any packets and is not being
-			   transferred a packet from the host, start
-			   transmitting. */
-			if (lp->tx_queue && lp->tx_queue_ready) {
-				outb(0x80 | lp->tx_queue, ioaddr + TX_START);
-				lp->tx_queue = 0;
-				lp->tx_queue_len = 0;
-				dev->trans_start = jiffies;
-				netif_wake_queue (dev);
-			} else {
-				lp->tx_started = 0;
-				netif_wake_queue (dev);
-			}
-		}
-	}
-
-	spin_unlock (&lp->lock);
-	return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	int boguscount = 5;
-
-	while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
-		ushort status = inw(ioaddr + DATAPORT);
-		ushort pkt_len = inw(ioaddr + DATAPORT);
-
-		if (net_debug > 4)
-			printk("%s: Rxing packet mode %02x status %04x.\n",
-				   dev->name, inb(ioaddr + RX_MODE), status);
-#ifndef final_version
-		if (status == 0) {
-			outb(0x05, ioaddr + RX_CTRL);
-			break;
-		}
-#endif
-
-		if ((status & 0xF0) != 0x20) {	/* There was an error. */
-			dev->stats.rx_errors++;
-			if (status & 0x08) dev->stats.rx_length_errors++;
-			if (status & 0x04) dev->stats.rx_frame_errors++;
-			if (status & 0x02) dev->stats.rx_crc_errors++;
-			if (status & 0x01) dev->stats.rx_over_errors++;
-		} else {
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-
-			if (pkt_len > 1550) {
-				printk("%s: The AT1700 claimed a very large packet, size %d.\n",
-					   dev->name, pkt_len);
-				/* Prime the FIFO and then flush the packet. */
-				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
-				outb(0x05, ioaddr + RX_CTRL);
-				dev->stats.rx_errors++;
-				break;
-			}
-			skb = netdev_alloc_skb(dev, pkt_len + 3);
-			if (skb == NULL) {
-				printk("%s: Memory squeeze, dropping packet (len %d).\n",
-					   dev->name, pkt_len);
-				/* Prime the FIFO and then flush the packet. */
-				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
-				outb(0x05, ioaddr + RX_CTRL);
-				dev->stats.rx_dropped++;
-				break;
-			}
-			skb_reserve(skb,2);
-
-			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
-			skb->protocol=eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-			dev->stats.rx_bytes += pkt_len;
-		}
-		if (--boguscount <= 0)
-			break;
-	}
-
-	/* If any worth-while packets have been received, dev_rint()
-	   has done a mark_bh(NET_BH) for us and will work on them
-	   when we get to the bottom-half routine. */
-	{
-		int i;
-		for (i = 0; i < 20; i++) {
-			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
-				break;
-			inw(ioaddr + DATAPORT);				/* dummy status read */
-			outb(0x05, ioaddr + RX_CTRL);
-		}
-
-		if (net_debug > 5)
-			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
-				   dev->name, inb(ioaddr + RX_MODE), i);
-	}
-}
-
-/* The inverse routine to net_open(). */
-static int net_close(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	netif_stop_queue(dev);
-
-	/* Set configuration register 0 to disable Tx and Rx. */
-	outb(0xda, ioaddr + CONFIG_0);
-
-	/* No statistic counters on the chip to update. */
-
-	/* Disable the IRQ on boards of fmv18x where it is feasible. */
-	if (lp->jumpered)
-		outb(0x00, ioaddr + IOCONFIG1);
-
-	/* Power-down the chip.  Green, green, green! */
-	outb(0x00, ioaddr + CONFIG_1);
-	return 0;
-}
-
-/*
-  Set the multicast/promiscuous mode for this adaptor.
-*/
-
-static void
-set_rx_mode(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct net_local *lp = netdev_priv(dev);
-	unsigned char mc_filter[8];		 /* Multicast hash filter */
-	unsigned long flags;
-
-	if (dev->flags & IFF_PROMISC) {
-		memset(mc_filter, 0xff, sizeof(mc_filter));
-		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
-	} else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
-			   (dev->flags & IFF_ALLMULTI)) {
-		/* Too many to filter perfectly -- accept all multicasts. */
-		memset(mc_filter, 0xff, sizeof(mc_filter));
-		outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
-	} else if (netdev_mc_empty(dev)) {
-		memset(mc_filter, 0x00, sizeof(mc_filter));
-		outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
-	} else {
-		struct netdev_hw_addr *ha;
-
-		memset(mc_filter, 0, sizeof(mc_filter));
-		netdev_for_each_mc_addr(ha, dev) {
-			unsigned int bit =
-				ether_crc_le(ETH_ALEN, ha->addr) >> 26;
-			mc_filter[bit >> 3] |= (1 << bit);
-		}
-		outb(0x02, ioaddr + RX_MODE);	/* Use normal mode. */
-	}
-
-	spin_lock_irqsave (&lp->lock, flags);
-	if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
-		int i;
-		int saved_bank = inw(ioaddr + CONFIG_0);
-		/* Switch to bank 1 and set the multicast table. */
-		outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
-		for (i = 0; i < 8; i++)
-			outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i));
-		memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
-		outw(saved_bank, ioaddr + CONFIG_0);
-	}
-	spin_unlock_irqrestore (&lp->lock, flags);
-}
-
-#ifdef MODULE
-static struct net_device *dev_at1700;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(net_debug, int, 0);
-MODULE_PARM_DESC(io, "AT1700/FMV18X I/O base address");
-MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number");
-MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)");
-
-static int __init at1700_module_init(void)
-{
-	if (io == 0)
-		printk("at1700: You should not use auto-probing with insmod!\n");
-	dev_at1700 = at1700_probe(-1);
-	if (IS_ERR(dev_at1700))
-		return PTR_ERR(dev_at1700);
-	return 0;
-}
-
-static void __exit at1700_module_exit(void)
-{
-	unregister_netdev(dev_at1700);
-	cleanup_card(dev_at1700);
-	free_netdev(dev_at1700);
-}
-module_init(at1700_module_init);
-module_exit(at1700_module_exit);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/fujitsu/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c
deleted file mode 100644
index a992d1f..0000000
--- a/drivers/net/ethernet/fujitsu/eth16i.c
+++ /dev/null
@@ -1,1483 +0,0 @@
-/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
-
-   Written 1994-1999 by Mika Kuoppala
-
-   Copyright (C) 1994-1999 by Mika Kuoppala
-   Based on skeleton.c and heavily on at1700.c by Donald Becker
-
-   This software may be used and distributed according to the terms
-   of the GNU General Public License, incorporated herein by reference.
-
-   The author may be reached as miku@iki.fi
-
-   This driver supports following cards :
-	- ICL EtherTeam 16i
-	- ICL EtherTeam 32 EISA
-	  (Uses true 32 bit transfers rather than 16i compatibility mode)
-
-   Example Module usage:
-        insmod eth16i.o io=0x2a0 mediatype=bnc
-
-	mediatype can be one of the following: bnc,tp,dix,auto,eprom
-
-	'auto' will try to autoprobe mediatype.
-	'eprom' will use whatever type defined in eprom.
-
-   I have benchmarked driver with PII/300Mhz as a ftp client
-   and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
-
-   Sources:
-     - skeleton.c  a sample network driver core for linux,
-       written by Donald Becker <becker@scyld.com>
-     - at1700.c a driver for Allied Telesis AT1700, written
-       by Donald Becker.
-     - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
-       written by Markku Viima
-     - The Fujitsu MB86965 databook.
-
-   Author thanks following persons due to their valueble assistance:
-        Markku Viima (ICL)
-	Ari Valve (ICL)
-	Donald Becker
-	Kurt Huwig <kurt@huwig.de>
-
-   Revision history:
-
-   Version	Date		Description
-
-   0.01         15.12-94        Initial version (card detection)
-   0.02         23.01-95        Interrupt is now hooked correctly
-   0.03         01.02-95        Rewrote initialization part
-   0.04         07.02-95        Base skeleton done...
-                                Made a few changes to signature checking
-                                to make it a bit reliable.
-                                - fixed bug in tx_buf mapping
-                                - fixed bug in initialization (DLC_EN
-                                  wasn't enabled when initialization
-                                  was done.)
-   0.05         08.02-95        If there were more than one packet to send,
-                                transmit was jammed due to invalid
-                                register write...now fixed
-   0.06         19.02-95        Rewrote interrupt handling
-   0.07         13.04-95        Wrote EEPROM read routines
-                                Card configuration now set according to
-                                data read from EEPROM
-   0.08         23.06-95        Wrote part that tries to probe used interface
-                                port if AUTO is selected
-
-   0.09         01.09-95        Added module support
-
-   0.10         04.09-95        Fixed receive packet allocation to work
-                                with kernels > 1.3.x
-
-   0.20		20.09-95	Added support for EtherTeam32 EISA
-
-   0.21         17.10-95        Removed the unnecessary extern
-				init_etherdev() declaration. Some
-				other cleanups.
-
-   0.22		22.02-96	Receive buffer was not flushed
-				correctly when faulty packet was
-				received. Now fixed.
-
-   0.23		26.02-96	Made resetting the adapter
-			 	more reliable.
-
-   0.24		27.02-96	Rewrote faulty packet handling in eth16i_rx
-
-   0.25		22.05-96	kfree() was missing from cleanup_module.
-
-   0.26		11.06-96	Sometimes card was not found by
-				check_signature(). Now made more reliable.
-
-   0.27		23.06-96	Oops. 16 consecutive collisions halted
-				adapter. Now will try to retransmit
-				MAX_COL_16 times before finally giving up.
-
-   0.28	        28.10-97	Added dev_id parameter (NULL) for free_irq
-
-   0.29         29.10-97        Multiple card support for module users
-
-   0.30         30.10-97        Fixed irq allocation bug.
-                                (request_irq moved from probe to open)
-
-   0.30a        21.08-98        Card detection made more relaxed. Driver
-                                had problems with some TCP/IP-PROM boots
-				to find the card. Suggested by
-				Kurt Huwig <kurt@huwig.de>
-
-   0.31         28.08-98        Media interface port can now be selected
-                                with module parameters or kernel
-				boot parameters.
-
-   0.32         31.08-98        IRQ was never freed if open/close
-                                pair wasn't called. Now fixed.
-
-   0.33         10.09-98        When eth16i_open() was called after
-                                eth16i_close() chip never recovered.
-				Now more shallow reset is made on
-				close.
-
-   0.34         29.06-99	Fixed one bad #ifdef.
-				Changed ioaddr -> io for consistency
-
-   0.35         01.07-99        transmit,-receive bytes were never
-                                updated in stats.
-
-   Bugs:
-	In some cases the media interface autoprobing code doesn't find
-	the correct interface type. In this case you can
-	manually choose the interface type in DOS with E16IC.EXE which is
-	configuration software for EtherTeam16i and EtherTeam32 cards.
-	This is also true for IRQ setting. You cannot use module
-	parameter to configure IRQ of the card (yet).
-
-   To do:
-	- Real multicast support
-	- Rewrite the media interface autoprobing code. Its _horrible_ !
-	- Possibly merge all the MB86965 specific code to external
-	  module for use by eth16.c and Donald's at1700.c
-	- IRQ configuration with module parameter. I will do
-	  this when i will get enough info about setting
-	  irq without configuration utility.
-*/
-
-static char *version =
-    "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-
-
-
-/* Few macros */
-#define BITSET(ioaddr, bnum)   ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
-#define BITCLR(ioaddr, bnum)   ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
-
-/* This is the I/O address space for Etherteam 16i adapter. */
-#define ETH16I_IO_EXTENT       32
-
-/* Ticks before deciding that transmit has timed out */
-#define TX_TIMEOUT             (400*HZ/1000)
-
-/* Maximum loop count when receiving packets */
-#define MAX_RX_LOOP            20
-
-/* Some interrupt masks */
-#define ETH16I_INTR_ON	       0xef8a       /* Higher is receive mask */
-#define ETH16I_INTR_OFF	       0x0000
-
-/* Buffers header status byte meanings */
-#define PKT_GOOD               BIT(5)
-#define PKT_GOOD_RMT           BIT(4)
-#define PKT_SHORT              BIT(3)
-#define PKT_ALIGN_ERR          BIT(2)
-#define PKT_CRC_ERR            BIT(1)
-#define PKT_RX_BUF_OVERFLOW    BIT(0)
-
-/* Transmit status register (DLCR0) */
-#define TX_STATUS_REG          0
-#define TX_DONE                BIT(7)
-#define NET_BUSY               BIT(6)
-#define TX_PKT_RCD             BIT(5)
-#define CR_LOST                BIT(4)
-#define TX_JABBER_ERR	       BIT(3)
-#define COLLISION              BIT(2)
-#define COLLISIONS_16          BIT(1)
-
-/* Receive status register (DLCR1) */
-#define RX_STATUS_REG          1
-#define RX_PKT                 BIT(7)  /* Packet received */
-#define BUS_RD_ERR             BIT(6)
-#define SHORT_PKT_ERR          BIT(3)
-#define ALIGN_ERR              BIT(2)
-#define CRC_ERR                BIT(1)
-#define RX_BUF_OVERFLOW        BIT(0)
-
-/* Transmit Interrupt Enable Register (DLCR2) */
-#define TX_INTR_REG            2
-#define TX_INTR_DONE           BIT(7)
-#define TX_INTR_COL            BIT(2)
-#define TX_INTR_16_COL         BIT(1)
-
-/* Receive Interrupt Enable Register (DLCR3) */
-#define RX_INTR_REG            3
-#define RX_INTR_RECEIVE        BIT(7)
-#define RX_INTR_SHORT_PKT      BIT(3)
-#define RX_INTR_CRC_ERR        BIT(1)
-#define RX_INTR_BUF_OVERFLOW   BIT(0)
-
-/* Transmit Mode Register (DLCR4) */
-#define TRANSMIT_MODE_REG      4
-#define LOOPBACK_CONTROL       BIT(1)
-#define CONTROL_OUTPUT         BIT(2)
-
-/* Receive Mode Register (DLCR5) */
-#define RECEIVE_MODE_REG       5
-#define RX_BUFFER_EMPTY        BIT(6)
-#define ACCEPT_BAD_PACKETS     BIT(5)
-#define RECEIVE_SHORT_ADDR     BIT(4)
-#define ACCEPT_SHORT_PACKETS   BIT(3)
-#define REMOTE_RESET           BIT(2)
-
-#define ADDRESS_FILTER_MODE    BIT(1) | BIT(0)
-#define REJECT_ALL             0
-#define ACCEPT_ALL             3
-#define MODE_1                 1            /* NODE ID, BC, MC, 2-24th bit */
-#define MODE_2                 2            /* NODE ID, BC, MC, Hash Table */
-
-/* Configuration Register 0 (DLCR6) */
-#define CONFIG_REG_0           6
-#define DLC_EN                 BIT(7)
-#define SRAM_CYCLE_TIME_100NS  BIT(6)
-#define SYSTEM_BUS_WIDTH_8     BIT(5)       /* 1 = 8bit, 0 = 16bit */
-#define BUFFER_WIDTH_8         BIT(4)       /* 1 = 8bit, 0 = 16bit */
-#define TBS1                   BIT(3)
-#define TBS0                   BIT(2)
-#define SRAM_BS1               BIT(1)       /* 00=8kb,  01=16kb  */
-#define SRAM_BS0               BIT(0)       /* 10=32kb, 11=64kb  */
-
-#ifndef ETH16I_TX_BUF_SIZE                   /* 0 = 2kb, 1 = 4kb  */
-#define ETH16I_TX_BUF_SIZE     3             /* 2 = 8kb, 3 = 16kb */
-#endif
-#define TX_BUF_1x2048          0
-#define TX_BUF_2x2048          1
-#define TX_BUF_2x4098          2
-#define TX_BUF_2x8192          3
-
-/* Configuration Register 1 (DLCR7) */
-#define CONFIG_REG_1           7
-#define POWERUP                BIT(5)
-
-/* Transmit start register */
-#define TRANSMIT_START_REG     10
-#define TRANSMIT_START_RB      2
-#define TX_START               BIT(7)       /* Rest of register bit indicate*/
-                                            /* number of packets in tx buffer*/
-/* Node ID registers (DLCR8-13) */
-#define NODE_ID_0              8
-#define NODE_ID_RB             0
-
-/* Hash Table registers (HT8-15) */
-#define HASH_TABLE_0           8
-#define HASH_TABLE_RB          1
-
-/* Buffer memory ports */
-#define BUFFER_MEM_PORT_LB     8
-#define DATAPORT               BUFFER_MEM_PORT_LB
-#define BUFFER_MEM_PORT_HB     9
-
-/* 16 Collision control register (BMPR11) */
-#define COL_16_REG             11
-#define HALT_ON_16             0x00
-#define RETRANS_AND_HALT_ON_16 0x02
-
-/* Maximum number of attempts to send after 16 concecutive collisions */
-#define MAX_COL_16	       10
-
-/* DMA Burst and Transceiver Mode Register (BMPR13) */
-#define TRANSCEIVER_MODE_REG   13
-#define TRANSCEIVER_MODE_RB    2
-#define IO_BASE_UNLOCK	       BIT(7)
-#define LOWER_SQUELCH_TRESH    BIT(6)
-#define LINK_TEST_DISABLE      BIT(5)
-#define AUI_SELECT             BIT(4)
-#define DIS_AUTO_PORT_SEL      BIT(3)
-
-/* Filter Self Receive Register (BMPR14)  */
-#define FILTER_SELF_RX_REG     14
-#define SKIP_RX_PACKET         BIT(2)
-#define FILTER_SELF_RECEIVE    BIT(0)
-
-/* EEPROM Control Register (BMPR 16) */
-#define EEPROM_CTRL_REG        16
-
-/* EEPROM Data Register (BMPR 17) */
-#define EEPROM_DATA_REG        17
-
-/* NMC93CSx6 EEPROM Control Bits */
-#define CS_0                   0x00
-#define CS_1                   0x20
-#define SK_0                   0x00
-#define SK_1                   0x40
-#define DI_0                   0x00
-#define DI_1                   0x80
-
-/* NMC93CSx6 EEPROM Instructions */
-#define EEPROM_READ            0x80
-
-/* NMC93CSx6 EEPROM Addresses */
-#define E_NODEID_0             0x02
-#define E_NODEID_1             0x03
-#define E_NODEID_2             0x04
-#define E_PORT_SELECT          0x14
-  #define E_PORT_BNC           0x00
-  #define E_PORT_DIX           0x01
-  #define E_PORT_TP            0x02
-  #define E_PORT_AUTO          0x03
-  #define E_PORT_FROM_EPROM    0x04
-#define E_PRODUCT_CFG          0x30
-
-
-/* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
-
-/* Jumperless Configuration Register (BMPR19) */
-#define JUMPERLESS_CONFIG      19
-
-/* ID ROM registers, writing to them also resets some parts of chip */
-#define ID_ROM_0               24
-#define ID_ROM_7               31
-#define RESET                  ID_ROM_0
-
-/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] __initdata = {
-	0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
-
-static unsigned int eth32i_portlist[] __initdata = {
-	0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
-	0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
-};
-
-/* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 };
-#define NUM_OF_ISA_IRQS    4
-
-/* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
-#define EISA_IRQ_REG	0xc89
-#define NUM_OF_EISA_IRQS   8
-
-static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
-
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef ETH16I_DEBUG
-#define ETH16I_DEBUG 0
-#endif
-static unsigned int eth16i_debug = ETH16I_DEBUG;
-
-/* Information for each board */
-
-struct eth16i_local {
-	unsigned char     tx_started;
-	unsigned char     tx_buf_busy;
-	unsigned short    tx_queue;  /* Number of packets in transmit buffer */
-	unsigned short    tx_queue_len;
-	unsigned int      tx_buf_size;
-	unsigned long     open_time;
-	unsigned long     tx_buffered_packets;
-	unsigned long     tx_buffered_bytes;
-	unsigned long     col_16;
-	spinlock_t	  lock;
-};
-
-/* Function prototypes */
-
-static int     eth16i_probe1(struct net_device *dev, int ioaddr);
-static int     eth16i_check_signature(int ioaddr);
-static int     eth16i_probe_port(int ioaddr);
-static void    eth16i_set_port(int ioaddr, int porttype);
-static int     eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l);
-static int     eth16i_receive_probe_packet(int ioaddr);
-static int     eth16i_get_irq(int ioaddr);
-static int     eth16i_read_eeprom(int ioaddr, int offset);
-static int     eth16i_read_eeprom_word(int ioaddr);
-static void    eth16i_eeprom_cmd(int ioaddr, unsigned char command);
-static int     eth16i_open(struct net_device *dev);
-static int     eth16i_close(struct net_device *dev);
-static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev);
-static void    eth16i_rx(struct net_device *dev);
-static void    eth16i_timeout(struct net_device *dev);
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id);
-static void    eth16i_reset(struct net_device *dev);
-static void    eth16i_timeout(struct net_device *dev);
-static void    eth16i_skip_packet(struct net_device *dev);
-static void    eth16i_multicast(struct net_device *dev);
-static void    eth16i_select_regbank(unsigned char regbank, int ioaddr);
-static void    eth16i_initialize(struct net_device *dev, int boot);
-
-#if 0
-static int     eth16i_set_irq(struct net_device *dev);
-#endif
-
-#ifdef MODULE
-static ushort  eth16i_parse_mediatype(const char* s);
-#endif
-
-static char cardname[] __initdata = "ICL EtherTeam 16i/32";
-
-static int __init do_eth16i_probe(struct net_device *dev)
-{
-	int i;
-	int ioaddr;
-	int base_addr = dev->base_addr;
-
-	if(eth16i_debug > 4)
-		printk(KERN_DEBUG "Probing started for %s\n", cardname);
-
-	if(base_addr > 0x1ff)           /* Check only single location */
-		return eth16i_probe1(dev, base_addr);
-	else if(base_addr != 0)         /* Don't probe at all */
-		return -ENXIO;
-
-	/* Seek card from the ISA io address space */
-	for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++)
-		if(eth16i_probe1(dev, ioaddr) == 0)
-			return 0;
-
-	/* Seek card from the EISA io address space */
-	for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++)
-		if(eth16i_probe1(dev, ioaddr) == 0)
-			return 0;
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eth16i_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local));
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_eth16i_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops eth16i_netdev_ops = {
-	.ndo_open               = eth16i_open,
-	.ndo_stop               = eth16i_close,
-	.ndo_start_xmit    	= eth16i_tx,
-	.ndo_set_rx_mode	= eth16i_multicast,
-	.ndo_tx_timeout 	= eth16i_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	static unsigned version_printed;
-	int retval;
-
-	/* Let's grab the region */
-	if (!request_region(ioaddr, ETH16I_IO_EXTENT, cardname))
-		return -EBUSY;
-
-	/*
-	  The MB86985 chip has on register which holds information in which
-	  io address the chip lies. First read this register and compare
-	  it to our current io address and if match then this could
-	  be our chip.
-	  */
-
-	if(ioaddr < 0x1000) {
-		if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
-		   != ioaddr) {
-			retval = -ENODEV;
-			goto out;
-		}
-	}
-
-	/* Now we will go a bit deeper and try to find the chip's signature */
-
-	if(eth16i_check_signature(ioaddr) != 0) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/*
-	   Now it seems that we have found a ethernet chip in this particular
-	   ioaddr. The MB86985 chip has this feature, that when you read a
-	   certain register it will increase it's io base address to next
-	   configurable slot. Now when we have found the chip, first thing is
-	   to make sure that the chip's ioaddr will hold still here.
-	   */
-
-	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-	outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
-
-	outb(0x00, ioaddr + RESET);             /* Reset some parts of chip */
-	BITSET(ioaddr + CONFIG_REG_0, BIT(7));  /* Disable the data link */
-
-	if( (eth16i_debug & version_printed++) == 0)
-		printk(KERN_INFO "%s", version);
-
-	dev->base_addr = ioaddr;
-	dev->irq = eth16i_get_irq(ioaddr);
-
-	/* Try to obtain interrupt vector */
-
-	if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, cardname, dev))) {
-		printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
-		       cardname, ioaddr, dev->irq);
-		goto out;
-	}
-
-	printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
-	       dev->name, cardname, ioaddr, dev->irq);
-
-
-	/* Now we will have to lock the chip's io address */
-	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-	outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
-
-	eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */
-
-	/* Now let's same some energy by shutting down the chip ;) */
-	BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
-
-	/* Initialize the device structure */
-	dev->netdev_ops         = &eth16i_netdev_ops;
-	dev->watchdog_timeo	= TX_TIMEOUT;
-	spin_lock_init(&lp->lock);
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out1;
-	return 0;
-out1:
-	free_irq(dev->irq, dev);
-out:
-	release_region(ioaddr, ETH16I_IO_EXTENT);
-	return retval;
-}
-
-
-static void eth16i_initialize(struct net_device *dev, int boot)
-{
-	int ioaddr = dev->base_addr;
-	int i, node_w = 0;
-	unsigned char node_byte = 0;
-
-	/* Setup station address */
-	eth16i_select_regbank(NODE_ID_RB, ioaddr);
-	for(i = 0 ; i < 3 ; i++) {
-		unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
-		((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
-	}
-
-	for(i = 0; i < 6; i++) {
-		outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
-		if(boot) {
-			printk("%02x", inb(ioaddr + NODE_ID_0 + i));
-			if(i != 5)
-				printk(":");
-		}
-	}
-
-	/* Now we will set multicast addresses to accept none */
-	eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
-	for(i = 0; i < 8; i++)
-		outb(0x00, ioaddr + HASH_TABLE_0 + i);
-
-	/*
-	  Now let's disable the transmitter and receiver, set the buffer ram
-	  cycle time, bus width and buffer data path width. Also we shall
-	  set transmit buffer size and total buffer size.
-	  */
-
-	eth16i_select_regbank(2, ioaddr);
-
-	node_byte = 0;
-	node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
-
-	if( (node_w & 0xFF00) == 0x0800)
-		node_byte |= BUFFER_WIDTH_8;
-
-	node_byte |= SRAM_BS1;
-
-	if( (node_w & 0x00FF) == 64)
-		node_byte |= SRAM_BS0;
-
-	node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
-
-	outb(node_byte, ioaddr + CONFIG_REG_0);
-
-	/* We shall halt the transmitting, if 16 collisions are detected */
-	outb(HALT_ON_16, ioaddr + COL_16_REG);
-
-#ifdef MODULE
-	/* if_port already set by init_module() */
-#else
-	dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
-		dev->mem_start : E_PORT_FROM_EPROM;
-#endif
-
-	/* Set interface port type */
-	if(boot) {
-		static const char * const porttype[] = {
-			"BNC", "DIX", "TP", "AUTO", "FROM_EPROM"
-		};
-
-		switch(dev->if_port)
-		{
-
-		case E_PORT_FROM_EPROM:
-			dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
-			break;
-
-		case E_PORT_AUTO:
-			dev->if_port = eth16i_probe_port(ioaddr);
-			break;
-
-		case E_PORT_BNC:
-		case E_PORT_TP:
-		case E_PORT_DIX:
-			break;
-		}
-
-		printk(" %s interface.\n", porttype[dev->if_port]);
-
-		eth16i_set_port(ioaddr, dev->if_port);
-	}
-
-	/* Set Receive Mode to normal operation */
-	outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
-}
-
-static int eth16i_probe_port(int ioaddr)
-{
-	int i;
-	int retcode;
-	unsigned char dummy_packet[64];
-
-	/* Powerup the chip */
-	outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
-	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
-	eth16i_select_regbank(NODE_ID_RB, ioaddr);
-
-	for(i = 0; i < 6; i++) {
-		dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
-		dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
-	}
-
-	dummy_packet[12] = 0x00;
-	dummy_packet[13] = 0x04;
-	memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14);
-
-	eth16i_select_regbank(2, ioaddr);
-
-	for(i = 0; i < 3; i++) {
-		BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-		BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-		eth16i_set_port(ioaddr, i);
-
-		if(eth16i_debug > 1)
-			printk(KERN_DEBUG "Set port number %d\n", i);
-
-		retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
-		if(retcode == 0) {
-			retcode = eth16i_receive_probe_packet(ioaddr);
-			if(retcode != -1) {
-				if(eth16i_debug > 1)
-					printk(KERN_DEBUG "Eth16i interface port found at %d\n", i);
-				return i;
-			}
-		}
-		else {
-			if(eth16i_debug > 1)
-				printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n");
-		}
-	}
-
-	if( eth16i_debug > 1)
-		printk(KERN_DEBUG "Using default port\n");
-
-	return E_PORT_BNC;
-}
-
-static void eth16i_set_port(int ioaddr, int porttype)
-{
-	unsigned short temp = 0;
-
-	eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
-	outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
-
-	temp |= DIS_AUTO_PORT_SEL;
-
-	switch(porttype) {
-
-	case E_PORT_BNC :
-		temp |= AUI_SELECT;
-		break;
-
-	case E_PORT_TP :
-		break;
-
-	case E_PORT_DIX :
-		temp |= AUI_SELECT;
-		BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
-		break;
-	}
-
-	outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
-
-	if(eth16i_debug > 1) {
-		printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
-		printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
-		       inb(ioaddr+TRANSCEIVER_MODE_REG));
-	}
-}
-
-static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
-{
-	unsigned long starttime;
-
-	outb(0xff, ioaddr + TX_STATUS_REG);
-
-	outw(l, ioaddr + DATAPORT);
-	outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
-
-	starttime = jiffies;
-	outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
-
-	while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
-		if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int eth16i_receive_probe_packet(int ioaddr)
-{
-	unsigned long starttime;
-
-	starttime = jiffies;
-
-	while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
-		if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-
-			if(eth16i_debug > 1)
-				printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n");
-			starttime = jiffies;
-			while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
-				if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-					if(eth16i_debug > 1)
-						printk(KERN_DEBUG "Timeout occurred waiting receive packet\n");
-					return -1;
-				}
-			}
-
-			if(eth16i_debug > 1)
-				printk(KERN_DEBUG "RECEIVE_PACKET\n");
-			return 0; /* Found receive packet */
-		}
-	}
-
-	if(eth16i_debug > 1) {
-		printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
-		printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
-	}
-
-	return 0; /* Return success */
-}
-
-#if 0
-static int eth16i_set_irq(struct net_device* dev)
-{
-	const int ioaddr = dev->base_addr;
-	const int irq = dev->irq;
-	int i = 0;
-
-	if(ioaddr < 0x1000) {
-		while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
-			i++;
-
-		if(i < NUM_OF_ISA_IRQS) {
-			u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
-			cbyte = (cbyte & 0x3F) | (i << 6);
-			outb(cbyte, ioaddr + JUMPERLESS_CONFIG);
-			return 0;
-		}
-	}
-	else {
-		printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
-	}
-
-	return -1;
-
-}
-#endif
-
-static int __init eth16i_get_irq(int ioaddr)
-{
-	unsigned char cbyte;
-
-	if( ioaddr < 0x1000) {
-		cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
-		return eth16i_irqmap[((cbyte & 0xC0) >> 6)];
-	} else {  /* Oh..the card is EISA so method getting IRQ different */
-		unsigned short index = 0;
-		cbyte = inb(ioaddr + EISA_IRQ_REG);
-		while( (cbyte & 0x01) == 0) {
-			cbyte = cbyte >> 1;
-			index++;
-		}
-		return eth32i_irqmap[index];
-	}
-}
-
-static int __init eth16i_check_signature(int ioaddr)
-{
-	int i;
-	unsigned char creg[4] = { 0 };
-
-	for(i = 0; i < 4 ; i++) {
-
-		creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
-
-		if(eth16i_debug > 1)
-			printk("eth16i: read signature byte %x at %x\n",
-			       creg[i],
-			       ioaddr + TRANSMIT_MODE_REG + i);
-	}
-
-	creg[0] &= 0x0F;      /* Mask collision cnr */
-	creg[2] &= 0x7F;      /* Mask DCLEN bit */
-
-#if 0
-	/*
-	   This was removed because the card was sometimes left to state
-	   from which it couldn't be find anymore. If there is need
-	   to more strict check still this have to be fixed.
-	   */
-	if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) {
-		if(creg[1] != 0x42)
-			return -1;
-	}
-#endif
-
-	if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
-		creg[2] &= 0x40;
-		creg[3] &= 0x03;
-
-		if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
-			return -1;
-	}
-
-	if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
-		return -1;
-
-	if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
-		return -1;
-
-	return 0;
-}
-
-static int eth16i_read_eeprom(int ioaddr, int offset)
-{
-	int data = 0;
-
-	eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
-	outb(CS_1, ioaddr + EEPROM_CTRL_REG);
-	data = eth16i_read_eeprom_word(ioaddr);
-	outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-
-	return data;
-}
-
-static int eth16i_read_eeprom_word(int ioaddr)
-{
-	int i;
-	int data = 0;
-
-	for(i = 16; i > 0; i--) {
-		outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-		eeprom_slow_io();
-		outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-		eeprom_slow_io();
-		data = (data << 1) |
-			((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
-
-		eeprom_slow_io();
-	}
-
-	return data;
-}
-
-static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
-{
-	int i;
-
-	outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-	outb(DI_0, ioaddr + EEPROM_DATA_REG);
-	outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-	outb(DI_1, ioaddr + EEPROM_DATA_REG);
-	outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-
-	for(i = 7; i >= 0; i--) {
-		short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
-		outb(cmd, ioaddr + EEPROM_DATA_REG);
-		outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
-		eeprom_slow_io();
-		outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-		eeprom_slow_io();
-	}
-}
-
-static int eth16i_open(struct net_device *dev)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	/* Powerup the chip */
-	outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
-	/* Initialize the chip */
-	eth16i_initialize(dev, 0);
-
-	/* Set the transmit buffer size */
-	lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
-
-	if(eth16i_debug > 0)
-		printk(KERN_DEBUG "%s: transmit buffer size %d\n",
-		       dev->name, lp->tx_buf_size);
-
-	/* Now enable Transmitter and Receiver sections */
-	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-
-	/* Now switch to register bank 2, for run time operation */
-	eth16i_select_regbank(2, ioaddr);
-
-	lp->open_time = jiffies;
-	lp->tx_started = 0;
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-
-	/* Turn on interrupts*/
-	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-static int eth16i_close(struct net_device *dev)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	eth16i_reset(dev);
-
-	/* Turn off interrupts*/
-	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-	netif_stop_queue(dev);
-
-	lp->open_time = 0;
-
-	/* Disable transmit and receive */
-	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
-	/* Reset the chip */
-	/* outb(0xff, ioaddr + RESET); */
-	/* outw(0xffff, ioaddr + TX_STATUS_REG);    */
-
-	outb(0x00, ioaddr + CONFIG_REG_1);
-
-	return 0;
-}
-
-static void eth16i_timeout(struct net_device *dev)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	/*
-	   If we get here, some higher level has decided that
-	   we are broken. There should really be a "kick me"
-	   function call instead.
-	   */
-
-	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-	printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
-	       dev->name,
-	inw(ioaddr + TX_STATUS_REG),  (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
-		       "IRQ conflict" : "network cable problem");
-
-	dev->trans_start = jiffies; /* prevent tx timeout */
-
-	/* Let's dump all registers */
-	if(eth16i_debug > 0) {
-		printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
-		       dev->name, inb(ioaddr + 0),
-		       inb(ioaddr + 1), inb(ioaddr + 2),
-		       inb(ioaddr + 3), inb(ioaddr + 4),
-		       inb(ioaddr + 5),
-		       inb(ioaddr + 6), inb(ioaddr + 7));
-
-		printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
-		       dev->name, inb(ioaddr + TRANSMIT_START_REG),
-		       inb(ioaddr + COL_16_REG));
-			printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
-		printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
-		printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
-	}
-	dev->stats.tx_errors++;
-	eth16i_reset(dev);
-	dev->trans_start = jiffies; /* prevent tx timeout */
-	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-	netif_wake_queue(dev);
-}
-
-static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	int status = 0;
-	ushort length = skb->len;
-	unsigned char *buf;
-	unsigned long flags;
-
-	if (length < ETH_ZLEN) {
-		if (skb_padto(skb, ETH_ZLEN))
-			return NETDEV_TX_OK;
-		length = ETH_ZLEN;
-	}
-	buf = skb->data;
-
-	netif_stop_queue(dev);
-
-	/* Turn off TX interrupts */
-	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-	/* We would be better doing the disable_irq tricks the 3c509 does,
-	   that would make this suck a lot less */
-
-	spin_lock_irqsave(&lp->lock, flags);
-
-	if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
-		if(eth16i_debug > 0)
-			printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
-	}
-	else {
-		outw(length, ioaddr + DATAPORT);
-
-		if( ioaddr < 0x1000 )
-			outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-		else {
-			unsigned char frag = length % 4;
-			outsl(ioaddr + DATAPORT, buf, length >> 2);
-			if( frag != 0 ) {
-				outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
-				if( frag == 3 )
-					outsw(ioaddr + DATAPORT,
-					      (buf + (length & 0xFFFC) + 2), 1);
-			}
-		}
-		lp->tx_buffered_packets++;
-		lp->tx_buffered_bytes = length;
-		lp->tx_queue++;
-		lp->tx_queue_len += length + 2;
-	}
-	lp->tx_buf_busy = 0;
-
-	if(lp->tx_started == 0) {
-		/* If the transmitter is idle..always trigger a transmit */
-		outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-		lp->tx_queue = 0;
-		lp->tx_queue_len = 0;
-		lp->tx_started = 1;
-		netif_wake_queue(dev);
-	}
-	else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-		/* There is still more room for one more packet in tx buffer */
-		netif_wake_queue(dev);
-	}
-
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-	/* Turn TX interrupts back on */
-	/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
-	status = 0;
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-}
-
-static void eth16i_rx(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	int boguscount = MAX_RX_LOOP;
-
-	/* Loop until all packets have been read */
-	while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
-
-		/* Read status byte from receive buffer */
-		ushort status = inw(ioaddr + DATAPORT);
-
-		/* Get the size of the packet from receive buffer */
-		ushort pkt_len = inw(ioaddr + DATAPORT);
-
-		if(eth16i_debug > 4)
-			printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
-			       dev->name,
-			       inb(ioaddr + RECEIVE_MODE_REG), status);
-
-		if( !(status & PKT_GOOD) ) {
-			dev->stats.rx_errors++;
-
-			if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
-				dev->stats.rx_length_errors++;
-				eth16i_reset(dev);
-				return;
-			}
-			else {
-				eth16i_skip_packet(dev);
-				dev->stats.rx_dropped++;
-			}
-		}
-		else {   /* Ok so now we should have a good packet */
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len + 3);
-			if( skb == NULL ) {
-				printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
-				       dev->name, pkt_len);
-				eth16i_skip_packet(dev);
-				dev->stats.rx_dropped++;
-				break;
-			}
-
-			skb_reserve(skb,2);
-
-			/*
-			   Now let's get the packet out of buffer.
-			   size is (pkt_len + 1) >> 1, cause we are now reading words
-			   and it have to be even aligned.
-			   */
-
-			if(ioaddr < 0x1000)
-				insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-				     (pkt_len + 1) >> 1);
-			else {
-				unsigned char *buf = skb_put(skb, pkt_len);
-				unsigned char frag = pkt_len % 4;
-
-				insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
-
-				if(frag != 0) {
-					unsigned short rest[2];
-					rest[0] = inw( ioaddr + DATAPORT );
-					if(frag == 3)
-						rest[1] = inw( ioaddr + DATAPORT );
-
-					memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
-				}
-			}
-
-			skb->protocol=eth_type_trans(skb, dev);
-
-			if( eth16i_debug > 5 ) {
-				int i;
-				printk(KERN_DEBUG "%s: Received packet of length %d.\n",
-				       dev->name, pkt_len);
-				for(i = 0; i < 14; i++)
-					printk(KERN_DEBUG " %02x", skb->data[i]);
-				printk(KERN_DEBUG ".\n");
-			}
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-			dev->stats.rx_bytes += pkt_len;
-
-		} /* else */
-
-		if(--boguscount <= 0)
-			break;
-
-	} /* while */
-}
-
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct eth16i_local *lp;
-	int ioaddr = 0, status;
-	int handled = 0;
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	/* Turn off all interrupts from adapter */
-	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-	/* eth16i_tx won't be called */
-	spin_lock(&lp->lock);
-
-	status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */
-	outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */
-
-	if (status)
-		handled = 1;
-
-	if(eth16i_debug > 3)
-		printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);
-
-	if( status & 0x7f00 ) {
-
-		dev->stats.rx_errors++;
-
-		if(status & (BUS_RD_ERR << 8) )
-			printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
-		if(status & (SHORT_PKT_ERR << 8) )   dev->stats.rx_length_errors++;
-		if(status & (ALIGN_ERR << 8) )       dev->stats.rx_frame_errors++;
-		if(status & (CRC_ERR << 8) )	    dev->stats.rx_crc_errors++;
-		if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++;
-	}
-	if( status & 0x001a) {
-
-		dev->stats.tx_errors++;
-
-		if(status & CR_LOST) dev->stats.tx_carrier_errors++;
-		if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++;
-
-#if 0
-		if(status & COLLISION) {
-			dev->stats.collisions +=
-				((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
-		}
-#endif
-		if(status & COLLISIONS_16) {
-			if(lp->col_16 < MAX_COL_16) {
-				lp->col_16++;
-				dev->stats.collisions++;
-				/* Resume transmitting, skip failed packet */
-				outb(0x02, ioaddr + COL_16_REG);
-			}
-			else {
-				printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);
-			}
-		}
-	}
-
-	if( status & 0x00ff ) {          /* Let's check the transmit status reg */
-
-		if(status & TX_DONE) {         /* The transmit has been done */
-			dev->stats.tx_packets = lp->tx_buffered_packets;
-			dev->stats.tx_bytes += lp->tx_buffered_bytes;
-			lp->col_16 = 0;
-
-			if(lp->tx_queue) {           /* Is there still packets ? */
-				/* There was packet(s) so start transmitting and write also
-				   how many packets there is to be sended */
-				outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-				lp->tx_queue = 0;
-				lp->tx_queue_len = 0;
-				lp->tx_started = 1;
-			}
-			else {
-				lp->tx_started = 0;
-			}
-			netif_wake_queue(dev);
-		}
-	}
-
-	if( ( status & 0x8000 ) ||
-	    ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
-		eth16i_rx(dev);  /* We have packet in receive buffer */
-	}
-
-	/* Turn interrupts back on */
-	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
-	if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-		/* There is still more room for one more packet in tx buffer */
-		netif_wake_queue(dev);
-	}
-
-	spin_unlock(&lp->lock);
-
-	return IRQ_RETVAL(handled);
-}
-
-static void eth16i_skip_packet(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	inw(ioaddr + DATAPORT);
-	inw(ioaddr + DATAPORT);
-	inw(ioaddr + DATAPORT);
-
-	outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
-	while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);
-}
-
-static void eth16i_reset(struct net_device *dev)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	if(eth16i_debug > 1)
-		printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
-
-	BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-	outw(0xffff, ioaddr + TX_STATUS_REG);
-	eth16i_select_regbank(2, ioaddr);
-
-	lp->tx_started = 0;
-	lp->tx_buf_busy = 0;
-	lp->tx_queue = 0;
-	lp->tx_queue_len = 0;
-	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-}
-
-static void eth16i_multicast(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
-	{
-		outb(3, ioaddr + RECEIVE_MODE_REG);
-	} else {
-		outb(2, ioaddr + RECEIVE_MODE_REG);
-	}
-}
-
-static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
-{
-	unsigned char data;
-
-	data = inb(ioaddr + CONFIG_REG_1);
-	outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
-}
-
-#ifdef MODULE
-
-static ushort eth16i_parse_mediatype(const char* s)
-{
-	if(!s)
-		return E_PORT_FROM_EPROM;
-
-        if (!strncmp(s, "bnc", 3))
-		return E_PORT_BNC;
-        else if (!strncmp(s, "tp", 2))
-                return E_PORT_TP;
-        else if (!strncmp(s, "dix", 3))
-                return E_PORT_DIX;
-        else if (!strncmp(s, "auto", 4))
-		return E_PORT_AUTO;
-	else
-		return E_PORT_FROM_EPROM;
-}
-
-#define MAX_ETH16I_CARDS 4  /* Max number of Eth16i cards per module */
-
-static struct net_device *dev_eth16i[MAX_ETH16I_CARDS];
-static int io[MAX_ETH16I_CARDS];
-#if 0
-static int irq[MAX_ETH16I_CARDS];
-#endif
-static char* mediatype[MAX_ETH16I_CARDS];
-static int debug = -1;
-
-MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
-MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
-MODULE_LICENSE("GPL");
-
-
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "eth16i I/O base address(es)");
-
-#if 0
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "eth16i interrupt request number");
-#endif
-
-module_param_array(mediatype, charp, NULL, 0);
-MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,eprom)");
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "eth16i debug level (0-6)");
-
-int __init init_module(void)
-{
-	int this_dev, found = 0;
-	struct net_device *dev;
-
-	for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
-		dev = alloc_etherdev(sizeof(struct eth16i_local));
-		if (!dev)
-			break;
-
-		dev->base_addr = io[this_dev];
-
-	        if(debug != -1)
-			eth16i_debug = debug;
-
-		if(eth16i_debug > 1)
-			printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );
-
-		dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
-
-		if(io[this_dev] == 0) {
-			if (this_dev != 0) { /* Only autoprobe 1st one */
-				free_netdev(dev);
-				break;
-			}
-
-			printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-
-		if (do_eth16i_probe(dev) == 0) {
-			dev_eth16i[found++] = dev;
-			continue;
-		}
-		printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
-		       io[this_dev]);
-		free_netdev(dev);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-	int this_dev;
-
-	for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
-		struct net_device *dev = dev_eth16i[this_dev];
-
-		if (netdev_priv(dev)) {
-			unregister_netdev(dev);
-			free_irq(dev->irq, dev);
-			release_region(dev->base_addr, ETH16I_IO_EXTENT);
-			free_netdev(dev);
-		}
-	}
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/3c505.c b/drivers/net/ethernet/i825xx/3c505.c
deleted file mode 100644
index 6a5c21b..0000000
--- a/drivers/net/ethernet/i825xx/3c505.c
+++ /dev/null
@@ -1,1671 +0,0 @@
-/*
- * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
- *      By Craig Southeren, Juha Laiho and Philip Blundell
- *
- * 3c505.c      This module implements an interface to the 3Com
- *              Etherlink Plus (3c505) Ethernet card. Linux device
- *              driver interface reverse engineered from the Linux 3C509
- *              device drivers. Some 3C505 information gleaned from
- *              the Crynwr packet driver. Still this driver would not
- *              be here without 3C505 technical reference provided by
- *              3Com.
- *
- * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
- *
- * Authors:     Linux 3c505 device driver by
- *                      Craig Southeren, <craigs@ineluki.apana.org.au>
- *              Final debugging by
- *                      Andrew Tridgell, <tridge@nimbus.anu.edu.au>
- *              Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
- *                      Juha Laiho, <jlaiho@ichaos.nullnet.fi>
- *              Linux 3C509 driver by
- *                      Donald Becker, <becker@super.org>
- *			(Now at <becker@scyld.com>)
- *              Crynwr packet driver by
- *                      Krishnan Gopalan and Gregg Stefancik,
- *                      Clemson University Engineering Computer Operations.
- *                      Portions of the code have been adapted from the 3c505
- *                         driver for NCSA Telnet by Bruce Orchard and later
- *                         modified by Warren Van Houten and krus@diku.dk.
- *              3C505 technical information provided by
- *                      Terry Murphy, of 3Com Network Adapter Division
- *              Linux 1.3.0 changes by
- *                      Alan Cox <Alan.Cox@linux.org>
- *              More debugging, DMA support, currently maintained by
- *                      Philip Blundell <philb@gnu.org>
- *              Multicard/soft configurable dma channel/rev 2 hardware support
- *                      by Christopher Collins <ccollins@pcug.org.au>
- *		Ethtool support (jgarzik), 11/17/2001
- */
-
-#define DRV_NAME	"3c505"
-#define DRV_VERSION	"1.10a"
-
-
-/* Theory of operation:
- *
- * The 3c505 is quite an intelligent board.  All communication with it is done
- * by means of Primary Command Blocks (PCBs); these are transferred using PIO
- * through the command register.  The card has 256k of on-board RAM, which is
- * used to buffer received packets.  It might seem at first that more buffers
- * are better, but in fact this isn't true.  From my tests, it seems that
- * more than about 10 buffers are unnecessary, and there is a noticeable
- * performance hit in having more active on the card.  So the majority of the
- * card's memory isn't, in fact, used.  Sadly, the card only has one transmit
- * buffer and, short of loading our own firmware into it (which is what some
- * drivers resort to) there's nothing we can do about this.
- *
- * We keep up to 4 "receive packet" commands active on the board at a time.
- * When a packet comes in, so long as there is a receive command active, the
- * board will send us a "packet received" PCB and then add the data for that
- * packet to the DMA queue.  If a DMA transfer is not already in progress, we
- * set one up to start uploading the data.  We have to maintain a list of
- * backlogged receive packets, because the card may decide to tell us about
- * a newly-arrived packet at any time, and we may not be able to start a DMA
- * transfer immediately (ie one may already be going on).  We can't NAK the
- * PCB, because then it would throw the packet away.
- *
- * Trying to send a PCB to the card at the wrong moment seems to have bad
- * effects.  If we send it a transmit PCB while a receive DMA is happening,
- * it will just NAK the PCB and so we will have wasted our time.  Worse, it
- * sometimes seems to interrupt the transfer.  The majority of the low-level
- * code is protected by one huge semaphore -- "busy" -- which is set whenever
- * it probably isn't safe to do anything to the card.  The receive routine
- * must gain a lock on "busy" before it can start a DMA transfer, and the
- * transmit routine must gain a lock before it sends the first PCB to the card.
- * The send_pcb() routine also has an internal semaphore to protect it against
- * being re-entered (which would be disastrous) -- this is needed because
- * several things can happen asynchronously (re-priming the receiver and
- * asking the card for statistics, for example).  send_pcb() will also refuse
- * to talk to the card at all if a DMA upload is happening.  The higher-level
- * networking code will reschedule a later retry if some part of the driver
- * is blocked.  In practice, this doesn't seem to happen very often.
- */
-
-/* This driver may now work with revision 2.x hardware, since all the read
- * operations on the HCR have been removed (we now keep our own softcopy).
- * But I don't have an old card to test it on.
- *
- * This has had the bad effect that the autoprobe routine is now a bit
- * less friendly to other devices.  However, it was never very good.
- * before, so I doubt it will hurt anybody.
- */
-
-/* The driver is a mess.  I took Craig's and Juha's code, and hacked it firstly
- * to make it more reliable, and secondly to add DMA mode.  Many things could
- * probably be done better; the concurrency protection is particularly awful.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c505.h"
-
-/*********************************************************
- *
- *  define debug messages here as common strings to reduce space
- *
- *********************************************************/
-
-#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
-#define TIMEOUT_MSG(lineno) \
-	pr_notice(timeout_msg, __FILE__, __func__, (lineno))
-
-#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
-#define INVALID_PCB_MSG(len) \
-	pr_notice(invalid_pcb_msg, (len), __FILE__, __func__, __LINE__)
-
-#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
-
-#define stilllooking_msg "still looking..."
-
-#define found_msg "found.\n"
-
-#define notfound_msg "not found (reason = %d)\n"
-
-#define couldnot_msg "%s: 3c505 not found\n"
-
-/*********************************************************
- *
- *  various other debug stuff
- *
- *********************************************************/
-
-#ifdef ELP_DEBUG
-static int elp_debug = ELP_DEBUG;
-#else
-static int elp_debug;
-#endif
-#define debug elp_debug
-
-/*
- *  0 = no messages (well, some)
- *  1 = messages when high level commands performed
- *  2 = messages when low level commands performed
- *  3 = messages when interrupts received
- */
-
-/*****************************************************************
- *
- * List of I/O-addresses we try to auto-sense
- * Last element MUST BE 0!
- *****************************************************************/
-
-static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
-
-/* Dma Memory related stuff */
-
-static unsigned long dma_mem_alloc(int size)
-{
-	int order = get_order(size);
-	return __get_dma_pages(GFP_KERNEL, order);
-}
-
-
-/*****************************************************************
- *
- * Functions for I/O (note the inline !)
- *
- *****************************************************************/
-
-static inline unsigned char inb_status(unsigned int base_addr)
-{
-	return inb(base_addr + PORT_STATUS);
-}
-
-static inline int inb_command(unsigned int base_addr)
-{
-	return inb(base_addr + PORT_COMMAND);
-}
-
-static inline void outb_control(unsigned char val, struct net_device *dev)
-{
-	outb(val, dev->base_addr + PORT_CONTROL);
-	((elp_device *)(netdev_priv(dev)))->hcr_val = val;
-}
-
-#define HCR_VAL(x)   (((elp_device *)(netdev_priv(x)))->hcr_val)
-
-static inline void outb_command(unsigned char val, unsigned int base_addr)
-{
-	outb(val, base_addr + PORT_COMMAND);
-}
-
-static inline unsigned int backlog_next(unsigned int n)
-{
-	return (n + 1) % BACKLOG_SIZE;
-}
-
-/*****************************************************************
- *
- *  useful functions for accessing the adapter
- *
- *****************************************************************/
-
-/*
- * use this routine when accessing the ASF bits as they are
- * changed asynchronously by the adapter
- */
-
-/* get adapter PCB status */
-#define	GET_ASF(addr) \
-	(get_status(addr)&ASF_PCB_MASK)
-
-static inline int get_status(unsigned int base_addr)
-{
-	unsigned long timeout = jiffies + 10*HZ/100;
-	register int stat1;
-	do {
-		stat1 = inb_status(base_addr);
-	} while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
-	if (time_after_eq(jiffies, timeout))
-		TIMEOUT_MSG(__LINE__);
-	return stat1;
-}
-
-static inline void set_hsf(struct net_device *dev, int hsf)
-{
-	elp_device *adapter = netdev_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&adapter->lock, flags);
-	outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
-	spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-static bool start_receive(struct net_device *, pcb_struct *);
-
-static inline void adapter_reset(struct net_device *dev)
-{
-	unsigned long timeout;
-	elp_device *adapter = netdev_priv(dev);
-	unsigned char orig_hcr = adapter->hcr_val;
-
-	outb_control(0, dev);
-
-	if (inb_status(dev->base_addr) & ACRF) {
-		do {
-			inb_command(dev->base_addr);
-			timeout = jiffies + 2*HZ/100;
-			while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
-		} while (inb_status(dev->base_addr) & ACRF);
-		set_hsf(dev, HSF_PCB_NAK);
-	}
-	outb_control(adapter->hcr_val | ATTN | DIR, dev);
-	mdelay(10);
-	outb_control(adapter->hcr_val & ~ATTN, dev);
-	mdelay(10);
-	outb_control(adapter->hcr_val | FLSH, dev);
-	mdelay(10);
-	outb_control(adapter->hcr_val & ~FLSH, dev);
-	mdelay(10);
-
-	outb_control(orig_hcr, dev);
-	if (!start_receive(dev, &adapter->tx_pcb))
-		pr_err("%s: start receive command failed\n", dev->name);
-}
-
-/* Check to make sure that a DMA transfer hasn't timed out.  This should
- * never happen in theory, but seems to occur occasionally if the card gets
- * prodded at the wrong time.
- */
-static inline void check_3c505_dma(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-	if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
-		unsigned long flags, f;
-		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;
-
-		f=claim_dma_lock();
-		disable_dma(dev->dma);
-		release_dma_lock(f);
-
-		if (adapter->rx_active)
-			adapter->rx_active--;
-		outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
-		spin_unlock_irqrestore(&adapter->lock, flags);
-	}
-}
-
-/* Primitive functions used by send_pcb() */
-static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
-{
-	unsigned long timeout;
-	outb_command(byte, base_addr);
-	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
-		if (inb_status(base_addr) & HCRE)
-			return false;
-	}
-	pr_warning("3c505: send_pcb_slow timed out\n");
-	return true;
-}
-
-static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
-{
-	unsigned int timeout;
-	outb_command(byte, base_addr);
-	for (timeout = 0; timeout < 40000; timeout++) {
-		if (inb_status(base_addr) & HCRE)
-			return false;
-	}
-	pr_warning("3c505: send_pcb_fast timed out\n");
-	return true;
-}
-
-/* Check to see if the receiver needs restarting, and kick it if so */
-static inline void prime_rx(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-	while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
-		if (!start_receive(dev, &adapter->itx_pcb))
-			break;
-	}
-}
-
-/*****************************************************************
- *
- * send_pcb
- *   Send a PCB to the adapter.
- *
- *	output byte to command reg  --<--+
- *	wait until HCRE is non zero      |
- *	loop until all bytes sent   -->--+
- *	set HSF1 and HSF2 to 1
- *	output pcb length
- *	wait until ASF give ACK or NAK
- *	set HSF1 and HSF2 to 0
- *
- *****************************************************************/
-
-/* This can be quite slow -- the adapter is allowed to take up to 40ms
- * to respond to the initial interrupt.
- *
- * We run initially with interrupts turned on, but with a semaphore set
- * so that nobody tries to re-enter this code.  Once the first byte has
- * gone through, we turn interrupts off and then send the others (the
- * timeout is reduced to 500us).
- */
-
-static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
-{
-	int i;
-	unsigned long timeout;
-	elp_device *adapter = netdev_priv(dev);
-	unsigned long flags;
-
-	check_3c505_dma(dev);
-
-	if (adapter->dmaing && adapter->current_dma.direction == 0)
-		return false;
-
-	/* Avoid contention */
-	if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
-		if (elp_debug >= 3) {
-			pr_debug("%s: send_pcb entered while threaded\n", dev->name);
-		}
-		return false;
-	}
-	/*
-	 * load each byte into the command register and
-	 * wait for the HCRE bit to indicate the adapter
-	 * had read the byte
-	 */
-	set_hsf(dev, 0);
-
-	if (send_pcb_slow(dev->base_addr, pcb->command))
-		goto abort;
-
-	spin_lock_irqsave(&adapter->lock, flags);
-
-	if (send_pcb_fast(dev->base_addr, pcb->length))
-		goto sti_abort;
-
-	for (i = 0; i < pcb->length; i++) {
-		if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
-			goto sti_abort;
-	}
-
-	outb_control(adapter->hcr_val | 3, dev);	/* signal end of PCB */
-	outb_command(2 + pcb->length, dev->base_addr);
-
-	/* now wait for the acknowledgement */
-	spin_unlock_irqrestore(&adapter->lock, flags);
-
-	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
-		switch (GET_ASF(dev->base_addr)) {
-		case ASF_PCB_ACK:
-			adapter->send_pcb_semaphore = 0;
-			return true;
-
-		case ASF_PCB_NAK:
-#ifdef ELP_DEBUG
-			pr_debug("%s: send_pcb got NAK\n", dev->name);
-#endif
-			goto abort;
-		}
-	}
-
-	if (elp_debug >= 1)
-		pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
-			dev->name, inb_status(dev->base_addr));
-	goto abort;
-
-      sti_abort:
-	spin_unlock_irqrestore(&adapter->lock, flags);
-      abort:
-	adapter->send_pcb_semaphore = 0;
-	return false;
-}
-
-
-/*****************************************************************
- *
- * receive_pcb
- *   Read a PCB from the adapter
- *
- *	wait for ACRF to be non-zero        ---<---+
- *	input a byte                               |
- *	if ASF1 and ASF2 were not both one         |
- *		before byte was read, loop      --->---+
- *	set HSF1 and HSF2 for ack
- *
- *****************************************************************/
-
-static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
-{
-	int i, j;
-	int total_length;
-	int stat;
-	unsigned long timeout;
-	unsigned long flags;
-
-	elp_device *adapter = netdev_priv(dev);
-
-	set_hsf(dev, 0);
-
-	/* get the command code */
-	timeout = jiffies + 2*HZ/100;
-	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
-	if (time_after_eq(jiffies, timeout)) {
-		TIMEOUT_MSG(__LINE__);
-		return false;
-	}
-	pcb->command = inb_command(dev->base_addr);
-
-	/* read the data length */
-	timeout = jiffies + 3*HZ/100;
-	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
-	if (time_after_eq(jiffies, timeout)) {
-		TIMEOUT_MSG(__LINE__);
-		pr_info("%s: status %02x\n", dev->name, stat);
-		return false;
-	}
-	pcb->length = inb_command(dev->base_addr);
-
-	if (pcb->length > MAX_PCB_DATA) {
-		INVALID_PCB_MSG(pcb->length);
-		adapter_reset(dev);
-		return false;
-	}
-	/* read the data */
-	spin_lock_irqsave(&adapter->lock, flags);
-	for (i = 0; i < MAX_PCB_DATA; i++) {
-		for (j = 0; j < 20000; j++) {
-			stat = get_status(dev->base_addr);
-			if (stat & ACRF)
-				break;
-		}
-		pcb->data.raw[i] = inb_command(dev->base_addr);
-		if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
-			break;
-	}
-	spin_unlock_irqrestore(&adapter->lock, flags);
-	if (i >= MAX_PCB_DATA) {
-		INVALID_PCB_MSG(i);
-		return false;
-	}
-	if (j >= 20000) {
-		TIMEOUT_MSG(__LINE__);
-		return false;
-	}
-	/* the last "data" byte was really the length! */
-	total_length = pcb->data.raw[i];
-
-	/* safety check total length vs data length */
-	if (total_length != (pcb->length + 2)) {
-		if (elp_debug >= 2)
-			pr_warning("%s: mangled PCB received\n", dev->name);
-		set_hsf(dev, HSF_PCB_NAK);
-		return false;
-	}
-
-	if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
-		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);
-				pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
-				pcb->command = 0;
-				return true;
-			} else {
-				pcb->command = 0xff;
-			}
-		}
-	}
-	set_hsf(dev, HSF_PCB_ACK);
-	return true;
-}
-
-/******************************************************
- *
- *  queue a receive command on the adapter so we will get an
- *  interrupt when a packet is received.
- *
- ******************************************************/
-
-static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
-{
-	bool status;
-	elp_device *adapter = netdev_priv(dev);
-
-	if (elp_debug >= 3)
-		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
-	    = tx_pcb->data.rcv_pkt.buf_ofs = 0;		/* Unused */
-	tx_pcb->data.rcv_pkt.buf_len = 1600;
-	tx_pcb->data.rcv_pkt.timeout = 0;	/* set timeout to zero */
-	status = send_pcb(dev, tx_pcb);
-	if (status)
-		adapter->rx_active++;
-	return status;
-}
-
-/******************************************************
- *
- * extract a packet from the adapter
- * this routine is only called from within the interrupt
- * service routine, so no cli/sti calls are needed
- * note that the length is always assumed to be even
- *
- ******************************************************/
-
-static void receive_packet(struct net_device *dev, int len)
-{
-	int rlen;
-	elp_device *adapter = netdev_priv(dev);
-	void *target;
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	rlen = (len + 1) & ~1;
-	skb = netdev_alloc_skb(dev, rlen + 2);
-
-	if (!skb) {
-		pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
-		target = adapter->dma_buffer;
-		adapter->current_dma.target = NULL;
-		/* FIXME: stats */
-		return;
-	}
-
-	skb_reserve(skb, 2);
-	target = skb_put(skb, rlen);
-	if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
-		adapter->current_dma.target = target;
-		target = adapter->dma_buffer;
-	} else {
-		adapter->current_dma.target = NULL;
-	}
-
-	/* if this happens, we die */
-	if (test_and_set_bit(0, (void *) &adapter->dmaing))
-		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;
-	adapter->current_dma.skb = skb;
-	adapter->current_dma.start_time = jiffies;
-
-	outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
-
-	flags=claim_dma_lock();
-	disable_dma(dev->dma);
-	clear_dma_ff(dev->dma);
-	set_dma_mode(dev->dma, 0x04);	/* dma read */
-	set_dma_addr(dev->dma, isa_virt_to_bus(target));
-	set_dma_count(dev->dma, rlen);
-	enable_dma(dev->dma);
-	release_dma_lock(flags);
-
-	if (elp_debug >= 3) {
-		pr_debug("%s: rx DMA transfer started\n", dev->name);
-	}
-
-	if (adapter->rx_active)
-		adapter->rx_active--;
-
-	if (!adapter->busy)
-		pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
-}
-
-/******************************************************
- *
- * interrupt handler
- *
- ******************************************************/
-
-static irqreturn_t elp_interrupt(int irq, void *dev_id)
-{
-	int len;
-	int dlen;
-	int icount = 0;
-	struct net_device *dev = dev_id;
-	elp_device *adapter = netdev_priv(dev);
-	unsigned long timeout;
-
-	spin_lock(&adapter->lock);
-
-	do {
-		/*
-		 * has a DMA transfer finished?
-		 */
-		if (inb_status(dev->base_addr) & DONE) {
-			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) {
-				dev_kfree_skb_irq(adapter->current_dma.skb);
-			} else {
-				struct sk_buff *skb = adapter->current_dma.skb;
-				if (skb) {
-					if (adapter->current_dma.target) {
-				  	/* have already done the skb_put() */
-				  	memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
-					}
-					skb->protocol = eth_type_trans(skb,dev);
-					dev->stats.rx_bytes += skb->len;
-					netif_rx(skb);
-				}
-			}
-			adapter->dmaing = 0;
-			if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
-				int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
-				adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
-				if (elp_debug >= 2)
-					pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
-				receive_packet(dev, t);
-			} else {
-				adapter->busy = 0;
-			}
-		} else {
-			/* has one timed out? */
-			check_3c505_dma(dev);
-		}
-
-		/*
-		 * receive a PCB from the adapter
-		 */
-		timeout = jiffies + 3*HZ/100;
-		while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
-			if (receive_pcb(dev, &adapter->irx_pcb)) {
-				switch (adapter->irx_pcb.command)
-				{
-				case 0:
-					break;
-					/*
-					 * received a packet - this must be handled fast
-					 */
-				case 0xff:
-				case CMD_RECEIVE_PACKET_COMPLETE:
-					/* if the device isn't open, don't pass packets up the stack */
-					if (!netif_running(dev))
-						break;
-					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) {
-						pr_err("%s: interrupt - packet not received correctly\n", dev->name);
-					} else {
-						if (elp_debug >= 3) {
-							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)
-								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)
-							pr_debug("%s: packet received\n", dev->name);
-					}
-					break;
-
-					/*
-					 * 82586 configured correctly
-					 */
-				case CMD_CONFIGURE_82586_RESPONSE:
-					adapter->got[CMD_CONFIGURE_82586] = 1;
-					if (elp_debug >= 3)
-						pr_debug("%s: interrupt - configure response received\n", dev->name);
-					break;
-
-					/*
-					 * Adapter memory configuration
-					 */
-				case CMD_CONFIGURE_ADAPTER_RESPONSE:
-					adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
-					if (elp_debug >= 3)
-						pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
-						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-					break;
-
-					/*
-					 * Multicast list loading
-					 */
-				case CMD_LOAD_MULTICAST_RESPONSE:
-					adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
-					if (elp_debug >= 3)
-						pr_debug("%s: Multicast address list loading %s.\n", dev->name,
-						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-					break;
-
-					/*
-					 * Station address setting
-					 */
-				case CMD_SET_ADDRESS_RESPONSE:
-					adapter->got[CMD_SET_STATION_ADDRESS] = 1;
-					if (elp_debug >= 3)
-						pr_debug("%s: Ethernet address setting %s.\n", dev->name,
-						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
-					break;
-
-
-					/*
-					 * received board statistics
-					 */
-				case CMD_NETWORK_STATISTICS_RESPONSE:
-					dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
-					dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
-					dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
-					dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
-					dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
-					dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
-					adapter->got[CMD_NETWORK_STATISTICS] = 1;
-					if (elp_debug >= 3)
-						pr_debug("%s: interrupt - statistics response received\n", dev->name);
-					break;
-
-					/*
-					 * sent a packet
-					 */
-				case CMD_TRANSMIT_PACKET_COMPLETE:
-					if (elp_debug >= 3)
-						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++;
-						pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
-						break;
-					case 0xfffe:
-						dev->stats.tx_fifo_errors++;
-						pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
-						break;
-					}
-					netif_wake_queue(dev);
-					break;
-
-					/*
-					 * some unknown PCB
-					 */
-				default:
-					pr_debug("%s: unknown PCB received - %2.2x\n",
-						dev->name, adapter->irx_pcb.command);
-					break;
-				}
-			} else {
-				pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
-				adapter_reset(dev);
-			}
-		}
-
-	} while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
-
-	prime_rx(dev);
-
-	/*
-	 * indicate no longer in interrupt routine
-	 */
-	spin_unlock(&adapter->lock);
-	return IRQ_HANDLED;
-}
-
-
-/******************************************************
- *
- * open the board
- *
- ******************************************************/
-
-static int elp_open(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-	int retval;
-
-	if (elp_debug >= 3)
-		pr_debug("%s: request to open device\n", dev->name);
-
-	/*
-	 * make sure we actually found the device
-	 */
-	if (adapter == NULL) {
-		pr_err("%s: Opening a non-existent physical device\n", dev->name);
-		return -EAGAIN;
-	}
-	/*
-	 * disable interrupts on the board
-	 */
-	outb_control(0, dev);
-
-	/*
-	 * clear any pending interrupts
-	 */
-	inb_command(dev->base_addr);
-	adapter_reset(dev);
-
-	/*
-	 * no receive PCBs active
-	 */
-	adapter->rx_active = 0;
-
-	adapter->busy = 0;
-	adapter->send_pcb_semaphore = 0;
-	adapter->rx_backlog.in = 0;
-	adapter->rx_backlog.out = 0;
-
-	spin_lock_init(&adapter->lock);
-
-	/*
-	 * install our interrupt service routine
-	 */
-	if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
-		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);
-		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) {
-		pr_err("%s: could not allocate DMA buffer\n", dev->name);
-		free_dma(dev->dma);
-		free_irq(dev->irq, dev);
-		return -ENOMEM;
-	}
-	adapter->dmaing = 0;
-
-	/*
-	 * enable interrupts on the board
-	 */
-	outb_control(CMDE, dev);
-
-	/*
-	 * configure adapter memory: we need 10 multicast addresses, default==0
-	 */
-	if (elp_debug >= 3)
-		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;
-	adapter->tx_pcb.data.memconf.mcast = 10;
-	adapter->tx_pcb.data.memconf.frame = 20;
-	adapter->tx_pcb.data.memconf.rcv_b = 20;
-	adapter->tx_pcb.data.memconf.progs = 0;
-	adapter->tx_pcb.length = sizeof(struct Memconf);
-	adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
-	if (!send_pcb(dev, &adapter->tx_pcb))
-		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));
-		if (time_after_eq(jiffies, timeout))
-			TIMEOUT_MSG(__LINE__);
-	}
-
-
-	/*
-	 * configure adapter to receive broadcast messages and wait for response
-	 */
-	if (elp_debug >= 3)
-		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))
-		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));
-		if (time_after_eq(jiffies, timeout))
-			TIMEOUT_MSG(__LINE__);
-	}
-
-	/* enable burst-mode DMA */
-	/* outb(0x1, dev->base_addr + PORT_AUXDMA); */
-
-	/*
-	 * queue receive commands to provide buffering
-	 */
-	prime_rx(dev);
-	if (elp_debug >= 3)
-		pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
-
-	/*
-	 * device is now officially open!
-	 */
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-
-/******************************************************
- *
- * send a packet to the adapter
- *
- ******************************************************/
-
-static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
-{
-	elp_device *adapter = netdev_priv(dev);
-	unsigned long target;
-	unsigned long flags;
-
-	/*
-	 * make sure the length is even and no shorter than 60 bytes
-	 */
-	unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
-
-	if (test_and_set_bit(0, (void *) &adapter->busy)) {
-		if (elp_debug >= 2)
-			pr_debug("%s: transmit blocked\n", dev->name);
-		return false;
-	}
-
-	dev->stats.tx_bytes += nlen;
-
-	/*
-	 * send the adapter a transmit packet command. Ignore segment and offset
-	 * and make sure the length is even
-	 */
-	adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
-	adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
-	adapter->tx_pcb.data.xmit_pkt.buf_ofs
-	    = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0;	/* Unused */
-	adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
-
-	if (!send_pcb(dev, &adapter->tx_pcb)) {
-		adapter->busy = 0;
-		return false;
-	}
-	/* if this happens, we die */
-	if (test_and_set_bit(0, (void *) &adapter->dmaing))
-		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;
-
-	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
-		skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
-		memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
-		target = isa_virt_to_bus(adapter->dma_buffer);
-	}
-	else {
-		target = isa_virt_to_bus(skb->data);
-	}
-	adapter->current_dma.skb = skb;
-
-	flags=claim_dma_lock();
-	disable_dma(dev->dma);
-	clear_dma_ff(dev->dma);
-	set_dma_mode(dev->dma, 0x48);	/* dma memory -> io */
-	set_dma_addr(dev->dma, target);
-	set_dma_count(dev->dma, nlen);
-	outb_control(adapter->hcr_val | DMAE | TCEN, dev);
-	enable_dma(dev->dma);
-	release_dma_lock(flags);
-
-	if (elp_debug >= 3)
-		pr_debug("%s: DMA transfer started\n", dev->name);
-
-	return true;
-}
-
-/*
- *	The upper layer thinks we timed out
- */
-
-static void elp_timeout(struct net_device *dev)
-{
-	int stat;
-
-	stat = inb_status(dev->base_addr);
-	pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
-		   (stat & ACRF) ? "interrupt" : "command");
-	if (elp_debug >= 1)
-		pr_debug("%s: status %#02x\n", dev->name, stat);
-	dev->trans_start = jiffies; /* prevent tx timeout */
-	dev->stats.tx_dropped++;
-	netif_wake_queue(dev);
-}
-
-/******************************************************
- *
- * start the transmitter
- *    return 0 if sent OK, else return 1
- *
- ******************************************************/
-
-static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	unsigned long flags;
-	elp_device *adapter = netdev_priv(dev);
-
-	spin_lock_irqsave(&adapter->lock, flags);
-	check_3c505_dma(dev);
-
-	if (elp_debug >= 3)
-		pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
-
-	netif_stop_queue(dev);
-
-	/*
-	 * send the packet at skb->data for skb->len
-	 */
-	if (!send_packet(dev, skb)) {
-		if (elp_debug >= 2) {
-			pr_debug("%s: failed to transmit packet\n", dev->name);
-		}
-		spin_unlock_irqrestore(&adapter->lock, flags);
-		return NETDEV_TX_BUSY;
-	}
-	if (elp_debug >= 3)
-		pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
-
-	prime_rx(dev);
-	spin_unlock_irqrestore(&adapter->lock, flags);
-	netif_start_queue(dev);
-	return NETDEV_TX_OK;
-}
-
-/******************************************************
- *
- * return statistics on the board
- *
- ******************************************************/
-
-static struct net_device_stats *elp_get_stats(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-
-	if (elp_debug >= 3)
-		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 */
-	if (!netif_running(dev))
-		return &dev->stats;
-
-	/* send a get statistics command to the board */
-	adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
-	adapter->tx_pcb.length = 0;
-	adapter->got[CMD_NETWORK_STATISTICS] = 0;
-	if (!send_pcb(dev, &adapter->tx_pcb))
-		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));
-		if (time_after_eq(jiffies, timeout)) {
-			TIMEOUT_MSG(__LINE__);
-			return &dev->stats;
-		}
-	}
-
-	/* statistics are now up to date */
-	return &dev->stats;
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-	return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-	debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-	.get_msglevel		= netdev_get_msglevel,
-	.set_msglevel		= netdev_set_msglevel,
-};
-
-/******************************************************
- *
- * close the board
- *
- ******************************************************/
-
-static int elp_close(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-
-	if (elp_debug >= 3)
-		pr_debug("%s: request to close device\n", dev->name);
-
-	netif_stop_queue(dev);
-
-	/* Someone may request the device statistic information even when
-	 * the interface is closed. The following will update the statistics
-	 * structure in the driver, so we'll be able to give current statistics.
-	 */
-	(void) elp_get_stats(dev);
-
-	/*
-	 * disable interrupts on the board
-	 */
-	outb_control(0, dev);
-
-	/*
-	 * release the IRQ
-	 */
-	free_irq(dev->irq, dev);
-
-	free_dma(dev->dma);
-	free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
-
-	return 0;
-}
-
-
-/************************************************************
- *
- * Set multicast list
- * num_addrs==0: clear mc_list
- * num_addrs==-1: set promiscuous mode
- * num_addrs>0: set mc_list
- *
- ************************************************************/
-
-static void elp_set_mc_list(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-	struct netdev_hw_addr *ha;
-	int i;
-	unsigned long flags;
-
-	if (elp_debug >= 3)
-		pr_debug("%s: request to set multicast list\n", dev->name);
-
-	spin_lock_irqsave(&adapter->lock, flags);
-
-	if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
-		/* send a "load multicast list" command to the board, max 10 addrs/cmd */
-		/* if num_addrs==0 the list will be cleared */
-		adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
-		adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
-		i = 0;
-		netdev_for_each_mc_addr(ha, dev)
-			memcpy(adapter->tx_pcb.data.multicast[i++],
-			       ha->addr, 6);
-		adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
-		if (!send_pcb(dev, &adapter->tx_pcb))
-			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));
-			if (time_after_eq(jiffies, timeout)) {
-				TIMEOUT_MSG(__LINE__);
-			}
-		}
-		if (!netdev_mc_empty(dev))
-			adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
-		else		/* num_addrs == 0 */
-			adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
-	} else
-		adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
-	/*
-	 * configure adapter to receive messages (as specified above)
-	 * and wait for response
-	 */
-	if (elp_debug >= 3)
-		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);
-		pr_err("%s: couldn't send 82586 configure command\n", dev->name);
-	}
-	else {
-		unsigned long timeout = jiffies + TIMEOUT;
-		spin_unlock_irqrestore(&adapter->lock, flags);
-		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
-		if (time_after_eq(jiffies, timeout))
-			TIMEOUT_MSG(__LINE__);
-	}
-}
-
-/************************************************************
- *
- * A couple of tests to see if there's 3C505 or not
- * Called only by elp_autodetect
- ************************************************************/
-
-static int __init elp_sense(struct net_device *dev)
-{
-	int addr = dev->base_addr;
-	const char *name = dev->name;
-	byte orig_HSR;
-
-	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
-		return -ENODEV;
-
-	orig_HSR = inb_status(addr);
-
-	if (elp_debug > 0)
-		pr_debug(search_msg, name, addr);
-
-	if (orig_HSR == 0xff) {
-		if (elp_debug > 0)
-			pr_cont(notfound_msg, 1);
-		goto out;
-	}
-
-	/* Wait for a while; the adapter may still be booting up */
-	if (elp_debug > 0)
-		pr_cont(stilllooking_msg);
-
-	if (orig_HSR & DIR) {
-		/* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
-		outb(0, dev->base_addr + PORT_CONTROL);
-		msleep(300);
-		if (inb_status(addr) & DIR) {
-			if (elp_debug > 0)
-				pr_cont(notfound_msg, 2);
-			goto out;
-		}
-	} else {
-		/* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
-		outb(DIR, dev->base_addr + PORT_CONTROL);
-		msleep(300);
-		if (!(inb_status(addr) & DIR)) {
-			if (elp_debug > 0)
-				pr_cont(notfound_msg, 3);
-			goto out;
-		}
-	}
-	/*
-	 * It certainly looks like a 3c505.
-	 */
-	if (elp_debug > 0)
-		pr_cont(found_msg);
-
-	return 0;
-out:
-	release_region(addr, ELP_IO_EXTENT);
-	return -ENODEV;
-}
-
-/*************************************************************
- *
- * Search through addr_list[] and try to find a 3C505
- * Called only by eplus_probe
- *************************************************************/
-
-static int __init elp_autodetect(struct net_device *dev)
-{
-	int idx = 0;
-
-	/* if base address set, then only check that address
-	   otherwise, run through the table */
-	if (dev->base_addr != 0) {	/* dev->base_addr == 0 ==> plain autodetect */
-		if (elp_sense(dev) == 0)
-			return dev->base_addr;
-	} else
-		while ((dev->base_addr = addr_list[idx++])) {
-			if (elp_sense(dev) == 0)
-				return dev->base_addr;
-		}
-
-	/* could not find an adapter */
-	if (elp_debug > 0)
-		pr_debug(couldnot_msg, dev->name);
-
-	return 0;		/* Because of this, the layer above will return -ENODEV */
-}
-
-static const struct net_device_ops elp_netdev_ops = {
-	.ndo_open		= elp_open,
-	.ndo_stop		= elp_close,
-	.ndo_get_stats 		= elp_get_stats,
-	.ndo_start_xmit		= elp_start_xmit,
-	.ndo_tx_timeout 	= elp_timeout,
-	.ndo_set_rx_mode	= elp_set_mc_list,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/******************************************************
- *
- * probe for an Etherlink Plus board at the specified address
- *
- ******************************************************/
-
-/* There are three situations we need to be able to detect here:
-
- *  a) the card is idle
- *  b) the card is still booting up
- *  c) the card is stuck in a strange state (some DOS drivers do this)
- *
- * In case (a), all is well.  In case (b), we wait 10 seconds to see if the
- * card finishes booting, and carry on if so.  In case (c), we do a hard reset,
- * loop round, and hope for the best.
- *
- * This is all very unpleasant, but hopefully avoids the problems with the old
- * probe code (which had a 15-second delay if the card was idle, and didn't
- * work at all if it was in a weird state).
- */
-
-static int __init elplus_setup(struct net_device *dev)
-{
-	elp_device *adapter = netdev_priv(dev);
-	int i, tries, tries1, okay;
-	unsigned long timeout;
-	unsigned long cookie = 0;
-	int err = -ENODEV;
-
-	/*
-	 *  setup adapter structure
-	 */
-
-	dev->base_addr = elp_autodetect(dev);
-	if (!dev->base_addr)
-		return -ENODEV;
-
-	adapter->send_pcb_semaphore = 0;
-
-	for (tries1 = 0; tries1 < 3; tries1++) {
-		outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
-		/* First try to write just one byte, to see if the card is
-		 * responding at all normally.
-		 */
-		timeout = jiffies + 5*HZ/100;
-		okay = 0;
-		while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
-		if ((inb_status(dev->base_addr) & HCRE)) {
-			outb_command(0, dev->base_addr);	/* send a spurious byte */
-			timeout = jiffies + 5*HZ/100;
-			while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
-			if (inb_status(dev->base_addr) & HCRE)
-				okay = 1;
-		}
-		if (!okay) {
-			/* Nope, it's ignoring the command register.  This means that
-			 * either it's still booting up, or it's died.
-			 */
-			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.
-				 */
-				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) {
-					pr_err("%s: 3c505 failed to start\n", dev->name);
-				} else {
-					okay = 1;  /* It started */
-				}
-			} else {
-				/* Otherwise, it must just be in a strange
-				 * state.  We probably need to kick it.
-				 */
-				pr_cont("3c505 is sulking\n");
-			}
-		}
-		for (tries = 0; tries < 5 && okay; tries++) {
-
-			/*
-			 * Try to set the Ethernet address, to make sure that the board
-			 * is working.
-			 */
-			adapter->tx_pcb.command = CMD_STATION_ADDRESS;
-			adapter->tx_pcb.length = 0;
-			cookie = probe_irq_on();
-			if (!send_pcb(dev, &adapter->tx_pcb)) {
-				pr_err("%s: could not send first PCB\n", dev->name);
-				probe_irq_off(cookie);
-				continue;
-			}
-			if (!receive_pcb(dev, &adapter->rx_pcb)) {
-				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)) {
-				pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
-					adapter->rx_pcb.command, adapter->rx_pcb.length);
-				probe_irq_off(cookie);
-				continue;
-			}
-			goto okay;
-		}
-		/* It's broken.  Do a hard reset to re-initialise the board,
-		 * and try again.
-		 */
-		pr_info("%s: resetting adapter\n", dev->name);
-		outb_control(adapter->hcr_val | FLSH | ATTN, dev);
-		outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
-	}
-	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) {
-			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:
-		pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
-		       dev->name);
-		goto out;
-	case 1:
-	case 6:
-	case 8:
-	case 13:
-		pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
-		       dev->name, dev->irq);
-		       goto out;
-	}
-	/*
-	 *  Now we have the IRQ number so we can disable the interrupts from
-	 *  the board until the board is opened.
-	 */
-	outb_control(adapter->hcr_val & ~CMDE, dev);
-
-	/*
-	 * copy Ethernet address into structure
-	 */
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
-
-	/* find a DMA channel */
-	if (!dev->dma) {
-		if (dev->mem_start) {
-			dev->dma = dev->mem_start & 7;
-		}
-		else {
-			pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
-			dev->dma = ELP_DMA;
-		}
-	}
-
-	/*
-	 * print remainder of startup message
-	 */
-	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
-	 */
-
-	adapter->tx_pcb.command = CMD_ADAPTER_INFO;
-	adapter->tx_pcb.length = 0;
-	if (!send_pcb(dev, &adapter->tx_pcb) ||
-	    !receive_pcb(dev, &adapter->rx_pcb) ||
-	    (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
-	    (adapter->rx_pcb.length != 10)) {
-		pr_cont("not responding to second PCB\n");
-	}
-	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
-	 */
-	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
-	adapter->tx_pcb.length = 12;
-	adapter->tx_pcb.data.memconf.cmd_q = 8;
-	adapter->tx_pcb.data.memconf.rcv_q = 8;
-	adapter->tx_pcb.data.memconf.mcast = 10;
-	adapter->tx_pcb.data.memconf.frame = 10;
-	adapter->tx_pcb.data.memconf.rcv_b = 10;
-	adapter->tx_pcb.data.memconf.progs = 0;
-	if (!send_pcb(dev, &adapter->tx_pcb) ||
-	    !receive_pcb(dev, &adapter->rx_pcb) ||
-	    (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
-	    (adapter->rx_pcb.length != 2)) {
-		pr_err("%s: could not configure adapter memory\n", dev->name);
-	}
-	if (adapter->rx_pcb.data.configure) {
-		pr_err("%s: adapter configuration failed\n", dev->name);
-	}
-
-	dev->netdev_ops = &elp_netdev_ops;
-	dev->watchdog_timeo = 10*HZ;
-	dev->ethtool_ops = &netdev_ethtool_ops;		/* local */
-
-	dev->mem_start = dev->mem_end = 0;
-
-	err = register_netdev(dev);
-	if (err)
-		goto out;
-
-	return 0;
-out:
-	release_region(dev->base_addr, ELP_IO_EXTENT);
-	return err;
-}
-
-#ifndef MODULE
-struct net_device * __init elplus_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(elp_device));
-	int err;
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = elplus_setup(dev);
-	if (err) {
-		free_netdev(dev);
-		return ERR_PTR(err);
-	}
-	return dev;
-}
-
-#else
-static struct net_device *dev_3c505[ELP_MAX_CARDS];
-static int io[ELP_MAX_CARDS];
-static int irq[ELP_MAX_CARDS];
-static int dma[ELP_MAX_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
-MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
-
-int __init init_module(void)
-{
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
-		struct net_device *dev = alloc_etherdev(sizeof(elp_device));
-		if (!dev)
-			break;
-
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		if (dma[this_dev]) {
-			dev->dma = dma[this_dev];
-		} else {
-			dev->dma = ELP_DMA;
-			pr_warning("3c505.c: warning, using default DMA channel,\n");
-		}
-		if (io[this_dev] == 0) {
-			if (this_dev) {
-				free_netdev(dev);
-				break;
-			}
-			pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
-		}
-		if (elplus_setup(dev) != 0) {
-			pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
-			free_netdev(dev);
-			break;
-		}
-		dev_3c505[this_dev] = dev;
-		found++;
-	}
-	if (!found)
-		return -ENODEV;
-	return 0;
-}
-
-void __exit cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
-		struct net_device *dev = dev_3c505[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			release_region(dev->base_addr, ELP_IO_EXTENT);
-			free_netdev(dev);
-		}
-	}
-}
-
-#endif				/* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/3c505.h b/drivers/net/ethernet/i825xx/3c505.h
deleted file mode 100644
index 04df2a9..0000000
--- a/drivers/net/ethernet/i825xx/3c505.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************
- *
- *  defines for 3Com Etherlink Plus adapter
- *
- *****************************************************************/
-
-#define ELP_DMA       6
-#define ELP_RX_PCBS   4
-#define ELP_MAX_CARDS 4
-
-/*
- * I/O register offsets
- */
-#define	PORT_COMMAND	0x00	/* read/write, 8-bit */
-#define	PORT_STATUS	0x02	/* read only, 8-bit */
-#define	PORT_AUXDMA	0x02	/* write only, 8-bit */
-#define	PORT_DATA	0x04	/* read/write, 16-bit */
-#define	PORT_CONTROL	0x06	/* read/write, 8-bit */
-
-#define ELP_IO_EXTENT	0x10	/* size of used IO registers */
-
-/*
- * host control registers bits
- */
-#define	ATTN	0x80	/* attention */
-#define	FLSH	0x40	/* flush data register */
-#define DMAE	0x20	/* DMA enable */
-#define DIR	0x10	/* direction */
-#define	TCEN	0x08	/* terminal count interrupt enable */
-#define	CMDE	0x04	/* command register interrupt enable */
-#define	HSF2	0x02	/* host status flag 2 */
-#define	HSF1	0x01	/* host status flag 1 */
-
-/*
- * combinations of HSF flags used for PCB transmission
- */
-#define	HSF_PCB_ACK	HSF1
-#define	HSF_PCB_NAK	HSF2
-#define	HSF_PCB_END	(HSF2|HSF1)
-#define	HSF_PCB_MASK	(HSF2|HSF1)
-
-/*
- * host status register bits
- */
-#define	HRDY	0x80	/* data register ready */
-#define	HCRE	0x40	/* command register empty */
-#define	ACRF	0x20	/* adapter command register full */
-/* #define DIR 	0x10	direction - same as in control register */
-#define	DONE	0x08	/* DMA done */
-#define	ASF3	0x04	/* adapter status flag 3 */
-#define	ASF2	0x02	/* adapter status flag 2 */
-#define	ASF1	0x01	/* adapter status flag 1 */
-
-/*
- * combinations of ASF flags used for PCB reception
- */
-#define	ASF_PCB_ACK	ASF1
-#define	ASF_PCB_NAK	ASF2
-#define	ASF_PCB_END	(ASF2|ASF1)
-#define	ASF_PCB_MASK	(ASF2|ASF1)
-
-/*
- * host aux DMA register bits
- */
-#define	DMA_BRST	0x01	/* DMA burst */
-
-/*
- * maximum amount of data allowed in a PCB
- */
-#define	MAX_PCB_DATA	62
-
-/*****************************************************************
- *
- *  timeout value
- *	this is a rough value used for loops to stop them from
- *	locking up the whole machine in the case of failure or
- *	error conditions
- *
- *****************************************************************/
-
-#define	TIMEOUT	300
-
-/*****************************************************************
- *
- * PCB commands
- *
- *****************************************************************/
-
-enum {
-  /*
-   * host PCB commands
-   */
-  CMD_CONFIGURE_ADAPTER_MEMORY	= 0x01,
-  CMD_CONFIGURE_82586		= 0x02,
-  CMD_STATION_ADDRESS		= 0x03,
-  CMD_DMA_DOWNLOAD		= 0x04,
-  CMD_DMA_UPLOAD		= 0x05,
-  CMD_PIO_DOWNLOAD		= 0x06,
-  CMD_PIO_UPLOAD		= 0x07,
-  CMD_RECEIVE_PACKET		= 0x08,
-  CMD_TRANSMIT_PACKET		= 0x09,
-  CMD_NETWORK_STATISTICS	= 0x0a,
-  CMD_LOAD_MULTICAST_LIST	= 0x0b,
-  CMD_CLEAR_PROGRAM		= 0x0c,
-  CMD_DOWNLOAD_PROGRAM		= 0x0d,
-  CMD_EXECUTE_PROGRAM		= 0x0e,
-  CMD_SELF_TEST			= 0x0f,
-  CMD_SET_STATION_ADDRESS	= 0x10,
-  CMD_ADAPTER_INFO		= 0x11,
-  NUM_TRANSMIT_CMDS,
-
-  /*
-   * adapter PCB commands
-   */
-  CMD_CONFIGURE_ADAPTER_RESPONSE	= 0x31,
-  CMD_CONFIGURE_82586_RESPONSE		= 0x32,
-  CMD_ADDRESS_RESPONSE			= 0x33,
-  CMD_DOWNLOAD_DATA_REQUEST		= 0x34,
-  CMD_UPLOAD_DATA_REQUEST		= 0x35,
-  CMD_RECEIVE_PACKET_COMPLETE		= 0x38,
-  CMD_TRANSMIT_PACKET_COMPLETE		= 0x39,
-  CMD_NETWORK_STATISTICS_RESPONSE	= 0x3a,
-  CMD_LOAD_MULTICAST_RESPONSE		= 0x3b,
-  CMD_CLEAR_PROGRAM_RESPONSE		= 0x3c,
-  CMD_DOWNLOAD_PROGRAM_RESPONSE		= 0x3d,
-  CMD_EXECUTE_RESPONSE			= 0x3e,
-  CMD_SELF_TEST_RESPONSE		= 0x3f,
-  CMD_SET_ADDRESS_RESPONSE		= 0x40,
-  CMD_ADAPTER_INFO_RESPONSE		= 0x41
-};
-
-/* Definitions for the PCB data structure */
-
-/* Data units */
-typedef unsigned char         byte;
-typedef unsigned short int    word;
-typedef unsigned long int     dword;
-
-/* Data structures */
-struct Memconf {
-	word	cmd_q,
-		rcv_q,
-		mcast,
-		frame,
-		rcv_b,
-		progs;
-};
-
-struct Rcv_pkt {
-	word	buf_ofs,
-		buf_seg,
-		buf_len,
-		timeout;
-};
-
-struct Xmit_pkt {
-	word	buf_ofs,
-		buf_seg,
-		pkt_len;
-};
-
-struct Rcv_resp {
-	word	buf_ofs,
-		buf_seg,
-		buf_len,
-		pkt_len,
-		timeout,
-		status;
-	dword	timetag;
-};
-
-struct Xmit_resp {
-	word	buf_ofs,
-		buf_seg,
-		c_stat,
-		status;
-};
-
-
-struct Netstat {
-	dword	tot_recv,
-		tot_xmit;
-	word	err_CRC,
-		err_align,
-		err_res,
-		err_ovrrun;
-};
-
-
-struct Selftest {
-	word	error;
-	union {
-		word ROM_cksum;
-		struct {
-			word ofs, seg;
-		} RAM;
-		word i82586;
-	} failure;
-};
-
-struct Info {
-	byte	minor_vers,
-		major_vers;
-	word	ROM_cksum,
-		RAM_sz,
-		free_ofs,
-		free_seg;
-};
-
-struct Memdump {
-       word size,
-            off,
-            seg;
-};
-
-/*
-Primary Command Block. The most important data structure. All communication
-between the host and the adapter is done with these. (Except for the actual
-Ethernet data, which has different packaging.)
-*/
-typedef struct {
-	byte	command;
-	byte	length;
-	union	{
-		struct Memconf		memconf;
-		word			configure;
-		struct Rcv_pkt		rcv_pkt;
-		struct Xmit_pkt		xmit_pkt;
-		byte			multicast[10][6];
-		byte			eth_addr[6];
-		byte			failed;
-		struct Rcv_resp		rcv_resp;
-		struct Xmit_resp	xmit_resp;
-		struct Netstat		netstat;
-		struct Selftest		selftest;
-		struct Info		info;
-		struct Memdump    	memdump;
-		byte			raw[62];
-	} data;
-} pcb_struct;
-
-/* These defines for 'configure' */
-#define RECV_STATION	0x00
-#define RECV_BROAD	0x01
-#define RECV_MULTI	0x02
-#define RECV_PROMISC	0x04
-#define NO_LOOPBACK	0x00
-#define INT_LOOPBACK	0x08
-#define EXT_LOOPBACK	0x10
-
-/*****************************************************************
- *
- *  structure to hold context information for adapter
- *
- *****************************************************************/
-
-#define DMA_BUFFER_SIZE  1600
-#define BACKLOG_SIZE      4
-
-typedef struct {
-	volatile short got[NUM_TRANSMIT_CMDS];	/* flags for
-						   command completion */
-	pcb_struct tx_pcb;	/* PCB for foreground sending */
-	pcb_struct rx_pcb;	/* PCB for foreground receiving */
-	pcb_struct itx_pcb;	/* PCB for background sending */
-	pcb_struct irx_pcb;	/* PCB for background receiving */
-
-	void *dma_buffer;
-
-	struct {
-		unsigned int length[BACKLOG_SIZE];
-		unsigned int in;
-		unsigned int out;
-	} rx_backlog;
-
-	struct {
-		unsigned int direction;
-		unsigned int length;
-		struct sk_buff *skb;
-	        void *target;
-		unsigned long start_time;
-	} current_dma;
-
-	/* flags */
-	unsigned long send_pcb_semaphore;
-	unsigned long dmaing;
-	unsigned long busy;
-
-	unsigned int rx_active;  /* number of receive PCBs */
-        volatile unsigned char hcr_val;  /* what we think the HCR contains */
-        spinlock_t lock;	/* Interrupt v tx lock */
-} elp_device;
diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
deleted file mode 100644
index e8984b05..0000000
--- a/drivers/net/ethernet/i825xx/3c507.c
+++ /dev/null
@@ -1,938 +0,0 @@
-/* 3c507.c: An EtherLink16 device driver for Linux. */
-/*
-	Written 1993,1994 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-
-	Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
-	and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
-	Mark Salazar <leslie@access.digex.net> made the changes for cards with
-	only 16K packet buffers.
-
-	Things remaining to do:
-	Verify that the tx and rx buffers don't have fencepost errors.
-	Move the theory of operation and memory map documentation.
-	The statistics need to be updated correctly.
-*/
-
-#define DRV_NAME		"3c507"
-#define DRV_VERSION		"1.10a"
-#define DRV_RELDATE		"11/17/2001"
-
-static const char version[] =
-	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
-
-/*
-  Sources:
-	This driver wouldn't have been written with the availability of the
-	Crynwr driver source code.	It provided a known-working implementation
-	that filled in the gaping holes of the Intel documentation.  Three cheers
-	for Russ Nelson.
-
-	Intel Microcommunications Databook, Vol. 1, 1990.  It provides just enough
-	info that the casual reader might think that it documents the i82586 :-<.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-/* use 0 for production, 1 for verification, 2..7 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-#define debug net_debug
-
-
-/*
-  			Details of the i82586.
-
-   You'll really need the databook to understand the details of this part,
-   but the outline is that the i82586 has two separate processing units.
-   Both are started from a list of three configuration tables, of which only
-   the last, the System Control Block (SCB), is used after reset-time.  The SCB
-   has the following fields:
-		Status word
-		Command word
-		Tx/Command block addr.
-		Rx block addr.
-   The command word accepts the following controls for the Tx and Rx units:
-  */
-
-#define	 CUC_START	 0x0100
-#define	 CUC_RESUME	 0x0200
-#define	 CUC_SUSPEND 0x0300
-#define	 RX_START	 0x0010
-#define	 RX_RESUME	 0x0020
-#define	 RX_SUSPEND	 0x0030
-
-/* The Rx unit uses a list of frame descriptors and a list of data buffer
-   descriptors.  We use full-sized (1518 byte) data buffers, so there is
-   a one-to-one pairing of frame descriptors to buffer descriptors.
-
-   The Tx ("command") unit executes a list of commands that look like:
-		Status word		Written by the 82586 when the command is done.
-		Command word	Command in lower 3 bits, post-command action in upper 3
-		Link word		The address of the next command.
-		Parameters		(as needed).
-
-	Some definitions related to the Command Word are:
- */
-#define CMD_EOL		0x8000			/* The last command of the list, stop. */
-#define CMD_SUSP	0x4000			/* Suspend after doing cmd. */
-#define CMD_INTR	0x2000			/* Interrupt after doing cmd. */
-
-enum commands {
-	CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-	CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	int last_restart;
-	ushort rx_head;
-	ushort rx_tail;
-	ushort tx_head;
-	ushort tx_cmd_link;
-	ushort tx_reap;
-	ushort tx_pkts_in_ring;
-	spinlock_t lock;
-	void __iomem *base;
-};
-
-/*
-  		Details of the EtherLink16 Implementation
-  The 3c507 is a generic shared-memory i82586 implementation.
-  The host can map 16K, 32K, 48K, or 64K of the 64K memory into
-  0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
-  */
-
-/* Offsets from the base I/O address. */
-#define	SA_DATA		0	/* Station address data, or 3Com signature. */
-#define MISC_CTRL	6	/* Switch the SA_DATA banks, and bus config bits. */
-#define RESET_IRQ	10	/* Reset the latched IRQ line. */
-#define SIGNAL_CA	11	/* Frob the 82586 Channel Attention line. */
-#define ROM_CONFIG	13
-#define MEM_CONFIG	14
-#define IRQ_CONFIG	15
-#define EL16_IO_EXTENT 16
-
-/* The ID port is used at boot-time to locate the ethercard. */
-#define ID_PORT		0x100
-
-/* Offsets to registers in the mailbox (SCB). */
-#define iSCB_STATUS	0x8
-#define iSCB_CMD		0xA
-#define iSCB_CBL		0xC	/* Command BLock offset. */
-#define iSCB_RFA		0xE	/* Rx Frame Area offset. */
-
-/*  Since the 3c507 maps the shared memory window so that the last byte is
-	at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
-	48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
-	We can account for this be setting the 'SBC Base' entry in the ISCP table
-	below for all the 16 bit offset addresses, and also adding the 'SCB Base'
-	value to all 24 bit physical addresses (in the SCP table and the TX and RX
-	Buffer Descriptors).
-					-Mark
-	*/
-#define SCB_BASE		((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
-
-/*
-  What follows in 'init_words[]' is the "program" that is downloaded to the
-  82586 memory.	 It's mostly tables and command blocks, and starts at the
-  reset address 0xfffff6.  This is designed to be similar to the EtherExpress,
-  thus the unusual location of the SCB at 0x0008.
-
-  Even with the additional "don't care" values, doing it this way takes less
-  program space than initializing the individual tables, and I feel it's much
-  cleaner.
-
-  The databook is particularly useless for the first two structures, I had
-  to use the Crynwr driver as an example.
-
-   The memory setup is as follows:
-   */
-
-#define CONFIG_CMD	0x0018
-#define SET_SA_CMD	0x0024
-#define SA_OFFSET	0x002A
-#define IDLELOOP	0x30
-#define TDR_CMD		0x38
-#define TDR_TIME	0x3C
-#define DUMP_CMD	0x40
-#define DIAG_CMD	0x48
-#define SET_MC_CMD	0x4E
-#define DUMP_DATA	0x56	/* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START	0x0100
-#define NUM_TX_BUFS 	5
-#define TX_BUF_SIZE 	(1518+14+20+16) /* packet+header+TBD */
-
-#define RX_BUF_START	0x2000
-#define RX_BUF_SIZE 	(1518+14+18)	/* packet+header+RBD */
-#define RX_BUF_END		(dev->mem_end - dev->mem_start)
-
-#define TX_TIMEOUT (HZ/20)
-
-/*
-  That's it: only 86 bytes to set up the beast, including every extra
-  command available.  The 170 byte buffer at DUMP_DATA is shared between the
-  Dump command (called only by the diagnostic program) and the SetMulticastList
-  command.
-
-  To complete the memory setup you only have to write the station address at
-  SA_OFFSET and create the Tx & Rx buffer lists.
-
-  The Tx command chain and buffer list is setup as follows:
-  A Tx command table, with the data buffer pointing to...
-  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
-	chaining together several smaller buffers.
-  A NoOp command, which initially points to itself,
-  And the packet data.
-
-  A transmit is done by filling in the Tx command table and data buffer,
-  re-writing the NoOp command, and finally changing the offset of the last
-  command to point to the current Tx command.  When the Tx command is finished,
-  it jumps to the NoOp, when it loops until the next Tx command changes the
-  "link offset" in the NoOp.  This way the 82586 never has to go through the
-  slow restart sequence.
-
-  The Rx buffer list is set up in the obvious ring structure.  We have enough
-  memory (and low enough interrupt latency) that we can avoid the complicated
-  Rx buffer linked lists by alway associating a full-size Rx data buffer with
-  each Rx data frame.
-
-  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
-  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
-  */
-
-static unsigned short init_words[] = {
-	/*	System Configuration Pointer (SCP). */
-	0x0000,					/* Set bus size to 16 bits. */
-	0,0,					/* pad words. */
-	0x0000,0x0000,			/* ISCP phys addr, set in init_82586_mem(). */
-
-	/*	Intermediate System Configuration Pointer (ISCP). */
-	0x0001,					/* Status word that's cleared when init is done. */
-	0x0008,0,0,				/* SCB offset, (skip, skip) */
-
-	/* System Control Block (SCB). */
-	0,0xf000|RX_START|CUC_START,	/* SCB status and cmd. */
-	CONFIG_CMD,				/* Command list pointer, points to Configure. */
-	RX_BUF_START,				/* Rx block list. */
-	0,0,0,0,				/* Error count: CRC, align, buffer, overrun. */
-
-	/* 0x0018: Configure command.  Change to put MAC data with packet. */
-	0, CmdConfigure,		/* Status, command.		*/
-	SET_SA_CMD,				/* Next command is Set Station Addr. */
-	0x0804,					/* "4" bytes of config data, 8 byte FIFO. */
-	0x2e40,					/* Magic values, including MAC data location. */
-	0,						/* Unused pad word. */
-
-	/* 0x0024: Setup station address command. */
-	0, CmdSASetup,
-	SET_MC_CMD,				/* Next command. */
-	0xaa00,0xb000,0x0bad,	/* Station address (to be filled in) */
-
-	/* 0x0030: NOP, looping back to itself.	 Point to first Tx buffer to Tx. */
-	0, CmdNOp, IDLELOOP, 0 /* pad */,
-
-	/* 0x0038: A unused Time-Domain Reflectometer command. */
-	0, CmdTDR, IDLELOOP, 0,
-
-	/* 0x0040: An unused Dump State command. */
-	0, CmdDump, IDLELOOP, DUMP_DATA,
-
-	/* 0x0048: An unused Diagnose command. */
-	0, CmdDiagnose, IDLELOOP,
-
-	/* 0x004E: An empty set-multicast-list command. */
-	0, CmdMulticastList, IDLELOOP, 0,
-};
-
-/* Index to functions, as function prototypes. */
-
-static int	el16_probe1(struct net_device *dev, int ioaddr);
-static int	el16_open(struct net_device *dev);
-static netdev_tx_t el16_send_packet(struct sk_buff *skb,
-				    struct net_device *dev);
-static irqreturn_t el16_interrupt(int irq, void *dev_id);
-static void el16_rx(struct net_device *dev);
-static int	el16_close(struct net_device *dev);
-static void el16_tx_timeout (struct net_device *dev);
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
-static void init_82586_mem(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void init_rx_bufs(struct net_device *);
-
-static int io = 0x300;
-static int irq;
-static int mem_start;
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-	If dev->base_addr == 0, probe all likely locations.
-	If dev->base_addr == 1, always return failure.
-	If dev->base_addr == 2, (detachable devices only) allocate space for the
-	device and return success.
-	*/
-
-struct net_device * __init el16_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
-	const unsigned *port;
-	int err = -ENODEV;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-		mem_start = dev->mem_start & 15;
-	}
-
-	if (io > 0x1ff) 	/* Check a single specified location. */
-		err = el16_probe1(dev, io);
-	else if (io != 0)
-		err = -ENXIO;		/* Don't probe at all. */
-	else {
-		for (port = ports; *port; port++) {
-			err = el16_probe1(dev, *port);
-			if (!err)
-				break;
-		}
-	}
-
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	free_irq(dev->irq, dev);
-	iounmap(((struct net_local *)netdev_priv(dev))->base);
-	release_region(dev->base_addr, EL16_IO_EXTENT);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static const struct net_device_ops netdev_ops = {
-	.ndo_open		= el16_open,
-	.ndo_stop		= el16_close,
-	.ndo_start_xmit 	= el16_send_packet,
-	.ndo_tx_timeout 	= el16_tx_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init el16_probe1(struct net_device *dev, int ioaddr)
-{
-	static unsigned char init_ID_done;
-	int i, irq, irqval, retval;
-	struct net_local *lp;
-
-	if (init_ID_done == 0) {
-		ushort lrs_state = 0xff;
-		/* Send the ID sequence to the ID_PORT to enable the board(s). */
-		outb(0x00, ID_PORT);
-		for(i = 0; i < 255; i++) {
-			outb(lrs_state, ID_PORT);
-			lrs_state <<= 1;
-			if (lrs_state & 0x100)
-				lrs_state ^= 0xe7;
-		}
-		outb(0x00, ID_PORT);
-		init_ID_done = 1;
-	}
-
-	if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
-		return -ENODEV;
-
-	if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
-	    (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	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. */
-
-	irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
-	irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
-	if (irqval) {
-		pr_cont("\n");
-		pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
-		retval = -EAGAIN;
-		goto out;
-	}
-
-	/* We've committed to using the board, and can start filling in *dev. */
-	dev->base_addr = ioaddr;
-
-	outb(0x01, ioaddr + MISC_CTRL);
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = inb(ioaddr + i);
-	pr_cont(" %pM", dev->dev_addr);
-
-	if (mem_start)
-		net_debug = mem_start & 7;
-
-#ifdef MEM_BASE
-	dev->mem_start = MEM_BASE;
-	dev->mem_end = dev->mem_start + 0x10000;
-#else
-	{
-		int base;
-		int size;
-		char mem_config = inb(ioaddr + MEM_CONFIG);
-		if (mem_config & 0x20) {
-			size = 64*1024;
-			base = 0xf00000 + (mem_config & 0x08 ? 0x080000
-							   : ((mem_config & 3) << 17));
-		} else {
-			size = ((mem_config & 3) + 1) << 14;
-			base = 0x0c0000 + ( (mem_config & 0x18) << 12);
-		}
-		dev->mem_start = base;
-		dev->mem_end = base + size;
-	}
-#endif
-
-	dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
-	dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
-	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)
-		pr_debug("%s", version);
-
-	lp = netdev_priv(dev);
-	spin_lock_init(&lp->lock);
-	lp->base = ioremap(dev->mem_start, RX_BUF_END);
-	if (!lp->base) {
-		pr_err("3c507: unable to remap memory\n");
-		retval = -EAGAIN;
-		goto out1;
-	}
-
-	dev->netdev_ops = &netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->ethtool_ops = &netdev_ethtool_ops;
- 	dev->flags &= ~IFF_MULTICAST;	/* Multicast doesn't work */
-	return 0;
-out1:
-	free_irq(dev->irq, dev);
-out:
-	release_region(ioaddr, EL16_IO_EXTENT);
-	return retval;
-}
-
-static int el16_open(struct net_device *dev)
-{
-	/* Initialize the 82586 memory and start it. */
-	init_82586_mem(dev);
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-
-static void el16_tx_timeout (struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	void __iomem *shmem = lp->base;
-
-	if (net_debug > 1)
-		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)
-			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)
-			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;
-	}
-	dev->trans_start = jiffies; /* prevent tx timeout */
-	netif_wake_queue (dev);
-}
-
-
-static netdev_tx_t el16_send_packet (struct sk_buff *skb,
-				     struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	unsigned char *buf = skb->data;
-
-	netif_stop_queue (dev);
-
-	spin_lock_irqsave (&lp->lock, flags);
-
-	dev->stats.tx_bytes += length;
-	/* Disable the 82586's input to the interrupt line. */
-	outb (0x80, ioaddr + MISC_CTRL);
-
-	hardware_send_packet (dev, buf, skb->len, length - skb->len);
-
-	/* Enable the 82586 interrupt input. */
-	outb (0x84, ioaddr + MISC_CTRL);
-
-	spin_unlock_irqrestore (&lp->lock, flags);
-
-	dev_kfree_skb (skb);
-
-	/* You might need to clean up and record Tx statistics here. */
-
-	return NETDEV_TX_OK;
-}
-
-/*	The typical workload of the driver:
-	Handle the network interface interrupts. */
-static irqreturn_t el16_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr, status, boguscount = 0;
-	ushort ack_cmd = 0;
-	void __iomem *shmem;
-
-	if (dev == NULL) {
-		pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
-		return IRQ_NONE;
-	}
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-	shmem = lp->base;
-
-	spin_lock(&lp->lock);
-
-	status = readw(shmem+iSCB_STATUS);
-
-	if (net_debug > 4) {
-		pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
-	}
-
-	/* Disable the 82586's input to the interrupt line. */
-	outb(0x80, ioaddr + MISC_CTRL);
-
-	/* Reap the Tx packet buffers. */
-	while (lp->tx_pkts_in_ring) {
-	  unsigned short tx_status = readw(shmem+lp->tx_reap);
-	  if (!(tx_status & 0x8000)) {
-		if (net_debug > 5)
-			pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
-		break;
-	  }
-	  /* Tx unsuccessful or some interesting status bit set. */
-	  if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
-		dev->stats.tx_errors++;
-		if (tx_status & 0x0600)  dev->stats.tx_carrier_errors++;
-		if (tx_status & 0x0100)  dev->stats.tx_fifo_errors++;
-		if (!(tx_status & 0x0040))  dev->stats.tx_heartbeat_errors++;
-		if (tx_status & 0x0020)  dev->stats.tx_aborted_errors++;
-		dev->stats.collisions += tx_status & 0xf;
-	  }
-	  dev->stats.tx_packets++;
-	  if (net_debug > 5)
-		  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;
-
-	  lp->tx_pkts_in_ring--;
-	  /* There is always more space in the Tx ring buffer now. */
-	  netif_wake_queue(dev);
-
-	  if (++boguscount > 10)
-		break;
-	}
-
-	if (status & 0x4000) { /* Packet received. */
-		if (net_debug > 5)
-			pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
-		el16_rx(dev);
-	}
-
-	/* Acknowledge the interrupt sources. */
-	ack_cmd = status & 0xf000;
-
-	if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
-		if (net_debug)
-			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.
-		   For now we rely on the Tx timeout if the resume doesn't work. */
-		ack_cmd |= CUC_RESUME;
-	}
-
-	if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
-		/* 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)
-			pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
-				   dev->name, status);
-		init_rx_bufs(dev);
-		writew(RX_BUF_START,shmem+iSCB_RFA);
-		ack_cmd |= RX_START;
-	}
-
-	writew(ack_cmd,shmem+iSCB_CMD);
-	outb(0, ioaddr + SIGNAL_CA);			/* Issue channel-attn. */
-
-	/* Clear the latched interrupt. */
-	outb(0, ioaddr + RESET_IRQ);
-
-	/* Enable the 82586's interrupt input. */
-	outb(0x84, ioaddr + MISC_CTRL);
-	spin_unlock(&lp->lock);
-	return IRQ_HANDLED;
-}
-
-static int el16_close(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	void __iomem *shmem = lp->base;
-
-	netif_stop_queue(dev);
-
-	/* Flush the Tx and disable Rx. */
-	writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
-	outb(0, ioaddr + SIGNAL_CA);
-
-	/* Disable the 82586's input to the interrupt line. */
-	outb(0x80, ioaddr + MISC_CTRL);
-
-	/* We always physically use the IRQ line, so we don't do free_irq(). */
-
-	/* Update the statistics here. */
-
-	return 0;
-}
-
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	void __iomem *write_ptr;
-	unsigned short SCB_base = SCB_BASE;
-
-	int cur_rxbuf = lp->rx_head = RX_BUF_START;
-
-	/* Initialize each Rx frame + data buffer. */
-	do {	/* While there is room for one more. */
-
-		write_ptr = lp->base + cur_rxbuf;
-
-		writew(0x0000,write_ptr);			/* Status */
-		writew(0x0000,write_ptr+=2);			/* Command */
-		writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2);	/* Link */
-		writew(cur_rxbuf + 22,write_ptr+=2);		/* Buffer offset */
-		writew(0x0000,write_ptr+=2);			/* Pad for dest addr. */
-		writew(0x0000,write_ptr+=2);
-		writew(0x0000,write_ptr+=2);
-		writew(0x0000,write_ptr+=2);			/* Pad for source addr. */
-		writew(0x0000,write_ptr+=2);
-		writew(0x0000,write_ptr+=2);
-		writew(0x0000,write_ptr+=2);			/* Pad for protocol. */
-
-		writew(0x0000,write_ptr+=2);			/* Buffer: Actual count */
-		writew(-1,write_ptr+=2);			/* Buffer: Next (none). */
-		writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
-		writew(0x0000,write_ptr+=2);
-		/* Finally, the number of bytes in the buffer. */
-		writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
-
-		lp->rx_tail = cur_rxbuf;
-		cur_rxbuf += RX_BUF_SIZE;
-	} while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-
-	/* Terminate the list by setting the EOL bit, and wrap the pointer to make
-	   the list a ring. */
-	write_ptr = lp->base + lp->rx_tail + 2;
-	writew(0xC000,write_ptr);				/* Command, mark as last. */
-	writew(lp->rx_head,write_ptr+2);			/* Link */
-}
-
-static void init_82586_mem(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	void __iomem *shmem = lp->base;
-
-	/* Enable loopback to protect the wire while starting up,
-	   and hold the 586 in reset during the memory initialization. */
-	outb(0x20, ioaddr + MISC_CTRL);
-
-	/* Fix the ISCP address and base. */
-	init_words[3] = SCB_BASE;
-	init_words[7] = SCB_BASE;
-
-	/* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
-	memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
-
-	/* Write the words at 0x0000. */
-	memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
-
-	/* Fill in the station address. */
-	memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
-
-	/* The Tx-block list is written as needed.  We just set up the values. */
-	lp->tx_cmd_link = IDLELOOP + 4;
-	lp->tx_head = lp->tx_reap = TX_BUF_START;
-
-	init_rx_bufs(dev);
-
-	/* Start the 586 by releasing the reset line, but leave loopback. */
-	outb(0xA0, ioaddr + MISC_CTRL);
-
-	/* This was time consuming to track down: you need to give two channel
-	   attention signals to reliably start up the i82586. */
-	outb(0, ioaddr + SIGNAL_CA);
-
-	{
-		int boguscnt = 50;
-		while (readw(shmem+iSCB_STATUS) == 0)
-			if (--boguscnt == 0) {
-				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. */
-		outb(0, ioaddr + SIGNAL_CA);
-	}
-
-	/* Disable loopback and enable interrupts. */
-	outb(0x84, ioaddr + MISC_CTRL);
-	if (net_debug > 4)
-		pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
-			   readw(shmem+iSCB_STATUS));
-}
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
-{
-	struct net_local *lp = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	ushort tx_block = lp->tx_head;
-	void __iomem *write_ptr = lp->base + tx_block;
-	static char padding[ETH_ZLEN];
-
-	/* Set the write pointer to the Tx block, and put out the header. */
-	writew(0x0000,write_ptr);			/* Tx status */
-	writew(CMD_INTR|CmdTx,write_ptr+=2);		/* Tx command */
-	writew(tx_block+16,write_ptr+=2);		/* Next command is a NoOp. */
-	writew(tx_block+8,write_ptr+=2);			/* Data Buffer offset. */
-
-	/* Output the data buffer descriptor. */
-	writew((pad + length) | 0x8000,write_ptr+=2);		/* Byte count parameter. */
-	writew(-1,write_ptr+=2);			/* No next data buffer. */
-	writew(tx_block+22+SCB_BASE,write_ptr+=2);	/* Buffer follows the NoOp command. */
-	writew(0x0000,write_ptr+=2);			/* Buffer address high bits (always zero). */
-
-	/* Output the Loop-back NoOp command. */
-	writew(0x0000,write_ptr+=2);			/* Tx status */
-	writew(CmdNOp,write_ptr+=2);			/* Tx command */
-	writew(tx_block+16,write_ptr+=2);		/* Next is myself. */
-
-	/* Output the packet at the write pointer. */
-	memcpy_toio(write_ptr+2, buf, length);
-	if (pad)
-		memcpy_toio(write_ptr+length+2, padding, pad);
-
-	/* Set the old command link pointing to this send packet. */
-	writew(tx_block,lp->base + lp->tx_cmd_link);
-	lp->tx_cmd_link = tx_block + 20;
-
-	/* Set the next free tx region. */
-	lp->tx_head = tx_block + TX_BUF_SIZE;
-	if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
-		lp->tx_head = TX_BUF_START;
-
-	if (net_debug > 4) {
-		pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
-			   dev->name, ioaddr, length, tx_block, lp->tx_head);
-	}
-
-	/* Grimly block further packets if there has been insufficient reaping. */
-	if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
-		netif_wake_queue(dev);
-}
-
-static void el16_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	void __iomem *shmem = lp->base;
-	ushort rx_head = lp->rx_head;
-	ushort rx_tail = lp->rx_tail;
-	ushort boguscount = 10;
-	short frame_status;
-
-	while ((frame_status = readw(shmem+rx_head)) < 0) {   /* Command complete */
-		void __iomem *read_frame = lp->base + rx_head;
-		ushort rfd_cmd = readw(read_frame+2);
-		ushort next_rx_frame = readw(read_frame+4);
-		ushort data_buffer_addr = readw(read_frame+6);
-		void __iomem *data_frame = lp->base + data_buffer_addr;
-		ushort pkt_len = readw(data_frame);
-
-		if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
-		    (pkt_len & 0xC000) != 0xC000) {
-			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,
-			       next_rx_frame, data_buffer_addr, pkt_len);
-		} else if ((frame_status & 0x2000) == 0) {
-			/* Frame Rxed, but with error. */
-			dev->stats.rx_errors++;
-			if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
-			if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
-			if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
-			if (frame_status & 0x0100) dev->stats.rx_over_errors++;
-			if (frame_status & 0x0080) dev->stats.rx_length_errors++;
-		} else {
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-
-			pkt_len &= 0x3fff;
-			skb = netdev_alloc_skb(dev, pkt_len + 2);
-			if (skb == NULL) {
-				pr_err("%s: Memory squeeze, dropping packet.\n",
-				       dev->name);
-				dev->stats.rx_dropped++;
-				break;
-			}
-
-			skb_reserve(skb,2);
-
-			/* 'skb->data' points to the start of sk_buff data area. */
-			memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
-
-			skb->protocol=eth_type_trans(skb,dev);
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-			dev->stats.rx_bytes += pkt_len;
-		}
-
-		/* Clear the status word and set End-of-List on the rx frame. */
-		writew(0,read_frame);
-		writew(0xC000,read_frame+2);
-		/* Clear the end-of-list on the prev. RFD. */
-		writew(0x0000,lp->base + rx_tail + 2);
-
-		rx_tail = rx_head;
-		rx_head = next_rx_frame;
-		if (--boguscount == 0)
-			break;
-	}
-
-	lp->rx_head = rx_head;
-	lp->rx_tail = rx_tail;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-	return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-	debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-	.get_msglevel		= netdev_get_msglevel,
-	.set_msglevel		= netdev_set_msglevel,
-};
-
-#ifdef MODULE
-static struct net_device *dev_3c507;
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
-MODULE_PARM_DESC(irq, "(ignored)");
-
-int __init init_module(void)
-{
-	if (io == 0)
-		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;
-}
-
-void __exit
-cleanup_module(void)
-{
-	struct net_device *dev = dev_3c507;
-	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
-	iounmap(((struct net_local *)netdev_priv(dev))->base);
-	release_region(dev->base_addr, EL16_IO_EXTENT);
-	free_netdev(dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c
index 6aa927a..1c54e22 100644
--- a/drivers/net/ethernet/i825xx/82596.c
+++ b/drivers/net/ethernet/i825xx/82596.c
@@ -95,9 +95,6 @@
 #if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
 #define ENABLE_BVME6000_NET
 #endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
-#define ENABLE_APRICOT
-#endif
 
 #ifdef ENABLE_MVME16x_NET
 #include <asm/mvme16xhw.h>
@@ -120,8 +117,15 @@
 #define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
 #define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
 #define ISCP_BUSY	0x00010000
-#define MACH_IS_APRICOT	0
 #else
+#error 82596.c: unknown architecture
+#endif
+
+/*
+ * These were the intel versions, left here for reference. There
+ * are currently no x86 users of this legacy i82596 chip.
+ */
+#if 0
 #define WSWAPrfd(x)     ((struct i596_rfd *)((long)x))
 #define WSWAPrbd(x)     ((struct i596_rbd *)((long)x))
 #define WSWAPiscp(x)    ((struct i596_iscp *)((long)x))
@@ -130,7 +134,6 @@
 #define WSWAPtbd(x)     ((struct i596_tbd *)((long)x))
 #define WSWAPchar(x)    ((char *)((long)x))
 #define ISCP_BUSY	0x0001
-#define MACH_IS_APRICOT	1
 #endif
 
 /*
@@ -383,11 +386,6 @@
 		i = *(volatile u32 *) (dev->base_addr);
 	}
 #endif
-#ifdef ENABLE_APRICOT
-	if (MACH_IS_APRICOT) {
-		outw(0, (short) (dev->base_addr) + 4);
-	}
-#endif
 }
 
 
@@ -617,9 +615,6 @@
 static int init_i596_mem(struct net_device *dev)
 {
 	struct i596_private *lp = dev->ml_priv;
-#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
-	short ioaddr = dev->base_addr;
-#endif
 	unsigned long flags;
 
 	MPU_PORT(dev, PORT_RESET, NULL);
@@ -653,18 +648,6 @@
 
 	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
 
-#elif defined(ENABLE_APRICOT)
-
-	{
-		u32 scp = virt_to_bus(&lp->scp);
-
-		/* change the scp address */
-		outw(0, ioaddr);
-		outw(0, ioaddr);
-		outb(4, ioaddr + 0xf);
-		outw(scp | 2, ioaddr);
-		outw(scp >> 16, ioaddr);
-	}
 #endif
 
 	lp->last_cmd = jiffies;
@@ -677,10 +660,6 @@
 	if (MACH_IS_BVME6000)
 		lp->scp.sysbus = 0x0000004c;
 #endif
-#ifdef ENABLE_APRICOT
-	if (MACH_IS_APRICOT)
-		lp->scp.sysbus = 0x00440000;
-#endif
 
 	lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
 	lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
@@ -698,10 +677,6 @@
 
 	DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
 
-#if defined(ENABLE_APRICOT)
-	(void) inb(ioaddr + 0x10);
-	outb(4, ioaddr + 0xf);
-#endif
 	CA(dev);
 
 	if (wait_istat(dev,lp,1000,"initialization timed out"))
@@ -1203,43 +1178,6 @@
 		goto found;
 	}
 #endif
-#ifdef ENABLE_APRICOT
-	{
-		int checksum = 0;
-		int ioaddr = 0x300;
-
-		/* this is easy the ethernet interface can only be at 0x300 */
-		/* first check nothing is already registered here */
-
-		if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
-			printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
-			err = -EBUSY;
-			goto out;
-		}
-
-		dev->base_addr = ioaddr;
-
-		for (i = 0; i < 8; i++) {
-			eth_addr[i] = inb(ioaddr + 8 + i);
-			checksum += eth_addr[i];
-		}
-
-		/* checksum is a multiple of 0x100, got this wrong first time
-		   some machines have 0x100, some 0x200. The DOS driver doesn't
-		   even bother with the checksum.
-		   Some other boards trip the checksum.. but then appear as
-		   ether address 0. Trap these - AC */
-
-		if ((checksum % 0x100) ||
-		    (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
-			err = -ENODEV;
-			goto out1;
-		}
-
-		dev->irq = 10;
-		goto found;
-	}
-#endif
 	err = -ENODEV;
 	goto out;
 
@@ -1296,9 +1234,6 @@
 #endif
 	free_page ((u32)(dev->mem_start));
 out1:
-#ifdef ENABLE_APRICOT
-	release_region(dev->base_addr, I596_TOTAL_SIZE);
-#endif
 out:
 	free_netdev(dev);
 	return ERR_PTR(err);
@@ -1455,10 +1390,6 @@
 		*ethirq = 3;
 	}
 #endif
-#ifdef ENABLE_APRICOT
-	(void) inb(ioaddr + 0x10);
-	outb(4, ioaddr + 0xf);
-#endif
 	CA(dev);
 
 	DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
@@ -1589,11 +1520,6 @@
 #ifdef MODULE
 static struct net_device *dev_82596;
 
-#ifdef ENABLE_APRICOT
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq, "Apricot IRQ number");
-#endif
-
 static int debug = -1;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "i82596 debug mask");
@@ -1620,10 +1546,6 @@
 			IOMAP_FULL_CACHING);
 #endif
 	free_page ((u32)(dev_82596->mem_start));
-#ifdef ENABLE_APRICOT
-	/* If we don't do this, we can't re-insmod it later. */
-	release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
-#endif
 	free_netdev(dev_82596);
 }
 
diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig
index 959faf7..955d929 100644
--- a/drivers/net/ethernet/i825xx/Kconfig
+++ b/drivers/net/ethernet/i825xx/Kconfig
@@ -6,7 +6,7 @@
 	bool "Intel (82586/82593/82596) devices"
 	default y
 	depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
-		   ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+		   ARCH_ACORN || SNI_RM || SUN3 || \
 		   GSC || BVME6000 || MVME16x || EXPERIMENTAL)
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y
@@ -20,29 +20,6 @@
 
 if NET_VENDOR_I825XX
 
-config ELPLUS
-	tristate "3c505 \"EtherLink Plus\" support"
-	depends on ISA && ISA_DMA_API
-	---help---
-	  Information about this network (Ethernet) card can be found in
-	  <file:Documentation/networking/3c505.txt>.  If you have a card of
-	  this type, say Y and read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called 3c505.
-
-config EL16
-	tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
-	depends on ISA && EXPERIMENTAL
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called 3c507.
-
 config ARM_ETHER1
 	tristate "Acorn Ether1 support"
 	depends on ARM && ARCH_ACORN
@@ -50,17 +27,6 @@
 	  If you have an Acorn system with one of these (AKA25) network cards,
 	  you should say Y to this option if you wish to use it with Linux.
 
-config APRICOT
-	tristate "Apricot Xen-II on board Ethernet"
-	depends on ISA
-	---help---
-	  If you have a network (Ethernet) controller of this type, say Y and
-	  read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called apricot.
-
 config BVME6000_NET
 	tristate "BVME6000 Ethernet support"
 	depends on BVME6000
@@ -70,33 +36,6 @@
 	  in your kernel.
 	  To compile this driver as a module, choose M here.
 
-config EEXPRESS
-	tristate "EtherExpress 16 support"
-	depends on ISA
-	---help---
-	  If you have an EtherExpress16 network (Ethernet) card, say Y and
-	  read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.  Note that the Intel
-	  EtherExpress16 card used to be regarded as a very poor choice
-	  because the driver was very unreliable. We now have a new driver
-	  that should do better.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called eexpress.
-
-config EEXPRESS_PRO
-	tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
-	depends on ISA
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y. This
-	  driver supports Intel i82595{FX,TX} based boards. Note however
-	  that the EtherExpress PRO/100 Ethernet card has its own separate
-	  driver.  Please read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called eepro.
-
 config LASI_82596
 	tristate "Lasi ethernet"
 	depends on GSC
@@ -104,14 +43,6 @@
 	  Say Y here to support the builtin Intel 82596 ethernet controller
 	  found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
 
-config LP486E
-	tristate "LP486E on board Ethernet"
-	depends on ISA
-	---help---
-	  Say Y here to support the 82596-based on-board Ethernet controller
-	  for the Panther motherboard, which is one of the two shipped in the
-	  Intel Professional Workstation.
-
 config MVME16x_NET
 	tristate "MVME16x Ethernet support"
 	depends on MVME16x
@@ -121,17 +52,6 @@
 	  driver for this chip in your kernel.
 	  To compile this driver as a module, choose M here.
 
-config NI52
-	tristate "NI5210 support"
-	depends on ISA
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called ni52.
-
 config SNI_82596
 	tristate "SNI RM ethernet"
 	depends on SNI_RM
@@ -148,14 +68,4 @@
 	  that this driver does not support 82586-based adapters on additional
 	  VME boards.
 
-config ZNET
-	tristate "Zenith Z-Note support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && ISA_DMA_API && X86
-	---help---
-	  The Zenith Z-Note notebook computer has a built-in network
-	  (Ethernet) card, and this is the Linux driver for it. Note that the
-	  IBM Thinkpad 300 is compatible with the Z-Note and is also supported
-	  by this driver. Read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
 endif # NET_VENDOR_I825XX
diff --git a/drivers/net/ethernet/i825xx/Makefile b/drivers/net/ethernet/i825xx/Makefile
index 6adff85..8c8dcd2 100644
--- a/drivers/net/ethernet/i825xx/Makefile
+++ b/drivers/net/ethernet/i825xx/Makefile
@@ -3,15 +3,7 @@
 #
 
 obj-$(CONFIG_ARM_ETHER1) += ether1.o
-obj-$(CONFIG_EEXPRESS) += eexpress.o
-obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_ELPLUS) += 3c505.o
-obj-$(CONFIG_EL16) += 3c507.o
-obj-$(CONFIG_LP486E) += lp486e.o
-obj-$(CONFIG_NI52) += ni52.o
 obj-$(CONFIG_SUN3_82586) += sun3_82586.o
-obj-$(CONFIG_ZNET) += znet.o
-obj-$(CONFIG_APRICOT) += 82596.o
 obj-$(CONFIG_LASI_82596) += lasi_82596.o
 obj-$(CONFIG_SNI_82596) += sni_82596.o
 obj-$(CONFIG_MVME16x_NET) += 82596.o
diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
deleted file mode 100644
index 7f49fd5..0000000
--- a/drivers/net/ethernet/i825xx/eepro.c
+++ /dev/null
@@ -1,1822 +0,0 @@
-/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
-/*
-	Written 1994, 1995,1996 by Bao C. Ha.
-
-	Copyright (C) 1994, 1995,1996 by Bao C. Ha.
-
-	This software may be used and distributed
-	according to the terms of the GNU General Public License,
-	incorporated herein by reference.
-
-	The author may be reached at bao.ha@srs.gov
-	or 418 Hastings Place, Martinez, GA 30907.
-
-	Things remaining to do:
-	Better record keeping of errors.
-	Eliminate transmit interrupt to reduce overhead.
-	Implement "concurrent processing". I won't be doing it!
-
-	Bugs:
-
-	If you have a problem of not detecting the 82595 during a
-	reboot (warm reset), disable the FLASH memory should fix it.
-	This is a compatibility hardware problem.
-
-	Versions:
-	0.13b	basic ethtool support (aris, 09/13/2004)
-	0.13a   in memory shortage, drop packets also in board
-		(Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
-	0.13    irq sharing, rewrote probe function, fixed a nasty bug in
-		hardware_send_packet and a major cleanup (aris, 11/08/2001)
-	0.12d	fixing a problem with single card detected as eight eth devices
-		fixing a problem with sudden drop in card performance
-		(chris (asdn@go2.pl), 10/29/2001)
-	0.12c	fixing some problems with old cards (aris, 01/08/2001)
-	0.12b	misc fixes (aris, 06/26/2000)
-	0.12a   port of version 0.12a of 2.2.x kernels to 2.3.x
-		(aris (aris@conectiva.com.br), 05/19/2000)
-	0.11e   some tweaks about multiple cards support (PdP, jul/aug 1999)
-	0.11d	added __initdata, __init stuff; call spin_lock_init
-	        in eepro_probe1. Replaced "eepro" by dev->name. Augmented
-		the code protected by spin_lock in interrupt routine
-		(PdP, 12/12/1998)
-	0.11c   minor cleanup (PdP, RMC, 09/12/1998)
-	0.11b   Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
-	        under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
-		avoid console flooding. Added locking at critical parts. Now
-		the dawn thing is SMP safe.
-	0.11a   Attempt to get 2.1.xx support up (RMC)
-	0.11	Brian Candler added support for multiple cards. Tested as
-		a module, no idea if it works when compiled into kernel.
-
-	0.10e	Rick Bressler notified me that ifconfig up;ifconfig down fails
-		because the irq is lost somewhere. Fixed that by moving
-		request_irq and free_irq to eepro_open and eepro_close respectively.
-	0.10d	Ugh! Now Wakeup works. Was seriously broken in my first attempt.
-		I'll need to find a way to specify an ioport other than
-		the default one in the PnP case. PnP definitively sucks.
-		And, yes, this is not the only reason.
-	0.10c	PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
-		to use.
-	0.10b	Should work now with (some) Pro/10+. At least for
-		me (and my two cards) it does. _No_ guarantee for
-		function with non-Pro/10+ cards! (don't have any)
-		(RMC, 9/11/96)
-
-	0.10	Added support for the Etherexpress Pro/10+.  The
-		IRQ map was changed significantly from the old
-		pro/10.  The new interrupt map was provided by
-		Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
-		(BCH, 9/3/96)
-
-	0.09	Fixed a race condition in the transmit algorithm,
-		which causes crashes under heavy load with fast
-		pentium computers.  The performance should also
-		improve a bit.  The size of RX buffer, and hence
-		TX buffer, can also be changed via lilo or insmod.
-		(BCH, 7/31/96)
-
-	0.08	Implement 32-bit I/O for the 82595TX and 82595FX
-		based lan cards.  Disable full-duplex mode if TPE
-		is not used.  (BCH, 4/8/96)
-
-	0.07a	Fix a stat report which counts every packet as a
-		heart-beat failure. (BCH, 6/3/95)
-
-	0.07	Modified to support all other 82595-based lan cards.
-		The IRQ vector of the EtherExpress Pro will be set
-		according to the value saved in the EEPROM.  For other
-		cards, I will do autoirq_request() to grab the next
-		available interrupt vector. (BCH, 3/17/95)
-
-	0.06a,b	Interim released.  Minor changes in the comments and
-		print out format. (BCH, 3/9/95 and 3/14/95)
-
-	0.06	First stable release that I am comfortable with. (BCH,
-		3/2/95)
-
-	0.05	Complete testing of multicast. (BCH, 2/23/95)
-
-	0.04	Adding multicast support. (BCH, 2/14/95)
-
-	0.03	First widely alpha release for public testing.
-		(BCH, 2/14/95)
-
-*/
-
-static const char version[] =
-	"eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
-
-#include <linux/module.h>
-
-/*
-  Sources:
-
-	This driver wouldn't have been written without the availability
-	of the Crynwr's Lan595 driver source code.  It helps me to
-	familiarize with the 82595 chipset while waiting for the Intel
-	documentation.  I also learned how to detect the 82595 using
-	the packet driver's technique.
-
-	This driver is written by cutting and pasting the skeleton.c driver
-	provided by Donald Becker.  I also borrowed the EEPROM routine from
-	Donald Becker's 82586 driver.
-
-	Datasheet for the Intel 82595 (including the TX and FX version). It
-	provides just enough info that the casual reader might think that it
-	documents the i82595.
-
-	The User Manual for the 82595.  It provides a lot of the missing
-	information.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "eepro"
-#define DRV_VERSION "0.13c"
-
-#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
-/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
-#define SLOW_DOWN inb(0x80)
-/* udelay(2) */
-#define compat_init_data     __initdata
-enum iftype { AUI=0, BNC=1, TPE=2 };
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int eepro_portlist[] compat_init_data =
-   { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
-/* note: 0x300 is default, the 595FX supports ALL IO Ports
-  from 0x000 to 0x3F0, some of which are reserved in PCs */
-
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define EEPRO_IO_EXTENT	16
-
-/* Different 82595 chips */
-#define	LAN595		0
-#define	LAN595TX	1
-#define	LAN595FX	2
-#define	LAN595FX_10ISA	3
-
-/* Information that need to be kept for each board. */
-struct eepro_local {
-	unsigned rx_start;
-	unsigned tx_start; /* start of the transmit chain */
-	int tx_last;  /* pointer to last packet in the transmit chain */
-	unsigned tx_end;   /* end of the transmit chain (plus 1) */
-	int eepro;	/* 1 for the EtherExpress Pro/10,
-			   2 for the EtherExpress Pro/10+,
-			   3 for the EtherExpress 10 (blue cards),
-			   0 for other 82595-based lan cards. */
-	int version;	/* a flag to indicate if this is a TX or FX
-				   version of the 82595 chip. */
-	int stepping;
-
-	spinlock_t lock; /* Serializing lock  */
-
-	unsigned rcv_ram;	/* pre-calculated space for rx */
-	unsigned xmt_ram;	/* pre-calculated space for tx */
-	unsigned char xmt_bar;
-	unsigned char xmt_lower_limit_reg;
-	unsigned char xmt_upper_limit_reg;
-	short xmt_lower_limit;
-	short xmt_upper_limit;
-	short rcv_lower_limit;
-	short rcv_upper_limit;
-	unsigned char eeprom_reg;
-	unsigned short word[8];
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00	/* Etherexpress Pro/10 */
-#define SA_ADDR1 0xaa
-#define SA_ADDR2 0x00
-
-#define GetBit(x,y) ((x & (1<<y))>>y)
-
-/* EEPROM Word 0: */
-#define ee_PnP       0  /* Plug 'n Play enable bit */
-#define ee_Word1     1  /* Word 1? */
-#define ee_BusWidth  2  /* 8/16 bit */
-#define ee_FlashAddr 3  /* Flash Address */
-#define ee_FlashMask 0x7   /* Mask */
-#define ee_AutoIO    6  /* */
-#define ee_reserved0 7  /* =0! */
-#define ee_Flash     8  /* Flash there? */
-#define ee_AutoNeg   9  /* Auto Negotiation enabled? */
-#define ee_IO0       10 /* IO Address LSB */
-#define ee_IO0Mask   0x /*...*/
-#define ee_IO1       15 /* IO MSB */
-
-/* EEPROM Word 1: */
-#define ee_IntSel    0   /* Interrupt */
-#define ee_IntMask   0x7
-#define ee_LI        3   /* Link Integrity 0= enabled */
-#define ee_PC        4   /* Polarity Correction 0= enabled */
-#define ee_TPE_AUI   5   /* PortSelection 1=TPE */
-#define ee_Jabber    6   /* Jabber prevention 0= enabled */
-#define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */
-#define ee_SMOUT     8   /* SMout Pin Control 0= Input */
-#define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */
-#define ee_reserved1 10  /* .. 12 =0! */
-#define ee_AltReady  13  /* Alternate Ready, 0=normal */
-#define ee_reserved2 14  /* =0! */
-#define ee_Duplex    15
-
-/* Word2,3,4: */
-#define ee_IA5       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA4       8 /*bit start for individual Addr Byte 5 */
-#define ee_IA3       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA2       8 /*bit start for individual Addr Byte 5 */
-#define ee_IA1       0 /*bit start for individual Addr Byte 5 */
-#define ee_IA0       8 /*bit start for individual Addr Byte 5 */
-
-/* Word 5: */
-#define ee_BNC_TPE   0 /* 0=TPE */
-#define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
-#define ee_BootTypeMask 0x3
-#define ee_NumConn   3  /* Number of Connections 0= One or Two */
-#define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */
-#define ee_PortTPE   5
-#define ee_PortBNC   6
-#define ee_PortAUI   7
-#define ee_PowerMgt  10 /* 0= disabled */
-#define ee_CP        13 /* Concurrent Processing */
-#define ee_CPMask    0x7
-
-/* Word 6: */
-#define ee_Stepping  0 /* Stepping info */
-#define ee_StepMask  0x0F
-#define ee_BoardID   4 /* Manucaturer Board ID, reserved */
-#define ee_BoardMask 0x0FFF
-
-/* Word 7: */
-#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */
-#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
-
-/*..*/
-#define ee_SIZE 0x40 /* total EEprom Size */
-#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
-
-
-/* Card identification via EEprom:   */
-#define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */
-#define ee_addr_id 0x11      /* Word offset for Card ID */
-#define ee_addr_SN 0x12      /* Serial Number */
-#define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */
-
-
-#define ee_vendor_intel0 0x25  /* Vendor ID Intel */
-#define ee_vendor_intel1 0xD4
-#define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */
-#define ee_id_eepro10p1 0x31
-
-#define TX_TIMEOUT ((4*HZ)/10)
-
-/* Index to functions, as function prototypes. */
-
-static int	eepro_probe1(struct net_device *dev, int autoprobe);
-static int	eepro_open(struct net_device *dev);
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
-				     struct net_device *dev);
-static irqreturn_t eepro_interrupt(int irq, void *dev_id);
-static void 	eepro_rx(struct net_device *dev);
-static void 	eepro_transmit_interrupt(struct net_device *dev);
-static int	eepro_close(struct net_device *dev);
-static void     set_multicast_list(struct net_device *dev);
-static void     eepro_tx_timeout (struct net_device *dev);
-
-static int read_eeprom(int ioaddr, int location, struct net_device *dev);
-static int	hardware_send_packet(struct net_device *dev, void *buf, short length);
-static int	eepro_grab_irq(struct net_device *dev);
-
-/*
-			Details of the i82595.
-
-You will need either the datasheet or the user manual to understand what
-is going on here.  The 82595 is very different from the 82586, 82593.
-
-The receive algorithm in eepro_rx() is just an implementation of the
-RCV ring structure that the Intel 82595 imposes at the hardware level.
-The receive buffer is set at 24K, and the transmit buffer is 8K.  I
-am assuming that the total buffer memory is 32K, which is true for the
-Intel EtherExpress Pro/10.  If it is less than that on a generic card,
-the driver will be broken.
-
-The transmit algorithm in the hardware_send_packet() is similar to the
-one in the eepro_rx().  The transmit buffer is a ring linked list.
-I just queue the next available packet to the end of the list.  In my
-system, the 82595 is so fast that the list seems to always contain a
-single packet.  In other systems with faster computers and more congested
-network traffics, the ring linked list should improve performance by
-allowing up to 8K worth of packets to be queued.
-
-The sizes of the receive and transmit buffers can now be changed via lilo
-or insmod.  Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
-where rx-buffer is in KB unit.  Modules uses the parameter mem which is
-also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
-The receive buffer has to be more than 3K or less than 29K.  Otherwise,
-it is reset to the default of 24K, and, hence, 8K for the trasnmit
-buffer (transmit-buffer = 32K - receive-buffer).
-
-*/
-#define RAM_SIZE        0x8000
-
-#define RCV_HEADER      8
-#define RCV_DEFAULT_RAM 0x6000
-
-#define XMT_HEADER      8
-#define XMT_DEFAULT_RAM	(RAM_SIZE - RCV_DEFAULT_RAM)
-
-#define XMT_START_PRO	RCV_DEFAULT_RAM
-#define XMT_START_10	0x0000
-#define RCV_START_PRO	0x0000
-#define RCV_START_10	XMT_DEFAULT_RAM
-
-#define	RCV_DONE	0x0008
-#define	RX_OK		0x2000
-#define	RX_ERROR	0x0d81
-
-#define	TX_DONE_BIT	0x0080
-#define	TX_OK		0x2000
-#define	CHAIN_BIT	0x8000
-#define	XMT_STATUS	0x02
-#define	XMT_CHAIN	0x04
-#define	XMT_COUNT	0x06
-
-#define	BANK0_SELECT	0x00
-#define	BANK1_SELECT	0x40
-#define	BANK2_SELECT	0x80
-
-/* Bank 0 registers */
-#define	COMMAND_REG	0x00	/* Register 0 */
-#define	MC_SETUP	0x03
-#define	XMT_CMD		0x04
-#define	DIAGNOSE_CMD	0x07
-#define	RCV_ENABLE_CMD	0x08
-#define	RCV_DISABLE_CMD	0x0a
-#define	STOP_RCV_CMD	0x0b
-#define	RESET_CMD	0x0e
-#define	POWER_DOWN_CMD	0x18
-#define	RESUME_XMT_CMD	0x1c
-#define	SEL_RESET_CMD	0x1e
-#define	STATUS_REG	0x01	/* Register 1 */
-#define	RX_INT		0x02
-#define	TX_INT		0x04
-#define	EXEC_STATUS	0x30
-#define	ID_REG		0x02	/* Register 2	*/
-#define	R_ROBIN_BITS	0xc0	/* round robin counter */
-#define	ID_REG_MASK	0x2c
-#define	ID_REG_SIG	0x24
-#define	AUTO_ENABLE	0x10
-#define	INT_MASK_REG	0x03	/* Register 3	*/
-#define	RX_STOP_MASK	0x01
-#define	RX_MASK		0x02
-#define	TX_MASK		0x04
-#define	EXEC_MASK	0x08
-#define	ALL_MASK	0x0f
-#define	IO_32_BIT	0x10
-#define	RCV_BAR		0x04	/* The following are word (16-bit) registers */
-#define	RCV_STOP	0x06
-
-#define	XMT_BAR_PRO	0x0a
-#define	XMT_BAR_10	0x0b
-
-#define	HOST_ADDRESS_REG	0x0c
-#define	IO_PORT		0x0e
-#define	IO_PORT_32_BIT	0x0c
-
-/* Bank 1 registers */
-#define	REG1	0x01
-#define	WORD_WIDTH	0x02
-#define	INT_ENABLE	0x80
-#define INT_NO_REG	0x02
-#define	RCV_LOWER_LIMIT_REG	0x08
-#define	RCV_UPPER_LIMIT_REG	0x09
-
-#define	XMT_LOWER_LIMIT_REG_PRO 0x0a
-#define	XMT_UPPER_LIMIT_REG_PRO 0x0b
-#define	XMT_LOWER_LIMIT_REG_10  0x0b
-#define	XMT_UPPER_LIMIT_REG_10  0x0a
-
-/* Bank 2 registers */
-#define	XMT_Chain_Int	0x20	/* Interrupt at the end of the transmit chain */
-#define	XMT_Chain_ErrStop	0x40 /* Interrupt at the end of the chain even if there are errors */
-#define	RCV_Discard_BadFrame	0x80 /* Throw bad frames away, and continue to receive others */
-#define	REG2		0x02
-#define	PRMSC_Mode	0x01
-#define	Multi_IA	0x20
-#define	REG3		0x03
-#define	TPE_BIT		0x04
-#define	BNC_BIT		0x20
-#define	REG13		0x0d
-#define	FDX		0x00
-#define	A_N_ENABLE	0x02
-
-#define	I_ADD_REG0	0x04
-#define	I_ADD_REG1	0x05
-#define	I_ADD_REG2	0x06
-#define	I_ADD_REG3	0x07
-#define	I_ADD_REG4	0x08
-#define	I_ADD_REG5	0x09
-
-#define	EEPROM_REG_PRO 0x0a
-#define	EEPROM_REG_10  0x0b
-
-#define EESK 0x01
-#define EECS 0x02
-#define EEDI 0x04
-#define EEDO 0x08
-
-/* do a full reset */
-#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
-
-/* do a nice reset */
-#define eepro_sel_reset(ioaddr) 	{ \
-					outb(SEL_RESET_CMD, ioaddr); \
-					SLOW_DOWN; \
-					SLOW_DOWN; \
-					}
-
-/* disable all interrupts */
-#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
-
-/* clear all interrupts */
-#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
-
-/* enable tx/rx */
-#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
-							ioaddr + INT_MASK_REG)
-
-/* enable exec event interrupt */
-#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
-
-/* enable rx */
-#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
-
-/* disable rx */
-#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
-
-/* switch bank */
-#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
-#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
-#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
-
-/* enable interrupt line */
-#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
-				ioaddr + REG1)
-
-/* disable interrupt line */
-#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
-				ioaddr + REG1);
-
-/* set diagnose flag */
-#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
-
-/* ack for rx int */
-#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
-
-/* ack for tx int */
-#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
-
-/* a complete sel reset */
-#define eepro_complete_selreset(ioaddr) { \
-						dev->stats.tx_errors++;\
-						eepro_sel_reset(ioaddr);\
-						lp->tx_end = \
-							lp->xmt_lower_limit;\
-						lp->tx_start = lp->tx_end;\
-						lp->tx_last = 0;\
-						dev->trans_start = jiffies;\
-						netif_wake_queue(dev);\
-						eepro_en_rx(ioaddr);\
-					}
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, allocate space for the device and return success
-   (detachable devices only).
-   */
-static int __init do_eepro_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-
-#ifdef PnPWakeup
-	/* XXXX for multiple cards should this only be run once? */
-
-	/* Wakeup: */
-	#define WakeupPort 0x279
-	#define WakeupSeq    {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
-	                      0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
-	                      0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
-	                      0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
-	{
-		unsigned short int WS[32]=WakeupSeq;
-
-		if (request_region(WakeupPort, 2, "eepro wakeup")) {
-			if (net_debug>5)
-				printk(KERN_DEBUG "Waking UP\n");
-
-			outb_p(0,WakeupPort);
-			outb_p(0,WakeupPort);
-			for (i=0; i<32; i++) {
-				outb_p(WS[i],WakeupPort);
-				if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
-			}
-
-			release_region(WakeupPort, 2);
-		} else
-			printk(KERN_WARNING "PnP wakeup region busy!\n");
-	}
-#endif
-
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return eepro_probe1(dev, 0);
-
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-	for (i = 0; eepro_portlist[i]; i++) {
-		dev->base_addr = eepro_portlist[i];
-		dev->irq = irq;
-		if (eepro_probe1(dev, 1) == 0)
-			return 0;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eepro_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_eepro_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static void __init printEEPROMInfo(struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	unsigned short Word;
-	int i,j;
-
-	j = ee_Checksum;
-	for (i = 0; i < 8; i++)
-		j += lp->word[i];
-	for ( ; i < ee_SIZE; i++)
-		j += read_eeprom(ioaddr, i, dev);
-
-	printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
-
-	Word = lp->word[0];
-	printk(KERN_DEBUG "Word0:\n");
-	printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
-	printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
-	printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
-	printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
-
-	if (net_debug>4)  {
-		Word = lp->word[1];
-		printk(KERN_DEBUG "Word1:\n");
-		printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
-		printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
-		printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
-		printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
-		printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
-		printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
-		printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
-	}
-
-	Word = lp->word[5];
-	printk(KERN_DEBUG "Word5:\n");
-	printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
-	printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
-	printk(KERN_DEBUG " Has ");
-	if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
-	if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
-	if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
-	printk(KERN_DEBUG "port(s)\n");
-
-	Word = lp->word[6];
-	printk(KERN_DEBUG "Word6:\n");
-	printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
-	printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
-
-	Word = lp->word[7];
-	printk(KERN_DEBUG "Word7:\n");
-	printk(KERN_DEBUG " INT to IRQ:\n");
-
-	for (i=0, j=0; i<15; i++)
-		if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
-
-	printk(KERN_DEBUG "\n");
-}
-
-/* function to recalculate the limits of buffer based on rcv_ram */
-static void eepro_recalc (struct net_device *dev)
-{
-	struct eepro_local *	lp;
-
-	lp = netdev_priv(dev);
-	lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
-
-	if (lp->eepro == LAN595FX_10ISA) {
-		lp->xmt_lower_limit = XMT_START_10;
-		lp->xmt_upper_limit = (lp->xmt_ram - 2);
-		lp->rcv_lower_limit = lp->xmt_ram;
-		lp->rcv_upper_limit = (RAM_SIZE - 2);
-	}
-	else {
-		lp->rcv_lower_limit = RCV_START_PRO;
-		lp->rcv_upper_limit = (lp->rcv_ram - 2);
-		lp->xmt_lower_limit = lp->rcv_ram;
-		lp->xmt_upper_limit = (RAM_SIZE - 2);
-	}
-}
-
-/* prints boot-time info */
-static void __init eepro_print_info (struct net_device *dev)
-{
-	struct eepro_local *	lp = netdev_priv(dev);
-	int			i;
-	const char *		ifmap[] = {"AUI", "10Base2", "10BaseT"};
-
-	i = inb(dev->base_addr + ID_REG);
-	printk(KERN_DEBUG " id: %#x ",i);
-	printk(" io: %#x ", (unsigned)dev->base_addr);
-
-	switch (lp->eepro) {
-		case LAN595FX_10ISA:
-			printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
-					dev->name, (unsigned)dev->base_addr);
-			break;
-		case LAN595FX:
-			printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
-					dev->name, (unsigned)dev->base_addr);
-			break;
-		case LAN595TX:
-			printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
-					dev->name, (unsigned)dev->base_addr);
-			break;
-		case LAN595:
-			printk("%s: Intel 82595-based lan card at %#x,",
-					dev->name, (unsigned)dev->base_addr);
-			break;
-	}
-
-	printk(" %pM", dev->dev_addr);
-
-	if (net_debug > 3)
-		printk(KERN_DEBUG ", %dK RCV buffer",
-				(int)(lp->rcv_ram)/1024);
-
-	if (dev->irq > 2)
-		printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
-	else
-		printk(", %s.\n", ifmap[dev->if_port]);
-
-	if (net_debug > 3) {
-		i = lp->word[5];
-		if (i & 0x2000) /* bit 13 of EEPROM word 5 */
-			printk(KERN_DEBUG "%s: Concurrent Processing is "
-				"enabled but not used!\n", dev->name);
-	}
-
-	/* Check the station address for the manufacturer's code */
-	if (net_debug>3)
-		printEEPROMInfo(dev);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops;
-
-static const struct net_device_ops eepro_netdev_ops = {
- 	.ndo_open               = eepro_open,
- 	.ndo_stop               = eepro_close,
- 	.ndo_start_xmit    	= eepro_send_packet,
-	.ndo_set_rx_mode	= set_multicast_list,
- 	.ndo_tx_timeout		= eepro_tx_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/* This is the real probe routine.  Linux has a history of friendly device
-   probes on the ISA bus.  A good device probe avoids doing writes, and
-   verifies that the correct device exists and functions.  */
-
-static int __init eepro_probe1(struct net_device *dev, int autoprobe)
-{
-	unsigned short station_addr[3], id, counter;
-	int i;
-	struct eepro_local *lp;
-	int ioaddr = dev->base_addr;
-	int err;
-
-	/* Grab the region so we can find another board if autoIRQ fails. */
-	if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
-		if (!autoprobe)
-			printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
-				ioaddr);
-		return -EBUSY;
-	}
-
-	/* Now, we are going to check for the signature of the
-	   ID_REG (register 2 of bank 0) */
-
-	id = inb(ioaddr + ID_REG);
-
-	if ((id & ID_REG_MASK) != ID_REG_SIG)
-		goto exit;
-
-	/* We seem to have the 82595 signature, let's
-	   play with its counter (last 2 bits of
-	   register 2 of bank 0) to be sure. */
-
-	counter = id & R_ROBIN_BITS;
-
-	if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
-		goto exit;
-
-	lp = netdev_priv(dev);
-	memset(lp, 0, sizeof(struct eepro_local));
-	lp->xmt_bar = XMT_BAR_PRO;
-	lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
-	lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
-	lp->eeprom_reg = EEPROM_REG_PRO;
-	spin_lock_init(&lp->lock);
-
-	/* Now, get the ethernet hardware address from
-	   the EEPROM */
-	station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
-	/* FIXME - find another way to know that we've found
-	 * an Etherexpress 10
-	 */
-	if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
-		lp->eepro = LAN595FX_10ISA;
-		lp->eeprom_reg = EEPROM_REG_10;
-		lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
-		lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
-		lp->xmt_bar = XMT_BAR_10;
-		station_addr[0] = read_eeprom(ioaddr, 2, dev);
-	}
-
-	/* get all words at once. will be used here and for ethtool */
-	for (i = 0; i < 8; i++) {
-		lp->word[i] = read_eeprom(ioaddr, i, dev);
-	}
-	station_addr[1] = lp->word[3];
-	station_addr[2] = lp->word[4];
-
-	if (!lp->eepro) {
-		if (lp->word[7] == ee_FX_INT2IRQ)
-			lp->eepro = 2;
-		else if (station_addr[2] == SA_ADDR1)
-			lp->eepro = 1;
-	}
-
-	/* Fill in the 'dev' fields. */
-	for (i=0; i < 6; i++)
-		dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
-
-	/* RX buffer must be more than 3K and less than 29K */
-	if (dev->mem_end < 3072 || dev->mem_end > 29696)
-		lp->rcv_ram = RCV_DEFAULT_RAM;
-
-	/* calculate {xmt,rcv}_{lower,upper}_limit */
-	eepro_recalc(dev);
-
-	if (GetBit(lp->word[5], ee_BNC_TPE))
-		dev->if_port = BNC;
-	else
-		dev->if_port = TPE;
-
- 	if (dev->irq < 2 && lp->eepro != 0) {
- 		/* Mask off INT number */
- 		int count = lp->word[1] & 7;
- 		unsigned irqMask = lp->word[7];
-
- 		while (count--)
- 			irqMask &= irqMask - 1;
-
- 		count = ffs(irqMask);
-
- 		if (count)
- 			dev->irq = count - 1;
-
- 		if (dev->irq < 2) {
- 			printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
- 			goto exit;
- 		} else if (dev->irq == 2) {
- 			dev->irq = 9;
- 		}
- 	}
-
-	dev->netdev_ops		= &eepro_netdev_ops;
- 	dev->watchdog_timeo	= TX_TIMEOUT;
-	dev->ethtool_ops	= &eepro_ethtool_ops;
-
-	/* print boot time info */
-	eepro_print_info(dev);
-
-	/* reset 82595 */
-	eepro_reset(ioaddr);
-
-	err = register_netdev(dev);
-	if (err)
-		goto err;
-	return 0;
-exit:
-	err = -ENODEV;
-err:
- 	release_region(dev->base_addr, EEPRO_IO_EXTENT);
- 	return err;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-
-static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
-static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
-static int	eepro_grab_irq(struct net_device *dev)
-{
-	static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
-	const int *irqp = irqlist;
-	int temp_reg, ioaddr = dev->base_addr;
-
-	eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-	/* Enable the interrupt line. */
-	eepro_en_intline(ioaddr);
-
-	/* be CAREFUL, BANK 0 now */
-	eepro_sw2bank0(ioaddr);
-
-	/* clear all interrupts */
-	eepro_clear_int(ioaddr);
-
-	/* Let EXEC event to interrupt */
-	eepro_en_intexec(ioaddr);
-
-	do {
-		eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-		temp_reg = inb(ioaddr + INT_NO_REG);
-		outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
-
-		eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-		if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
-			unsigned long irq_mask;
-			/* Twinkle the interrupt, and check if it's seen */
-			irq_mask = probe_irq_on();
-
-			eepro_diag(ioaddr); /* RESET the 82595 */
-			mdelay(20);
-
-			if (*irqp == probe_irq_off(irq_mask))  /* It's a good IRQ line */
-				break;
-
-			/* clear all interrupts */
-			eepro_clear_int(ioaddr);
-		}
-	} while (*++irqp);
-
-	eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
-	/* Disable the physical interrupt line. */
-	eepro_dis_intline(ioaddr);
-
-	eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-	/* Mask all the interrupts. */
-	eepro_dis_int(ioaddr);
-
-	/* clear all interrupts */
-	eepro_clear_int(ioaddr);
-
-	return dev->irq;
-}
-
-static int eepro_open(struct net_device *dev)
-{
-	unsigned short temp_reg, old8, old9;
-	int irqMask;
-	int i, ioaddr = dev->base_addr;
-	struct eepro_local *lp = netdev_priv(dev);
-
-	if (net_debug > 3)
-		printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
-
-	irqMask = lp->word[7];
-
-	if (lp->eepro == LAN595FX_10ISA) {
-		if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
-	}
-	else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
-		{
-			lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
-			if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
-		}
-
-	else if ((dev->dev_addr[0] == SA_ADDR0 &&
-			dev->dev_addr[1] == SA_ADDR1 &&
-			dev->dev_addr[2] == SA_ADDR2))
-		{
-			lp->eepro = 1;
-			if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
-		}  /* Yes, an Intel EtherExpress Pro/10 */
-
-	else lp->eepro = 0; /* No, it is a generic 82585 lan card */
-
-	/* Get the interrupt vector for the 82595 */
-	if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-
-	if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-
-	/* Initialize the 82595. */
-
-	eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-	temp_reg = inb(ioaddr + lp->eeprom_reg);
-
-	lp->stepping = temp_reg >> 5;	/* Get the stepping number of the 595 */
-
-	if (net_debug > 3)
-		printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
-
-	if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
-		outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
-	for (i=0; i < 6; i++)
-		outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
-
-	temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
-	outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
-		| RCV_Discard_BadFrame, ioaddr + REG1);
-
-	temp_reg = inb(ioaddr + REG2); /* Match broadcast */
-	outb(temp_reg | 0x14, ioaddr + REG2);
-
-	temp_reg = inb(ioaddr + REG3);
-	outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
-
-	/* Set the receiving mode */
-	eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
-	/* Set the interrupt vector */
-	temp_reg = inb(ioaddr + INT_NO_REG);
-	if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
-		outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
-	else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-
-	temp_reg = inb(ioaddr + INT_NO_REG);
-	if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
-		outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
-	else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-	if (net_debug > 3)
-		printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
-
-
-	/* Initialize the RCV and XMT upper and lower limits */
-	outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
-	outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
-	outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
-	outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
-
-	/* Enable the interrupt line. */
-	eepro_en_intline(ioaddr);
-
-	/* Switch back to Bank 0 */
-	eepro_sw2bank0(ioaddr);
-
-	/* Let RX and TX events to interrupt */
-	eepro_en_int(ioaddr);
-
-	/* clear all interrupts */
-	eepro_clear_int(ioaddr);
-
-	/* Initialize RCV */
-	outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
-	lp->rx_start = lp->rcv_lower_limit;
-	outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
-
-	/* Initialize XMT */
-	outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
-	lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
-	lp->tx_last = 0;
-
-	/* Check for the i82595TX and i82595FX */
-	old8 = inb(ioaddr + 8);
-	outb(~old8, ioaddr + 8);
-
-	if ((temp_reg = inb(ioaddr + 8)) == old8) {
-		if (net_debug > 3)
-			printk(KERN_DEBUG "i82595 detected!\n");
-		lp->version = LAN595;
-	}
-	else {
-		lp->version = LAN595TX;
-		outb(old8, ioaddr + 8);
-		old9 = inb(ioaddr + 9);
-
-		if (irqMask==ee_FX_INT2IRQ) {
-			if (net_debug > 3) {
-				printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
-				printk(KERN_DEBUG "i82595FX detected!\n");
-			}
-			lp->version = LAN595FX;
-			outb(old9, ioaddr + 9);
-			if (dev->if_port != TPE) {	/* Hopefully, this will fix the
-							problem of using Pentiums and
-							pro/10 w/ BNC. */
-				eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-				temp_reg = inb(ioaddr + REG13);
-				/* disable the full duplex mode since it is not
-				applicable with the 10Base2 cable. */
-				outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
-				eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
-			}
-		}
-		else if (net_debug > 3) {
-			printk(KERN_DEBUG "temp_reg: %#x  ~old9: %#x\n",temp_reg,((~old9)&0xff));
-			printk(KERN_DEBUG "i82595TX detected!\n");
-		}
-	}
-
-	eepro_sel_reset(ioaddr);
-
-	netif_start_queue(dev);
-
-	if (net_debug > 3)
-		printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
-
-	/* enabling rx */
-	eepro_en_rx(ioaddr);
-
-	return 0;
-}
-
-static void eepro_tx_timeout (struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	/* if (net_debug > 1) */
-	printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
-		"network cable problem");
-	/* This is not a duplicate. One message for the console,
-	   one for the log file  */
-	printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
-		"network cable problem");
-	eepro_complete_selreset(ioaddr);
-}
-
-
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
-				     struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	unsigned long flags;
-	int ioaddr = dev->base_addr;
-	short length = skb->len;
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);
-
-	if (length < ETH_ZLEN) {
-		if (skb_padto(skb, ETH_ZLEN))
-			return NETDEV_TX_OK;
-		length = ETH_ZLEN;
-	}
-	netif_stop_queue (dev);
-
-	eepro_dis_int(ioaddr);
-	spin_lock_irqsave(&lp->lock, flags);
-
-	{
-		unsigned char *buf = skb->data;
-
-		if (hardware_send_packet(dev, buf, length))
-			/* we won't wake queue here because we're out of space */
-			dev->stats.tx_dropped++;
-		else {
-			dev->stats.tx_bytes+=skb->len;
-			netif_wake_queue(dev);
-		}
-
-	}
-
-	dev_kfree_skb (skb);
-
-	/* You might need to clean up and record Tx statistics here. */
-	/* dev->stats.tx_aborted_errors++; */
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
-
-	eepro_en_int(ioaddr);
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	return NETDEV_TX_OK;
-}
-
-
-/*	The typical workload of the driver:
-	Handle the network interface interrupts. */
-
-static irqreturn_t
-eepro_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct eepro_local *lp;
-	int ioaddr, status, boguscount = 20;
-	int handled = 0;
-
-	lp = netdev_priv(dev);
-
-        spin_lock(&lp->lock);
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
-
-	ioaddr = dev->base_addr;
-
-	while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
-	{
-		handled = 1;
-		if (status & RX_INT) {
-			if (net_debug > 4)
-				printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
-
-			eepro_dis_int(ioaddr);
-
-			/* Get the received packets */
-			eepro_ack_rx(ioaddr);
-			eepro_rx(dev);
-
-			eepro_en_int(ioaddr);
-		}
-		if (status & TX_INT) {
-			if (net_debug > 4)
- 				printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
-
-
-			eepro_dis_int(ioaddr);
-
-			/* Process the status of transmitted packets */
-			eepro_ack_tx(ioaddr);
-			eepro_transmit_interrupt(dev);
-
-			eepro_en_int(ioaddr);
-		}
-	}
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
-
-	spin_unlock(&lp->lock);
-	return IRQ_RETVAL(handled);
-}
-
-static int eepro_close(struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	short temp_reg;
-
-	netif_stop_queue(dev);
-
-	eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
-	/* Disable the physical interrupt line. */
-	temp_reg = inb(ioaddr + REG1);
-	outb(temp_reg & 0x7f, ioaddr + REG1);
-
-	eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
-	/* Flush the Tx and disable Rx. */
-	outb(STOP_RCV_CMD, ioaddr);
-	lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
-	lp->tx_last = 0;
-
-	/* Mask all the interrupts. */
-	eepro_dis_int(ioaddr);
-
-	/* clear all interrupts */
-	eepro_clear_int(ioaddr);
-
-	/* Reset the 82595 */
-	eepro_reset(ioaddr);
-
-	/* release the interrupt */
-	free_irq(dev->irq, dev);
-
-	/* Update the statistics here. What statistics? */
-
-	return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	unsigned short mode;
-	struct netdev_hw_addr *ha;
-	int mc_count = netdev_mc_count(dev);
-
-	if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
-	{
-		eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-		mode = inb(ioaddr + REG2);
-		outb(mode | PRMSC_Mode, ioaddr + REG2);
-		mode = inb(ioaddr + REG3);
-		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-		eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-	}
-
-	else if (mc_count == 0)
-	{
-		eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-		mode = inb(ioaddr + REG2);
-		outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
-		mode = inb(ioaddr + REG3);
-		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-		eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-	}
-
-	else
-	{
-		unsigned short status, *eaddrs;
-		int i, boguscount = 0;
-
-		/* Disable RX and TX interrupts.  Necessary to avoid
-		   corruption of the HOST_ADDRESS_REG by interrupt
-		   service routines. */
-		eepro_dis_int(ioaddr);
-
-		eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
-		mode = inb(ioaddr + REG2);
-		outb(mode | Multi_IA, ioaddr + REG2);
-		mode = inb(ioaddr + REG3);
-		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-		eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
-		outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
-		outw(MC_SETUP, ioaddr + IO_PORT);
-		outw(0, ioaddr + IO_PORT);
-		outw(0, ioaddr + IO_PORT);
-		outw(6 * (mc_count + 1), ioaddr + IO_PORT);
-
-		netdev_for_each_mc_addr(ha, dev) {
-			eaddrs = (unsigned short *) ha->addr;
-			outw(*eaddrs++, ioaddr + IO_PORT);
-			outw(*eaddrs++, ioaddr + IO_PORT);
-			outw(*eaddrs++, ioaddr + IO_PORT);
-		}
-
-		eaddrs = (unsigned short *) dev->dev_addr;
-		outw(eaddrs[0], ioaddr + IO_PORT);
-		outw(eaddrs[1], ioaddr + IO_PORT);
-		outw(eaddrs[2], ioaddr + IO_PORT);
-		outw(lp->tx_end, ioaddr + lp->xmt_bar);
-		outb(MC_SETUP, ioaddr);
-
-		/* Update the transmit queue */
-		i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
-
-		if (lp->tx_start != lp->tx_end)
-		{
-			/* update the next address and the chain bit in the
-			   last packet */
-			outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-			outw(i, ioaddr + IO_PORT);
-			outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-			status = inw(ioaddr + IO_PORT);
-			outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-			lp->tx_end = i ;
-		}
-		else {
-			lp->tx_start = lp->tx_end = i ;
-		}
-
-		/* Acknowledge that the MC setup is done */
-		do { /* We should be doing this in the eepro_interrupt()! */
-			SLOW_DOWN;
-			SLOW_DOWN;
-			if (inb(ioaddr + STATUS_REG) & 0x08)
-			{
-				i = inb(ioaddr);
-				outb(0x08, ioaddr + STATUS_REG);
-
-				if (i & 0x20) { /* command ABORTed */
-					printk(KERN_NOTICE "%s: multicast setup failed.\n",
-						dev->name);
-					break;
-				} else if ((i & 0x0f) == 0x03)	{ /* MC-Done */
-					printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
-						dev->name, mc_count,
-						mc_count > 1 ? "es":"");
-					break;
-				}
-			}
-		} while (++boguscount < 100);
-
-		/* Re-enable RX and TX interrupts */
-		eepro_en_int(ioaddr);
-	}
-	if (lp->eepro == LAN595FX_10ISA) {
-		eepro_complete_selreset(ioaddr);
-	}
-	else
-		eepro_en_rx(ioaddr);
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
-/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
-
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { udelay(40); }
-#define EE_READ_CMD (6 << 6)
-
-static int
-read_eeprom(int ioaddr, int location, struct net_device *dev)
-{
-	int i;
-	unsigned short retval = 0;
-	struct eepro_local *lp = netdev_priv(dev);
-	short ee_addr = ioaddr + lp->eeprom_reg;
-	int read_cmd = location | EE_READ_CMD;
-	short ctrl_val = EECS ;
-
-	/* XXXX - black magic */
-		eepro_sw2bank1(ioaddr);
-		outb(0x00, ioaddr + STATUS_REG);
-	/* XXXX - black magic */
-
-	eepro_sw2bank2(ioaddr);
-	outb(ctrl_val, ee_addr);
-
-	/* Shift the read command bits out. */
-	for (i = 8; i >= 0; i--) {
-		short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
-			: ctrl_val;
-		outb(outval, ee_addr);
-		outb(outval | EESK, ee_addr);	/* EEPROM clock tick. */
-		eeprom_delay();
-		outb(outval, ee_addr);	/* Finish EEPROM a clock tick. */
-		eeprom_delay();
-	}
-	outb(ctrl_val, ee_addr);
-
-	for (i = 16; i > 0; i--) {
-		outb(ctrl_val | EESK, ee_addr);	 eeprom_delay();
-		retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
-		outb(ctrl_val, ee_addr);  eeprom_delay();
-	}
-
-	/* Terminate the EEPROM access. */
-	ctrl_val &= ~EECS;
-	outb(ctrl_val | EESK, ee_addr);
-	eeprom_delay();
-	outb(ctrl_val, ee_addr);
-	eeprom_delay();
-	eepro_sw2bank0(ioaddr);
-	return retval;
-}
-
-static int
-hardware_send_packet(struct net_device *dev, void *buf, short length)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	unsigned status, tx_available, last, end;
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
-
-	/* determine how much of the transmit buffer space is available */
-	if (lp->tx_end > lp->tx_start)
-		tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
-	else if (lp->tx_end < lp->tx_start)
-		tx_available = lp->tx_start - lp->tx_end;
-	else tx_available = lp->xmt_ram;
-
-	if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
-		/* No space available ??? */
-		return 1;
-		}
-
-		last = lp->tx_end;
-		end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-
-	if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
-		if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
-				/* Arrrr!!!, must keep the xmt header together,
-				several days were lost to chase this one down. */
-			last = lp->xmt_lower_limit;
-				end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-			}
-		else end = lp->xmt_lower_limit + (end -
-						lp->xmt_upper_limit + 2);
-		}
-
-		outw(last, ioaddr + HOST_ADDRESS_REG);
-		outw(XMT_CMD, ioaddr + IO_PORT);
-		outw(0, ioaddr + IO_PORT);
-		outw(end, ioaddr + IO_PORT);
-		outw(length, ioaddr + IO_PORT);
-
-		if (lp->version == LAN595)
-			outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
-		else {	/* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-			unsigned short temp = inb(ioaddr + INT_MASK_REG);
-			outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-			outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
-			outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-		}
-
-		/* A dummy read to flush the DRAM write pipeline */
-		status = inw(ioaddr + IO_PORT);
-
-		if (lp->tx_start == lp->tx_end) {
-		outw(last, ioaddr + lp->xmt_bar);
-			outb(XMT_CMD, ioaddr);
-			lp->tx_start = last;   /* I don't like to change tx_start here */
-		}
-		else {
-			/* update the next address and the chain bit in the
-			last packet */
-
-			if (lp->tx_end != last) {
-				outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-				outw(last, ioaddr + IO_PORT);
-			}
-
-			outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-			status = inw(ioaddr + IO_PORT);
-			outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
-			/* Continue the transmit command */
-			outb(RESUME_XMT_CMD, ioaddr);
-		}
-
-		lp->tx_last = last;
-		lp->tx_end = end;
-
-		if (net_debug > 5)
-			printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
-
-	return 0;
-}
-
-static void
-eepro_rx(struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	short boguscount = 20;
-	short rcv_car = lp->rx_start;
-	unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-
-	/* Set the read pointer to the start of the RCV */
-	outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
-
-	rcv_event = inw(ioaddr + IO_PORT);
-
-	while (rcv_event == RCV_DONE) {
-
-		rcv_status = inw(ioaddr + IO_PORT);
-		rcv_next_frame = inw(ioaddr + IO_PORT);
-		rcv_size = inw(ioaddr + IO_PORT);
-
-		if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
-
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-
-			dev->stats.rx_bytes+=rcv_size;
-			rcv_size &= 0x3fff;
-			skb = netdev_alloc_skb(dev, rcv_size + 5);
-			if (skb == NULL) {
-				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-				dev->stats.rx_dropped++;
-				rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-				lp->rx_start = rcv_next_frame;
-				outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-
-				break;
-			}
-			skb_reserve(skb,2);
-
-			if (lp->version == LAN595)
-				insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
-			else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-				unsigned short temp = inb(ioaddr + INT_MASK_REG);
-				outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-				insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
-					(rcv_size + 3) >> 2);
-				outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-			}
-
-			skb->protocol = eth_type_trans(skb,dev);
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-		}
-
-		else { /* Not sure will ever reach here,
-			I set the 595 to discard bad received frames */
-			dev->stats.rx_errors++;
-
-			if (rcv_status & 0x0100)
-				dev->stats.rx_over_errors++;
-
-			else if (rcv_status & 0x0400)
-				dev->stats.rx_frame_errors++;
-
-			else if (rcv_status & 0x0800)
-				dev->stats.rx_crc_errors++;
-
-			printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
-				dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
-		}
-
-		if (rcv_status & 0x1000)
-			dev->stats.rx_length_errors++;
-
-		rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-		lp->rx_start = rcv_next_frame;
-
-		if (--boguscount == 0)
-			break;
-
-		outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-		rcv_event = inw(ioaddr + IO_PORT);
-
-	}
-	if (rcv_car == 0)
-		rcv_car = lp->rcv_upper_limit | 0xff;
-
-	outw(rcv_car - 1, ioaddr + RCV_STOP);
-
-	if (net_debug > 5)
-		printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
-}
-
-static void
-eepro_transmit_interrupt(struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	short boguscount = 25;
-	short xmt_status;
-
-	while ((lp->tx_start != lp->tx_end) && boguscount--) {
-
-		outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
-		xmt_status = inw(ioaddr+IO_PORT);
-
-		if (!(xmt_status & TX_DONE_BIT))
-				break;
-
-		xmt_status = inw(ioaddr+IO_PORT);
-		lp->tx_start = inw(ioaddr+IO_PORT);
-
-		netif_wake_queue (dev);
-
-		if (xmt_status & TX_OK)
-			dev->stats.tx_packets++;
-		else {
-			dev->stats.tx_errors++;
-			if (xmt_status & 0x0400) {
-				dev->stats.tx_carrier_errors++;
-				printk(KERN_DEBUG "%s: carrier error\n",
-					dev->name);
-				printk(KERN_DEBUG "%s: XMT status = %#x\n",
-					dev->name, xmt_status);
-			}
-			else {
-				printk(KERN_DEBUG "%s: XMT status = %#x\n",
-					dev->name, xmt_status);
-				printk(KERN_DEBUG "%s: XMT status = %#x\n",
-					dev->name, xmt_status);
-			}
-		}
-		if (xmt_status & 0x000f) {
-			dev->stats.collisions += (xmt_status & 0x000f);
-		}
-
-		if ((xmt_status & 0x0040) == 0x0) {
-			dev->stats.tx_heartbeat_errors++;
-		}
-	}
-}
-
-static int eepro_ethtool_get_settings(struct net_device *dev,
-					struct ethtool_cmd *cmd)
-{
-	struct eepro_local	*lp = netdev_priv(dev);
-
-	cmd->supported = 	SUPPORTED_10baseT_Half |
-				SUPPORTED_10baseT_Full |
-				SUPPORTED_Autoneg;
-	cmd->advertising =	ADVERTISED_10baseT_Half |
-				ADVERTISED_10baseT_Full |
-				ADVERTISED_Autoneg;
-
-	if (GetBit(lp->word[5], ee_PortTPE)) {
-		cmd->supported |= SUPPORTED_TP;
-		cmd->advertising |= ADVERTISED_TP;
-	}
-	if (GetBit(lp->word[5], ee_PortBNC)) {
-		cmd->supported |= SUPPORTED_BNC;
-		cmd->advertising |= ADVERTISED_BNC;
-	}
-	if (GetBit(lp->word[5], ee_PortAUI)) {
-		cmd->supported |= SUPPORTED_AUI;
-		cmd->advertising |= ADVERTISED_AUI;
-	}
-
-	ethtool_cmd_speed_set(cmd, SPEED_10);
-
-	if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
-		cmd->duplex = DUPLEX_FULL;
-	}
-	else {
-		cmd->duplex = DUPLEX_HALF;
-	}
-
-	cmd->port = dev->if_port;
-	cmd->phy_address = dev->base_addr;
-	cmd->transceiver = XCVR_INTERNAL;
-
-	if (lp->word[0] & ee_AutoNeg) {
-		cmd->autoneg = 1;
-	}
-
-	return 0;
-}
-
-static void eepro_ethtool_get_drvinfo(struct net_device *dev,
-					struct ethtool_drvinfo *drvinfo)
-{
-	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
-	strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
-	snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
-		"ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops = {
-	.get_settings	= eepro_ethtool_get_settings,
-	.get_drvinfo 	= eepro_ethtool_get_drvinfo,
-};
-
-#ifdef MODULE
-
-#define MAX_EEPRO 8
-static struct net_device *dev_eepro[MAX_EEPRO];
-
-static int io[MAX_EEPRO] = {
-  [0 ... MAX_EEPRO-1] = -1
-};
-static int irq[MAX_EEPRO];
-static int mem[MAX_EEPRO] = {	/* Size of the rx buffer in KB */
-  [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
-};
-static int autodetect;
-
-static int n_eepro;
-/* For linux 2.1.xx */
-
-MODULE_AUTHOR("Pascal Dupuis and others");
-MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
-MODULE_LICENSE("GPL");
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param(autodetect, int, 0);
-MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
-MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
-MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
-
-int __init init_module(void)
-{
-	struct net_device *dev;
-	int i;
-	if (io[0] == -1 && autodetect == 0) {
-		printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
-		printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
-		return -ENODEV;
-	}
-	else if (autodetect) {
-		/* if autodetect is set then we must force detection */
-		for (i = 0; i < MAX_EEPRO; i++) {
-			io[i] = 0;
-		}
-
-		printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
-	}
-
-	for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
-		dev = alloc_etherdev(sizeof(struct eepro_local));
-		if (!dev)
-			break;
-
-		dev->mem_end = mem[i];
-		dev->base_addr = io[i];
-		dev->irq = irq[i];
-
-		if (do_eepro_probe(dev) == 0) {
-			dev_eepro[n_eepro++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		break;
-	}
-
-	if (n_eepro)
-		printk(KERN_INFO "%s", version);
-
-	return n_eepro ? 0 : -ENODEV;
-}
-
-void __exit
-cleanup_module(void)
-{
-	int i;
-
-	for (i=0; i<n_eepro; i++) {
-		struct net_device *dev = dev_eepro[i];
-		unregister_netdev(dev);
-		release_region(dev->base_addr, EEPRO_IO_EXTENT);
-		free_netdev(dev);
-	}
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
deleted file mode 100644
index 7a6a2f0..0000000
--- a/drivers/net/ethernet/i825xx/eexpress.c
+++ /dev/null
@@ -1,1661 +0,0 @@
-/* Intel EtherExpress 16 device driver for Linux
- *
- * Written by John Sullivan, 1995
- *  based on original code by Donald Becker, with changes by
- *  Alan Cox and Pauline Middelink.
- *
- * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
- *
- * Many modifications, and currently maintained, by
- *  Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE  Alan Cox <alan@lxorguk.ukuu.org.uk>
- * Added MCA support Adam Fritzler (now deleted)
- *
- * Note - this driver is experimental still - it has problems on faster
- * machines. Someone needs to sit down and go through it line by line with
- * a databook...
- */
-
-/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
- * design using the i82586 Ethernet coprocessor.  It bears no relationship,
- * as far as I know, to the similarly-named "EtherExpress Pro" range.
- *
- * Historically, Linux support for these cards has been very bad.  However,
- * things seem to be getting better slowly.
- */
-
-/* If your card is confused about what sort of interface it has (eg it
- * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
- * or 'SOFTSET /LISA' from DOS seems to help.
- */
-
-/* Here's the scoop on memory mapping.
- *
- * There are three ways to access EtherExpress card memory: either using the
- * shared-memory mapping, or using PIO through the dataport, or using PIO
- * through the "shadow memory" ports.
- *
- * The shadow memory system works by having the card map some of its memory
- * as follows:
- *
- * (the low five bits of the SMPTR are ignored)
- *
- *  base+0x4000..400f      memory at SMPTR+0..15
- *  base+0x8000..800f      memory at SMPTR+16..31
- *  base+0xc000..c007      dubious stuff (memory at SMPTR+16..23 apparently)
- *  base+0xc008..c00f      memory at 0x0008..0x000f
- *
- * This last set (the one at c008) is particularly handy because the SCB
- * lives at 0x0008.  So that set of ports gives us easy random access to data
- * in the SCB without having to mess around setting up pointers and the like.
- * We always use this method to access the SCB (via the scb_xx() functions).
- *
- * Dataport access works by aiming the appropriate (read or write) pointer
- * at the first address you're interested in, and then reading or writing from
- * the dataport.  The pointers auto-increment after each transfer.  We use
- * this for data transfer.
- *
- * We don't use the shared-memory system because it allegedly doesn't work on
- * all cards, and because it's a bit more prone to go wrong (it's one more
- * thing to configure...).
- */
-
-/* Known bugs:
- *
- * - The card seems to want to give us two interrupts every time something
- *   happens, where just one would be better.
- */
-
-/*
- *
- * Note by Zoltan Szilagyi 10-12-96:
- *
- * I've succeeded in eliminating the "CU wedged" messages, and hence the
- * lockups, which were only occurring with cards running in 8-bit mode ("force
- * 8-bit operation" in Intel's SoftSet utility). This version of the driver
- * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
- * CU before submitting a packet for transmission, and then restarts it as soon
- * as the process of handing the packet is complete. This is definitely an
- * unnecessary slowdown if the card is running in 16-bit mode; therefore one
- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
- * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
- * ftp's, which is significantly better than I get in DOS, so the overhead of
- * stopping and restarting the CU with each transmit is not prohibitive in
- * practice.
- *
- * Update by David Woodhouse 11/5/99:
- *
- * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
- * I assume that this is because 16-bit accesses are actually handled as two
- * 8-bit accesses.
- */
-
-#ifdef __alpha__
-#define LOCKUP16 1
-#endif
-#ifndef LOCKUP16
-#define LOCKUP16 0
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifndef NET_DEBUG
-#define NET_DEBUG 4
-#endif
-
-#include "eexpress.h"
-
-#define EEXP_IO_EXTENT  16
-
-/*
- * Private data declarations
- */
-
-struct net_local
-{
-	unsigned long last_tx;       /* jiffies when last transmit started */
-	unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
-	unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
-	unsigned short rx_last;      /* last rx buf */
-	unsigned short rx_ptr;       /* first rx buf to look at */
-	unsigned short tx_head;      /* next free tx buf */
-	unsigned short tx_reap;      /* first in-use tx buf */
-	unsigned short tx_tail;      /* previous tx buf to tx_head */
-	unsigned short tx_link;      /* last known-executing tx buf */
-	unsigned short last_tx_restart;   /* set to tx_link when we
-					     restart the CU */
-	unsigned char started;
-	unsigned short rx_buf_start;
-	unsigned short rx_buf_end;
-	unsigned short num_tx_bufs;
-	unsigned short num_rx_bufs;
-	unsigned char width;         /* 0 for 16bit, 1 for 8bit */
-	unsigned char was_promisc;
-	unsigned char old_mc_count;
-	spinlock_t lock;
-};
-
-/* This is the code and data that is downloaded to the EtherExpress card's
- * memory at boot time.
- */
-
-static unsigned short start_code[] = {
-/* 0x0000 */
-	0x0001,                 /* ISCP: busy - cleared after reset */
-	0x0008,0x0000,0x0000,   /* offset,address (lo,hi) of SCB */
-
-	0x0000,0x0000,          /* SCB: status, commands */
-	0x0000,0x0000,          /* links to first command block,
-				   first receive descriptor */
-	0x0000,0x0000,          /* CRC error, alignment error counts */
-	0x0000,0x0000,          /* out of resources, overrun error counts */
-
-	0x0000,0x0000,          /* pad */
-	0x0000,0x0000,
-
-/* 0x20 -- start of 82586 CU program */
-#define CONF_LINK 0x20
-	0x0000,Cmd_Config,
-	0x0032,                 /* link to next command */
-	0x080c,                 /* 12 bytes follow : fifo threshold=8 */
-	0x2e40,                 /* don't rx bad frames
-				 * SRDY/ARDY => ext. sync. : preamble len=8
-	                         * take addresses from data buffers
-				 * 6 bytes/address
-				 */
-	0x6000,                 /* default backoff method & priority
-				 * interframe spacing = 0x60 */
-	0xf200,                 /* slot time=0x200
-				 * max collision retry = 0xf */
-#define CONF_PROMISC  0x2e
-	0x0000,                 /* no HDLC : normal CRC : enable broadcast
-				 * disable promiscuous/multicast modes */
-	0x003c,                 /* minimum frame length = 60 octets) */
-
-	0x0000,Cmd_SetAddr,
-	0x003e,                 /* link to next command */
-#define CONF_HWADDR  0x38
-	0x0000,0x0000,0x0000,   /* hardware address placed here */
-
-	0x0000,Cmd_MCast,
-	0x0076,                 /* link to next command */
-#define CONF_NR_MULTICAST 0x44
-	0x0000,                 /* number of bytes in multicast address(es) */
-#define CONF_MULTICAST 0x46
-	0x0000, 0x0000, 0x0000, /* some addresses */
-	0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000,
-	0x0000, 0x0000, 0x0000,
-
-#define CONF_DIAG_RESULT  0x76
-	0x0000, Cmd_Diag,
-	0x007c,                 /* link to next command */
-
-	0x0000,Cmd_TDR|Cmd_INT,
-	0x0084,
-#define CONF_TDR_RESULT  0x82
-	0x0000,
-
-	0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
-	0x0084                  /* dummy link */
-};
-
-/* maps irq number to EtherExpress magic value */
-static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
-
-/*
- * Prototypes for Linux interface
- */
-
-static int eexp_open(struct net_device *dev);
-static int eexp_close(struct net_device *dev);
-static void eexp_timeout(struct net_device *dev);
-static netdev_tx_t eexp_xmit(struct sk_buff *buf,
-			     struct net_device *dev);
-
-static irqreturn_t eexp_irq(int irq, void *dev_addr);
-static void eexp_set_multicast(struct net_device *dev);
-
-/*
- * Prototypes for hardware access functions
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev);
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
-		       unsigned short len);
-static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
-					 unsigned char location);
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
-static void eexp_hw_txrestart(struct net_device *dev);
-
-static void eexp_hw_txinit    (struct net_device *dev);
-static void eexp_hw_rxinit    (struct net_device *dev);
-
-static void eexp_hw_init586   (struct net_device *dev);
-static void eexp_setup_filter (struct net_device *dev);
-
-static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
-enum eexp_iftype {AUI=0, BNC=1, TPE=2};
-
-#define STARTED_RU      2
-#define STARTED_CU      1
-
-/*
- * Primitive hardware access functions.
- */
-
-static inline unsigned short scb_status(struct net_device *dev)
-{
-	return inw(dev->base_addr + 0xc008);
-}
-
-static inline unsigned short scb_rdcmd(struct net_device *dev)
-{
-	return inw(dev->base_addr + 0xc00a);
-}
-
-static inline void scb_command(struct net_device *dev, unsigned short cmd)
-{
-	outw(cmd, dev->base_addr + 0xc00a);
-}
-
-static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
-{
-	outw(val, dev->base_addr + 0xc00c);
-}
-
-static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
-{
-	outw(val, dev->base_addr + 0xc00e);
-}
-
-static inline void set_loopback(struct net_device *dev)
-{
-	outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
-}
-
-static inline void clear_loopback(struct net_device *dev)
-{
-	outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
-}
-
-static inline unsigned short int SHADOW(short int addr)
-{
-	addr &= 0x1f;
-	if (addr > 0xf) addr += 0x3ff0;
-	return addr + 0x4000;
-}
-
-/*
- * Linux interface
- */
-
-/*
- * checks for presence of EtherExpress card
- */
-
-static int __init do_express_probe(struct net_device *dev)
-{
-	unsigned short *port;
-	static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
-	unsigned short ioaddr = dev->base_addr;
-	int dev_irq = dev->irq;
-	int err;
-
-	dev->if_port = 0xff; /* not set */
-
-	if (ioaddr&0xfe00) {
-		if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
-			return -EBUSY;
-		err = eexp_hw_probe(dev,ioaddr);
-		release_region(ioaddr, EEXP_IO_EXTENT);
-		return err;
-	} else if (ioaddr)
-		return -ENXIO;
-
-	for (port=&ports[0] ; *port ; port++ )
-	{
-		unsigned short sum = 0;
-		int i;
-		if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
-			continue;
-		for ( i=0 ; i<4 ; i++ )
-		{
-			unsigned short t;
-			t = inb(*port + ID_PORT);
-			sum |= (t>>4) << ((t & 0x03)<<2);
-		}
-		if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
-			release_region(*port, EEXP_IO_EXTENT);
-			return 0;
-		}
-		release_region(*port, EEXP_IO_EXTENT);
-		dev->irq = dev_irq;
-	}
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init express_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_express_probe(dev);
-	if (!err)
-		return dev;
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-/*
- * open and initialize the adapter, ready for use
- */
-
-static int eexp_open(struct net_device *dev)
-{
-	int ret;
-	unsigned short ioaddr = dev->base_addr;
-	struct net_local *lp = netdev_priv(dev);
-
-#if NET_DEBUG > 6
-	printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
-#endif
-
-	if (!dev->irq || !irqrmap[dev->irq])
-		return -ENXIO;
-
-	ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
-	if (ret)
-		return ret;
-
-	if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
-		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-			, ioaddr);
-		goto err_out1;
-	}
-	if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-			, ioaddr+0x4000);
-		goto err_out2;
-	}
-	if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-			, ioaddr+0x8000);
-		goto err_out3;
-	}
-	if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
-		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
-			, ioaddr+0xc000);
-		goto err_out4;
-	}
-
-	if (lp->width) {
-		printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
-		outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
-	}
-
-	eexp_hw_init586(dev);
-	netif_start_queue(dev);
-#if NET_DEBUG > 6
-	printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
-#endif
-	return 0;
-
-	err_out4:
-		release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
-	err_out3:
-		release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
-	err_out2:
-		release_region(ioaddr, EEXP_IO_EXTENT);
-	err_out1:
-		free_irq(dev->irq, dev);
-		return -EBUSY;
-}
-
-/*
- * close and disable the interface, leaving the 586 in reset.
- */
-
-static int eexp_close(struct net_device *dev)
-{
-	unsigned short ioaddr = dev->base_addr;
-	struct net_local *lp = netdev_priv(dev);
-
-	int irq = dev->irq;
-
-	netif_stop_queue(dev);
-
-	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-	lp->started = 0;
-	scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
-	outb(0,ioaddr+SIGNAL_CA);
-	free_irq(irq,dev);
-	outb(i586_RST,ioaddr+EEPROM_Ctrl);
-	release_region(ioaddr, EEXP_IO_EXTENT);
-	release_region(ioaddr+0x4000, 16);
-	release_region(ioaddr+0x8000, 16);
-	release_region(ioaddr+0xc000, 16);
-
-	return 0;
-}
-
-/*
- * This gets called when a higher level thinks we are broken.  Check that
- * nothing has become jammed in the CU.
- */
-
-static void unstick_cu(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short ioaddr = dev->base_addr;
-
-	if (lp->started)
-	{
-		if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
-		{
-			if (lp->tx_link==lp->last_tx_restart)
-			{
-				unsigned short boguscount=200,rsst;
-				printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
-				       dev->name, scb_status(dev));
-				eexp_hw_txinit(dev);
-				lp->last_tx_restart = 0;
-				scb_wrcbl(dev, lp->tx_link);
-				scb_command(dev, SCB_CUstart);
-				outb(0,ioaddr+SIGNAL_CA);
-				while (!SCB_complete(rsst=scb_status(dev)))
-				{
-					if (!--boguscount)
-					{
-						boguscount=200;
-						printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
-						       dev->name,rsst);
-						scb_wrcbl(dev, lp->tx_link);
-						scb_command(dev, SCB_CUstart);
-						outb(0,ioaddr+SIGNAL_CA);
-					}
-				}
-				netif_wake_queue(dev);
-			}
-			else
-			{
-				unsigned short status = scb_status(dev);
-				if (SCB_CUdead(status))
-				{
-					unsigned short txstatus = eexp_hw_lasttxstat(dev);
-					printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
-					       dev->name, status, txstatus);
-					eexp_hw_txrestart(dev);
-				}
-				else
-				{
-					unsigned short txstatus = eexp_hw_lasttxstat(dev);
-					if (netif_queue_stopped(dev) && !txstatus)
-					{
-						printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
-						       dev->name,status,txstatus);
-						eexp_hw_init586(dev);
-						netif_wake_queue(dev);
-					}
-					else
-					{
-						printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
-					}
-				}
-			}
-		}
-	}
-	else
-	{
-		if (time_after(jiffies, lp->init_time + 10))
-		{
-			unsigned short status = scb_status(dev);
-			printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
-			       dev->name, status);
-			eexp_hw_init586(dev);
-			netif_wake_queue(dev);
-		}
-	}
-}
-
-static void eexp_timeout(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_SMP
-	unsigned long flags;
-#endif
-	int status;
-
-	disable_irq(dev->irq);
-
-	/*
-	 *	Best would be to use synchronize_irq(); spin_lock() here
-	 *	lets make it work first..
-	 */
-
-#ifdef CONFIG_SMP
-	spin_lock_irqsave(&lp->lock, flags);
-#endif
-
-	status = scb_status(dev);
-	unstick_cu(dev);
-	printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
-	       (SCB_complete(status)?"lost interrupt":
-		"board on fire"));
-	dev->stats.tx_errors++;
-	lp->last_tx = jiffies;
-	if (!SCB_complete(status)) {
-		scb_command(dev, SCB_CUabort);
-		outb(0,dev->base_addr+SIGNAL_CA);
-	}
-	netif_wake_queue(dev);
-#ifdef CONFIG_SMP
-	spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-}
-
-/*
- * Called to transmit a packet, or to allow us to right ourselves
- * if the kernel thinks we've died.
- */
-static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
-{
-	short length = buf->len;
-#ifdef CONFIG_SMP
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-#endif
-
-#if NET_DEBUG > 6
-	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
-#endif
-
-	if (buf->len < ETH_ZLEN) {
-		if (skb_padto(buf, ETH_ZLEN))
-			return NETDEV_TX_OK;
-		length = ETH_ZLEN;
-	}
-
-	disable_irq(dev->irq);
-
-	/*
-	 *	Best would be to use synchronize_irq(); spin_lock() here
-	 *	lets make it work first..
-	 */
-
-#ifdef CONFIG_SMP
-	spin_lock_irqsave(&lp->lock, flags);
-#endif
-
-	{
-		unsigned short *data = (unsigned short *)buf->data;
-
-		dev->stats.tx_bytes += length;
-
-	        eexp_hw_tx_pio(dev,data,length);
-	}
-	dev_kfree_skb(buf);
-#ifdef CONFIG_SMP
-	spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-	enable_irq(dev->irq);
-	return NETDEV_TX_OK;
-}
-
-/*
- * Handle an EtherExpress interrupt
- * If we've finished initializing, start the RU and CU up.
- * If we've already started, reap tx buffers, handle any received packets,
- * check to make sure we've not become wedged.
- */
-
-static unsigned short eexp_start_irq(struct net_device *dev,
-				     unsigned short status)
-{
-	unsigned short ack_cmd = SCB_ack(status);
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short ioaddr = dev->base_addr;
-	if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
-		short diag_status, tdr_status;
-		while (SCB_CUstat(status)==2)
-			status = scb_status(dev);
-#if NET_DEBUG > 4
-		printk("%s: CU went non-active (status %04x)\n",
-		       dev->name, status);
-#endif
-
-		outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
-		diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
-		if (diag_status & 1<<11) {
-			printk(KERN_WARNING "%s: 82586 failed self-test\n",
-			       dev->name);
-		} else if (!(diag_status & 1<<13)) {
-			printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
-		}
-
-		outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
-		tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
-		if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
-			printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
-		}
-		else if (tdr_status & TDR_XCVRPROBLEM) {
-			printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
-		}
-		else if (tdr_status & TDR_LINKOK) {
-#if NET_DEBUG > 4
-			printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
-#endif
-		} else {
-			printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
-			       tdr_status);
-		}
-
-		lp->started |= STARTED_CU;
-		scb_wrcbl(dev, lp->tx_link);
-		/* if the RU isn't running, start it now */
-		if (!(lp->started & STARTED_RU)) {
-			ack_cmd |= SCB_RUstart;
-			scb_wrrfa(dev, lp->rx_buf_start);
-			lp->rx_ptr = lp->rx_buf_start;
-			lp->started |= STARTED_RU;
-		}
-		ack_cmd |= SCB_CUstart | 0x2000;
-	}
-
-	if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
-		lp->started|=STARTED_RU;
-
-	return ack_cmd;
-}
-
-static void eexp_cmd_clear(struct net_device *dev)
-{
-	unsigned long int oldtime = jiffies;
-	while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
-	if (scb_rdcmd(dev)) {
-		printk("%s: command didn't clear\n", dev->name);
-	}
-}
-
-static irqreturn_t eexp_irq(int dummy, void *dev_info)
-{
-	struct net_device *dev = dev_info;
-	struct net_local *lp;
-	unsigned short ioaddr,status,ack_cmd;
-	unsigned short old_read_ptr, old_write_ptr;
-
-	lp = netdev_priv(dev);
-	ioaddr = dev->base_addr;
-
-	spin_lock(&lp->lock);
-
-	old_read_ptr = inw(ioaddr+READ_PTR);
-	old_write_ptr = inw(ioaddr+WRITE_PTR);
-
-	outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-	status = scb_status(dev);
-
-#if NET_DEBUG > 4
-	printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
-#endif
-
-	if (lp->started == (STARTED_CU | STARTED_RU)) {
-
-		do {
-			eexp_cmd_clear(dev);
-
-			ack_cmd = SCB_ack(status);
-			scb_command(dev, ack_cmd);
-			outb(0,ioaddr+SIGNAL_CA);
-
-			eexp_cmd_clear(dev);
-
-			if (SCB_complete(status)) {
-				if (!eexp_hw_lasttxstat(dev)) {
-					printk("%s: tx interrupt but no status\n", dev->name);
-				}
-			}
-
-			if (SCB_rxdframe(status))
-				eexp_hw_rx_pio(dev);
-
-			status = scb_status(dev);
-		} while (status & 0xc000);
-
-		if (SCB_RUdead(status))
-		{
-			printk(KERN_WARNING "%s: RU stopped: status %04x\n",
-			       dev->name,status);
-#if 0
-			printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
-			outw(lp->cur_rfd, ioaddr+READ_PTR);
-			printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
-			outw(lp->cur_rfd+6, ioaddr+READ_PTR);
-			printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
-			outw(rbd, ioaddr+READ_PTR);
-			printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
-			outw(rbd+8, ioaddr+READ_PTR);
-			printk("[%04x]\n", inw(ioaddr+DATAPORT));
-#endif
-			dev->stats.rx_errors++;
-#if 1
-		        eexp_hw_rxinit(dev);
-#else
-			lp->cur_rfd = lp->first_rfd;
-#endif
-			scb_wrrfa(dev, lp->rx_buf_start);
-			scb_command(dev, SCB_RUstart);
-			outb(0,ioaddr+SIGNAL_CA);
-		}
-	} else {
-		if (status & 0x8000)
-			ack_cmd = eexp_start_irq(dev, status);
-		else
-			ack_cmd = SCB_ack(status);
-		scb_command(dev, ack_cmd);
-		outb(0,ioaddr+SIGNAL_CA);
-	}
-
-	eexp_cmd_clear(dev);
-
-	outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-#if NET_DEBUG > 6
-	printk("%s: leaving eexp_irq()\n", dev->name);
-#endif
-	outw(old_read_ptr, ioaddr+READ_PTR);
-	outw(old_write_ptr, ioaddr+WRITE_PTR);
-
-	spin_unlock(&lp->lock);
-	return IRQ_HANDLED;
-}
-
-/*
- * Hardware access functions
- */
-
-/*
- * Set the cable type to use.
- */
-
-static void eexp_hw_set_interface(struct net_device *dev)
-{
-	unsigned char oldval = inb(dev->base_addr + 0x300e);
-	oldval &= ~0x82;
-	switch (dev->if_port) {
-	case TPE:
-		oldval |= 0x2;
-	case BNC:
-		oldval |= 0x80;
-		break;
-	}
-	outb(oldval, dev->base_addr+0x300e);
-	mdelay(20);
-}
-
-/*
- * Check all the receive buffers, and hand any received packets
- * to the upper levels. Basic sanity check on each frame
- * descriptor, though we don't bother trying to fix broken ones.
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short rx_block = lp->rx_ptr;
-	unsigned short boguscount = lp->num_rx_bufs;
-	unsigned short ioaddr = dev->base_addr;
-	unsigned short status;
-
-#if NET_DEBUG > 6
-	printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
-#endif
-
- 	do {
- 		unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
-
-		outw(rx_block, ioaddr + READ_PTR);
-		status = inw(ioaddr + DATAPORT);
-
-		if (FD_Done(status))
-		{
-			rfd_cmd = inw(ioaddr + DATAPORT);
-			rx_next = inw(ioaddr + DATAPORT);
-			pbuf = inw(ioaddr + DATAPORT);
-
-			outw(pbuf, ioaddr + READ_PTR);
-			pkt_len = inw(ioaddr + DATAPORT);
-
-			if (rfd_cmd!=0x0000)
-  			{
-				printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
-				       dev->name, rfd_cmd);
-				continue;
-			}
-			else if (pbuf!=rx_block+0x16)
-			{
-				printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
-				       dev->name, rx_block+0x16, pbuf);
-				continue;
-			}
-			else if ((pkt_len & 0xc000)!=0xc000)
-			{
-				printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
-				       dev->name, pkt_len & 0xc000);
-  				continue;
-  			}
-  			else if (!FD_OK(status))
-			{
-				dev->stats.rx_errors++;
-				if (FD_CRC(status))
-					dev->stats.rx_crc_errors++;
-				if (FD_Align(status))
-					dev->stats.rx_frame_errors++;
-				if (FD_Resrc(status))
-					dev->stats.rx_fifo_errors++;
-				if (FD_DMA(status))
-					dev->stats.rx_over_errors++;
-				if (FD_Short(status))
-					dev->stats.rx_length_errors++;
-			}
-			else
-			{
-				struct sk_buff *skb;
-				pkt_len &= 0x3fff;
-				skb = netdev_alloc_skb(dev, pkt_len + 16);
-				if (skb == NULL)
-				{
-					printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
-					dev->stats.rx_dropped++;
-					break;
-				}
-				skb_reserve(skb, 2);
-				outw(pbuf+10, ioaddr+READ_PTR);
-			        insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
-				skb->protocol = eth_type_trans(skb,dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-			}
-			outw(rx_block, ioaddr+WRITE_PTR);
-			outw(0, ioaddr+DATAPORT);
-			outw(0, ioaddr+DATAPORT);
-			rx_block = rx_next;
-		}
-	} while (FD_Done(status) && boguscount--);
-	lp->rx_ptr = rx_block;
-}
-
-/*
- * Hand a packet to the card for transmission
- * If we get here, we MUST have already checked
- * to make sure there is room in the transmit
- * buffer region.
- */
-
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
-		       unsigned short len)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short ioaddr = dev->base_addr;
-
-	if (LOCKUP16 || lp->width) {
-		/* Stop the CU so that there is no chance that it
-		   jumps off to a bogus address while we are writing the
-		   pointer to the next transmit packet in 8-bit mode --
-		   this eliminates the "CU wedged" errors in 8-bit mode.
-		   (Zoltan Szilagyi 10-12-96) */
-		scb_command(dev, SCB_CUsuspend);
-		outw(0xFFFF, ioaddr+SIGNAL_CA);
-	}
-
- 	outw(lp->tx_head, ioaddr + WRITE_PTR);
-
-	outw(0x0000, ioaddr + DATAPORT);
-        outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
-	outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-	outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
-
-	outw(0x0000, ioaddr + DATAPORT);
-	outw(0x0000, ioaddr + DATAPORT);
-	outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-
-	outw(0x8000|len, ioaddr + DATAPORT);
-	outw(-1, ioaddr + DATAPORT);
-	outw(lp->tx_head+0x16, ioaddr + DATAPORT);
-	outw(0, ioaddr + DATAPORT);
-
-	outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
-
-	outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
-	outw(lp->tx_head, ioaddr + DATAPORT);
-
-	dev->trans_start = jiffies;
-	lp->tx_tail = lp->tx_head;
-	if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
-		lp->tx_head = TX_BUF_START;
-	else
-		lp->tx_head += TX_BUF_SIZE;
-	if (lp->tx_head != lp->tx_reap)
-		netif_wake_queue(dev);
-
-	if (LOCKUP16 || lp->width) {
-		/* Restart the CU so that the packet can actually
-		   be transmitted. (Zoltan Szilagyi 10-12-96) */
-		scb_command(dev, SCB_CUresume);
-		outw(0xFFFF, ioaddr+SIGNAL_CA);
-	}
-
-	dev->stats.tx_packets++;
-	lp->last_tx = jiffies;
-}
-
-static const struct net_device_ops eexp_netdev_ops = {
-	.ndo_open 		= eexp_open,
-	.ndo_stop 		= eexp_close,
-	.ndo_start_xmit		= eexp_xmit,
-	.ndo_set_rx_mode	= eexp_set_multicast,
-	.ndo_tx_timeout		= eexp_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/*
- * Sanity check the suspected EtherExpress card
- * Read hardware address, reset card, size memory and initialize buffer
- * memory pointers. These are held in netdev_priv(), in case someone has more
- * than one card in a machine.
- */
-
-static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
-{
-	unsigned short hw_addr[3];
-	unsigned char buswidth;
-	unsigned int memory_size;
-	int i;
-	unsigned short xsum = 0;
-	struct net_local *lp = netdev_priv(dev);
-
-	printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
-
-	outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
-	outb(0, ioaddr+EEPROM_Ctrl);
-	udelay(500);
-	outb(i586_RST, ioaddr+EEPROM_Ctrl);
-
-	hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
-	hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
-	hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
-
-	/* Standard Address or Compaq LTE Address */
-	if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
-	      (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
-	{
-		printk(" rejected: invalid address %04x%04x%04x\n",
-			hw_addr[2],hw_addr[1],hw_addr[0]);
-		return -ENODEV;
-	}
-
-	/* Calculate the EEPROM checksum.  Carry on anyway if it's bad,
-	 * though.
-	 */
-	for (i = 0; i < 64; i++)
-		xsum += eexp_hw_readeeprom(ioaddr, i);
-	if (xsum != 0xbaba)
-		printk(" (bad EEPROM xsum 0x%02x)", xsum);
-
-	dev->base_addr = ioaddr;
-	for ( i=0 ; i<6 ; i++ )
-		dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
-
-	{
-		static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
-		unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
-
-		/* Use the IRQ from EEPROM if none was given */
-		if (!dev->irq)
-			dev->irq = irqmap[setupval>>13];
-
-		if (dev->if_port == 0xff) {
-			dev->if_port = !(setupval & 0x1000) ? AUI :
-				eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
-		}
-
-		buswidth = !((setupval & 0x400) >> 10);
-	}
-
-	memset(lp, 0, sizeof(struct net_local));
-	spin_lock_init(&lp->lock);
-
- 	printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
- 	       eexp_ifmap[dev->if_port], buswidth?8:16);
-
-	if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
-		return -EBUSY;
-
- 	eexp_hw_set_interface(dev);
-
-	release_region(dev->base_addr + 0x300e, 1);
-
-	/* Find out how much RAM we have on the card */
-	outw(0, dev->base_addr + WRITE_PTR);
-	for (i = 0; i < 32768; i++)
-		outw(0, dev->base_addr + DATAPORT);
-
-        for (memory_size = 0; memory_size < 64; memory_size++)
-	{
-		outw(memory_size<<10, dev->base_addr + READ_PTR);
-		if (inw(dev->base_addr+DATAPORT))
-			break;
-		outw(memory_size<<10, dev->base_addr + WRITE_PTR);
-		outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
-		outw(memory_size<<10, dev->base_addr + READ_PTR);
-		if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
-			break;
-	}
-
-	/* Sort out the number of buffers.  We may have 16, 32, 48 or 64k
-	 * of RAM to play with.
-	 */
-	lp->num_tx_bufs = 4;
-	lp->rx_buf_end = 0x3ff6;
-	switch (memory_size)
-	{
-	case 64:
-		lp->rx_buf_end += 0x4000;
-	case 48:
-		lp->num_tx_bufs += 4;
-		lp->rx_buf_end += 0x4000;
-	case 32:
-		lp->rx_buf_end += 0x4000;
-	case 16:
-		printk(", %dk RAM)\n", memory_size);
-		break;
-	default:
-		printk(") bad memory size (%dk).\n", memory_size);
-		return -ENODEV;
-		break;
-	}
-
-	lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
-	lp->width = buswidth;
-
-	dev->netdev_ops = &eexp_netdev_ops;
-	dev->watchdog_timeo = 2*HZ;
-
-	return register_netdev(dev);
-}
-
-/*
- * Read a word from the EtherExpress on-board serial EEPROM.
- * The EEPROM contains 64 words of 16 bits.
- */
-static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
-						    unsigned char location)
-{
-	unsigned short cmd = 0x180|(location&0x7f);
-	unsigned short rval = 0,wval = EC_CS|i586_RST;
-	int i;
-
-	outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
-	for (i=0x100 ; i ; i>>=1 )
-	{
-		if (cmd&i)
-			wval |= EC_Wr;
-		else
-			wval &= ~EC_Wr;
-
-		outb(wval,ioaddr+EEPROM_Ctrl);
-		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-		eeprom_delay();
-		outb(wval,ioaddr+EEPROM_Ctrl);
-		eeprom_delay();
-	}
-	wval &= ~EC_Wr;
-	outb(wval,ioaddr+EEPROM_Ctrl);
-	for (i=0x8000 ; i ; i>>=1 )
-	{
-		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-		eeprom_delay();
-		if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
-			rval |= i;
-		outb(wval,ioaddr+EEPROM_Ctrl);
-		eeprom_delay();
-	}
-	wval &= ~EC_CS;
-	outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
-	eeprom_delay();
-	outb(wval,ioaddr+EEPROM_Ctrl);
-	eeprom_delay();
-	return rval;
-}
-
-/*
- * Reap tx buffers and return last transmit status.
- * if ==0 then either:
- *    a) we're not transmitting anything, so why are we here?
- *    b) we've died.
- * otherwise, Stat_Busy(return) means we've still got some packets
- * to transmit, Stat_Done(return) means our buffers should be empty
- * again
- */
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short tx_block = lp->tx_reap;
-	unsigned short status;
-
-	if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
-		return 0x0000;
-
-	do
-	{
-		outw(tx_block & ~31, dev->base_addr + SM_PTR);
-		status = inw(dev->base_addr + SHADOW(tx_block));
-		if (!Stat_Done(status))
-		{
-			lp->tx_link = tx_block;
-			return status;
-		}
-		else
-		{
-			lp->last_tx_restart = 0;
-			dev->stats.collisions += Stat_NoColl(status);
-			if (!Stat_OK(status))
-			{
-				char *whatsup = NULL;
-				dev->stats.tx_errors++;
-  				if (Stat_Abort(status))
-					dev->stats.tx_aborted_errors++;
-				if (Stat_TNoCar(status)) {
-					whatsup = "aborted, no carrier";
-					dev->stats.tx_carrier_errors++;
-				}
-				if (Stat_TNoCTS(status)) {
-					whatsup = "aborted, lost CTS";
-					dev->stats.tx_carrier_errors++;
-				}
-				if (Stat_TNoDMA(status)) {
-					whatsup = "FIFO underran";
-					dev->stats.tx_fifo_errors++;
-				}
-				if (Stat_TXColl(status)) {
-					whatsup = "aborted, too many collisions";
-					dev->stats.tx_aborted_errors++;
-				}
-				if (whatsup)
-					printk(KERN_INFO "%s: transmit %s\n",
-					       dev->name, whatsup);
-			}
-			else
-				dev->stats.tx_packets++;
-		}
-		if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
-			lp->tx_reap = tx_block = TX_BUF_START;
-		else
-			lp->tx_reap = tx_block += TX_BUF_SIZE;
-		netif_wake_queue(dev);
-	}
-	while (lp->tx_reap != lp->tx_head);
-
-	lp->tx_link = lp->tx_tail + 0x08;
-
-	return status;
-}
-
-/*
- * This should never happen. It is called when some higher routine detects
- * that the CU has stopped, to try to restart it from the last packet we knew
- * we were working on, or the idle loop if we had finished for the time.
- */
-
-static void eexp_hw_txrestart(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short ioaddr = dev->base_addr;
-
-	lp->last_tx_restart = lp->tx_link;
-	scb_wrcbl(dev, lp->tx_link);
-	scb_command(dev, SCB_CUstart);
-	outb(0,ioaddr+SIGNAL_CA);
-
-	{
-		unsigned short boguscount=50,failcount=5;
-		while (!scb_status(dev))
-		{
-			if (!--boguscount)
-			{
-				if (--failcount)
-				{
-					printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
-				        scb_wrcbl(dev, lp->tx_link);
-					scb_command(dev, SCB_CUstart);
-					outb(0,ioaddr+SIGNAL_CA);
-					boguscount = 100;
-				}
-				else
-				{
-					printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
-					eexp_hw_init586(dev);
-					netif_wake_queue(dev);
-					return;
-				}
-			}
-		}
-	}
-}
-
-/*
- * Writes down the list of transmit buffers into card memory.  Each
- * entry consists of an 82586 transmit command, followed by a jump
- * pointing to itself.  When we want to transmit a packet, we write
- * the data into the appropriate transmit buffer and then modify the
- * preceding jump to point at the new transmit command.  This means that
- * the 586 command unit is continuously active.
- */
-
-static void eexp_hw_txinit(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short tx_block = TX_BUF_START;
-	unsigned short curtbuf;
-	unsigned short ioaddr = dev->base_addr;
-
-	for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
-	{
-		outw(tx_block, ioaddr + WRITE_PTR);
-
-	        outw(0x0000, ioaddr + DATAPORT);
-		outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
-		outw(tx_block+0x08, ioaddr + DATAPORT);
-		outw(tx_block+0x0e, ioaddr + DATAPORT);
-
-		outw(0x0000, ioaddr + DATAPORT);
-		outw(0x0000, ioaddr + DATAPORT);
-		outw(tx_block+0x08, ioaddr + DATAPORT);
-
-		outw(0x8000, ioaddr + DATAPORT);
-		outw(-1, ioaddr + DATAPORT);
-		outw(tx_block+0x16, ioaddr + DATAPORT);
-		outw(0x0000, ioaddr + DATAPORT);
-
-		tx_block += TX_BUF_SIZE;
-	}
-	lp->tx_head = TX_BUF_START;
-	lp->tx_reap = TX_BUF_START;
-	lp->tx_tail = tx_block - TX_BUF_SIZE;
-	lp->tx_link = lp->tx_tail + 0x08;
-	lp->rx_buf_start = tx_block;
-
-}
-
-/*
- * Write the circular list of receive buffer descriptors to card memory.
- * The end of the list isn't marked, which means that the 82586 receive
- * unit will loop until buffers become available (this avoids it giving us
- * "out of resources" messages).
- */
-
-static void eexp_hw_rxinit(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short rx_block = lp->rx_buf_start;
-	unsigned short ioaddr = dev->base_addr;
-
-	lp->num_rx_bufs = 0;
-	lp->rx_first = lp->rx_ptr = rx_block;
-	do
-	{
-		lp->num_rx_bufs++;
-
-		outw(rx_block, ioaddr + WRITE_PTR);
-
-		outw(0, ioaddr + DATAPORT);  outw(0, ioaddr+DATAPORT);
-		outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
-		outw(0xffff, ioaddr+DATAPORT);
-
-		outw(0x0000, ioaddr+DATAPORT);
-		outw(0xdead, ioaddr+DATAPORT);
-		outw(0xdead, ioaddr+DATAPORT);
-		outw(0xdead, ioaddr+DATAPORT);
-		outw(0xdead, ioaddr+DATAPORT);
-		outw(0xdead, ioaddr+DATAPORT);
-		outw(0xdead, ioaddr+DATAPORT);
-
-		outw(0x0000, ioaddr+DATAPORT);
-		outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
-		outw(rx_block + 0x20, ioaddr+DATAPORT);
-		outw(0, ioaddr+DATAPORT);
-		outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
-
-		lp->rx_last = rx_block;
-		rx_block += RX_BUF_SIZE;
-	} while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
-
-
-	/* Make first Rx frame descriptor point to first Rx buffer
-           descriptor */
-	outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
-	outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-	/* Close Rx frame descriptor ring */
-  	outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
-  	outw(lp->rx_first, ioaddr+DATAPORT);
-
-	/* Close Rx buffer descriptor ring */
-	outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
-	outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-}
-
-/*
- * Un-reset the 586, and start the configuration sequence. We don't wait for
- * this to finish, but allow the interrupt handler to start the CU and RU for
- * us.  We can't start the receive/transmission system up before we know that
- * the hardware is configured correctly.
- */
-
-static void eexp_hw_init586(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned short ioaddr = dev->base_addr;
-	int i;
-
-#if NET_DEBUG > 6
-	printk("%s: eexp_hw_init586()\n", dev->name);
-#endif
-
-	lp->started = 0;
-
-	set_loopback(dev);
-
-	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-	/* Download the startup code */
-	outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
-	outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
-	outw(0x0000, ioaddr + 0x8008);
-	outw(0x0000, ioaddr + 0x800a);
-	outw(0x0000, ioaddr + 0x800c);
-	outw(0x0000, ioaddr + 0x800e);
-
-	for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
-		int j;
-		outw(i, ioaddr + SM_PTR);
-		for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
-			outw(start_code[(i+j)/2],
-			     ioaddr+0x4000+j);
-		for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
-			outw(start_code[(i+j+16)/2],
-			     ioaddr+0x8000+j);
-	}
-
-	/* Do we want promiscuous mode or multicast? */
-	outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
-	i = inw(ioaddr+SHADOW(CONF_PROMISC));
-	outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
-	     ioaddr+SHADOW(CONF_PROMISC));
-	lp->was_promisc = dev->flags & IFF_PROMISC;
-#if 0
-	eexp_setup_filter(dev);
-#endif
-
-	/* Write our hardware address */
-	outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
-	outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
-	outw(((unsigned short *)dev->dev_addr)[1],
-	     ioaddr+SHADOW(CONF_HWADDR+2));
-	outw(((unsigned short *)dev->dev_addr)[2],
-	     ioaddr+SHADOW(CONF_HWADDR+4));
-
-	eexp_hw_txinit(dev);
-	eexp_hw_rxinit(dev);
-
-	outb(0,ioaddr+EEPROM_Ctrl);
-	mdelay(5);
-
-	scb_command(dev, 0xf000);
-	outb(0,ioaddr+SIGNAL_CA);
-
-	outw(0, ioaddr+SM_PTR);
-
-	{
-		unsigned short rboguscount=50,rfailcount=5;
-		while (inw(ioaddr+0x4000))
-		{
-			if (!--rboguscount)
-			{
-				printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
-					dev->name);
-				scb_command(dev, 0);
-				outb(0,ioaddr+SIGNAL_CA);
-				rboguscount = 100;
-				if (!--rfailcount)
-				{
-					printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
-						dev->name);
-					return;
-				}
-			}
-		}
-	}
-
-        scb_wrcbl(dev, CONF_LINK);
-	scb_command(dev, 0xf000|SCB_CUstart);
-	outb(0,ioaddr+SIGNAL_CA);
-
-	{
-		unsigned short iboguscount=50,ifailcount=5;
-		while (!scb_status(dev))
-		{
-			if (!--iboguscount)
-			{
-				if (--ifailcount)
-				{
-					printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
-						dev->name, scb_status(dev), scb_rdcmd(dev));
-					scb_wrcbl(dev, CONF_LINK);
-				        scb_command(dev, 0xf000|SCB_CUstart);
-					outb(0,ioaddr+SIGNAL_CA);
-					iboguscount = 100;
-				}
-				else
-				{
-					printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
-					return;
-				}
-			}
-		}
-	}
-
-	clear_loopback(dev);
-	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
-	lp->init_time = jiffies;
-#if NET_DEBUG > 6
-        printk("%s: leaving eexp_hw_init586()\n", dev->name);
-#endif
-}
-
-static void eexp_setup_filter(struct net_device *dev)
-{
-	struct netdev_hw_addr *ha;
-	unsigned short ioaddr = dev->base_addr;
-	int count = netdev_mc_count(dev);
-	int i;
-	if (count > 8) {
-		printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
-		       dev->name, count);
-		count = 8;
-	}
-
-	outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
-	outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
-	i = 0;
-	netdev_for_each_mc_addr(ha, dev) {
-		unsigned short *data = (unsigned short *) ha->addr;
-
-		if (i == count)
-			break;
-		outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
-		outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
-		outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
-		outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
-		outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
-		outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
-		i++;
-	}
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-static void
-eexp_set_multicast(struct net_device *dev)
-{
-        unsigned short ioaddr = dev->base_addr;
-        struct net_local *lp = netdev_priv(dev);
-        int kick = 0, i;
-        if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
-                outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
-                i = inw(ioaddr+SHADOW(CONF_PROMISC));
-                outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
-                     ioaddr+SHADOW(CONF_PROMISC));
-                lp->was_promisc = dev->flags & IFF_PROMISC;
-                kick = 1;
-        }
-        if (!(dev->flags & IFF_PROMISC)) {
-                eexp_setup_filter(dev);
-                if (lp->old_mc_count != netdev_mc_count(dev)) {
-                        kick = 1;
-                        lp->old_mc_count = netdev_mc_count(dev);
-                }
-        }
-        if (kick) {
-                unsigned long oj;
-                scb_command(dev, SCB_CUsuspend);
-                outb(0, ioaddr+SIGNAL_CA);
-                outb(0, ioaddr+SIGNAL_CA);
-#if 0
-                printk("%s: waiting for CU to go suspended\n", dev->name);
-#endif
-                oj = jiffies;
-                while ((SCB_CUstat(scb_status(dev)) == 2) &&
-                       (time_before(jiffies, oj + 2000)));
-		if (SCB_CUstat(scb_status(dev)) == 2)
-			printk("%s: warning, CU didn't stop\n", dev->name);
-                lp->started &= ~(STARTED_CU);
-                scb_wrcbl(dev, CONF_LINK);
-                scb_command(dev, SCB_CUstart);
-                outb(0, ioaddr+SIGNAL_CA);
-        }
-}
-
-
-/*
- * MODULE stuff
- */
-
-#ifdef MODULE
-
-#define EEXP_MAX_CARDS     4    /* max number of cards to support */
-
-static struct net_device *dev_eexp[EEXP_MAX_CARDS];
-static int irq[EEXP_MAX_CARDS];
-static int io[EEXP_MAX_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-
-/* Ideally the user would give us io=, irq= for every card.  If any parameters
- * are specified, we verify and then use them.  If no parameters are given, we
- * autoprobe for one card only.
- */
-int __init init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
-		dev = alloc_etherdev(sizeof(struct net_local));
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		if (io[this_dev] == 0) {
-			if (this_dev)
-				break;
-			printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
-		}
-		if (do_express_probe(dev) == 0) {
-			dev_eexp[this_dev] = dev;
-			found++;
-			continue;
-		}
-		printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
-		free_netdev(dev);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
-		struct net_device *dev = dev_eexp[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			free_netdev(dev);
-		}
-	}
-}
-#endif
-
-/*
- * Local Variables:
- *  c-file-style: "linux"
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/ethernet/i825xx/eexpress.h b/drivers/net/ethernet/i825xx/eexpress.h
deleted file mode 100644
index dc9c6ea..0000000
--- a/drivers/net/ethernet/i825xx/eexpress.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * eexpress.h: Intel EtherExpress16 defines
- */
-
-/*
- * EtherExpress card register addresses
- * as offsets from the base IO region (dev->base_addr)
- */
-
-#define DATAPORT      0x0000
-#define WRITE_PTR     0x0002
-#define READ_PTR      0x0004
-#define SIGNAL_CA     0x0006
-#define SET_IRQ       0x0007
-#define SM_PTR        0x0008
-#define	MEM_Dec	      0x000a
-#define MEM_Ctrl      0x000b
-#define MEM_Page_Ctrl 0x000c
-#define Config        0x000d
-#define EEPROM_Ctrl   0x000e
-#define ID_PORT       0x000f
-#define	MEM_ECtrl     0x000f
-
-/*
- * card register defines
- */
-
-/* SET_IRQ */
-#define SIRQ_en       0x08
-#define SIRQ_dis      0x00
-
-/* EEPROM_Ctrl */
-#define EC_Clk        0x01
-#define EC_CS         0x02
-#define EC_Wr         0x04
-#define EC_Rd         0x08
-#define ASIC_RST      0x40
-#define i586_RST      0x80
-
-#define eeprom_delay() { udelay(40); }
-
-/*
- * i82586 Memory Configuration
- */
-
-/* (System Configuration Pointer) System start up block, read after 586_RST */
-#define SCP_START 0xfff6
-
-/* Intermediate System Configuration Pointer */
-#define ISCP_START 0x0000
-
-/* System Command Block */
-#define SCB_START 0x0008
-
-/* Start of buffer region.  Everything before this is used for control
- * structures and the CU configuration program.  The memory layout is
- * determined in eexp_hw_probe(), once we know how much memory is
- * available on the card.
- */
-
-#define TX_BUF_START 0x0100
-
-#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-
-/*
- * SCB defines
- */
-
-/* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) (((s) & 0x8000) != 0)
-#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
-#define SCB_CUdead(s)   (((s) & 0x2000) != 0)
-#define SCB_RUdead(s)   (((s) & 0x1000) != 0)
-#define SCB_ack(s)      ((s) & 0xf000)
-
-/* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s)   (((s)&0x0300)>>8)
-
-/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s)   (((s)&0x0070)>>4)
-
-/* SCB commands */
-#define SCB_CUnop       0x0000
-#define SCB_CUstart     0x0100
-#define SCB_CUresume    0x0200
-#define SCB_CUsuspend   0x0300
-#define SCB_CUabort     0x0400
-#define SCB_resetchip   0x0080
-
-#define SCB_RUnop       0x0000
-#define SCB_RUstart     0x0010
-#define SCB_RUresume    0x0020
-#define SCB_RUsuspend   0x0030
-#define SCB_RUabort     0x0040
-
-/*
- * Command block defines
- */
-
-#define Stat_Done(s)    (((s) & 0x8000) != 0)
-#define Stat_Busy(s)    (((s) & 0x4000) != 0)
-#define Stat_OK(s)      (((s) & 0x2000) != 0)
-#define Stat_Abort(s)   (((s) & 0x1000) != 0)
-#define Stat_STFail     (((s) & 0x0800) != 0)
-#define Stat_TNoCar(s)  (((s) & 0x0400) != 0)
-#define Stat_TNoCTS(s)  (((s) & 0x0200) != 0)
-#define Stat_TNoDMA(s)  (((s) & 0x0100) != 0)
-#define Stat_TDefer(s)  (((s) & 0x0080) != 0)
-#define Stat_TColl(s)   (((s) & 0x0040) != 0)
-#define Stat_TXColl(s)  (((s) & 0x0020) != 0)
-#define Stat_NoColl(s)  ((s) & 0x000f)
-
-/* Cmd_END will end AFTER the command if this is the first
- * command block after an SCB_CUstart, but BEFORE the command
- * for all subsequent commands. Best strategy is to place
- * Cmd_INT on the last command in the sequence, followed by a
- * dummy Cmd_Nop with Cmd_END after this.
- */
-
-#define Cmd_END     0x8000
-#define Cmd_SUS     0x4000
-#define Cmd_INT     0x2000
-
-#define Cmd_Nop     0x0000
-#define Cmd_SetAddr 0x0001
-#define Cmd_Config  0x0002
-#define Cmd_MCast   0x0003
-#define Cmd_Xmit    0x0004
-#define Cmd_TDR     0x0005
-#define Cmd_Dump    0x0006
-#define Cmd_Diag    0x0007
-
-
-/*
- * Frame Descriptor (Receive block) defines
- */
-
-#define FD_Done(s)  (((s) & 0x8000) != 0)
-#define FD_Busy(s)  (((s) & 0x4000) != 0)
-#define FD_OK(s)    (((s) & 0x2000) != 0)
-
-#define FD_CRC(s)   (((s) & 0x0800) != 0)
-#define FD_Align(s) (((s) & 0x0400) != 0)
-#define FD_Resrc(s) (((s) & 0x0200) != 0)
-#define FD_DMA(s)   (((s) & 0x0100) != 0)
-#define FD_Short(s) (((s) & 0x0080) != 0)
-#define FD_NoEOF(s) (((s) & 0x0040) != 0)
-
-struct rfd_header {
-	volatile unsigned long flags;
-	volatile unsigned short link;
-	volatile unsigned short rbd_offset;
-	volatile unsigned short dstaddr1;
-	volatile unsigned short dstaddr2;
-	volatile unsigned short dstaddr3;
-	volatile unsigned short srcaddr1;
-	volatile unsigned short srcaddr2;
-	volatile unsigned short srcaddr3;
-	volatile unsigned short length;
-
-	/* This is actually a Receive Buffer Descriptor.  The way we
-	 * arrange memory means that an RBD always follows the RFD that
-	 * points to it, so they might as well be in the same structure.
-	 */
-	volatile unsigned short actual_count;
-	volatile unsigned short next_rbd;
-	volatile unsigned short buf_addr1;
-	volatile unsigned short buf_addr2;
-	volatile unsigned short size;
-};
-
-/* Returned data from the Time Domain Reflectometer */
-
-#define TDR_LINKOK       (1<<15)
-#define TDR_XCVRPROBLEM  (1<<14)
-#define TDR_OPEN         (1<<13)
-#define TDR_SHORT        (1<<12)
-#define TDR_TIME         0x7ff
diff --git a/drivers/net/ethernet/i825xx/lp486e.c b/drivers/net/ethernet/i825xx/lp486e.c
deleted file mode 100644
index 3735bfa..0000000
--- a/drivers/net/ethernet/i825xx/lp486e.c
+++ /dev/null
@@ -1,1337 +0,0 @@
-/* Intel Professional Workstation/panther ethernet driver */
-/* lp486e.c: A panther 82596 ethernet driver for linux. */
-/*
-    History and copyrights:
-
-    Driver skeleton
-        Written 1993 by Donald Becker.
-        Copyright 1993 United States Government as represented by the Director,
-        National Security Agency.  This software may only be used and
-	distributed according to the terms of the GNU General Public License
-	as modified by SRC, incorporated herein by reference.
-
-        The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-    Apricot
-        Written 1994 by Mark Evans.
-        This driver is for the Apricot 82596 bus-master interface
-
-        Modularised 12/94 Mark Evans
-
-    Professional Workstation
-	Derived from apricot.c by Ard van Breemen
-	<ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
-
-	Credits:
-	Thanks to Murphy Software BV for letting me write this in their time.
-	Well, actually, I get paid doing this...
-	(Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
-	more information on the Professional Workstation)
-
-    Present version
-	aeb@cwi.nl
-*/
-/*
-    There are currently two motherboards that I know of in the
-    professional workstation. The only one that I know is the
-    intel panther motherboard. -- ard
-*/
-/*
-The pws is equipped with an intel 82596. This is a very intelligent controller
-which runs its own micro-code. Communication with the hostprocessor is done
-through linked lists of commands and buffers in the hostprocessors memory.
-A complete description of the 82596 is available from intel. Search for
-a file called "29021806.pdf". It is a complete description of the chip itself.
-To use it for the pws some additions are needed regarding generation of
-the PORT and CA signal, and the interrupt glue needed for a pc.
-I/O map:
-PORT  SIZE ACTION MEANING
-0xCB0    2 WRITE  Lower 16 bits for PORT command
-0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command
-0xCB4    1 WRITE  Generation of CA signal
-0xCB8    1 WRITE  Clear interrupt glue
-All other communication is through memory!
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "lp486e"
-
-/* debug print flags */
-#define LOG_SRCDST    0x80000000
-#define LOG_STATINT   0x40000000
-#define LOG_STARTINT  0x20000000
-
-#define i596_debug debug
-
-static int i596_debug = 0;
-
-static const char * const medianame[] = {
-	"10baseT", "AUI",
-	"10baseT-FD", "AUI-FD",
-};
-
-#define LP486E_TOTAL_SIZE 16
-
-#define I596_NULL (0xffffffff)
-
-#define CMD_EOL		0x8000	/* The last command of the list, stop. */
-#define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
-#define CMD_INTR	0x2000	/* Interrupt after doing cmd. */
-
-#define CMD_FLEX	0x0008	/* Enable flexible memory model */
-
-enum commands {
-	CmdNOP = 0,
-	CmdIASetup = 1,
-	CmdConfigure = 2,
-	CmdMulticastList = 3,
-	CmdTx = 4,
-	CmdTDR = 5,
-	CmdDump = 6,
-	CmdDiagnose = 7
-};
-
-#if 0
-static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
-				     "Tx", "TDR", "Dump", "Diagnose" };
-#endif
-
-/* Status word bits */
-#define	STAT_CX		0x8000	/* The CU finished executing a command
-				   with the Interrupt bit set */
-#define	STAT_FR		0x4000	/* The RU finished receiving a frame */
-#define	STAT_CNA	0x2000	/* The CU left the active state */
-#define	STAT_RNR	0x1000	/* The RU left the active state */
-#define STAT_ACK	(STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
-#define	STAT_CUS	0x0700	/* Status of CU: 0: idle, 1: suspended,
-				   2: active, 3-7: unused */
-#define STAT_RUS	0x00f0	/* Status of RU: 0: idle, 1: suspended,
-				   2: no resources, 4: ready,
-				   10: no resources due to no more RBDs,
-				   12: no more RBDs, other: unused */
-#define	STAT_T		0x0008	/* Bus throttle timers loaded */
-#define	STAT_ZERO	0x0807	/* Always zero */
-
-#if 0
-static char *CUstates[8] = {
-	"idle", "suspended", "active", 0, 0, 0, 0, 0
-};
-static char *RUstates[16] = {
-	"idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
-	0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
-};
-
-static void
-i596_out_status(int status) {
-	int bad = 0;
-	char *s;
-
-	printk("status %4.4x:", status);
-	if (status == 0xffff)
-		printk(" strange..\n");
-	else {
-		if (status & STAT_CX)
-			printk("  CU done");
-		if (status & STAT_CNA)
-			printk("  CU stopped");
-		if (status & STAT_FR)
-			printk("  got a frame");
-		if (status & STAT_RNR)
-			printk("  RU stopped");
-		if (status & STAT_T)
-			printk("  throttled");
-		if (status & STAT_ZERO)
-			bad = 1;
-		s = CUstates[(status & STAT_CUS) >> 8];
-		if (!s)
-			bad = 1;
-		else
-			printk("  CU(%s)", s);
-		s = RUstates[(status & STAT_RUS) >> 4];
-		if (!s)
-			bad = 1;
-		else
-			printk("  RU(%s)", s);
-		if (bad)
-			printk("  bad status");
-		printk("\n");
-	}
-}
-#endif
-
-/* Command word bits */
-#define ACK_CX		0x8000
-#define ACK_FR		0x4000
-#define ACK_CNA		0x2000
-#define ACK_RNR		0x1000
-
-#define CUC_START	0x0100
-#define CUC_RESUME	0x0200
-#define CUC_SUSPEND	0x0300
-#define CUC_ABORT	0x0400
-
-#define RX_START	0x0010
-#define RX_RESUME	0x0020
-#define RX_SUSPEND	0x0030
-#define RX_ABORT	0x0040
-
-typedef u32 phys_addr;
-
-static inline phys_addr
-va_to_pa(void *x) {
-	return x ? virt_to_bus(x) : I596_NULL;
-}
-
-static inline void *
-pa_to_va(phys_addr x) {
-	return (x == I596_NULL) ? NULL : bus_to_virt(x);
-}
-
-/* status bits for cmd */
-#define CMD_STAT_C	0x8000	/* CU command complete */
-#define CMD_STAT_B	0x4000	/* CU command in progress */
-#define CMD_STAT_OK	0x2000	/* CU command completed without errors */
-#define CMD_STAT_A	0x1000	/* CU command abnormally terminated */
-
-struct i596_cmd {		/* 8 bytes */
-	unsigned short status;
-	unsigned short command;
-	phys_addr pa_next;	/* va_to_pa(struct i596_cmd *next) */
-};
-
-#define EOF		0x8000
-#define SIZE_MASK	0x3fff
-
-struct i596_tbd {
-	unsigned short size;
-	unsigned short pad;
-	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */
-	phys_addr pa_data;	/* va_to_pa(char *data) */
-	struct sk_buff *skb;
-};
-
-struct tx_cmd {
-	struct i596_cmd cmd;
-	phys_addr pa_tbd;	/* va_to_pa(struct i596_tbd *tbd) */
-	unsigned short size;
-	unsigned short pad;
-};
-
-/* status bits for rfd */
-#define RFD_STAT_C	0x8000	/* Frame reception complete */
-#define RFD_STAT_B	0x4000	/* Frame reception in progress */
-#define RFD_STAT_OK	0x2000	/* Frame received without errors */
-#define RFD_STATUS	0x1fff
-#define RFD_LENGTH_ERR	0x1000
-#define RFD_CRC_ERR	0x0800
-#define RFD_ALIGN_ERR	0x0400
-#define RFD_NOBUFS_ERR	0x0200
-#define RFD_DMA_ERR	0x0100	/* DMA overrun failure to acquire system bus */
-#define RFD_SHORT_FRAME_ERR	0x0080
-#define RFD_NOEOP_ERR	0x0040
-#define RFD_TRUNC_ERR	0x0020
-#define RFD_MULTICAST  0x0002	/* 0: destination had our address
-				   1: destination was broadcast/multicast */
-#define RFD_COLLISION  0x0001
-
-/* receive frame descriptor */
-struct i596_rfd {
-	unsigned short stat;
-	unsigned short cmd;
-	phys_addr pa_next;	/* va_to_pa(struct i596_rfd *next) */
-	phys_addr pa_rbd;	/* va_to_pa(struct i596_rbd *rbd) */
-	unsigned short count;
-	unsigned short size;
-	char data[1532];
-};
-
-#define RBD_EL		0x8000
-#define RBD_P		0x4000
-#define RBD_SIZEMASK	0x3fff
-#define RBD_EOF		0x8000
-#define RBD_F		0x4000
-
-/* receive buffer descriptor */
-struct i596_rbd {
-	unsigned short size;
-	unsigned short pad;
-	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */
-	phys_addr pa_data;	/* va_to_pa(char *data) */
-	phys_addr pa_prev;	/* va_to_pa(struct i596_tbd *prev) */
-
-	/* Driver private part */
-	struct sk_buff *skb;
-};
-
-#define RX_RING_SIZE 64
-#define RX_SKBSIZE (ETH_FRAME_LEN+10)
-#define RX_RBD_SIZE 32
-
-/* System Control Block - 40 bytes */
-struct i596_scb {
-	u16 status;		/* 0 */
-	u16 command;		/* 2 */
-	phys_addr pa_cmd;	/* 4 - va_to_pa(struct i596_cmd *cmd) */
-	phys_addr pa_rfd;	/* 8 - va_to_pa(struct i596_rfd *rfd) */
-	u32 crc_err;		/* 12 */
-	u32 align_err;		/* 16 */
-	u32 resource_err;	/* 20 */
-	u32 over_err;		/* 24 */
-	u32 rcvdt_err;		/* 28 */
-	u32 short_err;		/* 32 */
-	u16 t_on;		/* 36 */
-	u16 t_off;		/* 38 */
-};
-
-/* Intermediate System Configuration Pointer - 8 bytes */
-struct i596_iscp {
-	u32 busy;		/* 0 */
-	phys_addr pa_scb;	/* 4 - va_to_pa(struct i596_scb *scb) */
-};
-
-/* System Configuration Pointer - 12 bytes */
-struct i596_scp {
-	u32 sysbus;		/* 0 */
-	u32 pad;		/* 4 */
-	phys_addr pa_iscp;	/* 8 - va_to_pa(struct i596_iscp *iscp) */
-};
-
-/* Selftest and dump results - needs 16-byte alignment */
-/*
- * The size of the dump area is 304 bytes. When the dump is executed
- * by the Port command an extra word will be appended to the dump area.
- * The extra word is a copy of the Dump status word (containing the
- * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
- */
-struct i596_dump {
-	u16 dump[153];		/* (304 = 130h) + 2 bytes */
-};
-
-struct i596_private {		/* aligned to a 16-byte boundary */
-	struct i596_scp scp;	/* 0 - needs 16-byte alignment */
-	struct i596_iscp iscp;	/* 12 */
-	struct i596_scb scb;	/* 20 */
-	u32 dummy;		/* 60 */
-	struct i596_dump dump;	/* 64 - needs 16-byte alignment */
-
-	struct i596_cmd set_add;
-	char eth_addr[8];	/* directly follows set_add */
-
-	struct i596_cmd set_conf;
-	char i596_config[16];	/* directly follows set_conf */
-
-	struct i596_cmd tdr;
-	unsigned long tdr_stat;	/* directly follows tdr */
-
-	int last_restart;
-	struct i596_rbd *rbd_list;
-	struct i596_rbd *rbd_tail;
-	struct i596_rfd *rx_tail;
-	struct i596_cmd *cmd_tail;
-	struct i596_cmd *cmd_head;
-	int cmd_backlog;
-	unsigned long last_cmd;
-	spinlock_t cmd_lock;
-};
-
-static char init_setup[14] = {
-	0x8E,	/* length 14 bytes, prefetch on */
-	0xC8,	/* default: fifo to 8, monitor off */
-	0x40,	/* default: don't save bad frames (apricot.c had 0x80) */
-	0x2E,	/* (default is 0x26)
-		   No source address insertion, 8 byte preamble */
-	0x00,	/* default priority and backoff */
-	0x60,	/* default interframe spacing */
-	0x00,	/* default slot time LSB */
-	0xf2,	/* default slot time and nr of retries */
-	0x00,	/* default various bits
-		   (0: promiscuous mode, 1: broadcast disable,
-		    2: encoding mode, 3: transmit on no CRS,
-		    4: no CRC insertion, 5: CRC type,
-		    6: bit stuffing, 7: padding) */
-	0x00,	/* default carrier sense and collision detect */
-	0x40,	/* default minimum frame length */
-	0xff,	/* (default is 0xff, and that is what apricot.c has;
-		   elp486.c has 0xfb: Enable crc append in memory.) */
-	0x00,	/* default: not full duplex */
-	0x7f	/* (default is 0x3f) multi IA */
-};
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct net_device *dev);
-static void i596_tx_timeout(struct net_device *dev);
-
-static int
-i596_timeout(struct net_device *dev, char *msg, int ct) {
-	struct i596_private *lp;
-	int boguscnt = ct;
-
-	lp = netdev_priv(dev);
-	while (lp->scb.command) {
-		if (--boguscnt == 0) {
-			printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
-			       dev->name, msg,
-			       lp->scb.status, lp->scb.command);
-			return 1;
-		}
-		udelay(5);
-		barrier();
-	}
-	return 0;
-}
-
-static inline int
-init_rx_bufs(struct net_device *dev, int num) {
-	struct i596_private *lp;
-	struct i596_rfd *rfd;
-	int i;
-	// struct i596_rbd *rbd;
-
-	lp = netdev_priv(dev);
-	lp->scb.pa_rfd = I596_NULL;
-
-	for (i = 0; i < num; i++) {
-		rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
-		if (rfd == NULL)
-			break;
-
-		rfd->stat = 0;
-		rfd->pa_rbd = I596_NULL;
-		rfd->count = 0;
-		rfd->size = 1532;
-		if (i == 0) {
-			rfd->cmd = CMD_EOL;
-			lp->rx_tail = rfd;
-		} else {
-			rfd->cmd = 0;
-		}
-		rfd->pa_next = lp->scb.pa_rfd;
-		lp->scb.pa_rfd = va_to_pa(rfd);
-		lp->rx_tail->pa_next = lp->scb.pa_rfd;
-	}
-
-#if 0
-	for (i = 0; i<RX_RBD_SIZE; i++) {
-		rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
-		if (rbd) {
-			rbd->pad = 0;
-			rbd->count = 0;
-			rbd->skb = dev_alloc_skb(RX_SKBSIZE);
-			if (!rbd->skb) {
-				printk("dev_alloc_skb failed");
-			}
-			rbd->next = rfd->rbd;
-			if (i) {
-				rfd->rbd->prev = rbd;
-				rbd->size = RX_SKBSIZE;
-			} else {
-				rbd->size = (RX_SKBSIZE | RBD_EL);
-				lp->rbd_tail = rbd;
-			}
-
-			rfd->rbd = rbd;
-		}
-	}
-	lp->rbd_tail->next = rfd->rbd;
-#endif
-	return i;
-}
-
-static inline void
-remove_rx_bufs(struct net_device *dev) {
-	struct i596_private *lp;
-	struct i596_rfd *rfd;
-
-	lp = netdev_priv(dev);
-	lp->rx_tail->pa_next = I596_NULL;
-
-	do {
-		rfd = pa_to_va(lp->scb.pa_rfd);
-		lp->scb.pa_rfd = rfd->pa_next;
-		kfree(rfd);
-	} while (rfd != lp->rx_tail);
-
-	lp->rx_tail = NULL;
-
-#if 0
-	for (lp->rbd_list) {
-	}
-#endif
-}
-
-#define PORT_RESET              0x00    /* reset 82596 */
-#define PORT_SELFTEST           0x01    /* selftest */
-#define PORT_ALTSCP             0x02    /* alternate SCB address */
-#define PORT_DUMP               0x03    /* dump */
-
-#define IOADDR	0xcb0		/* real constant */
-#define IRQ	10		/* default IRQ - can be changed by ECU */
-
-/* The 82596 requires two 16-bit write cycles for a port command */
-static inline void
-PORT(phys_addr a, unsigned int cmd) {
-	if (a & 0xf)
-		printk("lp486e.c: PORT: address not aligned\n");
-	outw(((a & 0xffff) | cmd), IOADDR);
-	outw(((a>>16) & 0xffff), IOADDR+2);
-}
-
-static inline void
-CA(void) {
-	outb(0, IOADDR+4);
-	udelay(8);
-}
-
-static inline void
-CLEAR_INT(void) {
-	outb(0, IOADDR+8);
-}
-
-#if 0
-/* selftest or dump */
-static void
-i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
-	struct i596_private *lp = netdev_priv(dev);
-	u16 *outp;
-	int i, m;
-
-	memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
-	outp = &(lp->dump.dump[0]);
-
-	PORT(va_to_pa(outp), portcmd);
-	mdelay(30);             /* random, unmotivated */
-
-	printk("lp486e i82596 %s result:\n", cmdname);
-	for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
-		;
-	for (i = 0; i < m; i++) {
-		printk(" %04x", lp->dump.dump[i]);
-		if (i%8 == 7)
-			printk("\n");
-	}
-	printk("\n");
-}
-#endif
-
-static int
-i596_scp_setup(struct net_device *dev) {
-	struct i596_private *lp = netdev_priv(dev);
-	int boguscnt;
-
-	/* Setup SCP, ISCP, SCB */
-	/*
-	 * sysbus bits:
-	 *  only a single byte is significant - here 0x44
-	 *  0x80: big endian mode (details depend on stepping)
-	 *  0x40: 1
-	 *  0x20: interrupt pin is active low
-	 *  0x10: lock function disabled
-	 *  0x08: external triggering of bus throttle timers
-	 *  0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
-	 *  0x01: unused
-	 */
-	lp->scp.sysbus = 0x00440000; 		/* linear mode */
-	lp->scp.pad = 0;			/* must be zero */
-	lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
-
-	/*
-	 * The CPU sets the ISCP to 1 before it gives the first CA()
-	 */
-	lp->iscp.busy = 0x0001;
-	lp->iscp.pa_scb = va_to_pa(&(lp->scb));
-
-	lp->scb.command = 0;
-	lp->scb.status = 0;
-	lp->scb.pa_cmd = I596_NULL;
-	/* lp->scb.pa_rfd has been initialised already */
-
-	lp->last_cmd = jiffies;
-	lp->cmd_backlog = 0;
-	lp->cmd_head = NULL;
-
-	/*
-	 * Reset the 82596.
-	 * We need to wait 10 systemclock cycles, and
-	 * 5 serial clock cycles.
-	 */
-	PORT(0, PORT_RESET);	/* address part ignored */
-	udelay(100);
-
-	/*
-	 * Before the CA signal is asserted, the default SCP address
-	 * (0x00fffff4) can be changed to a 16-byte aligned value
-	 */
-	PORT(va_to_pa(&lp->scp), PORT_ALTSCP);	/* change the scp address */
-
-	/*
-	 * The initialization procedure begins when a
-	 * Channel Attention signal is asserted after a reset.
-	 */
-
-	CA();
-
-	/*
-	 * The ISCP busy is cleared by the 82596 after the SCB address is read.
-	 */
-	boguscnt = 100;
-	while (lp->iscp.busy) {
-		if (--boguscnt == 0) {
-			/* No i82596 present? */
-			printk("%s: i82596 initialization timed out\n",
-			       dev->name);
-			return 1;
-		}
-		udelay(5);
-		barrier();
-	}
-	/* I find here boguscnt==100, so no delay was required. */
-
-	return 0;
-}
-
-static int
-init_i596(struct net_device *dev) {
-	struct i596_private *lp;
-
-	if (i596_scp_setup(dev))
-		return 1;
-
-	lp = netdev_priv(dev);
-	lp->scb.command = 0;
-
-	memcpy ((void *)lp->i596_config, init_setup, 14);
-	lp->set_conf.command = CmdConfigure;
-	i596_add_cmd(dev, (void *)&lp->set_conf);
-
-	memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
-	lp->set_add.command = CmdIASetup;
-	i596_add_cmd(dev, &lp->set_add);
-
-	lp->tdr.command = CmdTDR;
-	i596_add_cmd(dev, &lp->tdr);
-
-	if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
-		return 1;
-
-	lp->scb.command = RX_START;
-	CA();
-
-	barrier();
-
-	if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
-		return 1;
-
-	return 0;
-}
-
-/* Receive a single frame */
-static inline int
-i596_rx_one(struct net_device *dev, struct i596_private *lp,
-	    struct i596_rfd *rfd, int *frames) {
-
-	if (rfd->stat & RFD_STAT_OK) {
-		/* a good frame */
-		int pkt_len = (rfd->count & 0x3fff);
-		struct sk_buff *skb = netdev_alloc_skb(dev, pkt_len);
-
-		(*frames)++;
-
-		if (rfd->cmd & CMD_EOL)
-			printk("Received on EOL\n");
-
-		if (skb == NULL) {
-			printk ("%s: i596_rx Memory squeeze, "
-				"dropping packet.\n", dev->name);
-			dev->stats.rx_dropped++;
-			return 1;
-		}
-
-		memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
-
-		skb->protocol = eth_type_trans(skb,dev);
-		netif_rx(skb);
-		dev->stats.rx_packets++;
-	} else {
-#if 0
-		printk("Frame reception error status %04x\n",
-		       rfd->stat);
-#endif
-		dev->stats.rx_errors++;
-		if (rfd->stat & RFD_COLLISION)
-			dev->stats.collisions++;
-		if (rfd->stat & RFD_SHORT_FRAME_ERR)
-			dev->stats.rx_length_errors++;
-		if (rfd->stat & RFD_DMA_ERR)
-			dev->stats.rx_over_errors++;
-		if (rfd->stat & RFD_NOBUFS_ERR)
-			dev->stats.rx_fifo_errors++;
-		if (rfd->stat & RFD_ALIGN_ERR)
-			dev->stats.rx_frame_errors++;
-		if (rfd->stat & RFD_CRC_ERR)
-			dev->stats.rx_crc_errors++;
-		if (rfd->stat & RFD_LENGTH_ERR)
-			dev->stats.rx_length_errors++;
-	}
-	rfd->stat = rfd->count = 0;
-	return 0;
-}
-
-static int
-i596_rx(struct net_device *dev) {
-	struct i596_private *lp = netdev_priv(dev);
-	struct i596_rfd *rfd;
-	int frames = 0;
-
-	while (1) {
-		rfd = pa_to_va(lp->scb.pa_rfd);
-		if (!rfd) {
-			printk(KERN_ERR "i596_rx: NULL rfd?\n");
-			return 0;
-		}
-#if 1
-		if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
-			printk("SF:%p-%04x\n", rfd, rfd->stat);
-#endif
-		if (!(rfd->stat & RFD_STAT_C))
-			break;		/* next one not ready */
-		if (i596_rx_one(dev, lp, rfd, &frames))
-			break;		/* out of memory */
-		rfd->cmd = CMD_EOL;
-		lp->rx_tail->cmd = 0;
-		lp->rx_tail = rfd;
-		lp->scb.pa_rfd = rfd->pa_next;
-		barrier();
-	}
-
-	return frames;
-}
-
-static void
-i596_cleanup_cmd(struct net_device *dev) {
-	struct i596_private *lp;
-	struct i596_cmd *cmd;
-
-	lp = netdev_priv(dev);
-	while (lp->cmd_head) {
-		cmd = lp->cmd_head;
-
-		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
-		lp->cmd_backlog--;
-
-		switch ((cmd->command) & 0x7) {
-			case CmdTx: {
-				struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
-				struct i596_tbd * tx_cmd_tbd;
-				tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
-				dev_kfree_skb_any(tx_cmd_tbd->skb);
-
-				dev->stats.tx_errors++;
-				dev->stats.tx_aborted_errors++;
-
-				cmd->pa_next = I596_NULL;
-				kfree((unsigned char *)tx_cmd);
-				netif_wake_queue(dev);
-				break;
-			}
-			case CmdMulticastList: {
-				// unsigned short count = *((unsigned short *) (ptr + 1));
-
-				cmd->pa_next = I596_NULL;
-				kfree((unsigned char *)cmd);
-				break;
-			}
-			default: {
-				cmd->pa_next = I596_NULL;
-				break;
-			}
-		}
-		barrier();
-	}
-
-	if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
-		;
-
-	lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
-
-	if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
-		;
-
-	netif_stop_queue(dev);
-
-	lp->scb.command = CUC_ABORT | RX_ABORT;
-	CA();
-	barrier();
-
-	/* wait for shutdown */
-	if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
-		;
-
-	i596_cleanup_cmd(dev);
-	i596_rx(dev);
-
-	netif_start_queue(dev);
-	/*dev_kfree_skb(skb, FREE_WRITE);*/
-	init_i596(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
-	struct i596_private *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	cmd->status = 0;
-	cmd->command |= (CMD_EOL | CMD_INTR);
-	cmd->pa_next = I596_NULL;
-
-	spin_lock_irqsave(&lp->cmd_lock, flags);
-
-	if (lp->cmd_head) {
-		lp->cmd_tail->pa_next = va_to_pa(cmd);
-	} else {
-		lp->cmd_head = cmd;
-		if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
-			;
-		lp->scb.pa_cmd = va_to_pa(cmd);
-		lp->scb.command = CUC_START;
-		CA();
-	}
-	lp->cmd_tail = cmd;
-	lp->cmd_backlog++;
-
-	lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
-	spin_unlock_irqrestore(&lp->cmd_lock, flags);
-
-	if (lp->cmd_backlog > 16) {
-		int tickssofar = jiffies - lp->last_cmd;
-		if (tickssofar < HZ/4)
-			return;
-
-		printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
-		i596_reset(dev, lp, ioaddr);
-	}
-}
-
-static int i596_open(struct net_device *dev)
-{
-	int i;
-
-	i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
-	if (i) {
-		printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
-		return i;
-	}
-
-	if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
-		printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
-
-	if (i < 4) {
-		free_irq(dev->irq, dev);
-		return -EAGAIN;
-	}
-	netif_start_queue(dev);
-	init_i596(dev);
-	return 0;			/* Always succeed */
-}
-
-static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
-	struct tx_cmd *tx_cmd;
-	short length;
-
-	length = skb->len;
-
-	if (length < ETH_ZLEN) {
-		if (skb_padto(skb, ETH_ZLEN))
-			return NETDEV_TX_OK;
-		length = ETH_ZLEN;
-	}
-
-	tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
-	if (tx_cmd == NULL) {
-		printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
-		dev->stats.tx_dropped++;
-		dev_kfree_skb (skb);
-	} else {
-		struct i596_tbd *tx_cmd_tbd;
-		tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
-		tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
-		tx_cmd_tbd->pa_next = I596_NULL;
-
-		tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
-
-		tx_cmd->pad = 0;
-		tx_cmd->size = 0;
-		tx_cmd_tbd->pad = 0;
-		tx_cmd_tbd->size = (EOF | length);
-
-		tx_cmd_tbd->pa_data = va_to_pa (skb->data);
-		tx_cmd_tbd->skb = skb;
-
-		if (i596_debug & LOG_SRCDST)
-			print_eth (skb->data);
-
-		i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
-
-		dev->stats.tx_packets++;
-	}
-
-	return NETDEV_TX_OK;
-}
-
-static void
-i596_tx_timeout (struct net_device *dev) {
-	struct i596_private *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	/* Transmitter timeout, serious problems. */
-	printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
-	dev->stats.tx_errors++;
-
-	/* Try to restart the adaptor */
-	if (lp->last_restart == dev->stats.tx_packets) {
-		printk ("Resetting board.\n");
-
-		/* Shutdown and restart */
-		i596_reset (dev, lp, ioaddr);
-	} else {
-		/* Issue a channel attention signal */
-		printk ("Kicking board.\n");
-		lp->scb.command = (CUC_START | RX_START);
-		CA();
-		lp->last_restart = dev->stats.tx_packets;
-	}
-	netif_wake_queue(dev);
-}
-
-static void print_eth(char *add)
-{
-	int i;
-
-	printk ("Dest  ");
-	for (i = 0; i < 6; i++)
-		printk(" %2.2X", (unsigned char) add[i]);
-	printk ("\n");
-
-	printk ("Source");
-	for (i = 0; i < 6; i++)
-		printk(" %2.2X", (unsigned char) add[i+6]);
-	printk ("\n");
-
-	printk ("type %2.2X%2.2X\n",
-		(unsigned char) add[12], (unsigned char) add[13]);
-}
-
-static const struct net_device_ops i596_netdev_ops = {
-	.ndo_open		= i596_open,
-	.ndo_stop		= i596_close,
-	.ndo_start_xmit		= i596_start_xmit,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_tx_timeout		= i596_tx_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init lp486e_probe(struct net_device *dev) {
-	struct i596_private *lp;
-	unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
-	unsigned char *bios;
-	int i, j;
-	int ret = -ENOMEM;
-	static int probed;
-
-	if (probed)
-		return -ENODEV;
-	probed++;
-
-	if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
-		printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
-		return -EBUSY;
-	}
-
-	lp = netdev_priv(dev);
-	spin_lock_init(&lp->cmd_lock);
-
-	/*
-	 * Do we really have this thing?
-	 */
-	if (i596_scp_setup(dev)) {
-		ret = -ENODEV;
-		goto err_out_kfree;
-	}
-
-	dev->base_addr = IOADDR;
-	dev->irq = IRQ;
-
-
-	/*
-	 * How do we find the ethernet address? I don't know.
-	 * One possibility is to look at the EISA configuration area
-	 * [0xe8000-0xe9fff]. This contains the ethernet address
-	 * but not at a fixed address - things depend on setup options.
-	 *
-	 * If we find no address, or the wrong address, use
-	 *   ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
-	 * with the value found in the BIOS setup.
-	 */
-	bios = bus_to_virt(0xe8000);
-	for (j = 0; j < 0x2000; j++) {
-		if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
-			printk("%s: maybe address at BIOS 0x%x:",
-			       dev->name, 0xe8000+j);
-			for (i = 0; i < 6; i++) {
-				eth_addr[i] = bios[i+j];
-				printk(" %2.2X", eth_addr[i]);
-			}
-			printk("\n");
-		}
-	}
-
-	printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
-	       dev->name, dev->base_addr, dev->irq);
-	for (i = 0; i < 6; i++)
-		printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
-	printk("\n");
-
-	/* The LP486E-specific entries in the device structure. */
-	dev->netdev_ops = &i596_netdev_ops;
-	dev->watchdog_timeo = 5*HZ;
-
-#if 0
-	/* selftest reports 0x320925ae - don't know what that means */
-	i596_port_do(dev, PORT_SELFTEST, "selftest");
-	i596_port_do(dev, PORT_DUMP, "dump");
-#endif
-	return 0;
-
-err_out_kfree:
-	release_region(IOADDR, LP486E_TOTAL_SIZE);
-	return ret;
-}
-
-static inline void
-i596_handle_CU_completion(struct net_device *dev,
-			  struct i596_private *lp,
-			  unsigned short status,
-			  unsigned short *ack_cmdp) {
-	struct i596_cmd *cmd;
-	int frames_out = 0;
-	int commands_done = 0;
-	int cmd_val;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->cmd_lock, flags);
-	cmd = lp->cmd_head;
-
-	while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
-		cmd = lp->cmd_head;
-
-		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
-		lp->cmd_backlog--;
-
-		commands_done++;
-		cmd_val = cmd->command & 0x7;
-#if 0
-		printk("finished CU %s command (%d)\n",
-		       CUcmdnames[cmd_val], cmd_val);
-#endif
-		switch (cmd_val) {
-		case CmdTx:
-		{
-			struct tx_cmd *tx_cmd;
-			struct i596_tbd *tx_cmd_tbd;
-
-			tx_cmd = (struct tx_cmd *) cmd;
-			tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
-			frames_out++;
-			if (cmd->status & CMD_STAT_OK) {
-				if (i596_debug)
-					print_eth(pa_to_va(tx_cmd_tbd->pa_data));
-			} else {
-				dev->stats.tx_errors++;
-				if (i596_debug)
-					printk("transmission failure:%04x\n",
-					       cmd->status);
-				if (cmd->status & 0x0020)
-					dev->stats.collisions++;
-				if (!(cmd->status & 0x0040))
-					dev->stats.tx_heartbeat_errors++;
-				if (cmd->status & 0x0400)
-					dev->stats.tx_carrier_errors++;
-				if (cmd->status & 0x0800)
-					dev->stats.collisions++;
-				if (cmd->status & 0x1000)
-					dev->stats.tx_aborted_errors++;
-			}
-			dev_kfree_skb_irq(tx_cmd_tbd->skb);
-
-			cmd->pa_next = I596_NULL;
-			kfree((unsigned char *)tx_cmd);
-			netif_wake_queue(dev);
-			break;
-		}
-
-		case CmdMulticastList:
-			cmd->pa_next = I596_NULL;
-			kfree((unsigned char *)cmd);
-			break;
-
-		case CmdTDR:
-		{
-			unsigned long status = *((unsigned long *) (cmd + 1));
-			if (status & 0x8000) {
-				if (i596_debug)
-					printk("%s: link ok.\n", dev->name);
-			} else {
-				if (status & 0x4000)
-					printk("%s: Transceiver problem.\n",
-					       dev->name);
-				if (status & 0x2000)
-					printk("%s: Termination problem.\n",
-					       dev->name);
-				if (status & 0x1000)
-					printk("%s: Short circuit.\n",
-					       dev->name);
-				printk("%s: Time %ld.\n",
-				       dev->name, status & 0x07ff);
-			}
-		}
-		default:
-			cmd->pa_next = I596_NULL;
-			lp->last_cmd = jiffies;
-
-		}
-		barrier();
-	}
-
-	cmd = lp->cmd_head;
-	while (cmd && (cmd != lp->cmd_tail)) {
-		cmd->command &= 0x1fff;
-		cmd = pa_to_va(cmd->pa_next);
-		barrier();
-	}
-
-	if (lp->cmd_head)
-		*ack_cmdp |= CUC_START;
-	lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-	spin_unlock_irqrestore(&lp->cmd_lock, flags);
-}
-
-static irqreturn_t
-i596_interrupt(int irq, void *dev_instance)
-{
-	struct net_device *dev = dev_instance;
-	struct i596_private *lp = netdev_priv(dev);
-	unsigned short status, ack_cmd = 0;
-	int frames_in = 0;
-
-	/*
-	 * The 82596 examines the command, performs the required action,
-	 * and then clears the SCB command word.
-	 */
-	if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
-		;
-
-	/*
-	 * The status word indicates the status of the 82596.
-	 * It is modified only by the 82596.
-	 *
-	 * [So, we must not clear it. I find often status 0xffff,
-	 *  which is not one of the values allowed by the docs.]
-	 */
-	status = lp->scb.status;
-#if 0
-	if (i596_debug) {
-		printk("%s: i596 interrupt, ", dev->name);
-		i596_out_status(status);
-	}
-#endif
-	/* Impossible, but it happens - perhaps when we get
-	   a receive interrupt but scb.pa_rfd is I596_NULL. */
-	if (status == 0xffff) {
-		printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
-		goto out;
-	}
-
-	ack_cmd = (status & STAT_ACK);
-
-	if (status & (STAT_CX | STAT_CNA))
-		i596_handle_CU_completion(dev, lp, status, &ack_cmd);
-
-	if (status & (STAT_FR | STAT_RNR)) {
-		/* Restart the receive unit when it got inactive somehow */
-		if ((status & STAT_RNR) && netif_running(dev))
-			ack_cmd |= RX_START;
-
-		if (status & STAT_FR) {
-			frames_in = i596_rx(dev);
-			if (!frames_in)
-				printk("receive frame reported, but no frames\n");
-		}
-	}
-
-	/* acknowledge the interrupt */
-	/*
-	if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
-		ack_cmd |= CUC_START;
-	*/
-
-	if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
-		;
-
-	lp->scb.command = ack_cmd;
-
-	CLEAR_INT();
-	CA();
-
- out:
-	return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev) {
-	struct i596_private *lp = netdev_priv(dev);
-
-	netif_stop_queue(dev);
-
-	if (i596_debug)
-		printk("%s: Shutting down ethercard, status was %4.4x.\n",
-		       dev->name, lp->scb.status);
-
-	lp->scb.command = (CUC_ABORT | RX_ABORT);
-	CA();
-
-	i596_cleanup_cmd(dev);
-
-	if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
-		;
-
-	free_irq(dev->irq, dev);
-	remove_rx_bufs(dev);
-
-	return 0;
-}
-
-/*
-*	Set or clear the multicast filter for this adaptor.
-*/
-
-static void set_multicast_list(struct net_device *dev) {
-	struct i596_private *lp = netdev_priv(dev);
-	struct i596_cmd *cmd;
-
-	if (i596_debug > 1)
-		printk ("%s: set multicast list %d\n",
-			dev->name, netdev_mc_count(dev));
-
-	if (!netdev_mc_empty(dev)) {
-		struct netdev_hw_addr *ha;
-		char *cp;
-		cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
-			      netdev_mc_count(dev) * 6, GFP_ATOMIC);
-		if (cmd == NULL) {
-			printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
-			return;
-		}
-		cmd->command = CmdMulticastList;
-		*((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
-		cp = ((char *)(cmd + 1))+2;
-		netdev_for_each_mc_addr(ha, dev) {
-			memcpy(cp, ha->addr, 6);
-			cp += 6;
-		}
-		if (i596_debug & LOG_SRCDST)
-			print_eth (((char *)(cmd + 1)) + 2);
-		i596_add_cmd(dev, cmd);
-	} else {
-		if (lp->set_conf.pa_next != I596_NULL) {
-			return;
-		}
-		if (netdev_mc_empty(dev) &&
-		    !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
-			lp->i596_config[8] &= ~0x01;
-		} else {
-			lp->i596_config[8] |= 0x01;
-		}
-
-		i596_add_cmd(dev, &lp->set_conf);
-	}
-}
-
-MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
-MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
-MODULE_LICENSE("GPL");
-
-static struct net_device *dev_lp486e;
-static int full_duplex;
-static int options;
-static int io = IOADDR;
-static int irq = IRQ;
-
-module_param(debug, int, 0);
-//module_param(max_interrupt_work, int, 0);
-//module_param(reverse_probe, int, 0);
-//module_param(rx_copybreak, int, 0);
-module_param(options, int, 0);
-module_param(full_duplex, int, 0);
-
-static int __init lp486e_init_module(void) {
-	int err;
-	struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
-	if (!dev)
-		return -ENOMEM;
-
-	dev->irq = irq;
-	dev->base_addr = io;
-	err = lp486e_probe(dev);
-	if (err) {
-		free_netdev(dev);
-		return err;
-	}
-	err = register_netdev(dev);
-	if (err) {
-		release_region(dev->base_addr, LP486E_TOTAL_SIZE);
-		free_netdev(dev);
-		return err;
-	}
-	dev_lp486e = dev;
-	full_duplex = 0;
-	options = 0;
-	return 0;
-}
-
-static void __exit lp486e_cleanup_module(void) {
-	unregister_netdev(dev_lp486e);
-	release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
-	free_netdev(dev_lp486e);
-}
-
-module_init(lp486e_init_module);
-module_exit(lp486e_cleanup_module);
diff --git a/drivers/net/ethernet/i825xx/ni52.c b/drivers/net/ethernet/i825xx/ni52.c
deleted file mode 100644
index 272976e..0000000
--- a/drivers/net/ethernet/i825xx/ni52.c
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- *    [feel free to mail ....]
- *
- * when using as module: (no autoprobing!)
- *   run with e.g:
- *       insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
- *
- * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
- *
- * If you find a bug, please report me:
- *   The kernel panic output and any kmsg from the ni52 driver
- *   the ni5210-driver-version and the linux-kernel version
- *   how many shared memory (memsize) on the netcard,
- *   bootprom: yes/no, base_addr, mem_start
- *   maybe the ni5210-card revision and the i82586 version
- *
- * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
- *                mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
- *                           0xd8000,0xcc000,0xce000,0xda000,0xdc000
- *
- * sources:
- *   skeleton.c from Donald Becker
- *
- * I have also done a look in the following sources: (mail me if you need them)
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's (fourth) i82586-driver for BSD
- *   (before getting an i82596 (yes 596 not 586) manual, the existing drivers
- *    helped me a lot to understand this tricky chip.)
- *
- * Known Problems:
- *   The internal sysbus seems to be slow. So we often lose packets because of
- *   overruns while receiving from a fast remote host.
- *   This can slow down TCP connections. Maybe the newer ni5210 cards are
- *   better. My experience is, that if a machine sends with more than about
- *   500-600K/s the fifo/sysbus overflows.
- *
- * IMPORTANT NOTE:
- *   On fast networks, it's a (very) good idea to have 16K shared memory. With
- *   8K, we can store only 4 receive frames, so it can (easily) happen that a
- *   remote machine 'overruns' our system.
- *
- * Known i82586/card problems (I'm sure, there are many more!):
- *   Running the NOP-mode, the i82586 sometimes seems to forget to report
- *   every xmit-interrupt until we restart the CU.
- *   Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
- *   in the RBD-Struct which indicates an end of the RBD queue.
- *   Instead, the RU fetches another (randomly selected and
- *   usually used) RBD and begins to fill it. (Maybe, this happens only if
- *   the last buffer from the previous RFD fits exact into the queue and
- *   the next RFD can't fetch an initial RBD. Anyone knows more? )
- *
- * results from ftp performance tests with Linux 1.2.5
- *   send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
- *   sending in NOP-mode: peak performance up to 530K/s (but better don't
- *   run this mode)
- */
-
-/*
- * 29.Sept.96: virt_to_bus changes for new memory scheme
- * 19.Feb.96: more Mcast changes, module support (MH)
- *
- * 18.Nov.95: Mcast changes (AC).
- *
- * 23.April.95: fixed(?) receiving problems by configuring a RFD more
- *              than the number of RBD's. Can maybe cause other problems.
- * 18.April.95: Added MODULE support (MH)
- * 17.April.95: MC related changes in init586() and set_multicast_list().
- *              removed use of 'jiffies' in init586() (MH)
- *
- * 19.Sep.94: Added Multicast support (not tested yet) (MH)
- *
- * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
- *            Now, every RFD has exact one RBD. (MH)
- *
- * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
- *
- * 19.Aug.94: changed request_irq() parameter (MH)
- *
- * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
- *
- * 19.July.94: lotsa cleanups .. (MH)
- *
- * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
- *
- * 4.July.94: patches for Linux 1.1.24  (MH)
- *
- * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
- *
- * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
- *				too (MH)
- *
- * < 30.Sep.93: first versions
- */
-
-static int debuglevel;	/* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume; /* experimental .. better should be zero */
-static int rfdadd;	/* rfdadd=1 may be better for 8K MEM cards */
-static int fifo = 0x8;	/* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni52.h"
-
-#define DRV_NAME "ni52"
-
-#define DEBUG       /* debug on */
-#define SYSBUSVAL 1 /* 8 Bit */
-
-#define ni_attn586()  { outb(0, dev->base_addr + NI52_ATTENTION); }
-#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
-#define ni_disint()   { outb(0, dev->base_addr + NI52_INTDIS); }
-#define ni_enaint()   { outb(0, dev->base_addr + NI52_INTENA); }
-
-#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
-#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
-#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
-					- p->memtop))
-
-/******************* how to calculate the buffers *****************************
-
-  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
-  * --------------- in a different (more stable?) mode. Only in this mode it's
-  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
-  * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1524 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1    /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8  4 /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
-#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-
-#define NI52_TOTAL_SIZE 16
-#define NI52_ADDR0 0x02
-#define NI52_ADDR1 0x07
-#define NI52_ADDR2 0x01
-
-static int     ni52_probe1(struct net_device *dev, int ioaddr);
-static irqreturn_t ni52_interrupt(int irq, void *dev_id);
-static int     ni52_open(struct net_device *dev);
-static int     ni52_close(struct net_device *dev);
-static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
-static struct  net_device_stats *ni52_get_stats(struct net_device *dev);
-static void    set_multicast_list(struct net_device *dev);
-static void    ni52_timeout(struct net_device *dev);
-
-/* helper-functions */
-static int     init586(struct net_device *dev);
-static int     check586(struct net_device *dev, unsigned size);
-static void    alloc586(struct net_device *dev);
-static void    startrecv586(struct net_device *dev);
-static void   __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
-static void    ni52_rcv_int(struct net_device *dev);
-static void    ni52_xmt_int(struct net_device *dev);
-static void    ni52_rnr_int(struct net_device *dev);
-
-struct priv {
-	char __iomem *base;
-	char __iomem *mapped;
-	char __iomem *memtop;
-	spinlock_t spinlock;
-	int reset;
-	struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
-	struct scp_struct __iomem *scp;
-	struct iscp_struct __iomem *iscp;
-	struct scb_struct __iomem *scb;
-	struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
-	struct transmit_cmd_struct __iomem *xmit_cmds[2];
-	struct nop_cmd_struct __iomem *nop_cmds[2];
-#else
-	struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
-	struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
-#endif
-	int nop_point, num_recv_buffs;
-	char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
-	int xmit_count, xmit_last;
-};
-
-/* wait for command with timeout: */
-static void wait_for_scb_cmd(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-	int i;
-	for (i = 0; i < 16384; i++) {
-		if (readb(&p->scb->cmd_cuc) == 0)
-		      break;
-		udelay(4);
-		if (i == 16383) {
-			printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
-				dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
-			if (!p->reset) {
-				p->reset = 1;
-				ni_reset586();
-			}
-		}
-	}
-}
-
-static void wait_for_scb_cmd_ruc(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-	int i;
-	for (i = 0; i < 16384; i++) {
-		if (readb(&p->scb->cmd_ruc) == 0)
-			break;
-		udelay(4);
-		if (i == 16383) {
-			printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
-				dev->name, readb(&p->scb->cmd_ruc),
-				readb(&p->scb->rus));
-			if (!p->reset) {
-				p->reset = 1;
-				ni_reset586();
-			}
-		}
-	}
-}
-
-static void wait_for_stat_compl(void __iomem *p)
-{
-	struct nop_cmd_struct __iomem *addr = p;
-	int i;
-	for (i = 0; i < 32767; i++) {
-		if (readw(&((addr)->cmd_status)) & STAT_COMPL)
-			break;
-		udelay(32);
-	}
-}
-
-/**********************************************
- * close device
- */
-static int ni52_close(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	ni_reset586(); /* the hard way to stop the receiver */
-	netif_stop_queue(dev);
-	return 0;
-}
-
-/**********************************************
- * open device
- */
-static int ni52_open(struct net_device *dev)
-{
-	int ret;
-
-	ni_disint();
-	alloc586(dev);
-	init586(dev);
-	startrecv586(dev);
-	ni_enaint();
-
-	ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
-	if (ret) {
-		ni_reset586();
-		return ret;
-	}
-	netif_start_queue(dev);
-	return 0; /* most done by init */
-}
-
-static int check_iscp(struct net_device *dev, void __iomem *addr)
-{
-	struct iscp_struct __iomem *iscp = addr;
-	struct priv *p = netdev_priv(dev);
-	memset_io(iscp, 0, sizeof(struct iscp_struct));
-
-	writel(make24(iscp), &p->scp->iscp);
-	writeb(1, &iscp->busy);
-
-	ni_reset586();
-	ni_attn586();
-	mdelay(32);	/* wait a while... */
-	/* i82586 clears 'busy' after successful init */
-	if (readb(&iscp->busy))
-		return 0;
-	return 1;
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev, unsigned size)
-{
-	struct priv *p = netdev_priv(dev);
-	int i;
-
-	p->mapped = ioremap(dev->mem_start, size);
-	if (!p->mapped)
-		return 0;
-
-	p->base = p->mapped + size - 0x01000000;
-	p->memtop = p->mapped + size;
-	p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
-	p->scb	= (struct scb_struct __iomem *)	p->mapped;
-	p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
-	memset_io(p->scp, 0, sizeof(struct scp_struct));
-	for (i = 0; i < sizeof(struct scp_struct); i++)
-		/* memory was writeable? */
-		if (readb((char __iomem *)p->scp + i))
-			goto Enodev;
-	writeb(SYSBUSVAL, &p->scp->sysbus);	/* 1 = 8Bit-Bus, 0 = 16 Bit */
-	if (readb(&p->scp->sysbus) != SYSBUSVAL)
-		goto Enodev;
-
-	if (!check_iscp(dev, p->mapped))
-		goto Enodev;
-	if (!check_iscp(dev, p->iscp))
-		goto Enodev;
-	return 1;
-Enodev:
-	iounmap(p->mapped);
-	return 0;
-}
-
-/******************************************************************
- * set iscp at the right place, called by ni52_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-
-	ni_reset586();
-	mdelay(32);
-
-	memset_io(p->iscp, 0, sizeof(struct iscp_struct));
-	memset_io(p->scp , 0, sizeof(struct scp_struct));
-
-	writel(make24(p->iscp), &p->scp->iscp);
-	writeb(SYSBUSVAL, &p->scp->sysbus);
-	writew(make16(p->scb), &p->iscp->scb_offset);
-
-	writeb(1, &p->iscp->busy);
-	ni_reset586();
-	ni_attn586();
-
-	mdelay(32);
-
-	if (readb(&p->iscp->busy))
-		printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
-
-	p->reset = 0;
-
-	memset_io(p->scb, 0, sizeof(struct scb_struct));
-}
-
-/* set: io,irq,memstart,memend or set it when calling insmod */
-static int irq = 9;
-static int io = 0x300;
-static long memstart;	/* e.g 0xd0000 */
-static long memend;	/* e.g 0xd4000 */
-
-/**********************************************
- * probe the ni5210-card
- */
-struct net_device * __init ni52_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct priv));
-	static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
-	const int *port;
-	struct priv *p;
-	int err = 0;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	p = netdev_priv(dev);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-		memstart = dev->mem_start;
-		memend = dev->mem_end;
-	}
-
-	if (io > 0x1ff)	{	/* Check a single specified location. */
-		err = ni52_probe1(dev, io);
-	} else if (io > 0) {		/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
-			;
-		if (*port)
-			goto got_it;
-#ifdef FULL_IO_PROBE
-		for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
-			;
-		if (io < 0x400)
-			goto got_it;
-#endif
-		err = -ENODEV;
-	}
-	if (err)
-		goto out;
-got_it:
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	iounmap(p->mapped);
-	release_region(dev->base_addr, NI52_TOTAL_SIZE);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static const struct net_device_ops ni52_netdev_ops = {
-	.ndo_open		= ni52_open,
-	.ndo_stop		= ni52_close,
-	.ndo_get_stats		= ni52_get_stats,
-	.ndo_tx_timeout 	= ni52_timeout,
-	.ndo_start_xmit 	= ni52_send_packet,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init ni52_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, size, retval;
-	struct priv *priv = netdev_priv(dev);
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->mem_start = memstart;
-	dev->mem_end = memend;
-
-	spin_lock_init(&priv->spinlock);
-
-	if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
-		return -EBUSY;
-
-	if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
-	    !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[i] = inb(dev->base_addr+i);
-
-	if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
-	    dev->dev_addr[2] != NI52_ADDR2) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
-				dev->name, dev->base_addr);
-
-	/*
-	 * check (or search) IO-Memory, 8K and 16K
-	 */
-#ifdef MODULE
-	size = dev->mem_end - dev->mem_start;
-	if (size != 0x2000 && size != 0x4000) {
-		printk("\n");
-		printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
-		retval = -ENODEV;
-		goto out;
-	}
-	if (!check586(dev, size)) {
-		printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
-		retval = -ENODEV;
-		goto out;
-	}
-#else
-	if (dev->mem_start != 0) {
-		/* no auto-mem-probe */
-		size = 0x4000; /* check for 16K mem */
-		if (!check586(dev, size)) {
-			size = 0x2000; /* check for 8K mem */
-			if (!check586(dev, size)) {
-				printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
-				retval = -ENODEV;
-				goto out;
-			}
-		}
-	} else {
-		static const unsigned long memaddrs[] = {
-			0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
-			0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
-		};
-		for (i = 0;; i++) {
-			if (!memaddrs[i]) {
-				printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
-				retval = -ENODEV;
-				goto out;
-			}
-			dev->mem_start = memaddrs[i];
-			size = 0x2000; /* check for 8K mem */
-			if (check586(dev, size))
-				/* 8K-check */
-				break;
-			size = 0x4000; /* check for 16K mem */
-			if (check586(dev, size))
-				/* 16K-check */
-				break;
-		}
-	}
-	/* set mem_end showed by 'ifconfig' */
-	dev->mem_end = dev->mem_start + size;
-#endif
-
-	alloc586(dev);
-
-	/* set number of receive-buffs according to memsize */
-	if (size == 0x2000)
-		priv->num_recv_buffs = NUM_RECV_BUFFS_8;
-	else
-		priv->num_recv_buffs = NUM_RECV_BUFFS_16;
-
-	printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
-				dev->mem_start, size);
-
-	if (dev->irq < 2) {
-		unsigned long irq_mask;
-
-		irq_mask = probe_irq_on();
-		ni_reset586();
-		ni_attn586();
-
-		mdelay(20);
-		dev->irq = probe_irq_off(irq_mask);
-		if (!dev->irq) {
-			printk("?autoirq, Failed to detect IRQ line!\n");
-			retval = -EAGAIN;
-			iounmap(priv->mapped);
-			goto out;
-		}
-		printk("IRQ %d (autodetected).\n", dev->irq);
-	} else {
-		if (dev->irq == 2)
-			dev->irq = 9;
-		printk("IRQ %d (assigned and not checked!).\n", dev->irq);
-	}
-
-	dev->netdev_ops		= &ni52_netdev_ops;
-	dev->watchdog_timeo	= HZ/20;
-
-	return 0;
-out:
-	release_region(ioaddr, NI52_TOTAL_SIZE);
-	return retval;
-}
-
-/**********************************************
- * init the chip (ni52-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
-	void __iomem *ptr;
-	int i, result = 0;
-	struct priv *p = netdev_priv(dev);
-	struct configure_cmd_struct __iomem *cfg_cmd;
-	struct iasetup_cmd_struct __iomem *ias_cmd;
-	struct tdr_cmd_struct __iomem *tdr_cmd;
-	struct mcsetup_cmd_struct __iomem *mc_cmd;
-	struct netdev_hw_addr *ha;
-	int num_addrs = netdev_mc_count(dev);
-
-	ptr = p->scb + 1;
-
-	cfg_cmd = ptr; /* configure-command */
-	writew(0, &cfg_cmd->cmd_status);
-	writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
-	writew(0xFFFF, &cfg_cmd->cmd_link);
-
-	/* number of cfg bytes */
-	writeb(0x0a, &cfg_cmd->byte_cnt);
-	/* fifo-limit (8=tx:32/rx:64) */
-	writeb(fifo, &cfg_cmd->fifo);
-	/* hold or discard bad recv frames (bit 7) */
-	writeb(0x40, &cfg_cmd->sav_bf);
-	/* addr_len |!src_insert |pre-len |loopback */
-	writeb(0x2e, &cfg_cmd->adr_len);
-	writeb(0x00, &cfg_cmd->priority);
-	writeb(0x60, &cfg_cmd->ifs);
-	writeb(0x00, &cfg_cmd->time_low);
-	writeb(0xf2, &cfg_cmd->time_high);
-	writeb(0x00, &cfg_cmd->promisc);
-	if (dev->flags & IFF_ALLMULTI) {
-		int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
-		if (num_addrs > len) {
-			printk(KERN_ERR "%s: switching to promisc. mode\n",
-				dev->name);
-			writeb(0x01, &cfg_cmd->promisc);
-		}
-	}
-	if (dev->flags & IFF_PROMISC)
-		writeb(0x01, &cfg_cmd->promisc);
-	writeb(0x00, &cfg_cmd->carr_coll);
-	writew(make16(cfg_cmd), &p->scb->cbl_offset);
-	writeb(0, &p->scb->cmd_ruc);
-
-	writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-	ni_attn586();
-
-	wait_for_stat_compl(cfg_cmd);
-
-	if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
-							(STAT_COMPL|STAT_OK)) {
-		printk(KERN_ERR "%s: configure command failed: %x\n",
-				dev->name, readw(&cfg_cmd->cmd_status));
-		return 1;
-	}
-
-	/*
-	 * individual address setup
-	 */
-
-	ias_cmd = ptr;
-
-	writew(0, &ias_cmd->cmd_status);
-	writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
-	writew(0xffff, &ias_cmd->cmd_link);
-
-	memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
-
-	writew(make16(ias_cmd), &p->scb->cbl_offset);
-
-	writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-	ni_attn586();
-
-	wait_for_stat_compl(ias_cmd);
-
-	if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
-							(STAT_OK|STAT_COMPL)) {
-		printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
-		return 1;
-	}
-
-	/*
-	 * TDR, wire check .. e.g. no resistor e.t.c
-	 */
-
-	tdr_cmd = ptr;
-
-	writew(0, &tdr_cmd->cmd_status);
-	writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
-	writew(0xffff, &tdr_cmd->cmd_link);
-	writew(0, &tdr_cmd->status);
-
-	writew(make16(tdr_cmd), &p->scb->cbl_offset);
-	writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
-	ni_attn586();
-
-	wait_for_stat_compl(tdr_cmd);
-
-	if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
-		printk(KERN_ERR "%s: Problems while running the TDR.\n",
-				dev->name);
-	else {
-		udelay(16);
-		result = readw(&tdr_cmd->status);
-		writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
-		ni_attn586(); /* ack the interrupts */
-
-		if (result & TDR_LNK_OK)
-			;
-		else if (result & TDR_XCVR_PRB)
-			printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
-				dev->name);
-		else if (result & TDR_ET_OPN)
-			printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
-				dev->name, result & TDR_TIMEMASK);
-		else if (result & TDR_ET_SRT) {
-			/* time == 0 -> strange :-) */
-			if (result & TDR_TIMEMASK)
-				printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
-					dev->name, result & TDR_TIMEMASK);
-		} else
-			printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
-						dev->name, result);
-	}
-
-	/*
-	 * Multicast setup
-	 */
-	if (num_addrs && !(dev->flags & IFF_PROMISC)) {
-		mc_cmd = ptr;
-		writew(0, &mc_cmd->cmd_status);
-		writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
-		writew(0xffff, &mc_cmd->cmd_link);
-		writew(num_addrs * 6, &mc_cmd->mc_cnt);
-
-		i = 0;
-		netdev_for_each_mc_addr(ha, dev)
-			memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
-
-		writew(make16(mc_cmd), &p->scb->cbl_offset);
-		writeb(CUC_START, &p->scb->cmd_cuc);
-		ni_attn586();
-
-		wait_for_stat_compl(mc_cmd);
-
-		if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
-						 != (STAT_COMPL|STAT_OK))
-			printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
-	}
-
-	/*
-	 * alloc nop/xmit-cmds
-	 */
-#if (NUM_XMIT_BUFFS == 1)
-	for (i = 0; i < 2; i++) {
-		p->nop_cmds[i] = ptr;
-		writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
-		writew(0, &p->nop_cmds[i]->cmd_status);
-		writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
-		ptr = ptr + sizeof(struct nop_cmd_struct);
-	}
-#else
-	for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-		p->nop_cmds[i] = ptr;
-		writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
-		writew(0, &p->nop_cmds[i]->cmd_status);
-		writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
-		ptr = ptr + sizeof(struct nop_cmd_struct);
-	}
-#endif
-
-	ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
-
-	/*
-	 * alloc xmit-buffs / init xmit_cmds
-	 */
-	for (i = 0; i < NUM_XMIT_BUFFS; i++) {
-		/* Transmit cmd/buff 0 */
-		p->xmit_cmds[i] = ptr;
-		ptr = ptr + sizeof(struct transmit_cmd_struct);
-		p->xmit_cbuffs[i] = ptr; /* char-buffs */
-		ptr = ptr + XMIT_BUFF_SIZE;
-		p->xmit_buffs[i] = ptr; /* TBD */
-		ptr = ptr + sizeof(struct tbd_struct);
-		if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
-			printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
-				dev->name);
-			return 1;
-		}
-		memset_io(p->xmit_cmds[i], 0,
-					sizeof(struct transmit_cmd_struct));
-		memset_io(p->xmit_buffs[i], 0,
-					sizeof(struct tbd_struct));
-		writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
-					&p->xmit_cmds[i]->cmd_link);
-		writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
-		writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
-		writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
-		writew(0xffff, &p->xmit_buffs[i]->next);
-		writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
-	}
-
-	p->xmit_count = 0;
-	p->xmit_last	= 0;
-#ifndef NO_NOPCOMMANDS
-	p->nop_point	= 0;
-#endif
-
-	 /*
-		* 'start transmitter'
-		*/
-#ifndef NO_NOPCOMMANDS
-	writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
-	writeb(CUC_START, &p->scb->cmd_cuc);
-	ni_attn586();
-	wait_for_scb_cmd(dev);
-#else
-	writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
-	writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
-#endif
-
-	/*
-	 * ack. interrupts
-	 */
-	writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
-	ni_attn586();
-	udelay(16);
-
-	ni_enaint();
-
-	return 0;
-}
-
-/******************************************************
- * This is a helper routine for ni52_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
-{
-	struct rfd_struct __iomem *rfd = ptr;
-	struct rbd_struct __iomem *rbd;
-	int i;
-	struct priv *p = netdev_priv(dev);
-
-	memset_io(rfd, 0,
-		sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
-	p->rfd_first = rfd;
-
-	for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
-		writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
-			&rfd[i].next);
-		writew(0xffff, &rfd[i].rbd_offset);
-	}
-	/* RU suspend */
-	writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
-
-	ptr = rfd + (p->num_recv_buffs + rfdadd);
-
-	rbd = ptr;
-	ptr = rbd + p->num_recv_buffs;
-
-	 /* clr descriptors */
-	memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
-
-	for (i = 0; i < p->num_recv_buffs; i++) {
-		writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
-		writew(RECV_BUFF_SIZE, &rbd[i].size);
-		writel(make24(ptr), &rbd[i].buffer);
-		ptr = ptr + RECV_BUFF_SIZE;
-	}
-	p->rfd_top	= p->rfd_first;
-	p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
-	writew(make16(p->rfd_first), &p->scb->rfa_offset);
-	writew(make16(rbd), &p->rfd_first->rbd_offset);
-
-	return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t ni52_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	unsigned int stat;
-	int cnt = 0;
-	struct priv *p;
-
-	p = netdev_priv(dev);
-
-	if (debuglevel > 1)
-		printk("I");
-
-	spin_lock(&p->spinlock);
-
-	wait_for_scb_cmd(dev); /* wait for last command	*/
-
-	while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
-		writeb(stat, &p->scb->cmd_cuc);
-		ni_attn586();
-
-		if (stat & STAT_FR)	 /* received a frame */
-			ni52_rcv_int(dev);
-
-		if (stat & STAT_RNR) { /* RU went 'not ready' */
-			printk("(R)");
-			if (readb(&p->scb->rus) & RU_SUSPEND) {
-				/* special case: RU_SUSPEND */
-				wait_for_scb_cmd(dev);
-				writeb(RUC_RESUME, &p->scb->cmd_ruc);
-				ni_attn586();
-				wait_for_scb_cmd_ruc(dev);
-			} else {
-				printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
-					dev->name, stat, readb(&p->scb->rus));
-				ni52_rnr_int(dev);
-			}
-		}
-
-		/* Command with I-bit set complete */
-		if (stat & STAT_CX)
-			 ni52_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
-		if (stat & STAT_CNA) {	/* CU went 'not ready' */
-			if (netif_running(dev))
-				printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
-					dev->name, stat, readb(&p->scb->cus));
-		}
-#endif
-
-		if (debuglevel > 1)
-			printk("%d", cnt++);
-
-		/* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
-		wait_for_scb_cmd(dev);
-		if (readb(&p->scb->cmd_cuc)) {	 /* timed out? */
-			printk(KERN_ERR "%s: Acknowledge timed out.\n",
-				dev->name);
-			ni_disint();
-			break;
-		}
-	}
-	spin_unlock(&p->spinlock);
-
-	if (debuglevel > 1)
-		printk("i");
-	return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void ni52_rcv_int(struct net_device *dev)
-{
-	int status, cnt = 0;
-	unsigned short totlen;
-	struct sk_buff *skb;
-	struct rbd_struct __iomem *rbd;
-	struct priv *p = netdev_priv(dev);
-
-	if (debuglevel > 0)
-		printk("R");
-
-	for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
-		rbd = make32(readw(&p->rfd_top->rbd_offset));
-		if (status & RFD_OK) { /* frame received without error? */
-			totlen = readw(&rbd->status);
-			if (totlen & RBD_LAST) {
-				/* the first and the last buffer? */
-				totlen &= RBD_MASK; /* length of this frame */
-				writew(0x00, &rbd->status);
-				skb = netdev_alloc_skb(dev, totlen + 2);
-				if (skb != NULL) {
-					skb_reserve(skb, 2);
-					skb_put(skb, totlen);
-					memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
-					skb->protocol = eth_type_trans(skb, dev);
-					netif_rx(skb);
-					dev->stats.rx_packets++;
-					dev->stats.rx_bytes += totlen;
-				} else
-					dev->stats.rx_dropped++;
-			} else {
-				int rstat;
-				 /* free all RBD's until RBD_LAST is set */
-				totlen = 0;
-				while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
-					totlen += rstat & RBD_MASK;
-					if (!rstat) {
-						printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
-						break;
-					}
-					writew(0, &rbd->status);
-					rbd = make32(readw(&rbd->next));
-				}
-				totlen += rstat & RBD_MASK;
-				writew(0, &rbd->status);
-				printk(KERN_ERR "%s: received oversized frame! length: %d\n",
-					dev->name, totlen);
-				dev->stats.rx_dropped++;
-			 }
-		} else {/* frame !(ok), only with 'save-bad-frames' */
-			printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
-				dev->name, status);
-			dev->stats.rx_errors++;
-		}
-		writeb(0, &p->rfd_top->stat_high);
-		writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
-		writew(0xffff, &p->rfd_top->rbd_offset);
-		writeb(0, &p->rfd_last->last);	/* delete RFD_SUSP	*/
-		p->rfd_last = p->rfd_top;
-		p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
-		writew(make16(p->rfd_top), &p->scb->rfa_offset);
-
-		if (debuglevel > 0)
-			printk("%d", cnt++);
-	}
-
-	if (automatic_resume) {
-		wait_for_scb_cmd(dev);
-		writeb(RUC_RESUME, &p->scb->cmd_ruc);
-		ni_attn586();
-		wait_for_scb_cmd_ruc(dev);
-	}
-
-#ifdef WAIT_4_BUSY
-	{
-		int i;
-		for (i = 0; i < 1024; i++) {
-			if (p->rfd_top->status)
-				break;
-			udelay(16);
-			if (i == 1023)
-				printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
-		}
-	}
-#endif
-	if (debuglevel > 0)
-		printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void ni52_rnr_int(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-
-	dev->stats.rx_errors++;
-
-	wait_for_scb_cmd(dev);		/* wait for the last cmd, WAIT_4_FULLSTAT?? */
-	writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
-	ni_attn586();
-	wait_for_scb_cmd_ruc(dev);		/* wait for accept cmd. */
-
-	alloc_rfa(dev, p->rfd_first);
-	/* maybe add a check here, before restarting the RU */
-	startrecv586(dev); /* restart RU */
-
-	printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
-		dev->name, readb(&p->scb->rus));
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void ni52_xmt_int(struct net_device *dev)
-{
-	int status;
-	struct priv *p = netdev_priv(dev);
-
-	if (debuglevel > 0)
-		printk("X");
-
-	status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
-	if (!(status & STAT_COMPL))
-		printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
-
-	if (status & STAT_OK) {
-		dev->stats.tx_packets++;
-		dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
-	} else {
-		dev->stats.tx_errors++;
-		if (status & TCMD_LATECOLL) {
-			printk(KERN_ERR "%s: late collision detected.\n",
-				dev->name);
-			dev->stats.collisions++;
-		} else if (status & TCMD_NOCARRIER) {
-			dev->stats.tx_carrier_errors++;
-			printk(KERN_ERR "%s: no carrier detected.\n",
-				dev->name);
-		} else if (status & TCMD_LOSTCTS)
-			printk(KERN_ERR "%s: loss of CTS detected.\n",
-				dev->name);
-		else if (status & TCMD_UNDERRUN) {
-			dev->stats.tx_fifo_errors++;
-			printk(KERN_ERR "%s: DMA underrun detected.\n",
-				dev->name);
-		} else if (status & TCMD_MAXCOLL) {
-			printk(KERN_ERR "%s: Max. collisions exceeded.\n",
-				dev->name);
-			dev->stats.collisions += 16;
-		}
-	}
-#if (NUM_XMIT_BUFFS > 1)
-	if ((++p->xmit_last) == NUM_XMIT_BUFFS)
-		p->xmit_last = 0;
-#endif
-	netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-
-	wait_for_scb_cmd(dev);
-	wait_for_scb_cmd_ruc(dev);
-	writew(make16(p->rfd_first), &p->scb->rfa_offset);
-	writeb(RUC_START, &p->scb->cmd_ruc);
-	ni_attn586();		/* start cmd. */
-	wait_for_scb_cmd_ruc(dev);
-	/* wait for accept cmd. (no timeout!!) */
-}
-
-static void ni52_timeout(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
-	if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
-		netif_wake_queue(dev);
-#ifdef DEBUG
-		printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
-			dev->name);
-		printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
-			dev->name, (int)p->xmit_cmds[0]->cmd_status,
-			readw(&p->nop_cmds[0]->cmd_status),
-			readw(&p->nop_cmds[1]->cmd_status),
-			p->nop_point);
-#endif
-		writeb(CUC_ABORT, &p->scb->cmd_cuc);
-		ni_attn586();
-		wait_for_scb_cmd(dev);
-		writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
-		writeb(CUC_START, &p->scb->cmd_cuc);
-		ni_attn586();
-		wait_for_scb_cmd(dev);
-		dev->trans_start = jiffies; /* prevent tx timeout */
-		return 0;
-	}
-#endif
-	{
-#ifdef DEBUG
-		printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
-				dev->name, readb(&p->scb->cus));
-		printk(KERN_ERR "%s: command-stats: %04x %04x\n",
-				dev->name,
-				readw(&p->xmit_cmds[0]->cmd_status),
-				readw(&p->xmit_cmds[1]->cmd_status));
-		printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
-				dev->name);
-#endif
-		ni52_close(dev);
-		ni52_open(dev);
-	}
-	dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
-				    struct net_device *dev)
-{
-	int len, i;
-#ifndef NO_NOPCOMMANDS
-	int next_nop;
-#endif
-	struct priv *p = netdev_priv(dev);
-
-	if (skb->len > XMIT_BUFF_SIZE) {
-		printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
-		return NETDEV_TX_OK;
-	}
-
-	netif_stop_queue(dev);
-
-	memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
-	len = skb->len;
-	if (len < ETH_ZLEN) {
-		len = ETH_ZLEN;
-		memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
-							len - skb->len);
-	}
-
-#if (NUM_XMIT_BUFFS == 1)
-#	ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
-	if (readb(&p->scb->cus) & CU_ACTIVE) {
-		printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
-		printk(KERN_ERR "%s: stat: %04x %04x\n",
-				dev->name, readb(&p->scb->cus),
-				readw(&p->xmit_cmds[0]->cmd_status));
-	}
-#endif
-	writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
-	for (i = 0; i < 16; i++) {
-		writew(0, &p->xmit_cmds[0]->cmd_status);
-		wait_for_scb_cmd(dev);
-		if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
-			writeb(CUC_RESUME, &p->scb->cmd_cuc);
-		else {
-			writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
-			writeb(CUC_START, &p->scb->cmd_cuc);
-		}
-		ni_attn586();
-		if (!i)
-			dev_kfree_skb(skb);
-		wait_for_scb_cmd(dev);
-		/* test it, because CU sometimes doesn't start immediately */
-		if (readb(&p->scb->cus) & CU_ACTIVE)
-			break;
-		if (readw(&p->xmit_cmds[0]->cmd_status))
-			break;
-		if (i == 15)
-			printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
-	}
-#	else
-	next_nop = (p->nop_point + 1) & 0x1;
-	writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
-	writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
-	writew(make16(p->nop_cmds[next_nop]),
-				&p->nop_cmds[next_nop]->cmd_link);
-	writew(0, &p->xmit_cmds[0]->cmd_status);
-	writew(0, &p->nop_cmds[next_nop]->cmd_status);
-
-	writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
-	p->nop_point = next_nop;
-	dev_kfree_skb(skb);
-#	endif
-#else
-	writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
-	next_nop = p->xmit_count + 1
-	if (next_nop == NUM_XMIT_BUFFS)
-		next_nop = 0;
-	writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
-	/* linkpointer of xmit-command already points to next nop cmd */
-	writew(make16(p->nop_cmds[next_nop]),
-				&p->nop_cmds[next_nop]->cmd_link);
-	writew(0, &p->nop_cmds[next_nop]->cmd_status);
-	writew(make16(p->xmit_cmds[p->xmit_count]),
-				&p->nop_cmds[p->xmit_count]->cmd_link);
-	p->xmit_count = next_nop;
-	{
-		unsigned long flags;
-		spin_lock_irqsave(&p->spinlock);
-		if (p->xmit_count != p->xmit_last)
-			netif_wake_queue(dev);
-		spin_unlock_irqrestore(&p->spinlock);
-	}
-	dev_kfree_skb(skb);
-#endif
-	return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *ni52_get_stats(struct net_device *dev)
-{
-	struct priv *p = netdev_priv(dev);
-	unsigned short crc, aln, rsc, ovrn;
-
-	/* Get error-statistics from the ni82586 */
-	crc = readw(&p->scb->crc_errs);
-	writew(0, &p->scb->crc_errs);
-	aln = readw(&p->scb->aln_errs);
-	writew(0, &p->scb->aln_errs);
-	rsc = readw(&p->scb->rsc_errs);
-	writew(0, &p->scb->rsc_errs);
-	ovrn = readw(&p->scb->ovrn_errs);
-	writew(0, &p->scb->ovrn_errs);
-
-	dev->stats.rx_crc_errors += crc;
-	dev->stats.rx_fifo_errors += ovrn;
-	dev->stats.rx_frame_errors += aln;
-	dev->stats.rx_dropped += rsc;
-
-	return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-	netif_stop_queue(dev);
-	ni_disint();
-	alloc586(dev);
-	init586(dev);
-	startrecv586(dev);
-	ni_enaint();
-	netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni52;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(memstart, long, 0);
-module_param(memend, long, 0);
-MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
-MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
-MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
-MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
-
-int __init init_module(void)
-{
-	if (io <= 0x0 || !memend || !memstart || irq < 2) {
-		printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
-		printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
-		return -ENODEV;
-	}
-	dev_ni52 = ni52_probe(-1);
-	if (IS_ERR(dev_ni52))
-		return PTR_ERR(dev_ni52);
-	return 0;
-}
-
-void __exit cleanup_module(void)
-{
-	struct priv *p = netdev_priv(dev_ni52);
-	unregister_netdev(dev_ni52);
-	iounmap(p->mapped);
-	release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
-	free_netdev(dev_ni52);
-}
-#endif /* MODULE */
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/ni52.h b/drivers/net/ethernet/i825xx/ni52.h
deleted file mode 100644
index 0a03b28..0000000
--- a/drivers/net/ethernet/i825xx/ni52.h
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- *   crynwr-packet-driver by Russ Nelson
- *   Garret A. Wollman's i82586-driver for BSD
- */
-
-
-#define NI52_RESET     0  /* writing to this address, resets the i82586 */
-#define NI52_ATTENTION 1  /* channel attention, kick the 586 */
-#define NI52_TENA      3  /* 2-5 possibly wrong, Xmit enable */
-#define NI52_TDIS      2  /* Xmit disable */
-#define NI52_INTENA    5  /* Interrupt enable */
-#define NI52_INTDIS    4  /* Interrupt disable */
-#define NI52_MAGIC1    6  /* dunno exact function */
-#define NI52_MAGIC2    7  /* dunno exact function */
-
-#define NI52_MAGICVAL1 0x00  /* magic-values for ni5210 card */
-#define NI52_MAGICVAL2 0x55
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
-	u16 zero_dum0;	/* has to be zero */
-	u8 sysbus;	/* 0=16Bit,1=8Bit */
-	u8 zero_dum1;	/* has to be zero for 586 */
-	u16 zero_dum2;
-	u16 zero_dum3;
-	u32 iscp;		/* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
-	u8 busy;          /* 586 clears after successful init */
-	u8 zero_dummy;    /* has to be zero */
-	u16 scb_offset;    /* pointeroffset to the scb_base */
-	u32 scb_base;      /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
-	u8 rus;
-	u8 cus;
-	u8 cmd_ruc;        /* command word: RU part */
-	u8 cmd_cuc;        /* command word: CU part & ACK */
-	u16 cbl_offset;    /* pointeroffset, command block list */
-	u16 rfa_offset;    /* pointeroffset, receive frame area */
-	u16 crc_errs;      /* CRC-Error counter */
-	u16 aln_errs;      /* alignmenterror counter */
-	u16 rsc_errs;      /* Resourceerror counter */
-	u16 ovrn_errs;     /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK	0x0070	/* mask for RU commands */
-#define RUC_NOP		0x0000	/* NOP-command */
-#define RUC_START	0x0010	/* start RU */
-#define RUC_RESUME	0x0020	/* resume RU after suspend */
-#define RUC_SUSPEND	0x0030	/* suspend RU */
-#define RUC_ABORT	0x0040	/* abort receiver operation immediately */
-
-#define CUC_MASK        0x07  /* mask for CU command */
-#define CUC_NOP         0x00  /* NOP-command */
-#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME      0x02  /* resume after suspend */
-#define CUC_SUSPEND     0x03  /* Suspend CU */
-#define CUC_ABORT       0x04  /* abort command operation immediately */
-
-#define ACK_MASK        0xf0  /* mask for ACK command */
-#define ACK_CX          0x80  /* acknowledges STAT_CX */
-#define ACK_FR          0x40  /* ack. STAT_FR */
-#define ACK_CNA         0x20  /* ack. STAT_CNA */
-#define ACK_RNR         0x10  /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK       0xf0  /* mask for cause of interrupt */
-#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
-#define STAT_FR         0x40  /* RU finished receiving a frame */
-#define STAT_CNA        0x20  /* CU left active state */
-#define STAT_RNR        0x10  /* RU left ready state */
-
-#define CU_STATUS       0x7   /* CU status, 0=idle */
-#define CU_SUSPEND      0x1   /* CU is suspended */
-#define CU_ACTIVE       0x2   /* CU is active */
-
-#define RU_STATUS	0x70	/* RU status, 0=idle */
-#define RU_SUSPEND	0x10	/* RU suspended */
-#define RU_NOSPACE	0x20	/* RU no resources */
-#define RU_READY	0x40	/* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
-	u8  stat_low;	/* status word */
-	u8  stat_high;	/* status word */
-	u8  rfd_sf;	/* 82596 mode only */
-	u8  last;		/* Bit15,Last Frame on List / Bit14,suspend */
-	u16 next;		/* linkoffset to next RFD */
-	u16 rbd_offset;	/* pointeroffset to RBD-buffer */
-	u8  dest[6];	/* ethernet-address, destination */
-	u8  source[6];	/* ethernet-address, source */
-	u16 length;	/* 802.3 frame-length */
-	u16 zero_dummy;	/* dummy */
-};
-
-#define RFD_LAST     0x80	/* last: last rfd in the list */
-#define RFD_SUSP     0x40	/* last: suspend RU after  */
-#define RFD_COMPL    0x80
-#define RFD_OK       0x20
-#define RFD_BUSY     0x40
-#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC  0x08     /* CRC error */
-#define RFD_ERR_ALGN 0x04     /* Alignment error */
-#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
-#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
-
-#define RFD_ERR_FTS  0x0080	/* Frame to short */
-#define RFD_ERR_NEOP 0x0040	/* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020	/* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET  0x0001	/* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
-	u16 status;	/* status word,number of used bytes in buff */
-	u16 next;		/* pointeroffset to next RBD */
-	u32 buffer;	/* receive buffer address pointer */
-	u16 size;		/* size of this buffer */
-	u16 zero_dummy;    /* dummy */
-};
-
-#define RBD_LAST	0x8000	/* last buffer */
-#define RBD_USED	0x4000	/* this buffer has data */
-#define RBD_MASK	0x3fff	/* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL   0x8000	/* status: frame/command is complete */
-#define STAT_BUSY    0x4000	/* status: frame/command is busy */
-#define STAT_OK      0x2000	/* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP		0x0000	/* NOP */
-#define CMD_IASETUP	0x0001	/* initial address setup command */
-#define CMD_CONFIGURE	0x0002	/* configure command */
-#define CMD_MCSETUP	0x0003	/* MC setup command */
-#define CMD_XMIT	0x0004	/* transmit command */
-#define CMD_TDR		0x0005	/* time domain reflectometer (TDR) command */
-#define CMD_DUMP	0x0006	/* dump command */
-#define CMD_DIAGNOSE	0x0007	/* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST	0x8000	/* indicates last command in the CBL */
-#define CMD_SUSPEND	0x4000	/* suspend CU after this CB */
-#define CMD_INT		0x2000	/* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
-	u16 cmd_status;	/* status of this command */
-	u16 cmd_cmd;       /* the command itself (+bits) */
-	u16 cmd_link;      /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
-	u16 cmd_status;
-	u16 cmd_cmd;
-	u16 cmd_link;
-	u8  iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
-	u16 cmd_status;
-	u16 cmd_cmd;
-	u16 cmd_link;
-	u8  byte_cnt;   /* size of the config-cmd */
-	u8  fifo;       /* fifo/recv monitor */
-	u8  sav_bf;     /* save bad frames (bit7=1)*/
-	u8  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
-	u8  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
-	u8  ifs;        /* inter frame spacing */
-	u8  time_low;   /* slot time low */
-	u8  time_high;  /* slot time high(0-2) and max. retries(4-7) */
-	u8  promisc;    /* promisc-mode(0) , et al (1-7) */
-	u8  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
-	u8  fram_len;   /* minimal frame len */
-	u8  dummy;	     /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
-	u16 cmd_status;
-	u16 cmd_cmd;
-	u16 cmd_link;
-	u16 mc_cnt;		/* number of bytes in the MC-List */
-	u8  mc_list[0][6];  	/* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
-	u16 cmd_status;
-	u16 cmd_cmd;
-	u16 cmd_link;
-	u16 dump_offset;    /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
-	u16 cmd_status;
-	u16 cmd_cmd;
-	u16 cmd_link;
-	u16 tbd_offset;	/* pointeroffset to TBD */
-	u8  dest[6];       /* destination address of the frame */
-	u16 length;	/* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK     0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL     0x0020
-#define TCMD_HEARTBEAT   0x0040
-#define TCMD_DEFERRED    0x0080
-#define TCMD_UNDERRUN    0x0100
-#define TCMD_LOSTCTS     0x0200
-#define TCMD_NOCARRIER   0x0400
-#define TCMD_LATECOLL    0x0800
-
-struct tdr_cmd_struct
-{
-	u16 cmd_status;
-	u16 cmd_cmd;
-	u16 cmd_link;
-	u16 status;
-};
-
-#define TDR_LNK_OK	0x8000	/* No link problem identified */
-#define TDR_XCVR_PRB	0x4000	/* indicates a transceiver problem */
-#define TDR_ET_OPN	0x2000	/* open, no correct termination */
-#define TDR_ET_SRT	0x1000	/* TDR detected a short circuit */
-#define TDR_TIMEMASK	0x07ff	/* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
-	u16 size;		/* size + EOF-Flag(15) */
-	u16 next;          /* pointeroffset to next TBD */
-	u32 buffer;        /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
-
-
-
-
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
deleted file mode 100644
index c9479e0..0000000
--- a/drivers/net/ethernet/i825xx/znet.c
+++ /dev/null
@@ -1,928 +0,0 @@
-/* znet.c: An Zenith Z-Note ethernet driver for linux. */
-
-/*
-	Written by Donald Becker.
-
-	The author may be reached as becker@scyld.com.
-	This driver is based on the Linux skeleton driver.  The copyright of the
-	skeleton driver is held by the United States Government, as represented
-	by DIRNSA, and it is released under the GPL.
-
-	Thanks to Mike Hollick for alpha testing and suggestions.
-
-  References:
-	   The Crynwr packet driver.
-
-	  "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
-	  Intel Microcommunications Databook, Vol. 1, 1990.
-    As usual with Intel, the documentation is incomplete and inaccurate.
-	I had to read the Crynwr packet driver to figure out how to actually
-	use the i82593, and guess at what register bits matched the loosely
-	related i82586.
-
-					Theory of Operation
-
-	The i82593 used in the Zenith Z-Note series operates using two(!) slave
-	DMA	channels, one interrupt, and one 8-bit I/O port.
-
-	While there	several ways to configure '593 DMA system, I chose the one
-	that seemed commensurate with the highest system performance in the face
-	of moderate interrupt latency: Both DMA channels are configured as
-	recirculating ring buffers, with one channel (#0) dedicated to Rx and
-	the other channel (#1) to Tx and configuration.  (Note that this is
-	different than the Crynwr driver, where the Tx DMA channel is initialized
-	before each operation.  That approach simplifies operation and Tx error
-	recovery, but requires additional I/O in normal operation and precludes
-	transmit buffer	chaining.)
-
-	Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE.  This provides
-	a reasonable ring size for Rx, while simplifying DMA buffer allocation --
-	DMA buffers must not cross a 128K boundary.  (In truth the size selection
-	was influenced by my lack of '593 documentation.  I thus was constrained
-	to use the Crynwr '593 initialization table, which sets the Rx ring size
-	to 8K.)
-
-	Despite my usual low opinion about Intel-designed parts, I must admit
-	that the bulk data handling of the i82593 is a good design for
-	an integrated system, like a laptop, where using two slave DMA channels
-	doesn't pose a problem.  I still take issue with using only a single I/O
-	port.  In the same controlled environment there are essentially no
-	limitations on I/O space, and using multiple locations would eliminate
-	the	need for multiple operations when looking at status registers,
-	setting the Rx ring boundary, or switching to promiscuous mode.
-
-	I also question Zenith's selection of the '593: one of the advertised
-	advantages of earlier Intel parts was that if you figured out the magic
-	initialization incantation you could use the same part on many different
-	network types.  Zenith's use of the "FriendlyNet" (sic) connector rather
-	than an	on-board transceiver leads me to believe that they were planning
-	to take advantage of this.  But, uhmmm, the '593 omits all but ethernet
-	functionality from the serial subsystem.
- */
-
-/* 10/2002
-
-   o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
-
-   - Removed strange DMA snooping in znet_sent_packet, which lead to
-     TX buffer corruption on my laptop.
-   - Use init_etherdev stuff.
-   - Use kmalloc-ed DMA buffers.
-   - Use as few global variables as possible.
-   - Use proper resources management.
-   - Use wireless/i82593.h as much as possible (structure, constants)
-   - Compiles as module or build-in.
-   - Now survives unplugging/replugging cable.
-
-   Some code was taken from wavelan_cs.
-
-   Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
-   anything else. Testers (and detailed bug reports) are welcome :-).
-
-   o TODO :
-
-   - Properly handle multicast
-   - Understand why some traffic patterns add a 1s latency...
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/i82593.h>
-
-static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
-
-#ifndef ZNET_DEBUG
-#define ZNET_DEBUG 1
-#endif
-static unsigned int znet_debug = ZNET_DEBUG;
-module_param (znet_debug, int, 0);
-MODULE_PARM_DESC (znet_debug, "ZNet debug level");
-MODULE_LICENSE("GPL");
-
-/* The DMA modes we need aren't in <dma.h>. */
-#define DMA_RX_MODE		0x14	/* Auto init, I/O to mem, ++, demand. */
-#define DMA_TX_MODE		0x18	/* Auto init, Mem to I/O, ++, demand. */
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
-#define RX_BUF_SIZE 8192
-#define TX_BUF_SIZE 8192
-#define DMA_BUF_SIZE (RX_BUF_SIZE + 16)	/* 8k + 16 bytes for trailers */
-
-#define TX_TIMEOUT	(HZ/10)
-
-struct znet_private {
-	int rx_dma, tx_dma;
-	spinlock_t lock;
-	short sia_base, sia_size, io_size;
-	struct i82593_conf_block i593_init;
-	/* The starting, current, and end pointers for the packet buffers. */
-	ushort *rx_start, *rx_cur, *rx_end;
-	ushort *tx_start, *tx_cur, *tx_end;
-	ushort tx_buf_len;			/* Tx buffer length, in words. */
-};
-
-/* Only one can be built-in;-> */
-static struct net_device *znet_dev;
-
-#define NETIDBLK_MAGIC		"NETIDBLK"
-#define NETIDBLK_MAGIC_SIZE	8
-
-struct netidblk {
-	char magic[NETIDBLK_MAGIC_SIZE];	/* The magic number (string) "NETIDBLK" */
-	unsigned char netid[8]; /* The physical station address */
-	char nettype, globalopt;
-	char vendor[8];		/* The machine vendor and product name. */
-	char product[8];
-	char irq1, irq2;		/* Interrupts, only one is currently used.	*/
-	char dma1, dma2;
-	short dma_mem_misc[8];		/* DMA buffer locations (unused in Linux). */
-	short iobase1, iosize1;
-	short iobase2, iosize2;		/* Second iobase unused. */
-	char driver_options;			/* Misc. bits */
-	char pad;
-};
-
-static int	znet_open(struct net_device *dev);
-static netdev_tx_t znet_send_packet(struct sk_buff *skb,
-				    struct net_device *dev);
-static irqreturn_t znet_interrupt(int irq, void *dev_id);
-static void	znet_rx(struct net_device *dev);
-static int	znet_close(struct net_device *dev);
-static void hardware_init(struct net_device *dev);
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
-static void znet_tx_timeout (struct net_device *dev);
-
-/* Request needed resources */
-static int znet_request_resources (struct net_device *dev)
-{
-	struct znet_private *znet = netdev_priv(dev);
-
-	if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
-		goto failed;
-	if (request_dma (znet->rx_dma, "ZNet rx"))
-		goto free_irq;
-	if (request_dma (znet->tx_dma, "ZNet tx"))
-		goto free_rx_dma;
-	if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
-		goto free_tx_dma;
-	if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
-		goto free_sia;
-
-	return 0;				/* Happy ! */
-
- free_sia:
-	release_region (znet->sia_base, znet->sia_size);
- free_tx_dma:
-	free_dma (znet->tx_dma);
- free_rx_dma:
-	free_dma (znet->rx_dma);
- free_irq:
-	free_irq (dev->irq, dev);
- failed:
-	return -1;
-}
-
-static void znet_release_resources (struct net_device *dev)
-{
-	struct znet_private *znet = netdev_priv(dev);
-
-	release_region (znet->sia_base, znet->sia_size);
-	release_region (dev->base_addr, znet->io_size);
-	free_dma (znet->tx_dma);
-	free_dma (znet->rx_dma);
-	free_irq (dev->irq, dev);
-}
-
-/* Keep the magical SIA stuff in a single function... */
-static void znet_transceiver_power (struct net_device *dev, int on)
-{
-	struct znet_private *znet = netdev_priv(dev);
-	unsigned char v;
-
-	/* Turn on/off the 82501 SIA, using zenith-specific magic. */
-	/* Select LAN control register */
-	outb(0x10, znet->sia_base);
-
-	if (on)
-		v = inb(znet->sia_base + 1) | 0x84;
-	else
-		v = inb(znet->sia_base + 1) & ~0x84;
-
-	outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
-}
-
-/* Init the i82593, with current promisc/mcast configuration.
-   Also used from hardware_init. */
-static void znet_set_multicast_list (struct net_device *dev)
-{
-	struct znet_private *znet = netdev_priv(dev);
-	short ioaddr = dev->base_addr;
-	struct i82593_conf_block *cfblk = &znet->i593_init;
-
-	memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
-
-        /* The configuration block.  What an undocumented nightmare.
-	   The first set of values are those suggested (without explanation)
-	   for ethernet in the Intel 82586 databook.  The rest appear to be
-	   completely undocumented, except for cryptic notes in the Crynwr
-	   packet driver.  This driver uses the Crynwr values verbatim. */
-
-	/* maz : Rewritten to take advantage of the wanvelan includes.
-	   At least we have names, not just blind values */
-
-	/* Byte 0 */
-	cfblk->fifo_limit = 10;	/* = 16 B rx and 80 B tx fifo thresholds */
-	cfblk->forgnesi = 0;	/* 0=82C501, 1=AMD7992B compatibility */
-	cfblk->fifo_32 = 1;
-	cfblk->d6mod = 0;  	/* Run in i82593 advanced mode */
-	cfblk->throttle_enb = 1;
-
-	/* Byte 1 */
-	cfblk->throttle = 8;	/* Continuous w/interrupts, 128-clock DMA. */
-	cfblk->cntrxint = 0;	/* enable continuous mode receive interrupts */
-	cfblk->contin = 1;	/* enable continuous mode */
-
-	/* Byte 2 */
-	cfblk->addr_len = ETH_ALEN;
-	cfblk->acloc = 1;	/* Disable source addr insertion by i82593 */
-	cfblk->preamb_len = 2;	/* 8 bytes preamble */
-	cfblk->loopback = 0;	/* Loopback off */
-
-	/* Byte 3 */
-	cfblk->lin_prio = 0;	/* Default priorities & backoff methods. */
-	cfblk->tbofstop = 0;
-	cfblk->exp_prio = 0;
-	cfblk->bof_met = 0;
-
-	/* Byte 4 */
-	cfblk->ifrm_spc = 6;	/* 96 bit times interframe spacing */
-
-	/* Byte 5 */
-	cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
-
-	/* Byte 6 */
-	cfblk->slottim_hi = 2;	/* 512 bit times slot time (high) */
-	cfblk->max_retr = 15;	/* 15 collisions retries */
-
-	/* Byte 7 */
-	cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
-	cfblk->bc_dis = 0;	/* Enable broadcast reception */
-	cfblk->crs_1 = 0;	/* Don't transmit without carrier sense */
-	cfblk->nocrc_ins = 0;	/* i82593 generates CRC */
-	cfblk->crc_1632 = 0;	/* 32-bit Autodin-II CRC */
-	cfblk->crs_cdt = 0;	/* CD not to be interpreted as CS */
-
-	/* Byte 8 */
-	cfblk->cs_filter = 0;  	/* CS is recognized immediately */
-	cfblk->crs_src = 0;	/* External carrier sense */
-	cfblk->cd_filter = 0;  	/* CD is recognized immediately */
-
-	/* Byte 9 */
-	cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
-
-	/* Byte A */
-	cfblk->lng_typ = 1;	/* Type/length checks OFF */
-	cfblk->lng_fld = 1; 	/* Disable 802.3 length field check */
-	cfblk->rxcrc_xf = 1;	/* Don't transfer CRC to memory */
-	cfblk->artx = 1;	/* Disable automatic retransmission */
-	cfblk->sarec = 1;	/* Disable source addr trig of CD */
-	cfblk->tx_jabber = 0;	/* Disable jabber jam sequence */
-	cfblk->hash_1 = 1; 	/* Use bits 0-5 in mc address hash */
-	cfblk->lbpkpol = 0; 	/* Loopback pin active high */
-
-	/* Byte B */
-	cfblk->fdx = 0;		/* Disable full duplex operation */
-
-	/* Byte C */
-	cfblk->dummy_6 = 0x3f; 	/* all ones, Default multicast addresses & backoff. */
-	cfblk->mult_ia = 0;	/* No multiple individual addresses */
-	cfblk->dis_bof = 0;	/* Disable the backoff algorithm ?! */
-
-	/* Byte D */
-	cfblk->dummy_1 = 1; 	/* set to 1 */
-	cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
-	cfblk->mc_all = (!netdev_mc_empty(dev) ||
-			(dev->flags & IFF_ALLMULTI)); /* multicast all mode */
-	cfblk->rcv_mon = 0;	/* Monitor mode disabled */
-	cfblk->frag_acpt = 0;	/* Do not accept fragments */
-	cfblk->tstrttrs = 0;	/* No start transmission threshold */
-
-	/* Byte E */
-	cfblk->fretx = 1;	/* FIFO automatic retransmission */
-	cfblk->runt_eop = 0;	/* drop "runt" packets */
-	cfblk->hw_sw_pin = 0;	/* ?? */
-	cfblk->big_endn = 0;	/* Big Endian ? no... */
-	cfblk->syncrqs = 1;	/* Synchronous DRQ deassertion... */
-	cfblk->sttlen = 1;  	/* 6 byte status registers */
-	cfblk->rx_eop = 0;  	/* Signal EOP on packet reception */
-	cfblk->tx_eop = 0;  	/* Signal EOP on packet transmission */
-
-	/* Byte F */
-	cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
-	cfblk->rcvstop = 1; 	/* Enable Receive Stop Register */
-
-	if (znet_debug > 2) {
-		int i;
-		unsigned char *c;
-
-		for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
-			printk ("%02X ", c[i]);
-		printk ("\n");
-	}
-
-	*znet->tx_cur++ = sizeof(struct i82593_conf_block);
-	memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
-	znet->tx_cur += sizeof(struct i82593_conf_block)/2;
-	outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
-	/* XXX FIXME maz : Add multicast addresses here, so having a
-	 * multicast address configured isn't equal to IFF_ALLMULTI */
-}
-
-static const struct net_device_ops znet_netdev_ops = {
-	.ndo_open		= znet_open,
-	.ndo_stop		= znet_close,
-	.ndo_start_xmit		= znet_send_packet,
-	.ndo_set_rx_mode	= znet_set_multicast_list,
-	.ndo_tx_timeout		= znet_tx_timeout,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/* The Z-Note probe is pretty easy.  The NETIDBLK exists in the safe-to-probe
-   BIOS area.  We just scan for the signature, and pull the vital parameters
-   out of the structure. */
-
-static int __init znet_probe (void)
-{
-	int i;
-	struct netidblk *netinfo;
-	struct znet_private *znet;
-	struct net_device *dev;
-	char *p;
-	char *plast = phys_to_virt(0x100000 - NETIDBLK_MAGIC_SIZE);
-	int err = -ENOMEM;
-
-	/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
-	for(p = (char *)phys_to_virt(0xf0000); p <= plast; p++)
-		if (*p == 'N' &&
-		    strncmp(p, NETIDBLK_MAGIC, NETIDBLK_MAGIC_SIZE) == 0)
-			break;
-
-	if (p > plast) {
-		if (znet_debug > 1)
-			printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
-		return -ENODEV;
-	}
-
-	dev = alloc_etherdev(sizeof(struct znet_private));
-	if (!dev)
-		return -ENOMEM;
-
-	znet = netdev_priv(dev);
-
-	netinfo = (struct netidblk *)p;
-	dev->base_addr = netinfo->iobase1;
-	dev->irq = netinfo->irq1;
-
-	/* The station address is in the "netidblk" at 0x0f0000. */
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = netinfo->netid[i];
-
-	printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
-	       ", using IRQ %d DMA %d and %d.\n",
-	       dev->name, dev->base_addr, dev->dev_addr,
-	       dev->irq, netinfo->dma1, netinfo->dma2);
-
-	if (znet_debug > 1) {
-		printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
-		       dev->name, netinfo->vendor,
-		       netinfo->irq1, netinfo->irq2,
-		       netinfo->dma1, netinfo->dma2);
-		printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
-		       dev->name, netinfo->iobase1, netinfo->iosize1,
-		       netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
-	}
-
-	if (znet_debug > 0)
-		printk(KERN_INFO "%s", version);
-
-	znet->rx_dma = netinfo->dma1;
-	znet->tx_dma = netinfo->dma2;
-	spin_lock_init(&znet->lock);
-	znet->sia_base = 0xe6;	/* Magic address for the 82501 SIA */
-	znet->sia_size = 2;
-	/* maz: Despite the '593 being advertised above as using a
-	 * single 8bits I/O port, this driver does many 16bits
-	 * access. So set io_size accordingly */
-	znet->io_size  = 2;
-
-	if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
-		goto free_dev;
-	if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
-		goto free_rx;
-
-	if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
-	    !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
-		printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
-		goto free_tx;
-	}
-
-	znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
-	znet->tx_buf_len = TX_BUF_SIZE/2;
-	znet->tx_end = znet->tx_start + znet->tx_buf_len;
-
-	/* The ZNET-specific entries in the device structure. */
-	dev->netdev_ops = &znet_netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-	err = register_netdev(dev);
-	if (err)
-		goto free_tx;
-	znet_dev = dev;
-	return 0;
-
- free_tx:
-	kfree(znet->tx_start);
- free_rx:
-	kfree(znet->rx_start);
- free_dev:
-	free_netdev(dev);
-	return err;
-}
-
-
-static int znet_open(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	if (znet_debug > 2)
-		printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
-
-	/* These should never fail.  You can't add devices to a sealed box! */
-	if (znet_request_resources (dev)) {
-		printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
-		return -EBUSY;
-	}
-
-	znet_transceiver_power (dev, 1);
-
-	/* According to the Crynwr driver we should wait 50 msec. for the
-	   LAN clock to stabilize.  My experiments indicates that the '593 can
-	   be initialized immediately.  The delay is probably needed for the
-	   DC-to-DC converter to come up to full voltage, and for the oscillator
-	   to be spot-on at 20Mhz before transmitting.
-	   Until this proves to be a problem we rely on the higher layers for the
-	   delay and save allocating a timer entry. */
-
-	/* maz : Well, I'm getting every time the following message
-	 * without the delay on a 486@33. This machine is much too
-	 * fast... :-) So maybe the Crynwr driver wasn't wrong after
-	 * all, even if the message is completly harmless on my
-	 * setup. */
-	mdelay (50);
-
-	/* This follows the packet driver's lead, and checks for success. */
-	if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
-		printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
-		       dev->name);
-
-	hardware_init(dev);
-	netif_start_queue (dev);
-
-	return 0;
-}
-
-
-static void znet_tx_timeout (struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	ushort event, tx_status, rx_offset, state;
-
-	outb (CR0_STATUS_0, ioaddr);
-	event = inb (ioaddr);
-	outb (CR0_STATUS_1, ioaddr);
-	tx_status = inw (ioaddr);
-	outb (CR0_STATUS_2, ioaddr);
-	rx_offset = inw (ioaddr);
-	outb (CR0_STATUS_3, ioaddr);
-	state = inb (ioaddr);
-	printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
-	 " resetting.\n", dev->name, event, tx_status, rx_offset, state);
-	if (tx_status == TX_LOST_CRS)
-		printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
-			dev->name);
-	outb (OP0_RESET, ioaddr);
-	hardware_init (dev);
-	netif_wake_queue (dev);
-}
-
-static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct znet_private *znet = netdev_priv(dev);
-	unsigned long flags;
-	short length = skb->len;
-
-	if (znet_debug > 4)
-		printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
-
-	if (length < ETH_ZLEN) {
-		if (skb_padto(skb, ETH_ZLEN))
-			return NETDEV_TX_OK;
-		length = ETH_ZLEN;
-	}
-
-	netif_stop_queue (dev);
-
-	/* Check that the part hasn't reset itself, probably from suspend. */
-	outb(CR0_STATUS_0, ioaddr);
-	if (inw(ioaddr) == 0x0010 &&
-	    inw(ioaddr) == 0x0000 &&
-	    inw(ioaddr) == 0x0010) {
-		if (znet_debug > 1)
-			printk (KERN_WARNING "%s : waking up\n", dev->name);
-		hardware_init(dev);
-		znet_transceiver_power (dev, 1);
-	}
-
-	if (1) {
-		unsigned char *buf = (void *)skb->data;
-		ushort *tx_link = znet->tx_cur - 1;
-		ushort rnd_len = (length + 1)>>1;
-
-		dev->stats.tx_bytes+=length;
-
-		if (znet->tx_cur >= znet->tx_end)
-		  znet->tx_cur = znet->tx_start;
-		*znet->tx_cur++ = length;
-		if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
-			int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
-			memcpy(znet->tx_cur, buf, semi_cnt);
-			rnd_len -= semi_cnt>>1;
-			memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
-			znet->tx_cur = znet->tx_start + rnd_len;
-		} else {
-			memcpy(znet->tx_cur, buf, skb->len);
-			znet->tx_cur += rnd_len;
-		}
-		*znet->tx_cur++ = 0;
-
-		spin_lock_irqsave(&znet->lock, flags);
-		{
-			*tx_link = OP0_TRANSMIT | CR0_CHNL;
-			/* Is this always safe to do? */
-			outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
-		}
-		spin_unlock_irqrestore (&znet->lock, flags);
-
-		netif_start_queue (dev);
-
-		if (znet_debug > 4)
-		  printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
-	}
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-}
-
-/* The ZNET interrupt handler. */
-static irqreturn_t znet_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct znet_private *znet = netdev_priv(dev);
-	int ioaddr;
-	int boguscnt = 20;
-	int handled = 0;
-
-	spin_lock (&znet->lock);
-
-	ioaddr = dev->base_addr;
-
-	outb(CR0_STATUS_0, ioaddr);
-	do {
-		ushort status = inb(ioaddr);
-		if (znet_debug > 5) {
-			ushort result, rx_ptr, running;
-			outb(CR0_STATUS_1, ioaddr);
-			result = inw(ioaddr);
-			outb(CR0_STATUS_2, ioaddr);
-			rx_ptr = inw(ioaddr);
-			outb(CR0_STATUS_3, ioaddr);
-			running = inb(ioaddr);
-			printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
-				 dev->name, status, result, rx_ptr, running, boguscnt);
-		}
-		if ((status & SR0_INTERRUPT) == 0)
-			break;
-
-		handled = 1;
-
-		if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
-		    (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
-		    (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
-			int tx_status;
-			outb(CR0_STATUS_1, ioaddr);
-			tx_status = inw(ioaddr);
-			/* It's undocumented, but tx_status seems to match the i82586. */
-			if (tx_status & TX_OK) {
-				dev->stats.tx_packets++;
-				dev->stats.collisions += tx_status & TX_NCOL_MASK;
-			} else {
-				if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
-					dev->stats.tx_carrier_errors++;
-				if (tx_status & TX_UND_RUN)
-					dev->stats.tx_fifo_errors++;
-				if (!(tx_status & TX_HRT_BEAT))
-					dev->stats.tx_heartbeat_errors++;
-				if (tx_status & TX_MAX_COL)
-					dev->stats.tx_aborted_errors++;
-				/* ...and the catch-all. */
-				if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
-					dev->stats.tx_errors++;
-
-				/* Transceiver may be stuck if cable
-				 * was removed while emitting a
-				 * packet. Flip it off, then on to
-				 * reset it. This is very empirical,
-				 * but it seems to work. */
-
-				znet_transceiver_power (dev, 0);
-				znet_transceiver_power (dev, 1);
-			}
-			netif_wake_queue (dev);
-		}
-
-		if ((status & SR0_RECEPTION) ||
-		    (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
-			znet_rx(dev);
-		}
-		/* Clear the interrupts we've handled. */
-		outb(CR0_INT_ACK, ioaddr);
-	} while (boguscnt--);
-
-	spin_unlock (&znet->lock);
-
-	return IRQ_RETVAL(handled);
-}
-
-static void znet_rx(struct net_device *dev)
-{
-	struct znet_private *znet = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	int boguscount = 1;
-	short next_frame_end_offset = 0; 		/* Offset of next frame start. */
-	short *cur_frame_end;
-	short cur_frame_end_offset;
-
-	outb(CR0_STATUS_2, ioaddr);
-	cur_frame_end_offset = inw(ioaddr);
-
-	if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
-		printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
-			   dev->name, cur_frame_end_offset);
-		return;
-	}
-
-	/* Use same method as the Crynwr driver: construct a forward list in
-	   the same area of the backwards links we now have.  This allows us to
-	   pass packets to the upper layers in the order they were received --
-	   important for fast-path sequential operations. */
-	while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
-	       ++boguscount < 5) {
-		unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
-		int count, status;
-
-		if (cur_frame_end_offset < 4) {
-			/* Oh no, we have a special case: the frame trailer wraps around
-			   the end of the ring buffer.  We've saved space at the end of
-			   the ring buffer for just this problem. */
-			memcpy(znet->rx_end, znet->rx_start, 8);
-			cur_frame_end_offset += (RX_BUF_SIZE/2);
-		}
-		cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
-
-		lo_status = *cur_frame_end++;
-		hi_status = *cur_frame_end++;
-		status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
-		lo_cnt = *cur_frame_end++;
-		hi_cnt = *cur_frame_end++;
-		count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
-
-		if (znet_debug > 5)
-		  printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
-				 " count %#x status %04x.\n",
-				 cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
-				 count, status);
-		cur_frame_end[-4] = status;
-		cur_frame_end[-3] = next_frame_end_offset;
-		cur_frame_end[-2] = count;
-		next_frame_end_offset = cur_frame_end_offset;
-		cur_frame_end_offset -= ((count + 1)>>1) + 3;
-		if (cur_frame_end_offset < 0)
-		  cur_frame_end_offset += RX_BUF_SIZE/2;
-	}
-
-	/* Now step  forward through the list. */
-	do {
-		ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
-		int status = this_rfp_ptr[-4];
-		int pkt_len = this_rfp_ptr[-2];
-
-		if (znet_debug > 5)
-		  printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
-				 " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
-				 this_rfp_ptr[-3]<<1);
-		/* Once again we must assume that the i82586 docs apply. */
-		if ( ! (status & RX_RCV_OK)) { /* There was an error. */
-			dev->stats.rx_errors++;
-			if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
-			if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
-#if 0
-			if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
-			if (status & 0x0100) dev->stats.rx_fifo_errors++;
-#else
-			/* maz : Wild guess... */
-			if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
-#endif
-			if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
-		} else if (pkt_len > 1536) {
-			dev->stats.rx_length_errors++;
-		} else {
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len);
-			if (skb == NULL) {
-				if (znet_debug)
-				  printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-				dev->stats.rx_dropped++;
-				break;
-			}
-
-			if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
-				int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
-				memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
-				memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
-					   pkt_len - semi_cnt);
-			} else {
-				memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
-				if (znet_debug > 6) {
-					unsigned int *packet = (unsigned int *) skb->data;
-					printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
-						   packet[1], packet[2], packet[3]);
-				}
-		  }
-		  skb->protocol=eth_type_trans(skb,dev);
-		  netif_rx(skb);
-		  dev->stats.rx_packets++;
-		  dev->stats.rx_bytes += pkt_len;
-		}
-		znet->rx_cur = this_rfp_ptr;
-		if (znet->rx_cur >= znet->rx_end)
-			znet->rx_cur -= RX_BUF_SIZE/2;
-		update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
-		next_frame_end_offset = this_rfp_ptr[-3];
-		if (next_frame_end_offset == 0)		/* Read all the frames? */
-			break;			/* Done for now */
-		this_rfp_ptr = znet->rx_start + next_frame_end_offset;
-	} while (--boguscount);
-
-	/* If any worth-while packets have been received, dev_rint()
-	   has done a mark_bh(INET_BH) for us and will work on them
-	   when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to znet_open(). */
-static int znet_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	netif_stop_queue (dev);
-
-	outb(OP0_RESET, ioaddr);			/* CMD0_RESET */
-
-	if (znet_debug > 1)
-		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
-	/* Turn off transceiver power. */
-	znet_transceiver_power (dev, 0);
-
-	znet_release_resources (dev);
-
-	return 0;
-}
-
-static void show_dma(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-	unsigned char stat = inb (ioaddr);
-	struct znet_private *znet = netdev_priv(dev);
-	unsigned long flags;
-	short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
-	unsigned addr = inb(dma_port);
-	short residue;
-
-	addr |= inb(dma_port) << 8;
-	residue = get_dma_residue(znet->tx_dma);
-
-	if (znet_debug > 1) {
-		flags=claim_dma_lock();
-		printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
-		       stat, addr<<1, residue);
-		release_dma_lock(flags);
-	}
-}
-
-/* Initialize the hardware.  We have to do this when the board is open()ed
-   or when we come out of suspend mode. */
-static void hardware_init(struct net_device *dev)
-{
-	unsigned long flags;
-	short ioaddr = dev->base_addr;
-	struct znet_private *znet = netdev_priv(dev);
-
-	znet->rx_cur = znet->rx_start;
-	znet->tx_cur = znet->tx_start;
-
-	/* Reset the chip, and start it up. */
-	outb(OP0_RESET, ioaddr);
-
-	flags=claim_dma_lock();
-	disable_dma(znet->rx_dma); 		/* reset by an interrupting task. */
-	clear_dma_ff(znet->rx_dma);
-	set_dma_mode(znet->rx_dma, DMA_RX_MODE);
-	set_dma_addr(znet->rx_dma, isa_virt_to_bus(znet->rx_start));
-	set_dma_count(znet->rx_dma, RX_BUF_SIZE);
-	enable_dma(znet->rx_dma);
-	/* Now set up the Tx channel. */
-	disable_dma(znet->tx_dma);
-	clear_dma_ff(znet->tx_dma);
-	set_dma_mode(znet->tx_dma, DMA_TX_MODE);
-	set_dma_addr(znet->tx_dma, isa_virt_to_bus(znet->tx_start));
-	set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
-	enable_dma(znet->tx_dma);
-	release_dma_lock(flags);
-
-	if (znet_debug > 1)
-	  printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
-			 dev->name, znet->rx_start,znet->tx_start);
-	/* Do an empty configure command, just like the Crynwr driver.  This
-	   resets to chip to its default values. */
-	*znet->tx_cur++ = 0;
-	*znet->tx_cur++ = 0;
-	show_dma(dev);
-	outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
-	znet_set_multicast_list (dev);
-
-	*znet->tx_cur++ = 6;
-	memcpy(znet->tx_cur, dev->dev_addr, 6);
-	znet->tx_cur += 3;
-	show_dma(dev);
-	outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
-	show_dma(dev);
-
-	update_stop_hit(ioaddr, 8192);
-	if (znet_debug > 1)  printk(KERN_DEBUG "enabling Rx.\n");
-	outb(OP0_RCV_ENABLE, ioaddr);
-	netif_start_queue (dev);
-}
-
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
-{
-	outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
-	if (znet_debug > 5)
-	  printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
-			 (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
-	outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
-	outb(OP1_SWIT_TO_PORT_0, ioaddr);
-}
-
-static __exit void znet_cleanup (void)
-{
-	if (znet_dev) {
-		struct znet_private *znet = netdev_priv(znet_dev);
-
-		unregister_netdev (znet_dev);
-		kfree (znet->rx_start);
-		kfree (znet->tx_start);
-		free_netdev (znet_dev);
-	}
-}
-
-module_init (znet_probe);
-module_exit (znet_cleanup);
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 19b64de..328f47c 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -76,16 +76,16 @@
 MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
 		 "port to stack. 1:yes, 0:no.  Default = 0 ");
 MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
-		 "[2^x - 1], x = [6..14]. Default = "
+		 "[2^x - 1], x = [7..14]. Default = "
 		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
 MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
-		 "[2^x - 1], x = [6..14]. Default = "
+		 "[2^x - 1], x = [7..14]. Default = "
 		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
 MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
-		 "[2^x - 1], x = [6..14]. Default = "
+		 "[2^x - 1], x = [7..14]. Default = "
 		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
 MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue  "
-		 "[2^x - 1], x = [6..14]. Default = "
+		 "[2^x - 1], x = [7..14]. Default = "
 		 __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
 MODULE_PARM_DESC(use_mcs, " Multiple receive queues, 1: enable, 0: disable, "
 		 "Default = 1");
@@ -1921,10 +1921,8 @@
 	u64 hret;
 
 	ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC);
-	if (!ehea_mcl_entry) {
-		pr_err("no mem for mcl_entry\n");
+	if (!ehea_mcl_entry)
 		return;
-	}
 
 	INIT_LIST_HEAD(&ehea_mcl_entry->list);
 
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
index 27f8817..9b03033 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
@@ -64,11 +64,10 @@
 	}
 
 	queue->queue_length = nr_of_pages * pagesize;
-	queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
-	if (!queue->queue_pages) {
-		pr_err("no mem for queue_pages\n");
+	queue->queue_pages = kmalloc_array(nr_of_pages, sizeof(void *),
+					   GFP_KERNEL);
+	if (!queue->queue_pages)
 		return -ENOMEM;
-	}
 
 	/*
 	 * allocate pages for queue:
@@ -129,10 +128,8 @@
 	void *vpage;
 
 	cq = kzalloc(sizeof(*cq), GFP_KERNEL);
-	if (!cq) {
-		pr_err("no mem for cq\n");
+	if (!cq)
 		goto out_nomem;
-	}
 
 	cq->attr.max_nr_of_cqes = nr_of_cqe;
 	cq->attr.cq_token = cq_token;
@@ -257,10 +254,8 @@
 	struct ehea_eq *eq;
 
 	eq = kzalloc(sizeof(*eq), GFP_KERNEL);
-	if (!eq) {
-		pr_err("no mem for eq\n");
+	if (!eq)
 		return NULL;
-	}
 
 	eq->adapter = adapter;
 	eq->attr.type = type;
@@ -428,10 +423,8 @@
 
 
 	qp = kzalloc(sizeof(*qp), GFP_KERNEL);
-	if (!qp) {
-		pr_err("no mem for qp\n");
+	if (!qp)
 		return NULL;
-	}
 
 	qp->adapter = adapter;
 
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 256bdb8..4989481 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -2190,11 +2190,10 @@
 {
 	struct emac_instance *dev = netdev_priv(ndev);
 
-	strcpy(info->driver, "ibm_emac");
-	strcpy(info->version, DRV_VERSION);
-	info->fw_version[0] = '\0';
-	sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
-		dev->cell_index, dev->ofdev->dev.of_node->full_name);
+	strlcpy(info->driver, "ibm_emac", sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
+		 dev->cell_index, dev->ofdev->dev.of_node->full_name);
 	info->regdump_len = emac_ethtool_get_regs_len(ndev);
 }
 
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index 50ea12b..1f7ecf5 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -528,12 +528,9 @@
 	irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde;
 
 	mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
-	if (!mal) {
-		printk(KERN_ERR
-		       "mal%d: out of memory allocating MAL structure!\n",
-		       index);
+	if (!mal)
 		return -ENOMEM;
-	}
+
 	mal->index = index;
 	mal->ofdev = ofdev;
 	mal->version = of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal2") ? 2 : 1;
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index f2fdbb7..c859771 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -637,7 +637,6 @@
 	adapter->bounce_buffer =
 	    kmalloc(netdev->mtu + IBMVETH_BUFF_OH, GFP_KERNEL);
 	if (!adapter->bounce_buffer) {
-		netdev_err(netdev, "unable to allocate bounce buffer\n");
 		rc = -ENOMEM;
 		goto err_out_free_irq;
 	}
@@ -722,9 +721,8 @@
 static void netdev_get_drvinfo(struct net_device *dev,
 			       struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, ibmveth_driver_name, sizeof(info->driver) - 1);
-	strncpy(info->version, ibmveth_driver_version,
-		sizeof(info->version) - 1);
+	strlcpy(info->driver, ibmveth_driver_name, sizeof(info->driver));
+	strlcpy(info->version, ibmveth_driver_version, sizeof(info->version));
 }
 
 static netdev_features_t ibmveth_fix_features(struct net_device *dev,
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index ddee406..3d5f6d4 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -6,7 +6,7 @@
 	bool "Intel devices"
 	default y
 	depends on PCI || PCI_MSI || ISA || ISA_DMA_API || ARM || \
-		   ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
+		   ARCH_ACORN || SNI_RM || SUN3 || \
 		   GSC || BVME6000 || MVME16x || \
 		   (ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR) || \
 		   EXPERIMENTAL
@@ -74,6 +74,7 @@
 	tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
 	depends on PCI && (!SPARC32 || BROKEN)
 	select CRC32
+	select PTP_1588_CLOCK
 	---help---
 	  This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
 	  ethernet family of adapters. For PCI or PCI-X e1000 adapters,
@@ -94,6 +95,8 @@
 	tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
 	depends on PCI
 	select PTP_1588_CLOCK
+	select I2C
+	select I2C_ALGOBIT
 	---help---
 	  This driver supports Intel(R) 82575/82576 gigabit ethernet family of
 	  adapters.  For more information on how to identify your adapter, go
@@ -112,6 +115,17 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called igb.
 
+config IGB_HWMON
+	bool "Intel(R) PCI-Express Gigabit adapters HWMON support"
+	default y
+	depends on IGB && HWMON && !(IGB=y && HWMON=m)
+	---help---
+	  Say Y if you want to expose thermal sensor data on Intel devices.
+
+	  Some of our devices contain thermal sensors, both external and internal.
+	  This data is available via the hwmon sysfs interface and exposes
+	  the onboard sensors.
+
 config IGB_DCA
 	bool "Direct Cache Access (DCA) Support"
 	default y
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index a59f077..ec800b0 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -2928,8 +2928,7 @@
 	e100_phy_init(nic);
 
 	memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
-	memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		if (!eeprom_bad_csum_allow) {
 			netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, aborting\n");
 			err = -EAGAIN;
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 2b6cd02..26d9cd5 100644
--- a/drivers/net/ethernet/intel/e1000/e1000.h
+++ b/drivers/net/ethernet/intel/e1000/e1000.h
@@ -81,68 +81,69 @@
 
 #include "e1000_hw.h"
 
-#define E1000_MAX_INTR 10
+#define E1000_MAX_INTR			10
 
 /* TX/RX descriptor defines */
-#define E1000_DEFAULT_TXD                  256
-#define E1000_MAX_TXD                      256
-#define E1000_MIN_TXD                       48
-#define E1000_MAX_82544_TXD               4096
+#define E1000_DEFAULT_TXD		256
+#define E1000_MAX_TXD			256
+#define E1000_MIN_TXD			48
+#define E1000_MAX_82544_TXD		4096
 
-#define E1000_DEFAULT_RXD                  256
-#define E1000_MAX_RXD                      256
-#define E1000_MIN_RXD                       48
-#define E1000_MAX_82544_RXD               4096
+#define E1000_DEFAULT_RXD		256
+#define E1000_MAX_RXD			256
+#define E1000_MIN_RXD			48
+#define E1000_MAX_82544_RXD		4096
 
 #define E1000_MIN_ITR_USECS		10 /* 100000 irq/sec */
 #define E1000_MAX_ITR_USECS		10000 /* 100    irq/sec */
 
 /* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+#define MAXIMUM_ETHERNET_VLAN_SIZE	1522
 
 /* Supported Rx Buffer Sizes */
-#define E1000_RXBUFFER_128   128    /* Used for packet split */
-#define E1000_RXBUFFER_256   256    /* Used for packet split */
-#define E1000_RXBUFFER_512   512
-#define E1000_RXBUFFER_1024  1024
-#define E1000_RXBUFFER_2048  2048
-#define E1000_RXBUFFER_4096  4096
-#define E1000_RXBUFFER_8192  8192
-#define E1000_RXBUFFER_16384 16384
+#define E1000_RXBUFFER_128		128    /* Used for packet split */
+#define E1000_RXBUFFER_256		256    /* Used for packet split */
+#define E1000_RXBUFFER_512		512
+#define E1000_RXBUFFER_1024		1024
+#define E1000_RXBUFFER_2048		2048
+#define E1000_RXBUFFER_4096		4096
+#define E1000_RXBUFFER_8192		8192
+#define E1000_RXBUFFER_16384		16384
 
 /* SmartSpeed delimiters */
-#define E1000_SMARTSPEED_DOWNSHIFT 3
-#define E1000_SMARTSPEED_MAX       15
+#define E1000_SMARTSPEED_DOWNSHIFT	3
+#define E1000_SMARTSPEED_MAX		15
 
 /* Packet Buffer allocations */
-#define E1000_PBA_BYTES_SHIFT 0xA
-#define E1000_TX_HEAD_ADDR_SHIFT 7
-#define E1000_PBA_TX_MASK 0xFFFF0000
+#define E1000_PBA_BYTES_SHIFT		0xA
+#define E1000_TX_HEAD_ADDR_SHIFT	7
+#define E1000_PBA_TX_MASK		0xFFFF0000
 
 /* Flow Control Watermarks */
-#define E1000_FC_HIGH_DIFF 0x1638  /* High: 5688 bytes below Rx FIFO size */
-#define E1000_FC_LOW_DIFF 0x1640   /* Low:  5696 bytes below Rx FIFO size */
+#define E1000_FC_HIGH_DIFF	0x1638 /* High: 5688 bytes below Rx FIFO size */
+#define E1000_FC_LOW_DIFF	0x1640 /* Low:  5696 bytes below Rx FIFO size */
 
-#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
+#define E1000_FC_PAUSE_TIME	0xFFFF /* pause for the max or until send xon */
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
 #define E1000_TX_QUEUE_WAKE	16
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define E1000_RX_BUFFER_WRITE	16	/* Must be power of 2 */
+#define E1000_RX_BUFFER_WRITE	16 /* Must be power of 2 */
 
-#define AUTO_ALL_MODES            0
-#define E1000_EEPROM_82544_APM    0x0004
-#define E1000_EEPROM_APME         0x0400
+#define AUTO_ALL_MODES		0
+#define E1000_EEPROM_82544_APM	0x0004
+#define E1000_EEPROM_APME	0x0400
 
 #ifndef E1000_MASTER_SLAVE
 /* Switch to override PHY master/slave setting */
 #define E1000_MASTER_SLAVE	e1000_ms_hw_default
 #endif
 
-#define E1000_MNG_VLAN_NONE (-1)
+#define E1000_MNG_VLAN_NONE	(-1)
 
 /* wrapper around a pointer to a socket buffer,
- * so a DMA handle can be stored along with the buffer */
+ * so a DMA handle can be stored along with the buffer
+ */
 struct e1000_buffer {
 	struct sk_buff *skb;
 	dma_addr_t dma;
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index 14e3051..43462d5 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -115,12 +115,12 @@
 	if (hw->media_type == e1000_media_type_copper) {
 
 		ecmd->supported = (SUPPORTED_10baseT_Half |
-		                   SUPPORTED_10baseT_Full |
-		                   SUPPORTED_100baseT_Half |
-		                   SUPPORTED_100baseT_Full |
-		                   SUPPORTED_1000baseT_Full|
-		                   SUPPORTED_Autoneg |
-		                   SUPPORTED_TP);
+				   SUPPORTED_10baseT_Full |
+				   SUPPORTED_100baseT_Half |
+				   SUPPORTED_100baseT_Full |
+				   SUPPORTED_1000baseT_Full|
+				   SUPPORTED_Autoneg |
+				   SUPPORTED_TP);
 		ecmd->advertising = ADVERTISED_TP;
 
 		if (hw->autoneg == 1) {
@@ -161,8 +161,8 @@
 		ethtool_cmd_speed_set(ecmd, adapter->link_speed);
 
 		/* unfortunately FULL_DUPLEX != DUPLEX_FULL
-		 *          and HALF_DUPLEX != DUPLEX_HALF */
-
+		 * and HALF_DUPLEX != DUPLEX_HALF
+		 */
 		if (adapter->link_duplex == FULL_DUPLEX)
 			ecmd->duplex = DUPLEX_FULL;
 		else
@@ -179,8 +179,7 @@
 	if ((hw->media_type == e1000_media_type_copper) &&
 	    netif_carrier_ok(netdev))
 		ecmd->eth_tp_mdix = (!!adapter->phy_info.mdix_mode ?
-							ETH_TP_MDI_X :
-							ETH_TP_MDI);
+				     ETH_TP_MDI_X : ETH_TP_MDI);
 	else
 		ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
 
@@ -197,8 +196,7 @@
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
-	/*
-	 * MDI setting is only allowed when autoneg enabled because
+	/* MDI setting is only allowed when autoneg enabled because
 	 * some hardware doesn't allow MDI setting when speed or
 	 * duplex is forced.
 	 */
@@ -224,8 +222,8 @@
 				     ADVERTISED_Autoneg;
 		else
 			hw->autoneg_advertised = ecmd->advertising |
-			                         ADVERTISED_TP |
-			                         ADVERTISED_Autoneg;
+						 ADVERTISED_TP |
+						 ADVERTISED_Autoneg;
 		ecmd->advertising = hw->autoneg_advertised;
 	} else {
 		u32 speed = ethtool_cmd_speed(ecmd);
@@ -260,8 +258,7 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
-	/*
-	 * If the link is not reported up to netdev, interrupts are disabled,
+	/* If the link is not reported up to netdev, interrupts are disabled,
 	 * and so the physical link state may have changed since we last
 	 * looked. Set get_link_status to make sure that the true link
 	 * state is interrogated, rather than pulling a cached and possibly
@@ -484,7 +481,7 @@
 		le16_to_cpus(&eeprom_buff[i]);
 
 	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
-			eeprom->len);
+	       eeprom->len);
 	kfree(eeprom_buff);
 
 	return ret_val;
@@ -517,15 +514,17 @@
 	ptr = (void *)eeprom_buff;
 
 	if (eeprom->offset & 1) {
-		/* need read/modify/write of first changed EEPROM word */
-		/* only the second byte of the word is being modified */
+		/* need read/modify/write of first changed EEPROM word
+		 * only the second byte of the word is being modified
+		 */
 		ret_val = e1000_read_eeprom(hw, first_word, 1,
 					    &eeprom_buff[0]);
 		ptr++;
 	}
 	if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
-		/* need read/modify/write of last changed EEPROM word */
-		/* only the first byte of the word is being modified */
+		/* need read/modify/write of last changed EEPROM word
+		 * only the first byte of the word is being modified
+		 */
 		ret_val = e1000_read_eeprom(hw, last_word, 1,
 		                  &eeprom_buff[last_word - first_word]);
 	}
@@ -606,11 +605,13 @@
 	rx_old = adapter->rx_ring;
 
 	err = -ENOMEM;
-	txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL);
+	txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring),
+		       GFP_KERNEL);
 	if (!txdr)
 		goto err_alloc_tx;
 
-	rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL);
+	rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring),
+		       GFP_KERNEL);
 	if (!rxdr)
 		goto err_alloc_rx;
 
@@ -619,12 +620,12 @@
 
 	rxdr->count = max(ring->rx_pending,(u32)E1000_MIN_RXD);
 	rxdr->count = min(rxdr->count,(u32)(mac_type < e1000_82544 ?
-		E1000_MAX_RXD : E1000_MAX_82544_RXD));
+			  E1000_MAX_RXD : E1000_MAX_82544_RXD));
 	rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
 
 	txdr->count = max(ring->tx_pending,(u32)E1000_MIN_TXD);
 	txdr->count = min(txdr->count,(u32)(mac_type < e1000_82544 ?
-		E1000_MAX_TXD : E1000_MAX_82544_TXD));
+			  E1000_MAX_TXD : E1000_MAX_82544_TXD));
 	txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
 
 	for (i = 0; i < adapter->num_tx_queues; i++)
@@ -642,7 +643,8 @@
 			goto err_setup_tx;
 
 		/* save the new, restore the old in order to free it,
-		 * then restore the new back again */
+		 * then restore the new back again
+		 */
 
 		adapter->rx_ring = rx_old;
 		adapter->tx_ring = tx_old;
@@ -784,7 +786,6 @@
 	REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
 
 	if (hw->mac_type >= e1000_82543) {
-
 		REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF);
 		REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
 		REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
@@ -795,14 +796,11 @@
 			REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
 			                 0xFFFFFFFF);
 		}
-
 	} else {
-
 		REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
 		REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF);
 		REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF);
 		REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF);
-
 	}
 
 	value = E1000_MC_TBL_SIZE;
@@ -858,13 +856,14 @@
 
 	*data = 0;
 
-	/* NOTE: we don't test MSI interrupts here, yet */
-	/* Hook up test interrupt handler just for this test */
+	/* NOTE: we don't test MSI interrupts here, yet
+	 * Hook up test interrupt handler just for this test
+	 */
 	if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
-	                 netdev))
+			 netdev))
 		shared_int = false;
 	else if (request_irq(irq, e1000_test_intr, IRQF_SHARED,
-	         netdev->name, netdev)) {
+			     netdev->name, netdev)) {
 		*data = 1;
 		return -1;
 	}
@@ -1253,14 +1252,15 @@
 	ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
 			E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
 			E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
-			E1000_CTRL_FD);	 /* Force Duplex to FULL */
+			E1000_CTRL_FD); /* Force Duplex to FULL */
 
 	if (hw->media_type == e1000_media_type_copper &&
 	   hw->phy_type == e1000_phy_m88)
 		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
 	else {
 		/* Set the ILOS bit on the fiber Nic is half
-		 * duplex link is detected. */
+		 * duplex link is detected.
+		 */
 		stat_reg = er32(STATUS);
 		if ((stat_reg & E1000_STATUS_FD) == 0)
 			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
@@ -1446,7 +1446,7 @@
 
 			ret_val = e1000_check_lbtest_frame(
 					rxdr->buffer_info[l].skb,
-				   	1024);
+					1024);
 			if (!ret_val)
 				good_cnt++;
 			if (unlikely(++l == rxdr->count)) l = 0;
@@ -1493,7 +1493,8 @@
 		hw->serdes_has_link = false;
 
 		/* On some blade server designs, link establishment
-		 * could take as long as 2-3 minutes */
+		 * could take as long as 2-3 minutes
+		 */
 		do {
 			e1000_check_for_link(hw);
 			if (hw->serdes_has_link)
@@ -1545,7 +1546,8 @@
 		e_info(hw, "offline testing starting\n");
 
 		/* Link test performed before hardware reset so autoneg doesn't
-		 * interfere with test result */
+		 * interfere with test result
+		 */
 		if (e1000_link_test(adapter, &data[4]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
@@ -1639,7 +1641,8 @@
 	default:
 		/* dual port cards only support WoL on port A from now on
 		 * unless it was enabled in the eeprom for port B
-		 * so exclude FUNC_1 ports from having WoL enabled */
+		 * so exclude FUNC_1 ports from having WoL enabled
+		 */
 		if (er32(STATUS) & E1000_STATUS_FUNC_1 &&
 		    !adapter->eeprom_wol) {
 			wol->supported = 0;
@@ -1663,7 +1666,8 @@
 	wol->wolopts = 0;
 
 	/* this function will set ->supported = 0 and return 1 if wol is not
-	 * supported by this hardware */
+	 * supported by this hardware
+	 */
 	if (e1000_wol_exclusion(adapter, wol) ||
 	    !device_can_wakeup(&adapter->pdev->dev))
 		return;
@@ -1839,7 +1843,7 @@
 		data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
 			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
 	}
-/*	BUG_ON(i != E1000_STATS_LEN); */
+/* BUG_ON(i != E1000_STATS_LEN); */
 }
 
 static void e1000_get_strings(struct net_device *netdev, u32 stringset,
@@ -1859,37 +1863,37 @@
 			       ETH_GSTRING_LEN);
 			p += ETH_GSTRING_LEN;
 		}
-/*		BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */
+		/* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */
 		break;
 	}
 }
 
 static const struct ethtool_ops e1000_ethtool_ops = {
-	.get_settings           = e1000_get_settings,
-	.set_settings           = e1000_set_settings,
-	.get_drvinfo            = e1000_get_drvinfo,
-	.get_regs_len           = e1000_get_regs_len,
-	.get_regs               = e1000_get_regs,
-	.get_wol                = e1000_get_wol,
-	.set_wol                = e1000_set_wol,
-	.get_msglevel           = e1000_get_msglevel,
-	.set_msglevel           = e1000_set_msglevel,
-	.nway_reset             = e1000_nway_reset,
-	.get_link               = e1000_get_link,
-	.get_eeprom_len         = e1000_get_eeprom_len,
-	.get_eeprom             = e1000_get_eeprom,
-	.set_eeprom             = e1000_set_eeprom,
-	.get_ringparam          = e1000_get_ringparam,
-	.set_ringparam          = e1000_set_ringparam,
-	.get_pauseparam         = e1000_get_pauseparam,
-	.set_pauseparam         = e1000_set_pauseparam,
-	.self_test              = e1000_diag_test,
-	.get_strings            = e1000_get_strings,
-	.set_phys_id            = e1000_set_phys_id,
-	.get_ethtool_stats      = e1000_get_ethtool_stats,
-	.get_sset_count         = e1000_get_sset_count,
-	.get_coalesce           = e1000_get_coalesce,
-	.set_coalesce           = e1000_set_coalesce,
+	.get_settings		= e1000_get_settings,
+	.set_settings		= e1000_set_settings,
+	.get_drvinfo		= e1000_get_drvinfo,
+	.get_regs_len		= e1000_get_regs_len,
+	.get_regs		= e1000_get_regs,
+	.get_wol		= e1000_get_wol,
+	.set_wol		= e1000_set_wol,
+	.get_msglevel		= e1000_get_msglevel,
+	.set_msglevel		= e1000_set_msglevel,
+	.nway_reset		= e1000_nway_reset,
+	.get_link		= e1000_get_link,
+	.get_eeprom_len		= e1000_get_eeprom_len,
+	.get_eeprom		= e1000_get_eeprom,
+	.set_eeprom		= e1000_set_eeprom,
+	.get_ringparam		= e1000_get_ringparam,
+	.set_ringparam		= e1000_set_ringparam,
+	.get_pauseparam		= e1000_get_pauseparam,
+	.set_pauseparam		= e1000_set_pauseparam,
+	.self_test		= e1000_diag_test,
+	.get_strings		= e1000_get_strings,
+	.set_phys_id		= e1000_set_phys_id,
+	.get_ethtool_stats	= e1000_get_ethtool_stats,
+	.get_sset_count		= e1000_get_sset_count,
+	.get_coalesce		= e1000_get_coalesce,
+	.set_coalesce		= e1000_set_coalesce,
 	.get_ts_info		= ethtool_op_get_ts_info,
 };
 
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 8fedd24..2879b96 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -164,8 +164,9 @@
 	if (hw->phy_init_script) {
 		msleep(20);
 
-		/* Save off the current value of register 0x2F5B to be restored at
-		 * the end of this routine. */
+		/* Save off the current value of register 0x2F5B to be restored
+		 * at the end of this routine.
+		 */
 		ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
 
 		/* Disabled the PHY transmitter */
@@ -466,7 +467,8 @@
 	case e1000_82541:
 	case e1000_82541_rev_2:
 		/* These controllers can't ack the 64-bit write when issuing the
-		 * reset, so use IO-mapping as a workaround to issue the reset */
+		 * reset, so use IO-mapping as a workaround to issue the reset
+		 */
 		E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
 		break;
 	case e1000_82545_rev_3:
@@ -480,9 +482,9 @@
 		break;
 	}
 
-	/* After MAC reset, force reload of EEPROM to restore power-on settings to
-	 * device.  Later controllers reload the EEPROM automatically, so just wait
-	 * for reload to complete.
+	/* After MAC reset, force reload of EEPROM to restore power-on settings
+	 * to device.  Later controllers reload the EEPROM automatically, so
+	 * just wait for reload to complete.
 	 */
 	switch (hw->mac_type) {
 	case e1000_82542_rev2_0:
@@ -591,8 +593,8 @@
 		msleep(5);
 	}
 
-	/* Setup the receive address. This involves initializing all of the Receive
-	 * Address Registers (RARs 0 - 15).
+	/* Setup the receive address. This involves initializing all of the
+	 * Receive Address Registers (RARs 0 - 15).
 	 */
 	e1000_init_rx_addrs(hw);
 
@@ -611,7 +613,8 @@
 	for (i = 0; i < mta_size; i++) {
 		E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
 		/* use write flush to prevent Memory Write Block (MWB) from
-		 * occurring when accessing our register space */
+		 * occurring when accessing our register space
+		 */
 		E1000_WRITE_FLUSH();
 	}
 
@@ -630,7 +633,9 @@
 	case e1000_82546_rev_3:
 		break;
 	default:
-		/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+		/* Workaround for PCI-X problem when BIOS sets MMRBC
+		 * incorrectly.
+		 */
 		if (hw->bus_type == e1000_bus_type_pcix
 		    && e1000_pcix_get_mmrbc(hw) > 2048)
 			e1000_pcix_set_mmrbc(hw, 2048);
@@ -660,7 +665,8 @@
 	    hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
 		ctrl_ext = er32(CTRL_EXT);
 		/* Relaxed ordering must be disabled to avoid a parity
-		 * error crash in a PCI slot. */
+		 * error crash in a PCI slot.
+		 */
 		ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
 		ew32(CTRL_EXT, ctrl_ext);
 	}
@@ -810,8 +816,9 @@
 		ew32(FCRTL, 0);
 		ew32(FCRTH, 0);
 	} else {
-		/* We need to set up the Receive Threshold high and low water marks
-		 * as well as (optionally) enabling the transmission of XON frames.
+		/* We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
 		 */
 		if (hw->fc_send_xon) {
 			ew32(FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
@@ -868,42 +875,46 @@
 	e1000_config_collision_dist(hw);
 
 	/* Check for a software override of the flow control settings, and setup
-	 * the device accordingly.  If auto-negotiation is enabled, then software
-	 * will have to set the "PAUSE" bits to the correct value in the Tranmsit
-	 * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
-	 * auto-negotiation is disabled, then software will have to manually
-	 * configure the two flow control enable bits in the CTRL register.
+	 * the device accordingly.  If auto-negotiation is enabled, then
+	 * software will have to set the "PAUSE" bits to the correct value in
+	 * the Tranmsit Config Word Register (TXCW) and re-start
+	 * auto-negotiation.  However, if auto-negotiation is disabled, then
+	 * software will have to manually configure the two flow control enable
+	 * bits in the CTRL register.
 	 *
 	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames, but
-	 *          not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames but we do
-	 *          not support receiving pause frames).
-	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
+	 *  0:  Flow control is completely disabled
+	 *  1:  Rx flow control is enabled (we can receive pause frames, but
+	 *      not send pause frames).
+	 *  2:  Tx flow control is enabled (we can send pause frames but we do
+	 *      not support receiving pause frames).
+	 *  3:  Both Rx and TX flow control (symmetric) are enabled.
 	 */
 	switch (hw->fc) {
 	case E1000_FC_NONE:
-		/* Flow control is completely disabled by a software over-ride. */
+		/* Flow ctrl is completely disabled by a software over-ride */
 		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
 		break;
 	case E1000_FC_RX_PAUSE:
-		/* RX Flow control is enabled and TX Flow control is disabled by a
-		 * software over-ride. Since there really isn't a way to advertise
-		 * that we are capable of RX Pause ONLY, we will advertise that we
-		 * support both symmetric and asymmetric RX PAUSE. Later, we will
-		 *  disable the adapter's ability to send PAUSE frames.
+		/* Rx Flow control is enabled and Tx Flow control is disabled by
+		 * a software over-ride. Since there really isn't a way to
+		 * advertise that we are capable of Rx Pause ONLY, we will
+		 * advertise that we support both symmetric and asymmetric Rx
+		 * PAUSE. Later, we will disable the adapter's ability to send
+		 * PAUSE frames.
 		 */
 		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
 		break;
 	case E1000_FC_TX_PAUSE:
-		/* TX Flow control is enabled, and RX Flow control is disabled, by a
-		 * software over-ride.
+		/* Tx Flow control is enabled, and Rx Flow control is disabled,
+		 * by a software over-ride.
 		 */
 		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
 		break;
 	case E1000_FC_FULL:
-		/* Flow control (both RX and TX) is enabled by a software over-ride. */
+		/* Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
 		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
 		break;
 	default:
@@ -912,11 +923,11 @@
 		break;
 	}
 
-	/* Since auto-negotiation is enabled, take the link out of reset (the link
-	 * will be in reset, because we previously reset the chip). This will
-	 * restart auto-negotiation.  If auto-negotiation is successful then the
-	 * link-up status bit will be set and the flow control enable bits (RFCE
-	 * and TFCE) will be set according to their negotiated value.
+	/* Since auto-negotiation is enabled, take the link out of reset (the
+	 * link will be in reset, because we previously reset the chip). This
+	 * will restart auto-negotiation.  If auto-negotiation is successful
+	 * then the link-up status bit will be set and the flow control enable
+	 * bits (RFCE and TFCE) will be set according to their negotiated value.
 	 */
 	e_dbg("Auto-negotiation enabled\n");
 
@@ -927,11 +938,12 @@
 	hw->txcw = txcw;
 	msleep(1);
 
-	/* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
-	 * indication in the Device Status Register.  Time-out if a link isn't
-	 * seen in 500 milliseconds seconds (Auto-negotiation should complete in
-	 * less than 500 milliseconds even if the other end is doing it in SW).
-	 * For internal serdes, we just assume a signal is present, then poll.
+	/* If we have a signal (the cable is plugged in) then poll for a
+	 * "Link-Up" indication in the Device Status Register.  Time-out if a
+	 * link isn't seen in 500 milliseconds seconds (Auto-negotiation should
+	 * complete in less than 500 milliseconds even if the other end is doing
+	 * it in SW). For internal serdes, we just assume a signal is present,
+	 * then poll.
 	 */
 	if (hw->media_type == e1000_media_type_internal_serdes ||
 	    (er32(CTRL) & E1000_CTRL_SWDPIN1) == signal) {
@@ -946,9 +958,9 @@
 			e_dbg("Never got a valid link from auto-neg!!!\n");
 			hw->autoneg_failed = 1;
 			/* AutoNeg failed to achieve a link, so we'll call
-			 * e1000_check_for_link. This routine will force the link up if
-			 * we detect a signal. This will allow us to communicate with
-			 * non-autonegotiating link partners.
+			 * e1000_check_for_link. This routine will force the
+			 * link up if we detect a signal. This will allow us to
+			 * communicate with non-autonegotiating link partners.
 			 */
 			ret_val = e1000_check_for_link(hw);
 			if (ret_val) {
@@ -1042,9 +1054,9 @@
 	e_dbg("e1000_copper_link_preconfig");
 
 	ctrl = er32(CTRL);
-	/* With 82543, we need to force speed and duplex on the MAC equal to what
-	 * the PHY speed and duplex configuration is. In addition, we need to
-	 * perform a hardware reset on the PHY to take it out of reset.
+	/* With 82543, we need to force speed and duplex on the MAC equal to
+	 * what the PHY speed and duplex configuration is. In addition, we need
+	 * to perform a hardware reset on the PHY to take it out of reset.
 	 */
 	if (hw->mac_type > e1000_82543) {
 		ctrl |= E1000_CTRL_SLU;
@@ -1175,7 +1187,8 @@
 
 		/* when autonegotiation advertisement is only 1000Mbps then we
 		 * should disable SmartSpeed and enable Auto MasterSlave
-		 * resolution as hardware default. */
+		 * resolution as hardware default.
+		 */
 		if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
 			/* Disable SmartSpeed */
 			ret_val =
@@ -1485,13 +1498,15 @@
 
 	if (hw->autoneg) {
 		/* Setup autoneg and flow control advertisement
-		 * and perform autonegotiation */
+		 * and perform autonegotiation
+		 */
 		ret_val = e1000_copper_link_autoneg(hw);
 		if (ret_val)
 			return ret_val;
 	} else {
 		/* PHY will be set to 10H, 10F, 100H,or 100F
-		 * depending on value from forced_speed_duplex. */
+		 * depending on value from forced_speed_duplex.
+		 */
 		e_dbg("Forcing speed and duplex\n");
 		ret_val = e1000_phy_force_speed_duplex(hw);
 		if (ret_val) {
@@ -1609,7 +1624,8 @@
 	 * setup the PHY advertisement registers accordingly.  If
 	 * auto-negotiation is enabled, then software will have to set the
 	 * "PAUSE" bits to the correct value in the Auto-Negotiation
-	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start
+	 * auto-negotiation.
 	 *
 	 * The possible values of the "fc" parameter are:
 	 *      0:  Flow control is completely disabled
@@ -1636,7 +1652,7 @@
 		 * capable of RX Pause ONLY, we will advertise that we
 		 * support both symmetric and asymmetric RX PAUSE.  Later
 		 * (in e1000_config_fc_after_link_up) we will disable the
-		 *hw's ability to send PAUSE frames.
+		 * hw's ability to send PAUSE frames.
 		 */
 		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
 		break;
@@ -1720,15 +1736,15 @@
 	/* Are we forcing Full or Half Duplex? */
 	if (hw->forced_speed_duplex == e1000_100_full ||
 	    hw->forced_speed_duplex == e1000_10_full) {
-		/* We want to force full duplex so we SET the full duplex bits in the
-		 * Device and MII Control Registers.
+		/* We want to force full duplex so we SET the full duplex bits
+		 * in the Device and MII Control Registers.
 		 */
 		ctrl |= E1000_CTRL_FD;
 		mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
 		e_dbg("Full Duplex\n");
 	} else {
-		/* We want to force half duplex so we CLEAR the full duplex bits in
-		 * the Device and MII Control Registers.
+		/* We want to force half duplex so we CLEAR the full duplex bits
+		 * in the Device and MII Control Registers.
 		 */
 		ctrl &= ~E1000_CTRL_FD;
 		mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
@@ -1762,8 +1778,8 @@
 		if (ret_val)
 			return ret_val;
 
-		/* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
-		 * forced whenever speed are duplex are forced.
+		/* Clear Auto-Crossover to force MDI manually. M88E1000 requires
+		 * MDI forced whenever speed are duplex are forced.
 		 */
 		phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
 		ret_val =
@@ -1814,10 +1830,10 @@
 		e_dbg("Waiting for forced speed/duplex link.\n");
 		mii_status_reg = 0;
 
-		/* We will wait for autoneg to complete or 4.5 seconds to expire. */
+		/* Wait for autoneg to complete or 4.5 seconds to expire */
 		for (i = PHY_FORCE_TIME; i > 0; i--) {
-			/* Read the MII Status Register and wait for Auto-Neg Complete bit
-			 * to be set.
+			/* Read the MII Status Register and wait for Auto-Neg
+			 * Complete bit to be set.
 			 */
 			ret_val =
 			    e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
@@ -1834,20 +1850,24 @@
 			msleep(100);
 		}
 		if ((i == 0) && (hw->phy_type == e1000_phy_m88)) {
-			/* We didn't get link.  Reset the DSP and wait again for link. */
+			/* We didn't get link.  Reset the DSP and wait again
+			 * for link.
+			 */
 			ret_val = e1000_phy_reset_dsp(hw);
 			if (ret_val) {
 				e_dbg("Error Resetting PHY DSP\n");
 				return ret_val;
 			}
 		}
-		/* This loop will early-out if the link condition has been met.  */
+		/* This loop will early-out if the link condition has been
+		 * met
+		 */
 		for (i = PHY_FORCE_TIME; i > 0; i--) {
 			if (mii_status_reg & MII_SR_LINK_STATUS)
 				break;
 			msleep(100);
-			/* Read the MII Status Register and wait for Auto-Neg Complete bit
-			 * to be set.
+			/* Read the MII Status Register and wait for Auto-Neg
+			 * Complete bit to be set.
 			 */
 			ret_val =
 			    e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
@@ -1862,9 +1882,10 @@
 	}
 
 	if (hw->phy_type == e1000_phy_m88) {
-		/* Because we reset the PHY above, we need to re-force TX_CLK in the
-		 * Extended PHY Specific Control Register to 25MHz clock.  This value
-		 * defaults back to a 2.5MHz clock when the PHY is reset.
+		/* Because we reset the PHY above, we need to re-force TX_CLK in
+		 * the Extended PHY Specific Control Register to 25MHz clock.
+		 * This value defaults back to a 2.5MHz clock when the PHY is
+		 * reset.
 		 */
 		ret_val =
 		    e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
@@ -1879,8 +1900,9 @@
 		if (ret_val)
 			return ret_val;
 
-		/* In addition, because of the s/w reset above, we need to enable CRS on
-		 * TX.  This must be set for both full and half duplex operation.
+		/* In addition, because of the s/w reset above, we need to
+		 * enable CRS on Tx.  This must be set for both full and half
+		 * duplex operation.
 		 */
 		ret_val =
 		    e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
@@ -1951,7 +1973,8 @@
 	e_dbg("e1000_config_mac_to_phy");
 
 	/* 82544 or newer MAC, Auto Speed Detection takes care of
-	 * MAC speed/duplex configuration.*/
+	 * MAC speed/duplex configuration.
+	 */
 	if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100))
 		return E1000_SUCCESS;
 
@@ -1985,7 +2008,7 @@
 		 * registers depending on negotiated values.
 		 */
 		ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
-		                             &phy_data);
+					     &phy_data);
 		if (ret_val)
 			return ret_val;
 
@@ -2002,7 +2025,7 @@
 		if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
 			ctrl |= E1000_CTRL_SPD_1000;
 		else if ((phy_data & M88E1000_PSSR_SPEED) ==
-		         M88E1000_PSSR_100MBS)
+			 M88E1000_PSSR_100MBS)
 			ctrl |= E1000_CTRL_SPD_100;
 	}
 
@@ -2135,9 +2158,9 @@
 		if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
 			/* The AutoNeg process has completed, so we now need to
 			 * read both the Auto Negotiation Advertisement Register
-			 * (Address 4) and the Auto_Negotiation Base Page Ability
-			 * Register (Address 5) to determine how flow control was
-			 * negotiated.
+			 * (Address 4) and the Auto_Negotiation Base Page
+			 * Ability Register (Address 5) to determine how flow
+			 * control was negotiated.
 			 */
 			ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
 						     &mii_nway_adv_reg);
@@ -2148,18 +2171,19 @@
 			if (ret_val)
 				return ret_val;
 
-			/* Two bits in the Auto Negotiation Advertisement Register
-			 * (Address 4) and two bits in the Auto Negotiation Base
-			 * Page Ability Register (Address 5) determine flow control
-			 * for both the PHY and the link partner.  The following
-			 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
-			 * 1999, describes these PAUSE resolution bits and how flow
-			 * control is determined based upon these settings.
+			/* Two bits in the Auto Negotiation Advertisement
+			 * Register (Address 4) and two bits in the Auto
+			 * Negotiation Base Page Ability Register (Address 5)
+			 * determine flow control for both the PHY and the link
+			 * partner.  The following table, taken out of the IEEE
+			 * 802.3ab/D6.0 dated March 25, 1999, describes these
+			 * PAUSE resolution bits and how flow control is
+			 * determined based upon these settings.
 			 * NOTE:  DC = Don't Care
 			 *
 			 *   LOCAL DEVICE  |   LINK PARTNER
 			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
-			 *-------|---------|-------|---------|--------------------
+			 *-------|---------|-------|---------|------------------
 			 *   0   |    0    |  DC   |   DC    | E1000_FC_NONE
 			 *   0   |    1    |   0   |   DC    | E1000_FC_NONE
 			 *   0   |    1    |   1   |    0    | E1000_FC_NONE
@@ -2178,17 +2202,18 @@
 			 *
 			 *   LOCAL DEVICE  |   LINK PARTNER
 			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-			 *-------|---------|-------|---------|--------------------
+			 *-------|---------|-------|---------|------------------
 			 *   1   |   DC    |   1   |   DC    | E1000_FC_FULL
 			 *
 			 */
 			if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
 			    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
-				/* Now we need to check if the user selected RX ONLY
-				 * of pause frames.  In this case, we had to advertise
-				 * FULL flow control because we could not advertise RX
-				 * ONLY. Hence, we must now check to see if we need to
-				 * turn OFF  the TRANSMISSION of PAUSE frames.
+				/* Now we need to check if the user selected Rx
+				 * ONLY of pause frames.  In this case, we had
+				 * to advertise FULL flow control because we
+				 * could not advertise Rx ONLY. Hence, we must
+				 * now check to see if we need to turn OFF the
+				 * TRANSMISSION of PAUSE frames.
 				 */
 				if (hw->original_fc == E1000_FC_FULL) {
 					hw->fc = E1000_FC_FULL;
@@ -2203,7 +2228,7 @@
 			 *
 			 *   LOCAL DEVICE  |   LINK PARTNER
 			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-			 *-------|---------|-------|---------|--------------------
+			 *-------|---------|-------|---------|------------------
 			 *   0   |    1    |   1   |    1    | E1000_FC_TX_PAUSE
 			 *
 			 */
@@ -2220,7 +2245,7 @@
 			 *
 			 *   LOCAL DEVICE  |   LINK PARTNER
 			 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-			 *-------|---------|-------|---------|--------------------
+			 *-------|---------|-------|---------|------------------
 			 *   1   |    1    |   0   |    1    | E1000_FC_RX_PAUSE
 			 *
 			 */
@@ -2233,25 +2258,27 @@
 				e_dbg
 				    ("Flow Control = RX PAUSE frames only.\n");
 			}
-			/* Per the IEEE spec, at this point flow control should be
-			 * disabled.  However, we want to consider that we could
-			 * be connected to a legacy switch that doesn't advertise
-			 * desired flow control, but can be forced on the link
-			 * partner.  So if we advertised no flow control, that is
-			 * what we will resolve to.  If we advertised some kind of
-			 * receive capability (Rx Pause Only or Full Flow Control)
-			 * and the link partner advertised none, we will configure
-			 * ourselves to enable Rx Flow Control only.  We can do
-			 * this safely for two reasons:  If the link partner really
-			 * didn't want flow control enabled, and we enable Rx, no
-			 * harm done since we won't be receiving any PAUSE frames
-			 * anyway.  If the intent on the link partner was to have
-			 * flow control enabled, then by us enabling RX only, we
-			 * can at least receive pause frames and process them.
-			 * This is a good idea because in most cases, since we are
-			 * predominantly a server NIC, more times than not we will
-			 * be asked to delay transmission of packets than asking
-			 * our link partner to pause transmission of frames.
+			/* Per the IEEE spec, at this point flow control should
+			 * be disabled.  However, we want to consider that we
+			 * could be connected to a legacy switch that doesn't
+			 * advertise desired flow control, but can be forced on
+			 * the link partner.  So if we advertised no flow
+			 * control, that is what we will resolve to.  If we
+			 * advertised some kind of receive capability (Rx Pause
+			 * Only or Full Flow Control) and the link partner
+			 * advertised none, we will configure ourselves to
+			 * enable Rx Flow Control only.  We can do this safely
+			 * for two reasons:  If the link partner really
+			 * didn't want flow control enabled, and we enable Rx,
+			 * no harm done since we won't be receiving any PAUSE
+			 * frames anyway.  If the intent on the link partner was
+			 * to have flow control enabled, then by us enabling Rx
+			 * only, we can at least receive pause frames and
+			 * process them. This is a good idea because in most
+			 * cases, since we are predominantly a server NIC, more
+			 * times than not we will be asked to delay transmission
+			 * of packets than asking our link partner to pause
+			 * transmission of frames.
 			 */
 			else if ((hw->original_fc == E1000_FC_NONE ||
 				  hw->original_fc == E1000_FC_TX_PAUSE) ||
@@ -2316,8 +2343,7 @@
 	status = er32(STATUS);
 	rxcw = er32(RXCW);
 
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
+	/* If we don't have link (auto-negotiation failed or link partner
 	 * cannot auto-negotiate), and our link partner is not trying to
 	 * auto-negotiate with us (we are receiving idles or data),
 	 * we need to force link up. We also need to give auto-negotiation
@@ -2346,8 +2372,7 @@
 			goto out;
 		}
 	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
+		/* If we are forcing link and we are receiving /C/ ordered
 		 * sets, re-enable auto-negotiation in the TXCW register
 		 * and disable forced link in the Device Control register
 		 * in an attempt to auto-negotiate with our link partner.
@@ -2358,8 +2383,7 @@
 
 		hw->serdes_has_link = true;
 	} else if (!(E1000_TXCW_ANE & er32(TXCW))) {
-		/*
-		 * If we force link for non-auto-negotiation switch, check
+		/* If we force link for non-auto-negotiation switch, check
 		 * link status based on MAC synchronization for internal
 		 * serdes media type.
 		 */
@@ -2468,15 +2492,17 @@
 
 		if (phy_data & MII_SR_LINK_STATUS) {
 			hw->get_link_status = false;
-			/* Check if there was DownShift, must be checked immediately after
-			 * link-up */
+			/* Check if there was DownShift, must be checked
+			 * immediately after link-up
+			 */
 			e1000_check_downshift(hw);
 
 			/* If we are on 82544 or 82543 silicon and speed/duplex
-			 * are forced to 10H or 10F, then we will implement the polarity
-			 * reversal workaround.  We disable interrupts first, and upon
-			 * returning, place the devices interrupt state to its previous
-			 * value except for the link status change interrupt which will
+			 * are forced to 10H or 10F, then we will implement the
+			 * polarity reversal workaround.  We disable interrupts
+			 * first, and upon returning, place the devices
+			 * interrupt state to its previous value except for the
+			 * link status change interrupt which will
 			 * happen due to the execution of this workaround.
 			 */
 
@@ -2527,9 +2553,10 @@
 			}
 		}
 
-		/* Configure Flow Control now that Auto-Neg has completed. First, we
-		 * need to restore the desired flow control settings because we may
-		 * have had to re-autoneg with a different link partner.
+		/* Configure Flow Control now that Auto-Neg has completed.
+		 * First, we need to restore the desired flow control settings
+		 * because we may have had to re-autoneg with a different link
+		 * partner.
 		 */
 		ret_val = e1000_config_fc_after_link_up(hw);
 		if (ret_val) {
@@ -2538,11 +2565,12 @@
 		}
 
 		/* At this point we know that we are on copper and we have
-		 * auto-negotiated link.  These are conditions for checking the link
-		 * partner capability register.  We use the link speed to determine if
-		 * TBI compatibility needs to be turned on or off.  If the link is not
-		 * at gigabit speed, then TBI compatibility is not needed.  If we are
-		 * at gigabit speed, we turn on TBI compatibility.
+		 * auto-negotiated link.  These are conditions for checking the
+		 * link partner capability register.  We use the link speed to
+		 * determine if TBI compatibility needs to be turned on or off.
+		 * If the link is not at gigabit speed, then TBI compatibility
+		 * is not needed.  If we are at gigabit speed, we turn on TBI
+		 * compatibility.
 		 */
 		if (hw->tbi_compatibility_en) {
 			u16 speed, duplex;
@@ -2554,20 +2582,23 @@
 				return ret_val;
 			}
 			if (speed != SPEED_1000) {
-				/* If link speed is not set to gigabit speed, we do not need
-				 * to enable TBI compatibility.
+				/* If link speed is not set to gigabit speed, we
+				 * do not need to enable TBI compatibility.
 				 */
 				if (hw->tbi_compatibility_on) {
-					/* If we previously were in the mode, turn it off. */
+					/* If we previously were in the mode,
+					 * turn it off.
+					 */
 					rctl = er32(RCTL);
 					rctl &= ~E1000_RCTL_SBP;
 					ew32(RCTL, rctl);
 					hw->tbi_compatibility_on = false;
 				}
 			} else {
-				/* If TBI compatibility is was previously off, turn it on. For
-				 * compatibility with a TBI link partner, we will store bad
-				 * packets. Some frames have an additional byte on the end and
+				/* If TBI compatibility is was previously off,
+				 * turn it on. For compatibility with a TBI link
+				 * partner, we will store bad packets. Some
+				 * frames have an additional byte on the end and
 				 * will look like CRC errors to to the hardware.
 				 */
 				if (!hw->tbi_compatibility_on) {
@@ -2629,9 +2660,9 @@
 		*duplex = FULL_DUPLEX;
 	}
 
-	/* IGP01 PHY may advertise full duplex operation after speed downgrade even
-	 * if it is operating at half duplex.  Here we set the duplex settings to
-	 * match the duplex in the link partner's capabilities.
+	/* IGP01 PHY may advertise full duplex operation after speed downgrade
+	 * even if it is operating at half duplex.  Here we set the duplex
+	 * settings to match the duplex in the link partner's capabilities.
 	 */
 	if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
 		ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
@@ -2697,8 +2728,8 @@
  */
 static void e1000_raise_mdi_clk(struct e1000_hw *hw, u32 *ctrl)
 {
-	/* Raise the clock input to the Management Data Clock (by setting the MDC
-	 * bit), and then delay 10 microseconds.
+	/* Raise the clock input to the Management Data Clock (by setting the
+	 * MDC bit), and then delay 10 microseconds.
 	 */
 	ew32(CTRL, (*ctrl | E1000_CTRL_MDC));
 	E1000_WRITE_FLUSH();
@@ -2712,8 +2743,8 @@
  */
 static void e1000_lower_mdi_clk(struct e1000_hw *hw, u32 *ctrl)
 {
-	/* Lower the clock input to the Management Data Clock (by clearing the MDC
-	 * bit), and then delay 10 microseconds.
+	/* Lower the clock input to the Management Data Clock (by clearing the
+	 * MDC bit), and then delay 10 microseconds.
 	 */
 	ew32(CTRL, (*ctrl & ~E1000_CTRL_MDC));
 	E1000_WRITE_FLUSH();
@@ -2746,10 +2777,10 @@
 	ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
 
 	while (mask) {
-		/* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
-		 * then raising and lowering the Management Data Clock. A "0" is
-		 * shifted out to the PHY by setting the MDIO bit to "0" and then
-		 * raising and lowering the clock.
+		/* A "1" is shifted out to the PHY by setting the MDIO bit to
+		 * "1" and then raising and lowering the Management Data Clock.
+		 * A "0" is shifted out to the PHY by setting the MDIO bit to
+		 * "0" and then raising and lowering the clock.
 		 */
 		if (data & mask)
 			ctrl |= E1000_CTRL_MDIO;
@@ -2781,24 +2812,26 @@
 	u8 i;
 
 	/* In order to read a register from the PHY, we need to shift in a total
-	 * of 18 bits from the PHY. The first two bit (turnaround) times are used
-	 * to avoid contention on the MDIO pin when a read operation is performed.
-	 * These two bits are ignored by us and thrown away. Bits are "shifted in"
-	 * by raising the input to the Management Data Clock (setting the MDC bit),
-	 * and then reading the value of the MDIO bit.
+	 * of 18 bits from the PHY. The first two bit (turnaround) times are
+	 * used to avoid contention on the MDIO pin when a read operation is
+	 * performed. These two bits are ignored by us and thrown away. Bits are
+	 * "shifted in" by raising the input to the Management Data Clock
+	 * (setting the MDC bit), and then reading the value of the MDIO bit.
 	 */
 	ctrl = er32(CTRL);
 
-	/* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+	/* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
+	 * input.
+	 */
 	ctrl &= ~E1000_CTRL_MDIO_DIR;
 	ctrl &= ~E1000_CTRL_MDIO;
 
 	ew32(CTRL, ctrl);
 	E1000_WRITE_FLUSH();
 
-	/* Raise and Lower the clock before reading in the data. This accounts for
-	 * the turnaround bits. The first clock occurred when we clocked out the
-	 * last bit of the Register Address.
+	/* Raise and Lower the clock before reading in the data. This accounts
+	 * for the turnaround bits. The first clock occurred when we clocked out
+	 * the last bit of the Register Address.
 	 */
 	e1000_raise_mdi_clk(hw, &ctrl);
 	e1000_lower_mdi_clk(hw, &ctrl);
@@ -2870,8 +2903,8 @@
 
 	if (hw->mac_type > e1000_82543) {
 		/* Set up Op-code, Phy Address, and register address in the MDI
-		 * Control register.  The MAC will take care of interfacing with the
-		 * PHY to retrieve the desired data.
+		 * Control register.  The MAC will take care of interfacing with
+		 * the PHY to retrieve the desired data.
 		 */
 		if (hw->mac_type == e1000_ce4100) {
 			mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
@@ -2929,31 +2962,32 @@
 			*phy_data = (u16) mdic;
 		}
 	} else {
-		/* We must first send a preamble through the MDIO pin to signal the
-		 * beginning of an MII instruction.  This is done by sending 32
-		 * consecutive "1" bits.
+		/* We must first send a preamble through the MDIO pin to signal
+		 * the beginning of an MII instruction.  This is done by sending
+		 * 32 consecutive "1" bits.
 		 */
 		e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
 
 		/* Now combine the next few fields that are required for a read
 		 * operation.  We use this method instead of calling the
-		 * e1000_shift_out_mdi_bits routine five different times. The format of
-		 * a MII read instruction consists of a shift out of 14 bits and is
-		 * defined as follows:
+		 * e1000_shift_out_mdi_bits routine five different times. The
+		 * format of a MII read instruction consists of a shift out of
+		 * 14 bits and is defined as follows:
 		 *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
-		 * followed by a shift in of 18 bits.  This first two bits shifted in
-		 * are TurnAround bits used to avoid contention on the MDIO pin when a
-		 * READ operation is performed.  These two bits are thrown away
-		 * followed by a shift in of 16 bits which contains the desired data.
+		 * followed by a shift in of 18 bits.  This first two bits
+		 * shifted in are TurnAround bits used to avoid contention on
+		 * the MDIO pin when a READ operation is performed.  These two
+		 * bits are thrown away followed by a shift in of 16 bits which
+		 * contains the desired data.
 		 */
 		mdic = ((reg_addr) | (phy_addr << 5) |
 			(PHY_OP_READ << 10) | (PHY_SOF << 12));
 
 		e1000_shift_out_mdi_bits(hw, mdic, 14);
 
-		/* Now that we've shifted out the read command to the MII, we need to
-		 * "shift in" the 16-bit value (18 total bits) of the requested PHY
-		 * register address.
+		/* Now that we've shifted out the read command to the MII, we
+		 * need to "shift in" the 16-bit value (18 total bits) of the
+		 * requested PHY register address.
 		 */
 		*phy_data = e1000_shift_in_mdi_bits(hw);
 	}
@@ -3060,18 +3094,18 @@
 			}
 		}
 	} else {
-		/* We'll need to use the SW defined pins to shift the write command
-		 * out to the PHY. We first send a preamble to the PHY to signal the
-		 * beginning of the MII instruction.  This is done by sending 32
-		 * consecutive "1" bits.
+		/* We'll need to use the SW defined pins to shift the write
+		 * command out to the PHY. We first send a preamble to the PHY
+		 * to signal the beginning of the MII instruction.  This is done
+		 * by sending 32 consecutive "1" bits.
 		 */
 		e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
 
-		/* Now combine the remaining required fields that will indicate a
-		 * write operation. We use this method instead of calling the
-		 * e1000_shift_out_mdi_bits routine for each field in the command. The
-		 * format of a MII write instruction is as follows:
-		 * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+		/* Now combine the remaining required fields that will indicate
+		 * a write operation. We use this method instead of calling the
+		 * e1000_shift_out_mdi_bits routine for each field in the
+		 * command. The format of a MII write instruction is as follows:
+		 * <Preamble><SOF><OpCode><PhyAddr><RegAddr><Turnaround><Data>.
 		 */
 		mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
 			(PHY_OP_WRITE << 12) | (PHY_SOF << 14));
@@ -3100,10 +3134,10 @@
 	e_dbg("Resetting Phy...\n");
 
 	if (hw->mac_type > e1000_82543) {
-		/* Read the device control register and assert the E1000_CTRL_PHY_RST
-		 * bit. Then, take it out of reset.
+		/* Read the device control register and assert the
+		 * E1000_CTRL_PHY_RST bit. Then, take it out of reset.
 		 * For e1000 hardware, we delay for 10ms between the assert
-		 * and deassert.
+		 * and de-assert.
 		 */
 		ctrl = er32(CTRL);
 		ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
@@ -3115,8 +3149,9 @@
 		E1000_WRITE_FLUSH();
 
 	} else {
-		/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
-		 * bit to put the PHY into reset. Then, take it out of reset.
+		/* Read the Extended Device Control Register, assert the
+		 * PHY_RESET_DIR bit to put the PHY into reset. Then, take it
+		 * out of reset.
 		 */
 		ctrl_ext = er32(CTRL_EXT);
 		ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
@@ -3301,7 +3336,8 @@
 	e_dbg("e1000_phy_igp_get_info");
 
 	/* The downshift status is checked only once, after link is established,
-	 * and it stored in the hw->speed_downgraded parameter. */
+	 * and it stored in the hw->speed_downgraded parameter.
+	 */
 	phy_info->downshift = (e1000_downshift) hw->speed_downgraded;
 
 	/* IGP01E1000 does not need to support it. */
@@ -3327,7 +3363,9 @@
 
 	if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		/* Local/Remote Receiver Information are only valid at 1000 Mbps */
+		/* Local/Remote Receiver Information are only valid @ 1000
+		 * Mbps
+		 */
 		ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
 		if (ret_val)
 			return ret_val;
@@ -3379,7 +3417,8 @@
 	e_dbg("e1000_phy_m88_get_info");
 
 	/* The downshift status is checked only once, after link is established,
-	 * and it stored in the hw->speed_downgraded parameter. */
+	 * and it stored in the hw->speed_downgraded parameter.
+	 */
 	phy_info->downshift = (e1000_downshift) hw->speed_downgraded;
 
 	ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
@@ -3574,8 +3613,8 @@
 	}
 
 	if (eeprom->type == e1000_eeprom_spi) {
-		/* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
-		 * 32KB (incremented by powers of 2).
+		/* eeprom_size will be an enum [0..8] that maps to eeprom sizes
+		 * 128B to 32KB (incremented by powers of 2).
 		 */
 		/* Set to default value for initial eeprom read. */
 		eeprom->word_size = 64;
@@ -3585,8 +3624,9 @@
 		eeprom_size =
 		    (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
 		/* 256B eeprom size was not supported in earlier hardware, so we
-		 * bump eeprom_size up one to ensure that "1" (which maps to 256B)
-		 * is never the result used in the shifting logic below. */
+		 * bump eeprom_size up one to ensure that "1" (which maps to
+		 * 256B) is never the result used in the shifting logic below.
+		 */
 		if (eeprom_size)
 			eeprom_size++;
 
@@ -3618,8 +3658,8 @@
  */
 static void e1000_lower_ee_clk(struct e1000_hw *hw, u32 *eecd)
 {
-	/* Lower the clock input to the EEPROM (by clearing the SK bit), and then
-	 * wait 50 microseconds.
+	/* Lower the clock input to the EEPROM (by clearing the SK bit), and
+	 * then wait 50 microseconds.
 	 */
 	*eecd = *eecd & ~E1000_EECD_SK;
 	ew32(EECD, *eecd);
@@ -3651,10 +3691,11 @@
 		eecd |= E1000_EECD_DO;
 	}
 	do {
-		/* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
-		 * and then raising and then lowering the clock (the SK bit controls
-		 * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
-		 * by setting "DI" to "0" and then raising and then lowering the clock.
+		/* A "1" is shifted out to the EEPROM by setting bit "DI" to a
+		 * "1", and then raising and then lowering the clock (the SK bit
+		 * controls the clock input to the EEPROM).  A "0" is shifted
+		 * out to the EEPROM by setting "DI" to "0" and then raising and
+		 * then lowering the clock.
 		 */
 		eecd &= ~E1000_EECD_DI;
 
@@ -3691,9 +3732,9 @@
 
 	/* In order to read a register from the EEPROM, we need to shift 'count'
 	 * bits in from the EEPROM. Bits are "shifted in" by raising the clock
-	 * input to the EEPROM (setting the SK bit), and then reading the value of
-	 * the "DO" bit.  During this "shifting in" process the "DI" bit should
-	 * always be clear.
+	 * input to the EEPROM (setting the SK bit), and then reading the value
+	 * of the "DO" bit.  During this "shifting in" process the "DI" bit
+	 * should always be clear.
 	 */
 
 	eecd = er32(EECD);
@@ -3945,8 +3986,8 @@
 	if (eeprom->word_size == 0)
 		e1000_init_eeprom_params(hw);
 
-	/* A check for invalid values:  offset too large, too many words, and not
-	 * enough words.
+	/* A check for invalid values:  offset too large, too many words, and
+	 * not enough words.
 	 */
 	if ((offset >= eeprom->word_size)
 	    || (words > eeprom->word_size - offset) || (words == 0)) {
@@ -3964,7 +4005,8 @@
 		return -E1000_ERR_EEPROM;
 
 	/* Set up the SPI or Microwire EEPROM for bit-bang reading.  We have
-	 * acquired the EEPROM at this point, so any returns should release it */
+	 * acquired the EEPROM at this point, so any returns should release it
+	 */
 	if (eeprom->type == e1000_eeprom_spi) {
 		u16 word_in;
 		u8 read_opcode = EEPROM_READ_OPCODE_SPI;
@@ -3976,7 +4018,9 @@
 
 		e1000_standby_eeprom(hw);
 
-		/* Some SPI eeproms use the 8th address bit embedded in the opcode */
+		/* Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
 		if ((eeprom->address_bits == 8) && (offset >= 128))
 			read_opcode |= EEPROM_A8_OPCODE_SPI;
 
@@ -3985,11 +4029,13 @@
 		e1000_shift_out_ee_bits(hw, (u16) (offset * 2),
 					eeprom->address_bits);
 
-		/* Read the data.  The address of the eeprom internally increments with
-		 * each byte (spi) being read, saving on the overhead of eeprom setup
-		 * and tear-down.  The address counter will roll over if reading beyond
-		 * the size of the eeprom, thus allowing the entire memory to be read
-		 * starting from any offset. */
+		/* Read the data.  The address of the eeprom internally
+		 * increments with each byte (spi) being read, saving on the
+		 * overhead of eeprom setup and tear-down.  The address counter
+		 * will roll over if reading beyond the size of the eeprom, thus
+		 * allowing the entire memory to be read starting from any
+		 * offset.
+		 */
 		for (i = 0; i < words; i++) {
 			word_in = e1000_shift_in_ee_bits(hw, 16);
 			data[i] = (word_in >> 8) | (word_in << 8);
@@ -4003,8 +4049,9 @@
 			e1000_shift_out_ee_bits(hw, (u16) (offset + i),
 						eeprom->address_bits);
 
-			/* Read the data.  For microwire, each word requires the overhead
-			 * of eeprom setup and tear-down. */
+			/* Read the data.  For microwire, each word requires the
+			 * overhead of eeprom setup and tear-down.
+			 */
 			data[i] = e1000_shift_in_ee_bits(hw, 16);
 			e1000_standby_eeprom(hw);
 		}
@@ -4119,8 +4166,8 @@
 	if (eeprom->word_size == 0)
 		e1000_init_eeprom_params(hw);
 
-	/* A check for invalid values:  offset too large, too many words, and not
-	 * enough words.
+	/* A check for invalid values:  offset too large, too many words, and
+	 * not enough words.
 	 */
 	if ((offset >= eeprom->word_size)
 	    || (words > eeprom->word_size - offset) || (words == 0)) {
@@ -4174,7 +4221,9 @@
 
 		e1000_standby_eeprom(hw);
 
-		/* Some SPI eeproms use the 8th address bit embedded in the opcode */
+		/* Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
 		if ((eeprom->address_bits == 8) && (offset >= 128))
 			write_opcode |= EEPROM_A8_OPCODE_SPI;
 
@@ -4186,16 +4235,19 @@
 
 		/* Send the data */
 
-		/* Loop to allow for up to whole page write (32 bytes) of eeprom */
+		/* Loop to allow for up to whole page write (32 bytes) of
+		 * eeprom
+		 */
 		while (widx < words) {
 			u16 word_out = data[widx];
 			word_out = (word_out >> 8) | (word_out << 8);
 			e1000_shift_out_ee_bits(hw, word_out, 16);
 			widx++;
 
-			/* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
-			 * operation, while the smaller eeproms are capable of an 8-byte
-			 * PAGE WRITE operation.  Break the inner loop to pass new address
+			/* Some larger eeprom sizes are capable of a 32-byte
+			 * PAGE WRITE operation, while the smaller eeproms are
+			 * capable of an 8-byte PAGE WRITE operation.  Break the
+			 * inner loop to pass new address
 			 */
 			if ((((offset + widx) * 2) % eeprom->page_size) == 0) {
 				e1000_standby_eeprom(hw);
@@ -4249,14 +4301,15 @@
 		/* Send the data */
 		e1000_shift_out_ee_bits(hw, data[words_written], 16);
 
-		/* Toggle the CS line.  This in effect tells the EEPROM to execute
-		 * the previous command.
+		/* Toggle the CS line.  This in effect tells the EEPROM to
+		 * execute the previous command.
 		 */
 		e1000_standby_eeprom(hw);
 
-		/* Read DO repeatedly until it is high (equal to '1').  The EEPROM will
-		 * signal that the command has been completed by raising the DO signal.
-		 * If DO does not go high in 10 milliseconds, then error out.
+		/* Read DO repeatedly until it is high (equal to '1').  The
+		 * EEPROM will signal that the command has been completed by
+		 * raising the DO signal. If DO does not go high in 10
+		 * milliseconds, then error out.
 		 */
 		for (i = 0; i < 200; i++) {
 			eecd = er32(EECD);
@@ -4483,7 +4536,8 @@
 	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
 		/* If the offset we want to clear is the same offset of the
 		 * manageability VLAN ID, then clear all bits except that of the
-		 * manageability unit */
+		 * manageability unit
+		 */
 		vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
 		E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
 		E1000_WRITE_FLUSH();
@@ -4911,12 +4965,12 @@
 	 * counters overcount this packet as a CRC error and undercount
 	 * the packet as a good packet
 	 */
-	/* This packet should not be counted as a CRC error.    */
+	/* This packet should not be counted as a CRC error. */
 	stats->crcerrs--;
-	/* This packet does count as a Good Packet Received.    */
+	/* This packet does count as a Good Packet Received. */
 	stats->gprc++;
 
-	/* Adjust the Good Octets received counters             */
+	/* Adjust the Good Octets received counters */
 	carry_bit = 0x80000000 & stats->gorcl;
 	stats->gorcl += frame_len;
 	/* If the high bit of Gorcl (the low 32 bits of the Good Octets
@@ -5196,8 +5250,9 @@
 		if (ret_val)
 			return ret_val;
 
-		/* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
-		 * find the polarity status */
+		/* If speed is 1000 Mbps, must read the
+		 * IGP01E1000_PHY_PCS_INIT_REG to find the polarity status
+		 */
 		if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
 		    IGP01E1000_PSSR_SPEED_1000MBPS) {
 
@@ -5213,8 +5268,9 @@
 			    e1000_rev_polarity_reversed :
 			    e1000_rev_polarity_normal;
 		} else {
-			/* For 10 Mbps, read the polarity bit in the status register. (for
-			 * 100 Mbps this bit is always 0) */
+			/* For 10 Mbps, read the polarity bit in the status
+			 * register. (for 100 Mbps this bit is always 0)
+			 */
 			*polarity =
 			    (phy_data & IGP01E1000_PSSR_POLARITY_REVERSED) ?
 			    e1000_rev_polarity_reversed :
@@ -5374,8 +5430,9 @@
 		}
 	} else {
 		if (hw->dsp_config_state == e1000_dsp_config_activated) {
-			/* Save off the current value of register 0x2F5B to be restored at
-			 * the end of the routines. */
+			/* Save off the current value of register 0x2F5B to be
+			 * restored at the end of the routines.
+			 */
 			ret_val =
 			    e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
 
@@ -5391,7 +5448,7 @@
 			msleep(20);
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-						      IGP01E1000_IEEE_FORCE_GIGA);
+						    IGP01E1000_IEEE_FORCE_GIGA);
 			if (ret_val)
 				return ret_val;
 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
@@ -5412,7 +5469,7 @@
 			}
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-						      IGP01E1000_IEEE_RESTART_AUTONEG);
+					IGP01E1000_IEEE_RESTART_AUTONEG);
 			if (ret_val)
 				return ret_val;
 
@@ -5429,8 +5486,9 @@
 		}
 
 		if (hw->ffe_config_state == e1000_ffe_config_active) {
-			/* Save off the current value of register 0x2F5B to be restored at
-			 * the end of the routines. */
+			/* Save off the current value of register 0x2F5B to be
+			 * restored at the end of the routines.
+			 */
 			ret_val =
 			    e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
 
@@ -5446,7 +5504,7 @@
 			msleep(20);
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-						      IGP01E1000_IEEE_FORCE_GIGA);
+						    IGP01E1000_IEEE_FORCE_GIGA);
 			if (ret_val)
 				return ret_val;
 			ret_val =
@@ -5456,7 +5514,7 @@
 				return ret_val;
 
 			ret_val = e1000_write_phy_reg(hw, 0x0000,
-						      IGP01E1000_IEEE_RESTART_AUTONEG);
+					IGP01E1000_IEEE_RESTART_AUTONEG);
 			if (ret_val)
 				return ret_val;
 
@@ -5542,8 +5600,9 @@
 		return E1000_SUCCESS;
 
 	/* During driver activity LPLU should not be used or it will attain link
-	 * from the lowest speeds starting from 10Mbps. The capability is used for
-	 * Dx transitions and states */
+	 * from the lowest speeds starting from 10Mbps. The capability is used
+	 * for Dx transitions and states
+	 */
 	if (hw->mac_type == e1000_82541_rev_2
 	    || hw->mac_type == e1000_82547_rev_2) {
 		ret_val =
@@ -5563,10 +5622,11 @@
 				return ret_val;
 		}
 
-		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used during
-		 * Dx states where the power conservation is most important.  During
-		 * driver activity we should enable SmartSpeed, so performance is
-		 * maintained. */
+		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
 		if (hw->smart_speed == e1000_smart_speed_on) {
 			ret_val =
 			    e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 294da56..8502c62 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -239,7 +239,6 @@
  * e1000_init_module is the first routine called when the driver is
  * loaded. All it does is register with the PCI subsystem.
  **/
-
 static int __init e1000_init_module(void)
 {
 	int ret;
@@ -266,7 +265,6 @@
  * e1000_exit_module is called just before the driver is removed
  * from memory.
  **/
-
 static void __exit e1000_exit_module(void)
 {
 	pci_unregister_driver(&e1000_driver);
@@ -301,7 +299,6 @@
  * e1000_irq_disable - Mask off interrupt generation on the NIC
  * @adapter: board private structure
  **/
-
 static void e1000_irq_disable(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -315,7 +312,6 @@
  * e1000_irq_enable - Enable default interrupt generation settings
  * @adapter: board private structure
  **/
-
 static void e1000_irq_enable(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -398,11 +394,12 @@
 	e1000_configure_rx(adapter);
 	/* call E1000_DESC_UNUSED which always leaves
 	 * at least 1 descriptor unused to make sure
-	 * next_to_use != next_to_clean */
+	 * next_to_use != next_to_clean
+	 */
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		struct e1000_rx_ring *ring = &adapter->rx_ring[i];
 		adapter->alloc_rx_buf(adapter, ring,
-		                      E1000_DESC_UNUSED(ring));
+				      E1000_DESC_UNUSED(ring));
 	}
 }
 
@@ -433,9 +430,7 @@
  * The phy may be powered down to save power and turn off link when the
  * driver is unloaded and wake on lan is not enabled (among others)
  * *** this routine MUST be followed by a call to e1000_reset ***
- *
  **/
-
 void e1000_power_up_phy(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -444,7 +439,8 @@
 	/* Just clear the power down bit to wake the phy back up */
 	if (hw->media_type == e1000_media_type_copper) {
 		/* according to the manual, the phy will retain its
-		 * settings across a power-down/up cycle */
+		 * settings across a power-down/up cycle
+		 */
 		e1000_read_phy_reg(hw, PHY_CTRL, &mii_reg);
 		mii_reg &= ~MII_CR_POWER_DOWN;
 		e1000_write_phy_reg(hw, PHY_CTRL, mii_reg);
@@ -459,7 +455,8 @@
 	 * The PHY cannot be powered down if any of the following is true *
 	 * (a) WoL is enabled
 	 * (b) AMT is active
-	 * (c) SoL/IDER session is active */
+	 * (c) SoL/IDER session is active
+	 */
 	if (!adapter->wol && hw->mac_type >= e1000_82540 &&
 	   hw->media_type == e1000_media_type_copper) {
 		u16 mii_reg = 0;
@@ -529,8 +526,7 @@
 
 	e1000_irq_disable(adapter);
 
-	/*
-	 * Setting DOWN must be after irq_disable to prevent
+	/* Setting DOWN must be after irq_disable to prevent
 	 * a screaming interrupt.  Setting DOWN also prevents
 	 * tasks from rescheduling.
 	 */
@@ -627,14 +623,14 @@
 		 * rounded up to the next 1KB and expressed in KB.  Likewise,
 		 * the Rx FIFO should be large enough to accommodate at least
 		 * one full receive packet and is similarly rounded up and
-		 * expressed in KB. */
+		 * expressed in KB.
+		 */
 		pba = er32(PBA);
 		/* upper 16 bits has Tx packet buffer allocation size in KB */
 		tx_space = pba >> 16;
 		/* lower 16 bits has Rx packet buffer allocation size in KB */
 		pba &= 0xffff;
-		/*
-		 * the tx fifo also stores 16 bytes of information about the tx
+		/* the Tx fifo also stores 16 bytes of information about the Tx
 		 * but don't include ethernet FCS because hardware appends it
 		 */
 		min_tx_space = (hw->max_frame_size +
@@ -649,7 +645,8 @@
 
 		/* If current Tx allocation is less than the min Tx FIFO size,
 		 * and the min Tx FIFO size is less than the current Rx FIFO
-		 * allocation, take space away from current Rx allocation */
+		 * allocation, take space away from current Rx allocation
+		 */
 		if (tx_space < min_tx_space &&
 		    ((min_tx_space - tx_space) < pba)) {
 			pba = pba - (min_tx_space - tx_space);
@@ -663,8 +660,9 @@
 				break;
 			}
 
-			/* if short on rx space, rx wins and must trump tx
-			 * adjustment or use Early Receive if available */
+			/* if short on Rx space, Rx wins and must trump Tx
+			 * adjustment or use Early Receive if available
+			 */
 			if (pba < min_rx_space)
 				pba = min_rx_space;
 		}
@@ -672,8 +670,7 @@
 
 	ew32(PBA, pba);
 
-	/*
-	 * flow control settings:
+	/* flow control settings:
 	 * The high water mark must be low enough to fit one full frame
 	 * (or the size used for early receive) above it in the Rx FIFO.
 	 * Set it to the lower of:
@@ -707,7 +704,8 @@
 		u32 ctrl = er32(CTRL);
 		/* clear phy power management bit if we are in gig only mode,
 		 * which if enabled will attempt negotiation to 100Mb, which
-		 * can cause a loss of link at power off or driver unload */
+		 * can cause a loss of link at power off or driver unload
+		 */
 		ctrl &= ~E1000_CTRL_SWDPIN3;
 		ew32(CTRL, ctrl);
 	}
@@ -808,9 +806,8 @@
 static netdev_features_t e1000_fix_features(struct net_device *netdev,
 	netdev_features_t features)
 {
-	/*
-	 * Since there is no support for separate rx/tx vlan accel
-	 * enable/disable make sure tx flag is always in same state as rx.
+	/* Since there is no support for separate Rx/Tx vlan accel
+	 * enable/disable make sure Tx flag is always in same state as Rx.
 	 */
 	if (features & NETIF_F_HW_VLAN_RX)
 		features |= NETIF_F_HW_VLAN_TX;
@@ -1012,16 +1009,14 @@
 	if (err)
 		goto err_sw_init;
 
-	/*
-	 * there is a workaround being applied below that limits
+	/* there is a workaround being applied below that limits
 	 * 64-bit DMA addresses to 64-bit hardware.  There are some
 	 * 32-bit adapters that Tx hang when given 64-bit DMA addresses
 	 */
 	pci_using_dac = 0;
 	if ((hw->bus_type == e1000_bus_type_pcix) &&
 	    !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-		/*
-		 * according to DMA-API-HOWTO, coherent calls will always
+		/* according to DMA-API-HOWTO, coherent calls will always
 		 * succeed if the set call did
 		 */
 		dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
@@ -1099,7 +1094,8 @@
 	}
 
 	/* before reading the EEPROM, reset the controller to
-	 * put the device in a known good starting state */
+	 * put the device in a known good starting state
+	 */
 
 	e1000_reset_hw(hw);
 
@@ -1107,8 +1103,7 @@
 	if (e1000_validate_eeprom_checksum(hw) < 0) {
 		e_err(probe, "The EEPROM Checksum Is Not Valid\n");
 		e1000_dump_eeprom(adapter);
-		/*
-		 * set MAC address to all zeroes to invalidate and temporary
+		/* set MAC address to all zeroes to invalidate and temporary
 		 * disable this device for the user. This blocks regular
 		 * traffic while still permitting ethtool ioctls from reaching
 		 * the hardware as well as allowing the user to run the
@@ -1123,9 +1118,8 @@
 	}
 	/* don't block initalization here due to bad MAC address */
 	memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len);
-	memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len);
 
-	if (!is_valid_ether_addr(netdev->perm_addr))
+	if (!is_valid_ether_addr(netdev->dev_addr))
 		e_err(probe, "Invalid MAC Address\n");
 
 
@@ -1170,7 +1164,8 @@
 
 	/* now that we have the eeprom settings, apply the special cases
 	 * where the eeprom may be wrong or the board simply won't support
-	 * wake on lan on a particular port */
+	 * wake on lan on a particular port
+	 */
 	switch (pdev->device) {
 	case E1000_DEV_ID_82546GB_PCIE:
 		adapter->eeprom_wol = 0;
@@ -1178,7 +1173,8 @@
 	case E1000_DEV_ID_82546EB_FIBER:
 	case E1000_DEV_ID_82546GB_FIBER:
 		/* Wake events only supported on port A for dual fiber
-		 * regardless of eeprom setting */
+		 * regardless of eeprom setting
+		 */
 		if (er32(STATUS) & E1000_STATUS_FUNC_1)
 			adapter->eeprom_wol = 0;
 		break;
@@ -1271,7 +1267,6 @@
  * Hot-Plug event, or because the driver is going to be removed from
  * memory.
  **/
-
 static void e1000_remove(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
@@ -1307,7 +1302,6 @@
  * e1000_sw_init initializes the Adapter private data structure.
  * e1000_init_hw_struct MUST be called before this function
  **/
-
 static int e1000_sw_init(struct e1000_adapter *adapter)
 {
 	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
@@ -1338,7 +1332,6 @@
  * We allocate one ring per queue at run-time since we don't know the
  * number of queues at compile-time.
  **/
-
 static int e1000_alloc_queues(struct e1000_adapter *adapter)
 {
 	adapter->tx_ring = kcalloc(adapter->num_tx_queues,
@@ -1368,7 +1361,6 @@
  * handler is registered with the OS, the watchdog task is started,
  * and the stack is notified that the interface is ready.
  **/
-
 static int e1000_open(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1402,7 +1394,8 @@
 	/* before we allocate an interrupt, we must be ready to handle it.
 	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
 	 * as soon as we call pci_request_irq, so we have to setup our
-	 * clean_rx handler before we do so.  */
+	 * clean_rx handler before we do so.
+	 */
 	e1000_configure(adapter);
 
 	err = e1000_request_irq(adapter);
@@ -1445,7 +1438,6 @@
  * needs to be disabled.  A global MAC reset is issued to stop the
  * hardware, and all transmit and receive resources are freed.
  **/
-
 static int e1000_close(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1460,10 +1452,11 @@
 	e1000_free_all_rx_resources(adapter);
 
 	/* kill manageability vlan ID if supported, but not if a vlan with
-	 * the same ID is registered on the host OS (let 8021q kill it) */
+	 * the same ID is registered on the host OS (let 8021q kill it)
+	 */
 	if ((hw->mng_cookie.status &
-			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
-	     !test_bit(adapter->mng_vlan_id, adapter->active_vlans)) {
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
+	    !test_bit(adapter->mng_vlan_id, adapter->active_vlans)) {
 		e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
 	}
 
@@ -1484,7 +1477,8 @@
 	unsigned long end = begin + len;
 
 	/* First rev 82545 and 82546 need to not allow any memory
-	 * write location to cross 64k boundary due to errata 23 */
+	 * write location to cross 64k boundary due to errata 23
+	 */
 	if (hw->mac_type == e1000_82545 ||
 	    hw->mac_type == e1000_ce4100 ||
 	    hw->mac_type == e1000_82546) {
@@ -1501,7 +1495,6 @@
  *
  * Return 0 on success, negative on failure
  **/
-
 static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
 				    struct e1000_tx_ring *txdr)
 {
@@ -1510,11 +1503,8 @@
 
 	size = sizeof(struct e1000_buffer) * txdr->count;
 	txdr->buffer_info = vzalloc(size);
-	if (!txdr->buffer_info) {
-		e_err(probe, "Unable to allocate memory for the Tx descriptor "
-		      "ring\n");
+	if (!txdr->buffer_info)
 		return -ENOMEM;
-	}
 
 	/* round up to nearest 4K */
 
@@ -1578,7 +1568,6 @@
  *
  * Return 0 on success, negative on failure
  **/
-
 int e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
 {
 	int i, err = 0;
@@ -1603,7 +1592,6 @@
  *
  * Configure the Tx unit of the MAC after a reset.
  **/
-
 static void e1000_configure_tx(struct e1000_adapter *adapter)
 {
 	u64 tdba;
@@ -1624,8 +1612,10 @@
 		ew32(TDBAL, (tdba & 0x00000000ffffffffULL));
 		ew32(TDT, 0);
 		ew32(TDH, 0);
-		adapter->tx_ring[0].tdh = ((hw->mac_type >= e1000_82543) ? E1000_TDH : E1000_82542_TDH);
-		adapter->tx_ring[0].tdt = ((hw->mac_type >= e1000_82543) ? E1000_TDT : E1000_82542_TDT);
+		adapter->tx_ring[0].tdh = ((hw->mac_type >= e1000_82543) ?
+					   E1000_TDH : E1000_82542_TDH);
+		adapter->tx_ring[0].tdt = ((hw->mac_type >= e1000_82543) ?
+					   E1000_TDT : E1000_82542_TDT);
 		break;
 	}
 
@@ -1680,7 +1670,8 @@
 		adapter->txd_cmd |= E1000_TXD_CMD_RS;
 
 	/* Cache if we're 82544 running in PCI-X because we'll
-	 * need this to apply a workaround later in the send path. */
+	 * need this to apply a workaround later in the send path.
+	 */
 	if (hw->mac_type == e1000_82544 &&
 	    hw->bus_type == e1000_bus_type_pcix)
 		adapter->pcix_82544 = true;
@@ -1696,7 +1687,6 @@
  *
  * Returns 0 on success, negative on failure
  **/
-
 static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
 				    struct e1000_rx_ring *rxdr)
 {
@@ -1705,11 +1695,8 @@
 
 	size = sizeof(struct e1000_buffer) * rxdr->count;
 	rxdr->buffer_info = vzalloc(size);
-	if (!rxdr->buffer_info) {
-		e_err(probe, "Unable to allocate memory for the Rx descriptor "
-		      "ring\n");
+	if (!rxdr->buffer_info)
 		return -ENOMEM;
-	}
 
 	desc_len = sizeof(struct e1000_rx_desc);
 
@@ -1778,7 +1765,6 @@
  *
  * Return 0 on success, negative on failure
  **/
-
 int e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
 {
 	int i, err = 0;
@@ -1847,7 +1833,8 @@
 	/* This is useful for sniffing bad packets. */
 	if (adapter->netdev->features & NETIF_F_RXALL) {
 		/* UPE and MPE will be handled by normal PROMISC logic
-		 * in e1000e_set_rx_mode */
+		 * in e1000e_set_rx_mode
+		 */
 		rctl |= (E1000_RCTL_SBP | /* Receive bad packets */
 			 E1000_RCTL_BAM | /* RX All Bcast Pkts */
 			 E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
@@ -1869,7 +1856,6 @@
  *
  * Configure the Rx unit of the MAC after a reset.
  **/
-
 static void e1000_configure_rx(struct e1000_adapter *adapter)
 {
 	u64 rdba;
@@ -1902,7 +1888,8 @@
 	}
 
 	/* Setup the HW Rx Head and Tail Descriptor Pointers and
-	 * the Base and Length of the Rx Descriptor Ring */
+	 * the Base and Length of the Rx Descriptor Ring
+	 */
 	switch (adapter->num_rx_queues) {
 	case 1:
 	default:
@@ -1912,8 +1899,10 @@
 		ew32(RDBAL, (rdba & 0x00000000ffffffffULL));
 		ew32(RDT, 0);
 		ew32(RDH, 0);
-		adapter->rx_ring[0].rdh = ((hw->mac_type >= e1000_82543) ? E1000_RDH : E1000_82542_RDH);
-		adapter->rx_ring[0].rdt = ((hw->mac_type >= e1000_82543) ? E1000_RDT : E1000_82542_RDT);
+		adapter->rx_ring[0].rdh = ((hw->mac_type >= e1000_82543) ?
+					   E1000_RDH : E1000_82542_RDH);
+		adapter->rx_ring[0].rdt = ((hw->mac_type >= e1000_82543) ?
+					   E1000_RDT : E1000_82542_RDT);
 		break;
 	}
 
@@ -1939,7 +1928,6 @@
  *
  * Free all transmit software resources
  **/
-
 static void e1000_free_tx_resources(struct e1000_adapter *adapter,
 				    struct e1000_tx_ring *tx_ring)
 {
@@ -1962,7 +1950,6 @@
  *
  * Free all transmit software resources
  **/
-
 void e1000_free_all_tx_resources(struct e1000_adapter *adapter)
 {
 	int i;
@@ -1997,7 +1984,6 @@
  * @adapter: board private structure
  * @tx_ring: ring to be cleaned
  **/
-
 static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
 				struct e1000_tx_ring *tx_ring)
 {
@@ -2033,7 +2019,6 @@
  * e1000_clean_all_tx_rings - Free Tx Buffers for all queues
  * @adapter: board private structure
  **/
-
 static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter)
 {
 	int i;
@@ -2049,7 +2034,6 @@
  *
  * Free all receive software resources
  **/
-
 static void e1000_free_rx_resources(struct e1000_adapter *adapter,
 				    struct e1000_rx_ring *rx_ring)
 {
@@ -2072,7 +2056,6 @@
  *
  * Free all receive software resources
  **/
-
 void e1000_free_all_rx_resources(struct e1000_adapter *adapter)
 {
 	int i;
@@ -2086,7 +2069,6 @@
  * @adapter: board private structure
  * @rx_ring: ring to free buffers from
  **/
-
 static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
 				struct e1000_rx_ring *rx_ring)
 {
@@ -2145,7 +2127,6 @@
  * e1000_clean_all_rx_rings - Free Rx Buffers for all queues
  * @adapter: board private structure
  **/
-
 static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter)
 {
 	int i;
@@ -2205,7 +2186,6 @@
  *
  * Returns 0 on success, negative on failure
  **/
-
 static int e1000_set_mac(struct net_device *netdev, void *p)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -2240,7 +2220,6 @@
  * responsible for configuring the hardware for proper unicast, multicast,
  * promiscuous mode, and all-multi behavior.
  **/
-
 static void e1000_set_rx_mode(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -2253,10 +2232,8 @@
 	int mta_reg_count = E1000_NUM_MTA_REGISTERS;
 	u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
 
-	if (!mcarray) {
-		e_err(probe, "memory allocation failed\n");
+	if (!mcarray)
 		return;
-	}
 
 	/* Check for Promiscuous and All Multicast modes */
 
@@ -2326,10 +2303,10 @@
 	}
 
 	/* write the hash table completely, write from bottom to avoid
-	 * both stupid write combining chipsets, and flushing each write */
+	 * both stupid write combining chipsets, and flushing each write
+	 */
 	for (i = mta_reg_count - 1; i >= 0 ; i--) {
-		/*
-		 * If we are on an 82544 has an errata where writing odd
+		/* If we are on an 82544 has an errata where writing odd
 		 * offsets overwrites the previous even offset, but writing
 		 * backwards over the range solves the issue by always
 		 * writing the odd offset first
@@ -2467,8 +2444,8 @@
 			bool txb2b = true;
 			/* update snapshot of PHY registers on LSC */
 			e1000_get_speed_and_duplex(hw,
-			                           &adapter->link_speed,
-			                           &adapter->link_duplex);
+						   &adapter->link_speed,
+						   &adapter->link_duplex);
 
 			ctrl = er32(CTRL);
 			pr_info("%s NIC Link is Up %d Mbps %s, "
@@ -2542,7 +2519,8 @@
 			/* We've lost link, so the controller stops DMA,
 			 * but we've got queued Tx work that's never going
 			 * to get done, so reset controller to flush Tx.
-			 * (Do the reset outside of interrupt context). */
+			 * (Do the reset outside of interrupt context).
+			 */
 			adapter->tx_timeout_count++;
 			schedule_work(&adapter->reset_task);
 			/* exit immediately since reset is imminent */
@@ -2552,8 +2530,7 @@
 
 	/* Simple mode for Interrupt Throttle Rate (ITR) */
 	if (hw->mac_type >= e1000_82540 && adapter->itr_setting == 4) {
-		/*
-		 * Symmetric Tx/Rx gets a reduced ITR=2000;
+		/* Symmetric Tx/Rx gets a reduced ITR=2000;
 		 * Total asymmetrical Tx or Rx gets ITR=8000;
 		 * everyone else is between 2000-8000.
 		 */
@@ -2668,18 +2645,16 @@
 		goto set_itr_now;
 	}
 
-	adapter->tx_itr = e1000_update_itr(adapter,
-	                            adapter->tx_itr,
-	                            adapter->total_tx_packets,
-	                            adapter->total_tx_bytes);
+	adapter->tx_itr = e1000_update_itr(adapter, adapter->tx_itr,
+					   adapter->total_tx_packets,
+					   adapter->total_tx_bytes);
 	/* conservative mode (itr 3) eliminates the lowest_latency setting */
 	if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
 		adapter->tx_itr = low_latency;
 
-	adapter->rx_itr = e1000_update_itr(adapter,
-	                            adapter->rx_itr,
-	                            adapter->total_rx_packets,
-	                            adapter->total_rx_bytes);
+	adapter->rx_itr = e1000_update_itr(adapter, adapter->rx_itr,
+					   adapter->total_rx_packets,
+					   adapter->total_rx_bytes);
 	/* conservative mode (itr 3) eliminates the lowest_latency setting */
 	if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
 		adapter->rx_itr = low_latency;
@@ -2705,10 +2680,11 @@
 	if (new_itr != adapter->itr) {
 		/* this attempts to bias the interrupt rate towards Bulk
 		 * by adding intermediate steps when interrupt rate is
-		 * increasing */
+		 * increasing
+		 */
 		new_itr = new_itr > adapter->itr ?
-		             min(adapter->itr + (new_itr >> 2), new_itr) :
-		             new_itr;
+			  min(adapter->itr + (new_itr >> 2), new_itr) :
+			  new_itr;
 		adapter->itr = new_itr;
 		ew32(ITR, 1000000000 / (new_itr * 256));
 	}
@@ -2870,7 +2846,8 @@
 		/* Workaround for Controller erratum --
 		 * descriptor for non-tso packet in a linear SKB that follows a
 		 * tso gets written back prematurely before the data is fully
-		 * DMA'd to the controller */
+		 * DMA'd to the controller
+		 */
 		if (!skb->data_len && tx_ring->last_tx_tso &&
 		    !skb_is_gso(skb)) {
 			tx_ring->last_tx_tso = false;
@@ -2878,7 +2855,8 @@
 		}
 
 		/* Workaround for premature desc write-backs
-		 * in TSO mode.  Append 4-byte sentinel desc */
+		 * in TSO mode.  Append 4-byte sentinel desc
+		 */
 		if (unlikely(mss && !nr_frags && size == len && size > 8))
 			size -= 4;
 		/* work-around for errata 10 and it applies
@@ -2891,7 +2869,8 @@
 		        size = 2015;
 
 		/* Workaround for potential 82544 hang in PCI-X.  Avoid
-		 * terminating buffers within evenly-aligned dwords. */
+		 * terminating buffers within evenly-aligned dwords.
+		 */
 		if (unlikely(adapter->pcix_82544 &&
 		   !((unsigned long)(skb->data + offset + size - 1) & 4) &&
 		   size > 4))
@@ -2903,7 +2882,7 @@
 		buffer_info->mapped_as_page = false;
 		buffer_info->dma = dma_map_single(&pdev->dev,
 						  skb->data + offset,
-						  size,	DMA_TO_DEVICE);
+						  size, DMA_TO_DEVICE);
 		if (dma_mapping_error(&pdev->dev, buffer_info->dma))
 			goto dma_error;
 		buffer_info->next_to_watch = i;
@@ -2934,12 +2913,15 @@
 			buffer_info = &tx_ring->buffer_info[i];
 			size = min(len, max_per_txd);
 			/* Workaround for premature desc write-backs
-			 * in TSO mode.  Append 4-byte sentinel desc */
-			if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
+			 * in TSO mode.  Append 4-byte sentinel desc
+			 */
+			if (unlikely(mss && f == (nr_frags-1) &&
+			    size == len && size > 8))
 				size -= 4;
 			/* Workaround for potential 82544 hang in PCI-X.
 			 * Avoid terminating buffers within evenly-aligned
-			 * dwords. */
+			 * dwords.
+			 */
 			bufend = (unsigned long)
 				page_to_phys(skb_frag_page(frag));
 			bufend += offset + size - 1;
@@ -3003,7 +2985,7 @@
 
 	if (likely(tx_flags & E1000_TX_FLAGS_TSO)) {
 		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
-		             E1000_TXD_CMD_TSE;
+			     E1000_TXD_CMD_TSE;
 		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
 
 		if (likely(tx_flags & E1000_TX_FLAGS_IPV4))
@@ -3044,13 +3026,15 @@
 	/* Force memory writes to complete before letting h/w
 	 * know there are new descriptors to fetch.  (Only
 	 * applicable for weak-ordered memory model archs,
-	 * such as IA-64). */
+	 * such as IA-64).
+	 */
 	wmb();
 
 	tx_ring->next_to_use = i;
 	writel(i, hw->hw_addr + tx_ring->tdt);
 	/* we need this if more than one processor can write to our tail
-	 * at a time, it syncronizes IO on IA64/Altix systems */
+	 * at a time, it synchronizes IO on IA64/Altix systems
+	 */
 	mmiowb();
 }
 
@@ -3099,11 +3083,13 @@
 	netif_stop_queue(netdev);
 	/* Herbert's original patch had:
 	 *  smp_mb__after_netif_stop_queue();
-	 * but since that doesn't exist yet, just open code it. */
+	 * but since that doesn't exist yet, just open code it.
+	 */
 	smp_mb();
 
 	/* We need to check again in a case another CPU has just
-	 * made room available. */
+	 * made room available.
+	 */
 	if (likely(E1000_DESC_UNUSED(tx_ring) < size))
 		return -EBUSY;
 
@@ -3114,7 +3100,7 @@
 }
 
 static int e1000_maybe_stop_tx(struct net_device *netdev,
-                               struct e1000_tx_ring *tx_ring, int size)
+			       struct e1000_tx_ring *tx_ring, int size)
 {
 	if (likely(E1000_DESC_UNUSED(tx_ring) >= size))
 		return 0;
@@ -3138,10 +3124,11 @@
 	int tso;
 	unsigned int f;
 
-	/* This goes back to the question of how to logically map a tx queue
+	/* This goes back to the question of how to logically map a Tx queue
 	 * to a flow.  Right now, performance is impacted slightly negatively
-	 * if using multiple tx queues.  If the stack breaks away from a
-	 * single qdisc implementation, we can look at this again. */
+	 * if using multiple Tx queues.  If the stack breaks away from a
+	 * single qdisc implementation, we can look at this again.
+	 */
 	tx_ring = adapter->tx_ring;
 
 	if (unlikely(skb->len <= 0)) {
@@ -3166,7 +3153,8 @@
 	 * initiating the DMA for each buffer.  The calc is:
 	 * 4 = ceil(buffer len/mss).  To make sure we don't
 	 * overrun the FIFO, adjust the max buffer len if mss
-	 * drops. */
+	 * drops.
+	 */
 	if (mss) {
 		u8 hdr_len;
 		max_per_txd = min(mss << 2, max_per_txd);
@@ -3182,8 +3170,10 @@
 				 * this hardware's requirements
 				 * NOTE: this is a TSO only workaround
 				 * if end byte alignment not correct move us
-				 * into the next dword */
-				if ((unsigned long)(skb_tail_pointer(skb) - 1) & 4)
+				 * into the next dword
+				 */
+				if ((unsigned long)(skb_tail_pointer(skb) - 1)
+				    & 4)
 					break;
 				/* fall through */
 				pull_size = min((unsigned int)4, skb->data_len);
@@ -3231,7 +3221,8 @@
 		count += nr_frags;
 
 	/* need: count + 2 desc gap to keep tail from touching
-	 * head, otherwise try next time */
+	 * head, otherwise try next time
+	 */
 	if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2)))
 		return NETDEV_TX_BUSY;
 
@@ -3270,7 +3261,7 @@
 		tx_flags |= E1000_TX_FLAGS_NO_FCS;
 
 	count = e1000_tx_map(adapter, tx_ring, skb, first, max_per_txd,
-	                     nr_frags, mss);
+			     nr_frags, mss);
 
 	if (count) {
 		netdev_sent_queue(netdev, skb->len);
@@ -3372,9 +3363,7 @@
 	/* Print Registers */
 	e1000_regdump(adapter);
 
-	/*
-	 * transmit dump
-	 */
+	/* transmit dump */
 	pr_info("TX Desc ring0 dump\n");
 
 	/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
@@ -3435,9 +3424,7 @@
 	}
 
 rx_ring_summary:
-	/*
-	 * receive dump
-	 */
+	/* receive dump */
 	pr_info("\nRX Desc ring dump\n");
 
 	/* Legacy Receive Descriptor Format
@@ -3502,7 +3489,6 @@
  * e1000_tx_timeout - Respond to a Tx Hang
  * @netdev: network interface device structure
  **/
-
 static void e1000_tx_timeout(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3530,7 +3516,6 @@
  * Returns the address of the device statistics structure.
  * The statistics are actually updated from the watchdog.
  **/
-
 static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
 {
 	/* only return the current stats */
@@ -3544,7 +3529,6 @@
  *
  * Returns 0 on success, negative on failure
  **/
-
 static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3581,8 +3565,9 @@
 	 * means we reserve 2 more, this pushes us to allocate from the next
 	 * larger slab size.
 	 * i.e. RXBUFFER_2048 --> size-4096 slab
-	 *  however with the new *_jumbo_rx* routines, jumbo receives will use
-	 *  fragmented skbs */
+	 * however with the new *_jumbo_rx* routines, jumbo receives will use
+	 * fragmented skbs
+	 */
 
 	if (max_frame <= E1000_RXBUFFER_2048)
 		adapter->rx_buffer_len = E1000_RXBUFFER_2048;
@@ -3617,7 +3602,6 @@
  * e1000_update_stats - Update the board statistics counters
  * @adapter: board private structure
  **/
-
 void e1000_update_stats(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
@@ -3628,8 +3612,7 @@
 
 #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
-	/*
-	 * Prevent stats update while adapter is being reset, or if the pci
+	/* Prevent stats update while adapter is being reset, or if the pci
 	 * connection is down.
 	 */
 	if (adapter->link_speed == 0)
@@ -3719,7 +3702,8 @@
 	/* Rx Errors */
 
 	/* 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
+	 */
 	netdev->stats.rx_errors = adapter->stats.rxerrc +
 		adapter->stats.crcerrs + adapter->stats.algnerrc +
 		adapter->stats.ruc + adapter->stats.roc +
@@ -3773,7 +3757,6 @@
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
  **/
-
 static irqreturn_t e1000_intr(int irq, void *data)
 {
 	struct net_device *netdev = data;
@@ -3784,8 +3767,7 @@
 	if (unlikely((!icr)))
 		return IRQ_NONE;  /* Not our interrupt */
 
-	/*
-	 * we might have caused the interrupt, but the above
+	/* we might have caused the interrupt, but the above
 	 * read cleared it, and just in case the driver is
 	 * down there is nothing to do so return handled
 	 */
@@ -3811,7 +3793,8 @@
 		__napi_schedule(&adapter->napi);
 	} else {
 		/* this really should not happen! if it does it is basically a
-		 * bug, but not a hard error, so enable ints and continue */
+		 * bug, but not a hard error, so enable ints and continue
+		 */
 		if (!test_bit(__E1000_DOWN, &adapter->flags))
 			e1000_irq_enable(adapter);
 	}
@@ -3825,7 +3808,8 @@
  **/
 static int e1000_clean(struct napi_struct *napi, int budget)
 {
-	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter,
+						     napi);
 	int tx_clean_complete = 0, work_done = 0;
 
 	tx_clean_complete = e1000_clean_tx_irq(adapter, &adapter->tx_ring[0]);
@@ -3916,11 +3900,12 @@
 
 	if (adapter->detect_tx_hung) {
 		/* Detect a transmit hang in hardware, this serializes the
-		 * check with the clearing of time_stamp and movement of i */
+		 * check with the clearing of time_stamp and movement of i
+		 */
 		adapter->detect_tx_hung = false;
 		if (tx_ring->buffer_info[eop].time_stamp &&
 		    time_after(jiffies, tx_ring->buffer_info[eop].time_stamp +
-		               (adapter->tx_timeout_factor * HZ)) &&
+			       (adapter->tx_timeout_factor * HZ)) &&
 		    !(er32(STATUS) & E1000_STATUS_TXOFF)) {
 
 			/* detected Tx unit hang */
@@ -3963,7 +3948,6 @@
  * @csum:        receive descriptor csum field
  * @sk_buff:     socket buffer with received data
  **/
-
 static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
 			      u32 csum, struct sk_buff *skb)
 {
@@ -3999,7 +3983,7 @@
  * e1000_consume_page - helper function
  **/
 static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
-                               u16 length)
+			       u16 length)
 {
 	bi->page = NULL;
 	skb->len += length;
@@ -4095,11 +4079,11 @@
 			if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
 				       last_byte)) {
 				spin_lock_irqsave(&adapter->stats_lock,
-				                  irq_flags);
+						  irq_flags);
 				e1000_tbi_adjust_stats(hw, &adapter->stats,
 						       length, mapped);
 				spin_unlock_irqrestore(&adapter->stats_lock,
-				                       irq_flags);
+						       irq_flags);
 				length--;
 			} else {
 				if (netdev->features & NETIF_F_RXALL)
@@ -4107,7 +4091,8 @@
 				/* recycle both page and skb */
 				buffer_info->skb = skb;
 				/* an error means any chain goes out the window
-				 * too */
+				 * too
+				 */
 				if (rx_ring->rx_skb_top)
 					dev_kfree_skb(rx_ring->rx_skb_top);
 				rx_ring->rx_skb_top = NULL;
@@ -4123,7 +4108,7 @@
 				/* this is the beginning of a chain */
 				rxtop = skb;
 				skb_fill_page_desc(rxtop, 0, buffer_info->page,
-				                   0, length);
+						   0, length);
 			} else {
 				/* this is the middle of a chain */
 				skb_fill_page_desc(rxtop,
@@ -4141,38 +4126,42 @@
 				    skb_shinfo(rxtop)->nr_frags,
 				    buffer_info->page, 0, length);
 				/* re-use the current skb, we only consumed the
-				 * page */
+				 * page
+				 */
 				buffer_info->skb = skb;
 				skb = rxtop;
 				rxtop = NULL;
 				e1000_consume_page(buffer_info, skb, length);
 			} else {
 				/* no chain, got EOP, this buf is the packet
-				 * copybreak to save the put_page/alloc_page */
+				 * copybreak to save the put_page/alloc_page
+				 */
 				if (length <= copybreak &&
 				    skb_tailroom(skb) >= length) {
 					u8 *vaddr;
 					vaddr = kmap_atomic(buffer_info->page);
-					memcpy(skb_tail_pointer(skb), vaddr, length);
+					memcpy(skb_tail_pointer(skb), vaddr,
+					       length);
 					kunmap_atomic(vaddr);
 					/* re-use the page, so don't erase
-					 * buffer_info->page */
+					 * buffer_info->page
+					 */
 					skb_put(skb, length);
 				} else {
 					skb_fill_page_desc(skb, 0,
-					                   buffer_info->page, 0,
-				                           length);
+							   buffer_info->page, 0,
+							   length);
 					e1000_consume_page(buffer_info, skb,
-					                   length);
+							   length);
 				}
 			}
 		}
 
 		/* Receive Checksum Offload XXX recompute due to CRC strip? */
 		e1000_rx_checksum(adapter,
-		                  (u32)(status) |
-		                  ((u32)(rx_desc->errors) << 24),
-		                  le16_to_cpu(rx_desc->csum), skb);
+				  (u32)(status) |
+				  ((u32)(rx_desc->errors) << 24),
+				  le16_to_cpu(rx_desc->csum), skb);
 
 		total_rx_bytes += (skb->len - 4); /* don't count FCS */
 		if (likely(!(netdev->features & NETIF_F_RXFCS)))
@@ -4214,8 +4203,7 @@
 	return cleaned;
 }
 
-/*
- * this should improve performance for small packets with large amounts
+/* this should improve performance for small packets with large amounts
  * of reassembly being done in the stack
  */
 static void e1000_check_copybreak(struct net_device *netdev,
@@ -4319,9 +4307,9 @@
 				       last_byte)) {
 				spin_lock_irqsave(&adapter->stats_lock, flags);
 				e1000_tbi_adjust_stats(hw, &adapter->stats,
-				                       length, skb->data);
+						       length, skb->data);
 				spin_unlock_irqrestore(&adapter->stats_lock,
-				                       flags);
+						       flags);
 				length--;
 			} else {
 				if (netdev->features & NETIF_F_RXALL)
@@ -4386,10 +4374,9 @@
  * @rx_ring: pointer to receive ring structure
  * @cleaned_count: number of buffers to allocate this pass
  **/
-
 static void
 e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
-                             struct e1000_rx_ring *rx_ring, int cleaned_count)
+			     struct e1000_rx_ring *rx_ring, int cleaned_count)
 {
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
@@ -4430,7 +4417,7 @@
 
 		if (!buffer_info->dma) {
 			buffer_info->dma = dma_map_page(&pdev->dev,
-			                                buffer_info->page, 0,
+							buffer_info->page, 0,
 							buffer_info->length,
 							DMA_FROM_DEVICE);
 			if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
@@ -4460,7 +4447,8 @@
 		/* Force memory writes to complete before letting h/w
 		 * know there are new descriptors to fetch.  (Only
 		 * applicable for weak-ordered memory model archs,
-		 * such as IA-64). */
+		 * such as IA-64).
+		 */
 		wmb();
 		writel(i, adapter->hw.hw_addr + rx_ring->rdt);
 	}
@@ -4470,7 +4458,6 @@
  * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
  * @adapter: address of board private structure
  **/
-
 static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
 				   struct e1000_rx_ring *rx_ring,
 				   int cleaned_count)
@@ -4541,8 +4528,7 @@
 			break; /* while !buffer_info->skb */
 		}
 
-		/*
-		 * XXX if it was allocated cleanly it will never map to a
+		/* XXX if it was allocated cleanly it will never map to a
 		 * boundary crossing
 		 */
 
@@ -4580,7 +4566,8 @@
 		/* Force memory writes to complete before letting h/w
 		 * know there are new descriptors to fetch.  (Only
 		 * applicable for weak-ordered memory model archs,
-		 * such as IA-64). */
+		 * such as IA-64).
+		 */
 		wmb();
 		writel(i, hw->hw_addr + rx_ring->rdt);
 	}
@@ -4590,7 +4577,6 @@
  * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
  * @adapter:
  **/
-
 static void e1000_smartspeed(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -4603,7 +4589,8 @@
 
 	if (adapter->smartspeed == 0) {
 		/* If Master/Slave config fault is asserted twice,
-		 * we assume back-to-back */
+		 * we assume back-to-back
+		 */
 		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
 		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
 		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
@@ -4616,7 +4603,7 @@
 			adapter->smartspeed++;
 			if (!e1000_phy_setup_autoneg(hw) &&
 			   !e1000_read_phy_reg(hw, PHY_CTRL,
-				   	       &phy_ctrl)) {
+					       &phy_ctrl)) {
 				phy_ctrl |= (MII_CR_AUTO_NEG_EN |
 					     MII_CR_RESTART_AUTO_NEG);
 				e1000_write_phy_reg(hw, PHY_CTRL,
@@ -4647,7 +4634,6 @@
  * @ifreq:
  * @cmd:
  **/
-
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
 	switch (cmd) {
@@ -4666,7 +4652,6 @@
  * @ifreq:
  * @cmd:
  **/
-
 static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
 			   int cmd)
 {
@@ -4928,7 +4913,8 @@
 	hw->autoneg = 0;
 
 	/* Make sure dplx is at most 1 bit and lsb of speed is not set
-	 * for the switch() below to work */
+	 * for the switch() below to work
+	 */
 	if ((spd & 1) || (dplx & ~1))
 		goto err_inval;
 
@@ -5131,8 +5117,7 @@
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling 'interrupt' - used by things like netconsole to send skbs
+/* Polling 'interrupt' - used by things like netconsole to send skbs
  * without having to re-enable interrupts. It's not called while
  * the interrupt routine is executing.
  */
diff --git a/drivers/net/ethernet/intel/e1000/e1000_param.c b/drivers/net/ethernet/intel/e1000/e1000_param.c
index 750fc01..c9cde35 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_param.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_param.c
@@ -267,7 +267,6 @@
  * value exists, a default value is used.  The final value is stored
  * in a variable in the adapter structure.
  **/
-
 void e1000_check_options(struct e1000_adapter *adapter)
 {
 	struct e1000_option opt;
@@ -319,7 +318,8 @@
 			.def  = E1000_DEFAULT_RXD,
 			.arg  = { .r = {
 				.min = E1000_MIN_RXD,
-				.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD
+				.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
+				       E1000_MAX_82544_RXD
 			}}
 		};
 
@@ -408,7 +408,7 @@
 		if (num_TxAbsIntDelay > bd) {
 			adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
 			e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
-			                      adapter);
+					      adapter);
 		} else {
 			adapter->tx_abs_int_delay = opt.def;
 		}
@@ -426,7 +426,7 @@
 		if (num_RxIntDelay > bd) {
 			adapter->rx_int_delay = RxIntDelay[bd];
 			e1000_validate_option(&adapter->rx_int_delay, &opt,
-			                      adapter);
+					      adapter);
 		} else {
 			adapter->rx_int_delay = opt.def;
 		}
@@ -444,7 +444,7 @@
 		if (num_RxAbsIntDelay > bd) {
 			adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
 			e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
-			                      adapter);
+					      adapter);
 		} else {
 			adapter->rx_abs_int_delay = opt.def;
 		}
@@ -479,16 +479,17 @@
 				break;
 			case 4:
 				e_dev_info("%s set to simplified "
-				           "(2000-8000) ints mode\n", opt.name);
+					   "(2000-8000) ints mode\n", opt.name);
 				adapter->itr_setting = adapter->itr;
 				break;
 			default:
 				e1000_validate_option(&adapter->itr, &opt,
-				        adapter);
+						      adapter);
 				/* save the setting, because the dynamic bits
 				 * change itr.
 				 * clear the lower two bits because they are
-				 * used as control */
+				 * used as control
+				 */
 				adapter->itr_setting = adapter->itr & ~3;
 				break;
 			}
@@ -533,7 +534,6 @@
  *
  * Handles speed and duplex options on fiber adapters
  **/
-
 static void e1000_check_fiber_options(struct e1000_adapter *adapter)
 {
 	int bd = adapter->bd_number;
@@ -559,7 +559,6 @@
  *
  * Handles speed and duplex options on copper adapters
  **/
-
 static void e1000_check_copper_options(struct e1000_adapter *adapter)
 {
 	struct e1000_option opt;
@@ -681,22 +680,22 @@
 		e_dev_info("Using Autonegotiation at Half Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
-		                                 ADVERTISE_100_HALF;
+						 ADVERTISE_100_HALF;
 		break;
 	case FULL_DUPLEX:
 		e_dev_info("Full Duplex specified without Speed\n");
 		e_dev_info("Using Autonegotiation at Full Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
-		                                 ADVERTISE_100_FULL |
-		                                 ADVERTISE_1000_FULL;
+						 ADVERTISE_100_FULL |
+						 ADVERTISE_1000_FULL;
 		break;
 	case SPEED_10:
 		e_dev_info("10 Mbps Speed specified without Duplex\n");
 		e_dev_info("Using Autonegotiation at 10 Mbps only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
-		                                 ADVERTISE_10_FULL;
+						 ADVERTISE_10_FULL;
 		break;
 	case SPEED_10 + HALF_DUPLEX:
 		e_dev_info("Forcing to 10 Mbps Half Duplex\n");
@@ -715,7 +714,7 @@
 		e_dev_info("Using Autonegotiation at 100 Mbps only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
-		                                 ADVERTISE_100_FULL;
+						 ADVERTISE_100_FULL;
 		break;
 	case SPEED_100 + HALF_DUPLEX:
 		e_dev_info("Forcing to 100 Mbps Half Duplex\n");
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index e73c2c3..e099138 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -32,69 +32,6 @@
 
 #include "e1000.h"
 
-#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL	 0x00
-#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL	 0x02
-#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL	 0x10
-#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE	 0x1F
-
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS	 0x0008
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS	 0x0800
-#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING	 0x0010
-
-#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
-#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT	 0x0000
-#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE		 0x2000
-
-#define E1000_KMRNCTRLSTA_OPMODE_MASK		 0x000C
-#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO	 0x0004
-
-#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
-#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN	 0x00010000
-
-#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN	 0x8
-#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN	 0x9
-
-/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
-#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE	 0x0002 /* 1=Reversal Disab. */
-#define GG82563_PSCR_CROSSOVER_MODE_MASK	 0x0060
-#define GG82563_PSCR_CROSSOVER_MODE_MDI		 0x0000 /* 00=Manual MDI */
-#define GG82563_PSCR_CROSSOVER_MODE_MDIX	 0x0020 /* 01=Manual MDIX */
-#define GG82563_PSCR_CROSSOVER_MODE_AUTO	 0x0060 /* 11=Auto crossover */
-
-/* PHY Specific Control Register 2 (Page 0, Register 26) */
-#define GG82563_PSCR2_REVERSE_AUTO_NEG		 0x2000
-						/* 1=Reverse Auto-Negotiation */
-
-/* MAC Specific Control Register (Page 2, Register 21) */
-/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
-#define GG82563_MSCR_TX_CLK_MASK		 0x0007
-#define GG82563_MSCR_TX_CLK_10MBPS_2_5		 0x0004
-#define GG82563_MSCR_TX_CLK_100MBPS_25		 0x0005
-#define GG82563_MSCR_TX_CLK_1000MBPS_25		 0x0007
-
-#define GG82563_MSCR_ASSERT_CRS_ON_TX		 0x0010 /* 1=Assert */
-
-/* DSP Distance Register (Page 5, Register 26) */
-#define GG82563_DSPD_CABLE_LENGTH		 0x0007 /* 0 = <50M
-							   1 = 50-80M
-							   2 = 80-110M
-							   3 = 110-140M
-							   4 = >140M
-							*/
-
-/* Kumeran Mode Control Register (Page 193, Register 16) */
-#define GG82563_KMCR_PASS_FALSE_CARRIER		 0x0800
-
-/* Max number of times Kumeran read/write should be validated */
-#define GG82563_MAX_KMRN_RETRY  0x5
-
-/* Power Management Control Register (Page 193, Register 20) */
-#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE	 0x0001
-					   /* 1=Enable SERDES Electrical Idle */
-
-/* In-Band Control Register (Page 194, Register 18) */
-#define GG82563_ICR_DIS_PADDING			 0x0010 /* Disable Padding */
-
 /* A table for the GG82563 cable length where the range is defined
  * with a lower bound at "index" and the upper bound at
  * "index + 5".
@@ -111,11 +48,10 @@
 static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
-static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
-static s32  e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                            u16 *data);
-static s32  e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                             u16 data);
+static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+					   u16 *data);
+static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+					    u16 data);
 static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
 
 /**
@@ -625,16 +561,16 @@
 
 	e_dbg("GG82563 PSCR: %X\n", phy_data);
 
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
 	if (ret_val)
 		return ret_val;
 
 	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
 
 	/* Reset the phy to commit changes. */
-	phy_data |= MII_CR_RESET;
+	phy_data |= BMCR_RESET;
 
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
 	if (ret_val)
 		return ret_val;
 
@@ -696,7 +632,7 @@
 static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = 0;
+	s32 ret_val;
 	u16 phy_data, index;
 
 	ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
@@ -774,6 +710,9 @@
 	ctrl = er32(CTRL);
 
 	ret_val = e1000_acquire_phy_80003es2lan(hw);
+	if (ret_val)
+		return ret_val;
+
 	e_dbg("Issuing a global reset to MAC\n");
 	ew32(CTRL, ctrl | E1000_CTRL_RST);
 	e1000_release_phy_80003es2lan(hw);
@@ -833,6 +772,8 @@
 
 	/* Setup link and flow control */
 	ret_val = mac->ops.setup_link(hw);
+	if (ret_val)
+		return ret_val;
 
 	/* Disable IBIST slave mode (far-end loopback) */
 	e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
@@ -1006,7 +947,7 @@
 		return ret_val;
 
 	/* SW Reset the PHY so all changes take effect */
-	ret_val = e1000e_commit_phy(hw);
+	ret_val = hw->phy.ops.commit(hw);
 	if (ret_val) {
 		e_dbg("Error Resetting the PHY\n");
 		return ret_val;
@@ -1272,7 +1213,7 @@
 					   u16 *data)
 {
 	u32 kmrnctrlsta;
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
 	if (ret_val)
@@ -1307,7 +1248,7 @@
 					    u16 data)
 {
 	u32 kmrnctrlsta;
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
 	if (ret_val)
@@ -1331,7 +1272,7 @@
  **/
 static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
 {
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	/* If there's an alternate MAC address place it in RAR0
 	 * so that it will override the Si installed default perm
@@ -1434,18 +1375,18 @@
 	.acquire		= e1000_acquire_phy_80003es2lan,
 	.check_polarity		= e1000_check_polarity_m88,
 	.check_reset_block	= e1000e_check_reset_block_generic,
-	.commit		 	= e1000e_phy_sw_reset,
-	.force_speed_duplex 	= e1000_phy_force_speed_duplex_80003es2lan,
-	.get_cfg_done       	= e1000_get_cfg_done_80003es2lan,
-	.get_cable_length   	= e1000_get_cable_length_80003es2lan,
-	.get_info       	= e1000e_get_phy_info_m88,
-	.read_reg       	= e1000_read_phy_reg_gg82563_80003es2lan,
+	.commit			= e1000e_phy_sw_reset,
+	.force_speed_duplex	= e1000_phy_force_speed_duplex_80003es2lan,
+	.get_cfg_done		= e1000_get_cfg_done_80003es2lan,
+	.get_cable_length	= e1000_get_cable_length_80003es2lan,
+	.get_info		= e1000e_get_phy_info_m88,
+	.read_reg		= e1000_read_phy_reg_gg82563_80003es2lan,
 	.release		= e1000_release_phy_80003es2lan,
-	.reset		  	= e1000e_phy_hw_reset_generic,
-	.set_d0_lplu_state  	= NULL,
-	.set_d3_lplu_state  	= e1000e_set_d3_lplu_state,
-	.write_reg      	= e1000_write_phy_reg_gg82563_80003es2lan,
-	.cfg_on_link_up      	= e1000_cfg_on_link_up_80003es2lan,
+	.reset			= e1000e_phy_hw_reset_generic,
+	.set_d0_lplu_state	= NULL,
+	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
+	.write_reg		= e1000_write_phy_reg_gg82563_80003es2lan,
+	.cfg_on_link_up		= e1000_cfg_on_link_up_80003es2lan,
 };
 
 static const struct e1000_nvm_operations es2_nvm_ops = {
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.h b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
new file mode 100644
index 0000000..90d363b
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
@@ -0,0 +1,95 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_80003ES2LAN_H_
+#define _E1000E_80003ES2LAN_H_
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL	0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL	0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL	0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE	0x1F
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS	0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS	0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING	0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT	0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE		0x2000
+
+#define E1000_KMRNCTRLSTA_OPMODE_MASK		0x000C
+#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO	0x0004
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00	/* Gig Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN	0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN	0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN	0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE	0x0002	/* 1=Reversal Dis */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK	0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI		0x0000	/* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX	0x0020	/* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO	0x0060	/* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG		0x2000	/* 1=Reverse Auto-Neg */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK		0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5		0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25		0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_25		0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX		0x0010	/* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26)
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-100M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define GG82563_DSPD_CABLE_LENGTH		0x0007
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER		0x0800
+
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY			0x5
+
+/* Power Management Control Register (Page 193, Register 20) */
+/* 1=Enable SERDES Electrical Idle */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE	0x0001
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING			0x0010	/* Disable Padding */
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index c77d010..2faffbd 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -44,21 +44,6 @@
 
 #include "e1000.h"
 
-#define ID_LED_RESERVED_F746 0xF746
-#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
-			      (ID_LED_OFF1_ON2  <<  8) | \
-			      (ID_LED_DEF1_DEF2 <<  4) | \
-			      (ID_LED_DEF1_DEF2))
-
-#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
-#define AN_RETRY_COUNT          5 /* Autoneg Retry Count value */
-#define E1000_BASE1000T_STATUS          10
-#define E1000_IDLE_ERROR_COUNT_MASK     0xFF
-#define E1000_RECEIVE_ERROR_COUNTER     21
-#define E1000_RECEIVE_ERROR_MAX         0xFFFF
-
-#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
-
 static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
 static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
 static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
@@ -67,9 +52,7 @@
 				      u16 words, u16 *data);
 static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
-static s32 e1000_setup_link_82571(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
-static void e1000_clear_vfta_82571(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
 static s32 e1000_led_on_82574(struct e1000_hw *hw);
 static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
@@ -449,13 +432,13 @@
 		break;
 	case e1000_82574:
 	case e1000_82583:
-		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+		ret_val = e1e_rphy(hw, MII_PHYSID1, &phy_id);
 		if (ret_val)
 			return ret_val;
 
 		phy->id = (u32)(phy_id << 16);
 		udelay(20);
-		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+		ret_val = e1e_rphy(hw, MII_PHYSID2, &phy_id);
 		if (ret_val)
 			return ret_val;
 
@@ -556,16 +539,14 @@
 	s32 i = 0;
 
 	extcnf_ctrl = er32(EXTCNF_CTRL);
-	extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
 	do {
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
 		ew32(EXTCNF_CTRL, extcnf_ctrl);
 		extcnf_ctrl = er32(EXTCNF_CTRL);
 
 		if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
 			break;
 
-		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
 		usleep_range(2000, 4000);
 		i++;
 	} while (i < MDIO_OWNERSHIP_TIMEOUT);
@@ -937,6 +918,8 @@
 
 		/* When LPLU is enabled, we should disable SmartSpeed */
 		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+		if (ret_val)
+			return ret_val;
 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
 		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
 		if (ret_val)
@@ -1329,9 +1312,10 @@
 			 */
 			vfta_offset = (hw->mng_cookie.vlan_id >>
 				       E1000_VFTA_ENTRY_SHIFT) &
-				      E1000_VFTA_ENTRY_MASK;
-			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
-					       E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+			    E1000_VFTA_ENTRY_MASK;
+			vfta_bit_in_reg =
+			    1 << (hw->mng_cookie.vlan_id &
+				  E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
 		}
 		break;
 	default:
@@ -1399,7 +1383,7 @@
 {
 	u16 status_1kbt = 0;
 	u16 receive_errors = 0;
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	/* Read PHY Receive Error counter first, if its is max - all F's then
 	 * read the Base1000T status register If both are max then PHY is hung.
@@ -1544,13 +1528,12 @@
 
 	ctrl = er32(CTRL);
 	status = er32(STATUS);
-	rxcw = er32(RXCW);
+	er32(RXCW);
 	/* SYNCH bit and IV bit are sticky */
 	udelay(10);
 	rxcw = er32(RXCW);
 
 	if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
-
 		/* Receiver is synchronized with no invalid bits.  */
 		switch (mac->serdes_link_state) {
 		case e1000_serdes_link_autoneg_complete:
@@ -1799,6 +1782,8 @@
 			if (ret_val)
 				return ret_val;
 			ret_val = e1000e_update_nvm_checksum(hw);
+			if (ret_val)
+				return ret_val;
 		}
 	}
 
@@ -1812,7 +1797,7 @@
 static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
 {
 	if (hw->mac.type == e1000_82571) {
-		s32 ret_val = 0;
+		s32 ret_val;
 
 		/* If there's an alternate MAC address place it in RAR0
 		 * so that it will override the Si installed default perm
@@ -1931,7 +1916,7 @@
 	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
 	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
 	.write_reg		= e1000e_write_phy_reg_igp,
-	.cfg_on_link_up      	= NULL,
+	.cfg_on_link_up		= NULL,
 };
 
 static const struct e1000_phy_operations e82_phy_ops_m88 = {
@@ -1940,7 +1925,7 @@
 	.check_reset_block	= e1000e_check_reset_block_generic,
 	.commit			= e1000e_phy_sw_reset,
 	.force_speed_duplex	= e1000e_phy_force_speed_duplex_m88,
-	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cfg_done		= e1000e_get_cfg_done_generic,
 	.get_cable_length	= e1000e_get_cable_length_m88,
 	.get_info		= e1000e_get_phy_info_m88,
 	.read_reg		= e1000e_read_phy_reg_m88,
@@ -1949,7 +1934,7 @@
 	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
 	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
 	.write_reg		= e1000e_write_phy_reg_m88,
-	.cfg_on_link_up      	= NULL,
+	.cfg_on_link_up		= NULL,
 };
 
 static const struct e1000_phy_operations e82_phy_ops_bm = {
@@ -1958,7 +1943,7 @@
 	.check_reset_block	= e1000e_check_reset_block_generic,
 	.commit			= e1000e_phy_sw_reset,
 	.force_speed_duplex	= e1000e_phy_force_speed_duplex_m88,
-	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cfg_done		= e1000e_get_cfg_done_generic,
 	.get_cable_length	= e1000e_get_cable_length_m88,
 	.get_info		= e1000e_get_phy_info_m88,
 	.read_reg		= e1000e_read_phy_reg_bm2,
@@ -1967,7 +1952,7 @@
 	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
 	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
 	.write_reg		= e1000e_write_phy_reg_bm2,
-	.cfg_on_link_up      	= NULL,
+	.cfg_on_link_up		= NULL,
 };
 
 static const struct e1000_nvm_operations e82571_nvm_ops = {
@@ -2044,6 +2029,7 @@
 				  | FLAG_HAS_MSIX
 				  | FLAG_HAS_JUMBO_FRAMES
 				  | FLAG_HAS_WOL
+				  | FLAG_HAS_HW_TIMESTAMP
 				  | FLAG_APME_IN_CTRL3
 				  | FLAG_HAS_SMART_POWER_DOWN
 				  | FLAG_HAS_AMT
@@ -2065,6 +2051,7 @@
 	.mac			= e1000_82583,
 	.flags			= FLAG_HAS_HW_VLAN_FILTER
 				  | FLAG_HAS_WOL
+				  | FLAG_HAS_HW_TIMESTAMP
 				  | FLAG_APME_IN_CTRL3
 				  | FLAG_HAS_SMART_POWER_DOWN
 				  | FLAG_HAS_AMT
diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h
new file mode 100644
index 0000000..85cb1a3
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/82571.h
@@ -0,0 +1,58 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_82571_H_
+#define _E1000E_82571_H_
+
+#define ID_LED_RESERVED_F746	0xF746
+#define ID_LED_DEFAULT_82573	((ID_LED_DEF1_DEF2 << 12) | \
+				 (ID_LED_OFF1_ON2  <<  8) | \
+				 (ID_LED_DEF1_DEF2 <<  4) | \
+				 (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX	0x08000000
+#define AN_RETRY_COUNT		5	/* Autoneg Retry Count value */
+
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n)	(0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574	0x000DC	/* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574	0x01F00000
+
+/* Manageability Operation Mode mask */
+#define E1000_NVM_INIT_CTRL2_MNGM	0x6000
+
+#define E1000_BASE1000T_STATUS		10
+#define E1000_IDLE_ERROR_COUNT_MASK	0xFF
+#define E1000_RECEIVE_ERROR_COUNTER	21
+#define E1000_RECEIVE_ERROR_MAX		0xFFFF
+bool e1000_check_phy_82574(struct e1000_hw *hw);
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile
index 591b713..c2dcfcc 100644
--- a/drivers/net/ethernet/intel/e1000e/Makefile
+++ b/drivers/net/ethernet/intel/e1000e/Makefile
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -34,5 +34,5 @@
 
 e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \
 	       mac.o manage.o nvm.o phy.o \
-	       param.o ethtool.o netdev.o
+	       param.o ethtool.o netdev.o ptp.o
 
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 4dab6fc..fc3a4fe 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -29,25 +29,6 @@
 #ifndef _E1000_DEFINES_H_
 #define _E1000_DEFINES_H_
 
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-
 /* Number of Transmit and Receive Descriptors must be a multiple of 8 */
 #define REQ_TX_DESCRIPTOR_MULTIPLE  8
 #define REQ_RX_DESCRIPTOR_MULTIPLE  8
@@ -86,7 +67,6 @@
 #define E1000_CTRL_EXT_EIAME          0x01000000
 #define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
 #define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
-#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
 #define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
 #define E1000_CTRL_EXT_LSECCK         0x00001000
 #define E1000_CTRL_EXT_PHYPDEN        0x00100000
@@ -107,6 +87,7 @@
 #define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
 #define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
 
+#define E1000_RXDEXT_STATERR_TST   0x00000100	/* Time Stamp taken */
 #define E1000_RXDEXT_STATERR_CE    0x01000000
 #define E1000_RXDEXT_STATERR_SE    0x02000000
 #define E1000_RXDEXT_STATERR_SEQ   0x04000000
@@ -115,19 +96,19 @@
 
 /* mask to determine if packets should be dropped due to frame errors */
 #define E1000_RXD_ERR_FRAME_ERR_MASK ( \
-    E1000_RXD_ERR_CE  |                \
-    E1000_RXD_ERR_SE  |                \
-    E1000_RXD_ERR_SEQ |                \
-    E1000_RXD_ERR_CXE |                \
-    E1000_RXD_ERR_RXE)
+	E1000_RXD_ERR_CE  |		\
+	E1000_RXD_ERR_SE  |		\
+	E1000_RXD_ERR_SEQ |		\
+	E1000_RXD_ERR_CXE |		\
+	E1000_RXD_ERR_RXE)
 
 /* Same mask, but for extended and packet split descriptors */
 #define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
-    E1000_RXDEXT_STATERR_CE  |            \
-    E1000_RXDEXT_STATERR_SE  |            \
-    E1000_RXDEXT_STATERR_SEQ |            \
-    E1000_RXDEXT_STATERR_CXE |            \
-    E1000_RXDEXT_STATERR_RXE)
+	E1000_RXDEXT_STATERR_CE  |	\
+	E1000_RXDEXT_STATERR_SE  |	\
+	E1000_RXDEXT_STATERR_SEQ |	\
+	E1000_RXDEXT_STATERR_CXE |	\
+	E1000_RXDEXT_STATERR_RXE)
 
 #define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
 #define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
@@ -242,9 +223,9 @@
 #define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
 #define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
 
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
+#define E1000_PCS_LCTL_FORCE_FCTRL	0x80
+
+#define E1000_PCS_LSTS_AN_COMPLETE	0x10000
 
 /* Device Status */
 #define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
@@ -260,8 +241,6 @@
 #define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
 #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
 
-/* Constants used to interpret the masked PCI-X bus speed. */
-
 #define HALF_DUPLEX 1
 #define FULL_DUPLEX 2
 
@@ -274,14 +253,15 @@
 #define ADVERTISE_1000_FULL               0x0020
 
 /* 1000/H is not supported, nor spec-compliant. */
-#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-				ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
-						     ADVERTISE_1000_FULL)
-#define E1000_ALL_NOT_GIG      ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-				ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
-#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+#define E1000_ALL_SPEED_DUPLEX	( \
+	ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
+	ADVERTISE_100_FULL | ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG	( \
+	ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
+	ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED	(ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED	(ADVERTISE_10_HALF | ADVERTISE_10_FULL)
+#define E1000_ALL_HALF_DUPLEX	(ADVERTISE_10_HALF | ADVERTISE_100_HALF)
 
 #define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
 
@@ -319,6 +299,7 @@
 #define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
 #define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
 #define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+#define E1000_TXD_EXTCMD_TSTAMP	0x00000010 /* IEEE1588 Timestamp packet */
 
 /* Transmit Control */
 #define E1000_TCTL_EN     0x00000002    /* enable Tx */
@@ -328,8 +309,6 @@
 #define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
 #define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
 
-/* Transmit Arbitration Count */
-
 /* SerDes Control */
 #define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
 
@@ -384,10 +363,15 @@
 
 #define E1000_KABGTXD_BGSQLBIAS           0x00050000
 
+/* Low Power IDLE Control */
+#define E1000_LPIC_LPIET_SHIFT		24	/* Low Power Idle Entry Time */
+
 /* PBA constants */
 #define E1000_PBA_8K  0x0008    /* 8KB */
 #define E1000_PBA_16K 0x0010    /* 16KB */
 
+#define E1000_PBA_RXA_MASK	0xFFFF
+
 #define E1000_PBS_16K E1000_PBA_16K
 
 /* Uncorrectable/correctable ECC Error counts and enable bits */
@@ -439,11 +423,11 @@
  *   o LSC    = Link Status Change
  */
 #define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC)
+	E1000_IMS_RXT0   |    \
+	E1000_IMS_TXDW   |    \
+	E1000_IMS_RXDMT0 |    \
+	E1000_IMS_RXSEQ  |    \
+	E1000_IMS_LSC)
 
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
@@ -542,6 +526,28 @@
 #define E1000_RXCW_C          0x20000000        /* Receive config */
 #define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
 
+#define E1000_TSYNCTXCTL_VALID		0x00000001 /* Tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED	0x00000010 /* enable Tx timestamping */
+
+#define E1000_TSYNCRXCTL_VALID		0x00000001 /* Rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK	0x0000000E /* Rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2	0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1	0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2	0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL	0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2	0x0A
+#define E1000_TSYNCRXCTL_ENABLED	0x00000010 /* enable Rx timestamping */
+#define E1000_TSYNCRXCTL_SYSCFI		0x00000020 /* Sys clock frequency */
+
+#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE	0x00000000
+#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE	0x00010000
+
+#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE	0x00000000
+#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE	0x01000000
+
+#define E1000_TIMINCA_INCPERIOD_SHIFT	24
+#define E1000_TIMINCA_INCVALUE_MASK	0x00FFFFFF
+
 /* PCI Express Control */
 #define E1000_GCR_RXD_NO_SNOOP          0x00000001
 #define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
@@ -557,66 +563,6 @@
 			   E1000_GCR_TXDSCW_NO_SNOOP      | \
 			   E1000_GCR_TXDSCR_NO_SNOOP)
 
-/* PHY Control Register */
-#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
-#define MII_CR_POWER_DOWN       0x0800  /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
-#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
-#define MII_CR_SPEED_1000       0x0040
-#define MII_CR_SPEED_100        0x2000
-#define MII_CR_SPEED_10         0x0000
-
-/* PHY Status Register */
-#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
-#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
-#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP 100TX Full Dplx Capable */
-#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS     0x0001 /* LP has Auto Neg Capability */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
-					/* 0=DTE device */
-#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
-					/* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
-					/* 0=Automatic Master/Slave config */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
-
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CONTROL      0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Register */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
-
-#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
-
 /* NVM Control */
 #define E1000_EECD_SK        0x00000001 /* NVM Clock */
 #define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
@@ -648,6 +594,10 @@
 /* NVM Word Offsets */
 #define NVM_COMPAT                 0x0003
 #define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_FUTURE_INIT_WORD1      0x0019
+#define NVM_COMPAT_VALID_CSUM      0x0001
+#define NVM_FUTURE_INIT_WORD1_VALID_CSUM	0x0040
+
 #define NVM_INIT_CONTROL2_REG      0x000F
 #define NVM_INIT_CONTROL3_PORT_B   0x0014
 #define NVM_INIT_3GIO_3            0x001A
@@ -656,8 +606,6 @@
 #define NVM_ALT_MAC_ADDR_PTR       0x0037
 #define NVM_CHECKSUM_REG           0x003F
 
-#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
-
 #define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
 #define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
 
@@ -766,9 +714,6 @@
 #define M88E1000_PSCR_AUTO_X_1000T     0x0040
 /* Auto crossover enabled all speeds */
 #define M88E1000_PSCR_AUTO_X_MODE      0x0060
-/* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold)
- * 0=Normal 10BASE-T Rx Threshold
- */
 #define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
 
 /* M88E1000 PHY Specific Status Register */
@@ -804,11 +749,6 @@
 /* BME1000 PHY Specific Control Register */
 #define BME1000_PSCR_ENABLE_DOWNSHIFT   0x0800 /* 1 = enable downshift */
 
-
-#define PHY_PAGE_SHIFT 5
-#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
-                           ((reg) & MAX_PHY_REG_ADDRESS))
-
 /* Bits...
  * 15-5: page
  * 4-0: register offset
@@ -855,8 +795,4 @@
 /* SerDes Control */
 #define E1000_GEN_POLL_TIMEOUT          640
 
-/* FW Semaphore */
-#define E1000_FWSM_WLOCK_MAC_MASK	0x0380
-#define E1000_FWSM_WLOCK_MAC_SHIFT	7
-
 #endif /* _E1000_DEFINES_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 7e95f22..fcc7581 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -41,7 +41,11 @@
 #include <linux/pci-aspm.h>
 #include <linux/crc32.h>
 #include <linux/if_vlan.h>
-
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_classify.h>
+#include <linux/mii.h>
 #include "hw.h"
 
 struct e1000_info;
@@ -75,9 +79,6 @@
 #define E1000_MIN_ITR_USECS		10 /* 100000 irq/sec */
 #define E1000_MAX_ITR_USECS		10000 /* 100    irq/sec */
 
-/* Early Receive defines */
-#define E1000_ERT_2048			0x100
-
 #define E1000_FC_PAUSE_TIME		0x0680 /* 858 usec */
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
@@ -94,70 +95,6 @@
 
 #define DEFAULT_JUMBO			9234
 
-/* BM/HV Specific Registers */
-#define BM_PORT_CTRL_PAGE                 769
-
-#define PHY_UPPER_SHIFT                   21
-#define BM_PHY_REG(page, reg) \
-	(((reg) & MAX_PHY_REG_ADDRESS) |\
-	 (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
-	 (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
-
-/* PHY Wakeup Registers and defines */
-#define BM_PORT_GEN_CFG PHY_REG(BM_PORT_CTRL_PAGE, 17)
-#define BM_RCTL         PHY_REG(BM_WUC_PAGE, 0)
-#define BM_WUC          PHY_REG(BM_WUC_PAGE, 1)
-#define BM_WUFC         PHY_REG(BM_WUC_PAGE, 2)
-#define BM_WUS          PHY_REG(BM_WUC_PAGE, 3)
-#define BM_RAR_L(_i)    (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
-#define BM_RAR_M(_i)    (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
-#define BM_RAR_H(_i)    (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
-#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
-#define BM_MTA(_i)      (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
-
-#define BM_RCTL_UPE           0x0001          /* Unicast Promiscuous Mode */
-#define BM_RCTL_MPE           0x0002          /* Multicast Promiscuous Mode */
-#define BM_RCTL_MO_SHIFT      3               /* Multicast Offset Shift */
-#define BM_RCTL_MO_MASK       (3 << 3)        /* Multicast Offset Mask */
-#define BM_RCTL_BAM           0x0020          /* Broadcast Accept Mode */
-#define BM_RCTL_PMCF          0x0040          /* Pass MAC Control Frames */
-#define BM_RCTL_RFCE          0x0080          /* Rx Flow Control Enable */
-
-#define HV_STATS_PAGE	778
-#define HV_SCC_UPPER	PHY_REG(HV_STATS_PAGE, 16) /* Single Collision Count */
-#define HV_SCC_LOWER	PHY_REG(HV_STATS_PAGE, 17)
-#define HV_ECOL_UPPER	PHY_REG(HV_STATS_PAGE, 18) /* Excessive Coll. Count */
-#define HV_ECOL_LOWER	PHY_REG(HV_STATS_PAGE, 19)
-#define HV_MCC_UPPER	PHY_REG(HV_STATS_PAGE, 20) /* Multiple Coll. Count */
-#define HV_MCC_LOWER	PHY_REG(HV_STATS_PAGE, 21)
-#define HV_LATECOL_UPPER PHY_REG(HV_STATS_PAGE, 23) /* Late Collision Count */
-#define HV_LATECOL_LOWER PHY_REG(HV_STATS_PAGE, 24)
-#define HV_COLC_UPPER	PHY_REG(HV_STATS_PAGE, 25) /* Collision Count */
-#define HV_COLC_LOWER	PHY_REG(HV_STATS_PAGE, 26)
-#define HV_DC_UPPER	PHY_REG(HV_STATS_PAGE, 27) /* Defer Count */
-#define HV_DC_LOWER	PHY_REG(HV_STATS_PAGE, 28)
-#define HV_TNCRS_UPPER	PHY_REG(HV_STATS_PAGE, 29) /* Transmit with no CRS */
-#define HV_TNCRS_LOWER	PHY_REG(HV_STATS_PAGE, 30)
-
-#define E1000_FCRTV_PCH     0x05F40 /* PCH Flow Control Refresh Timer Value */
-
-/* BM PHY Copper Specific Status */
-#define BM_CS_STATUS                      17
-#define BM_CS_STATUS_LINK_UP              0x0400
-#define BM_CS_STATUS_RESOLVED             0x0800
-#define BM_CS_STATUS_SPEED_MASK           0xC000
-#define BM_CS_STATUS_SPEED_1000           0x8000
-
-/* 82577 Mobile Phy Status Register */
-#define HV_M_STATUS                       26
-#define HV_M_STATUS_AUTONEG_COMPLETE      0x1000
-#define HV_M_STATUS_SPEED_MASK            0x0300
-#define HV_M_STATUS_SPEED_1000            0x0200
-#define HV_M_STATUS_LINK_UP               0x0040
-
-#define E1000_ICH_FWSM_PCIM2PCI		0x01000000 /* ME PCIm-to-PCI active */
-#define E1000_ICH_FWSM_PCIM2PCI_COUNT	2000
-
 /* Time to wait before putting the device into D3 if there's no link (in ms). */
 #define LINK_TIMEOUT		100
 
@@ -355,6 +292,7 @@
 	u64 gorc_old;
 	u32 alloc_rx_buff_failed;
 	u32 rx_dma_failed;
+	u32 rx_hwtstamp_cleared;
 
 	unsigned int rx_ps_pages;
 	u16 rx_ps_bsize0;
@@ -368,7 +306,7 @@
 	/* structs defined in e1000_hw.h */
 	struct e1000_hw hw;
 
-	spinlock_t stats64_lock;
+	spinlock_t stats64_lock;	/* protects statistics counters */
 	struct e1000_hw_stats stats;
 	struct e1000_phy_info phy_info;
 	struct e1000_phy_stats phy_stats;
@@ -404,6 +342,16 @@
 
 	u16 tx_ring_count;
 	u16 rx_ring_count;
+
+	struct hwtstamp_config hwtstamp_config;
+	struct delayed_work systim_overflow_work;
+	struct sk_buff *tx_hwtstamp_skb;
+	struct work_struct tx_hwtstamp_work;
+	spinlock_t systim_lock;	/* protects SYSTIML/H regsters */
+	struct cyclecounter cc;
+	struct timecounter tc;
+	struct ptp_clock *ptp_clock;
+	struct ptp_clock_info ptp_clock_info;
 };
 
 struct e1000_info {
@@ -418,6 +366,40 @@
 	const struct e1000_nvm_operations *nvm_ops;
 };
 
+s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
+
+/* The system time is maintained by a 64-bit counter comprised of the 32-bit
+ * SYSTIMH and SYSTIML registers.  How the counter increments (and therefore
+ * its resolution) is based on the contents of the TIMINCA register - it
+ * increments every incperiod (bits 31:24) clock ticks by incvalue (bits 23:0).
+ * For the best accuracy, the incperiod should be as small as possible.  The
+ * incvalue is scaled by a factor as large as possible (while still fitting
+ * in bits 23:0) so that relatively small clock corrections can be made.
+ *
+ * As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of
+ * INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n)
+ * bits to count nanoseconds leaving the rest for fractional nonseconds.
+ */
+#define INCVALUE_96MHz		125
+#define INCVALUE_SHIFT_96MHz	17
+#define INCPERIOD_SHIFT_96MHz	2
+#define INCPERIOD_96MHz		(12 >> INCPERIOD_SHIFT_96MHz)
+
+#define INCVALUE_25MHz		40
+#define INCVALUE_SHIFT_25MHz	18
+#define INCPERIOD_25MHz		1
+
+/* Another drawback of scaling the incvalue by a large factor is the
+ * 64-bit SYSTIM register overflows more quickly.  This is dealt with
+ * by simply reading the clock before it overflows.
+ *
+ * Clock	ns bits	Overflows after
+ * ~~~~~~	~~~~~~~	~~~~~~~~~~~~~~~
+ * 96MHz	47-bit	2^(47-INCPERIOD_SHIFT_96MHz) / 10^9 / 3600 = 9.77 hrs
+ * 25MHz	46-bit	2^46 / 10^9 / 3600 = 19.55 hours
+ */
+#define E1000_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 60 * 4)
+
 /* hardware capability, feature, and workaround flags */
 #define FLAG_HAS_AMT                      (1 << 0)
 #define FLAG_HAS_FLASH                    (1 << 1)
@@ -433,7 +415,7 @@
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
 #define FLAG_IS_QUAD_PORT_A               (1 << 12)
 #define FLAG_IS_QUAD_PORT                 (1 << 13)
-/* reserved bit14 */
+#define FLAG_HAS_HW_TIMESTAMP             (1 << 14)
 #define FLAG_APME_IN_WUC                  (1 << 15)
 #define FLAG_APME_IN_CTRL3                (1 << 16)
 #define FLAG_APME_CHECK_PORT_B            (1 << 17)
@@ -449,7 +431,7 @@
 #define FLAG_MSI_ENABLED                  (1 << 27)
 /* reserved (1 << 28) */
 #define FLAG_TSO_FORCE                    (1 << 29)
-#define FLAG_RX_RESTART_NOW               (1 << 30)
+#define FLAG_RESTART_NOW                  (1 << 30)
 #define FLAG_MSI_TEST_FAILED              (1 << 31)
 
 #define FLAG2_CRC_STRIPPING               (1 << 0)
@@ -465,6 +447,7 @@
 #define FLAG2_NO_DISABLE_RX               (1 << 10)
 #define FLAG2_PCIM2PCI_ARBITER_WA         (1 << 11)
 #define FLAG2_DFLT_CRC_STRIPPING          (1 << 12)
+#define FLAG2_CHECK_RX_HWTSTAMP           (1 << 13)
 
 #define E1000_RX_DESC_PS(R, i)	    \
 	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -514,8 +497,6 @@
 
 extern unsigned int copybreak;
 
-extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
-
 extern const struct e1000_info e1000_82571_info;
 extern const struct e1000_info e1000_82572_info;
 extern const struct e1000_info e1000_82573_info;
@@ -529,138 +510,8 @@
 extern const struct e1000_info e1000_pch_lpt_info;
 extern const struct e1000_info e1000_es2_info;
 
-extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
-					 u32 pba_num_size);
-
-extern s32  e1000e_commit_phy(struct e1000_hw *hw);
-
-extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
-
-extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
-extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
-
-extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
-extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
-						 bool state);
-extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw);
-extern void e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
-extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
-extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
-extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
-
-extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_setup_led_generic(struct e1000_hw *hw);
-extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
-extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
-extern void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
-extern void e1000_set_lan_id_single_port(struct e1000_hw *hw);
-extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
-extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
-extern s32 e1000e_id_led_init_generic(struct e1000_hw *hw);
-extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
-extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
-extern s32 e1000e_setup_link_generic(struct e1000_hw *hw);
-extern void e1000_clear_vfta_generic(struct e1000_hw *hw);
-extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
-extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-					       u8 *mc_addr_list,
-					       u32 mc_addr_count);
-extern void e1000e_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
-extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
-extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
-extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
-extern void e1000e_config_collision_dist_generic(struct e1000_hw *hw);
-extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
-extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
-extern s32 e1000e_blink_led_generic(struct e1000_hw *hw);
-extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
-extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
-extern void e1000e_reset_adaptive(struct e1000_hw *hw);
-extern void e1000e_update_adaptive(struct e1000_hw *hw);
-
-extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_id(struct e1000_hw *hw);
-extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
-extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
-extern s32 e1000_set_page_igp(struct e1000_hw *hw, u16 page);
-extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
-                                          u16 *data);
-extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
-extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
-                                           u16 data);
-extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
-extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
-extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw);
-extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
-extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
-extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw,
-						 u16 *phy_reg);
-extern s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw,
-						  u16 *phy_reg);
-extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
-extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset,
-                                        u16 data);
-extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset,
-                                       u16 *data);
-extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-			       u32 usec_interval, bool *success);
-extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
-extern void e1000_power_up_phy_copper(struct e1000_hw *hw);
-extern void e1000_power_down_phy_copper(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_check_downshift(struct e1000_hw *hw);
-extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset,
-                                        u16 *data);
-extern s32 e1000_read_phy_reg_page_hv(struct e1000_hw *hw, u32 offset,
-				      u16 *data);
-extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset,
-                                         u16 data);
-extern s32 e1000_write_phy_reg_page_hv(struct e1000_hw *hw, u32 offset,
-				       u16 data);
-extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
-extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
-extern s32 e1000_check_polarity_82577(struct e1000_hw *hw);
-extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
-extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
-extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
-
-extern s32 e1000_check_polarity_m88(struct e1000_hw *hw);
-extern s32 e1000_get_phy_info_ife(struct e1000_hw *hw);
-extern s32 e1000_check_polarity_ife(struct e1000_hw *hw);
-extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
-extern s32 e1000_check_polarity_igp(struct e1000_hw *hw);
-extern bool e1000_check_phy_82574(struct e1000_hw *hw);
+extern void e1000e_ptp_init(struct e1000_adapter *adapter);
+extern void e1000e_ptp_remove(struct e1000_adapter *adapter);
 
 static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
@@ -687,20 +538,7 @@
 	return hw->phy.ops.write_reg_locked(hw, offset, data);
 }
 
-static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
-{
-	return hw->phy.ops.get_cable_length(hw);
-}
-
-extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
-extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
-extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
-extern void e1000e_release_nvm(struct e1000_hw *hw);
 extern void e1000e_reload_nvm_generic(struct e1000_hw *hw);
-extern s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
 
 static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
 {
@@ -735,10 +573,6 @@
 	return hw->phy.ops.get_info(hw);
 }
 
-extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
-extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
-extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
-
 static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
 {
 	return readl(hw->hw_addr + reg);
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index fd4772a..2c18137 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
+#include <linux/mdio.h>
 
 #include "e1000.h"
 
@@ -98,7 +99,6 @@
 	E1000_STAT("rx_flow_control_xoff", stats.xoffrxc),
 	E1000_STAT("tx_flow_control_xon", stats.xontxc),
 	E1000_STAT("tx_flow_control_xoff", stats.xofftxc),
-	E1000_STAT("rx_long_byte_count", stats.gorc),
 	E1000_STAT("rx_csum_offload_good", hw_csum_good),
 	E1000_STAT("rx_csum_offload_errors", hw_csum_err),
 	E1000_STAT("rx_header_split", rx_hdr_split),
@@ -108,6 +108,7 @@
 	E1000_STAT("dropped_smbus", stats.mgpdc),
 	E1000_STAT("rx_dma_failed", rx_dma_failed),
 	E1000_STAT("tx_dma_failed", tx_dma_failed),
+	E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
 	E1000_STAT("uncorr_ecc_errors", uncorr_errors),
 	E1000_STAT("corr_ecc_errors", corr_errors),
 };
@@ -129,7 +130,6 @@
 	u32 speed;
 
 	if (hw->phy.media_type == e1000_media_type_copper) {
-
 		ecmd->supported = (SUPPORTED_10baseT_Half |
 				   SUPPORTED_10baseT_Full |
 				   SUPPORTED_100baseT_Half |
@@ -327,12 +327,12 @@
 	}
 
 	/* reset the link */
-
 	if (netif_running(adapter->netdev)) {
 		e1000e_down(adapter);
 		e1000e_up(adapter);
-	} else
+	} else {
 		e1000e_reset(adapter);
+	}
 
 	clear_bit(__E1000_RESETTING, &adapter->state);
 	return 0;
@@ -417,7 +417,7 @@
 	adapter->msg_enable = data;
 }
 
-static int e1000_get_regs_len(struct net_device *netdev)
+static int e1000_get_regs_len(struct net_device __always_unused *netdev)
 {
 #define E1000_REGS_LEN 32 /* overestimate */
 	return E1000_REGS_LEN * sizeof(u32);
@@ -471,10 +471,10 @@
 		regs_buff[22] = adapter->phy_stats.receive_errors;
 		regs_buff[23] = regs_buff[13]; /* mdix mode */
 	}
-	regs_buff[21] = 0; /* was idle_errors */
-	e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
-	regs_buff[24] = (u32)phy_data;  /* phy local receiver status */
-	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
+	regs_buff[21] = 0;	/* was idle_errors */
+	e1e_rphy(hw, MII_STAT1000, &phy_data);
+	regs_buff[24] = (u32)phy_data;	/* phy local receiver status */
+	regs_buff[25] = regs_buff[24];	/* phy remote receiver status */
 }
 
 static int e1000_get_eeprom_len(struct net_device *netdev)
@@ -761,8 +761,9 @@
 				      (test[pat] & write));
 		val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset);
 		if (val != (test[pat] & write & mask)) {
-			e_err("pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
-			      reg + offset, val, (test[pat] & write & mask));
+			e_err("pattern test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
+			      reg + (offset << 2), val,
+			      (test[pat] & write & mask));
 			*data = reg;
 			return 1;
 		}
@@ -777,7 +778,7 @@
 	__ew32(&adapter->hw, reg, write & mask);
 	val = __er32(&adapter->hw, reg);
 	if ((write & mask) != (val & mask)) {
-		e_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
+		e_err("set/check test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
 		      reg, (val & mask), (write & mask));
 		*data = reg;
 		return 1;
@@ -885,12 +886,20 @@
 		    E1000_FWSM_WLOCK_MAC_SHIFT;
 
 	for (i = 0; i < mac->rar_entry_count; i++) {
-		/* Cannot test write-protected SHRAL[n] registers */
-		if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
-			continue;
+		if (mac->type == e1000_pch_lpt) {
+			/* Cannot test write-protected SHRAL[n] registers */
+			if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
+				continue;
 
-		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
-				       mask, 0xFFFFFFFF);
+			/* SHRAH[9] different than the others */
+			if (i == 10)
+				mask |= (1 << 30);
+			else
+				mask &= ~(1 << 30);
+		}
+
+		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
+				       0xFFFFFFFF);
 	}
 
 	for (i = 0; i < mac->mta_reg_count; i++)
@@ -924,7 +933,7 @@
 	return *data;
 }
 
-static irqreturn_t e1000_test_intr(int irq, void *data)
+static irqreturn_t e1000_test_intr(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = (struct net_device *) data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1274,7 +1283,7 @@
 
 	if (hw->phy.type == e1000_phy_ife) {
 		/* force 100, set loopback */
-		e1e_wphy(hw, PHY_CONTROL, 0x6100);
+		e1e_wphy(hw, MII_BMCR, 0x6100);
 
 		/* Now set up the MAC to the same speed/duplex as the PHY. */
 		ctrl_reg = er32(CTRL);
@@ -1297,9 +1306,9 @@
 		/* Auto-MDI/MDIX Off */
 		e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
 		/* reset to update Auto-MDI/MDIX */
-		e1e_wphy(hw, PHY_CONTROL, 0x9140);
+		e1e_wphy(hw, MII_BMCR, 0x9140);
 		/* autoneg off */
-		e1e_wphy(hw, PHY_CONTROL, 0x8140);
+		e1e_wphy(hw, MII_BMCR, 0x8140);
 		break;
 	case e1000_phy_gg82563:
 		e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
@@ -1311,7 +1320,7 @@
 		phy_reg |= 0x006;
 		e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
 		/* Assert SW reset for above settings to take effect */
-		e1000e_commit_phy(hw);
+		hw->phy.ops.commit(hw);
 		mdelay(1);
 		/* Force Full Duplex */
 		e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
@@ -1345,7 +1354,6 @@
 		e1e_rphy(hw, PHY_REG(776, 18), &phy_reg);
 		e1e_wphy(hw, PHY_REG(776, 18), phy_reg | 1);
 		/* Enable loopback on the PHY */
-#define I82577_PHY_LBK_CTRL          19
 		e1e_wphy(hw, I82577_PHY_LBK_CTRL, 0x8001);
 		break;
 	default:
@@ -1353,7 +1361,7 @@
 	}
 
 	/* force 1000, set loopback */
-	e1e_wphy(hw, PHY_CONTROL, 0x4140);
+	e1e_wphy(hw, MII_BMCR, 0x4140);
 	mdelay(250);
 
 	/* Now set up the MAC to the same speed/duplex as the PHY. */
@@ -1395,7 +1403,7 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ctrl = er32(CTRL);
-	int link = 0;
+	int link;
 
 	/* special requirements for 82571/82572 fiber adapters */
 
@@ -1528,11 +1536,12 @@
 		hw->mac.autoneg = 1;
 		if (hw->phy.type == e1000_phy_gg82563)
 			e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180);
-		e1e_rphy(hw, PHY_CONTROL, &phy_reg);
-		if (phy_reg & MII_CR_LOOPBACK) {
-			phy_reg &= ~MII_CR_LOOPBACK;
-			e1e_wphy(hw, PHY_CONTROL, phy_reg);
-			e1000e_commit_phy(hw);
+		e1e_rphy(hw, MII_BMCR, &phy_reg);
+		if (phy_reg & BMCR_LOOPBACK) {
+			phy_reg &= ~BMCR_LOOPBACK;
+			e1e_wphy(hw, MII_BMCR, phy_reg);
+			if (hw->phy.ops.commit)
+				hw->phy.ops.commit(hw);
 		}
 		break;
 	}
@@ -1694,7 +1703,8 @@
 	return *data;
 }
 
-static int e1000e_get_sset_count(struct net_device *netdev, int sset)
+static int e1000e_get_sset_count(struct net_device __always_unused *netdev,
+				 int sset)
 {
 	switch (sset) {
 	case ETH_SS_TEST:
@@ -1957,7 +1967,7 @@
 }
 
 static void e1000_get_ethtool_stats(struct net_device *netdev,
-				    struct ethtool_stats *stats,
+				    struct ethtool_stats __always_unused *stats,
 				    u64 *data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1986,8 +1996,8 @@
 	}
 }
 
-static void e1000_get_strings(struct net_device *netdev, u32 stringset,
-			      u8 *data)
+static void e1000_get_strings(struct net_device __always_unused *netdev,
+			      u32 stringset, u8 *data)
 {
 	u8 *p = data;
 	int i;
@@ -2007,7 +2017,8 @@
 }
 
 static int e1000_get_rxnfc(struct net_device *netdev,
-			   struct ethtool_rxnfc *info, u32 *rule_locs)
+			   struct ethtool_rxnfc *info,
+			   u32 __always_unused *rule_locs)
 {
 	info->data = 0;
 
@@ -2053,6 +2064,171 @@
 	}
 }
 
+static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u16 cap_addr, adv_addr, lpa_addr, pcs_stat_addr, phy_data, lpi_ctrl;
+	u32 status, ret_val;
+
+	if (!(adapter->flags & FLAG_IS_ICH) ||
+	    !(adapter->flags2 & FLAG2_HAS_EEE))
+		return -EOPNOTSUPP;
+
+	switch (hw->phy.type) {
+	case e1000_phy_82579:
+		cap_addr = I82579_EEE_CAPABILITY;
+		adv_addr = I82579_EEE_ADVERTISEMENT;
+		lpa_addr = I82579_EEE_LP_ABILITY;
+		pcs_stat_addr = I82579_EEE_PCS_STATUS;
+		break;
+	case e1000_phy_i217:
+		cap_addr = I217_EEE_CAPABILITY;
+		adv_addr = I217_EEE_ADVERTISEMENT;
+		lpa_addr = I217_EEE_LP_ABILITY;
+		pcs_stat_addr = I217_EEE_PCS_STATUS;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		return -EBUSY;
+
+	/* EEE Capability */
+	ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data);
+	if (ret_val)
+		goto release;
+	edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data);
+
+	/* EEE Advertised */
+	ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &phy_data);
+	if (ret_val)
+		goto release;
+	edata->advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+	/* EEE Link Partner Advertised */
+	ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data);
+	if (ret_val)
+		goto release;
+	edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+	/* EEE PCS Status */
+	ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data);
+	if (hw->phy.type == e1000_phy_82579)
+		phy_data <<= 8;
+
+release:
+	hw->phy.ops.release(hw);
+	if (ret_val)
+		return -ENODATA;
+
+	e1e_rphy(hw, I82579_LPI_CTRL, &lpi_ctrl);
+	status = er32(STATUS);
+
+	/* Result of the EEE auto negotiation - there is no register that
+	 * has the status of the EEE negotiation so do a best-guess based
+	 * on whether both Tx and Rx LPI indications have been received or
+	 * base it on the link speed, the EEE advertised speeds on both ends
+	 * and the speeds on which EEE is enabled locally.
+	 */
+	if (((phy_data & E1000_EEE_TX_LPI_RCVD) &&
+	     (phy_data & E1000_EEE_RX_LPI_RCVD)) ||
+	    ((status & E1000_STATUS_SPEED_100) &&
+	     (edata->advertised & ADVERTISED_100baseT_Full) &&
+	     (edata->lp_advertised & ADVERTISED_100baseT_Full) &&
+	     (lpi_ctrl & I82579_LPI_CTRL_100_ENABLE)) ||
+	    ((status & E1000_STATUS_SPEED_1000) &&
+	     (edata->advertised & ADVERTISED_1000baseT_Full) &&
+	     (edata->lp_advertised & ADVERTISED_1000baseT_Full) &&
+	     (lpi_ctrl & I82579_LPI_CTRL_1000_ENABLE)))
+		edata->eee_active = true;
+
+	edata->eee_enabled = !hw->dev_spec.ich8lan.eee_disable;
+	edata->tx_lpi_enabled = true;
+	edata->tx_lpi_timer = er32(LPIC) >> E1000_LPIC_LPIET_SHIFT;
+
+	return 0;
+}
+
+static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	struct ethtool_eee eee_curr;
+	s32 ret_val;
+
+	if (!(adapter->flags & FLAG_IS_ICH) ||
+	    !(adapter->flags2 & FLAG2_HAS_EEE))
+		return -EOPNOTSUPP;
+
+	ret_val = e1000e_get_eee(netdev, &eee_curr);
+	if (ret_val)
+		return ret_val;
+
+	if (eee_curr.advertised != edata->advertised) {
+		e_err("Setting EEE advertisement is not supported\n");
+		return -EINVAL;
+	}
+
+	if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
+		e_err("Setting EEE tx-lpi is not supported\n");
+		return -EINVAL;
+	}
+
+	if (eee_curr.tx_lpi_timer != edata->tx_lpi_timer) {
+		e_err("Setting EEE Tx LPI timer is not supported\n");
+		return -EINVAL;
+	}
+
+	if (hw->dev_spec.ich8lan.eee_disable != !edata->eee_enabled) {
+		hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
+
+		/* reset the link */
+		if (netif_running(netdev))
+			e1000e_reinit_locked(adapter);
+		else
+			e1000e_reset(adapter);
+	}
+
+	return 0;
+}
+
+static int e1000e_get_ts_info(struct net_device *netdev,
+			      struct ethtool_ts_info *info)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	ethtool_op_get_ts_info(netdev, info);
+
+	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+		return 0;
+
+	info->so_timestamping |= (SOF_TIMESTAMPING_TX_HARDWARE |
+				  SOF_TIMESTAMPING_RX_HARDWARE |
+				  SOF_TIMESTAMPING_RAW_HARDWARE);
+
+	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+	info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
+			    (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+			    (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+			    (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+			    (1 << HWTSTAMP_FILTER_ALL));
+
+	if (adapter->ptp_clock)
+		info->phc_index = ptp_clock_index(adapter->ptp_clock);
+
+	return 0;
+}
+
 static const struct ethtool_ops e1000_ethtool_ops = {
 	.get_settings		= e1000_get_settings,
 	.set_settings		= e1000_set_settings,
@@ -2080,7 +2256,9 @@
 	.get_coalesce		= e1000_get_coalesce,
 	.set_coalesce		= e1000_set_coalesce,
 	.get_rxnfc		= e1000_get_rxnfc,
-	.get_ts_info		= ethtool_op_get_ts_info,
+	.get_ts_info		= e1000e_get_ts_info,
+	.get_eee		= e1000e_get_eee,
+	.set_eee		= e1000e_set_eee,
 };
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index b88676f..1e6b889 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -29,332 +29,10 @@
 #ifndef _E1000_HW_H_
 #define _E1000_HW_H_
 
-#include <linux/types.h>
-
-struct e1000_hw;
-struct e1000_adapter;
-
+#include "regs.h"
 #include "defines.h"
 
-enum e1e_registers {
-	E1000_CTRL     = 0x00000, /* Device Control - RW */
-	E1000_STATUS   = 0x00008, /* Device Status - RO */
-	E1000_EECD     = 0x00010, /* EEPROM/Flash Control - RW */
-	E1000_EERD     = 0x00014, /* EEPROM Read - RW */
-	E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */
-	E1000_FLA      = 0x0001C, /* Flash Access - RW */
-	E1000_MDIC     = 0x00020, /* MDI Control - RW */
-	E1000_SCTL     = 0x00024, /* SerDes Control - RW */
-	E1000_FCAL     = 0x00028, /* Flow Control Address Low - RW */
-	E1000_FCAH     = 0x0002C, /* Flow Control Address High -RW */
-	E1000_FEXTNVM4 = 0x00024, /* Future Extended NVM 4 - RW */
-	E1000_FEXTNVM  = 0x00028, /* Future Extended NVM - RW */
-	E1000_FCT      = 0x00030, /* Flow Control Type - RW */
-	E1000_VET      = 0x00038, /* VLAN Ether Type - RW */
-	E1000_FEXTNVM3 = 0x0003C, /* Future Extended NVM 3 - RW */
-	E1000_ICR      = 0x000C0, /* Interrupt Cause Read - R/clr */
-	E1000_ITR      = 0x000C4, /* Interrupt Throttling Rate - RW */
-	E1000_ICS      = 0x000C8, /* Interrupt Cause Set - WO */
-	E1000_IMS      = 0x000D0, /* Interrupt Mask Set - RW */
-	E1000_IMC      = 0x000D8, /* Interrupt Mask Clear - WO */
-	E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
-	E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
-	E1000_IVAR     = 0x000E4, /* Interrupt Vector Allocation - RW */
-	E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
-#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
-	E1000_RCTL     = 0x00100, /* Rx Control - RW */
-	E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
-	E1000_TXCW     = 0x00178, /* Tx Configuration Word - RW */
-	E1000_RXCW     = 0x00180, /* Rx Configuration Word - RO */
-	E1000_TCTL     = 0x00400, /* Tx Control - RW */
-	E1000_TCTL_EXT = 0x00404, /* Extended Tx Control - RW */
-	E1000_TIPG     = 0x00410, /* Tx Inter-packet gap -RW */
-	E1000_AIT      = 0x00458, /* Adaptive Interframe Spacing Throttle -RW */
-	E1000_LEDCTL   = 0x00E00, /* LED Control - RW */
-	E1000_EXTCNF_CTRL  = 0x00F00, /* Extended Configuration Control */
-	E1000_EXTCNF_SIZE  = 0x00F08, /* Extended Configuration Size */
-	E1000_PHY_CTRL     = 0x00F10, /* PHY Control Register in CSR */
-#define E1000_POEMB	E1000_PHY_CTRL	/* PHY OEM Bits */
-	E1000_PBA      = 0x01000, /* Packet Buffer Allocation - RW */
-	E1000_PBS      = 0x01008, /* Packet Buffer Size */
-	E1000_PBECCSTS = 0x0100C, /* Packet Buffer ECC Status - RW */
-	E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
-	E1000_EEWR     = 0x0102C, /* EEPROM Write Register - RW */
-	E1000_FLOP     = 0x0103C, /* FLASH Opcode Register */
-	E1000_PBA_ECC  = 0x01100, /* PBA ECC Register */
-	E1000_ERT      = 0x02008, /* Early Rx Threshold - RW */
-	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
-	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
-	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
-/* Convenience macros
- *
- * Note: "_n" is the queue number of the register to be written to.
- *
- * Example usage:
- * E1000_RDBAL(current_rx_queue)
- */
-	E1000_RDBAL_BASE = 0x02800, /* Rx Descriptor Base Address Low - RW */
-#define E1000_RDBAL(_n)	(E1000_RDBAL_BASE + (_n << 8))
-	E1000_RDBAH_BASE = 0x02804, /* Rx Descriptor Base Address High - RW */
-#define E1000_RDBAH(_n)	(E1000_RDBAH_BASE + (_n << 8))
-	E1000_RDLEN_BASE = 0x02808, /* Rx Descriptor Length - RW */
-#define E1000_RDLEN(_n)	(E1000_RDLEN_BASE + (_n << 8))
-	E1000_RDH_BASE = 0x02810, /* Rx Descriptor Head - RW */
-#define E1000_RDH(_n)	(E1000_RDH_BASE + (_n << 8))
-	E1000_RDT_BASE = 0x02818, /* Rx Descriptor Tail - RW */
-#define E1000_RDT(_n)	(E1000_RDT_BASE + (_n << 8))
-	E1000_RDTR     = 0x02820, /* Rx Delay Timer - RW */
-	E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
-#define E1000_RXDCTL(_n)   (E1000_RXDCTL_BASE + (_n << 8))
-	E1000_RADV     = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */
-
-	E1000_KABGTXD  = 0x03004, /* AFE Band Gap Transmit Ref Data */
-	E1000_TDBAL_BASE = 0x03800, /* Tx Descriptor Base Address Low - RW */
-#define E1000_TDBAL(_n)	(E1000_TDBAL_BASE + (_n << 8))
-	E1000_TDBAH_BASE = 0x03804, /* Tx Descriptor Base Address High - RW */
-#define E1000_TDBAH(_n)	(E1000_TDBAH_BASE + (_n << 8))
-	E1000_TDLEN_BASE = 0x03808, /* Tx Descriptor Length - RW */
-#define E1000_TDLEN(_n)	(E1000_TDLEN_BASE + (_n << 8))
-	E1000_TDH_BASE = 0x03810, /* Tx Descriptor Head - RW */
-#define E1000_TDH(_n)	(E1000_TDH_BASE + (_n << 8))
-	E1000_TDT_BASE = 0x03818, /* Tx Descriptor Tail - RW */
-#define E1000_TDT(_n)	(E1000_TDT_BASE + (_n << 8))
-	E1000_TIDV     = 0x03820, /* Tx Interrupt Delay Value - RW */
-	E1000_TXDCTL_BASE = 0x03828, /* Tx Descriptor Control - RW */
-#define E1000_TXDCTL(_n)   (E1000_TXDCTL_BASE + (_n << 8))
-	E1000_TADV     = 0x0382C, /* Tx Interrupt Absolute Delay Val - RW */
-	E1000_TARC_BASE = 0x03840, /* Tx Arbitration Count (0) */
-#define E1000_TARC(_n)   (E1000_TARC_BASE + (_n << 8))
-	E1000_CRCERRS  = 0x04000, /* CRC Error Count - R/clr */
-	E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */
-	E1000_SYMERRS  = 0x04008, /* Symbol Error Count - R/clr */
-	E1000_RXERRC   = 0x0400C, /* Receive Error Count - R/clr */
-	E1000_MPC      = 0x04010, /* Missed Packet Count - R/clr */
-	E1000_SCC      = 0x04014, /* Single Collision Count - R/clr */
-	E1000_ECOL     = 0x04018, /* Excessive Collision Count - R/clr */
-	E1000_MCC      = 0x0401C, /* Multiple Collision Count - R/clr */
-	E1000_LATECOL  = 0x04020, /* Late Collision Count - R/clr */
-	E1000_COLC     = 0x04028, /* Collision Count - R/clr */
-	E1000_DC       = 0x04030, /* Defer Count - R/clr */
-	E1000_TNCRS    = 0x04034, /* Tx-No CRS - R/clr */
-	E1000_SEC      = 0x04038, /* Sequence Error Count - R/clr */
-	E1000_CEXTERR  = 0x0403C, /* Carrier Extension Error Count - R/clr */
-	E1000_RLEC     = 0x04040, /* Receive Length Error Count - R/clr */
-	E1000_XONRXC   = 0x04048, /* XON Rx Count - R/clr */
-	E1000_XONTXC   = 0x0404C, /* XON Tx Count - R/clr */
-	E1000_XOFFRXC  = 0x04050, /* XOFF Rx Count - R/clr */
-	E1000_XOFFTXC  = 0x04054, /* XOFF Tx Count - R/clr */
-	E1000_FCRUC    = 0x04058, /* Flow Control Rx Unsupported Count- R/clr */
-	E1000_PRC64    = 0x0405C, /* Packets Rx (64 bytes) - R/clr */
-	E1000_PRC127   = 0x04060, /* Packets Rx (65-127 bytes) - R/clr */
-	E1000_PRC255   = 0x04064, /* Packets Rx (128-255 bytes) - R/clr */
-	E1000_PRC511   = 0x04068, /* Packets Rx (255-511 bytes) - R/clr */
-	E1000_PRC1023  = 0x0406C, /* Packets Rx (512-1023 bytes) - R/clr */
-	E1000_PRC1522  = 0x04070, /* Packets Rx (1024-1522 bytes) - R/clr */
-	E1000_GPRC     = 0x04074, /* Good Packets Rx Count - R/clr */
-	E1000_BPRC     = 0x04078, /* Broadcast Packets Rx Count - R/clr */
-	E1000_MPRC     = 0x0407C, /* Multicast Packets Rx Count - R/clr */
-	E1000_GPTC     = 0x04080, /* Good Packets Tx Count - R/clr */
-	E1000_GORCL    = 0x04088, /* Good Octets Rx Count Low - R/clr */
-	E1000_GORCH    = 0x0408C, /* Good Octets Rx Count High - R/clr */
-	E1000_GOTCL    = 0x04090, /* Good Octets Tx Count Low - R/clr */
-	E1000_GOTCH    = 0x04094, /* Good Octets Tx Count High - R/clr */
-	E1000_RNBC     = 0x040A0, /* Rx No Buffers Count - R/clr */
-	E1000_RUC      = 0x040A4, /* Rx Undersize Count - R/clr */
-	E1000_RFC      = 0x040A8, /* Rx Fragment Count - R/clr */
-	E1000_ROC      = 0x040AC, /* Rx Oversize Count - R/clr */
-	E1000_RJC      = 0x040B0, /* Rx Jabber Count - R/clr */
-	E1000_MGTPRC   = 0x040B4, /* Management Packets Rx Count - R/clr */
-	E1000_MGTPDC   = 0x040B8, /* Management Packets Dropped Count - R/clr */
-	E1000_MGTPTC   = 0x040BC, /* Management Packets Tx Count - R/clr */
-	E1000_TORL     = 0x040C0, /* Total Octets Rx Low - R/clr */
-	E1000_TORH     = 0x040C4, /* Total Octets Rx High - R/clr */
-	E1000_TOTL     = 0x040C8, /* Total Octets Tx Low - R/clr */
-	E1000_TOTH     = 0x040CC, /* Total Octets Tx High - R/clr */
-	E1000_TPR      = 0x040D0, /* Total Packets Rx - R/clr */
-	E1000_TPT      = 0x040D4, /* Total Packets Tx - R/clr */
-	E1000_PTC64    = 0x040D8, /* Packets Tx (64 bytes) - R/clr */
-	E1000_PTC127   = 0x040DC, /* Packets Tx (65-127 bytes) - R/clr */
-	E1000_PTC255   = 0x040E0, /* Packets Tx (128-255 bytes) - R/clr */
-	E1000_PTC511   = 0x040E4, /* Packets Tx (256-511 bytes) - R/clr */
-	E1000_PTC1023  = 0x040E8, /* Packets Tx (512-1023 bytes) - R/clr */
-	E1000_PTC1522  = 0x040EC, /* Packets Tx (1024-1522 Bytes) - R/clr */
-	E1000_MPTC     = 0x040F0, /* Multicast Packets Tx Count - R/clr */
-	E1000_BPTC     = 0x040F4, /* Broadcast Packets Tx Count - R/clr */
-	E1000_TSCTC    = 0x040F8, /* TCP Segmentation Context Tx - R/clr */
-	E1000_TSCTFC   = 0x040FC, /* TCP Segmentation Context Tx Fail - R/clr */
-	E1000_IAC      = 0x04100, /* Interrupt Assertion Count */
-	E1000_ICRXPTC  = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */
-	E1000_ICRXATC  = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */
-	E1000_ICTXPTC  = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */
-	E1000_ICTXATC  = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */
-	E1000_ICTXQEC  = 0x04118, /* Irq Cause Tx Queue Empty Count */
-	E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
-	E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
-	E1000_ICRXOC   = 0x04124, /* Irq Cause Receiver Overrun Count */
-	E1000_RXCSUM   = 0x05000, /* Rx Checksum Control - RW */
-	E1000_RFCTL    = 0x05008, /* Receive Filter Control */
-	E1000_MTA      = 0x05200, /* Multicast Table Array - RW Array */
-	E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */
-#define E1000_RAL(_n)   (E1000_RAL_BASE + ((_n) * 8))
-#define E1000_RA        (E1000_RAL(0))
-	E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */
-#define E1000_RAH(_n)   (E1000_RAH_BASE + ((_n) * 8))
-	E1000_SHRAL_PCH_LPT_BASE = 0x05408,
-#define E1000_SHRAL_PCH_LPT(_n)   (E1000_SHRAL_PCH_LPT_BASE + ((_n) * 8))
-	E1000_SHRAH_PCH_LTP_BASE = 0x0540C,
-#define E1000_SHRAH_PCH_LPT(_n)   (E1000_SHRAH_PCH_LTP_BASE + ((_n) * 8))
-	E1000_SHRAL_BASE = 0x05438, /* Shared Receive Address Low - RW */
-#define E1000_SHRAL(_n)   (E1000_SHRAL_BASE + ((_n) * 8))
-	E1000_SHRAH_BASE = 0x0543C, /* Shared Receive Address High - RW */
-#define E1000_SHRAH(_n)   (E1000_SHRAH_BASE + ((_n) * 8))
-	E1000_VFTA     = 0x05600, /* VLAN Filter Table Array - RW Array */
-	E1000_WUC      = 0x05800, /* Wakeup Control - RW */
-	E1000_WUFC     = 0x05808, /* Wakeup Filter Control - RW */
-	E1000_WUS      = 0x05810, /* Wakeup Status - RO */
-	E1000_MRQC     = 0x05818, /* Multiple Receive Control - RW */
-	E1000_MANC     = 0x05820, /* Management Control - RW */
-	E1000_FFLT     = 0x05F00, /* Flexible Filter Length Table - RW Array */
-	E1000_HOST_IF  = 0x08800, /* Host Interface */
-
-	E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
-	E1000_MANC2H    = 0x05860, /* Management Control To Host - RW */
-	E1000_MDEF_BASE = 0x05890, /* Management Decision Filters */
-#define E1000_MDEF(_n)   (E1000_MDEF_BASE + ((_n) * 4))
-	E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
-	E1000_GCR	= 0x05B00, /* PCI-Ex Control */
-	E1000_GCR2      = 0x05B64, /* PCI-Ex Control #2 */
-	E1000_FACTPS    = 0x05B30, /* Function Active and Power State to MNG */
-	E1000_SWSM      = 0x05B50, /* SW Semaphore */
-	E1000_FWSM      = 0x05B54, /* FW Semaphore */
-	E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
-	E1000_RETA_BASE = 0x05C00, /* Redirection Table - RW */
-#define E1000_RETA(_n)	(E1000_RETA_BASE + ((_n) * 4))
-	E1000_RSSRK_BASE = 0x05C80, /* RSS Random Key - RW */
-#define E1000_RSSRK(_n)	(E1000_RSSRK_BASE + ((_n) * 4))
-	E1000_FFLT_DBG  = 0x05F04, /* Debug Register */
-	E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */
-#define E1000_PCH_RAICC(_n)	(E1000_PCH_RAICC_BASE + ((_n) * 4))
-#define E1000_CRC_OFFSET	E1000_PCH_RAICC_BASE
-	E1000_HICR      = 0x08F00, /* Host Interface Control */
-};
-
-#define E1000_MAX_PHY_ADDR		4
-
-/* IGP01E1000 Specific Registers */
-#define IGP01E1000_PHY_PORT_CONFIG	0x10 /* Port Config */
-#define IGP01E1000_PHY_PORT_STATUS	0x11 /* Status */
-#define IGP01E1000_PHY_PORT_CTRL	0x12 /* Control */
-#define IGP01E1000_PHY_LINK_HEALTH	0x13 /* PHY Link Health */
-#define IGP02E1000_PHY_POWER_MGMT	0x19 /* Power Management */
-#define IGP01E1000_PHY_PAGE_SELECT	0x1F /* Page Select */
-#define BM_PHY_PAGE_SELECT		22   /* Page Select for BM */
-#define IGP_PAGE_SHIFT			5
-#define PHY_REG_MASK			0x1F
-
-#define BM_WUC_PAGE			800
-#define BM_WUC_ADDRESS_OPCODE		0x11
-#define BM_WUC_DATA_OPCODE		0x12
-#define BM_WUC_ENABLE_PAGE		769
-#define BM_WUC_ENABLE_REG		17
-#define BM_WUC_ENABLE_BIT		(1 << 2)
-#define BM_WUC_HOST_WU_BIT		(1 << 4)
-#define BM_WUC_ME_WU_BIT		(1 << 5)
-
-#define BM_WUC	PHY_REG(BM_WUC_PAGE, 1)
-#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
-#define BM_WUS	PHY_REG(BM_WUC_PAGE, 3)
-
-#define IGP01E1000_PHY_PCS_INIT_REG	0x00B4
-#define IGP01E1000_PHY_POLARITY_MASK	0x0078
-
-#define IGP01E1000_PSCR_AUTO_MDIX	0x1000
-#define IGP01E1000_PSCR_FORCE_MDI_MDIX	0x2000 /* 0=MDI, 1=MDIX */
-
-#define IGP01E1000_PSCFR_SMART_SPEED	0x0080
-
-#define IGP02E1000_PM_SPD		0x0001 /* Smart Power Down */
-#define IGP02E1000_PM_D0_LPLU		0x0002 /* For D0a states */
-#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			0x0800
-#define IGP01E1000_PSSR_SPEED_MASK		0xC000
-#define IGP01E1000_PSSR_SPEED_1000MBPS		0xC000
-
-#define IGP02E1000_PHY_CHANNEL_NUM		4
-#define IGP02E1000_PHY_AGC_A			0x11B1
-#define IGP02E1000_PHY_AGC_B			0x12B1
-#define IGP02E1000_PHY_AGC_C			0x14B1
-#define IGP02E1000_PHY_AGC_D			0x18B1
-
-#define IGP02E1000_AGC_LENGTH_SHIFT	9 /* Course - 15:13, Fine - 12:9 */
-#define IGP02E1000_AGC_LENGTH_MASK	0x7F
-#define IGP02E1000_AGC_RANGE		15
-
-/* manage.c */
-#define E1000_VFTA_ENTRY_SHIFT		5
-#define E1000_VFTA_ENTRY_MASK		0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK	0x1F
-
-#define E1000_HICR_EN			0x01  /* Enable bit - RO */
-/* Driver sets this bit when done to put command in RAM */
-#define E1000_HICR_C			0x02
-#define E1000_HICR_FW_RESET_ENABLE	0x40
-#define E1000_HICR_FW_RESET		0x80
-
-#define E1000_FWSM_MODE_MASK		0xE
-#define E1000_FWSM_MODE_SHIFT		1
-
-#define E1000_MNG_IAMT_MODE		0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH	0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET	0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT	10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD	64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING	0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN	0x2
-
-/* nvm.c */
-#define E1000_STM_OPCODE  0xDB00
-
-#define E1000_KMRNCTRLSTA_OFFSET	0x001F0000
-#define E1000_KMRNCTRLSTA_OFFSET_SHIFT	16
-#define E1000_KMRNCTRLSTA_REN		0x00200000
-#define E1000_KMRNCTRLSTA_CTRL_OFFSET	0x1    /* Kumeran Control */
-#define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3    /* Kumeran Diagnostic */
-#define E1000_KMRNCTRLSTA_TIMEOUTS	0x4    /* Kumeran Timeouts */
-#define E1000_KMRNCTRLSTA_INBAND_PARAM	0x9    /* Kumeran InBand Parameters */
-#define E1000_KMRNCTRLSTA_IBIST_DISABLE	0x0200 /* Kumeran IBIST Disable */
-#define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000 /* Nearend Loopback mode */
-#define E1000_KMRNCTRLSTA_K1_CONFIG	0x7
-#define E1000_KMRNCTRLSTA_K1_ENABLE	0x0002
-#define E1000_KMRNCTRLSTA_HD_CTRL	0x10   /* Kumeran HD Control */
-
-#define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
-#define IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED	0x1B /* PHY Special and LED Control */
-#define IFE_PHY_MDIX_CONTROL		0x1C /* MDI/MDI-X Control */
-
-/* IFE PHY Extended Status Control */
-#define IFE_PESC_POLARITY_REVERSED	0x0100
-
-/* IFE PHY Special Control */
-#define IFE_PSC_AUTO_POLARITY_DISABLE		0x0010
-#define IFE_PSC_FORCE_POLARITY			0x0020
-
-/* IFE PHY Special Control and LED Control */
-#define IFE_PSCL_PROBE_MODE		0x0020
-#define IFE_PSCL_PROBE_LEDS_OFF		0x0006 /* Force LEDs 0 and 2 off */
-#define IFE_PSCL_PROBE_LEDS_ON		0x0007 /* Force LEDs 0 and 2 on */
-
-/* IFE PHY MDIX Control */
-#define IFE_PMC_MDIX_STATUS	0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_FORCE_MDIX	0x0040 /* 1=force MDI-X, 0=force MDI */
-#define IFE_PMC_AUTO_MDIX	0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
-
-#define E1000_CABLE_LENGTH_UNDEFINED	0xFF
+struct e1000_hw;
 
 #define E1000_DEV_ID_82571EB_COPPER		0x105E
 #define E1000_DEV_ID_82571EB_FIBER		0x105F
@@ -374,13 +52,11 @@
 #define E1000_DEV_ID_82573L			0x109A
 #define E1000_DEV_ID_82574L			0x10D3
 #define E1000_DEV_ID_82574LA			0x10F6
-#define E1000_DEV_ID_82583V                     0x150C
-
+#define E1000_DEV_ID_82583V			0x150C
 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT	0x1096
 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT	0x1098
 #define E1000_DEV_ID_80003ES2LAN_COPPER_SPT	0x10BA
 #define E1000_DEV_ID_80003ES2LAN_SERDES_SPT	0x10BB
-
 #define E1000_DEV_ID_ICH8_82567V_3		0x1501
 #define E1000_DEV_ID_ICH8_IGP_M_AMT		0x1049
 #define E1000_DEV_ID_ICH8_IGP_AMT		0x104A
@@ -415,12 +91,12 @@
 #define E1000_DEV_ID_PCH_LPTLP_I218_LM		0x155A
 #define E1000_DEV_ID_PCH_LPTLP_I218_V		0x1559
 
-#define E1000_REVISION_4 4
+#define E1000_REVISION_4	4
 
-#define E1000_FUNC_1 1
+#define E1000_FUNC_1		1
 
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0	0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1	3
 
 enum e1000_mac_type {
 	e1000_82571,
@@ -525,16 +201,6 @@
 	e1000_serdes_link_forced_up
 };
 
-/* Receive Descriptor */
-struct e1000_rx_desc {
-	__le64 buffer_addr; /* Address of the descriptor's data buffer */
-	__le16 length;      /* Length of data DMAed into data buffer */
-	__le16 csum;	/* Packet checksum */
-	u8  status;      /* Descriptor status */
-	u8  errors;      /* Descriptor Errors */
-	__le16 special;
-};
-
 /* Receive Descriptor - Extended */
 union e1000_rx_desc_extended {
 	struct {
@@ -657,7 +323,7 @@
 		struct {
 			u8 status;     /* Descriptor status */
 			u8 popts;      /* Packet Options */
-			__le16 special;   /* */
+			__le16 special;
 		} fields;
 	} upper;
 };
@@ -753,7 +419,7 @@
 	u8 checksum;
 };
 
-#define E1000_HI_MAX_DATA_LENGTH     252
+#define E1000_HI_MAX_DATA_LENGTH	252
 struct e1000_host_command_info {
 	struct e1000_host_command_header command_header;
 	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
@@ -768,13 +434,18 @@
 	u16 command_length;
 };
 
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+#define E1000_HI_MAX_MNG_DATA_LENGTH	0x6F8
 struct e1000_host_mng_command_info {
 	struct e1000_host_mng_command_header command_header;
 	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
 };
 
-/* Function pointers and static data for the MAC. */
+#include "mac.h"
+#include "phy.h"
+#include "nvm.h"
+#include "manage.h"
+
+/* Function pointers for the MAC. */
 struct e1000_mac_operations {
 	s32  (*id_led_init)(struct e1000_hw *);
 	s32  (*blink_led)(struct e1000_hw *);
@@ -1003,4 +674,8 @@
 	} dev_spec;
 };
 
+#include "82571.h"
+#include "80003es2lan.h"
+#include "ich8lan.h"
+
 #endif
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 24d9f61..dff7bff 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -57,147 +57,6 @@
 
 #include "e1000.h"
 
-#define ICH_FLASH_GFPREG		0x0000
-#define ICH_FLASH_HSFSTS		0x0004
-#define ICH_FLASH_HSFCTL		0x0006
-#define ICH_FLASH_FADDR			0x0008
-#define ICH_FLASH_FDATA0		0x0010
-#define ICH_FLASH_PR0			0x0074
-
-#define ICH_FLASH_READ_COMMAND_TIMEOUT	500
-#define ICH_FLASH_WRITE_COMMAND_TIMEOUT	500
-#define ICH_FLASH_ERASE_COMMAND_TIMEOUT	3000000
-#define ICH_FLASH_LINEAR_ADDR_MASK	0x00FFFFFF
-#define ICH_FLASH_CYCLE_REPEAT_COUNT	10
-
-#define ICH_CYCLE_READ			0
-#define ICH_CYCLE_WRITE			2
-#define ICH_CYCLE_ERASE			3
-
-#define FLASH_GFPREG_BASE_MASK		0x1FFF
-#define FLASH_SECTOR_ADDR_SHIFT		12
-
-#define ICH_FLASH_SEG_SIZE_256		256
-#define ICH_FLASH_SEG_SIZE_4K		4096
-#define ICH_FLASH_SEG_SIZE_8K		8192
-#define ICH_FLASH_SEG_SIZE_64K		65536
-
-
-#define E1000_ICH_FWSM_RSPCIPHY	0x00000040 /* Reset PHY on PCI Reset */
-/* FW established a valid mode */
-#define E1000_ICH_FWSM_FW_VALID		0x00008000
-
-#define E1000_ICH_MNG_IAMT_MODE		0x2
-
-#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
-				 (ID_LED_DEF1_OFF2 <<  8) | \
-				 (ID_LED_DEF1_ON2  <<  4) | \
-				 (ID_LED_DEF1_DEF2))
-
-#define E1000_ICH_NVM_SIG_WORD		0x13
-#define E1000_ICH_NVM_SIG_MASK		0xC000
-#define E1000_ICH_NVM_VALID_SIG_MASK    0xC0
-#define E1000_ICH_NVM_SIG_VALUE         0x80
-
-#define E1000_ICH8_LAN_INIT_TIMEOUT	1500
-
-#define E1000_FEXTNVM_SW_CONFIG		1
-#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
-
-#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK    0x0C000000
-#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC  0x08000000
-
-#define E1000_FEXTNVM4_BEACON_DURATION_MASK    0x7
-#define E1000_FEXTNVM4_BEACON_DURATION_8USEC   0x7
-#define E1000_FEXTNVM4_BEACON_DURATION_16USEC  0x3
-
-#define PCIE_ICH8_SNOOP_ALL		PCIE_NO_SNOOP_ALL
-
-#define E1000_ICH_RAR_ENTRIES		7
-#define E1000_PCH2_RAR_ENTRIES		5 /* RAR[0], SHRA[0-3] */
-#define E1000_PCH_LPT_RAR_ENTRIES	12 /* RAR[0], SHRA[0-10] */
-
-#define PHY_PAGE_SHIFT 5
-#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
-			   ((reg) & MAX_PHY_REG_ADDRESS))
-#define IGP3_KMRN_DIAG  PHY_REG(770, 19) /* KMRN Diagnostic */
-#define IGP3_VR_CTRL    PHY_REG(776, 18) /* Voltage Regulator Control */
-
-#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS	0x0002
-#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
-#define IGP3_VR_CTRL_MODE_SHUTDOWN	0x0200
-
-#define HV_LED_CONFIG		PHY_REG(768, 30) /* LED Configuration */
-
-#define SW_FLAG_TIMEOUT    1000 /* SW Semaphore flag timeout in milliseconds */
-
-/* SMBus Control Phy Register */
-#define CV_SMB_CTRL		PHY_REG(769, 23)
-#define CV_SMB_CTRL_FORCE_SMBUS	0x0001
-
-/* SMBus Address Phy Register */
-#define HV_SMB_ADDR            PHY_REG(768, 26)
-#define HV_SMB_ADDR_MASK       0x007F
-#define HV_SMB_ADDR_PEC_EN     0x0200
-#define HV_SMB_ADDR_VALID      0x0080
-#define HV_SMB_ADDR_FREQ_MASK           0x1100
-#define HV_SMB_ADDR_FREQ_LOW_SHIFT      8
-#define HV_SMB_ADDR_FREQ_HIGH_SHIFT     12
-
-/* PHY Power Management Control */
-#define HV_PM_CTRL		PHY_REG(770, 17)
-#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA	0x100
-
-/* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL				PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK		0x6000
-#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT	0x80
-
-/* EMI Registers */
-#define I82579_EMI_ADDR         0x10
-#define I82579_EMI_DATA         0x11
-#define I82579_LPI_UPDATE_TIMER 0x4805	/* in 40ns units + 40 ns base value */
-#define I82579_MSE_THRESHOLD    0x084F	/* Mean Square Error Threshold */
-#define I82579_MSE_LINK_DOWN    0x2411	/* MSE count before dropping link */
-#define I217_EEE_ADVERTISEMENT  0x8001	/* IEEE MMD Register 7.60 */
-#define I217_EEE_LP_ABILITY     0x8002	/* IEEE MMD Register 7.61 */
-#define I217_EEE_100_SUPPORTED  (1 << 1)	/* 100BaseTx EEE supported */
-
-/* Intel Rapid Start Technology Support */
-#define I217_PROXY_CTRL                 BM_PHY_REG(BM_WUC_PAGE, 70)
-#define I217_PROXY_CTRL_AUTO_DISABLE    0x0080
-#define I217_SxCTRL                     PHY_REG(BM_PORT_CTRL_PAGE, 28)
-#define I217_SxCTRL_ENABLE_LPI_RESET    0x1000
-#define I217_CGFREG                     PHY_REG(772, 29)
-#define I217_CGFREG_ENABLE_MTA_RESET    0x0002
-#define I217_MEMPWR                     PHY_REG(772, 26)
-#define I217_MEMPWR_DISABLE_SMB_RELEASE 0x0010
-
-/* Strapping Option Register - RO */
-#define E1000_STRAP                     0x0000C
-#define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
-#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
-#define E1000_STRAP_SMT_FREQ_MASK       0x00003000
-#define E1000_STRAP_SMT_FREQ_SHIFT      12
-
-/* OEM Bits Phy Register */
-#define HV_OEM_BITS            PHY_REG(768, 25)
-#define HV_OEM_BITS_LPLU       0x0004 /* Low Power Link Up */
-#define HV_OEM_BITS_GBE_DIS    0x0040 /* Gigabit Disable */
-#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
-
-#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
-#define E1000_NVM_K1_ENABLE 0x1  /* NVM Enable K1 bit */
-
-/* KMRN Mode Control */
-#define HV_KMRN_MODE_CTRL      PHY_REG(769, 16)
-#define HV_KMRN_MDIO_SLOW      0x0400
-
-/* KMRN FIFO Control and Status */
-#define HV_KMRN_FIFO_CTRLSTA                  PHY_REG(770, 16)
-#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK    0x7000
-#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT   12
-
 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
 /* Offset 04h HSFSTS */
 union ich8_hws_flash_status {
@@ -252,7 +111,6 @@
 	u32 regval;
 };
 
-static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
 static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
@@ -264,9 +122,7 @@
 					 u16 *data);
 static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
 					 u8 size, u16 *data);
-static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
 static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
-static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
 static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
 static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
 static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
@@ -278,7 +134,7 @@
 static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
 static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
 static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
-static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
+static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
 static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
@@ -330,12 +186,12 @@
 	u16 retry_count;
 
 	for (retry_count = 0; retry_count < 2; retry_count++) {
-		ret_val = e1e_rphy_locked(hw, PHY_ID1, &phy_reg);
+		ret_val = e1e_rphy_locked(hw, MII_PHYSID1, &phy_reg);
 		if (ret_val || (phy_reg == 0xFFFF))
 			continue;
 		phy_id = (u32)(phy_reg << 16);
 
-		ret_val = e1e_rphy_locked(hw, PHY_ID2, &phy_reg);
+		ret_val = e1e_rphy_locked(hw, MII_PHYSID2, &phy_reg);
 		if (ret_val || (phy_reg == 0xFFFF)) {
 			phy_id = 0;
 			continue;
@@ -378,10 +234,15 @@
 	s32 ret_val;
 	u16 phy_reg;
 
+	/* Gate automatic PHY configuration by hardware on managed and
+	 * non-managed 82579 and newer adapters.
+	 */
+	e1000_gate_hw_phy_config_ich8lan(hw, true);
+
 	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val) {
 		e_dbg("Failed to initialize PHY flow\n");
-		return ret_val;
+		goto out;
 	}
 
 	/* The MAC-PHY interconnect may be in SMBus mode.  If the PHY is
@@ -402,13 +263,6 @@
 
 		/* fall-through */
 	case e1000_pch2lan:
-		/* Gate automatic PHY configuration by hardware on
-		 * non-managed 82579
-		 */
-		if ((hw->mac.type == e1000_pch2lan) &&
-		    !(fwsm & E1000_ICH_FWSM_FW_VALID))
-			e1000_gate_hw_phy_config_ich8lan(hw, true);
-
 		if (e1000_phy_is_accessible_pchlan(hw)) {
 			if (hw->mac.type == e1000_pch_lpt) {
 				/* Unforce SMBus mode in PHY */
@@ -443,6 +297,15 @@
 		mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
 		ew32(FEXTNVM3, mac_reg);
 
+		if (hw->mac.type == e1000_pch_lpt) {
+			/* Toggling LANPHYPC brings the PHY out of SMBus mode
+			 * So ensure that the MAC is also out of SMBus mode
+			 */
+			mac_reg = er32(CTRL_EXT);
+			mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+			ew32(CTRL_EXT, mac_reg);
+		}
+
 		/* Toggle LANPHYPC Value bit */
 		mac_reg = er32(CTRL);
 		mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
@@ -476,6 +339,7 @@
 	 */
 	ret_val = e1000e_phy_hw_reset_generic(hw);
 
+out:
 	/* Ungate automatic PHY configuration on non-managed 82579 */
 	if ((hw->mac.type == e1000_pch2lan) &&
 	    !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
@@ -495,7 +359,7 @@
 static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	phy->addr                     = 1;
 	phy->reset_delay_us           = 100;
@@ -778,68 +642,143 @@
 	if (mac->type == e1000_ich8lan)
 		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
-	/* Gate automatic PHY configuration by hardware on managed
-	 * 82579 and i217
-	 */
-	if ((mac->type == e1000_pch2lan || mac->type == e1000_pch_lpt) &&
-	    (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
-		e1000_gate_hw_phy_config_ich8lan(hw, true);
-
 	return 0;
 }
 
 /**
+ *  __e1000_access_emi_reg_locked - Read/write EMI register
+ *  @hw: pointer to the HW structure
+ *  @addr: EMI address to program
+ *  @data: pointer to value to read/write from/to the EMI address
+ *  @read: boolean flag to indicate read or write
+ *
+ *  This helper function assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
+					 u16 *data, bool read)
+{
+	s32 ret_val;
+
+	ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, address);
+	if (ret_val)
+		return ret_val;
+
+	if (read)
+		ret_val = e1e_rphy_locked(hw, I82579_EMI_DATA, data);
+	else
+		ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, *data);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_read_emi_reg_locked - Read Extended Management Interface register
+ *  @hw: pointer to the HW structure
+ *  @addr: EMI address to program
+ *  @data: value to be read from the EMI address
+ *
+ *  Assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
+{
+	return __e1000_access_emi_reg_locked(hw, addr, data, true);
+}
+
+/**
+ *  e1000_write_emi_reg_locked - Write Extended Management Interface register
+ *  @hw: pointer to the HW structure
+ *  @addr: EMI address to program
+ *  @data: value to be written to the EMI address
+ *
+ *  Assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+static s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
+{
+	return __e1000_access_emi_reg_locked(hw, addr, &data, false);
+}
+
+/**
  *  e1000_set_eee_pchlan - Enable/disable EEE support
  *  @hw: pointer to the HW structure
  *
- *  Enable/disable EEE based on setting in dev_spec structure.  The bits in
- *  the LPI Control register will remain set only if/when link is up.
+ *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
+ *  the link and the EEE capabilities of the link partner.  The LPI Control
+ *  register bits will remain set only if/when link is up.
  **/
 static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
 {
 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	s32 ret_val = 0;
-	u16 phy_reg;
+	s32 ret_val;
+	u16 lpi_ctrl;
 
 	if ((hw->phy.type != e1000_phy_82579) &&
 	    (hw->phy.type != e1000_phy_i217))
 		return 0;
 
-	ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val)
 		return ret_val;
 
-	if (dev_spec->eee_disable)
-		phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
-	else
-		phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
-
-	ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
+	ret_val = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
 	if (ret_val)
-		return ret_val;
+		goto release;
 
-	if ((hw->phy.type == e1000_phy_i217) && !dev_spec->eee_disable) {
+	/* Clear bits that enable EEE in various speeds */
+	lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
+
+	/* Enable EEE if not disabled by user */
+	if (!dev_spec->eee_disable) {
+		u16 lpa, pcs_status, data;
+
 		/* Save off link partner's EEE ability */
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			return ret_val;
-		ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
-					  I217_EEE_LP_ABILITY);
+		switch (hw->phy.type) {
+		case e1000_phy_82579:
+			lpa = I82579_EEE_LP_ABILITY;
+			pcs_status = I82579_EEE_PCS_STATUS;
+			break;
+		case e1000_phy_i217:
+			lpa = I217_EEE_LP_ABILITY;
+			pcs_status = I217_EEE_PCS_STATUS;
+			break;
+		default:
+			ret_val = -E1000_ERR_PHY;
+			goto release;
+		}
+		ret_val = e1000_read_emi_reg_locked(hw, lpa,
+						    &dev_spec->eee_lp_ability);
 		if (ret_val)
 			goto release;
-		e1e_rphy_locked(hw, I82579_EMI_DATA, &dev_spec->eee_lp_ability);
 
-		/* EEE is not supported in 100Half, so ignore partner's EEE
-		 * in 100 ability if full-duplex is not advertised.
+		/* Enable EEE only for speeds in which the link partner is
+		 * EEE capable.
 		 */
-		e1e_rphy_locked(hw, PHY_LP_ABILITY, &phy_reg);
-		if (!(phy_reg & NWAY_LPAR_100TX_FD_CAPS))
-			dev_spec->eee_lp_ability &= ~I217_EEE_100_SUPPORTED;
-release:
-		hw->phy.ops.release(hw);
+		if (dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
+			lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
+
+		if (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
+			e1e_rphy_locked(hw, MII_LPA, &data);
+			if (data & LPA_100FULL)
+				lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
+			else
+				/* EEE is not supported in 100Half, so ignore
+				 * partner's EEE in 100 ability if full-duplex
+				 * is not advertised.
+				 */
+				dev_spec->eee_lp_ability &=
+				    ~I82579_EEE_100_SUPPORTED;
+		}
+
+		/* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
+		ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
+		if (ret_val)
+			goto release;
 	}
 
-	return 0;
+	ret_val = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
+release:
+	hw->phy.ops.release(hw);
+
+	return ret_val;
 }
 
 /**
@@ -1017,7 +956,7 @@
  *
  *  Acquires the mutex for performing NVM operations.
  **/
-static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw __always_unused *hw)
 {
 	mutex_lock(&nvm_mutex);
 
@@ -1030,7 +969,7 @@
  *
  *  Releases the mutex used while performing NVM operations.
  **/
-static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+static void e1000_release_nvm_ich8lan(struct e1000_hw __always_unused *hw)
 {
 	mutex_unlock(&nvm_mutex);
 }
@@ -1322,7 +1261,7 @@
 	u32 strap = er32(STRAP);
 	u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
 	    E1000_STRAP_SMT_FREQ_SHIFT;
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
 
@@ -1558,7 +1497,7 @@
  **/
 s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
 {
-	s32 ret_val = 0;
+	s32 ret_val;
 	u32 ctrl_reg = 0;
 	u32 ctrl_ext = 0;
 	u32 reg = 0;
@@ -1727,7 +1666,7 @@
 		 */
 		if (hw->phy.revision < 2) {
 			e1000e_phy_sw_reset(hw);
-			ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140);
+			ret_val = e1e_wphy(hw, MII_BMCR, 0x3140);
 		}
 	}
 
@@ -1757,6 +1696,11 @@
 	if (ret_val)
 		goto release;
 	ret_val = e1e_wphy_locked(hw, BM_PORT_GEN_CFG, phy_data & 0x00FF);
+	if (ret_val)
+		goto release;
+
+	/* set MSE higher to enable link to stay up when noise is high */
+	ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
 release:
 	hw->phy.ops.release(hw);
 
@@ -1983,22 +1927,18 @@
 
 	/* Set MDIO slow mode before any other MDIO access */
 	ret_val = e1000_set_mdio_slow_mode_hv(hw);
+	if (ret_val)
+		return ret_val;
 
 	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val)
 		return ret_val;
-	ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_THRESHOLD);
-	if (ret_val)
-		goto release;
 	/* set MSE higher to enable link to stay up when noise is high */
-	ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0034);
-	if (ret_val)
-		goto release;
-	ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_LINK_DOWN);
+	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
 	if (ret_val)
 		goto release;
 	/* drop link after 5 times MSE threshold was reached */
-	ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0005);
+	ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
 release:
 	hw->phy.ops.release(hw);
 
@@ -2172,10 +2112,9 @@
 		ret_val = hw->phy.ops.acquire(hw);
 		if (ret_val)
 			return ret_val;
-		ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
-					  I82579_LPI_UPDATE_TIMER);
-		if (!ret_val)
-			ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x1387);
+		ret_val = e1000_write_emi_reg_locked(hw,
+						     I82579_LPI_UPDATE_TIMER,
+						     0x1387);
 		hw->phy.ops.release(hw);
 	}
 
@@ -2219,7 +2158,7 @@
  **/
 static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
 {
-	s32 ret_val = 0;
+	s32 ret_val;
 	u16 oem_reg;
 
 	ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
@@ -2277,6 +2216,8 @@
 
 		/* When LPLU is enabled, we should disable SmartSpeed */
 		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+		if (ret_val)
+			return ret_val;
 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
 		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
 		if (ret_val)
@@ -2949,19 +2890,32 @@
 {
 	s32 ret_val;
 	u16 data;
+	u16 word;
+	u16 valid_csum_mask;
 
-	/* Read 0x19 and check bit 6.  If this bit is 0, the checksum
-	 * needs to be fixed.  This bit is an indication that the NVM
-	 * was prepared by OEM software and did not calculate the
-	 * checksum...a likely scenario.
+	/* Read NVM and check Invalid Image CSUM bit.  If this bit is 0,
+	 * the checksum needs to be fixed.  This bit is an indication that
+	 * the NVM was prepared by OEM software and did not calculate
+	 * the checksum...a likely scenario.
 	 */
-	ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
+	switch (hw->mac.type) {
+	case e1000_pch_lpt:
+		word = NVM_COMPAT;
+		valid_csum_mask = NVM_COMPAT_VALID_CSUM;
+		break;
+	default:
+		word = NVM_FUTURE_INIT_WORD1;
+		valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
+		break;
+	}
+
+	ret_val = e1000_read_nvm(hw, word, 1, &data);
 	if (ret_val)
 		return ret_val;
 
-	if (!(data & 0x40)) {
-		data |= 0x40;
-		ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
+	if (!(data & valid_csum_mask)) {
+		data |= valid_csum_mask;
+		ret_val = e1000_write_nvm(hw, word, 1, &data);
 		if (ret_val)
 			return ret_val;
 		ret_val = e1000e_update_nvm_checksum(hw);
@@ -3975,8 +3929,7 @@
 	if (ret_val)
 		return;
 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
-				       reg_data);
+	e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, reg_data);
 }
 
 /**
@@ -4011,19 +3964,20 @@
 		if (!dev_spec->eee_disable) {
 			u16 eee_advert;
 
-			ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
-						  I217_EEE_ADVERTISEMENT);
+			ret_val =
+			    e1000_read_emi_reg_locked(hw,
+						      I217_EEE_ADVERTISEMENT,
+						      &eee_advert);
 			if (ret_val)
 				goto release;
-			e1e_rphy_locked(hw, I82579_EMI_DATA, &eee_advert);
 
 			/* Disable LPLU if both link partners support 100BaseT
 			 * EEE and 100Full is advertised on both ends of the
 			 * link.
 			 */
-			if ((eee_advert & I217_EEE_100_SUPPORTED) &&
+			if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
 			    (dev_spec->eee_lp_ability &
-			     I217_EEE_100_SUPPORTED) &&
+			     I82579_EEE_100_SUPPORTED) &&
 			    (hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
 				phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
 					      E1000_PHY_CTRL_NOND0A_LPLU);
@@ -4037,7 +3991,6 @@
 		 * The SMBus release must also be disabled on LCD reset.
 		 */
 		if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
-
 			/* Enable proxy to reset only on power good. */
 			e1e_rphy_locked(hw, I217_PROXY_CTRL, &phy_reg);
 			phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
@@ -4298,7 +4251,7 @@
 	u32 bank = 0;
 	u32 status;
 
-	e1000e_get_cfg_done(hw);
+	e1000e_get_cfg_done_generic(hw);
 
 	/* Wait for indication from h/w that it has completed basic config */
 	if (hw->mac.type >= e1000_ich10lan) {
@@ -4427,7 +4380,7 @@
 	.reset_hw		= e1000_reset_hw_ich8lan,
 	.init_hw		= e1000_init_hw_ich8lan,
 	.setup_link		= e1000_setup_link_ich8lan,
-	.setup_physical_interface= e1000_setup_copper_link_ich8lan,
+	.setup_physical_interface = e1000_setup_copper_link_ich8lan,
 	/* id_led_init dependent on mac type */
 	.config_collision_dist	= e1000e_config_collision_dist_generic,
 	.rar_set		= e1000e_rar_set_generic,
@@ -4449,7 +4402,7 @@
 
 static const struct e1000_nvm_operations ich8_nvm_ops = {
 	.acquire		= e1000_acquire_nvm_ich8lan,
-	.read		 	= e1000_read_nvm_ich8lan,
+	.read			= e1000_read_nvm_ich8lan,
 	.release		= e1000_release_nvm_ich8lan,
 	.reload			= e1000e_reload_nvm_generic,
 	.update			= e1000_update_nvm_checksum_ich8lan,
@@ -4531,6 +4484,7 @@
 	.mac			= e1000_pch2lan,
 	.flags			= FLAG_IS_ICH
 				  | FLAG_HAS_WOL
+				  | FLAG_HAS_HW_TIMESTAMP
 				  | FLAG_HAS_CTRLEXT_ON_LOAD
 				  | FLAG_HAS_AMT
 				  | FLAG_HAS_FLASH
@@ -4539,7 +4493,7 @@
 	.flags2			= FLAG2_HAS_PHY_STATS
 				  | FLAG2_HAS_EEE,
 	.pba			= 26,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.max_hw_frame_size	= 9018,
 	.get_variants		= e1000_get_variants_ich8lan,
 	.mac_ops		= &ich8_mac_ops,
 	.phy_ops		= &ich8_phy_ops,
@@ -4550,6 +4504,7 @@
 	.mac			= e1000_pch_lpt,
 	.flags			= FLAG_IS_ICH
 				  | FLAG_HAS_WOL
+				  | FLAG_HAS_HW_TIMESTAMP
 				  | FLAG_HAS_CTRLEXT_ON_LOAD
 				  | FLAG_HAS_AMT
 				  | FLAG_HAS_FLASH
@@ -4558,7 +4513,7 @@
 	.flags2			= FLAG2_HAS_PHY_STATS
 				  | FLAG2_HAS_EEE,
 	.pba			= 26,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.max_hw_frame_size	= 9018,
 	.get_variants		= e1000_get_variants_ich8lan,
 	.mac_ops		= &ich8_mac_ops,
 	.phy_ops		= &ich8_phy_ops,
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
new file mode 100644
index 0000000..b6d3174
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -0,0 +1,268 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_ICH8LAN_H_
+#define _E1000E_ICH8LAN_H_
+
+#define ICH_FLASH_GFPREG		0x0000
+#define ICH_FLASH_HSFSTS		0x0004
+#define ICH_FLASH_HSFCTL		0x0006
+#define ICH_FLASH_FADDR			0x0008
+#define ICH_FLASH_FDATA0		0x0010
+#define ICH_FLASH_PR0			0x0074
+
+/* Requires up to 10 seconds when MNG might be accessing part. */
+#define ICH_FLASH_READ_COMMAND_TIMEOUT	10000000
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT	10000000
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT	10000000
+#define ICH_FLASH_LINEAR_ADDR_MASK	0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT	10
+
+#define ICH_CYCLE_READ			0
+#define ICH_CYCLE_WRITE			2
+#define ICH_CYCLE_ERASE			3
+
+#define FLASH_GFPREG_BASE_MASK		0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT		12
+
+#define ICH_FLASH_SEG_SIZE_256		256
+#define ICH_FLASH_SEG_SIZE_4K		4096
+#define ICH_FLASH_SEG_SIZE_8K		8192
+#define ICH_FLASH_SEG_SIZE_64K		65536
+
+#define E1000_ICH_FWSM_RSPCIPHY	0x00000040	/* Reset PHY on PCI Reset */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID	0x00008000
+#define E1000_ICH_FWSM_PCIM2PCI	0x01000000	/* ME PCIm-to-PCI active */
+#define E1000_ICH_FWSM_PCIM2PCI_COUNT	2000
+
+#define E1000_ICH_MNG_IAMT_MODE		0x2
+
+#define E1000_FWSM_WLOCK_MAC_MASK	0x0380
+#define E1000_FWSM_WLOCK_MAC_SHIFT	7
+
+/* Shared Receive Address Registers */
+#define E1000_SHRAL_PCH_LPT(_i)		(0x05408 + ((_i) * 8))
+#define E1000_SHRAH_PCH_LPT(_i)		(0x0540C + ((_i) * 8))
+
+#define ID_LED_DEFAULT_ICH8LAN	((ID_LED_DEF1_DEF2 << 12) | \
+				 (ID_LED_OFF1_OFF2 <<  8) | \
+				 (ID_LED_OFF1_ON2  <<  4) | \
+				 (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD		0x13
+#define E1000_ICH_NVM_SIG_MASK		0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK	0xC0
+#define E1000_ICH_NVM_SIG_VALUE		0x80
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT	1500
+
+#define E1000_FEXTNVM_SW_CONFIG		1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M	(1 << 27)	/* different on ICH8M */
+
+#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK	0x0C000000
+#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC	0x08000000
+
+#define E1000_FEXTNVM4_BEACON_DURATION_MASK	0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_8USEC	0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_16USEC	0x3
+
+#define PCIE_ICH8_SNOOP_ALL	PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES	7
+#define E1000_PCH2_RAR_ENTRIES	5	/* RAR[0], SHRA[0-3] */
+#define E1000_PCH_LPT_RAR_ENTRIES	12	/* RAR[0], SHRA[0-10] */
+
+#define PHY_PAGE_SHIFT		5
+#define PHY_REG(page, reg)	(((page) << PHY_PAGE_SHIFT) | \
+				 ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG	PHY_REG(770, 19)	/* KMRN Diagnostic */
+#define IGP3_VR_CTRL	PHY_REG(776, 18)	/* Voltage Regulator Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS		0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK	0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN		0x0200
+
+/* PHY Wakeup Registers and defines */
+#define BM_PORT_GEN_CFG		PHY_REG(BM_PORT_CTRL_PAGE, 17)
+#define BM_RCTL			PHY_REG(BM_WUC_PAGE, 0)
+#define BM_WUC			PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC			PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS			PHY_REG(BM_WUC_PAGE, 3)
+#define BM_RAR_L(_i)		(BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i)		(BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i)		(BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i)		(BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i)		(BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+
+#define BM_RCTL_UPE		0x0001	/* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE		0x0002	/* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT	3	/* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK		(3 << 3)	/* Multicast Offset Mask */
+#define BM_RCTL_BAM		0x0020	/* Broadcast Accept Mode */
+#define BM_RCTL_PMCF		0x0040	/* Pass MAC Control Frames */
+#define BM_RCTL_RFCE		0x0080	/* Rx Flow Control Enable */
+
+#define HV_LED_CONFIG		PHY_REG(768, 30)	/* LED Configuration */
+#define HV_MUX_DATA_CTRL	PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC	0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED	0x0004
+#define HV_STATS_PAGE	778
+/* Half-duplex collision counts */
+#define HV_SCC_UPPER	PHY_REG(HV_STATS_PAGE, 16)	/* Single Collision */
+#define HV_SCC_LOWER	PHY_REG(HV_STATS_PAGE, 17)
+#define HV_ECOL_UPPER	PHY_REG(HV_STATS_PAGE, 18)	/* Excessive Coll. */
+#define HV_ECOL_LOWER	PHY_REG(HV_STATS_PAGE, 19)
+#define HV_MCC_UPPER	PHY_REG(HV_STATS_PAGE, 20)	/* Multiple Collision */
+#define HV_MCC_LOWER	PHY_REG(HV_STATS_PAGE, 21)
+#define HV_LATECOL_UPPER PHY_REG(HV_STATS_PAGE, 23)	/* Late Collision */
+#define HV_LATECOL_LOWER PHY_REG(HV_STATS_PAGE, 24)
+#define HV_COLC_UPPER	PHY_REG(HV_STATS_PAGE, 25)	/* Collision */
+#define HV_COLC_LOWER	PHY_REG(HV_STATS_PAGE, 26)
+#define HV_DC_UPPER	PHY_REG(HV_STATS_PAGE, 27)	/* Defer Count */
+#define HV_DC_LOWER	PHY_REG(HV_STATS_PAGE, 28)
+#define HV_TNCRS_UPPER	PHY_REG(HV_STATS_PAGE, 29)	/* Tx with no CRS */
+#define HV_TNCRS_LOWER	PHY_REG(HV_STATS_PAGE, 30)
+
+#define E1000_FCRTV_PCH	0x05F40	/* PCH Flow Control Refresh Timer Value */
+
+#define E1000_NVM_K1_CONFIG	0x1B	/* NVM K1 Config Word */
+#define E1000_NVM_K1_ENABLE	0x1	/* NVM Enable K1 bit */
+
+/* SMBus Control Phy Register */
+#define CV_SMB_CTRL		PHY_REG(769, 23)
+#define CV_SMB_CTRL_FORCE_SMBUS	0x0001
+
+/* SMBus Address Phy Register */
+#define HV_SMB_ADDR		PHY_REG(768, 26)
+#define HV_SMB_ADDR_MASK	0x007F
+#define HV_SMB_ADDR_PEC_EN	0x0200
+#define HV_SMB_ADDR_VALID	0x0080
+#define HV_SMB_ADDR_FREQ_MASK		0x1100
+#define HV_SMB_ADDR_FREQ_LOW_SHIFT	8
+#define HV_SMB_ADDR_FREQ_HIGH_SHIFT	12
+
+/* Strapping Option Register - RO */
+#define E1000_STRAP			0x0000C
+#define E1000_STRAP_SMBUS_ADDRESS_MASK	0x00FE0000
+#define E1000_STRAP_SMBUS_ADDRESS_SHIFT	17
+#define E1000_STRAP_SMT_FREQ_MASK	0x00003000
+#define E1000_STRAP_SMT_FREQ_SHIFT	12
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS		PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU	0x0004	/* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS	0x0040	/* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN	0x0400	/* Restart Auto-negotiation */
+
+/* KMRN Mode Control */
+#define HV_KMRN_MODE_CTRL	PHY_REG(769, 16)
+#define HV_KMRN_MDIO_SLOW	0x0400
+
+/* KMRN FIFO Control and Status */
+#define HV_KMRN_FIFO_CTRLSTA			PHY_REG(770, 16)
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK	0x7000
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT	12
+
+/* PHY Power Management Control */
+#define HV_PM_CTRL		PHY_REG(770, 17)
+#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA	0x100
+
+#define SW_FLAG_TIMEOUT		1000	/* SW Semaphore flag timeout in ms */
+
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL				PHY_REG(772, 20)
+#define I82579_LPI_CTRL_100_ENABLE		0x2000
+#define I82579_LPI_CTRL_1000_ENABLE		0x4000
+#define I82579_LPI_CTRL_ENABLE_MASK		0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT	0x80
+
+/* Extended Management Interface (EMI) Registers */
+#define I82579_EMI_ADDR		0x10
+#define I82579_EMI_DATA		0x11
+#define I82579_LPI_UPDATE_TIMER	0x4805	/* in 40ns units + 40 ns base value */
+#define I82579_MSE_THRESHOLD	0x084F	/* 82579 Mean Square Error Threshold */
+#define I82577_MSE_THRESHOLD	0x0887	/* 82577 Mean Square Error Threshold */
+#define I82579_MSE_LINK_DOWN	0x2411	/* MSE count before dropping link */
+#define I82579_EEE_PCS_STATUS		0x182D	/* IEEE MMD Register 3.1 >> 8 */
+#define I82579_EEE_CAPABILITY		0x0410	/* IEEE MMD Register 3.20 */
+#define I82579_EEE_ADVERTISEMENT	0x040E	/* IEEE MMD Register 7.60 */
+#define I82579_EEE_LP_ABILITY		0x040F	/* IEEE MMD Register 7.61 */
+#define I82579_EEE_100_SUPPORTED	(1 << 1)	/* 100BaseTx EEE */
+#define I82579_EEE_1000_SUPPORTED	(1 << 2)	/* 1000BaseTx EEE */
+#define I217_EEE_PCS_STATUS	0x9401	/* IEEE MMD Register 3.1 */
+#define I217_EEE_CAPABILITY	0x8000	/* IEEE MMD Register 3.20 */
+#define I217_EEE_ADVERTISEMENT	0x8001	/* IEEE MMD Register 7.60 */
+#define I217_EEE_LP_ABILITY	0x8002	/* IEEE MMD Register 7.61 */
+
+#define E1000_EEE_RX_LPI_RCVD	0x0400	/* Tx LP idle received */
+#define E1000_EEE_TX_LPI_RCVD	0x0800	/* Rx LP idle received */
+
+/* Intel Rapid Start Technology Support */
+#define I217_PROXY_CTRL		BM_PHY_REG(BM_WUC_PAGE, 70)
+#define I217_PROXY_CTRL_AUTO_DISABLE	0x0080
+#define I217_SxCTRL			PHY_REG(BM_PORT_CTRL_PAGE, 28)
+#define I217_SxCTRL_ENABLE_LPI_RESET	0x1000
+#define I217_CGFREG			PHY_REG(772, 29)
+#define I217_CGFREG_ENABLE_MTA_RESET	0x0002
+#define I217_MEMPWR			PHY_REG(772, 26)
+#define I217_MEMPWR_DISABLE_SMB_RELEASE	0x0010
+
+/* Receive Address Initial CRC Calculation */
+#define E1000_PCH_RAICC(_n)	(0x05F50 + ((_n) * 4))
+
+/* Latency Tolerance Reporting */
+#define E1000_LTRV			0x000F8
+#define E1000_LTRV_SCALE_MAX		5
+#define E1000_LTRV_SCALE_FACTOR		5
+#define E1000_LTRV_REQ_SHIFT		15
+#define E1000_LTRV_NOSNOOP_SHIFT	16
+#define E1000_LTRV_SEND			(1 << 30)
+
+/* Proprietary Latency Tolerance Reporting PCI Capability */
+#define E1000_PCI_LTR_CAP_LPT		0xA8
+
+/* OBFF Control & Threshold Defines */
+#define E1000_SVCR_OFF_EN		0x00000001
+#define E1000_SVCR_OFF_MASKINT		0x00001000
+#define E1000_SVCR_OFF_TIMER_MASK	0xFFFF0000
+#define E1000_SVCR_OFF_TIMER_SHIFT	16
+#define E1000_SVT_OFF_HWM_MASK		0x0000001F
+
+void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+						  bool state);
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw);
+void e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
+s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
+s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
+#endif /* _E1000E_ICH8LAN_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 54d9daf..b78e021 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -165,7 +165,7 @@
 s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
 {
 	u32 i;
-	s32 ret_val = 0;
+	s32 ret_val;
 	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
 	u8 alt_mac_addr[ETH_ALEN];
 
@@ -1021,6 +1021,7 @@
 {
 	struct e1000_mac_info *mac = &hw->mac;
 	s32 ret_val = 0;
+	u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg;
 	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
 	u16 speed, duplex;
 
@@ -1052,14 +1053,14 @@
 		 * has completed.  We read this twice because this reg has
 		 * some "sticky" (latched) bits.
 		 */
-		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+		ret_val = e1e_rphy(hw, MII_BMSR, &mii_status_reg);
 		if (ret_val)
 			return ret_val;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+		ret_val = e1e_rphy(hw, MII_BMSR, &mii_status_reg);
 		if (ret_val)
 			return ret_val;
 
-		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+		if (!(mii_status_reg & BMSR_ANEGCOMPLETE)) {
 			e_dbg("Copper PHY and Auto Neg has not completed.\n");
 			return ret_val;
 		}
@@ -1070,11 +1071,10 @@
 		 * Page Ability Register (Address 5) to determine how
 		 * flow control was negotiated.
 		 */
-		ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);
+		ret_val = e1e_rphy(hw, MII_ADVERTISE, &mii_nway_adv_reg);
 		if (ret_val)
 			return ret_val;
-		ret_val =
-		    e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
+		ret_val = e1e_rphy(hw, MII_LPA, &mii_nway_lp_ability_reg);
 		if (ret_val)
 			return ret_val;
 
@@ -1111,8 +1111,8 @@
 		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
 		 *
 		 */
-		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+		if ((mii_nway_adv_reg & ADVERTISE_PAUSE_CAP) &&
+		    (mii_nway_lp_ability_reg & LPA_PAUSE_CAP)) {
 			/* Now we need to check if the user selected Rx ONLY
 			 * of pause frames.  In this case, we had to advertise
 			 * FULL flow control because we could not advertise Rx
@@ -1134,10 +1134,10 @@
 		 *-------|---------|-------|---------|--------------------
 		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
 		 */
-		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-			 (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+		else if (!(mii_nway_adv_reg & ADVERTISE_PAUSE_CAP) &&
+			 (mii_nway_adv_reg & ADVERTISE_PAUSE_ASYM) &&
+			 (mii_nway_lp_ability_reg & LPA_PAUSE_CAP) &&
+			 (mii_nway_lp_ability_reg & LPA_PAUSE_ASYM)) {
 			hw->fc.current_mode = e1000_fc_tx_pause;
 			e_dbg("Flow Control = Tx PAUSE frames only.\n");
 		}
@@ -1148,10 +1148,10 @@
 		 *-------|---------|-------|---------|--------------------
 		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
 		 */
-		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+		else if ((mii_nway_adv_reg & ADVERTISE_PAUSE_CAP) &&
+			 (mii_nway_adv_reg & ADVERTISE_PAUSE_ASYM) &&
+			 !(mii_nway_lp_ability_reg & LPA_PAUSE_CAP) &&
+			 (mii_nway_lp_ability_reg & LPA_PAUSE_ASYM)) {
 			hw->fc.current_mode = e1000_fc_rx_pause;
 			e_dbg("Flow Control = Rx PAUSE frames only.\n");
 		} else {
@@ -1185,6 +1185,130 @@
 		}
 	}
 
+	/* Check for the case where we have SerDes media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
+	    mac->autoneg) {
+		/* Read the PCS_LSTS and check to see if AutoNeg
+		 * has completed.
+		 */
+		pcs_status_reg = er32(PCS_LSTAT);
+
+		if (!(pcs_status_reg & E1000_PCS_LSTS_AN_COMPLETE)) {
+			e_dbg("PCS Auto Neg has not completed.\n");
+			return ret_val;
+		}
+
+		/* The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (PCS_ANADV) and the Auto_Negotiation Base
+		 * Page Ability Register (PCS_LPAB) to determine how
+		 * flow control was negotiated.
+		 */
+		pcs_adv_reg = er32(PCS_ANADV);
+		pcs_lp_ability_reg = er32(PCS_LPAB);
+
+		/* Two bits in the Auto Negotiation Advertisement Register
+		 * (PCS_ANADV) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (PCS_LPAB) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *
+		 */
+		if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+		    (pcs_lp_ability_reg & E1000_TXCW_PAUSE)) {
+			/* Now we need to check if the user selected Rx ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise Rx
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.requested_mode == e1000_fc_full) {
+				hw->fc.current_mode = e1000_fc_full;
+				e_dbg("Flow Control = FULL.\n");
+			} else {
+				hw->fc.current_mode = e1000_fc_rx_pause;
+				e_dbg("Flow Control = Rx PAUSE frames only.\n");
+			}
+		}
+		/* For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(pcs_adv_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+			 (pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_tx_pause;
+			e_dbg("Flow Control = Tx PAUSE frames only.\n");
+		}
+		/* For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+			 !(pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+			 (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+			hw->fc.current_mode = e1000_fc_rx_pause;
+			e_dbg("Flow Control = Rx PAUSE frames only.\n");
+		} else {
+			/* Per the IEEE spec, at this point flow control
+			 * should be disabled.
+			 */
+			hw->fc.current_mode = e1000_fc_none;
+			e_dbg("Flow Control = NONE.\n");
+		}
+
+		/* Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		pcs_ctrl_reg = er32(PCS_LCTL);
+		pcs_ctrl_reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+		ew32(PCS_LCTL, pcs_ctrl_reg);
+
+		ret_val = e1000e_force_mac_fc(hw);
+		if (ret_val) {
+			e_dbg("Error forcing flow control settings\n");
+			return ret_val;
+		}
+	}
+
 	return 0;
 }
 
@@ -1231,8 +1355,8 @@
  *  Sets the speed and duplex to gigabit full duplex (the only possible option)
  *  for fiber/serdes links.
  **/
-s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed,
-					     u16 *duplex)
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw __always_unused
+					     *hw, u16 *speed, u16 *duplex)
 {
 	*speed = SPEED_1000;
 	*duplex = FULL_DUPLEX;
diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h
new file mode 100644
index 0000000..a61fee4
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/mac.h
@@ -0,0 +1,74 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_MAC_H_
+#define _E1000E_MAC_H_
+
+s32 e1000e_blink_led_generic(struct e1000_hw *hw);
+s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
+s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
+s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
+s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
+s32 e1000e_force_mac_fc(struct e1000_hw *hw);
+s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
+s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+void e1000_set_lan_id_single_port(struct e1000_hw *hw);
+s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
+s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+				       u16 *duplex);
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw,
+					     u16 *speed, u16 *duplex);
+s32 e1000e_id_led_init_generic(struct e1000_hw *hw);
+s32 e1000e_led_on_generic(struct e1000_hw *hw);
+s32 e1000e_led_off_generic(struct e1000_hw *hw);
+void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
+					u8 *mc_addr_list, u32 mc_addr_count);
+s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
+s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+s32 e1000e_setup_led_generic(struct e1000_hw *hw);
+s32 e1000e_setup_link_generic(struct e1000_hw *hw);
+s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw);
+s32 e1000e_validate_mdi_setting_crossover_generic(struct e1000_hw *hw);
+
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+void e1000_clear_vfta_generic(struct e1000_hw *hw);
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000e_reset_adaptive(struct e1000_hw *hw);
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+void e1000e_update_adaptive(struct e1000_hw *hw);
+void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+
+void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+void e1000e_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
+void e1000e_config_collision_dist_generic(struct e1000_hw *hw);
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c
index 6dc47be..e4b0f1e 100644
--- a/drivers/net/ethernet/intel/e1000e/manage.c
+++ b/drivers/net/ethernet/intel/e1000e/manage.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -28,19 +28,6 @@
 
 #include "e1000.h"
 
-enum e1000_mng_mode {
-	e1000_mng_mode_none = 0,
-	e1000_mng_mode_asf,
-	e1000_mng_mode_pt,
-	e1000_mng_mode_ipmi,
-	e1000_mng_mode_host_if_only
-};
-
-#define E1000_FACTPS_MNGCG		0x20000000
-
-/* Intel(R) Active Management Technology signature */
-#define E1000_IAMT_SIGNATURE		0x544D4149
-
 /**
  *  e1000_calculate_checksum - Calculate checksum for buffer
  *  @buffer: pointer to EEPROM
diff --git a/drivers/net/ethernet/intel/e1000e/manage.h b/drivers/net/ethernet/intel/e1000e/manage.h
new file mode 100644
index 0000000..326897c
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/manage.h
@@ -0,0 +1,72 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_MANAGE_H_
+#define _E1000E_MANAGE_H_
+
+bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG			0x20000000
+
+#define E1000_FWSM_MODE_MASK			0xE
+#define E1000_FWSM_MODE_SHIFT			1
+
+#define E1000_MNG_IAMT_MODE			0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH		0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET		0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT		10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD		64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING	0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN	0x2
+
+#define E1000_VFTA_ENTRY_SHIFT			5
+#define E1000_VFTA_ENTRY_MASK			0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK		0x1F
+
+#define E1000_HICR_EN			0x01	/* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C			0x02
+#define E1000_HICR_SV			0x04	/* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE	0x40
+#define E1000_HICR_FW_RESET		0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE		0x544D4149
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 643c883..a177b8b 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -42,7 +42,6 @@
 #include <linux/slab.h>
 #include <net/checksum.h>
 #include <net/ip6_checksum.h>
-#include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
@@ -56,7 +55,7 @@
 
 #define DRV_EXTRAVERSION "-k"
 
-#define DRV_VERSION "2.1.4" DRV_EXTRAVERSION
+#define DRV_VERSION "2.2.14" DRV_EXTRAVERSION
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -87,20 +86,7 @@
 	char *name;
 };
 
-#define E1000_RDFH	0x02410	/* Rx Data FIFO Head - RW */
-#define E1000_RDFT	0x02418	/* Rx Data FIFO Tail - RW */
-#define E1000_RDFHS	0x02420	/* Rx Data FIFO Head Saved - RW */
-#define E1000_RDFTS	0x02428	/* Rx Data FIFO Tail Saved - RW */
-#define E1000_RDFPC	0x02430	/* Rx Data FIFO Packet Count - RW */
-
-#define E1000_TDFH	0x03410	/* Tx Data FIFO Head - RW */
-#define E1000_TDFT	0x03418	/* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS	0x03420	/* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS	0x03428	/* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC	0x03430	/* Tx Data FIFO Packet Count - RW */
-
 static const struct e1000_reg_info e1000_reg_info_tbl[] = {
-
 	/* General Registers */
 	{E1000_CTRL, "CTRL"},
 	{E1000_STATUS, "STATUS"},
@@ -488,20 +474,87 @@
 }
 
 /**
+ * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+ * @adapter: board private structure
+ * @hwtstamps: time stamp structure to update
+ * @systim: unsigned 64bit system time value.
+ *
+ * Convert the system time value stored in the RX/TXSTMP registers into a
+ * hwtstamp which can be used by the upper level time stamping functions.
+ *
+ * The 'systim_lock' spinlock is used to protect the consistency of the
+ * system time value. This is needed because reading the 64 bit time
+ * value involves reading two 32 bit registers. The first read latches the
+ * value.
+ **/
+static void e1000e_systim_to_hwtstamp(struct e1000_adapter *adapter,
+				      struct skb_shared_hwtstamps *hwtstamps,
+				      u64 systim)
+{
+	u64 ns;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->systim_lock, flags);
+	ns = timecounter_cyc2time(&adapter->tc, systim);
+	spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+	memset(hwtstamps, 0, sizeof(*hwtstamps));
+	hwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * e1000e_rx_hwtstamp - utility function which checks for Rx time stamp
+ * @adapter: board private structure
+ * @status: descriptor extended error and status field
+ * @skb: particular skb to include time stamp
+ *
+ * If the time stamp is valid, convert it into the timecounter ns value
+ * and store that result into the shhwtstamps structure which is passed
+ * up the network stack.
+ **/
+static void e1000e_rx_hwtstamp(struct e1000_adapter *adapter, u32 status,
+			       struct sk_buff *skb)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u64 rxstmp;
+
+	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP) ||
+	    !(status & E1000_RXDEXT_STATERR_TST) ||
+	    !(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
+		return;
+
+	/* The Rx time stamp registers contain the time stamp.  No other
+	 * received packet will be time stamped until the Rx time stamp
+	 * registers are read.  Because only one packet can be time stamped
+	 * at a time, the register values must belong to this packet and
+	 * therefore none of the other additional attributes need to be
+	 * compared.
+	 */
+	rxstmp = (u64)er32(RXSTMPL);
+	rxstmp |= (u64)er32(RXSTMPH) << 32;
+	e1000e_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), rxstmp);
+
+	adapter->flags2 &= ~FLAG2_CHECK_RX_HWTSTAMP;
+}
+
+/**
  * e1000_receive_skb - helper function to handle Rx indications
  * @adapter: board private structure
- * @status: descriptor status field as written by hardware
+ * @staterr: descriptor extended error and status field as written by hardware
  * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
  * @skb: pointer to sk_buff to be indicated to stack
  **/
 static void e1000_receive_skb(struct e1000_adapter *adapter,
 			      struct net_device *netdev, struct sk_buff *skb,
-			      u8 status, __le16 vlan)
+			      u32 staterr, __le16 vlan)
 {
 	u16 tag = le16_to_cpu(vlan);
+
+	e1000e_rx_hwtstamp(adapter, staterr, skb);
+
 	skb->protocol = eth_type_trans(skb, netdev);
 
-	if (status & E1000_RXD_STAT_VP)
+	if (staterr & E1000_RXD_STAT_VP)
 		__vlan_hwaccel_put_tag(skb, tag);
 
 	napi_gro_receive(&adapter->napi, skb);
@@ -765,7 +818,7 @@
 	struct e1000_buffer *buffer_info;
 	struct sk_buff *skb;
 	unsigned int i;
-	unsigned int bufsz = 256 - 16 /* for skb_reserve */;
+	unsigned int bufsz = 256 - 16;	/* for skb_reserve */
 
 	i = rx_ring->next_to_use;
 	buffer_info = &rx_ring->buffer_info[i];
@@ -1050,9 +1103,9 @@
 	adapter->tx_hang_recheck = false;
 	netif_stop_queue(netdev);
 
-	e1e_rphy(hw, PHY_STATUS, &phy_status);
-	e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status);
-	e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status);
+	e1e_rphy(hw, MII_BMSR, &phy_status);
+	e1e_rphy(hw, MII_STAT1000, &phy_1000t_status);
+	e1e_rphy(hw, MII_ESTATUS, &phy_ext_status);
 
 	pci_read_config_word(adapter->pdev, PCI_STATUS, &pci_status);
 
@@ -1092,6 +1145,41 @@
 }
 
 /**
+ * e1000e_tx_hwtstamp_work - check for Tx time stamp
+ * @work: pointer to work struct
+ *
+ * This work function polls the TSYNCTXCTL valid bit to determine when a
+ * timestamp has been taken for the current stored skb.  The timestamp must
+ * be for this skb because only one such packet is allowed in the queue.
+ */
+static void e1000e_tx_hwtstamp_work(struct work_struct *work)
+{
+	struct e1000_adapter *adapter = container_of(work, struct e1000_adapter,
+						     tx_hwtstamp_work);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (!adapter->tx_hwtstamp_skb)
+		return;
+
+	if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+		struct skb_shared_hwtstamps shhwtstamps;
+		u64 txstmp;
+
+		txstmp = er32(TXSTMPL);
+		txstmp |= (u64)er32(TXSTMPH) << 32;
+
+		e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
+
+		skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
+		dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+		adapter->tx_hwtstamp_skb = NULL;
+	} else {
+		/* reschedule to check later */
+		schedule_work(&adapter->tx_hwtstamp_work);
+	}
+}
+
+/**
  * e1000_clean_tx_irq - Reclaim resources after transmit completes
  * @tx_ring: Tx descriptor ring
  *
@@ -1345,8 +1433,8 @@
 			   cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
 			adapter->rx_hdr_split++;
 
-		e1000_receive_skb(adapter, netdev, skb,
-				  staterr, rx_desc->wb.middle.vlan);
+		e1000_receive_skb(adapter, netdev, skb, staterr,
+				  rx_desc->wb.middle.vlan);
 
 next_desc:
 		rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
@@ -1645,7 +1733,7 @@
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
  **/
-static irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1671,7 +1759,7 @@
 			/* disable receives */
 			u32 rctl = er32(RCTL);
 			ew32(RCTL, rctl & ~E1000_RCTL_EN);
-			adapter->flags |= FLAG_RX_RESTART_NOW;
+			adapter->flags |= FLAG_RESTART_NOW;
 		}
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -1711,7 +1799,7 @@
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
  **/
-static irqreturn_t e1000_intr(int irq, void *data)
+static irqreturn_t e1000_intr(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1751,7 +1839,7 @@
 			/* disable receives */
 			rctl = er32(RCTL);
 			ew32(RCTL, rctl & ~E1000_RCTL_EN);
-			adapter->flags |= FLAG_RX_RESTART_NOW;
+			adapter->flags |= FLAG_RESTART_NOW;
 		}
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -1786,7 +1874,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t e1000_msix_other(int irq, void *data)
+static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1818,8 +1906,7 @@
 	return IRQ_HANDLED;
 }
 
-
-static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
+static irqreturn_t e1000_intr_msix_tx(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1837,7 +1924,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
+static irqreturn_t e1000_intr_msix_rx(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1924,7 +2011,6 @@
 	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
 
 	/* Auto-Mask Other interrupts upon ICR read */
-#define E1000_EIAC_MASK_82574   0x01F00000
 	ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
 	ctrl_ext |= E1000_CTRL_EXT_EIAME;
 	ew32(CTRL_EXT, ctrl_ext);
@@ -2394,9 +2480,7 @@
  *      while increasing bulk throughput.  This functionality is controlled
  *      by the InterruptThrottleRate module parameter.
  **/
-static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
-				     u16 itr_setting, int packets,
-				     int bytes)
+static unsigned int e1000_update_itr(u16 itr_setting, int packets, int bytes)
 {
 	unsigned int retval = itr_setting;
 
@@ -2441,7 +2525,6 @@
 
 static void e1000_set_itr(struct e1000_adapter *adapter)
 {
-	struct e1000_hw *hw = &adapter->hw;
 	u16 current_itr;
 	u32 new_itr = adapter->itr;
 
@@ -2457,18 +2540,16 @@
 		goto set_itr_now;
 	}
 
-	adapter->tx_itr = e1000_update_itr(adapter,
-				    adapter->tx_itr,
-				    adapter->total_tx_packets,
-				    adapter->total_tx_bytes);
+	adapter->tx_itr = e1000_update_itr(adapter->tx_itr,
+					   adapter->total_tx_packets,
+					   adapter->total_tx_bytes);
 	/* conservative mode (itr 3) eliminates the lowest_latency setting */
 	if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
 		adapter->tx_itr = low_latency;
 
-	adapter->rx_itr = e1000_update_itr(adapter,
-				    adapter->rx_itr,
-				    adapter->total_rx_packets,
-				    adapter->total_rx_bytes);
+	adapter->rx_itr = e1000_update_itr(adapter->rx_itr,
+					   adapter->total_rx_packets,
+					   adapter->total_rx_bytes);
 	/* conservative mode (itr 3) eliminates the lowest_latency setting */
 	if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
 		adapter->rx_itr = low_latency;
@@ -2504,10 +2585,7 @@
 		if (adapter->msix_entries)
 			adapter->rx_ring->set_itr = 1;
 		else
-			if (new_itr)
-				ew32(ITR, 1000000000 / (new_itr * 256));
-			else
-				ew32(ITR, 0);
+			e1000e_write_itr(adapter, new_itr);
 	}
 }
 
@@ -3049,7 +3127,7 @@
 
 	ew32(RCTL, rctl);
 	/* just started the receive unit, no need to restart */
-	adapter->flags &= ~FLAG_RX_RESTART_NOW;
+	adapter->flags &= ~FLAG_RESTART_NOW;
 }
 
 /**
@@ -3144,18 +3222,23 @@
 		rxcsum &= ~E1000_RXCSUM_TUOFL;
 	ew32(RXCSUM, rxcsum);
 
-	if (adapter->hw.mac.type == e1000_pch2lan) {
-		/* With jumbo frames, excessive C-state transition
-		 * latencies result in dropped transactions.
-		 */
-		if (adapter->netdev->mtu > ETH_DATA_LEN) {
+	/* With jumbo frames, excessive C-state transition latencies result
+	 * in dropped transactions.
+	 */
+	if (adapter->netdev->mtu > ETH_DATA_LEN) {
+		u32 lat =
+		    ((er32(PBA) & E1000_PBA_RXA_MASK) * 1024 -
+		     adapter->max_frame_size) * 8 / 1000;
+
+		if (adapter->flags & FLAG_IS_ICH) {
 			u32 rxdctl = er32(RXDCTL(0));
 			ew32(RXDCTL(0), rxdctl | 0x3);
-			pm_qos_update_request(&adapter->netdev->pm_qos_req, 55);
-		} else {
-			pm_qos_update_request(&adapter->netdev->pm_qos_req,
-					      PM_QOS_DEFAULT_VALUE);
 		}
+
+		pm_qos_update_request(&adapter->netdev->pm_qos_req, lat);
+	} else {
+		pm_qos_update_request(&adapter->netdev->pm_qos_req,
+				      PM_QOS_DEFAULT_VALUE);
 	}
 
 	/* Enable Receives */
@@ -3344,6 +3427,241 @@
 }
 
 /**
+ * e1000e_get_base_timinca - get default SYSTIM time increment attributes
+ * @adapter: board private structure
+ * @timinca: pointer to returned time increment attributes
+ *
+ * Get attributes for incrementing the System Time Register SYSTIML/H at
+ * the default base frequency, and set the cyclecounter shift value.
+ **/
+s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 incvalue, incperiod, shift;
+
+	/* Make sure clock is enabled on I217 before checking the frequency */
+	if ((hw->mac.type == e1000_pch_lpt) &&
+	    !(er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_ENABLED) &&
+	    !(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_ENABLED)) {
+		u32 fextnvm7 = er32(FEXTNVM7);
+
+		if (!(fextnvm7 & (1 << 0))) {
+			ew32(FEXTNVM7, fextnvm7 | (1 << 0));
+			e1e_flush();
+		}
+	}
+
+	switch (hw->mac.type) {
+	case e1000_pch2lan:
+	case e1000_pch_lpt:
+		/* On I217, the clock frequency is 25MHz or 96MHz as
+		 * indicated by the System Clock Frequency Indication
+		 */
+		if ((hw->mac.type != e1000_pch_lpt) ||
+		    (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+			/* Stable 96MHz frequency */
+			incperiod = INCPERIOD_96MHz;
+			incvalue = INCVALUE_96MHz;
+			shift = INCVALUE_SHIFT_96MHz;
+			adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz;
+			break;
+		}
+		/* fall-through */
+	case e1000_82574:
+	case e1000_82583:
+		/* Stable 25MHz frequency */
+		incperiod = INCPERIOD_25MHz;
+		incvalue = INCVALUE_25MHz;
+		shift = INCVALUE_SHIFT_25MHz;
+		adapter->cc.shift = shift;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*timinca = ((incperiod << E1000_TIMINCA_INCPERIOD_SHIFT) |
+		    ((incvalue << shift) & E1000_TIMINCA_INCVALUE_MASK));
+
+	return 0;
+}
+
+/**
+ * e1000e_config_hwtstamp - configure the hwtstamp registers and enable/disable
+ * @adapter: board private structure
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware filters.
+ * Not all combinations are supported, in particular event type has to be
+ * specified. Matching the kind of event packet is not supported, with the
+ * exception of "all V2 events regardless of level 2 or 4".
+ **/
+static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct hwtstamp_config *config = &adapter->hwtstamp_config;
+	u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
+	u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
+	u32 rxmtrl = 0;
+	u16 rxudp = 0;
+	bool is_l4 = false;
+	bool is_l2 = false;
+	u32 regval;
+	s32 ret_val;
+
+	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+		return -EINVAL;
+
+	/* flags reserved for future extensions - must be zero */
+	if (config->flags)
+		return -EINVAL;
+
+	switch (config->tx_type) {
+	case HWTSTAMP_TX_OFF:
+		tsync_tx_ctl = 0;
+		break;
+	case HWTSTAMP_TX_ON:
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	switch (config->rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		tsync_rx_ctl = 0;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+		rxmtrl = E1000_RXMTRL_PTP_V1_SYNC_MESSAGE;
+		is_l4 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+		rxmtrl = E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE;
+		is_l4 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+		/* Also time stamps V2 L2 Path Delay Request/Response */
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
+		rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
+		is_l2 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+		/* Also time stamps V2 L2 Path Delay Request/Response. */
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
+		rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
+		is_l2 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+		/* Hardware cannot filter just V2 L4 Sync messages;
+		 * fall-through to V2 (both L2 and L4) Sync.
+		 */
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+		/* Also time stamps V2 Path Delay Request/Response. */
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+		rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
+		is_l2 = true;
+		is_l4 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+		/* Hardware cannot filter just V2 L4 Delay Request messages;
+		 * fall-through to V2 (both L2 and L4) Delay Request.
+		 */
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		/* Also time stamps V2 Path Delay Request/Response. */
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+		rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
+		is_l2 = true;
+		is_l4 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+		/* Hardware cannot filter just V2 L4 or L2 Event messages;
+		 * fall-through to all V2 (both L2 and L4) Events.
+		 */
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
+		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+		is_l2 = true;
+		is_l4 = true;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+		/* For V1, the hardware can only filter Sync messages or
+		 * Delay Request messages but not both so fall-through to
+		 * time stamp all packets.
+		 */
+	case HWTSTAMP_FILTER_ALL:
+		is_l2 = true;
+		is_l4 = true;
+		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+		config->rx_filter = HWTSTAMP_FILTER_ALL;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	/* enable/disable Tx h/w time stamping */
+	regval = er32(TSYNCTXCTL);
+	regval &= ~E1000_TSYNCTXCTL_ENABLED;
+	regval |= tsync_tx_ctl;
+	ew32(TSYNCTXCTL, regval);
+	if ((er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_ENABLED) !=
+	    (regval & E1000_TSYNCTXCTL_ENABLED)) {
+		e_err("Timesync Tx Control register not set as expected\n");
+		return -EAGAIN;
+	}
+
+	/* enable/disable Rx h/w time stamping */
+	regval = er32(TSYNCRXCTL);
+	regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
+	regval |= tsync_rx_ctl;
+	ew32(TSYNCRXCTL, regval);
+	if ((er32(TSYNCRXCTL) & (E1000_TSYNCRXCTL_ENABLED |
+				 E1000_TSYNCRXCTL_TYPE_MASK)) !=
+	    (regval & (E1000_TSYNCRXCTL_ENABLED |
+		       E1000_TSYNCRXCTL_TYPE_MASK))) {
+		e_err("Timesync Rx Control register not set as expected\n");
+		return -EAGAIN;
+	}
+
+	/* L2: define ethertype filter for time stamped packets */
+	if (is_l2)
+		rxmtrl |= ETH_P_1588;
+
+	/* define which PTP packets get time stamped */
+	ew32(RXMTRL, rxmtrl);
+
+	/* Filter by destination port */
+	if (is_l4) {
+		rxudp = PTP_EV_PORT;
+		cpu_to_be16s(&rxudp);
+	}
+	ew32(RXUDP, rxudp);
+
+	e1e_flush();
+
+	/* Clear TSYNCRXCTL_VALID & TSYNCTXCTL_VALID bit */
+	er32(RXSTMPH);
+	er32(TXSTMPH);
+
+	/* Get and set the System Time Register SYSTIM base frequency */
+	ret_val = e1000e_get_base_timinca(adapter, &regval);
+	if (ret_val)
+		return ret_val;
+	ew32(TIMINCA, regval);
+
+	/* reset the ns time counter */
+	timecounter_init(&adapter->tc, &adapter->cc,
+			 ktime_to_ns(ktime_get_real()));
+
+	return 0;
+}
+
+/**
  * e1000_configure - configure the hardware for Rx and Tx
  * @adapter: private board structure
  **/
@@ -3509,14 +3827,17 @@
 		break;
 	case e1000_pch2lan:
 	case e1000_pch_lpt:
-		fc->high_water = 0x05C20;
-		fc->low_water = 0x05048;
-		fc->pause_time = 0x0650;
 		fc->refresh_time = 0x0400;
-		if (adapter->netdev->mtu > ETH_DATA_LEN) {
-			pba = 14;
-			ew32(PBA, pba);
+
+		if (adapter->netdev->mtu <= ETH_DATA_LEN) {
+			fc->high_water = 0x05C20;
+			fc->low_water = 0x05048;
+			fc->pause_time = 0x0650;
+			break;
 		}
+
+		fc->high_water = ((pba << 10) * 9 / 10) & E1000_FCRTH_RTH;
+		fc->low_water = ((pba << 10) * 8 / 10) & E1000_FCRTL_RTL;
 		break;
 	}
 
@@ -3569,6 +3890,9 @@
 
 	e1000e_reset_adaptive(hw);
 
+	/* initialize systim and reset the ns time counter */
+	e1000e_config_hwtstamp(adapter);
+
 	if (!netif_running(adapter->netdev) &&
 	    !test_bit(__E1000_TESTING, &adapter->state)) {
 		e1000_power_down_phy(adapter);
@@ -3705,6 +4029,24 @@
 }
 
 /**
+ * e1000e_cyclecounter_read - read raw cycle counter (used by time counter)
+ * @cc: cyclecounter structure
+ **/
+static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)
+{
+	struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter,
+						     cc);
+	struct e1000_hw *hw = &adapter->hw;
+	cycle_t systim;
+
+	/* latch SYSTIMH on read of SYSTIML */
+	systim = (cycle_t)er32(SYSTIML);
+	systim |= (cycle_t)er32(SYSTIMH) << 32;
+
+	return systim;
+}
+
+/**
  * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
  * @adapter: board private structure to initialize
  *
@@ -3730,6 +4072,17 @@
 	if (e1000_alloc_queues(adapter))
 		return -ENOMEM;
 
+	/* Setup hardware time stamping cyclecounter */
+	if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
+		adapter->cc.read = e1000e_cyclecounter_read;
+		adapter->cc.mask = CLOCKSOURCE_MASK(64);
+		adapter->cc.mult = 1;
+		/* cc.shift set in e1000e_get_base_tininca() */
+
+		spin_lock_init(&adapter->systim_lock);
+		INIT_WORK(&adapter->tx_hwtstamp_work, e1000e_tx_hwtstamp_work);
+	}
+
 	/* Explicitly disable IRQ since the NIC can be in any state. */
 	e1000_irq_disable(adapter);
 
@@ -3742,7 +4095,7 @@
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
  **/
-static irqreturn_t e1000_intr_msi_test(int irq, void *data)
+static irqreturn_t e1000_intr_msi_test(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3913,10 +4266,8 @@
 		e1000_update_mng_vlan(adapter);
 
 	/* DMA latency requirement to workaround jumbo issue */
-	if (adapter->hw.mac.type == e1000_pch2lan)
-		pm_qos_add_request(&adapter->netdev->pm_qos_req,
-				   PM_QOS_CPU_DMA_LATENCY,
-				   PM_QOS_DEFAULT_VALUE);
+	pm_qos_add_request(&adapter->netdev->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+			   PM_QOS_DEFAULT_VALUE);
 
 	/* before we allocate an interrupt, we must be ready to handle it.
 	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -4024,8 +4375,7 @@
 	    !test_bit(__E1000_TESTING, &adapter->state))
 		e1000e_release_hw_control(adapter);
 
-	if (adapter->hw.mac.type == e1000_pch2lan)
-		pm_qos_remove_request(&adapter->netdev->pm_qos_req);
+	pm_qos_remove_request(&adapter->netdev->pm_qos_req);
 
 	pm_runtime_put_sync(&pdev->dev);
 
@@ -4312,14 +4662,14 @@
 	    (adapter->hw.phy.media_type == e1000_media_type_copper)) {
 		int ret_val;
 
-		ret_val  = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr);
-		ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr);
-		ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise);
-		ret_val |= e1e_rphy(hw, PHY_LP_ABILITY, &phy->lpa);
-		ret_val |= e1e_rphy(hw, PHY_AUTONEG_EXP, &phy->expansion);
-		ret_val |= e1e_rphy(hw, PHY_1000T_CTRL, &phy->ctrl1000);
-		ret_val |= e1e_rphy(hw, PHY_1000T_STATUS, &phy->stat1000);
-		ret_val |= e1e_rphy(hw, PHY_EXT_STATUS, &phy->estatus);
+		ret_val = e1e_rphy(hw, MII_BMCR, &phy->bmcr);
+		ret_val |= e1e_rphy(hw, MII_BMSR, &phy->bmsr);
+		ret_val |= e1e_rphy(hw, MII_ADVERTISE, &phy->advertise);
+		ret_val |= e1e_rphy(hw, MII_LPA, &phy->lpa);
+		ret_val |= e1e_rphy(hw, MII_EXPANSION, &phy->expansion);
+		ret_val |= e1e_rphy(hw, MII_CTRL1000, &phy->ctrl1000);
+		ret_val |= e1e_rphy(hw, MII_STAT1000, &phy->stat1000);
+		ret_val |= e1e_rphy(hw, MII_ESTATUS, &phy->estatus);
 		if (ret_val)
 			e_warn("Error reading PHY register\n");
 	} else {
@@ -4346,9 +4696,8 @@
 	u32 ctrl = er32(CTRL);
 
 	/* Link status message must follow this format for user tools */
-	printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
-		adapter->netdev->name,
-		adapter->link_speed,
+	pr_info("%s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
+		adapter->netdev->name, adapter->link_speed,
 		adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half",
 		(ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE) ? "Rx/Tx" :
 		(ctrl & E1000_CTRL_RFCE) ? "Rx" :
@@ -4401,11 +4750,11 @@
 {
 	/* make sure the receive unit is started */
 	if ((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
-	    (adapter->flags & FLAG_RX_RESTART_NOW)) {
+	    (adapter->flags & FLAG_RESTART_NOW)) {
 		struct e1000_hw *hw = &adapter->hw;
 		u32 rctl = er32(RCTL);
 		ew32(RCTL, rctl | E1000_RCTL_EN);
-		adapter->flags &= ~FLAG_RX_RESTART_NOW;
+		adapter->flags &= ~FLAG_RESTART_NOW;
 	}
 }
 
@@ -4481,6 +4830,13 @@
 						   &adapter->link_speed,
 						   &adapter->link_duplex);
 			e1000_print_link_info(adapter);
+
+			/* check if SmartSpeed worked */
+			e1000e_check_downshift(hw);
+			if (phy->speed_downgraded)
+				netdev_warn(netdev,
+					    "Link Speed was downgraded by SmartSpeed\n");
+
 			/* On supported PHYs, check for duplex mismatch only
 			 * if link has autonegotiated at 10/100 half
 			 */
@@ -4492,9 +4848,9 @@
 			    (adapter->link_duplex == HALF_DUPLEX)) {
 				u16 autoneg_exp;
 
-				e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp);
+				e1e_rphy(hw, MII_EXPANSION, &autoneg_exp);
 
-				if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
+				if (!(autoneg_exp & EXPANSION_NWAY))
 					e_info("Autonegotiated half duplex but link partner cannot autoneg.  Try forcing full duplex if link gets many collisions.\n");
 			}
 
@@ -4567,15 +4923,22 @@
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
 			/* Link status message must follow this format */
-			printk(KERN_INFO "e1000e: %s NIC Link is Down\n",
-			       adapter->netdev->name);
+			pr_info("%s NIC Link is Down\n", adapter->netdev->name);
 			netif_carrier_off(netdev);
 			if (!test_bit(__E1000_DOWN, &adapter->state))
 				mod_timer(&adapter->phy_info_timer,
 					  round_jiffies(jiffies + 2 * HZ));
 
-			if (adapter->flags & FLAG_RX_NEEDS_RESTART)
-				schedule_work(&adapter->reset_task);
+			/* The link is lost so the controller stops DMA.
+			 * If there is queued Tx work that cannot be done
+			 * or if on an 8000ES2LAN which requires a Rx packet
+			 * buffer work-around on link down event, reset the
+			 * controller to flush the Tx/Rx packet buffers.
+			 * (Do the reset outside of interrupt context).
+			 */
+			if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
+			    (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+				adapter->flags |= FLAG_RESTART_NOW;
 			else
 				pm_schedule_suspend(netdev->dev.parent,
 							LINK_TIMEOUT);
@@ -4597,20 +4960,14 @@
 	adapter->gotc_old = adapter->stats.gotc;
 	spin_unlock(&adapter->stats64_lock);
 
-	e1000e_update_adaptive(&adapter->hw);
-
-	if (!netif_carrier_ok(netdev) &&
-	    (e1000_desc_unused(tx_ring) + 1 < tx_ring->count)) {
-		/* We've lost link, so the controller stops DMA,
-		 * but we've got queued Tx work that's never going
-		 * to get done, so reset controller to flush Tx.
-		 * (Do the reset outside of interrupt context).
-		 */
+	if (adapter->flags & FLAG_RESTART_NOW) {
 		schedule_work(&adapter->reset_task);
 		/* return immediately since reset is imminent */
 		return;
 	}
 
+	e1000e_update_adaptive(&adapter->hw);
+
 	/* Simple mode for Interrupt Throttle Rate (ITR) */
 	if (adapter->itr_setting == 4) {
 		/* Symmetric Tx/Rx gets a reduced ITR=2000;
@@ -4647,6 +5004,17 @@
 	if (adapter->flags2 & FLAG2_CHECK_PHY_HANG)
 		e1000e_check_82574_phy_workaround(adapter);
 
+	/* Clear valid timestamp stuck in RXSTMPL/H due to a Rx error */
+	if (adapter->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
+		if ((adapter->flags2 & FLAG2_CHECK_RX_HWTSTAMP) &&
+		    (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) {
+			er32(RXSTMPH);
+			adapter->rx_hwtstamp_cleared++;
+		} else {
+			adapter->flags2 |= FLAG2_CHECK_RX_HWTSTAMP;
+		}
+	}
+
 	/* Reset the timer */
 	if (!test_bit(__E1000_DOWN, &adapter->state))
 		mod_timer(&adapter->watchdog_timer,
@@ -4658,6 +5026,7 @@
 #define E1000_TX_FLAGS_TSO		0x00000004
 #define E1000_TX_FLAGS_IPV4		0x00000008
 #define E1000_TX_FLAGS_NO_FCS		0x00000010
+#define E1000_TX_FLAGS_HWTSTAMP		0x00000020
 #define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
 #define E1000_TX_FLAGS_VLAN_SHIFT	16
 
@@ -4916,6 +5285,11 @@
 	if (unlikely(tx_flags & E1000_TX_FLAGS_NO_FCS))
 		txd_lower &= ~(E1000_TXD_CMD_IFCS);
 
+	if (unlikely(tx_flags & E1000_TX_FLAGS_HWTSTAMP)) {
+		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+		txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+	}
+
 	i = tx_ring->next_to_use;
 
 	do {
@@ -4964,12 +5338,11 @@
 	struct e1000_hw *hw =  &adapter->hw;
 	u16 length, offset;
 
-	if (vlan_tx_tag_present(skb)) {
-		if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
-		    (adapter->hw.mng_cookie.status &
-			E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
-			return 0;
-	}
+	if (vlan_tx_tag_present(skb) &&
+	    !((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
+	      (adapter->hw.mng_cookie.status &
+	       E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
+		return 0;
 
 	if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
 		return 0;
@@ -5140,7 +5513,15 @@
 	count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
 			     nr_frags);
 	if (count) {
-		skb_tx_timestamp(skb);
+		if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+			     !adapter->tx_hwtstamp_skb)) {
+			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+			tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
+			adapter->tx_hwtstamp_skb = skb_get(skb);
+			schedule_work(&adapter->tx_hwtstamp_work);
+		} else {
+			skb_tx_timestamp(skb);
+		}
 
 		netdev_sent_queue(netdev, skb->len);
 		e1000_tx_queue(tx_ring, tx_flags, count);
@@ -5180,10 +5561,9 @@
 	if (test_bit(__E1000_DOWN, &adapter->state))
 		return;
 
-	if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
-	      (adapter->flags & FLAG_RX_RESTART_NOW))) {
+	if (!(adapter->flags & FLAG_RESTART_NOW)) {
 		e1000e_dump(adapter);
-		e_err("Reset adapter\n");
+		e_err("Reset adapter unexpectedly\n");
 	}
 	e1000e_reinit_locked(adapter);
 }
@@ -5369,6 +5749,61 @@
 	return 0;
 }
 
+/**
+ * e1000e_hwtstamp_ioctl - control hardware time stamping
+ * @netdev: network interface device structure
+ * @ifreq: interface request
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware filters.
+ * Not all combinations are supported, in particular event type has to be
+ * specified. Matching the kind of event packet is not supported, with the
+ * exception of "all V2 events regardless of level 2 or 4".
+ **/
+static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct hwtstamp_config config;
+	int ret_val;
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	adapter->hwtstamp_config = config;
+
+	ret_val = e1000e_config_hwtstamp(adapter);
+	if (ret_val)
+		return ret_val;
+
+	config = adapter->hwtstamp_config;
+
+	switch (config.rx_filter) {
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		/* With V2 type filters which specify a Sync or Delay Request,
+		 * Path Delay Request/Response messages are also time stamped
+		 * by hardware so notify the caller the requested packets plus
+		 * some others are time stamped.
+		 */
+		config.rx_filter = HWTSTAMP_FILTER_SOME;
+		break;
+	default:
+		break;
+	}
+
+	return copy_to_user(ifr->ifr_data, &config,
+			    sizeof(config)) ? -EFAULT : 0;
+}
+
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
 	switch (cmd) {
@@ -5376,6 +5811,8 @@
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
 		return e1000_mii_ioctl(netdev, ifr, cmd);
+	case SIOCSHWTSTAMP:
+		return e1000e_hwtstamp_ioctl(netdev, ifr);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -5386,7 +5823,7 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 i, mac_reg;
 	u16 phy_reg, wuc_enable;
-	int retval = 0;
+	int retval;
 
 	/* copy MAC RARs to PHY RARs */
 	e1000_copy_rx_addrs_to_phy_ich8lan(hw);
@@ -5600,14 +6037,21 @@
 #else
 static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 {
+	u16 aspm_ctl = 0;
+
+	if (state & PCIE_LINK_STATE_L0S)
+		aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L0S;
+	if (state & PCIE_LINK_STATE_L1)
+		aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L1;
+
 	/* Both device and parent should have the same ASPM setting.
 	 * Disable ASPM in downstream component first and then upstream.
 	 */
-	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, state);
+	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
 
 	if (pdev->bus->self)
 		pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
-					   state);
+					   aspm_ctl);
 }
 #endif
 static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
@@ -5792,7 +6236,7 @@
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 
-static irqreturn_t e1000_intr_msix(int irq, void *data)
+static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data)
 {
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -5956,7 +6400,6 @@
 	 */
 	if (!(adapter->flags & FLAG_HAS_AMT))
 		e1000e_get_hw_control(adapter);
-
 }
 
 static void e1000_print_device_info(struct e1000_adapter *adapter)
@@ -6114,8 +6557,8 @@
 	}
 
 	err = pci_request_selected_regions_exclusive(pdev,
-	                                  pci_select_bars(pdev, IORESOURCE_MEM),
-	                                  e1000e_driver_name);
+					  pci_select_bars(pdev, IORESOURCE_MEM),
+					  e1000e_driver_name);
 	if (err)
 		goto err_pci_reg;
 
@@ -6274,11 +6717,10 @@
 			"NVM Read Error while reading MAC address\n");
 
 	memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
-	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
-			netdev->perm_addr);
+			netdev->dev_addr);
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -6364,6 +6806,9 @@
 	/* carrier off reporting is important to ethtool even BEFORE open */
 	netif_carrier_off(netdev);
 
+	/* init PTP hardware clock */
+	e1000e_ptp_init(adapter);
+
 	e1000_print_device_info(adapter);
 
 	if (pci_dev_run_wake(pdev))
@@ -6412,6 +6857,8 @@
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	bool down = test_bit(__E1000_DOWN, &adapter->state);
 
+	e1000e_ptp_remove(adapter);
+
 	/* The timers may be rescheduled, so explicitly disable them
 	 * from being rescheduled.
 	 */
@@ -6426,6 +6873,14 @@
 	cancel_work_sync(&adapter->update_phy_task);
 	cancel_work_sync(&adapter->print_hang_task);
 
+	if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
+		cancel_work_sync(&adapter->tx_hwtstamp_work);
+		if (adapter->tx_hwtstamp_skb) {
+			dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+			adapter->tx_hwtstamp_skb = NULL;
+		}
+	}
+
 	if (!(netdev->flags & IFF_UP))
 		e1000_power_down_phy(adapter);
 
@@ -6578,7 +7033,7 @@
 	int ret;
 	pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
 		e1000e_driver_version);
-	pr_info("Copyright(c) 1999 - 2012 Intel Corporation.\n");
+	pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n");
 	ret = pci_register_driver(&e1000_driver);
 
 	return ret;
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index b646880..84fecc2 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -359,7 +359,7 @@
 s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 {
 	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
+	s32 ret_val = -E1000_ERR_NVM;
 	u16 widx = 0;
 
 	/* A check for invalid values:  offset too large, too many words,
@@ -371,16 +371,18 @@
 		return -E1000_ERR_NVM;
 	}
 
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
 	while (widx < words) {
 		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
 
-		ret_val = e1000_ready_nvm_eeprom(hw);
+		ret_val = nvm->ops.acquire(hw);
 		if (ret_val)
-			goto release;
+			return ret_val;
+
+		ret_val = e1000_ready_nvm_eeprom(hw);
+		if (ret_val) {
+			nvm->ops.release(hw);
+			return ret_val;
+		}
 
 		e1000_standby_nvm(hw);
 
@@ -413,12 +415,10 @@
 				break;
 			}
 		}
+		usleep_range(10000, 20000);
+		nvm->ops.release(hw);
 	}
 
-	usleep_range(10000, 20000);
-release:
-	nvm->ops.release(hw);
-
 	return ret_val;
 }
 
@@ -464,8 +464,8 @@
 	if (nvm_data != NVM_PBA_PTR_GUARD) {
 		e_dbg("NVM PBA number is not stored as string\n");
 
-		/* we will need 11 characters to store the PBA */
-		if (pba_num_size < 11) {
+		/* make sure callers buffer is big enough to store the PBA */
+		if (pba_num_size < E1000_PBANUM_LENGTH) {
 			e_dbg("PBA string buffer too small\n");
 			return E1000_ERR_NO_SPACE;
 		}
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.h b/drivers/net/ethernet/intel/e1000e/nvm.h
new file mode 100644
index 0000000..45fc695
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/nvm.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_NVM_H_
+#define _E1000E_NVM_H_
+
+s32 e1000e_acquire_nvm(struct e1000_hw *hw);
+
+s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+				  u32 pba_num_size);
+s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000e_release_nvm(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE	0xDB00
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index 89d536d..98da75d 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -53,8 +53,7 @@
  */
 #define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
 #define E1000_PARAM(X, desc)					\
-	static int X[E1000_MAX_NIC+1]		\
-		= E1000_PARAM_INIT;				\
+	static int X[E1000_MAX_NIC+1] = E1000_PARAM_INIT;	\
 	static unsigned int num_##X;				\
 	module_param_array_named(X, X, int, &num_##X, 0);	\
 	MODULE_PARM_DESC(X, desc);
@@ -447,8 +446,7 @@
 		if (num_SmartPowerDownEnable > bd) {
 			unsigned int spd = SmartPowerDownEnable[bd];
 			e1000_validate_option(&spd, &opt, adapter);
-			if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN)
-			    && spd)
+			if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && spd)
 				adapter->flags |= FLAG_SMART_POWER_DOWN;
 		}
 	}
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 28b38ff..0930c13 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -28,16 +28,12 @@
 
 #include "e1000.h"
 
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
 static s32 e1000_wait_autoneg(struct e1000_hw *hw);
-static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
 static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
 					  u16 *data, bool read, bool page_set);
 static u32 e1000_get_phy_addr_for_hv_page(u32 page);
 static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
-                                          u16 *data, bool read);
+					  u16 *data, bool read);
 
 /* Cable length tables */
 static const u16 e1000_m88_cable_length_table[] = {
@@ -57,48 +53,6 @@
 #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
 		ARRAY_SIZE(e1000_igp_2_cable_length_table)
 
-#define BM_PHY_REG_PAGE(offset) \
-	((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
-#define BM_PHY_REG_NUM(offset) \
-	((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
-	 (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
-		~MAX_PHY_REG_ADDRESS)))
-
-#define HV_INTC_FC_PAGE_START             768
-#define I82578_ADDR_REG                   29
-#define I82577_ADDR_REG                   16
-#define I82577_CFG_REG                    22
-#define I82577_CFG_ASSERT_CRS_ON_TX       (1 << 15)
-#define I82577_CFG_ENABLE_DOWNSHIFT       (3 << 10) /* auto downshift 100/10 */
-#define I82577_CTRL_REG                   23
-
-/* 82577 specific PHY registers */
-#define I82577_PHY_CTRL_2            18
-#define I82577_PHY_STATUS_2          26
-#define I82577_PHY_DIAG_STATUS       31
-
-/* I82577 PHY Status 2 */
-#define I82577_PHY_STATUS2_REV_POLARITY   0x0400
-#define I82577_PHY_STATUS2_MDIX           0x0800
-#define I82577_PHY_STATUS2_SPEED_MASK     0x0300
-#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
-
-/* I82577 PHY Control 2 */
-#define I82577_PHY_CTRL2_MANUAL_MDIX      0x0200
-#define I82577_PHY_CTRL2_AUTO_MDI_MDIX    0x0400
-#define I82577_PHY_CTRL2_MDIX_CFG_MASK    0x0600
-
-/* I82577 PHY Diagnostics Status */
-#define I82577_DSTATUS_CABLE_LENGTH       0x03FC
-#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
-
-/* BM PHY Copper Specific Control 1 */
-#define BM_CS_CTRL1                       16
-
-#define HV_MUX_DATA_CTRL               PHY_REG(776, 16)
-#define HV_MUX_DATA_CTRL_GEN_TO_MAC    0x0400
-#define HV_MUX_DATA_CTRL_FORCE_SPEED   0x0004
-
 /**
  *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
  *  @hw: pointer to the HW structure
@@ -135,13 +89,13 @@
 		return 0;
 
 	while (retry_count < 2) {
-		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+		ret_val = e1e_rphy(hw, MII_PHYSID1, &phy_id);
 		if (ret_val)
 			return ret_val;
 
 		phy->id = (u32)(phy_id << 16);
 		udelay(20);
-		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+		ret_val = e1e_rphy(hw, MII_PHYSID2, &phy_id);
 		if (ret_val)
 			return ret_val;
 
@@ -645,31 +599,31 @@
 	u16 phy_data;
 
 	/* Resolve Master/Slave mode */
-	ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &phy_data);
+	ret_val = e1e_rphy(hw, MII_CTRL1000, &phy_data);
 	if (ret_val)
 		return ret_val;
 
 	/* load defaults for future use */
-	hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ?
-	    ((phy_data & CR_1000T_MS_VALUE) ?
+	hw->phy.original_ms_type = (phy_data & CTL1000_ENABLE_MASTER) ?
+	    ((phy_data & CTL1000_AS_MASTER) ?
 	     e1000_ms_force_master : e1000_ms_force_slave) : e1000_ms_auto;
 
 	switch (hw->phy.ms_type) {
 	case e1000_ms_force_master:
-		phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+		phy_data |= (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
 		break;
 	case e1000_ms_force_slave:
-		phy_data |= CR_1000T_MS_ENABLE;
-		phy_data &= ~(CR_1000T_MS_VALUE);
+		phy_data |= CTL1000_ENABLE_MASTER;
+		phy_data &= ~(CTL1000_AS_MASTER);
 		break;
 	case e1000_ms_auto:
-		phy_data &= ~CR_1000T_MS_ENABLE;
+		phy_data &= ~CTL1000_ENABLE_MASTER;
 		/* fall-through */
 	default:
 		break;
 	}
 
-	return e1e_wphy(hw, PHY_1000T_CTRL, phy_data);
+	return e1e_wphy(hw, MII_CTRL1000, phy_data);
 }
 
 /**
@@ -792,7 +746,7 @@
 			if (ret_val)
 				return ret_val;
 			/* Commit the changes. */
-			ret_val = e1000e_commit_phy(hw);
+			ret_val = phy->ops.commit(hw);
 			if (ret_val) {
 				e_dbg("Error committing the PHY changes\n");
 				return ret_val;
@@ -848,10 +802,12 @@
 	}
 
 	/* Commit the changes. */
-	ret_val = e1000e_commit_phy(hw);
-	if (ret_val) {
-		e_dbg("Error committing the PHY changes\n");
-		return ret_val;
+	if (phy->ops.commit) {
+		ret_val = phy->ops.commit(hw);
+		if (ret_val) {
+			e_dbg("Error committing the PHY changes\n");
+			return ret_val;
+		}
 	}
 
 	if (phy->type == e1000_phy_82578) {
@@ -895,10 +851,12 @@
 	msleep(100);
 
 	/* disable lplu d0 during driver init */
-	ret_val = e1000_set_d0_lplu_state(hw, false);
-	if (ret_val) {
-		e_dbg("Error Disabling LPLU D0\n");
-		return ret_val;
+	if (hw->phy.ops.set_d0_lplu_state) {
+		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+		if (ret_val) {
+			e_dbg("Error Disabling LPLU D0\n");
+			return ret_val;
+		}
 	}
 	/* Configure mdi-mdix settings */
 	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
@@ -943,12 +901,12 @@
 				return ret_val;
 
 			/* Set auto Master/Slave resolution process */
-			ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+			ret_val = e1e_rphy(hw, MII_CTRL1000, &data);
 			if (ret_val)
 				return ret_val;
 
-			data &= ~CR_1000T_MS_ENABLE;
-			ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+			data &= ~CTL1000_ENABLE_MASTER;
+			ret_val = e1e_wphy(hw, MII_CTRL1000, data);
 			if (ret_val)
 				return ret_val;
 		}
@@ -978,13 +936,13 @@
 	phy->autoneg_advertised &= phy->autoneg_mask;
 
 	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
-	ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+	ret_val = e1e_rphy(hw, MII_ADVERTISE, &mii_autoneg_adv_reg);
 	if (ret_val)
 		return ret_val;
 
 	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
 		/* Read the MII 1000Base-T Control Register (Address 9). */
-		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+		ret_val = e1e_rphy(hw, MII_CTRL1000, &mii_1000t_ctrl_reg);
 		if (ret_val)
 			return ret_val;
 	}
@@ -1000,36 +958,35 @@
 	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
 	 * the  1000Base-T Control Register (Address 9).
 	 */
-	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
-				 NWAY_AR_100TX_HD_CAPS |
-				 NWAY_AR_10T_FD_CAPS   |
-				 NWAY_AR_10T_HD_CAPS);
-	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+	mii_autoneg_adv_reg &= ~(ADVERTISE_100FULL |
+				 ADVERTISE_100HALF |
+				 ADVERTISE_10FULL | ADVERTISE_10HALF);
+	mii_1000t_ctrl_reg &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
 
 	e_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
 
 	/* Do we want to advertise 10 Mb Half Duplex? */
 	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
 		e_dbg("Advertise 10mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+		mii_autoneg_adv_reg |= ADVERTISE_10HALF;
 	}
 
 	/* Do we want to advertise 10 Mb Full Duplex? */
 	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
 		e_dbg("Advertise 10mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+		mii_autoneg_adv_reg |= ADVERTISE_10FULL;
 	}
 
 	/* Do we want to advertise 100 Mb Half Duplex? */
 	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
 		e_dbg("Advertise 100mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+		mii_autoneg_adv_reg |= ADVERTISE_100HALF;
 	}
 
 	/* Do we want to advertise 100 Mb Full Duplex? */
 	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
 		e_dbg("Advertise 100mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+		mii_autoneg_adv_reg |= ADVERTISE_100FULL;
 	}
 
 	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
@@ -1039,14 +996,14 @@
 	/* Do we want to advertise 1000 Mb Full Duplex? */
 	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
 		e_dbg("Advertise 1000mb Full duplex\n");
-		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+		mii_1000t_ctrl_reg |= ADVERTISE_1000FULL;
 	}
 
 	/* Check for a software override of the flow control settings, and
 	 * setup the PHY advertisement registers accordingly.  If
 	 * auto-negotiation is enabled, then software will have to set the
 	 * "PAUSE" bits to the correct value in the Auto-Negotiation
-	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * Advertisement Register (MII_ADVERTISE) and re-start auto-
 	 * negotiation.
 	 *
 	 * The possible values of the "fc" parameter are:
@@ -1064,7 +1021,8 @@
 		/* Flow control (Rx & Tx) is completely disabled by a
 		 * software over-ride.
 		 */
-		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		mii_autoneg_adv_reg &=
+		    ~(ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
 		break;
 	case e1000_fc_rx_pause:
 		/* Rx Flow control is enabled, and Tx Flow control is
@@ -1076,34 +1034,36 @@
 		 * (in e1000e_config_fc_after_link_up) we will disable the
 		 * hw's ability to send PAUSE frames.
 		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		mii_autoneg_adv_reg |=
+		    (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
 		break;
 	case e1000_fc_tx_pause:
 		/* Tx Flow control is enabled, and Rx Flow control is
 		 * disabled, by a software over-ride.
 		 */
-		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
-		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		mii_autoneg_adv_reg |= ADVERTISE_PAUSE_ASYM;
+		mii_autoneg_adv_reg &= ~ADVERTISE_PAUSE_CAP;
 		break;
 	case e1000_fc_full:
 		/* Flow control (both Rx and Tx) is enabled by a software
 		 * over-ride.
 		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		mii_autoneg_adv_reg |=
+		    (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
 		break;
 	default:
 		e_dbg("Flow control param set incorrectly\n");
 		return -E1000_ERR_CONFIG;
 	}
 
-	ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+	ret_val = e1e_wphy(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
 	if (ret_val)
 		return ret_val;
 
 	e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
 	if (phy->autoneg_mask & ADVERTISE_1000_FULL)
-		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+		ret_val = e1e_wphy(hw, MII_CTRL1000, mii_1000t_ctrl_reg);
 
 	return ret_val;
 }
@@ -1145,12 +1105,12 @@
 	/* Restart auto-negotiation by setting the Auto Neg Enable bit and
 	 * the Auto Neg Restart bit in the PHY control register.
 	 */
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+	ret_val = e1e_rphy(hw, MII_BMCR, &phy_ctrl);
 	if (ret_val)
 		return ret_val;
 
-	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+	phy_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	ret_val = e1e_wphy(hw, MII_BMCR, phy_ctrl);
 	if (ret_val)
 		return ret_val;
 
@@ -1196,7 +1156,7 @@
 		 * depending on user settings.
 		 */
 		e_dbg("Forcing Speed and Duplex\n");
-		ret_val = e1000_phy_force_speed_duplex(hw);
+		ret_val = hw->phy.ops.force_speed_duplex(hw);
 		if (ret_val) {
 			e_dbg("Error Forcing Speed and Duplex\n");
 			return ret_val;
@@ -1237,13 +1197,13 @@
 	u16 phy_data;
 	bool link;
 
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
 	if (ret_val)
 		return ret_val;
 
 	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
 
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
 	if (ret_val)
 		return ret_val;
 
@@ -1315,20 +1275,22 @@
 
 	e_dbg("M88E1000 PSCR: %X\n", phy_data);
 
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
 	if (ret_val)
 		return ret_val;
 
 	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
 
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
 	if (ret_val)
 		return ret_val;
 
 	/* Reset the phy to commit changes. */
-	ret_val = e1000e_commit_phy(hw);
-	if (ret_val)
-		return ret_val;
+	if (hw->phy.ops.commit) {
+		ret_val = hw->phy.ops.commit(hw);
+		if (ret_val)
+			return ret_val;
+	}
 
 	if (phy->autoneg_wait_to_complete) {
 		e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
@@ -1406,13 +1368,13 @@
 	u16 data;
 	bool link;
 
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+	ret_val = e1e_rphy(hw, MII_BMCR, &data);
 	if (ret_val)
 		return ret_val;
 
 	e1000e_phy_force_speed_duplex_setup(hw, &data);
 
-	ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+	ret_val = e1e_wphy(hw, MII_BMCR, data);
 	if (ret_val)
 		return ret_val;
 
@@ -1456,13 +1418,13 @@
 /**
  *  e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
  *  @hw: pointer to the HW structure
- *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *  @phy_ctrl: pointer to current value of MII_BMCR
  *
  *  Forces speed and duplex on the PHY by doing the following: disable flow
  *  control, force speed/duplex on the MAC, disable auto speed detection,
  *  disable auto-negotiation, configure duplex, configure speed, configure
  *  the collision distance, write configuration to CTRL register.  The
- *  caller must write to the PHY_CONTROL register for these settings to
+ *  caller must write to the MII_BMCR register for these settings to
  *  take affect.
  **/
 void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
@@ -1482,29 +1444,28 @@
 	ctrl &= ~E1000_CTRL_ASDE;
 
 	/* Disable autoneg on the phy */
-	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+	*phy_ctrl &= ~BMCR_ANENABLE;
 
 	/* Forcing Full or Half Duplex? */
 	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
 		ctrl &= ~E1000_CTRL_FD;
-		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		*phy_ctrl &= ~BMCR_FULLDPLX;
 		e_dbg("Half Duplex\n");
 	} else {
 		ctrl |= E1000_CTRL_FD;
-		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		*phy_ctrl |= BMCR_FULLDPLX;
 		e_dbg("Full Duplex\n");
 	}
 
 	/* Forcing 10mb or 100mb? */
 	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
 		ctrl |= E1000_CTRL_SPD_100;
-		*phy_ctrl |= MII_CR_SPEED_100;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		*phy_ctrl |= BMCR_SPEED100;
+		*phy_ctrl &= ~BMCR_SPEED1000;
 		e_dbg("Forcing 100mb\n");
 	} else {
 		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-		*phy_ctrl |= MII_CR_SPEED_10;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		*phy_ctrl &= ~(BMCR_SPEED1000 | BMCR_SPEED100);
 		e_dbg("Forcing 10mb\n");
 	}
 
@@ -1745,13 +1706,13 @@
 
 	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
 	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
 		if (ret_val)
 			break;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
 		if (ret_val)
 			break;
-		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+		if (phy_status & BMSR_ANEGCOMPLETE)
 			break;
 		msleep(100);
 	}
@@ -1778,21 +1739,21 @@
 	u16 i, phy_status;
 
 	for (i = 0; i < iterations; i++) {
-		/* Some PHYs require the PHY_STATUS register to be read
+		/* Some PHYs require the MII_BMSR register to be read
 		 * twice due to the link bit being sticky.  No harm doing
 		 * it across the board.
 		 */
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
 		if (ret_val)
 			/* If the first read fails, another entity may have
 			 * ownership of the resources, wait and try again to
 			 * see if they have relinquished the resources yet.
 			 */
 			udelay(usec_interval);
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
 		if (ret_val)
 			break;
-		if (phy_status & MII_SR_LINK_STATUS)
+		if (phy_status & BMSR_LSTATUS)
 			break;
 		if (usec_interval >= 1000)
 			mdelay(usec_interval/1000);
@@ -1962,21 +1923,19 @@
 	phy->is_mdix = !!(phy_data & M88E1000_PSSR_MDIX);
 
 	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
-		ret_val = e1000_get_cable_length(hw);
+		ret_val = hw->phy.ops.get_cable_length(hw);
 		if (ret_val)
 			return ret_val;
 
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+		ret_val = e1e_rphy(hw, MII_STAT1000, &phy_data);
 		if (ret_val)
 			return ret_val;
 
-		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
-				? e1000_1000t_rx_status_ok
-				: e1000_1000t_rx_status_not_ok;
+		phy->local_rx = (phy_data & LPA_1000LOCALRXOK)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
 
-		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
-				 ? e1000_1000t_rx_status_ok
-				 : e1000_1000t_rx_status_not_ok;
+		phy->remote_rx = (phy_data & LPA_1000REMRXOK)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
 	} else {
 		/* Set values to "undefined" */
 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
@@ -2026,21 +1985,19 @@
 
 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		ret_val = e1000_get_cable_length(hw);
+		ret_val = phy->ops.get_cable_length(hw);
 		if (ret_val)
 			return ret_val;
 
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+		ret_val = e1e_rphy(hw, MII_STAT1000, &data);
 		if (ret_val)
 			return ret_val;
 
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-				? e1000_1000t_rx_status_ok
-				: e1000_1000t_rx_status_not_ok;
+		phy->local_rx = (data & LPA_1000LOCALRXOK)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
 
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-				 ? e1000_1000t_rx_status_ok
-				 : e1000_1000t_rx_status_not_ok;
+		phy->remote_rx = (data & LPA_1000REMRXOK)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
 	} else {
 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
 		phy->local_rx = e1000_1000t_rx_status_undefined;
@@ -2114,12 +2071,12 @@
 	s32 ret_val;
 	u16 phy_ctrl;
 
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+	ret_val = e1e_rphy(hw, MII_BMCR, &phy_ctrl);
 	if (ret_val)
 		return ret_val;
 
-	phy_ctrl |= MII_CR_RESET;
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+	phy_ctrl |= BMCR_RESET;
+	ret_val = e1e_wphy(hw, MII_BMCR, phy_ctrl);
 	if (ret_val)
 		return ret_val;
 
@@ -2166,17 +2123,17 @@
 
 	phy->ops.release(hw);
 
-	return e1000_get_phy_cfg_done(hw);
+	return phy->ops.get_cfg_done(hw);
 }
 
 /**
- *  e1000e_get_cfg_done - Generic configuration done
+ *  e1000e_get_cfg_done_generic - Generic configuration done
  *  @hw: pointer to the HW structure
  *
  *  Generic function to wait 10 milli-seconds for configuration to complete
  *  and return success.
  **/
-s32 e1000e_get_cfg_done(struct e1000_hw *hw)
+s32 e1000e_get_cfg_done_generic(struct e1000_hw __always_unused *hw)
 {
 	mdelay(10);
 
@@ -2266,38 +2223,6 @@
 	return 0;
 }
 
-/* Internal function pointers */
-
-/**
- *  e1000_get_phy_cfg_done - Generic PHY configuration done
- *  @hw: pointer to the HW structure
- *
- *  Return success if silicon family did not implement a family specific
- *  get_cfg_done function.
- **/
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_cfg_done)
-		return hw->phy.ops.get_cfg_done(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
- *  @hw: pointer to the HW structure
- *
- *  When the silicon family has not implemented a forced speed/duplex
- *  function for the PHY, simply return 0.
- **/
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.force_speed_duplex)
-		return hw->phy.ops.force_speed_duplex(hw);
-
-	return 0;
-}
-
 /**
  *  e1000e_get_phy_type_from_id - Get PHY type from id
  *  @phy_id: phy_id read from the phy
@@ -2549,7 +2474,6 @@
 	hw->phy.addr = 1;
 
 	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-
 		/* Page is shifted left, PHY expects (page x 32) */
 		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
 						    page);
@@ -2672,7 +2596,7 @@
  **/
 s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
 {
-	s32 ret_val = 0;
+	s32 ret_val;
 
 	/* Select Port Control Registers page */
 	ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
@@ -2781,9 +2705,9 @@
 	u16 mii_reg = 0;
 
 	/* The PHY will retain its settings across a power down/up cycle */
-	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
-	mii_reg &= ~MII_CR_POWER_DOWN;
-	e1e_wphy(hw, PHY_CONTROL, mii_reg);
+	e1e_rphy(hw, MII_BMCR, &mii_reg);
+	mii_reg &= ~BMCR_PDOWN;
+	e1e_wphy(hw, MII_BMCR, mii_reg);
 }
 
 /**
@@ -2799,50 +2723,13 @@
 	u16 mii_reg = 0;
 
 	/* The PHY will retain its settings across a power down/up cycle */
-	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
-	mii_reg |= MII_CR_POWER_DOWN;
-	e1e_wphy(hw, PHY_CONTROL, mii_reg);
+	e1e_rphy(hw, MII_BMCR, &mii_reg);
+	mii_reg |= BMCR_PDOWN;
+	e1e_wphy(hw, MII_BMCR, mii_reg);
 	usleep_range(1000, 2000);
 }
 
 /**
- *  e1000e_commit_phy - Soft PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a soft PHY reset on those that apply. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 e1000e_commit_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.commit)
-		return hw->phy.ops.commit(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_set_d0_lplu_state - Sets low power link up state for D0
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D0
- *  and SmartSpeed is disabled when active is true, else clear lplu for D0
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
-{
-	if (hw->phy.ops.set_d0_lplu_state)
-		return hw->phy.ops.set_d0_lplu_state(hw, active);
-
-	return 0;
-}
-
-/**
  *  __e1000_read_phy_reg_hv -  Read HV PHY register
  *  @hw: pointer to the HW structure
  *  @offset: register offset to be read
@@ -3104,8 +2991,8 @@
                                           u16 *data, bool read)
 {
 	s32 ret_val;
-	u32 addr_reg = 0;
-	u32 data_reg = 0;
+	u32 addr_reg;
+	u32 data_reg;
 
 	/* This takes care of the difference with desktop vs mobile phy */
 	addr_reg = (hw->phy.type == e1000_phy_82578) ?
@@ -3154,8 +3041,8 @@
 		return 0;
 
 	/* Do not apply workaround if in PHY loopback bit 14 set */
-	e1e_rphy(hw, PHY_CONTROL, &data);
-	if (data & PHY_CONTROL_LB)
+	e1e_rphy(hw, MII_BMCR, &data);
+	if (data & BMCR_LOOPBACK)
 		return 0;
 
 	/* check if link is up and at 1Gbps */
@@ -3173,8 +3060,9 @@
 	msleep(200);
 
 	/* flush the packets in the fifo buffer */
-	ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL, HV_MUX_DATA_CTRL_GEN_TO_MAC |
-			   HV_MUX_DATA_CTRL_FORCE_SPEED);
+	ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
+			   (HV_MUX_DATA_CTRL_GEN_TO_MAC |
+			    HV_MUX_DATA_CTRL_FORCE_SPEED));
 	if (ret_val)
 		return ret_val;
 
@@ -3218,13 +3106,13 @@
 	u16 phy_data;
 	bool link;
 
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
 	if (ret_val)
 		return ret_val;
 
 	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
 
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
 	if (ret_val)
 		return ret_val;
 
@@ -3292,17 +3180,15 @@
 		if (ret_val)
 			return ret_val;
 
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+		ret_val = e1e_rphy(hw, MII_STAT1000, &data);
 		if (ret_val)
 			return ret_val;
 
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
+		phy->local_rx = (data & LPA_1000LOCALRXOK)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
 
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
+		phy->remote_rx = (data & LPA_1000REMRXOK)
+		    ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
 	} else {
 		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
 		phy->local_rx = e1000_1000t_rx_status_undefined;
@@ -3333,7 +3219,7 @@
 	         I82577_DSTATUS_CABLE_LENGTH_SHIFT;
 
 	if (length == E1000_CABLE_LENGTH_UNDEFINED)
-		ret_val = -E1000_ERR_PHY;
+		return -E1000_ERR_PHY;
 
 	phy->cable_length = length;
 
diff --git a/drivers/net/ethernet/intel/e1000e/phy.h b/drivers/net/ethernet/intel/e1000e/phy.h
new file mode 100644
index 0000000..f4f71b9
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/phy.h
@@ -0,0 +1,242 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_PHY_H_
+#define _E1000E_PHY_H_
+
+s32 e1000e_check_downshift(struct e1000_hw *hw);
+s32 e1000_check_polarity_m88(struct e1000_hw *hw);
+s32 e1000_check_polarity_igp(struct e1000_hw *hw);
+s32 e1000_check_polarity_ife(struct e1000_hw *hw);
+s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
+s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
+s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+s32 e1000e_get_cfg_done_generic(struct e1000_hw *hw);
+s32 e1000e_get_phy_id(struct e1000_hw *hw);
+s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
+s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
+s32 e1000_get_phy_info_ife(struct e1000_hw *hw);
+s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_set_page_igp(struct e1000_hw *hw, u16 page);
+s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32 e1000e_setup_copper_link(struct e1000_hw *hw);
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+				u32 usec_interval, bool *success);
+s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+s32 e1000e_determine_phy_address(struct e1000_hw *hw);
+s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg);
+s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg);
+s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
+void e1000_power_up_phy_copper(struct e1000_hw *hw);
+void e1000_power_down_phy_copper(struct e1000_hw *hw);
+s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_phy_reg_page_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_phy_reg_page_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
+s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
+s32 e1000_check_polarity_82577(struct e1000_hw *hw);
+s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
+
+#define E1000_MAX_PHY_ADDR		8
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG	0x10	/* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS	0x11	/* Status */
+#define IGP01E1000_PHY_PORT_CTRL	0x12	/* Control */
+#define IGP01E1000_PHY_LINK_HEALTH	0x13	/* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT	0x19	/* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT	0x1F	/* Page Select */
+#define BM_PHY_PAGE_SELECT		22	/* Page Select for BM */
+#define IGP_PAGE_SHIFT			5
+#define PHY_REG_MASK			0x1F
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE		769
+#define BM_WUC_PAGE			800
+#define BM_WUC_ADDRESS_OPCODE		0x11
+#define BM_WUC_DATA_OPCODE		0x12
+#define BM_WUC_ENABLE_PAGE		BM_PORT_CTRL_PAGE
+#define BM_WUC_ENABLE_REG		17
+#define BM_WUC_ENABLE_BIT		(1 << 2)
+#define BM_WUC_HOST_WU_BIT		(1 << 4)
+#define BM_WUC_ME_WU_BIT		(1 << 5)
+
+#define PHY_UPPER_SHIFT			21
+#define BM_PHY_REG(page, reg) \
+	(((reg) & MAX_PHY_REG_ADDRESS) |\
+	 (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+	 (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define BM_PHY_REG_PAGE(offset) \
+	((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+	((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+	 (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+		~MAX_PHY_REG_ADDRESS)))
+
+#define HV_INTC_FC_PAGE_START		768
+#define I82578_ADDR_REG			29
+#define I82577_ADDR_REG			16
+#define I82577_CFG_REG			22
+#define I82577_CFG_ASSERT_CRS_ON_TX	(1 << 15)
+#define I82577_CFG_ENABLE_DOWNSHIFT	(3 << 10)	/* auto downshift */
+#define I82577_CTRL_REG			23
+
+/* 82577 specific PHY registers */
+#define I82577_PHY_CTRL_2		18
+#define I82577_PHY_LBK_CTRL		19
+#define I82577_PHY_STATUS_2		26
+#define I82577_PHY_DIAG_STATUS		31
+
+/* I82577 PHY Status 2 */
+#define I82577_PHY_STATUS2_REV_POLARITY		0x0400
+#define I82577_PHY_STATUS2_MDIX			0x0800
+#define I82577_PHY_STATUS2_SPEED_MASK		0x0300
+#define I82577_PHY_STATUS2_SPEED_1000MBPS	0x0200
+
+/* I82577 PHY Control 2 */
+#define I82577_PHY_CTRL2_MANUAL_MDIX		0x0200
+#define I82577_PHY_CTRL2_AUTO_MDI_MDIX		0x0400
+#define I82577_PHY_CTRL2_MDIX_CFG_MASK		0x0600
+
+/* I82577 PHY Diagnostics Status */
+#define I82577_DSTATUS_CABLE_LENGTH		0x03FC
+#define I82577_DSTATUS_CABLE_LENGTH_SHIFT	2
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1			16
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS			17
+#define BM_CS_STATUS_LINK_UP		0x0400
+#define BM_CS_STATUS_RESOLVED		0x0800
+#define BM_CS_STATUS_SPEED_MASK		0xC000
+#define BM_CS_STATUS_SPEED_1000		0x8000
+
+/* 82577 Mobile Phy Status Register */
+#define HV_M_STATUS			26
+#define HV_M_STATUS_AUTONEG_COMPLETE	0x1000
+#define HV_M_STATUS_SPEED_MASK		0x0300
+#define HV_M_STATUS_SPEED_1000		0x0200
+#define HV_M_STATUS_LINK_UP		0x0040
+
+#define IGP01E1000_PHY_PCS_INIT_REG	0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK	0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX	0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX	0x2000	/* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED	0x0080
+
+#define IGP02E1000_PM_SPD		0x0001	/* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU		0x0002	/* For D0a states */
+#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		0x0800
+#define IGP01E1000_PSSR_SPEED_MASK	0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS	0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM	4
+#define IGP02E1000_PHY_AGC_A		0x11B1
+#define IGP02E1000_PHY_AGC_B		0x12B1
+#define IGP02E1000_PHY_AGC_C		0x14B1
+#define IGP02E1000_PHY_AGC_D		0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT	9	/* Course=15:13, Fine=12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK	0x7F
+#define IGP02E1000_AGC_RANGE		15
+
+#define E1000_CABLE_LENGTH_UNDEFINED	0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET	0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT	16
+#define E1000_KMRNCTRLSTA_REN		0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET	0x1	/* Kumeran Control */
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3	/* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS	0x4	/* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM	0x9	/* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_IBIST_DISABLE	0x0200	/* Kumeran IBIST Disable */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000	/* Nearend Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG	0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE	0x0002	/* enable K1 */
+#define E1000_KMRNCTRLSTA_HD_CTRL	0x10	/* Kumeran HD Control */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
+#define IFE_PHY_SPECIAL_CONTROL		0x11	/* 100BaseTx PHY Special Ctrl */
+#define IFE_PHY_SPECIAL_CONTROL_LED	0x1B	/* PHY Special and LED Ctrl */
+#define IFE_PHY_MDIX_CONTROL		0x1C	/* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED	0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE	0x0010
+#define IFE_PSC_FORCE_POLARITY		0x0020
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE		0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF		0x0006	/* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON		0x0007	/* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS		0x0020	/* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX		0x0040	/* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX		0x0080	/* 1=enable auto, 0=disable */
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
new file mode 100644
index 0000000..b477fa5
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -0,0 +1,277 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* PTP 1588 Hardware Clock (PHC)
+ * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
+ * Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
+ */
+
+#include "e1000.h"
+
+/**
+ * e1000e_phc_adjfreq - adjust the frequency of the hardware clock
+ * @ptp: ptp clock structure
+ * @delta: Desired frequency change in parts per billion
+ *
+ * Adjust the frequency of the PHC cycle counter by the indicated delta from
+ * the base frequency.
+ **/
+static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
+{
+	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+						     ptp_clock_info);
+	struct e1000_hw *hw = &adapter->hw;
+	bool neg_adj = false;
+	u64 adjustment;
+	u32 timinca, incvalue;
+	s32 ret_val;
+
+	if ((delta > ptp->max_adj) || (delta <= -1000000000))
+		return -EINVAL;
+
+	if (delta < 0) {
+		neg_adj = true;
+		delta = -delta;
+	}
+
+	/* Get the System Time Register SYSTIM base frequency */
+	ret_val = e1000e_get_base_timinca(adapter, &timinca);
+	if (ret_val)
+		return ret_val;
+
+	incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
+
+	adjustment = incvalue;
+	adjustment *= delta;
+	adjustment = div_u64(adjustment, 1000000000);
+
+	incvalue = neg_adj ? (incvalue - adjustment) : (incvalue + adjustment);
+
+	timinca &= ~E1000_TIMINCA_INCVALUE_MASK;
+	timinca |= incvalue;
+
+	ew32(TIMINCA, timinca);
+
+	return 0;
+}
+
+/**
+ * e1000e_phc_adjtime - Shift the time of the hardware clock
+ * @ptp: ptp clock structure
+ * @delta: Desired change in nanoseconds
+ *
+ * Adjust the timer by resetting the timecounter structure.
+ **/
+static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+						     ptp_clock_info);
+	unsigned long flags;
+	s64 now;
+
+	spin_lock_irqsave(&adapter->systim_lock, flags);
+	now = timecounter_read(&adapter->tc);
+	now += delta;
+	timecounter_init(&adapter->tc, &adapter->cc, now);
+	spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+	return 0;
+}
+
+/**
+ * e1000e_phc_gettime - Reads the current time from the hardware clock
+ * @ptp: ptp clock structure
+ * @ts: timespec structure to hold the current time value
+ *
+ * Read the timecounter and return the correct value in ns after converting
+ * it into a struct timespec.
+ **/
+static int e1000e_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+						     ptp_clock_info);
+	unsigned long flags;
+	u32 remainder;
+	u64 ns;
+
+	spin_lock_irqsave(&adapter->systim_lock, flags);
+	ns = timecounter_read(&adapter->tc);
+	spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+	ts->tv_sec = div_u64_rem(ns, NSEC_PER_SEC, &remainder);
+	ts->tv_nsec = remainder;
+
+	return 0;
+}
+
+/**
+ * e1000e_phc_settime - Set the current time on the hardware clock
+ * @ptp: ptp clock structure
+ * @ts: timespec containing the new time for the cycle counter
+ *
+ * Reset the timecounter to use a new base value instead of the kernel
+ * wall timer value.
+ **/
+static int e1000e_phc_settime(struct ptp_clock_info *ptp,
+			      const struct timespec *ts)
+{
+	struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+						     ptp_clock_info);
+	unsigned long flags;
+	u64 ns;
+
+	ns = ts->tv_sec * NSEC_PER_SEC;
+	ns += ts->tv_nsec;
+
+	/* reset the timecounter */
+	spin_lock_irqsave(&adapter->systim_lock, flags);
+	timecounter_init(&adapter->tc, &adapter->cc, ns);
+	spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+	return 0;
+}
+
+/**
+ * e1000e_phc_enable - enable or disable an ancillary feature
+ * @ptp: ptp clock structure
+ * @request: Desired resource to enable or disable
+ * @on: Caller passes one to enable or zero to disable
+ *
+ * Enable (or disable) ancillary features of the PHC subsystem.
+ * Currently, no ancillary features are supported.
+ **/
+static int e1000e_phc_enable(struct ptp_clock_info __always_unused *ptp,
+			     struct ptp_clock_request __always_unused *request,
+			     int __always_unused on)
+{
+	return -EOPNOTSUPP;
+}
+
+static void e1000e_systim_overflow_work(struct work_struct *work)
+{
+	struct e1000_adapter *adapter = container_of(work, struct e1000_adapter,
+						     systim_overflow_work.work);
+	struct e1000_hw *hw = &adapter->hw;
+	struct timespec ts;
+
+	adapter->ptp_clock_info.gettime(&adapter->ptp_clock_info, &ts);
+
+	e_dbg("SYSTIM overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
+
+	schedule_delayed_work(&adapter->systim_overflow_work,
+			      E1000_SYSTIM_OVERFLOW_PERIOD);
+}
+
+static const struct ptp_clock_info e1000e_ptp_clock_info = {
+	.owner		= THIS_MODULE,
+	.n_alarm	= 0,
+	.n_ext_ts	= 0,
+	.n_per_out	= 0,
+	.pps		= 0,
+	.adjfreq	= e1000e_phc_adjfreq,
+	.adjtime	= e1000e_phc_adjtime,
+	.gettime	= e1000e_phc_gettime,
+	.settime	= e1000e_phc_settime,
+	.enable		= e1000e_phc_enable,
+};
+
+/**
+ * e1000e_ptp_init - initialize PTP for devices which support it
+ * @adapter: board private structure
+ *
+ * This function performs the required steps for enabling PTP support.
+ * If PTP support has already been loaded it simply calls the cyclecounter
+ * init routine and exits.
+ **/
+void e1000e_ptp_init(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	adapter->ptp_clock = NULL;
+
+	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+		return;
+
+	adapter->ptp_clock_info = e1000e_ptp_clock_info;
+
+	snprintf(adapter->ptp_clock_info.name,
+		 sizeof(adapter->ptp_clock_info.name), "%pm",
+		 adapter->netdev->perm_addr);
+
+	switch (hw->mac.type) {
+	case e1000_pch2lan:
+	case e1000_pch_lpt:
+		if ((hw->mac.type != e1000_pch_lpt) ||
+		    (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+			adapter->ptp_clock_info.max_adj = 24000000 - 1;
+			break;
+		}
+		/* fall-through */
+	case e1000_82574:
+	case e1000_82583:
+		adapter->ptp_clock_info.max_adj = 600000000 - 1;
+		break;
+	default:
+		break;
+	}
+
+	INIT_DELAYED_WORK(&adapter->systim_overflow_work,
+			  e1000e_systim_overflow_work);
+
+	schedule_delayed_work(&adapter->systim_overflow_work,
+			      E1000_SYSTIM_OVERFLOW_PERIOD);
+
+	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
+						&adapter->pdev->dev);
+	if (IS_ERR(adapter->ptp_clock)) {
+		adapter->ptp_clock = NULL;
+		e_err("ptp_clock_register failed\n");
+	} else {
+		e_info("registered PHC clock\n");
+	}
+}
+
+/**
+ * e1000e_ptp_remove - disable PTP device and stop the overflow check
+ * @adapter: board private structure
+ *
+ * Stop the PTP support, and cancel the delayed work.
+ **/
+void e1000e_ptp_remove(struct e1000_adapter *adapter)
+{
+	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+		return;
+
+	cancel_delayed_work_sync(&adapter->systim_overflow_work);
+
+	if (adapter->ptp_clock) {
+		ptp_clock_unregister(adapter->ptp_clock);
+		adapter->ptp_clock = NULL;
+		e_info("removed PHC\n");
+	}
+}
diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h
new file mode 100644
index 0000000..794fe14
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/regs.h
@@ -0,0 +1,252 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_REGS_H_
+#define _E1000E_REGS_H_
+
+#define E1000_CTRL	0x00000	/* Device Control - RW */
+#define E1000_STATUS	0x00008	/* Device Status - RO */
+#define E1000_EECD	0x00010	/* EEPROM/Flash Control - RW */
+#define E1000_EERD	0x00014	/* EEPROM Read - RW */
+#define E1000_CTRL_EXT	0x00018	/* Extended Device Control - RW */
+#define E1000_FLA	0x0001C	/* Flash Access - RW */
+#define E1000_MDIC	0x00020	/* MDI Control - RW */
+#define E1000_SCTL	0x00024	/* SerDes Control - RW */
+#define E1000_FCAL	0x00028	/* Flow Control Address Low - RW */
+#define E1000_FCAH	0x0002C	/* Flow Control Address High -RW */
+#define E1000_FEXTNVM	0x00028	/* Future Extended NVM - RW */
+#define E1000_FEXTNVM3	0x0003C	/* Future Extended NVM 3 - RW */
+#define E1000_FEXTNVM4	0x00024	/* Future Extended NVM 4 - RW */
+#define E1000_FEXTNVM7	0x000E4	/* Future Extended NVM 7 - RW */
+#define E1000_FCT	0x00030	/* Flow Control Type - RW */
+#define E1000_VET	0x00038	/* VLAN Ether Type - RW */
+#define E1000_ICR	0x000C0	/* Interrupt Cause Read - R/clr */
+#define E1000_ITR	0x000C4	/* Interrupt Throttling Rate - RW */
+#define E1000_ICS	0x000C8	/* Interrupt Cause Set - WO */
+#define E1000_IMS	0x000D0	/* Interrupt Mask Set - RW */
+#define E1000_IMC	0x000D8	/* Interrupt Mask Clear - WO */
+#define E1000_IAM	0x000E0	/* Interrupt Acknowledge Auto Mask */
+#define E1000_IVAR	0x000E4	/* Interrupt Vector Allocation Register - RW */
+#define E1000_SVCR	0x000F0
+#define E1000_SVT	0x000F4
+#define E1000_LPIC	0x000FC	/* Low Power IDLE control */
+#define E1000_RCTL	0x00100	/* Rx Control - RW */
+#define E1000_FCTTV	0x00170	/* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW	0x00178	/* Tx Configuration Word - RW */
+#define E1000_RXCW	0x00180	/* Rx Configuration Word - RO */
+#define E1000_PBA_ECC	0x01100	/* PBA ECC Register */
+#define E1000_TCTL	0x00400	/* Tx Control - RW */
+#define E1000_TCTL_EXT	0x00404	/* Extended Tx Control - RW */
+#define E1000_TIPG	0x00410	/* Tx Inter-packet gap -RW */
+#define E1000_AIT	0x00458	/* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL	0x00E00	/* LED Control - RW */
+#define E1000_EXTCNF_CTRL	0x00F00	/* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE	0x00F08	/* Extended Configuration Size */
+#define E1000_PHY_CTRL	0x00F10	/* PHY Control Register in CSR */
+#define E1000_POEMB	E1000_PHY_CTRL	/* PHY OEM Bits */
+#define E1000_PBA	0x01000	/* Packet Buffer Allocation - RW */
+#define E1000_PBS	0x01008	/* Packet Buffer Size */
+#define E1000_PBECCSTS	0x0100C	/* Packet Buffer ECC Status - RW */
+#define E1000_EEMNGCTL	0x01010	/* MNG EEprom Control */
+#define E1000_EEWR	0x0102C	/* EEPROM Write Register - RW */
+#define E1000_FLOP	0x0103C	/* FLASH Opcode Register */
+#define E1000_ERT	0x02008	/* Early Rx Threshold - RW */
+#define E1000_FCRTL	0x02160	/* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH	0x02168	/* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL	0x02170	/* Packet Split Receive Control - RW */
+#define E1000_RDFH	0x02410	/* Rx Data FIFO Head - RW */
+#define E1000_RDFT	0x02418	/* Rx Data FIFO Tail - RW */
+#define E1000_RDFHS	0x02420	/* Rx Data FIFO Head Saved - RW */
+#define E1000_RDFTS	0x02428	/* Rx Data FIFO Tail Saved - RW */
+#define E1000_RDFPC	0x02430	/* Rx Data FIFO Packet Count - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDTR	0x02820	/* Rx Delay Timer - RW */
+#define E1000_RADV	0x0282C	/* Rx Interrupt Absolute Delay Timer - RW */
+/* Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)	((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+			 (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)	((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+			 (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)	((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+			 (0x0C008 + ((_n) * 0x40)))
+#define E1000_RDH(_n)	((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+			 (0x0C010 + ((_n) * 0x40)))
+#define E1000_RDT(_n)	((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+			 (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)	((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+				 (0x0C028 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)	((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+			 (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)	((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+			 (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)	((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+			 (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)	((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+			 (0x0E010 + ((_n) * 0x40)))
+#define E1000_TDT(_n)	((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+			 (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)	((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+				 (0x0E028 + ((_n) * 0x40)))
+#define E1000_TARC(_n)		(0x03840 + ((_n) * 0x100))
+#define E1000_KABGTXD		0x03004	/* AFE Band Gap Transmit Ref Data */
+#define E1000_RAL(_i)		(((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+				 (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)		(((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+				 (0x054E4 + ((_i - 16) * 8)))
+#define E1000_SHRAL(_i)		(0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i)		(0x0543C + ((_i) * 8))
+#define E1000_TDFH		0x03410	/* Tx Data FIFO Head - RW */
+#define E1000_TDFT		0x03418	/* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS		0x03420	/* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS		0x03428	/* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC		0x03430	/* Tx Data FIFO Packet Count - RW */
+#define E1000_TIDV	0x03820	/* Tx Interrupt Delay Value - RW */
+#define E1000_TADV	0x0382C	/* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_CRCERRS	0x04000	/* CRC Error Count - R/clr */
+#define E1000_ALGNERRC	0x04004	/* Alignment Error Count - R/clr */
+#define E1000_SYMERRS	0x04008	/* Symbol Error Count - R/clr */
+#define E1000_RXERRC	0x0400C	/* Receive Error Count - R/clr */
+#define E1000_MPC	0x04010	/* Missed Packet Count - R/clr */
+#define E1000_SCC	0x04014	/* Single Collision Count - R/clr */
+#define E1000_ECOL	0x04018	/* Excessive Collision Count - R/clr */
+#define E1000_MCC	0x0401C	/* Multiple Collision Count - R/clr */
+#define E1000_LATECOL	0x04020	/* Late Collision Count - R/clr */
+#define E1000_COLC	0x04028	/* Collision Count - R/clr */
+#define E1000_DC	0x04030	/* Defer Count - R/clr */
+#define E1000_TNCRS	0x04034	/* Tx-No CRS - R/clr */
+#define E1000_SEC	0x04038	/* Sequence Error Count - R/clr */
+#define E1000_CEXTERR	0x0403C	/* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC	0x04040	/* Receive Length Error Count - R/clr */
+#define E1000_XONRXC	0x04048	/* XON Rx Count - R/clr */
+#define E1000_XONTXC	0x0404C	/* XON Tx Count - R/clr */
+#define E1000_XOFFRXC	0x04050	/* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC	0x04054	/* XOFF Tx Count - R/clr */
+#define E1000_FCRUC	0x04058	/* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64	0x0405C	/* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127	0x04060	/* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255	0x04064	/* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511	0x04068	/* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023	0x0406C	/* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522	0x04070	/* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC	0x04074	/* Good Packets Rx Count - R/clr */
+#define E1000_BPRC	0x04078	/* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC	0x0407C	/* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC	0x04080	/* Good Packets Tx Count - R/clr */
+#define E1000_GORCL	0x04088	/* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH	0x0408C	/* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL	0x04090	/* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH	0x04094	/* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC	0x040A0	/* Rx No Buffers Count - R/clr */
+#define E1000_RUC	0x040A4	/* Rx Undersize Count - R/clr */
+#define E1000_RFC	0x040A8	/* Rx Fragment Count - R/clr */
+#define E1000_ROC	0x040AC	/* Rx Oversize Count - R/clr */
+#define E1000_RJC	0x040B0	/* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC	0x040B4	/* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC	0x040B8	/* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC	0x040BC	/* Management Packets Tx Count - R/clr */
+#define E1000_TORL	0x040C0	/* Total Octets Rx Low - R/clr */
+#define E1000_TORH	0x040C4	/* Total Octets Rx High - R/clr */
+#define E1000_TOTL	0x040C8	/* Total Octets Tx Low - R/clr */
+#define E1000_TOTH	0x040CC	/* Total Octets Tx High - R/clr */
+#define E1000_TPR	0x040D0	/* Total Packets Rx - R/clr */
+#define E1000_TPT	0x040D4	/* Total Packets Tx - R/clr */
+#define E1000_PTC64	0x040D8	/* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127	0x040DC	/* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255	0x040E0	/* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511	0x040E4	/* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023	0x040E8	/* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522	0x040EC	/* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC	0x040F0	/* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC	0x040F4	/* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC	0x040F8	/* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC	0x040FC	/* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC	0x04100	/* Interrupt Assertion Count */
+#define E1000_ICRXPTC	0x04104	/* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC	0x04108	/* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC	0x0410C	/* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC	0x04110	/* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC	0x04118	/* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC	0x0411C	/* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC	0x04120	/* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC	0x04124	/* Interrupt Cause Receiver Overrun Count */
+#define E1000_CRC_OFFSET	0x05F50	/* CRC Offset register */
+
+#define E1000_PCS_LCTL	0x04208	/* PCS Link Control - RW */
+#define E1000_PCS_LSTAT	0x0420C	/* PCS Link Status - RO */
+#define E1000_PCS_ANADV	0x04218	/* AN advertisement - RW */
+#define E1000_PCS_LPAB	0x0421C	/* Link Partner Ability - RW */
+#define E1000_RXCSUM	0x05000	/* Rx Checksum Control - RW */
+#define E1000_RFCTL	0x05008	/* Receive Filter Control */
+#define E1000_MTA	0x05200	/* Multicast Table Array - RW Array */
+#define E1000_RA	0x05400	/* Receive Address - RW Array */
+#define E1000_VFTA	0x05600	/* VLAN Filter Table Array - RW Array */
+#define E1000_WUC	0x05800	/* Wakeup Control - RW */
+#define E1000_WUFC	0x05808	/* Wakeup Filter Control - RW */
+#define E1000_WUS	0x05810	/* Wakeup Status - RO */
+#define E1000_MANC	0x05820	/* Management Control - RW */
+#define E1000_FFLT	0x05F00	/* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF	0x08800	/* Host Interface */
+
+#define E1000_KMRNCTRLSTA	0x00034	/* MAC-PHY interface - RW */
+#define E1000_MANC2H		0x05860	/* Management Control To Host - RW */
+/* Management Decision Filters */
+#define E1000_MDEF(_n)		(0x05890 + (4 * (_n)))
+#define E1000_SW_FW_SYNC	0x05B5C	/* SW-FW Synchronization - RW */
+#define E1000_GCR	0x05B00	/* PCI-Ex Control */
+#define E1000_GCR2	0x05B64	/* PCI-Ex Control #2 */
+#define E1000_FACTPS	0x05B30	/* Function Active and Power State to MNG */
+#define E1000_SWSM	0x05B50	/* SW Semaphore */
+#define E1000_FWSM	0x05B54	/* FW Semaphore */
+/* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_SWSM2	0x05B58
+#define E1000_FFLT_DBG	0x05F04	/* Debug Register */
+#define E1000_HICR	0x08F00	/* Host Interface Control */
+
+/* RSS registers */
+#define E1000_MRQC	0x05818	/* Multiple Receive Control - RW */
+#define E1000_RETA(_i)	(0x05C00 + ((_i) * 4))	/* Redirection Table - RW */
+#define E1000_RSSRK(_i)	(0x05C80 + ((_i) * 4))	/* RSS Random Key - RW */
+#define E1000_TSYNCRXCTL	0x0B620	/* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL	0x0B614	/* Tx Time Sync Control register - RW */
+#define E1000_RXSTMPL	0x0B624	/* Rx timestamp Low - RO */
+#define E1000_RXSTMPH	0x0B628	/* Rx timestamp High - RO */
+#define E1000_TXSTMPL	0x0B618	/* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH	0x0B61C	/* Tx timestamp value High - RO */
+#define E1000_SYSTIML	0x0B600	/* System time register Low - RO */
+#define E1000_SYSTIMH	0x0B604	/* System time register High - RO */
+#define E1000_TIMINCA	0x0B608	/* Increment attributes register - RW */
+#define E1000_RXMTRL	0x0B634	/* Time sync Rx EtherType and Msg Type - RW */
+#define E1000_RXUDP	0x0B638	/* Time Sync Rx UDP Port - RW */
+
+#endif
diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile
index 624476c..f19700e 100644
--- a/drivers/net/ethernet/intel/igb/Makefile
+++ b/drivers/net/ethernet/intel/igb/Makefile
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel 82575 PCI-Express Ethernet Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -34,4 +34,4 @@
 
 igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
 	    e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
-	    e1000_i210.o igb_ptp.o
+	    e1000_i210.o igb_ptp.o igb_hwmon.o
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index fdaaf27..84e7e09 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   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,7 @@
 
 #include <linux/types.h>
 #include <linux/if_ether.h>
+#include <linux/i2c.h>
 
 #include "e1000_mac.h"
 #include "e1000_82575.h"
@@ -110,15 +111,293 @@
 	return ext_mdio;
 }
 
-static s32 igb_get_invariants_82575(struct e1000_hw *hw)
+/**
+ *  igb_init_phy_params_82575 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = 0;
+	u32 ctrl_ext;
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type = e1000_phy_none;
+		goto out;
+	}
+
+	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us	= 100;
+
+	ctrl_ext = rd32(E1000_CTRL_EXT);
+
+	if (igb_sgmii_active_82575(hw)) {
+		phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
+	} else {
+		phy->ops.reset = igb_phy_hw_reset;
+		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+	}
+
+	wr32(E1000_CTRL_EXT, ctrl_ext);
+	igb_reset_mdicnfg_82580(hw);
+
+	if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
+		phy->ops.read_reg = igb_read_phy_reg_sgmii_82575;
+		phy->ops.write_reg = igb_write_phy_reg_sgmii_82575;
+	} else {
+		switch (hw->mac.type) {
+		case e1000_82580:
+		case e1000_i350:
+			phy->ops.read_reg = igb_read_phy_reg_82580;
+			phy->ops.write_reg = igb_write_phy_reg_82580;
+			break;
+		case e1000_i210:
+		case e1000_i211:
+			phy->ops.read_reg = igb_read_phy_reg_gs40g;
+			phy->ops.write_reg = igb_write_phy_reg_gs40g;
+			break;
+		default:
+			phy->ops.read_reg = igb_read_phy_reg_igp;
+			phy->ops.write_reg = igb_write_phy_reg_igp;
+		}
+	}
+
+	/* set lan id */
+	hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
+			E1000_STATUS_FUNC_SHIFT;
+
+	/* Set phy->phy_addr and phy->id. */
+	ret_val = igb_get_phy_id_82575(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Verify phy id and set remaining function pointers */
+	switch (phy->id) {
+	case I347AT4_E_PHY_ID:
+	case M88E1112_E_PHY_ID:
+	case M88E1111_I_PHY_ID:
+		phy->type		= e1000_phy_m88;
+		phy->ops.get_phy_info	= igb_get_phy_info_m88;
+		if (phy->id == I347AT4_E_PHY_ID ||
+		    phy->id == M88E1112_E_PHY_ID)
+			phy->ops.get_cable_length =
+					 igb_get_cable_length_m88_gen2;
+		else
+			phy->ops.get_cable_length = igb_get_cable_length_m88;
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy->type = e1000_phy_igp_3;
+		phy->ops.get_phy_info = igb_get_phy_info_igp;
+		phy->ops.get_cable_length = igb_get_cable_length_igp_2;
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
+		phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82575;
+		phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state;
+		break;
+	case I82580_I_PHY_ID:
+	case I350_I_PHY_ID:
+		phy->type = e1000_phy_82580;
+		phy->ops.force_speed_duplex =
+					 igb_phy_force_speed_duplex_82580;
+		phy->ops.get_cable_length = igb_get_cable_length_82580;
+		phy->ops.get_phy_info = igb_get_phy_info_82580;
+		phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
+		phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
+		break;
+	case I210_I_PHY_ID:
+		phy->type		= e1000_phy_i210;
+		phy->ops.check_polarity	= igb_check_polarity_m88;
+		phy->ops.get_phy_info	= igb_get_phy_info_m88;
+		phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
+		phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
+		phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  igb_init_nvm_params_82575 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
+{
 	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = rd32(E1000_EECD);
+	u16 size;
+
+	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+		     E1000_EECD_SIZE_EX_SHIFT);
+	/* Added to a constant, "size" becomes the left-shift value
+	 * for setting word_size.
+	 */
+	size += NVM_WORD_SIZE_BASE_SHIFT;
+
+	/* Just in case size is out of range, cap it to the largest
+	 * EEPROM size supported
+	 */
+	if (size > 15)
+		size = 15;
+
+	nvm->word_size = 1 << size;
+	if (hw->mac.type < e1000_i210) {
+		nvm->opcode_bits = 8;
+		nvm->delay_usec = 1;
+
+		switch (nvm->override) {
+		case e1000_nvm_override_spi_large:
+			nvm->page_size = 32;
+			nvm->address_bits = 16;
+			break;
+		case e1000_nvm_override_spi_small:
+			nvm->page_size = 8;
+			nvm->address_bits = 8;
+			break;
+		default:
+			nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+			nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ?
+					    16 : 8;
+			break;
+		}
+		if (nvm->word_size == (1 << 15))
+			nvm->page_size = 128;
+
+		nvm->type = e1000_nvm_eeprom_spi;
+	} else {
+		nvm->type = e1000_nvm_flash_hw;
+	}
+
+	/* NVM Function Pointers */
+	switch (hw->mac.type) {
+	case e1000_82580:
+		nvm->ops.validate = igb_validate_nvm_checksum_82580;
+		nvm->ops.update = igb_update_nvm_checksum_82580;
+		nvm->ops.acquire = igb_acquire_nvm_82575;
+		nvm->ops.release = igb_release_nvm_82575;
+		if (nvm->word_size < (1 << 15))
+			nvm->ops.read = igb_read_nvm_eerd;
+		else
+			nvm->ops.read = igb_read_nvm_spi;
+		nvm->ops.write = igb_write_nvm_spi;
+		break;
+	case e1000_i350:
+		nvm->ops.validate = igb_validate_nvm_checksum_i350;
+		nvm->ops.update = igb_update_nvm_checksum_i350;
+		nvm->ops.acquire = igb_acquire_nvm_82575;
+		nvm->ops.release = igb_release_nvm_82575;
+		if (nvm->word_size < (1 << 15))
+			nvm->ops.read = igb_read_nvm_eerd;
+		else
+			nvm->ops.read = igb_read_nvm_spi;
+		nvm->ops.write = igb_write_nvm_spi;
+		break;
+	case e1000_i210:
+		nvm->ops.validate = igb_validate_nvm_checksum_i210;
+		nvm->ops.update   = igb_update_nvm_checksum_i210;
+		nvm->ops.acquire = igb_acquire_nvm_i210;
+		nvm->ops.release = igb_release_nvm_i210;
+		nvm->ops.read    = igb_read_nvm_srrd_i210;
+		nvm->ops.write   = igb_write_nvm_srwr_i210;
+		nvm->ops.valid_led_default = igb_valid_led_default_i210;
+		break;
+	case e1000_i211:
+		nvm->ops.acquire  = igb_acquire_nvm_i210;
+		nvm->ops.release  = igb_release_nvm_i210;
+		nvm->ops.read     = igb_read_nvm_i211;
+		nvm->ops.valid_led_default = igb_valid_led_default_i210;
+		nvm->ops.validate = NULL;
+		nvm->ops.update   = NULL;
+		nvm->ops.write    = NULL;
+		break;
+	default:
+		nvm->ops.validate = igb_validate_nvm_checksum;
+		nvm->ops.update = igb_update_nvm_checksum;
+		nvm->ops.acquire = igb_acquire_nvm_82575;
+		nvm->ops.release = igb_release_nvm_82575;
+		if (nvm->word_size < (1 << 15))
+			nvm->ops.read = igb_read_nvm_eerd;
+		else
+			nvm->ops.read = igb_read_nvm_spi;
+		nvm->ops.write = igb_write_nvm_spi;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  igb_init_mac_params_82575 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	switch (mac->type) {
+	case e1000_82576:
+		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+		break;
+	case e1000_82580:
+		mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+		break;
+	case e1000_i350:
+		mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
+		break;
+	default:
+		mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+		break;
+	}
+	/* reset */
+	if (mac->type >= e1000_82580)
+		mac->ops.reset_hw = igb_reset_hw_82580;
+	else
+		mac->ops.reset_hw = igb_reset_hw_82575;
+
+	if (mac->type >= e1000_i210) {
+		mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210;
+		mac->ops.release_swfw_sync = igb_release_swfw_sync_i210;
+
+	} else {
+		mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575;
+		mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
+	}
+
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+		(rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
+			? true : false;
+	/* enable EEE on i350 parts and later parts */
+	if (mac->type >= e1000_i350)
+		dev_spec->eee_disable = false;
+	else
+		dev_spec->eee_disable = true;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+		(hw->phy.media_type == e1000_media_type_copper)
+			? igb_setup_copper_link_82575
+			: igb_setup_serdes_link_82575;
+
+	return 0;
+}
+
+static s32 igb_get_invariants_82575(struct e1000_hw *hw)
+{
 	struct e1000_mac_info *mac = &hw->mac;
 	struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575;
-	u32 eecd;
 	s32 ret_val;
-	u16 size;
 	u32 ctrl_ext = 0;
 
 	switch (hw->device_id) {
@@ -179,7 +458,7 @@
 	 * SerDes mode on the 82575. There can be an external PHY attached
 	 * on the SGMII interface. For this, we'll set sgmii_active to true.
 	 */
-	phy->media_type = e1000_media_type_copper;
+	hw->phy.media_type = e1000_media_type_copper;
 	dev_spec->sgmii_active = false;
 
 	ctrl_ext = rd32(E1000_CTRL_EXT);
@@ -195,154 +474,15 @@
 		break;
 	}
 
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	switch (mac->type) {
-	case e1000_82576:
-		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
-		break;
-	case e1000_82580:
-		mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
-		break;
-	case e1000_i350:
-		mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
-		break;
-	default:
-		mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
-		break;
-	}
-	/* reset */
-	if (mac->type >= e1000_82580)
-		mac->ops.reset_hw = igb_reset_hw_82580;
-	else
-		mac->ops.reset_hw = igb_reset_hw_82575;
-
-	if (mac->type >= e1000_i210) {
-		mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210;
-		mac->ops.release_swfw_sync = igb_release_swfw_sync_i210;
-	} else {
-		mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575;
-		mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
-	}
-
-	/* Set if part includes ASF firmware */
-	mac->asf_firmware_present = true;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid =
-		(rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
-			? true : false;
-	/* enable EEE on i350 parts and later parts */
-	if (mac->type >= e1000_i350)
-		dev_spec->eee_disable = false;
-	else
-		dev_spec->eee_disable = true;
-	/* physical interface link setup */
-	mac->ops.setup_physical_interface =
-		(hw->phy.media_type == e1000_media_type_copper)
-			? igb_setup_copper_link_82575
-			: igb_setup_serdes_link_82575;
+	/* mac initialization and operations */
+	ret_val = igb_init_mac_params_82575(hw);
+	if (ret_val)
+		goto out;
 
 	/* NVM initialization */
-	eecd = rd32(E1000_EECD);
-	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
-		     E1000_EECD_SIZE_EX_SHIFT);
-
-	/*
-	 * Added to a constant, "size" becomes the left-shift value
-	 * for setting word_size.
-	 */
-	size += NVM_WORD_SIZE_BASE_SHIFT;
-
-	/*
-	 * Check for invalid size
-	 */
-	if ((hw->mac.type == e1000_82576) && (size > 15)) {
-		pr_notice("The NVM size is not valid, defaulting to 32K\n");
-		size = 15;
-	}
-
-	nvm->word_size = 1 << size;
-	if (hw->mac.type < e1000_i210) {
-		nvm->opcode_bits        = 8;
-		nvm->delay_usec         = 1;
-		switch (nvm->override) {
-		case e1000_nvm_override_spi_large:
-			nvm->page_size    = 32;
-			nvm->address_bits = 16;
-			break;
-		case e1000_nvm_override_spi_small:
-			nvm->page_size    = 8;
-			nvm->address_bits = 8;
-			break;
-		default:
-			nvm->page_size    = eecd
-				& E1000_EECD_ADDR_BITS ? 32 : 8;
-			nvm->address_bits = eecd
-				& E1000_EECD_ADDR_BITS ? 16 : 8;
-			break;
-		}
-		if (nvm->word_size == (1 << 15))
-			nvm->page_size = 128;
-
-		nvm->type = e1000_nvm_eeprom_spi;
-	} else
-		nvm->type = e1000_nvm_flash_hw;
-
-	/* NVM Function Pointers */
-	switch (hw->mac.type) {
-	case e1000_82580:
-		nvm->ops.validate = igb_validate_nvm_checksum_82580;
-		nvm->ops.update = igb_update_nvm_checksum_82580;
-		nvm->ops.acquire = igb_acquire_nvm_82575;
-		nvm->ops.release = igb_release_nvm_82575;
-		if (nvm->word_size < (1 << 15))
-			nvm->ops.read = igb_read_nvm_eerd;
-		else
-			nvm->ops.read = igb_read_nvm_spi;
-		nvm->ops.write = igb_write_nvm_spi;
-		break;
-	case e1000_i350:
-		nvm->ops.validate = igb_validate_nvm_checksum_i350;
-		nvm->ops.update = igb_update_nvm_checksum_i350;
-		nvm->ops.acquire = igb_acquire_nvm_82575;
-		nvm->ops.release = igb_release_nvm_82575;
-		if (nvm->word_size < (1 << 15))
-			nvm->ops.read = igb_read_nvm_eerd;
-		else
-			nvm->ops.read = igb_read_nvm_spi;
-		nvm->ops.write = igb_write_nvm_spi;
-		break;
-	case e1000_i210:
-		nvm->ops.validate = igb_validate_nvm_checksum_i210;
-		nvm->ops.update   = igb_update_nvm_checksum_i210;
-		nvm->ops.acquire = igb_acquire_nvm_i210;
-		nvm->ops.release = igb_release_nvm_i210;
-		nvm->ops.read    = igb_read_nvm_srrd_i210;
-		nvm->ops.write   = igb_write_nvm_srwr_i210;
-		nvm->ops.valid_led_default = igb_valid_led_default_i210;
-		break;
-	case e1000_i211:
-		nvm->ops.acquire  = igb_acquire_nvm_i210;
-		nvm->ops.release  = igb_release_nvm_i210;
-		nvm->ops.read     = igb_read_nvm_i211;
-		nvm->ops.valid_led_default = igb_valid_led_default_i210;
-		nvm->ops.validate = NULL;
-		nvm->ops.update   = NULL;
-		nvm->ops.write    = NULL;
-		break;
-	default:
-		nvm->ops.validate = igb_validate_nvm_checksum;
-		nvm->ops.update = igb_update_nvm_checksum;
-		nvm->ops.acquire = igb_acquire_nvm_82575;
-		nvm->ops.release = igb_release_nvm_82575;
-		if (nvm->word_size < (1 << 15))
-			nvm->ops.read = igb_read_nvm_eerd;
-		else
-			nvm->ops.read = igb_read_nvm_spi;
-		nvm->ops.write = igb_write_nvm_spi;
-		break;
-	}
+	ret_val = igb_init_nvm_params_82575(hw);
+	if (ret_val)
+		goto out;
 
 	/* if part supports SR-IOV then initialize mailbox parameters */
 	switch (mac->type) {
@@ -355,107 +495,10 @@
 	}
 
 	/* setup PHY parameters */
-	if (phy->media_type != e1000_media_type_copper) {
-		phy->type = e1000_phy_none;
-		return 0;
-	}
+	ret_val = igb_init_phy_params_82575(hw);
 
-	phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us      = 100;
-
-	ctrl_ext = rd32(E1000_CTRL_EXT);
-
-	/* PHY function pointers */
-	if (igb_sgmii_active_82575(hw)) {
-		phy->ops.reset      = igb_phy_hw_reset_sgmii_82575;
-		ctrl_ext |= E1000_CTRL_I2C_ENA;
-	} else {
-		phy->ops.reset      = igb_phy_hw_reset;
-		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
-	}
-
-	wr32(E1000_CTRL_EXT, ctrl_ext);
-	igb_reset_mdicnfg_82580(hw);
-
-	if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
-		phy->ops.read_reg   = igb_read_phy_reg_sgmii_82575;
-		phy->ops.write_reg  = igb_write_phy_reg_sgmii_82575;
-	} else if ((hw->mac.type == e1000_82580)
-		|| (hw->mac.type == e1000_i350)) {
-		phy->ops.read_reg   = igb_read_phy_reg_82580;
-		phy->ops.write_reg  = igb_write_phy_reg_82580;
-	} else if (hw->phy.type >= e1000_phy_i210) {
-		phy->ops.read_reg   = igb_read_phy_reg_gs40g;
-		phy->ops.write_reg  = igb_write_phy_reg_gs40g;
-	} else {
-		phy->ops.read_reg   = igb_read_phy_reg_igp;
-		phy->ops.write_reg  = igb_write_phy_reg_igp;
-	}
-
-	/* set lan id */
-	hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
-	               E1000_STATUS_FUNC_SHIFT;
-
-	/* Set phy->phy_addr and phy->id. */
-	ret_val = igb_get_phy_id_82575(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Verify phy id and set remaining function pointers */
-	switch (phy->id) {
-	case I347AT4_E_PHY_ID:
-	case M88E1112_E_PHY_ID:
-	case M88E1111_I_PHY_ID:
-		phy->type                   = e1000_phy_m88;
-		phy->ops.get_phy_info       = igb_get_phy_info_m88;
-
-		if (phy->id == I347AT4_E_PHY_ID ||
-		    phy->id == M88E1112_E_PHY_ID)
-			phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
-		else
-			phy->ops.get_cable_length = igb_get_cable_length_m88;
-
-		if (phy->id == I210_I_PHY_ID) {
-			phy->ops.get_cable_length =
-					 igb_get_cable_length_m88_gen2;
-			phy->ops.set_d0_lplu_state =
-					igb_set_d0_lplu_state_82580;
-			phy->ops.set_d3_lplu_state =
-					igb_set_d3_lplu_state_82580;
-		}
-		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
-		break;
-	case IGP03E1000_E_PHY_ID:
-		phy->type                   = e1000_phy_igp_3;
-		phy->ops.get_phy_info       = igb_get_phy_info_igp;
-		phy->ops.get_cable_length   = igb_get_cable_length_igp_2;
-		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
-		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82575;
-		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state;
-		break;
-	case I82580_I_PHY_ID:
-	case I350_I_PHY_ID:
-		phy->type                   = e1000_phy_82580;
-		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;
-		phy->ops.get_cable_length   = igb_get_cable_length_82580;
-		phy->ops.get_phy_info       = igb_get_phy_info_82580;
-		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82580;
-		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state_82580;
-		break;
-	case I210_I_PHY_ID:
-		phy->type                   = e1000_phy_i210;
-		phy->ops.get_phy_info       = igb_get_phy_info_m88;
-		phy->ops.check_polarity     = igb_check_polarity_m88;
-		phy->ops.get_cable_length   = igb_get_cable_length_m88_gen2;
-		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82580;
-		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state_82580;
-		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
-		break;
-	default:
-		return -E1000_ERR_PHY;
-	}
-
-	return 0;
+out:
+	return ret_val;
 }
 
 /**
@@ -2302,18 +2345,157 @@
 	return ret_val;
 }
 
+static const u8 e1000_emc_temp_data[4] = {
+	E1000_EMC_INTERNAL_DATA,
+	E1000_EMC_DIODE1_DATA,
+	E1000_EMC_DIODE2_DATA,
+	E1000_EMC_DIODE3_DATA
+};
+static const u8 e1000_emc_therm_limit[4] = {
+	E1000_EMC_INTERNAL_THERM_LIMIT,
+	E1000_EMC_DIODE1_THERM_LIMIT,
+	E1000_EMC_DIODE2_THERM_LIMIT,
+	E1000_EMC_DIODE3_THERM_LIMIT
+};
+
+/* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
+ *  @hw: pointer to hardware structure
+ *
+ *  Updates the temperatures in mac.thermal_sensor_data
+ */
+s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
+{
+	s32 status = E1000_SUCCESS;
+	u16 ets_offset;
+	u16 ets_cfg;
+	u16 ets_sensor;
+	u8  num_sensors;
+	u8  sensor_index;
+	u8  sensor_location;
+	u8  i;
+	struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+	if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
+		return E1000_NOT_IMPLEMENTED;
+
+	data->sensor[0].temp = (rd32(E1000_THMJT) & 0xFF);
+
+	/* Return the internal sensor only if ETS is unsupported */
+	hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
+	if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
+		return status;
+
+	hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
+	if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+	    != NVM_ETS_TYPE_EMC)
+		return E1000_NOT_IMPLEMENTED;
+
+	num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
+	if (num_sensors > E1000_MAX_SENSORS)
+		num_sensors = E1000_MAX_SENSORS;
+
+	for (i = 1; i < num_sensors; i++) {
+		hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
+		sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
+				NVM_ETS_DATA_INDEX_SHIFT);
+		sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
+				   NVM_ETS_DATA_LOC_SHIFT);
+
+		if (sensor_location != 0)
+			hw->phy.ops.read_i2c_byte(hw,
+					e1000_emc_temp_data[sensor_index],
+					E1000_I2C_THERMAL_SENSOR_ADDR,
+					&data->sensor[i].temp);
+	}
+	return status;
+}
+
+/* igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the thermal sensor thresholds according to the NVM map
+ *  and save off the threshold and location values into mac.thermal_sensor_data
+ */
+s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
+{
+	s32 status = E1000_SUCCESS;
+	u16 ets_offset;
+	u16 ets_cfg;
+	u16 ets_sensor;
+	u8  low_thresh_delta;
+	u8  num_sensors;
+	u8  sensor_index;
+	u8  sensor_location;
+	u8  therm_limit;
+	u8  i;
+	struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+	if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
+		return E1000_NOT_IMPLEMENTED;
+
+	memset(data, 0, sizeof(struct e1000_thermal_sensor_data));
+
+	data->sensor[0].location = 0x1;
+	data->sensor[0].caution_thresh =
+		(rd32(E1000_THHIGHTC) & 0xFF);
+	data->sensor[0].max_op_thresh =
+		(rd32(E1000_THLOWTC) & 0xFF);
+
+	/* Return the internal sensor only if ETS is unsupported */
+	hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
+	if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
+		return status;
+
+	hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
+	if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+	    != NVM_ETS_TYPE_EMC)
+		return E1000_NOT_IMPLEMENTED;
+
+	low_thresh_delta = ((ets_cfg & NVM_ETS_LTHRES_DELTA_MASK) >>
+			    NVM_ETS_LTHRES_DELTA_SHIFT);
+	num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
+
+	for (i = 1; i <= num_sensors; i++) {
+		hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
+		sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
+				NVM_ETS_DATA_INDEX_SHIFT);
+		sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
+				   NVM_ETS_DATA_LOC_SHIFT);
+		therm_limit = ets_sensor & NVM_ETS_DATA_HTHRESH_MASK;
+
+		hw->phy.ops.write_i2c_byte(hw,
+			e1000_emc_therm_limit[sensor_index],
+			E1000_I2C_THERMAL_SENSOR_ADDR,
+			therm_limit);
+
+		if ((i < E1000_MAX_SENSORS) && (sensor_location != 0)) {
+			data->sensor[i].location = sensor_location;
+			data->sensor[i].caution_thresh = therm_limit;
+			data->sensor[i].max_op_thresh = therm_limit -
+							low_thresh_delta;
+		}
+	}
+	return status;
+}
+
 static struct e1000_mac_operations e1000_mac_ops_82575 = {
 	.init_hw              = igb_init_hw_82575,
 	.check_for_link       = igb_check_for_link_82575,
 	.rar_set              = igb_rar_set,
 	.read_mac_addr        = igb_read_mac_addr_82575,
 	.get_speed_and_duplex = igb_get_speed_and_duplex_copper,
+#ifdef CONFIG_IGB_HWMON
+	.get_thermal_sensor_data = igb_get_thermal_sensor_data_generic,
+	.init_thermal_sensor_thresh = igb_init_thermal_sensor_thresh_generic,
+#endif
 };
 
 static struct e1000_phy_operations e1000_phy_ops_82575 = {
 	.acquire              = igb_acquire_phy_82575,
 	.get_cfg_done         = igb_get_cfg_done_82575,
 	.release              = igb_release_phy_82575,
+	.write_i2c_byte       = igb_write_i2c_byte,
+	.read_i2c_byte        = igb_read_i2c_byte,
 };
 
 static struct e1000_nvm_operations e1000_nvm_ops_82575 = {
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 44b76b3..73ab41f 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -32,6 +32,10 @@
 extern void igb_power_up_serdes_link_82575(struct e1000_hw *hw);
 extern void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
 extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
+extern s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+				u8 dev_addr, u8 *data);
+extern s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+				 u8 dev_addr, u8 data);
 
 #define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
                                      (ID_LED_DEF1_DEF2 <<  8) | \
@@ -260,5 +264,16 @@
 void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
 u16 igb_rxpbs_adjust_82580(u32 data);
 s32 igb_set_eee_i350(struct e1000_hw *);
+s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
+s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);
 
+#define E1000_I2C_THERMAL_SENSOR_ADDR	0xF8
+#define E1000_EMC_INTERNAL_DATA		0x00
+#define E1000_EMC_INTERNAL_THERM_LIMIT	0x20
+#define E1000_EMC_DIODE1_DATA		0x01
+#define E1000_EMC_DIODE1_THERM_LIMIT	0x19
+#define E1000_EMC_DIODE2_DATA		0x23
+#define E1000_EMC_DIODE2_THERM_LIMIT	0x1A
+#define E1000_EMC_DIODE3_DATA		0x2A
+#define E1000_EMC_DIODE3_THERM_LIMIT	0x30
 #endif
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 45dce06..7e13337 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -470,6 +470,7 @@
 #define E1000_ERR_NO_SPACE          17
 #define E1000_ERR_NVM_PBA_SECTION   18
 #define E1000_ERR_INVM_VALUE_NOT_FOUND	19
+#define E1000_ERR_I2C               20
 
 /* Loop limit on how long we wait for auto-negotiation to complete */
 #define COPPER_LINK_UP_LIMIT              10
@@ -674,6 +675,18 @@
 #define NVM_COMB_VER_SHFT               8
 #define NVM_VER_INVALID            0xFFFF
 #define NVM_ETRACK_SHIFT               16
+#define NVM_ETS_CFG			0x003E
+#define NVM_ETS_LTHRES_DELTA_MASK	0x07C0
+#define NVM_ETS_LTHRES_DELTA_SHIFT	6
+#define NVM_ETS_TYPE_MASK		0x0038
+#define NVM_ETS_TYPE_SHIFT		3
+#define NVM_ETS_TYPE_EMC		0x000
+#define NVM_ETS_NUM_SENSORS_MASK	0x0007
+#define NVM_ETS_DATA_LOC_MASK		0x3C00
+#define NVM_ETS_DATA_LOC_SHIFT		10
+#define NVM_ETS_DATA_INDEX_MASK		0x0300
+#define NVM_ETS_DATA_INDEX_SHIFT	8
+#define NVM_ETS_DATA_HTHRESH_MASK	0x00FF
 
 #define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
 #define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index c2a51dc..0d5cf9c 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -325,6 +325,10 @@
 	s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
 	s32  (*acquire_swfw_sync)(struct e1000_hw *, u16);
 	void (*release_swfw_sync)(struct e1000_hw *, u16);
+#ifdef CONFIG_IGB_HWMON
+	s32 (*get_thermal_sensor_data)(struct e1000_hw *);
+	s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
+#endif
 
 };
 
@@ -342,6 +346,8 @@
 	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
 	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
 	s32  (*write_reg)(struct e1000_hw *, u32, u16);
+	s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *);
+	s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8);
 };
 
 struct e1000_nvm_operations {
@@ -354,6 +360,19 @@
 	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
 };
 
+#define E1000_MAX_SENSORS		3
+
+struct e1000_thermal_diode_data {
+	u8 location;
+	u8 temp;
+	u8 caution_thresh;
+	u8 max_op_thresh;
+};
+
+struct e1000_thermal_sensor_data {
+	struct e1000_thermal_diode_data sensor[E1000_MAX_SENSORS];
+};
+
 struct e1000_info {
 	s32 (*get_invariants)(struct e1000_hw *);
 	struct e1000_mac_operations *mac_ops;
@@ -399,6 +418,7 @@
 	bool report_tx_early;
 	bool serdes_has_link;
 	bool tx_pkt_filtering;
+	struct e1000_thermal_sensor_data thermal_sensor_data;
 };
 
 struct e1000_phy_info {
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index fbcdbeb..6a42344 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h
index 1c89358..e4e1a73 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index 101e6e4..a5c7200 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h
index e2b2c4b..e6d6ce4 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c
index 5988b89..38e0df3 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index dbcfa3d..c13b56d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index fbb7604..5b62adb 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h
index 7012d45..6bfc0c4 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.h
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2012 Intel Corporation.
+  Copyright(c) 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index fe76004..2918c97 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
index ed282f8..784fd1c 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index e5db485..1534328 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -75,6 +75,14 @@
 #define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
 #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
 #define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+#define E1000_I2CPARAMS        0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_I2CBB_EN      0x00000100  /* I2C - Bit Bang Enable */
+#define E1000_I2C_CLK_OUT   0x00000200  /* I2C- Clock */
+#define E1000_I2C_DATA_OUT  0x00000400  /* I2C- Data Out */
+#define E1000_I2C_DATA_OE_N 0x00000800  /* I2C- Data Output Enable */
+#define E1000_I2C_DATA_IN   0x00001000  /* I2C- Data In */
+#define E1000_I2C_CLK_OE_N  0x00002000  /* I2C- Clock Output Enable */
+#define E1000_I2C_CLK_IN    0x00004000  /* I2C- Clock In */
 
 /* IEEE 1588 TIMESYNCH */
 #define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
@@ -124,6 +132,14 @@
 
 /* Split and Replication RX Control - RW */
 #define E1000_RXPBS    0x02404  /* Rx Packet Buffer Size - RW */
+
+/* Thermal sensor configuration and status registers */
+#define E1000_THMJT	0x08100 /* Junction Temperature */
+#define E1000_THLOWTC	0x08104 /* Low Threshold Control */
+#define E1000_THMIDTC	0x08108 /* Mid Threshold Control */
+#define E1000_THHIGHTC	0x0810C /* High Threshold Control */
+#define E1000_THSTAT	0x08110 /* Thermal Sensor Status */
+
 /*
  * Convenience macros
  *
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 17f1686..d27edbc 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   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,6 +39,8 @@
 #include <linux/ptp_clock_kernel.h>
 #include <linux/bitops.h>
 #include <linux/if_vlan.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 
 struct igb_adapter;
 
@@ -137,8 +139,6 @@
 #define IGB_RX_HDR_LEN		IGB_RXBUFFER_256
 #define IGB_RX_BUFSZ		IGB_RXBUFFER_2048
 
-/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define IGB_TX_QUEUE_WAKE	16
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #define IGB_RX_BUFFER_WRITE	16	/* Must be power of 2 */
 
@@ -167,6 +167,17 @@
 #define IGB_TX_FLAGS_VLAN_MASK		0xffff0000
 #define IGB_TX_FLAGS_VLAN_SHIFT	16
 
+/*
+ * The largest size we can write to the descriptor is 65535.  In order to
+ * maintain a power of two alignment we have to limit ourselves to 32K.
+ */
+#define IGB_MAX_TXD_PWR	15
+#define IGB_MAX_DATA_PER_TXD	(1 << IGB_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGB_MAX_DATA_PER_TXD)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct igb_tx_buffer {
@@ -219,6 +230,7 @@
 		struct igb_tx_buffer *tx_buffer_info;
 		struct igb_rx_buffer *rx_buffer_info;
 	};
+	unsigned long last_rx_timestamp;
 	void *desc;			/* descriptor ring memory */
 	unsigned long flags;		/* ring specific flags */
 	void __iomem *tail;		/* pointer to ring tail register */
@@ -272,10 +284,18 @@
 enum e1000_ring_flags_t {
 	IGB_RING_FLAG_RX_SCTP_CSUM,
 	IGB_RING_FLAG_RX_LB_VLAN_BSWAP,
+	IGB_RING_FLAG_RX_BUILD_SKB_ENABLED,
 	IGB_RING_FLAG_TX_CTX_IDX,
 	IGB_RING_FLAG_TX_DETECT_HANG
 };
 
+#define ring_uses_build_skb(ring) \
+	test_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+#define set_ring_build_skb_enabled(ring) \
+	set_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+#define clear_ring_build_skb_enabled(ring) \
+	clear_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+
 #define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
 
 #define IGB_RX_DESC(R, i)	    \
@@ -301,6 +321,32 @@
 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
 }
 
+struct igb_i2c_client_list {
+	struct i2c_client *client;
+	struct igb_i2c_client_list *next;
+};
+
+#ifdef CONFIG_IGB_HWMON
+
+#define IGB_HWMON_TYPE_LOC	0
+#define IGB_HWMON_TYPE_TEMP	1
+#define IGB_HWMON_TYPE_CAUTION	2
+#define IGB_HWMON_TYPE_MAX	3
+
+struct hwmon_attr {
+	struct device_attribute dev_attr;
+	struct e1000_hw *hw;
+	struct e1000_thermal_diode_data *sensor;
+	char name[12];
+	};
+
+struct hwmon_buff {
+	struct device *device;
+	struct hwmon_attr *hwmon_list;
+	unsigned int n_hwmon;
+	};
+#endif
+
 /* board specific private data structure */
 struct igb_adapter {
 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -386,11 +432,22 @@
 	struct delayed_work ptp_overflow_work;
 	struct work_struct ptp_tx_work;
 	struct sk_buff *ptp_tx_skb;
+	unsigned long ptp_tx_start;
+	unsigned long last_rx_ptp_check;
 	spinlock_t tmreg_lock;
 	struct cyclecounter cc;
 	struct timecounter tc;
+	u32 tx_hwtstamp_timeouts;
+	u32 rx_hwtstamp_cleared;
 
 	char fw_version[32];
+#ifdef CONFIG_IGB_HWMON
+	struct hwmon_buff igb_hwmon_buff;
+	bool ets;
+#endif
+	struct i2c_algo_bit_data i2c_algo;
+	struct i2c_adapter i2c_adap;
+	struct igb_i2c_client_list *i2c_clients;
 };
 
 #define IGB_FLAG_HAS_MSI		(1 << 0)
@@ -449,6 +506,7 @@
 extern void igb_ptp_stop(struct igb_adapter *adapter);
 extern void igb_ptp_reset(struct igb_adapter *adapter);
 extern void igb_ptp_tx_work(struct work_struct *work);
+extern void igb_ptp_rx_hang(struct igb_adapter *adapter);
 extern void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
 extern void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
 				struct sk_buff *skb);
@@ -466,7 +524,10 @@
 
 extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
 				  struct ifreq *ifr, int cmd);
-
+#ifdef CONFIG_IGB_HWMON
+extern void igb_sysfs_exit(struct igb_adapter *adapter);
+extern int igb_sysfs_init(struct igb_adapter *adapter);
+#endif
 static inline s32 igb_reset_phy(struct e1000_hw *hw)
 {
 	if (hw->phy.ops.reset)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index bfe9208..a3830a8 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -92,6 +92,8 @@
 	IGB_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
 	IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
 	IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
+	IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+	IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
 };
 
 #define IGB_NETDEV_STAT(_net_stat) { \
@@ -1889,7 +1891,7 @@
 	} else {
 		hw->mac.ops.check_for_link(&adapter->hw);
 		if (hw->mac.autoneg)
-			msleep(4000);
+			msleep(5000);
 
 		if (!(rd32(E1000_STATUS) & E1000_STATUS_LU))
 			*data = 1;
@@ -2272,12 +2274,21 @@
 	struct igb_adapter *adapter = netdev_priv(dev);
 
 	switch (adapter->hw.mac.type) {
+	case e1000_82575:
+		info->so_timestamping =
+			SOF_TIMESTAMPING_TX_SOFTWARE |
+			SOF_TIMESTAMPING_RX_SOFTWARE |
+			SOF_TIMESTAMPING_SOFTWARE;
+		return 0;
 	case e1000_82576:
 	case e1000_82580:
 	case e1000_i350:
 	case e1000_i210:
 	case e1000_i211:
 		info->so_timestamping =
+			SOF_TIMESTAMPING_TX_SOFTWARE |
+			SOF_TIMESTAMPING_RX_SOFTWARE |
+			SOF_TIMESTAMPING_SOFTWARE |
 			SOF_TIMESTAMPING_TX_HARDWARE |
 			SOF_TIMESTAMPING_RX_HARDWARE |
 			SOF_TIMESTAMPING_RAW_HARDWARE;
diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c
new file mode 100644
index 0000000..0a9b073
--- /dev/null
+++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c
@@ -0,0 +1,242 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2013 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "igb.h"
+#include "e1000_82575.h"
+#include "e1000_hw.h"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/hwmon.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_IGB_HWMON
+/* hwmon callback functions */
+static ssize_t igb_hwmon_show_location(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	return sprintf(buf, "loc%u\n",
+		       igb_attr->sensor->location);
+}
+
+static ssize_t igb_hwmon_show_temp(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value;
+
+	/* reset the temp field */
+	igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
+
+	value = igb_attr->sensor->temp;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value = igb_attr->sensor->caution_thresh;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value = igb_attr->sensor->max_op_thresh;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+/* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
+ * @ adapter: pointer to the adapter structure
+ * @ offset: offset in the eeprom sensor data table
+ * @ type: type of sensor data to display
+ *
+ * For each file we want in hwmon's sysfs interface we need a device_attribute
+ * This is included in our hwmon_attr struct that contains the references to
+ * the data structures we need to get the data to display.
+ */
+static int igb_add_hwmon_attr(struct igb_adapter *adapter,
+				unsigned int offset, int type) {
+	int rc;
+	unsigned int n_attr;
+	struct hwmon_attr *igb_attr;
+
+	n_attr = adapter->igb_hwmon_buff.n_hwmon;
+	igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr];
+
+	switch (type) {
+	case IGB_HWMON_TYPE_LOC:
+		igb_attr->dev_attr.show = igb_hwmon_show_location;
+		snprintf(igb_attr->name, sizeof(igb_attr->name),
+			 "temp%u_label", offset);
+		break;
+	case IGB_HWMON_TYPE_TEMP:
+		igb_attr->dev_attr.show = igb_hwmon_show_temp;
+		snprintf(igb_attr->name, sizeof(igb_attr->name),
+			 "temp%u_input", offset);
+		break;
+	case IGB_HWMON_TYPE_CAUTION:
+		igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
+		snprintf(igb_attr->name, sizeof(igb_attr->name),
+			 "temp%u_max", offset);
+		break;
+	case IGB_HWMON_TYPE_MAX:
+		igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
+		snprintf(igb_attr->name, sizeof(igb_attr->name),
+			 "temp%u_crit", offset);
+		break;
+	default:
+		rc = -EPERM;
+		return rc;
+	}
+
+	/* These always the same regardless of type */
+	igb_attr->sensor =
+		&adapter->hw.mac.thermal_sensor_data.sensor[offset];
+	igb_attr->hw = &adapter->hw;
+	igb_attr->dev_attr.store = NULL;
+	igb_attr->dev_attr.attr.mode = S_IRUGO;
+	igb_attr->dev_attr.attr.name = igb_attr->name;
+	sysfs_attr_init(&igb_attr->dev_attr.attr);
+	rc = device_create_file(&adapter->pdev->dev,
+				&igb_attr->dev_attr);
+	if (rc == 0)
+		++adapter->igb_hwmon_buff.n_hwmon;
+
+	return rc;
+}
+
+static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
+{
+	int i;
+
+	if (adapter == NULL)
+		return;
+
+	for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) {
+		device_remove_file(&adapter->pdev->dev,
+			   &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr);
+	}
+
+	kfree(adapter->igb_hwmon_buff.hwmon_list);
+
+	if (adapter->igb_hwmon_buff.device)
+		hwmon_device_unregister(adapter->igb_hwmon_buff.device);
+}
+
+/* called from igb_main.c */
+void igb_sysfs_exit(struct igb_adapter *adapter)
+{
+	igb_sysfs_del_adapter(adapter);
+}
+
+/* called from igb_main.c */
+int igb_sysfs_init(struct igb_adapter *adapter)
+{
+	struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff;
+	unsigned int i;
+	int n_attrs;
+	int rc = 0;
+
+	/* If this method isn't defined we don't support thermals */
+	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
+		goto exit;
+
+	/* Don't create thermal hwmon interface if no sensors present */
+	rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
+		if (rc)
+			goto exit;
+
+	/* Allocation space for max attributes
+	 * max num sensors * values (loc, temp, max, caution)
+	 */
+	n_attrs = E1000_MAX_SENSORS * 4;
+	igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
+					  GFP_KERNEL);
+	if (!igb_hwmon->hwmon_list) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev);
+	if (IS_ERR(igb_hwmon->device)) {
+		rc = PTR_ERR(igb_hwmon->device);
+		goto err;
+	}
+
+	for (i = 0; i < E1000_MAX_SENSORS; i++) {
+
+		/* Only create hwmon sysfs entries for sensors that have
+		 * meaningful data.
+		 */
+		if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
+			continue;
+
+		/* Bail if any hwmon attr struct fails to initialize */
+		rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
+		rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
+		rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
+		rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
+		if (rc)
+			goto err;
+	}
+
+	goto exit;
+
+err:
+	igb_sysfs_del_adapter(adapter);
+exit:
+	return rc;
+}
+#endif
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 31cfe2e..ed79a1c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2012 Intel Corporation.
+  Copyright(c) 2007-2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -57,6 +57,7 @@
 #ifdef CONFIG_IGB_DCA
 #include <linux/dca.h>
 #endif
+#include <linux/i2c.h>
 #include "igb.h"
 
 #define MAJ 4
@@ -68,7 +69,8 @@
 char igb_driver_version[] = DRV_VERSION;
 static const char igb_driver_string[] =
 				"Intel(R) Gigabit Ethernet Network Driver";
-static const char igb_copyright[] = "Copyright (c) 2007-2012 Intel Corporation.";
+static const char igb_copyright[] =
+				"Copyright (c) 2007-2013 Intel Corporation.";
 
 static const struct e1000_info *igb_info_tbl[] = {
 	[board_82575] = &e1000_82575_info,
@@ -193,6 +195,7 @@
 };
 #endif
 static void igb_shutdown(struct pci_dev *);
+static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
 #ifdef CONFIG_IGB_DCA
 static int igb_notify_dca(struct notifier_block *, unsigned long, void *);
 static struct notifier_block dca_notifier = {
@@ -234,6 +237,7 @@
 	.driver.pm = &igb_pm_ops,
 #endif
 	.shutdown = igb_shutdown,
+	.sriov_configure = igb_pci_sriov_configure,
 	.err_handler = &igb_err_handler
 };
 
@@ -565,6 +569,91 @@
 	return;
 }
 
+/*  igb_get_i2c_data - Reads the I2C SDA data bit
+ *  @hw: pointer to hardware structure
+ *  @i2cctl: Current value of I2CCTL register
+ *
+ *  Returns the I2C data bit value
+ */
+static int igb_get_i2c_data(void *data)
+{
+	struct igb_adapter *adapter = (struct igb_adapter *)data;
+	struct e1000_hw *hw = &adapter->hw;
+	s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+	return ((i2cctl & E1000_I2C_DATA_IN) != 0);
+}
+
+/* igb_set_i2c_data - Sets the I2C data bit
+ *  @data: pointer to hardware structure
+ *  @state: I2C data value (0 or 1) to set
+ *
+ *  Sets the I2C data bit
+ */
+static void igb_set_i2c_data(void *data, int state)
+{
+	struct igb_adapter *adapter = (struct igb_adapter *)data;
+	struct e1000_hw *hw = &adapter->hw;
+	s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+	if (state)
+		i2cctl |= E1000_I2C_DATA_OUT;
+	else
+		i2cctl &= ~E1000_I2C_DATA_OUT;
+
+	i2cctl &= ~E1000_I2C_DATA_OE_N;
+	i2cctl |= E1000_I2C_CLK_OE_N;
+	wr32(E1000_I2CPARAMS, i2cctl);
+	wrfl();
+
+}
+
+/* igb_set_i2c_clk - Sets the I2C SCL clock
+ *  @data: pointer to hardware structure
+ *  @state: state to set clock
+ *
+ *  Sets the I2C clock line to state
+ */
+static void igb_set_i2c_clk(void *data, int state)
+{
+	struct igb_adapter *adapter = (struct igb_adapter *)data;
+	struct e1000_hw *hw = &adapter->hw;
+	s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+	if (state) {
+		i2cctl |= E1000_I2C_CLK_OUT;
+		i2cctl &= ~E1000_I2C_CLK_OE_N;
+	} else {
+		i2cctl &= ~E1000_I2C_CLK_OUT;
+		i2cctl &= ~E1000_I2C_CLK_OE_N;
+	}
+	wr32(E1000_I2CPARAMS, i2cctl);
+	wrfl();
+}
+
+/* igb_get_i2c_clk - Gets the I2C SCL clock state
+ *  @data: pointer to hardware structure
+ *
+ *  Gets the I2C clock state
+ */
+static int igb_get_i2c_clk(void *data)
+{
+	struct igb_adapter *adapter = (struct igb_adapter *)data;
+	struct e1000_hw *hw = &adapter->hw;
+	s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+	return ((i2cctl & E1000_I2C_CLK_IN) != 0);
+}
+
+static const struct i2c_algo_bit_data igb_i2c_algo = {
+	.setsda		= igb_set_i2c_data,
+	.setscl		= igb_set_i2c_clk,
+	.getsda		= igb_get_i2c_data,
+	.getscl		= igb_get_i2c_clk,
+	.udelay		= 5,
+	.timeout	= 20,
+};
+
 /**
  * igb_get_hw_dev - return device
  * used by hardware layer to print debugging information
@@ -1708,6 +1797,18 @@
 		igb_force_mac_fc(hw);
 
 	igb_init_dmac(adapter, pba);
+#ifdef CONFIG_IGB_HWMON
+	/* Re-initialize the thermal sensor on i350 devices. */
+	if (!test_bit(__IGB_DOWN, &adapter->state)) {
+		if (mac->type == e1000_i350 && hw->bus.func == 0) {
+			/* If present, re-initialize the external thermal sensor
+			 * interface.
+			 */
+			if (adapter->ets)
+				mac->ops.init_thermal_sensor_thresh(hw);
+		}
+	}
+#endif
 	if (!netif_running(adapter->netdev))
 		igb_power_down_link(adapter);
 
@@ -1822,6 +1923,37 @@
 	return;
 }
 
+static const struct i2c_board_info i350_sensor_info = {
+	I2C_BOARD_INFO("i350bb", 0Xf8),
+};
+
+/*  igb_init_i2c - Init I2C interface
+ *  @adapter: pointer to adapter structure
+ *
+ */
+static s32 igb_init_i2c(struct igb_adapter *adapter)
+{
+	s32 status = E1000_SUCCESS;
+
+	/* I2C interface supported on i350 devices */
+	if (adapter->hw.mac.type != e1000_i350)
+		return E1000_SUCCESS;
+
+	/* Initialize the i2c bus which is controlled by the registers.
+	 * This bus will use the i2c_algo_bit structue that implements
+	 * the protocol through toggling of the 4 bits in the register.
+	 */
+	adapter->i2c_adap.owner = THIS_MODULE;
+	adapter->i2c_algo = igb_i2c_algo;
+	adapter->i2c_algo.data = adapter;
+	adapter->i2c_adap.algo_data = &adapter->i2c_algo;
+	adapter->i2c_adap.dev.parent = &adapter->pdev->dev;
+	strlcpy(adapter->i2c_adap.name, "igb BB",
+		sizeof(adapter->i2c_adap.name));
+	status = i2c_bit_add_bus(&adapter->i2c_adap);
+	return status;
+}
+
 /**
  * igb_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -2022,9 +2154,8 @@
 		dev_err(&pdev->dev, "NVM Read Error\n");
 
 	memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
-	memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len);
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		dev_err(&pdev->dev, "Invalid MAC Address\n");
 		err = -EIO;
 		goto err_eeprom;
@@ -2115,6 +2246,13 @@
 	/* reset the hardware with the new settings */
 	igb_reset(adapter);
 
+	/* Init the I2C interface */
+	err = igb_init_i2c(adapter);
+	if (err) {
+		dev_err(&pdev->dev, "failed to init i2c interface\n");
+		goto err_eeprom;
+	}
+
 	/* let the f/w know that the h/w is now under the control of the
 	 * driver. */
 	igb_get_hw_control(adapter);
@@ -2135,7 +2273,27 @@
 	}
 
 #endif
+#ifdef CONFIG_IGB_HWMON
+	/* Initialize the thermal sensor on i350 devices. */
+	if (hw->mac.type == e1000_i350 && hw->bus.func == 0) {
+		u16 ets_word;
 
+		/*
+		 * Read the NVM to determine if this i350 device supports an
+		 * external thermal sensor.
+		 */
+		hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_word);
+		if (ets_word != 0x0000 && ets_word != 0xFFFF)
+			adapter->ets = true;
+		else
+			adapter->ets = false;
+		if (igb_sysfs_init(adapter))
+			dev_err(&pdev->dev,
+				"failed to allocate sysfs resources\n");
+	} else {
+		adapter->ets = false;
+	}
+#endif
 	/* do hw tstamp init after resetting */
 	igb_ptp_init(adapter);
 
@@ -2176,6 +2334,7 @@
 
 err_register:
 	igb_release_hw_control(adapter);
+	memset(&adapter->i2c_adap, 0, sizeof(adapter->i2c_adap));
 err_eeprom:
 	if (!igb_check_reset_block(hw))
 		igb_reset_phy(hw);
@@ -2196,6 +2355,111 @@
 	return err;
 }
 
+#ifdef CONFIG_PCI_IOV
+static int  igb_disable_sriov(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* reclaim resources allocated to VFs */
+	if (adapter->vf_data) {
+		/* disable iov and allow time for transactions to clear */
+		if (igb_vfs_are_assigned(adapter)) {
+			dev_warn(&pdev->dev,
+				 "Cannot deallocate SR-IOV virtual functions while they are assigned - VFs will not be deallocated\n");
+			return -EPERM;
+		} else {
+			pci_disable_sriov(pdev);
+			msleep(500);
+		}
+
+		kfree(adapter->vf_data);
+		adapter->vf_data = NULL;
+		adapter->vfs_allocated_count = 0;
+		wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+		wrfl();
+		msleep(100);
+		dev_info(&pdev->dev, "IOV Disabled\n");
+
+		/* Re-enable DMA Coalescing flag since IOV is turned off */
+		adapter->flags |= IGB_FLAG_DMAC;
+	}
+
+	return 0;
+}
+
+static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	int old_vfs = pci_num_vf(pdev);
+	int err = 0;
+	int i;
+
+	if (!num_vfs)
+		goto out;
+	else if (old_vfs && old_vfs == num_vfs)
+		goto out;
+	else if (old_vfs && old_vfs != num_vfs)
+		err = igb_disable_sriov(pdev);
+
+	if (err)
+		goto out;
+
+	if (num_vfs > 7) {
+		err = -EPERM;
+		goto out;
+	}
+
+	adapter->vfs_allocated_count = num_vfs;
+
+	adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
+				sizeof(struct vf_data_storage), GFP_KERNEL);
+
+	/* if allocation failed then we do not support SR-IOV */
+	if (!adapter->vf_data) {
+		adapter->vfs_allocated_count = 0;
+		dev_err(&pdev->dev,
+			"Unable to allocate memory for VF Data Storage\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = pci_enable_sriov(pdev, adapter->vfs_allocated_count);
+	if (err)
+		goto err_out;
+
+	dev_info(&pdev->dev, "%d VFs allocated\n",
+		 adapter->vfs_allocated_count);
+	for (i = 0; i < adapter->vfs_allocated_count; i++)
+		igb_vf_configure(adapter, i);
+
+	/* DMA Coalescing is not supported in IOV mode. */
+	adapter->flags &= ~IGB_FLAG_DMAC;
+	goto out;
+
+err_out:
+	kfree(adapter->vf_data);
+	adapter->vf_data = NULL;
+	adapter->vfs_allocated_count = 0;
+out:
+	return err;
+}
+
+#endif
+/*
+ *  igb_remove_i2c - Cleanup  I2C interface
+ *  @adapter: pointer to adapter structure
+ *
+ */
+static void igb_remove_i2c(struct igb_adapter *adapter)
+{
+
+	/* free the adapter bus structure */
+	i2c_del_adapter(&adapter->i2c_adap);
+}
+
 /**
  * igb_remove - Device Removal Routine
  * @pdev: PCI device information struct
@@ -2212,8 +2476,11 @@
 	struct e1000_hw *hw = &adapter->hw;
 
 	pm_runtime_get_noresume(&pdev->dev);
+#ifdef CONFIG_IGB_HWMON
+	igb_sysfs_exit(adapter);
+#endif
+	igb_remove_i2c(adapter);
 	igb_ptp_stop(adapter);
-
 	/*
 	 * The watchdog timer may be rescheduled, so explicitly
 	 * disable watchdog from being rescheduled.
@@ -2243,23 +2510,7 @@
 	igb_clear_interrupt_scheme(adapter);
 
 #ifdef CONFIG_PCI_IOV
-	/* reclaim resources allocated to VFs */
-	if (adapter->vf_data) {
-		/* disable iov and allow time for transactions to clear */
-		if (igb_vfs_are_assigned(adapter)) {
-			dev_info(&pdev->dev, "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
-		} else {
-			pci_disable_sriov(pdev);
-			msleep(500);
-		}
-
-		kfree(adapter->vf_data);
-		adapter->vf_data = NULL;
-		wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
-		wrfl();
-		msleep(100);
-		dev_info(&pdev->dev, "IOV Disabled\n");
-	}
+	igb_disable_sriov(pdev);
 #endif
 
 	iounmap(hw->hw_addr);
@@ -2290,103 +2541,22 @@
 #ifdef CONFIG_PCI_IOV
 	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_hw *hw = &adapter->hw;
-	int old_vfs = pci_num_vf(adapter->pdev);
-	int i;
 
 	/* Virtualization features not supported on i210 family. */
 	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
 		return;
 
-	if (old_vfs) {
-		dev_info(&pdev->dev, "%d pre-allocated VFs found - override "
-			 "max_vfs setting of %d\n", old_vfs, max_vfs);
-		adapter->vfs_allocated_count = old_vfs;
-	}
+	igb_enable_sriov(pdev, max_vfs);
+	pci_sriov_set_totalvfs(pdev, 7);
 
-	if (!adapter->vfs_allocated_count)
-		return;
-
-	adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
-				sizeof(struct vf_data_storage), GFP_KERNEL);
-
-	/* if allocation failed then we do not support SR-IOV */
-	if (!adapter->vf_data) {
-		adapter->vfs_allocated_count = 0;
-		dev_err(&pdev->dev, "Unable to allocate memory for VF "
-			"Data Storage\n");
-		goto out;
-	}
-
-	if (!old_vfs) {
-		if (pci_enable_sriov(pdev, adapter->vfs_allocated_count))
-			goto err_out;
-	}
-	dev_info(&pdev->dev, "%d VFs allocated\n",
-		 adapter->vfs_allocated_count);
-	for (i = 0; i < adapter->vfs_allocated_count; i++)
-		igb_vf_configure(adapter, i);
-
-	/* DMA Coalescing is not supported in IOV mode. */
-	adapter->flags &= ~IGB_FLAG_DMAC;
-	goto out;
-err_out:
-	kfree(adapter->vf_data);
-	adapter->vf_data = NULL;
-	adapter->vfs_allocated_count = 0;
-out:
-	return;
 #endif /* CONFIG_PCI_IOV */
 }
 
-/**
- * igb_sw_init - Initialize general software structures (struct igb_adapter)
- * @adapter: board private structure to initialize
- *
- * igb_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
- **/
-static int igb_sw_init(struct igb_adapter *adapter)
+static void igb_init_queue_configuration(struct igb_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	struct net_device *netdev = adapter->netdev;
-	struct pci_dev *pdev = adapter->pdev;
 	u32 max_rss_queues;
 
-	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
-
-	/* set default ring sizes */
-	adapter->tx_ring_count = IGB_DEFAULT_TXD;
-	adapter->rx_ring_count = IGB_DEFAULT_RXD;
-
-	/* set default ITR values */
-	adapter->rx_itr_setting = IGB_DEFAULT_ITR;
-	adapter->tx_itr_setting = IGB_DEFAULT_ITR;
-
-	/* set default work limits */
-	adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
-
-	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
-				  VLAN_HLEN;
-	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
-
-	spin_lock_init(&adapter->stats64_lock);
-#ifdef CONFIG_PCI_IOV
-	switch (hw->mac.type) {
-	case e1000_82576:
-	case e1000_i350:
-		if (max_vfs > 7) {
-			dev_warn(&pdev->dev,
-				 "Maximum of 7 VFs per PF, using max\n");
-			adapter->vfs_allocated_count = 7;
-		} else
-			adapter->vfs_allocated_count = max_vfs;
-		break;
-	default:
-		break;
-	}
-#endif /* CONFIG_PCI_IOV */
-
 	/* Determine the maximum number of RSS queues supported. */
 	switch (hw->mac.type) {
 	case e1000_i211:
@@ -2445,11 +2615,64 @@
 			adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
 		break;
 	}
+}
+
+/**
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igb_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int igb_sw_init(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+	/* set default ring sizes */
+	adapter->tx_ring_count = IGB_DEFAULT_TXD;
+	adapter->rx_ring_count = IGB_DEFAULT_RXD;
+
+	/* set default ITR values */
+	adapter->rx_itr_setting = IGB_DEFAULT_ITR;
+	adapter->tx_itr_setting = IGB_DEFAULT_ITR;
+
+	/* set default work limits */
+	adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
+
+	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
+				  VLAN_HLEN;
+	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+	spin_lock_init(&adapter->stats64_lock);
+#ifdef CONFIG_PCI_IOV
+	switch (hw->mac.type) {
+	case e1000_82576:
+	case e1000_i350:
+		if (max_vfs > 7) {
+			dev_warn(&pdev->dev,
+				 "Maximum of 7 VFs per PF, using max\n");
+			adapter->vfs_allocated_count = 7;
+		} else
+			adapter->vfs_allocated_count = max_vfs;
+		if (adapter->vfs_allocated_count)
+			dev_warn(&pdev->dev,
+				 "Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
+		break;
+	default:
+		break;
+	}
+#endif /* CONFIG_PCI_IOV */
+
+	igb_init_queue_configuration(adapter);
 
 	/* Setup and initialize a copy of the hw vlan table array */
-	adapter->shadow_vfta = kzalloc(sizeof(u32) *
-				E1000_VLAN_FILTER_TBL_SIZE,
-				GFP_ATOMIC);
+	adapter->shadow_vfta = kcalloc(E1000_VLAN_FILTER_TBL_SIZE, sizeof(u32),
+				       GFP_ATOMIC);
 
 	/* This call may decrease the number of queues */
 	if (igb_init_interrupt_scheme(adapter, true)) {
@@ -3131,6 +3354,20 @@
 	wr32(E1000_RXDCTL(reg_idx), rxdctl);
 }
 
+static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
+				  struct igb_ring *rx_ring)
+{
+#define IGB_MAX_BUILD_SKB_SIZE \
+	(SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) - \
+	 (NET_SKB_PAD + NET_IP_ALIGN + IGB_TS_HDR_LEN))
+
+	/* set build_skb flag */
+	if (adapter->max_frame_size <= IGB_MAX_BUILD_SKB_SIZE)
+		set_ring_build_skb_enabled(rx_ring);
+	else
+		clear_ring_build_skb_enabled(rx_ring);
+}
+
 /**
  * igb_configure_rx - Configure receive Unit after Reset
  * @adapter: board private structure
@@ -3150,8 +3387,11 @@
 
 	/* Setup the HW Rx Head and Tail Descriptor Pointers and
 	 * the Base and Length of the Rx Descriptor Ring */
-	for (i = 0; i < adapter->num_rx_queues; i++)
-		igb_configure_rx_ring(adapter, adapter->rx_ring[i]);
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct igb_ring *rx_ring = adapter->rx_ring[i];
+		igb_set_rx_buffer_len(adapter, rx_ring);
+		igb_configure_rx_ring(adapter, rx_ring);
+	}
 }
 
 /**
@@ -3768,6 +4008,7 @@
 	}
 
 	igb_spoof_check(adapter);
+	igb_ptp_rx_hang(adapter);
 
 	/* Reset the timer */
 	if (!test_bit(__IGB_DOWN, &adapter->state))
@@ -4193,13 +4434,6 @@
 	tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
-/*
- * The largest size we can write to the descriptor is 65535.  In order to
- * maintain a power of two alignment we have to limit ourselves to 32K.
- */
-#define IGB_MAX_TXD_PWR	15
-#define IGB_MAX_DATA_PER_TXD	(1<<IGB_MAX_TXD_PWR)
-
 static void igb_tx_map(struct igb_ring *tx_ring,
 		       struct igb_tx_buffer *first,
 		       const u8 hdr_len)
@@ -4368,15 +4602,25 @@
 	struct igb_tx_buffer *first;
 	int tso;
 	u32 tx_flags = 0;
+	u16 count = TXD_USE_COUNT(skb_headlen(skb));
 	__be16 protocol = vlan_get_protocol(skb);
 	u8 hdr_len = 0;
 
-	/* need: 1 descriptor per page,
+	/* need: 1 descriptor per page * PAGE_SIZE/IGB_MAX_DATA_PER_TXD,
+	 *       + 1 desc for skb_headlen/IGB_MAX_DATA_PER_TXD,
 	 *       + 2 desc gap to keep tail from touching head,
-	 *       + 1 desc for skb->data,
 	 *       + 1 desc for context descriptor,
-	 * otherwise try next time */
-	if (igb_maybe_stop_tx(tx_ring, skb_shinfo(skb)->nr_frags + 4)) {
+	 * otherwise try next time
+	 */
+	if (NETDEV_FRAG_PAGE_MAX_SIZE > IGB_MAX_DATA_PER_TXD) {
+		unsigned short f;
+		for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+			count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+	} else {
+		count += skb_shinfo(skb)->nr_frags;
+	}
+
+	if (igb_maybe_stop_tx(tx_ring, count + 3)) {
 		/* this is a hard error */
 		return NETDEV_TX_BUSY;
 	}
@@ -4387,12 +4631,15 @@
 	first->bytecount = skb->len;
 	first->gso_segs = 1;
 
+	skb_tx_timestamp(skb);
+
 	if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
 		     !(adapter->ptp_tx_skb))) {
 		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 		tx_flags |= IGB_TX_FLAGS_TSTAMP;
 
 		adapter->ptp_tx_skb = skb_get(skb);
+		adapter->ptp_tx_start = jiffies;
 		if (adapter->hw.mac.type == e1000_82576)
 			schedule_work(&adapter->ptp_tx_work);
 	}
@@ -4415,7 +4662,7 @@
 	igb_tx_map(tx_ring, first, hdr_len);
 
 	/* Make sure there is space in the ring for the next send. */
-	igb_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 4);
+	igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
 	return NETDEV_TX_OK;
 
@@ -4969,7 +5216,7 @@
 {
 	unsigned char mac_addr[ETH_ALEN];
 
-	eth_random_addr(mac_addr);
+	eth_zero_addr(mac_addr);
 	igb_set_vf_mac(adapter, vf, mac_addr);
 
 	return 0;
@@ -5322,9 +5569,9 @@
 {
 	unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
 
-	/* generate a new mac address as we were hotplug removed/added */
+	/* clear mac address as we were hotplug removed/added */
 	if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC))
-		eth_random_addr(vf_mac);
+		eth_zero_addr(vf_mac);
 
 	/* process remaining reset events */
 	igb_vf_reset(adapter, vf);
@@ -5703,7 +5950,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		rmb();
+		read_barrier_depends();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
@@ -5819,9 +6066,10 @@
 		}
 	}
 
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
 	if (unlikely(total_packets &&
 		     netif_carrier_ok(tx_ring->netdev) &&
-		     igb_desc_unused(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
+		     igb_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) {
 		/* Make sure that anybody stopping the queue after this
 		 * sees the new next_to_clean.
 		 */
@@ -5870,6 +6118,41 @@
 					 DMA_FROM_DEVICE);
 }
 
+static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
+				  struct page *page,
+				  unsigned int truesize)
+{
+	/* avoid re-using remote pages */
+	if (unlikely(page_to_nid(page) != numa_node_id()))
+		return false;
+
+#if (PAGE_SIZE < 8192)
+	/* if we are only owner of page we can reuse it */
+	if (unlikely(page_count(page) != 1))
+		return false;
+
+	/* flip page offset to other buffer */
+	rx_buffer->page_offset ^= IGB_RX_BUFSZ;
+
+	/* since we are the only owner of the page and we need to
+	 * increment it, just set the value to 2 in order to avoid
+	 * an unnecessary locked operation
+	 */
+	atomic_set(&page->_count, 2);
+#else
+	/* move offset up to the next cache line */
+	rx_buffer->page_offset += truesize;
+
+	if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ))
+		return false;
+
+	/* bump ref count on page before it is given to the stack */
+	get_page(page);
+#endif
+
+	return true;
+}
+
 /**
  * igb_add_rx_frag - Add contents of Rx buffer to sk_buff
  * @rx_ring: rx descriptor ring to transact packets on
@@ -5892,6 +6175,11 @@
 {
 	struct page *page = rx_buffer->page;
 	unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
+#if (PAGE_SIZE < 8192)
+	unsigned int truesize = IGB_RX_BUFSZ;
+#else
+	unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
+#endif
 
 	if ((size <= IGB_RX_HDR_LEN) && !skb_is_nonlinear(skb)) {
 		unsigned char *va = page_address(page) + rx_buffer->page_offset;
@@ -5914,38 +6202,88 @@
 	}
 
 	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
-			rx_buffer->page_offset, size, IGB_RX_BUFSZ);
+			rx_buffer->page_offset, size, truesize);
 
-	/* avoid re-using remote pages */
-	if (unlikely(page_to_nid(page) != numa_node_id()))
-		return false;
+	return igb_can_reuse_rx_page(rx_buffer, page, truesize);
+}
 
+static struct sk_buff *igb_build_rx_buffer(struct igb_ring *rx_ring,
+					   union e1000_adv_rx_desc *rx_desc)
+{
+	struct igb_rx_buffer *rx_buffer;
+	struct sk_buff *skb;
+	struct page *page;
+	void *page_addr;
+	unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
 #if (PAGE_SIZE < 8192)
-	/* if we are only owner of page we can reuse it */
-	if (unlikely(page_count(page) != 1))
-		return false;
-
-	/* flip page offset to other buffer */
-	rx_buffer->page_offset ^= IGB_RX_BUFSZ;
-
-	/*
-	 * since we are the only owner of the page and we need to
-	 * increment it, just set the value to 2 in order to avoid
-	 * an unnecessary locked operation
-	 */
-	atomic_set(&page->_count, 2);
+	unsigned int truesize = IGB_RX_BUFSZ;
 #else
-	/* move offset up to the next cache line */
-	rx_buffer->page_offset += SKB_DATA_ALIGN(size);
-
-	if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ))
-		return false;
-
-	/* bump ref count on page before it is given to the stack */
-	get_page(page);
+	unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
+				SKB_DATA_ALIGN(NET_SKB_PAD +
+					       NET_IP_ALIGN +
+					       size);
 #endif
 
-	return true;
+	/* If we spanned a buffer we have a huge mess so test for it */
+	BUG_ON(unlikely(!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)));
+
+	/* Guarantee this function can be used by verifying buffer sizes */
+	BUILD_BUG_ON(SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) < (NET_SKB_PAD +
+							NET_IP_ALIGN +
+							IGB_TS_HDR_LEN +
+							ETH_FRAME_LEN +
+							ETH_FCS_LEN));
+
+	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+	page = rx_buffer->page;
+	prefetchw(page);
+
+	page_addr = page_address(page) + rx_buffer->page_offset;
+
+	/* prefetch first cache line of first page */
+	prefetch(page_addr + NET_SKB_PAD + NET_IP_ALIGN);
+#if L1_CACHE_BYTES < 128
+	prefetch(page_addr + L1_CACHE_BYTES + NET_SKB_PAD + NET_IP_ALIGN);
+#endif
+
+	/* build an skb to around the page buffer */
+	skb = build_skb(page_addr, truesize);
+	if (unlikely(!skb)) {
+		rx_ring->rx_stats.alloc_failed++;
+		return NULL;
+	}
+
+	/* we are reusing so sync this buffer for CPU use */
+	dma_sync_single_range_for_cpu(rx_ring->dev,
+				      rx_buffer->dma,
+				      rx_buffer->page_offset,
+				      IGB_RX_BUFSZ,
+				      DMA_FROM_DEVICE);
+
+	/* update pointers within the skb to store the data */
+	skb_reserve(skb, NET_IP_ALIGN + NET_SKB_PAD);
+	__skb_put(skb, size);
+
+	/* pull timestamp out of packet data */
+	if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
+		igb_ptp_rx_pktstamp(rx_ring->q_vector, skb->data, skb);
+		__skb_pull(skb, IGB_TS_HDR_LEN);
+	}
+
+	if (igb_can_reuse_rx_page(rx_buffer, page, truesize)) {
+		/* hand second half of page back to the ring */
+		igb_reuse_rx_page(rx_ring, rx_buffer);
+	} else {
+		/* we are not reusing the buffer so unmap it */
+		dma_unmap_page(rx_ring->dev, rx_buffer->dma,
+			       PAGE_SIZE, DMA_FROM_DEVICE);
+	}
+
+	/* clear contents of buffer_info */
+	rx_buffer->dma = 0;
+	rx_buffer->page = NULL;
+
+	return skb;
 }
 
 static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
@@ -5957,13 +6295,6 @@
 
 	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
 
-	/*
-	 * This memory barrier is needed to keep us from reading
-	 * any other fields out of the rx_desc until we know the
-	 * RXD_STAT_DD bit is set
-	 */
-	rmb();
-
 	page = rx_buffer->page;
 	prefetchw(page);
 
@@ -6363,8 +6694,17 @@
 		if (!igb_test_staterr(rx_desc, E1000_RXD_STAT_DD))
 			break;
 
+		/* This memory barrier is needed to keep us from reading
+		 * any other fields out of the rx_desc until we know the
+		 * RXD_STAT_DD bit is set
+		 */
+		rmb();
+
 		/* retrieve a buffer from the ring */
-		skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
+		if (ring_uses_build_skb(rx_ring))
+			skb = igb_build_rx_buffer(rx_ring, rx_desc);
+		else
+			skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
 
 		/* exit if we failed to retrieve a buffer */
 		if (!skb)
@@ -6451,6 +6791,14 @@
 	return true;
 }
 
+static inline unsigned int igb_rx_offset(struct igb_ring *rx_ring)
+{
+	if (ring_uses_build_skb(rx_ring))
+		return NET_SKB_PAD + NET_IP_ALIGN;
+	else
+		return 0;
+}
+
 /**
  * igb_alloc_rx_buffers - Replace used receive buffers; packet split
  * @adapter: address of board private structure
@@ -6477,7 +6825,9 @@
 		 * Refresh the desc even if buffer_addrs didn't change
 		 * because each write-back erases this info.
 		 */
-		rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
+		rx_desc->read.pkt_addr = cpu_to_le64(bi->dma +
+						     bi->page_offset +
+						     igb_rx_offset(rx_ring));
 
 		rx_desc++;
 		bi++;
@@ -6903,6 +7253,72 @@
 	}
 }
 
+#ifdef CONFIG_PCI_IOV
+static int igb_sriov_reinit(struct pci_dev *dev)
+{
+	struct net_device *netdev = pci_get_drvdata(dev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct pci_dev *pdev = adapter->pdev;
+
+	rtnl_lock();
+
+	if (netif_running(netdev))
+		igb_close(netdev);
+
+	igb_clear_interrupt_scheme(adapter);
+
+	igb_init_queue_configuration(adapter);
+
+	if (igb_init_interrupt_scheme(adapter, true)) {
+		dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+		return -ENOMEM;
+	}
+
+	if (netif_running(netdev))
+		igb_open(netdev);
+
+	rtnl_unlock();
+
+	return 0;
+}
+
+static int igb_pci_disable_sriov(struct pci_dev *dev)
+{
+	int err = igb_disable_sriov(dev);
+
+	if (!err)
+		err = igb_sriov_reinit(dev);
+
+	return err;
+}
+
+static int igb_pci_enable_sriov(struct pci_dev *dev, int num_vfs)
+{
+	int err = igb_enable_sriov(dev, num_vfs);
+
+	if (err)
+		goto out;
+
+	err = igb_sriov_reinit(dev);
+	if (!err)
+		return num_vfs;
+
+out:
+	return err;
+}
+
+#endif
+static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+	if (num_vfs == 0)
+		return igb_pci_disable_sriov(dev);
+	else
+		return igb_pci_enable_sriov(dev, num_vfs);
+#endif
+	return 0;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Polling 'interrupt' - used by things like netconsole to send skbs
@@ -7308,4 +7724,133 @@
 	}
 }
 
+static DEFINE_SPINLOCK(i2c_clients_lock);
+
+/*  igb_get_i2c_client - returns matching client
+ *  in adapters's client list.
+ *  @adapter: adapter struct
+ *  @dev_addr: device address of i2c needed.
+ */
+static struct i2c_client *
+igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr)
+{
+	ulong flags;
+	struct igb_i2c_client_list *client_list;
+	struct i2c_client *client = NULL;
+	struct i2c_board_info client_info = {
+		I2C_BOARD_INFO("igb", 0x00),
+	};
+
+	spin_lock_irqsave(&i2c_clients_lock, flags);
+	client_list = adapter->i2c_clients;
+
+	/* See if we already have an i2c_client */
+	while (client_list) {
+		if (client_list->client->addr == (dev_addr >> 1)) {
+			client = client_list->client;
+			goto exit;
+		} else {
+			client_list = client_list->next;
+		}
+	}
+
+	/* no client_list found, create a new one */
+	client_list = kzalloc(sizeof(*client_list), GFP_ATOMIC);
+	if (client_list == NULL)
+		goto exit;
+
+	/* dev_addr passed to us is left-shifted by 1 bit
+	 * i2c_new_device call expects it to be flush to the right.
+	 */
+	client_info.addr = dev_addr >> 1;
+	client_info.platform_data = adapter;
+	client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info);
+	if (client_list->client == NULL) {
+		dev_info(&adapter->pdev->dev,
+			"Failed to create new i2c device..\n");
+		goto err_no_client;
+	}
+
+	/* insert new client at head of list */
+	client_list->next = adapter->i2c_clients;
+	adapter->i2c_clients = client_list;
+
+	client = client_list->client;
+	goto exit;
+
+err_no_client:
+	kfree(client_list);
+exit:
+	spin_unlock_irqrestore(&i2c_clients_lock, flags);
+	return client;
+}
+
+/*  igb_read_i2c_byte - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @dev_addr: device address
+ *  @data: value read
+ *
+ *  Performs byte read operation over I2C interface at
+ *  a specified device address.
+ */
+s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+				u8 dev_addr, u8 *data)
+{
+	struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
+	struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr);
+	s32 status;
+	u16 swfw_mask = 0;
+
+	if (!this_client)
+		return E1000_ERR_I2C;
+
+	swfw_mask = E1000_SWFW_PHY0_SM;
+
+	if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)
+	    != E1000_SUCCESS)
+		return E1000_ERR_SWFW_SYNC;
+
+	status = i2c_smbus_read_byte_data(this_client, byte_offset);
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+	if (status < 0)
+		return E1000_ERR_I2C;
+	else {
+		*data = status;
+		return E1000_SUCCESS;
+	}
+}
+
+/*  igb_write_i2c_byte - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @dev_addr: device address
+ *  @data: value to write
+ *
+ *  Performs byte write operation over I2C interface at
+ *  a specified device address.
+ */
+s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+				 u8 dev_addr, u8 data)
+{
+	struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
+	struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr);
+	s32 status;
+	u16 swfw_mask = E1000_SWFW_PHY0_SM;
+
+	if (!this_client)
+		return E1000_ERR_I2C;
+
+	if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != E1000_SUCCESS)
+		return E1000_ERR_SWFW_SYNC;
+	status = i2c_smbus_write_byte_data(this_client, byte_offset, data);
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+	if (status)
+		return E1000_ERR_I2C;
+	else
+		return E1000_SUCCESS;
+
+}
 /* igb_main.c */
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index ab34297..0987822 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/pci.h>
+#include <linux/ptp_classify.h>
 
 #include "igb.h"
 
@@ -70,6 +71,7 @@
  */
 
 #define IGB_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 9)
+#define IGB_PTP_TX_TIMEOUT		(HZ * 15)
 #define INCPERIOD_82576			(1 << E1000_TIMINCA_16NS_SHIFT)
 #define INCVALUE_82576_MASK		((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
 #define INCVALUE_82576			(16 << IGB_82576_TSYNC_SHIFT)
@@ -396,6 +398,15 @@
 	if (!adapter->ptp_tx_skb)
 		return;
 
+	if (time_is_before_jiffies(adapter->ptp_tx_start +
+				   IGB_PTP_TX_TIMEOUT)) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+		adapter->tx_hwtstamp_timeouts++;
+		dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
+		return;
+	}
+
 	tsynctxctl = rd32(E1000_TSYNCTXCTL);
 	if (tsynctxctl & E1000_TSYNCTXCTL_VALID)
 		igb_ptp_tx_hwtstamp(adapter);
@@ -419,6 +430,51 @@
 }
 
 /**
+ * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
+ *
+ * This watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
+ */
+void igb_ptp_rx_hang(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct igb_ring *rx_ring;
+	u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL);
+	unsigned long rx_event;
+	int n;
+
+	if (hw->mac.type != e1000_82576)
+		return;
+
+	/* If we don't have a valid timestamp in the registers, just update the
+	 * timeout counter and exit
+	 */
+	if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) {
+		adapter->last_rx_ptp_check = jiffies;
+		return;
+	}
+
+	/* Determine the most recent watchdog or rx_timestamp event */
+	rx_event = adapter->last_rx_ptp_check;
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = adapter->rx_ring[n];
+		if (time_after(rx_ring->last_rx_timestamp, rx_event))
+			rx_event = rx_ring->last_rx_timestamp;
+	}
+
+	/* Only need to read the high RXSTMP register to clear the lock */
+	if (time_is_before_jiffies(rx_event + 5 * HZ)) {
+		rd32(E1000_RXSTMPH);
+		adapter->last_rx_ptp_check = jiffies;
+		adapter->rx_hwtstamp_cleared++;
+		dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang");
+	}
+}
+
+/**
  * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
  * @adapter: Board private structure.
  *
@@ -643,7 +699,6 @@
 	else
 		wr32(E1000_ETQF(3), 0);
 
-#define PTP_PORT 319
 	/* L4 Queue Filter[3]: filter by destination port and protocol */
 	if (is_l4) {
 		u32 ftqf = (IPPROTO_UDP /* UDP */
@@ -652,12 +707,12 @@
 			| E1000_FTQF_MASK); /* mask all inputs */
 		ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
 
-		wr32(E1000_IMIR(3), htons(PTP_PORT));
+		wr32(E1000_IMIR(3), htons(PTP_EV_PORT));
 		wr32(E1000_IMIREXT(3),
 		     (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
 		if (hw->mac.type == e1000_82576) {
 			/* enable source port check */
-			wr32(E1000_SPQF(3), htons(PTP_PORT));
+			wr32(E1000_SPQF(3), htons(PTP_EV_PORT));
 			ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
 		}
 		wr32(E1000_FTQF(3), ftqf);
@@ -801,6 +856,10 @@
 	}
 
 	cancel_work_sync(&adapter->ptp_tx_work);
+	if (adapter->ptp_tx_skb) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+	}
 
 	if (adapter->ptp_clock) {
 		ptp_clock_unregister(adapter->ptp_clock);
diff --git a/drivers/net/ethernet/intel/igbvf/igbvf.h b/drivers/net/ethernet/intel/igbvf/igbvf.h
index fdca7b6..a1463e3 100644
--- a/drivers/net/ethernet/intel/igbvf/igbvf.h
+++ b/drivers/net/ethernet/intel/igbvf/igbvf.h
@@ -127,8 +127,8 @@
 		/* Tx */
 		struct {
 			unsigned long time_stamp;
+			union e1000_adv_tx_desc *next_to_watch;
 			u16 length;
-			u16 next_to_watch;
 			u16 mapped_as_page;
 		};
 		/* Rx */
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 277f5df..d60cd43 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -797,20 +797,31 @@
 	struct sk_buff *skb;
 	union e1000_adv_tx_desc *tx_desc, *eop_desc;
 	unsigned int total_bytes = 0, total_packets = 0;
-	unsigned int i, eop, count = 0;
+	unsigned int i, count = 0;
 	bool cleaned = false;
 
 	i = tx_ring->next_to_clean;
-	eop = tx_ring->buffer_info[i].next_to_watch;
-	eop_desc = IGBVF_TX_DESC_ADV(*tx_ring, eop);
+	buffer_info = &tx_ring->buffer_info[i];
+	eop_desc = buffer_info->next_to_watch;
 
-	while ((eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)) &&
-	       (count < tx_ring->count)) {
-		rmb();	/* read buffer_info after eop_desc status */
+	do {
+		/* if next_to_watch is not set then there is no work pending */
+		if (!eop_desc)
+			break;
+
+		/* prevent any other reads prior to eop_desc */
+		read_barrier_depends();
+
+		/* if DD is not set pending work has not been completed */
+		if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
+			break;
+
+		/* clear next_to_watch to prevent false hangs */
+		buffer_info->next_to_watch = NULL;
+
 		for (cleaned = false; !cleaned; count++) {
 			tx_desc = IGBVF_TX_DESC_ADV(*tx_ring, i);
-			buffer_info = &tx_ring->buffer_info[i];
-			cleaned = (i == eop);
+			cleaned = (tx_desc == eop_desc);
 			skb = buffer_info->skb;
 
 			if (skb) {
@@ -831,10 +842,12 @@
 			i++;
 			if (i == tx_ring->count)
 				i = 0;
+
+			buffer_info = &tx_ring->buffer_info[i];
 		}
-		eop = tx_ring->buffer_info[i].next_to_watch;
-		eop_desc = IGBVF_TX_DESC_ADV(*tx_ring, eop);
-	}
+
+		eop_desc = buffer_info->next_to_watch;
+	} while (count < tx_ring->count);
 
 	tx_ring->next_to_clean = i;
 
@@ -1399,12 +1412,10 @@
 	int i;
 
 	if (!netdev_mc_empty(netdev)) {
-		mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
-		if (!mta_list) {
-			dev_err(&adapter->pdev->dev,
-			        "failed to allocate multicast filter list\n");
+		mta_list = kmalloc_array(netdev_mc_count(netdev), ETH_ALEN,
+					 GFP_ATOMIC);
+		if (!mta_list)
 			return;
-		}
 	}
 
 	/* prepare a packed array of only addresses. */
@@ -1738,7 +1749,6 @@
 		return -EADDRNOTAVAIL;
 
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	return 0;
 }
@@ -1964,7 +1974,6 @@
 	context_desc->seqnum_seed = 0;
 
 	buffer_info->time_stamp = jiffies;
-	buffer_info->next_to_watch = i;
 	buffer_info->dma = 0;
 	i++;
 	if (i == tx_ring->count)
@@ -2024,7 +2033,6 @@
 		context_desc->mss_l4len_idx = 0;
 
 		buffer_info->time_stamp = jiffies;
-		buffer_info->next_to_watch = i;
 		buffer_info->dma = 0;
 		i++;
 		if (i == tx_ring->count)
@@ -2064,8 +2072,7 @@
 
 static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
                                    struct igbvf_ring *tx_ring,
-                                   struct sk_buff *skb,
-                                   unsigned int first)
+				   struct sk_buff *skb)
 {
 	struct igbvf_buffer *buffer_info;
 	struct pci_dev *pdev = adapter->pdev;
@@ -2080,7 +2087,6 @@
 	buffer_info->length = len;
 	/* set time_stamp *before* dma to help avoid a possible race */
 	buffer_info->time_stamp = jiffies;
-	buffer_info->next_to_watch = i;
 	buffer_info->mapped_as_page = false;
 	buffer_info->dma = dma_map_single(&pdev->dev, skb->data, len,
 					  DMA_TO_DEVICE);
@@ -2103,7 +2109,6 @@
 		BUG_ON(len >= IGBVF_MAX_DATA_PER_TXD);
 		buffer_info->length = len;
 		buffer_info->time_stamp = jiffies;
-		buffer_info->next_to_watch = i;
 		buffer_info->mapped_as_page = true;
 		buffer_info->dma = skb_frag_dma_map(&pdev->dev, frag, 0, len,
 						DMA_TO_DEVICE);
@@ -2112,7 +2117,6 @@
 	}
 
 	tx_ring->buffer_info[i].skb = skb;
-	tx_ring->buffer_info[first].next_to_watch = i;
 
 	return ++count;
 
@@ -2123,7 +2127,6 @@
 	buffer_info->dma = 0;
 	buffer_info->time_stamp = 0;
 	buffer_info->length = 0;
-	buffer_info->next_to_watch = 0;
 	buffer_info->mapped_as_page = false;
 	if (count)
 		count--;
@@ -2142,7 +2145,8 @@
 
 static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter,
                                       struct igbvf_ring *tx_ring,
-                                      int tx_flags, int count, u32 paylen,
+				      int tx_flags, int count,
+				      unsigned int first, u32 paylen,
                                       u8 hdr_len)
 {
 	union e1000_adv_tx_desc *tx_desc = NULL;
@@ -2192,6 +2196,7 @@
 	 * such as IA-64). */
 	wmb();
 
+	tx_ring->buffer_info[first].next_to_watch = tx_desc;
 	tx_ring->next_to_use = i;
 	writel(i, adapter->hw.hw_addr + tx_ring->tail);
 	/* we need this if more than one processor can write to our tail
@@ -2258,11 +2263,11 @@
 	 * count reflects descriptors mapped, if 0 then mapping error
 	 * has occurred and we need to rewind the descriptor queue
 	 */
-	count = igbvf_tx_map_adv(adapter, tx_ring, skb, first);
+	count = igbvf_tx_map_adv(adapter, tx_ring, skb);
 
 	if (count) {
 		igbvf_tx_queue_adv(adapter, tx_ring, tx_flags, count,
-		                   skb->len, hdr_len);
+				   first, skb->len, hdr_len);
 		/* Make sure there is space in the ring for the next send. */
 		igbvf_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 4);
 	} else {
@@ -2736,30 +2741,24 @@
 	err = hw->mac.ops.reset_hw(hw);
 	if (err) {
 		dev_info(&pdev->dev,
-			 "PF still in reset state, assigning new address."
-			 " Is the PF interface up?\n");
-		eth_hw_addr_random(netdev);
-		memcpy(adapter->hw.mac.addr, netdev->dev_addr,
-			netdev->addr_len);
+			 "PF still in reset state. Is the PF interface up?\n");
 	} else {
 		err = hw->mac.ops.read_mac_addr(hw);
-		if (err) {
-			dev_err(&pdev->dev, "Error reading MAC address\n");
-			goto err_hw_init;
-		}
+		if (err)
+			dev_info(&pdev->dev, "Error reading MAC address.\n");
+		else if (is_zero_ether_addr(adapter->hw.mac.addr))
+			dev_info(&pdev->dev, "MAC address not assigned by administrator.\n");
 		memcpy(netdev->dev_addr, adapter->hw.mac.addr,
-			netdev->addr_len);
+		       netdev->addr_len);
 	}
 
 	if (!is_valid_ether_addr(netdev->dev_addr)) {
-		dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
-		        netdev->dev_addr);
-		err = -EIO;
-		goto err_hw_init;
+		dev_info(&pdev->dev, "Assigning random MAC address.\n");
+		eth_hw_addr_random(netdev);
+		memcpy(adapter->hw.mac.addr, netdev->dev_addr,
+			netdev->addr_len);
 	}
 
-	memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
-
 	setup_timer(&adapter->watchdog_timer, &igbvf_watchdog,
 	            (unsigned long) adapter);
 
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index ae96c10..ea48083 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -500,9 +500,8 @@
 	}
 
 	ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
-	memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		netif_err(adapter, probe, adapter->netdev, "Invalid MAC Address\n");
 		err = -EIO;
 		goto err_eeprom;
@@ -709,11 +708,8 @@
 
 	size = sizeof(struct ixgb_buffer) * txdr->count;
 	txdr->buffer_info = vzalloc(size);
-	if (!txdr->buffer_info) {
-		netif_err(adapter, probe, adapter->netdev,
-			  "Unable to allocate transmit descriptor ring memory\n");
+	if (!txdr->buffer_info)
 		return -ENOMEM;
-	}
 
 	/* round up to nearest 4K */
 
@@ -798,11 +794,8 @@
 
 	size = sizeof(struct ixgb_buffer) * rxdr->count;
 	rxdr->buffer_info = vzalloc(size);
-	if (!rxdr->buffer_info) {
-		netif_err(adapter, probe, adapter->netdev,
-			  "Unable to allocate receive descriptor ring\n");
+	if (!rxdr->buffer_info)
 		return -ENOMEM;
-	}
 
 	/* Round up to nearest 4K */
 
diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 687c83d..be2989e 100644
--- a/drivers/net/ethernet/intel/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel 10 Gigabit PCI Express Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 8e78676..a8e10cf 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,7 @@
 #include <linux/cpumask.h>
 #include <linux/aer.h>
 #include <linux/if_vlan.h>
+#include <linux/jiffies.h>
 
 #include <linux/clocksource.h>
 #include <linux/net_tstamp.h>
@@ -91,21 +92,26 @@
  */
 #define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
 
-#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
-
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #define IXGBE_RX_BUFFER_WRITE	16	/* Must be power of 2 */
 
-#define IXGBE_TX_FLAGS_CSUM		(u32)(1)
-#define IXGBE_TX_FLAGS_HW_VLAN		(u32)(1 << 1)
-#define IXGBE_TX_FLAGS_SW_VLAN		(u32)(1 << 2)
-#define IXGBE_TX_FLAGS_TSO		(u32)(1 << 3)
-#define IXGBE_TX_FLAGS_IPV4		(u32)(1 << 4)
-#define IXGBE_TX_FLAGS_FCOE		(u32)(1 << 5)
-#define IXGBE_TX_FLAGS_FSO		(u32)(1 << 6)
-#define IXGBE_TX_FLAGS_TXSW		(u32)(1 << 7)
-#define IXGBE_TX_FLAGS_TSTAMP		(u32)(1 << 8)
-#define IXGBE_TX_FLAGS_NO_IFCS		(u32)(1 << 9)
+enum ixgbe_tx_flags {
+	/* cmd_type flags */
+	IXGBE_TX_FLAGS_HW_VLAN	= 0x01,
+	IXGBE_TX_FLAGS_TSO	= 0x02,
+	IXGBE_TX_FLAGS_TSTAMP	= 0x04,
+
+	/* olinfo flags */
+	IXGBE_TX_FLAGS_CC	= 0x08,
+	IXGBE_TX_FLAGS_IPV4	= 0x10,
+	IXGBE_TX_FLAGS_CSUM	= 0x20,
+
+	/* software defined flags */
+	IXGBE_TX_FLAGS_SW_VLAN	= 0x40,
+	IXGBE_TX_FLAGS_FCOE	= 0x80,
+};
+
+/* VLAN info */
 #define IXGBE_TX_FLAGS_VLAN_MASK	0xffff0000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK	0xe0000000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT  29
@@ -150,7 +156,7 @@
 
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD)
-#define DESC_NEEDED ((MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE)) + 4)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
 
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
@@ -195,6 +201,7 @@
 
 enum ixgbe_ring_state_t {
 	__IXGBE_TX_FDIR_INIT_DONE,
+	__IXGBE_TX_XPS_INIT_DONE,
 	__IXGBE_TX_DETECT_HANG,
 	__IXGBE_HANG_CHECK_ARMED,
 	__IXGBE_RX_RSC_ENABLED,
@@ -224,6 +231,7 @@
 		struct ixgbe_tx_buffer *tx_buffer_info;
 		struct ixgbe_rx_buffer *rx_buffer_info;
 	};
+	unsigned long last_rx_timestamp;
 	unsigned long state;
 	u8 __iomem *tail;
 	dma_addr_t dma;			/* phys. address of descriptor ring */
@@ -271,15 +279,10 @@
 
 #define IXGBE_MAX_RSS_INDICES  16
 #define IXGBE_MAX_VMDQ_INDICES 64
-#define IXGBE_MAX_FDIR_INDICES 64
-#ifdef IXGBE_FCOE
+#define IXGBE_MAX_FDIR_INDICES 63	/* based on q_vector limit */
 #define IXGBE_MAX_FCOE_INDICES  8
-#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES)
-#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES)
-#else
-#define MAX_RX_QUEUES IXGBE_MAX_FDIR_INDICES
-#define MAX_TX_QUEUES IXGBE_MAX_FDIR_INDICES
-#endif /* IXGBE_FCOE */
+#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1)
+#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1)
 struct ixgbe_ring_feature {
 	u16 limit;	/* upper limit on feature indices */
 	u16 indices;	/* current value of indices */
@@ -573,11 +576,14 @@
 
 	struct ptp_clock *ptp_clock;
 	struct ptp_clock_info ptp_caps;
+	struct work_struct ptp_tx_work;
+	struct sk_buff *ptp_tx_skb;
+	unsigned long ptp_tx_start;
 	unsigned long last_overflow_check;
+	unsigned long last_rx_ptp_check;
 	spinlock_t tmreg_lock;
 	struct cyclecounter cc;
 	struct timecounter tc;
-	int rx_hwtstamp_filter;
 	u32 base_incval;
 
 	/* SR-IOV */
@@ -614,6 +620,7 @@
 	__IXGBE_DOWN,
 	__IXGBE_SERVICE_SCHED,
 	__IXGBE_IN_SFP_INIT,
+	__IXGBE_READ_I2C,
 };
 
 struct ixgbe_cb {
@@ -694,8 +701,8 @@
 extern void ixgbe_set_rx_mode(struct net_device *netdev);
 #ifdef CONFIG_IXGBE_DCB
 extern void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
-extern int ixgbe_setup_tc(struct net_device *dev, u8 tc);
 #endif
+extern int ixgbe_setup_tc(struct net_device *dev, u8 tc);
 extern void ixgbe_tx_ctxtdesc(struct ixgbe_ring *, u32, u32, u32, u32);
 extern void ixgbe_do_reset(struct net_device *netdev);
 #ifdef CONFIG_IXGBE_HWMON
@@ -742,15 +749,32 @@
 extern void ixgbe_ptp_init(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
-extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
-				  struct sk_buff *skb);
-extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
-				  union ixgbe_adv_rx_desc *rx_desc,
-				  struct sk_buff *skb);
+extern void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
+extern void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+				    struct sk_buff *skb);
+static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
+					 union ixgbe_adv_rx_desc *rx_desc,
+					 struct sk_buff *skb)
+{
+	if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
+		return;
+
+	__ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
+
+	/*
+	 * Update the last_rx_timestamp timer in order to enable watchdog check
+	 * for error case of latched timestamp on a dropped packet.
+	 */
+	rx_ring->last_rx_timestamp = jiffies;
+}
+
 extern int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
 				    struct ifreq *ifr, int cmd);
 extern void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_reset(struct ixgbe_adapter *adapter);
 extern void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
+#ifdef CONFIG_PCI_IOV
+void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter);
+#endif
 
 #endif /* _IXGBE_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 4253733..d0113fc 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -41,7 +41,6 @@
 
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
                                          ixgbe_link_speed speed,
-                                         bool autoneg,
                                          bool autoneg_wait_to_complete);
 static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
                                        u8 *eeprom_data);
@@ -633,15 +632,15 @@
  *  ixgbe_setup_mac_link_82598 - Set MAC link speed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if auto-negotiation enabled
  *  @autoneg_wait_to_complete: true when waiting for completion is needed
  *
  *  Set the link speed in the AUTOC register and restarts link.
  **/
 static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw,
-                                           ixgbe_link_speed speed, bool autoneg,
-                                           bool autoneg_wait_to_complete)
+				      ixgbe_link_speed speed,
+				      bool autoneg_wait_to_complete)
 {
+	bool		 autoneg	   = false;
 	s32              status            = 0;
 	ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
 	u32              curr_autoc        = IXGBE_READ_REG(hw, IXGBE_AUTOC);
@@ -685,20 +684,18 @@
  *  ixgbe_setup_copper_link_82598 - Set the PHY autoneg advertised field
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  *  @autoneg_wait_to_complete: true if waiting is needed to complete
  *
  *  Sets the link speed in the AUTOC register in the MAC and restarts link.
  **/
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
                                                ixgbe_link_speed speed,
-                                               bool autoneg,
                                                bool autoneg_wait_to_complete)
 {
 	s32 status;
 
 	/* Setup the PHY according to input speed */
-	status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+	status = hw->phy.ops.setup_link_speed(hw, speed,
 	                                      autoneg_wait_to_complete);
 	/* Set up MAC */
 	ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete);
@@ -1006,15 +1003,16 @@
 }
 
 /**
- *  ixgbe_read_i2c_eeprom_82598 - Reads 8 bit word over I2C interface.
+ *  ixgbe_read_i2c_phy_82598 - Reads 8 bit word over I2C interface.
  *  @hw: pointer to hardware structure
- *  @byte_offset: EEPROM byte offset to read
+ *  @dev_addr: address to read from
+ *  @byte_offset: byte offset to read from dev_addr
  *  @eeprom_data: value read
  *
- *  Performs 8 byte read operation to SFP module's EEPROM over I2C interface.
+ *  Performs 8 byte read operation to SFP module's data over I2C interface.
  **/
-static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
-				       u8 *eeprom_data)
+static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
+				    u8 byte_offset, u8 *eeprom_data)
 {
 	s32 status = 0;
 	u16 sfp_addr = 0;
@@ -1028,7 +1026,7 @@
 		 * 0xC30D.  These registers are used to talk to the SFP+
 		 * module's EEPROM through the SDA/SCL (I2C) interface.
 		 */
-		sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset;
+		sfp_addr = (dev_addr << 8) + byte_offset;
 		sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK);
 		hw->phy.ops.write_reg(hw,
 		                      IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
@@ -1060,7 +1058,6 @@
 		*eeprom_data = (u8)(sfp_data >> 8);
 	} else {
 		status = IXGBE_ERR_PHY;
-		goto out;
 	}
 
 out:
@@ -1068,6 +1065,36 @@
 }
 
 /**
+ *  ixgbe_read_i2c_eeprom_82598 - Reads 8 bit word over I2C interface.
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to read
+ *  @eeprom_data: value read
+ *
+ *  Performs 8 byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
+				       u8 *eeprom_data)
+{
+	return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR,
+					byte_offset, eeprom_data);
+}
+
+/**
+ *  ixgbe_read_i2c_sff8472_82598 - Reads 8 bit word over I2C interface.
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset at address 0xA2
+ *  @eeprom_data: value read
+ *
+ *  Performs 8 byte read operation to SFP module's SFF-8472 data over I2C
+ **/
+static s32 ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset,
+				       u8 *sff8472_data)
+{
+	return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR2,
+					byte_offset, sff8472_data);
+}
+
+/**
  *  ixgbe_get_supported_physical_layer_82598 - Returns physical layer type
  *  @hw: pointer to hardware structure
  *
@@ -1300,6 +1327,7 @@
 	.write_reg		= &ixgbe_write_phy_reg_generic,
 	.setup_link		= &ixgbe_setup_phy_link_generic,
 	.setup_link_speed	= &ixgbe_setup_phy_link_speed_generic,
+	.read_i2c_sff8472	= &ixgbe_read_i2c_sff8472_82598,
 	.read_i2c_eeprom	= &ixgbe_read_i2c_eeprom_82598,
 	.check_overtemp   = &ixgbe_tn_check_overtemp,
 };
@@ -1311,4 +1339,3 @@
 	.eeprom_ops		= &eeprom_ops_82598,
 	.phy_ops		= &phy_ops_82598,
 };
-
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 1073aea..203a00c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -45,21 +45,17 @@
 static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
 static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
 						 ixgbe_link_speed speed,
-						 bool autoneg,
 						 bool autoneg_wait_to_complete);
 static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
                                            ixgbe_link_speed speed,
-                                           bool autoneg,
                                            bool autoneg_wait_to_complete);
 static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
 				      bool autoneg_wait_to_complete);
 static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
                                ixgbe_link_speed speed,
-                               bool autoneg,
                                bool autoneg_wait_to_complete);
 static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
                                          ixgbe_link_speed speed,
-                                         bool autoneg,
                                          bool autoneg_wait_to_complete);
 static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
 
@@ -234,13 +230,13 @@
  *  ixgbe_get_link_capabilities_82599 - Determines link capabilities
  *  @hw: pointer to hardware structure
  *  @speed: pointer to link speed
- *  @negotiation: true when autoneg or autotry is enabled
+ *  @autoneg: true when autoneg or autotry is enabled
  *
  *  Determines the link capabilities by reading the AUTOC register.
  **/
 static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
                                              ixgbe_link_speed *speed,
-                                             bool *negotiation)
+					     bool *autoneg)
 {
 	s32 status = 0;
 	u32 autoc = 0;
@@ -251,7 +247,7 @@
 	    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
 	    hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
-		*negotiation = true;
+		*autoneg = true;
 		goto out;
 	}
 
@@ -268,22 +264,22 @@
 	switch (autoc & IXGBE_AUTOC_LMS_MASK) {
 	case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
-		*negotiation = false;
+		*autoneg = false;
 		break;
 
 	case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
 		*speed = IXGBE_LINK_SPEED_10GB_FULL;
-		*negotiation = false;
+		*autoneg = false;
 		break;
 
 	case IXGBE_AUTOC_LMS_1G_AN:
 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
-		*negotiation = true;
+		*autoneg = true;
 		break;
 
 	case IXGBE_AUTOC_LMS_10G_SERIAL:
 		*speed = IXGBE_LINK_SPEED_10GB_FULL;
-		*negotiation = false;
+		*autoneg = false;
 		break;
 
 	case IXGBE_AUTOC_LMS_KX4_KX_KR:
@@ -295,7 +291,7 @@
 			*speed |= IXGBE_LINK_SPEED_10GB_FULL;
 		if (autoc & IXGBE_AUTOC_KX_SUPP)
 			*speed |= IXGBE_LINK_SPEED_1GB_FULL;
-		*negotiation = true;
+		*autoneg = true;
 		break;
 
 	case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII:
@@ -306,12 +302,12 @@
 			*speed |= IXGBE_LINK_SPEED_10GB_FULL;
 		if (autoc & IXGBE_AUTOC_KX_SUPP)
 			*speed |= IXGBE_LINK_SPEED_1GB_FULL;
-		*negotiation = true;
+		*autoneg = true;
 		break;
 
 	case IXGBE_AUTOC_LMS_SGMII_1G_100M:
 		*speed = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_100_FULL;
-		*negotiation = false;
+		*autoneg = false;
 		break;
 
 	default:
@@ -323,7 +319,7 @@
 	if (hw->phy.multispeed_fiber) {
 		*speed |= IXGBE_LINK_SPEED_10GB_FULL |
 		          IXGBE_LINK_SPEED_1GB_FULL;
-		*negotiation = true;
+		*autoneg = true;
 	}
 
 out:
@@ -510,14 +506,12 @@
  *  ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  *  @autoneg_wait_to_complete: true when waiting for completion is needed
  *
  *  Set the link speed in the AUTOC register and restarts link.
  **/
 static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
                                           ixgbe_link_speed speed,
-                                          bool autoneg,
                                           bool autoneg_wait_to_complete)
 {
 	s32 status = 0;
@@ -527,11 +521,11 @@
 	u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
 	u32 i = 0;
 	bool link_up = false;
-	bool negotiation;
+	bool autoneg = false;
 
 	/* Mask off requested but non-supported speeds */
 	status = hw->mac.ops.get_link_capabilities(hw, &link_speed,
-						   &negotiation);
+						   &autoneg);
 	if (status != 0)
 		return status;
 
@@ -564,7 +558,6 @@
 
 		status = ixgbe_setup_mac_link_82599(hw,
 						    IXGBE_LINK_SPEED_10GB_FULL,
-						    autoneg,
 						    autoneg_wait_to_complete);
 		if (status != 0)
 			return status;
@@ -617,7 +610,6 @@
 
 		status = ixgbe_setup_mac_link_82599(hw,
 						    IXGBE_LINK_SPEED_1GB_FULL,
-						    autoneg,
 						    autoneg_wait_to_complete);
 		if (status != 0)
 			return status;
@@ -646,7 +638,6 @@
 	if (speedcnt > 1)
 		status = ixgbe_setup_mac_link_multispeed_fiber(hw,
 		                                               highest_link_speed,
-		                                               autoneg,
 		                                               autoneg_wait_to_complete);
 
 out:
@@ -666,13 +657,12 @@
  *  ixgbe_setup_mac_link_smartspeed - Set MAC link speed using SmartSpeed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  *  @autoneg_wait_to_complete: true when waiting for completion is needed
  *
  *  Implements the Intel SmartSpeed algorithm.
  **/
 static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
-				     ixgbe_link_speed speed, bool autoneg,
+				     ixgbe_link_speed speed,
 				     bool autoneg_wait_to_complete)
 {
 	s32 status = 0;
@@ -703,7 +693,7 @@
 	/* First, try to get link with full advertisement */
 	hw->phy.smart_speed_active = false;
 	for (j = 0; j < IXGBE_SMARTSPEED_MAX_RETRIES; j++) {
-		status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+		status = ixgbe_setup_mac_link_82599(hw, speed,
 						    autoneg_wait_to_complete);
 		if (status != 0)
 			goto out;
@@ -738,7 +728,7 @@
 
 	/* Turn SmartSpeed on to disable KR support */
 	hw->phy.smart_speed_active = true;
-	status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+	status = ixgbe_setup_mac_link_82599(hw, speed,
 					    autoneg_wait_to_complete);
 	if (status != 0)
 		goto out;
@@ -764,7 +754,7 @@
 
 	/* We didn't get link.  Turn SmartSpeed back off. */
 	hw->phy.smart_speed_active = false;
-	status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+	status = ixgbe_setup_mac_link_82599(hw, speed,
 					    autoneg_wait_to_complete);
 
 out:
@@ -778,14 +768,13 @@
  *  ixgbe_setup_mac_link_82599 - Set MAC link speed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  *  @autoneg_wait_to_complete: true when waiting for completion is needed
  *
  *  Set the link speed in the AUTOC register and restarts link.
  **/
 static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
-                               ixgbe_link_speed speed, bool autoneg,
-                               bool autoneg_wait_to_complete)
+				      ixgbe_link_speed speed,
+				      bool autoneg_wait_to_complete)
 {
 	s32 status = 0;
 	u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
@@ -799,6 +788,7 @@
 	u32 i;
 	ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
 	bool got_lock = false;
+	bool autoneg = false;
 
 	/* Check to see if speed passed in is supported. */
 	status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities,
@@ -911,20 +901,18 @@
  *  ixgbe_setup_copper_link_82599 - Set the PHY autoneg advertised field
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  *  @autoneg_wait_to_complete: true if waiting is needed to complete
  *
  *  Restarts link on PHY and MAC based on settings passed in.
  **/
 static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
                                          ixgbe_link_speed speed,
-                                         bool autoneg,
                                          bool autoneg_wait_to_complete)
 {
 	s32 status;
 
 	/* Setup the PHY according to input speed */
-	status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+	status = hw->phy.ops.setup_link_speed(hw, speed,
 	                                      autoneg_wait_to_complete);
 	/* Set up MAC */
 	ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete);
@@ -2253,6 +2241,7 @@
 	.setup_link_speed	= &ixgbe_setup_phy_link_speed_generic,
 	.read_i2c_byte		= &ixgbe_read_i2c_byte_generic,
 	.write_i2c_byte		= &ixgbe_write_i2c_byte_generic,
+	.read_i2c_sff8472	= &ixgbe_read_i2c_sff8472_generic,
 	.read_i2c_eeprom	= &ixgbe_read_i2c_eeprom_generic,
 	.write_i2c_eeprom	= &ixgbe_write_i2c_eeprom_generic,
 	.check_overtemp		= &ixgbe_tn_check_overtemp,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 5e68afd..99e472e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index f7a0970..bc3948ea 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
index 9bc17c0..1f2c805 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
index 1f4108e..1634de8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
index 87592b4..ac78077 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
index ba83570..3164f54 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
index 4eac80d..05e23b8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
index 4dec47f..a4ef076 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index f1e002d..f3d68f9 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -30,6 +30,7 @@
 #include <linux/dcbnl.h>
 #include "ixgbe_dcb_82598.h"
 #include "ixgbe_dcb_82599.h"
+#include "ixgbe_sriov.h"
 
 /* Callbacks for DCB netlink in the kernel */
 #define BIT_DCB_MODE	0x01
@@ -301,7 +302,6 @@
 	*setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc;
 }
 
-#ifdef IXGBE_FCOE
 static void ixgbe_dcbnl_devreset(struct net_device *dev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(dev);
@@ -320,7 +320,6 @@
 
 	clear_bit(__IXGBE_RESETTING, &adapter->state);
 }
-#endif
 
 static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 {
@@ -450,7 +449,6 @@
 static int ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	u8 rval = 0;
 
 	if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
 		switch (tcid) {
@@ -461,14 +459,14 @@
 			*num = adapter->dcb_cfg.num_tcs.pfc_tcs;
 			break;
 		default:
-			rval = -EINVAL;
+			return -EINVAL;
 			break;
 		}
 	} else {
-		rval = -EINVAL;
+		return -EINVAL;
 	}
 
-	return rval;
+	return 0;
 }
 
 static int ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
@@ -541,6 +539,7 @@
 	int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
 	int i, err = 0;
 	__u8 max_tc = 0;
+	__u8 map_chg = 0;
 
 	if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
 		return -EINVAL;
@@ -550,15 +549,22 @@
 						  GFP_KERNEL);
 		if (!adapter->ixgbe_ieee_ets)
 			return -ENOMEM;
-	}
 
-	memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
+		/* initialize UP2TC mappings to invalid value */
+		for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+			adapter->ixgbe_ieee_ets->prio_tc[i] =
+				IEEE_8021QAZ_MAX_TCS;
+	}
 
 	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
 		if (ets->prio_tc[i] > max_tc)
 			max_tc = ets->prio_tc[i];
+		if (ets->prio_tc[i] != adapter->ixgbe_ieee_ets->prio_tc[i])
+			map_chg = 1;
 	}
 
+	memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
+
 	if (max_tc)
 		max_tc++;
 
@@ -567,6 +573,8 @@
 
 	if (max_tc != netdev_get_num_tc(dev))
 		err = ixgbe_setup_tc(dev, max_tc);
+	else if (map_chg)
+		ixgbe_dcbnl_devreset(dev);
 
 	if (err)
 		goto err_out;
@@ -643,9 +651,11 @@
 		return err;
 
 	err = dcb_ieee_setapp(dev, app);
+	if (err)
+		return err;
 
 #ifdef IXGBE_FCOE
-	if (!err && app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+	if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
 	    app->protocol == ETH_P_FCOE) {
 		u8 app_mask = dcb_ieee_getapp_mask(dev, app);
 
@@ -656,6 +666,23 @@
 		ixgbe_dcbnl_devreset(dev);
 	}
 #endif
+
+	/* VF devices should use default UP when available */
+	if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+	    app->protocol == 0) {
+		int vf;
+
+		adapter->default_up = app->priority;
+
+		for (vf = 0; vf < adapter->num_vfs; vf++) {
+			struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+			if (!vfinfo->pf_qos)
+				ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+						app->priority, vf);
+		}
+	}
+
 	return 0;
 }
 
@@ -683,6 +710,24 @@
 		ixgbe_dcbnl_devreset(dev);
 	}
 #endif
+	/* IF default priority is being removed clear VF default UP */
+	if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+	    app->protocol == 0 && adapter->default_up == app->priority) {
+		int vf;
+		long unsigned int app_mask = dcb_ieee_getapp_mask(dev, app);
+		int qos = app_mask ? find_first_bit(&app_mask, 8) : 0;
+
+		adapter->default_up = qos;
+
+		for (vf = 0; vf < adapter->num_vfs; vf++) {
+			struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+			if (!vfinfo->pf_qos)
+				ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+						qos, vf);
+		}
+	}
+
 	return err;
 }
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
index 3504686..c5933f6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 3268584..f4d2e9e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   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,6 +39,7 @@
 #include <linux/uaccess.h>
 
 #include "ixgbe.h"
+#include "ixgbe_phy.h"
 
 
 #define IXGBE_ALL_RAR_ENTRIES 16
@@ -156,7 +157,7 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	ixgbe_link_speed supported_link;
 	u32 link_speed = 0;
-	bool autoneg;
+	bool autoneg = false;
 	bool link_up;
 
 	hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg);
@@ -333,10 +334,10 @@
 			return err;
 		/* this sets the link speed and restarts auto-neg */
 		hw->mac.autotry_restart = true;
-		err = hw->mac.ops.setup_link(hw, advertised, true, true);
+		err = hw->mac.ops.setup_link(hw, advertised, true);
 		if (err) {
 			e_info(probe, "setup link failed with code %d\n", err);
-			hw->mac.ops.setup_link(hw, old, true, true);
+			hw->mac.ops.setup_link(hw, old, true);
 		}
 	} else {
 		/* in this case we currently only support 10Gb/FULL */
@@ -1040,6 +1041,9 @@
 			p = (char *) adapter +
 					ixgbe_gstrings_stats[i].stat_offset;
 			break;
+		default:
+			data[i] = 0;
+			continue;
 		}
 
 		data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
@@ -1096,8 +1100,10 @@
 
 	switch (stringset) {
 	case ETH_SS_TEST:
-		memcpy(data, *ixgbe_gstrings_test,
-		       IXGBE_TEST_LEN * ETH_GSTRING_LEN);
+		for (i = 0; i < IXGBE_TEST_LEN; i++) {
+			memcpy(data, ixgbe_gstrings_test[i], ETH_GSTRING_LEN);
+			data += ETH_GSTRING_LEN;
+		}
 		break;
 	case ETH_SS_STATS:
 		for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
@@ -1837,19 +1843,11 @@
                             struct ethtool_test *eth_test, u64 *data)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
 	bool if_running = netif_running(netdev);
 
 	set_bit(__IXGBE_TESTING, &adapter->state);
 	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
-		/* Offline tests */
-
-		e_info(hw, "offline testing starting\n");
-
-		/* Link test performed before hardware reset so autoneg doesn't
-		 * interfere with test result */
-		if (ixgbe_link_test(adapter, &data[4]))
-			eth_test->flags |= ETH_TEST_FL_FAILED;
-
 		if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
 			int i;
 			for (i = 0; i < adapter->num_vfs; i++) {
@@ -1870,12 +1868,24 @@
 			}
 		}
 
+		/* Offline tests */
+		e_info(hw, "offline testing starting\n");
+
 		if (if_running)
 			/* indicate we're in test mode */
 			dev_close(netdev);
-		else
-			ixgbe_reset(adapter);
 
+		/* bringing adapter down disables SFP+ optics */
+		if (hw->mac.ops.enable_tx_laser)
+			hw->mac.ops.enable_tx_laser(hw);
+
+		/* Link test performed before hardware reset so autoneg doesn't
+		 * interfere with test result
+		 */
+		if (ixgbe_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		ixgbe_reset(adapter);
 		e_info(hw, "register testing starting\n");
 		if (ixgbe_reg_test(adapter, &data[0]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1908,16 +1918,22 @@
 skip_loopback:
 		ixgbe_reset(adapter);
 
+		/* clear testing bit and return adapter to previous state */
 		clear_bit(__IXGBE_TESTING, &adapter->state);
 		if (if_running)
 			dev_open(netdev);
 	} else {
 		e_info(hw, "online testing starting\n");
+
+		/* if adapter is down, SFP+ optics will be disabled */
+		if (!if_running && hw->mac.ops.enable_tx_laser)
+			hw->mac.ops.enable_tx_laser(hw);
+
 		/* Online tests */
 		if (ixgbe_link_test(adapter, &data[4]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
-		/* Online tests aren't run; pass by default */
+		/* Offline tests aren't run; pass by default */
 		data[0] = 0;
 		data[1] = 0;
 		data[2] = 0;
@@ -1925,6 +1941,10 @@
 
 		clear_bit(__IXGBE_TESTING, &adapter->state);
 	}
+
+	/* if adapter was down, ensure SFP+ optics are disabled again */
+	if (!if_running && hw->mac.ops.disable_tx_laser)
+		hw->mac.ops.disable_tx_laser(hw);
 skip_ol_tests:
 	msleep_interruptible(4 * 1000);
 }
@@ -2093,13 +2113,17 @@
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
 	struct ixgbe_q_vector *q_vector;
 	int i;
-	u16 tx_itr_param, rx_itr_param;
+	u16 tx_itr_param, rx_itr_param, tx_itr_prev;
 	bool need_reset = false;
 
-	/* don't accept tx specific changes if we've got mixed RxTx vectors */
-	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count
-	    && ec->tx_coalesce_usecs)
-		return -EINVAL;
+	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) {
+		/* reject Tx specific changes in case of mixed RxTx vectors */
+		if (ec->tx_coalesce_usecs)
+			return -EINVAL;
+		tx_itr_prev = adapter->rx_itr_setting;
+	} else {
+		tx_itr_prev = adapter->tx_itr_setting;
+	}
 
 	if ((ec->rx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)) ||
 	    (ec->tx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)))
@@ -2125,8 +2149,25 @@
 	else
 		tx_itr_param = adapter->tx_itr_setting;
 
+	/* mixed Rx/Tx */
+	if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
+		adapter->tx_itr_setting = adapter->rx_itr_setting;
+
+#if IS_ENABLED(CONFIG_BQL)
+	/* detect ITR changes that require update of TXDCTL.WTHRESH */
+	if ((adapter->tx_itr_setting > 1) &&
+	    (adapter->tx_itr_setting < IXGBE_100K_ITR)) {
+		if ((tx_itr_prev == 1) ||
+		    (tx_itr_prev > IXGBE_100K_ITR))
+			need_reset = true;
+	} else {
+		if ((tx_itr_prev > 1) &&
+		    (tx_itr_prev < IXGBE_100K_ITR))
+			need_reset = true;
+	}
+#endif
 	/* check the old value and enable RSC if necessary */
-	need_reset = ixgbe_update_rsc(adapter);
+	need_reset |= ixgbe_update_rsc(adapter);
 
 	for (i = 0; i < adapter->num_q_vectors; i++) {
 		q_vector = adapter->q_vector[i];
@@ -2695,6 +2736,14 @@
 			(1 << HWTSTAMP_FILTER_NONE) |
 			(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
 			(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+			(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
 			(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
 		break;
 	default:
@@ -2704,6 +2753,225 @@
 	return 0;
 }
 
+static unsigned int ixgbe_max_channels(struct ixgbe_adapter *adapter)
+{
+	unsigned int max_combined;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+	if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+		/* We only support one q_vector without MSI-X */
+		max_combined = 1;
+	} else if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+		/* SR-IOV currently only allows one queue on the PF */
+		max_combined = 1;
+	} else if (tcs > 1) {
+		/* For DCB report channels per traffic class */
+		if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+			/* 8 TC w/ 4 queues per TC */
+			max_combined = 4;
+		} else if (tcs > 4) {
+			/* 8 TC w/ 8 queues per TC */
+			max_combined = 8;
+		} else {
+			/* 4 TC w/ 16 queues per TC */
+			max_combined = 16;
+		}
+	} else if (adapter->atr_sample_rate) {
+		/* support up to 64 queues with ATR */
+		max_combined = IXGBE_MAX_FDIR_INDICES;
+	} else {
+		/* support up to 16 queues with RSS */
+		max_combined = IXGBE_MAX_RSS_INDICES;
+	}
+
+	return max_combined;
+}
+
+static void ixgbe_get_channels(struct net_device *dev,
+			       struct ethtool_channels *ch)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+
+	/* report maximum channels */
+	ch->max_combined = ixgbe_max_channels(adapter);
+
+	/* report info for other vector */
+	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+		ch->max_other = NON_Q_VECTORS;
+		ch->other_count = NON_Q_VECTORS;
+	}
+
+	/* record RSS queues */
+	ch->combined_count = adapter->ring_feature[RING_F_RSS].indices;
+
+	/* nothing else to report if RSS is disabled */
+	if (ch->combined_count == 1)
+		return;
+
+	/* we do not support ATR queueing if SR-IOV is enabled */
+	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+		return;
+
+	/* same thing goes for being DCB enabled */
+	if (netdev_get_num_tc(dev) > 1)
+		return;
+
+	/* if ATR is disabled we can exit */
+	if (!adapter->atr_sample_rate)
+		return;
+
+	/* report flow director queues as maximum channels */
+	ch->combined_count = adapter->ring_feature[RING_F_FDIR].indices;
+}
+
+static int ixgbe_set_channels(struct net_device *dev,
+			      struct ethtool_channels *ch)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	unsigned int count = ch->combined_count;
+
+	/* verify they are not requesting separate vectors */
+	if (!count || ch->rx_count || ch->tx_count)
+		return -EINVAL;
+
+	/* verify other_count has not changed */
+	if (ch->other_count != NON_Q_VECTORS)
+		return -EINVAL;
+
+	/* verify the number of channels does not exceed hardware limits */
+	if (count > ixgbe_max_channels(adapter))
+		return -EINVAL;
+
+	/* update feature limits from largest to smallest supported values */
+	adapter->ring_feature[RING_F_FDIR].limit = count;
+
+	/* cap RSS limit at 16 */
+	if (count > IXGBE_MAX_RSS_INDICES)
+		count = IXGBE_MAX_RSS_INDICES;
+	adapter->ring_feature[RING_F_RSS].limit = count;
+
+#ifdef IXGBE_FCOE
+	/* cap FCoE limit at 8 */
+	if (count > IXGBE_FCRETA_SIZE)
+		count = IXGBE_FCRETA_SIZE;
+	adapter->ring_feature[RING_F_FCOE].limit = count;
+
+#endif
+	/* use setup TC to update any traffic class queue mapping */
+	return ixgbe_setup_tc(dev, netdev_get_num_tc(dev));
+}
+
+static int ixgbe_get_module_info(struct net_device *dev,
+				       struct ethtool_modinfo *modinfo)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 status;
+	u8 sff8472_rev, addr_mode;
+	int ret_val = 0;
+	bool page_swap = false;
+
+	/* avoid concurent i2c reads */
+	while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+		msleep(100);
+
+	/* used by the service task */
+	set_bit(__IXGBE_READ_I2C, &adapter->state);
+
+	/* Check whether we support SFF-8472 or not */
+	status = hw->phy.ops.read_i2c_eeprom(hw,
+					     IXGBE_SFF_SFF_8472_COMP,
+					     &sff8472_rev);
+	if (status != 0) {
+		ret_val = -EIO;
+		goto err_out;
+	}
+
+	/* addressing mode is not supported */
+	status = hw->phy.ops.read_i2c_eeprom(hw,
+					     IXGBE_SFF_SFF_8472_SWAP,
+					     &addr_mode);
+	if (status != 0) {
+		ret_val = -EIO;
+		goto err_out;
+	}
+
+	if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
+		e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
+		page_swap = true;
+	}
+
+	if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap) {
+		/* We have a SFP, but it does not support SFF-8472 */
+		modinfo->type = ETH_MODULE_SFF_8079;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+	} else {
+		/* We have a SFP which supports a revision of SFF-8472. */
+		modinfo->type = ETH_MODULE_SFF_8472;
+		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+	}
+
+err_out:
+	clear_bit(__IXGBE_READ_I2C, &adapter->state);
+	return ret_val;
+}
+
+static int ixgbe_get_module_eeprom(struct net_device *dev,
+					 struct ethtool_eeprom *ee,
+					 u8 *data)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+	u8 databyte = 0xFF;
+	int i = 0;
+	int ret_val = 0;
+
+	/* ixgbe_get_module_info is called before this function in all
+	 * cases, so we do not need any checks we already do above,
+	 * and can trust ee->len to be a known value.
+	 */
+
+	while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+		msleep(100);
+	set_bit(__IXGBE_READ_I2C, &adapter->state);
+
+	/* Read the first block, SFF-8079 */
+	for (i = 0; i < ETH_MODULE_SFF_8079_LEN; i++) {
+		status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
+		if (status != 0) {
+			/* Error occured while reading module */
+			ret_val = -EIO;
+			goto err_out;
+		}
+		data[i] = databyte;
+	}
+
+	/* If the second block is requested, check if SFF-8472 is supported. */
+	if (ee->len == ETH_MODULE_SFF_8472_LEN) {
+		if (data[IXGBE_SFF_SFF_8472_COMP] == IXGBE_SFF_SFF_8472_UNSUP)
+			return -EOPNOTSUPP;
+
+		/* Read the second block, SFF-8472 */
+		for (i = ETH_MODULE_SFF_8079_LEN;
+		     i < ETH_MODULE_SFF_8472_LEN; i++) {
+			status = hw->phy.ops.read_i2c_sff8472(hw,
+				i - ETH_MODULE_SFF_8079_LEN, &databyte);
+			if (status != 0) {
+				/* Error occured while reading module */
+				ret_val = -EIO;
+				goto err_out;
+			}
+			data[i] = databyte;
+		}
+	}
+
+err_out:
+	clear_bit(__IXGBE_READ_I2C, &adapter->state);
+
+	return ret_val;
+}
+
 static const struct ethtool_ops ixgbe_ethtool_ops = {
 	.get_settings           = ixgbe_get_settings,
 	.set_settings           = ixgbe_set_settings,
@@ -2732,7 +3000,11 @@
 	.set_coalesce           = ixgbe_set_coalesce,
 	.get_rxnfc		= ixgbe_get_rxnfc,
 	.set_rxnfc		= ixgbe_set_rxnfc,
+	.get_channels		= ixgbe_get_channels,
+	.set_channels		= ixgbe_set_channels,
 	.get_ts_info		= ixgbe_get_ts_info,
+	.get_module_info	= ixgbe_get_module_info,
+	.get_module_eeprom	= ixgbe_get_module_eeprom,
 };
 
 void ixgbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 252850d..f58db453 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -544,15 +544,14 @@
 		first->gso_segs = DIV_ROUND_UP(skb->len - *hdr_len,
 					       skb_shinfo(skb)->gso_size);
 		first->bytecount += (first->gso_segs - 1) * *hdr_len;
-		first->tx_flags |= IXGBE_TX_FLAGS_FSO;
+		first->tx_flags |= IXGBE_TX_FLAGS_TSO;
 	}
 
 	/* set flag indicating FCOE to ixgbe_tx_map call */
-	first->tx_flags |= IXGBE_TX_FLAGS_FCOE;
+	first->tx_flags |= IXGBE_TX_FLAGS_FCOE | IXGBE_TX_FLAGS_CC;
 
-	/* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */
+	/* mss_l4len_id: use 0 for FSO as TSO, no need for L4LEN */
 	mss_l4len_idx = skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
-	mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
 
 	/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
 	vlan_macip_lens = skb_transport_offset(skb) +
@@ -717,10 +716,8 @@
 
 	/* Extra buffer to be shared by all DDPs for HW work around */
 	buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC);
-	if (!buffer) {
-		e_err(drv, "failed to allocate extra DDP buffer\n");
+	if (!buffer)
 		return -ENOMEM;
-	}
 
 	dma = dma_map_single(dev, buffer, IXGBE_FCBUFF_MIN, DMA_FROM_DEVICE);
 	if (dma_mapping_error(dev, dma)) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
index bf724da..3a02759 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 8c74f73..ef5f7a6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -386,7 +386,6 @@
 		fcoe = &adapter->ring_feature[RING_F_FCOE];
 
 		/* limit ourselves based on feature limits */
-		fcoe_i = min_t(u16, fcoe_i, num_online_cpus());
 		fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
 
 		if (fcoe_i) {
@@ -562,9 +561,6 @@
 		fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
 
 		if (vmdq_i > 1 && fcoe_i) {
-			/* reserve no more than number of CPUs */
-			fcoe_i = min_t(u16, fcoe_i, num_online_cpus());
-
 			/* alloc queues for FCoE separately */
 			fcoe->indices = fcoe_i;
 			fcoe->offset = vmdq_i * rss_i;
@@ -623,8 +619,7 @@
 	if (rss_i > 1 && adapter->atr_sample_rate) {
 		f = &adapter->ring_feature[RING_F_FDIR];
 
-		f->indices = min_t(u16, num_online_cpus(), f->limit);
-		rss_i = max_t(u16, rss_i, f->indices);
+		rss_i = f->indices = f->limit;
 
 		if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
 			adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
@@ -776,19 +771,23 @@
 {
 	struct ixgbe_q_vector *q_vector;
 	struct ixgbe_ring *ring;
-	int node = -1;
+	int node = NUMA_NO_NODE;
 	int cpu = -1;
 	int ring_count, size;
+	u8 tcs = netdev_get_num_tc(adapter->netdev);
 
 	ring_count = txr_count + rxr_count;
 	size = sizeof(struct ixgbe_q_vector) +
 	       (sizeof(struct ixgbe_ring) * ring_count);
 
 	/* customize cpu for Flow Director mapping */
-	if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
-		if (cpu_online(v_idx)) {
-			cpu = v_idx;
-			node = cpu_to_node(cpu);
+	if ((tcs <= 1) && !(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) {
+		u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
+		if (rss_i > 1 && adapter->atr_sample_rate) {
+			if (cpu_online(v_idx)) {
+				cpu = v_idx;
+				node = cpu_to_node(cpu);
+			}
 		}
 	}
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 20a5af6..68478d6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -66,7 +66,7 @@
 #define DRV_VERSION "3.11.33-k"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static const char ixgbe_copyright[] =
-				"Copyright (c) 1999-2012 Intel Corporation.";
+				"Copyright (c) 1999-2013 Intel Corporation.";
 
 static const struct ixgbe_info *ixgbe_info_tbl[] = {
 	[board_82598] = &ixgbe_82598_info,
@@ -803,6 +803,7 @@
 	/* Do the reset outside of interrupt context */
 	if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
 		adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+		e_warn(drv, "initiating reset due to tx timeout\n");
 		ixgbe_service_event_schedule(adapter);
 	}
 }
@@ -837,7 +838,7 @@
 			break;
 
 		/* prevent any other reads prior to eop_desc */
-		rmb();
+		read_barrier_depends();
 
 		/* if DD is not set pending work has not been completed */
 		if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
@@ -850,9 +851,6 @@
 		total_bytes += tx_buffer->bytecount;
 		total_packets += tx_buffer->gso_segs;
 
-		if (unlikely(tx_buffer->tx_flags & IXGBE_TX_FLAGS_TSTAMP))
-			ixgbe_ptp_tx_hwtstamp(q_vector, tx_buffer->skb);
-
 		/* free the skb */
 		dev_kfree_skb_any(tx_buffer->skb);
 
@@ -1401,6 +1399,7 @@
 	/* set gso_size to avoid messing up TCP MSS */
 	skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len),
 						 IXGBE_CB(skb)->append_cnt);
+	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 }
 
 static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring,
@@ -1441,7 +1440,7 @@
 
 	ixgbe_rx_checksum(rx_ring, rx_desc, skb);
 
-	ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
+	ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
 
 	if ((dev->features & NETIF_F_HW_VLAN_RX) &&
 	    ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
@@ -2180,10 +2179,10 @@
 			return;
 
 		if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) {
-			u32 autoneg;
+			u32 speed;
 			bool link_up = false;
 
-			hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+			hw->mac.ops.check_link(hw, &speed, &link_up, false);
 
 			if (link_up)
 				return;
@@ -2787,13 +2786,19 @@
 
 	/*
 	 * set WTHRESH to encourage burst writeback, it should not be set
-	 * higher than 1 when ITR is 0 as it could cause false TX hangs
+	 * higher than 1 when:
+	 * - ITR is 0 as it could cause false TX hangs
+	 * - ITR is set to > 100k int/sec and BQL is enabled
 	 *
 	 * In order to avoid issues WTHRESH + PTHRESH should always be equal
 	 * to or less than the number of on chip descriptors, which is
 	 * currently 40.
 	 */
+#if IS_ENABLED(CONFIG_BQL)
+	if (!ring->q_vector || (ring->q_vector->itr < IXGBE_100K_ITR))
+#else
 	if (!ring->q_vector || (ring->q_vector->itr < 8))
+#endif
 		txdctl |= (1 << 16);	/* WTHRESH = 1 */
 	else
 		txdctl |= (8 << 16);	/* WTHRESH = 8 */
@@ -2814,6 +2819,16 @@
 		ring->atr_sample_rate = 0;
 	}
 
+	/* initialize XPS */
+	if (!test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, &ring->state)) {
+		struct ixgbe_q_vector *q_vector = ring->q_vector;
+
+		if (q_vector)
+			netif_set_xps_queue(adapter->netdev,
+					    &q_vector->affinity_mask,
+					    ring->queue_index);
+	}
+
 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
 
 	/* enable queue */
@@ -3996,25 +4011,25 @@
  **/
 static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
 {
-	u32 autoneg;
-	bool negotiation, link_up = false;
+	u32 speed;
+	bool autoneg, link_up = false;
 	u32 ret = IXGBE_ERR_LINK_SETUP;
 
 	if (hw->mac.ops.check_link)
-		ret = hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+		ret = hw->mac.ops.check_link(hw, &speed, &link_up, false);
 
 	if (ret)
 		goto link_cfg_out;
 
-	autoneg = hw->phy.autoneg_advertised;
-	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
-		ret = hw->mac.ops.get_link_capabilities(hw, &autoneg,
-							&negotiation);
+	speed = hw->phy.autoneg_advertised;
+	if ((!speed) && (hw->mac.ops.get_link_capabilities))
+		ret = hw->mac.ops.get_link_capabilities(hw, &speed,
+							&autoneg);
 	if (ret)
 		goto link_cfg_out;
 
 	if (hw->mac.ops.setup_link)
-		ret = hw->mac.ops.setup_link(hw, autoneg, negotiation, link_up);
+		ret = hw->mac.ops.setup_link(hw, speed, link_up);
 link_cfg_out:
 	return ret;
 }
@@ -4466,7 +4481,7 @@
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
-	unsigned int rss;
+	unsigned int rss, fdir;
 	u32 fwsm;
 #ifdef CONFIG_IXGBE_DCB
 	int j;
@@ -4481,38 +4496,57 @@
 	hw->subsystem_vendor_id = pdev->subsystem_vendor;
 	hw->subsystem_device_id = pdev->subsystem_device;
 
-	/* Set capability flags */
+	/* Set common capability flags and settings */
 	rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
 	adapter->ring_feature[RING_F_RSS].limit = rss;
+	adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
+	adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+	adapter->max_q_vectors = MAX_Q_VECTORS_82599;
+	adapter->atr_sample_rate = 20;
+	fdir = min_t(int, IXGBE_MAX_FDIR_INDICES, num_online_cpus());
+	adapter->ring_feature[RING_F_FDIR].limit = fdir;
+	adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_64K;
+#ifdef CONFIG_IXGBE_DCA
+	adapter->flags |= IXGBE_FLAG_DCA_CAPABLE;
+#endif
+#ifdef IXGBE_FCOE
+	adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
+	adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+#ifdef CONFIG_IXGBE_DCB
+	/* Default traffic class to use for FCoE */
+	adapter->fcoe.up = IXGBE_FCOE_DEFTC;
+#endif /* CONFIG_IXGBE_DCB */
+#endif /* IXGBE_FCOE */
+
+	/* Set MAC specific capability flags and exceptions */
 	switch (hw->mac.type) {
 	case ixgbe_mac_82598EB:
+		adapter->flags2 &= ~IXGBE_FLAG2_RSC_CAPABLE;
+		adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
+
 		if (hw->device_id == IXGBE_DEV_ID_82598AT)
 			adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
+
 		adapter->max_q_vectors = MAX_Q_VECTORS_82598;
+		adapter->ring_feature[RING_F_FDIR].limit = 0;
+		adapter->atr_sample_rate = 0;
+		adapter->fdir_pballoc = 0;
+#ifdef IXGBE_FCOE
+		adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
+		adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+#ifdef CONFIG_IXGBE_DCB
+		adapter->fcoe.up = 0;
+#endif /* IXGBE_DCB */
+#endif /* IXGBE_FCOE */
+		break;
+	case ixgbe_mac_82599EB:
+		if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
+			adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
 		break;
 	case ixgbe_mac_X540:
 		fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
 		if (fwsm & IXGBE_FWSM_TS_ENABLED)
 			adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
-	case ixgbe_mac_82599EB:
-		adapter->max_q_vectors = MAX_Q_VECTORS_82599;
-		adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
-		adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
-		if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
-			adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
-		/* Flow Director hash filters enabled */
-		adapter->atr_sample_rate = 20;
-		adapter->ring_feature[RING_F_FDIR].limit =
-							 IXGBE_MAX_FDIR_INDICES;
-		adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_64K;
-#ifdef IXGBE_FCOE
-		adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
-		adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
-#ifdef CONFIG_IXGBE_DCB
-		/* Default traffic class to use for FCoE */
-		adapter->fcoe.up = IXGBE_FCOE_DEFTC;
-#endif
-#endif /* IXGBE_FCOE */
 		break;
 	default:
 		break;
@@ -4871,7 +4905,7 @@
 	 */
 	if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) &&
 	    (adapter->hw.mac.type == ixgbe_mac_82599EB) &&
-	    (max_frame > MAXIMUM_ETHERNET_VLAN_SIZE))
+	    (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)))
 		e_warn(probe, "Setting MTU > 1500 will disable legacy VFs\n");
 
 	e_info(probe, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
@@ -5534,6 +5568,8 @@
 		break;
 	}
 
+	adapter->last_rx_ptp_check = jiffies;
+
 	if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED)
 		ixgbe_ptp_start_cyclecounter(adapter);
 
@@ -5614,6 +5650,7 @@
 			 * to get done, so reset controller to flush Tx.
 			 * (Do the reset outside of interrupt context).
 			 */
+			e_warn(drv, "initiating reset to clear Tx work after link loss\n");
 			adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
 		}
 	}
@@ -5678,6 +5715,10 @@
 	    !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
 		return;
 
+	/* concurent i2c reads are not supported */
+	if (test_bit(__IXGBE_READ_I2C, &adapter->state))
+		return;
+
 	/* someone else is in init, wait until next service event */
 	if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
 		return;
@@ -5738,8 +5779,8 @@
 static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-	u32 autoneg;
-	bool negotiation;
+	u32 speed;
+	bool autoneg = false;
 
 	if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG))
 		return;
@@ -5750,11 +5791,11 @@
 
 	adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
 
-	autoneg = hw->phy.autoneg_advertised;
-	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
-		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
+	speed = hw->phy.autoneg_advertised;
+	if ((!speed) && (hw->mac.ops.get_link_capabilities))
+		hw->mac.ops.get_link_capabilities(hw, &speed, &autoneg);
 	if (hw->mac.ops.setup_link)
-		hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
+		hw->mac.ops.setup_link(hw, speed, true);
 
 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
 	adapter->link_check_timeout = jiffies;
@@ -5878,7 +5919,6 @@
 	struct ixgbe_adapter *adapter = container_of(work,
 						     struct ixgbe_adapter,
 						     service_task);
-
 	ixgbe_reset_subtask(adapter);
 	ixgbe_sfp_detection_subtask(adapter);
 	ixgbe_sfp_link_config_subtask(adapter);
@@ -5886,7 +5926,11 @@
 	ixgbe_watchdog_subtask(adapter);
 	ixgbe_fdir_reinit_subtask(adapter);
 	ixgbe_check_hang_subtask(adapter);
-	ixgbe_ptp_overflow_check(adapter);
+
+	if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) {
+		ixgbe_ptp_overflow_check(adapter);
+		ixgbe_ptp_rx_hang(adapter);
+	}
 
 	ixgbe_service_event_complete(adapter);
 }
@@ -5899,6 +5943,9 @@
 	u32 vlan_macip_lens, type_tucmd;
 	u32 mss_l4len_idx, l4len;
 
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
+
 	if (!skb_is_gso(skb))
 		return 0;
 
@@ -5941,10 +5988,9 @@
 	first->gso_segs = skb_shinfo(skb)->gso_segs;
 	first->bytecount += (first->gso_segs - 1) * *hdr_len;
 
-	/* mss_l4len_id: use 1 as index for TSO */
+	/* mss_l4len_id: use 0 as index for TSO */
 	mss_l4len_idx = l4len << IXGBE_ADVTXD_L4LEN_SHIFT;
 	mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
-	mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
 
 	/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
 	vlan_macip_lens = skb_network_header_len(skb);
@@ -5966,12 +6012,9 @@
 	u32 type_tucmd = 0;
 
 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
-		if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN)) {
-			if (unlikely(skb->no_fcs))
-				first->tx_flags |= IXGBE_TX_FLAGS_NO_IFCS;
-			if (!(first->tx_flags & IXGBE_TX_FLAGS_TXSW))
-				return;
-		}
+		if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
+		    !(first->tx_flags & IXGBE_TX_FLAGS_CC))
+			return;
 	} else {
 		u8 l4_hdr = 0;
 		switch (first->protocol) {
@@ -6029,30 +6072,32 @@
 			  type_tucmd, mss_l4len_idx);
 }
 
-static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
+#define IXGBE_SET_FLAG(_input, _flag, _result) \
+	((_flag <= _result) ? \
+	 ((u32)(_input & _flag) * (_result / _flag)) : \
+	 ((u32)(_input & _flag) / (_flag / _result)))
+
+static u32 ixgbe_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
 {
 	/* set type for advanced descriptor with frame checksum insertion */
-	__le32 cmd_type = cpu_to_le32(IXGBE_ADVTXD_DTYP_DATA |
-				      IXGBE_ADVTXD_DCMD_DEXT);
+	u32 cmd_type = IXGBE_ADVTXD_DTYP_DATA |
+		       IXGBE_ADVTXD_DCMD_DEXT |
+		       IXGBE_ADVTXD_DCMD_IFCS;
 
 	/* set HW vlan bit if vlan is present */
-	if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
-		cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE);
-
-	if (tx_flags & IXGBE_TX_FLAGS_TSTAMP)
-		cmd_type |= cpu_to_le32(IXGBE_ADVTXD_MAC_TSTAMP);
+	cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_HW_VLAN,
+				   IXGBE_ADVTXD_DCMD_VLE);
 
 	/* set segmentation enable bits for TSO/FSO */
-#ifdef IXGBE_FCOE
-	if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FSO))
-#else
-	if (tx_flags & IXGBE_TX_FLAGS_TSO)
-#endif
-		cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_TSE);
+	cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_TSO,
+				   IXGBE_ADVTXD_DCMD_TSE);
+
+	/* set timestamp bit if present */
+	cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_TSTAMP,
+				   IXGBE_ADVTXD_MAC_TSTAMP);
 
 	/* insert frame checksum */
-	if (!(tx_flags & IXGBE_TX_FLAGS_NO_IFCS))
-		cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_IFCS);
+	cmd_type ^= IXGBE_SET_FLAG(skb->no_fcs, 1, IXGBE_ADVTXD_DCMD_IFCS);
 
 	return cmd_type;
 }
@@ -6060,36 +6105,27 @@
 static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
 				   u32 tx_flags, unsigned int paylen)
 {
-	__le32 olinfo_status = cpu_to_le32(paylen << IXGBE_ADVTXD_PAYLEN_SHIFT);
+	u32 olinfo_status = paylen << IXGBE_ADVTXD_PAYLEN_SHIFT;
 
 	/* enable L4 checksum for TSO and TX checksum offload */
-	if (tx_flags & IXGBE_TX_FLAGS_CSUM)
-		olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_TXSM);
+	olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+					IXGBE_TX_FLAGS_CSUM,
+					IXGBE_ADVTXD_POPTS_TXSM);
 
 	/* enble IPv4 checksum for TSO */
-	if (tx_flags & IXGBE_TX_FLAGS_IPV4)
-		olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM);
-
-	/* use index 1 context for TSO/FSO/FCOE */
-#ifdef IXGBE_FCOE
-	if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FCOE))
-#else
-	if (tx_flags & IXGBE_TX_FLAGS_TSO)
-#endif
-		olinfo_status |= cpu_to_le32(1 << IXGBE_ADVTXD_IDX_SHIFT);
+	olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+					IXGBE_TX_FLAGS_IPV4,
+					IXGBE_ADVTXD_POPTS_IXSM);
 
 	/*
 	 * Check Context must be set if Tx switch is enabled, which it
 	 * always is for case where virtual functions are running
 	 */
-#ifdef IXGBE_FCOE
-	if (tx_flags & (IXGBE_TX_FLAGS_TXSW | IXGBE_TX_FLAGS_FCOE))
-#else
-	if (tx_flags & IXGBE_TX_FLAGS_TXSW)
-#endif
-		olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_CC);
+	olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+					IXGBE_TX_FLAGS_CC,
+					IXGBE_ADVTXD_CC);
 
-	tx_desc->read.olinfo_status = olinfo_status;
+	tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
 #define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
@@ -6099,22 +6135,22 @@
 			 struct ixgbe_tx_buffer *first,
 			 const u8 hdr_len)
 {
-	dma_addr_t dma;
 	struct sk_buff *skb = first->skb;
 	struct ixgbe_tx_buffer *tx_buffer;
 	union ixgbe_adv_tx_desc *tx_desc;
-	struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
-	unsigned int data_len = skb->data_len;
-	unsigned int size = skb_headlen(skb);
-	unsigned int paylen = skb->len - hdr_len;
+	struct skb_frag_struct *frag;
+	dma_addr_t dma;
+	unsigned int data_len, size;
 	u32 tx_flags = first->tx_flags;
-	__le32 cmd_type;
+	u32 cmd_type = ixgbe_tx_cmd_type(skb, tx_flags);
 	u16 i = tx_ring->next_to_use;
 
 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
 
-	ixgbe_tx_olinfo_status(tx_desc, tx_flags, paylen);
-	cmd_type = ixgbe_tx_cmd_type(tx_flags);
+	ixgbe_tx_olinfo_status(tx_desc, tx_flags, skb->len - hdr_len);
+
+	size = skb_headlen(skb);
+	data_len = skb->data_len;
 
 #ifdef IXGBE_FCOE
 	if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
@@ -6128,19 +6164,22 @@
 
 #endif
 	dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
-	if (dma_mapping_error(tx_ring->dev, dma))
-		goto dma_error;
 
-	/* record length, and DMA address */
-	dma_unmap_len_set(first, len, size);
-	dma_unmap_addr_set(first, dma, dma);
+	tx_buffer = first;
 
-	tx_desc->read.buffer_addr = cpu_to_le64(dma);
+	for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+		if (dma_mapping_error(tx_ring->dev, dma))
+			goto dma_error;
 
-	for (;;) {
+		/* record length, and DMA address */
+		dma_unmap_len_set(tx_buffer, len, size);
+		dma_unmap_addr_set(tx_buffer, dma, dma);
+
+		tx_desc->read.buffer_addr = cpu_to_le64(dma);
+
 		while (unlikely(size > IXGBE_MAX_DATA_PER_TXD)) {
 			tx_desc->read.cmd_type_len =
-				cmd_type | cpu_to_le32(IXGBE_MAX_DATA_PER_TXD);
+				cpu_to_le32(cmd_type ^ IXGBE_MAX_DATA_PER_TXD);
 
 			i++;
 			tx_desc++;
@@ -6148,18 +6187,18 @@
 				tx_desc = IXGBE_TX_DESC(tx_ring, 0);
 				i = 0;
 			}
+			tx_desc->read.olinfo_status = 0;
 
 			dma += IXGBE_MAX_DATA_PER_TXD;
 			size -= IXGBE_MAX_DATA_PER_TXD;
 
 			tx_desc->read.buffer_addr = cpu_to_le64(dma);
-			tx_desc->read.olinfo_status = 0;
 		}
 
 		if (likely(!data_len))
 			break;
 
-		tx_desc->read.cmd_type_len = cmd_type | cpu_to_le32(size);
+		tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type ^ size);
 
 		i++;
 		tx_desc++;
@@ -6167,6 +6206,7 @@
 			tx_desc = IXGBE_TX_DESC(tx_ring, 0);
 			i = 0;
 		}
+		tx_desc->read.olinfo_status = 0;
 
 #ifdef IXGBE_FCOE
 		size = min_t(unsigned int, data_len, skb_frag_size(frag));
@@ -6177,22 +6217,13 @@
 
 		dma = skb_frag_dma_map(tx_ring->dev, frag, 0, size,
 				       DMA_TO_DEVICE);
-		if (dma_mapping_error(tx_ring->dev, dma))
-			goto dma_error;
 
 		tx_buffer = &tx_ring->tx_buffer_info[i];
-		dma_unmap_len_set(tx_buffer, len, size);
-		dma_unmap_addr_set(tx_buffer, dma, dma);
-
-		tx_desc->read.buffer_addr = cpu_to_le64(dma);
-		tx_desc->read.olinfo_status = 0;
-
-		frag++;
 	}
 
 	/* write last descriptor with RS and EOP bits */
-	cmd_type |= cpu_to_le32(size) | cpu_to_le32(IXGBE_TXD_CMD);
-	tx_desc->read.cmd_type_len = cmd_type;
+	cmd_type |= size | IXGBE_TXD_CMD;
+	tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
 
 	netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
 
@@ -6353,38 +6384,40 @@
 	return __ixgbe_maybe_stop_tx(tx_ring, size);
 }
 
+#ifdef IXGBE_FCOE
 static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
-	struct ixgbe_adapter *adapter = netdev_priv(dev);
-	int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
-					       smp_processor_id();
-#ifdef IXGBE_FCOE
-	__be16 protocol = vlan_get_protocol(skb);
+	struct ixgbe_adapter *adapter;
+	struct ixgbe_ring_feature *f;
+	int txq;
 
-	if (((protocol == htons(ETH_P_FCOE)) ||
-	    (protocol == htons(ETH_P_FIP))) &&
-	    (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) {
-		struct ixgbe_ring_feature *f;
+	/*
+	 * only execute the code below if protocol is FCoE
+	 * or FIP and we have FCoE enabled on the adapter
+	 */
+	switch (vlan_get_protocol(skb)) {
+	case __constant_htons(ETH_P_FCOE):
+	case __constant_htons(ETH_P_FIP):
+		adapter = netdev_priv(dev);
 
-		f = &adapter->ring_feature[RING_F_FCOE];
-
-		while (txq >= f->indices)
-			txq -= f->indices;
-		txq += adapter->ring_feature[RING_F_FCOE].offset;
-
-		return txq;
-	}
-#endif
-
-	if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
-		while (unlikely(txq >= dev->real_num_tx_queues))
-			txq -= dev->real_num_tx_queues;
-		return txq;
+		if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
+			break;
+	default:
+		return __netdev_pick_tx(dev, skb);
 	}
 
-	return skb_tx_hash(dev, skb);
+	f = &adapter->ring_feature[RING_F_FCOE];
+
+	txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
+					   smp_processor_id();
+
+	while (txq >= f->indices)
+		txq -= f->indices;
+
+	return txq + f->offset;
 }
 
+#endif
 netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
 			  struct ixgbe_adapter *adapter,
 			  struct ixgbe_ring *tx_ring)
@@ -6445,6 +6478,11 @@
 	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
 		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 		tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
+
+		/* schedule check for Tx timestamp */
+		adapter->ptp_tx_skb = skb_get(skb);
+		adapter->ptp_tx_start = jiffies;
+		schedule_work(&adapter->ptp_tx_work);
 	}
 
 #ifdef CONFIG_PCI_IOV
@@ -6453,7 +6491,7 @@
 	 * Tx switch had been disabled.
 	 */
 	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
-		tx_flags |= IXGBE_TX_FLAGS_TXSW;
+		tx_flags |= IXGBE_TX_FLAGS_CC;
 
 #endif
 	/* DCB maps skb priorities 0-7 onto 3 bit PCP of VLAN tag. */
@@ -6784,6 +6822,7 @@
 	}
 }
 
+#endif /* CONFIG_IXGBE_DCB */
 /**
  * ixgbe_setup_tc - configure net_device for multiple traffic classes
  *
@@ -6809,6 +6848,7 @@
 		ixgbe_close(dev);
 	ixgbe_clear_interrupt_scheme(adapter);
 
+#ifdef CONFIG_IXGBE_DCB
 	if (tc) {
 		netdev_set_num_tc(dev, tc);
 		ixgbe_set_prio_tc_map(adapter);
@@ -6831,15 +6871,28 @@
 		adapter->dcb_cfg.pfc_mode_enable = false;
 	}
 
-	ixgbe_init_interrupt_scheme(adapter);
 	ixgbe_validate_rtr(adapter, tc);
+
+#endif /* CONFIG_IXGBE_DCB */
+	ixgbe_init_interrupt_scheme(adapter);
+
 	if (netif_running(dev))
-		ixgbe_open(dev);
+		return ixgbe_open(dev);
 
 	return 0;
 }
 
-#endif /* CONFIG_IXGBE_DCB */
+#ifdef CONFIG_PCI_IOV
+void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	rtnl_lock();
+	ixgbe_setup_tc(netdev, netdev_get_num_tc(netdev));
+	rtnl_unlock();
+}
+
+#endif
 void ixgbe_do_reset(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -6985,7 +7038,7 @@
 	return err;
 }
 
-static int ixgbe_ndo_fdb_del(struct ndmsg *ndm,
+static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
 			     struct net_device *dev,
 			     const unsigned char *addr)
 {
@@ -7062,7 +7115,8 @@
 }
 
 static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
-				    struct net_device *dev)
+				    struct net_device *dev,
+				    u32 filter_mask)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(dev);
 	u16 mode;
@@ -7082,7 +7136,9 @@
 	.ndo_open		= ixgbe_open,
 	.ndo_stop		= ixgbe_close,
 	.ndo_start_xmit		= ixgbe_xmit_frame,
+#ifdef IXGBE_FCOE
 	.ndo_select_queue	= ixgbe_select_queue,
+#endif
 	.ndo_set_rx_mode	= ixgbe_set_rx_mode,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_mac_address	= ixgbe_set_mac,
@@ -7194,9 +7250,8 @@
 	const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
 	static int cards_found;
 	int i, err, pci_using_dac;
+	unsigned int indices = MAX_TX_QUEUES;
 	u8 part_str[IXGBE_PBANUM_LENGTH];
-	unsigned int indices = num_possible_cpus();
-	unsigned int dcb_max = 0;
 #ifdef IXGBE_FCOE
 	u16 device_caps;
 #endif
@@ -7245,25 +7300,15 @@
 	pci_set_master(pdev);
 	pci_save_state(pdev);
 
+	if (ii->mac == ixgbe_mac_82598EB) {
 #ifdef CONFIG_IXGBE_DCB
-	if (ii->mac == ixgbe_mac_82598EB)
-		dcb_max = min_t(unsigned int, indices * MAX_TRAFFIC_CLASS,
-				IXGBE_MAX_RSS_INDICES);
-	else
-		dcb_max = min_t(unsigned int, indices * MAX_TRAFFIC_CLASS,
-				IXGBE_MAX_FDIR_INDICES);
+		/* 8 TC w/ 4 queues per TC */
+		indices = 4 * MAX_TRAFFIC_CLASS;
+#else
+		indices = IXGBE_MAX_RSS_INDICES;
 #endif
+	}
 
-	if (ii->mac == ixgbe_mac_82598EB)
-		indices = min_t(unsigned int, indices, IXGBE_MAX_RSS_INDICES);
-	else
-		indices = min_t(unsigned int, indices, IXGBE_MAX_FDIR_INDICES);
-
-#ifdef IXGBE_FCOE
-	indices += min_t(unsigned int, num_possible_cpus(),
-			 IXGBE_MAX_FCOE_INDICES);
-#endif
-	indices = max_t(unsigned int, dcb_max, indices);
 	netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices);
 	if (!netdev) {
 		err = -ENOMEM;
@@ -7366,7 +7411,15 @@
 	}
 
 #ifdef CONFIG_PCI_IOV
-	ixgbe_enable_sriov(adapter, ii);
+	/* SR-IOV not supported on the 82598 */
+	if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+		goto skip_sriov;
+	/* Mailbox */
+	ixgbe_init_mbx_params_pf(hw);
+	memcpy(&hw->mbx.ops, ii->mbx_ops, sizeof(hw->mbx.ops));
+	ixgbe_enable_sriov(adapter);
+	pci_sriov_set_totalvfs(pdev, 63);
+skip_sriov:
 
 #endif
 	netdev->features = NETIF_F_SG |
@@ -7410,13 +7463,17 @@
 
 #ifdef IXGBE_FCOE
 	if (adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) {
+		unsigned int fcoe_l;
+
 		if (hw->mac.ops.get_device_caps) {
 			hw->mac.ops.get_device_caps(hw, &device_caps);
 			if (device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)
 				adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
 		}
 
-		adapter->ring_feature[RING_F_FCOE].limit = IXGBE_FCRETA_SIZE;
+
+		fcoe_l = min_t(int, IXGBE_FCRETA_SIZE, num_online_cpus());
+		adapter->ring_feature[RING_F_FCOE].limit = fcoe_l;
 
 		netdev->features |= NETIF_F_FSO |
 				    NETIF_F_FCOE_CRC;
@@ -7444,9 +7501,8 @@
 	}
 
 	memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
-	memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		e_dev_err("invalid MAC address\n");
 		err = -EIO;
 		goto err_sw_init;
@@ -7623,8 +7679,14 @@
 	if (netdev->reg_state == NETREG_REGISTERED)
 		unregister_netdev(netdev);
 
-	ixgbe_disable_sriov(adapter);
-
+#ifdef CONFIG_PCI_IOV
+	/*
+	 * Only disable SR-IOV on unload if the user specified the now
+	 * deprecated max_vfs module parameter.
+	 */
+	if (max_vfs)
+		ixgbe_disable_sriov(adapter);
+#endif
 	ixgbe_clear_interrupt_scheme(adapter);
 
 	ixgbe_release_hw_control(adapter);
@@ -7729,6 +7791,8 @@
 		if (vfdev) {
 			e_dev_err("Issuing VFLR to VF %d\n", vf);
 			pci_write_config_dword(vfdev, 0xA8, 0x00008000);
+			/* Free device reference count */
+			pci_dev_put(vfdev);
 		}
 
 		pci_cleanup_aer_uncorrect_error_status(pdev);
@@ -7838,6 +7902,7 @@
 	.resume   = ixgbe_resume,
 #endif
 	.shutdown = ixgbe_shutdown,
+	.sriov_configure = ixgbe_pci_sriov_configure,
 	.err_handler = &ixgbe_err_handler
 };
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
index 1f3e32b..d4a64e6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index 42dd65e..e44ff47 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 71659ed..060d2ad 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -494,11 +494,9 @@
  *  ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  **/
 s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
                                        ixgbe_link_speed speed,
-                                       bool autoneg,
                                        bool autoneg_wait_to_complete)
 {
 
@@ -854,11 +852,9 @@
 
 	status = hw->phy.ops.read_i2c_eeprom(hw,
 					     IXGBE_SFF_IDENTIFIER,
-	                                     &identifier);
+					     &identifier);
 
-	if (status == IXGBE_ERR_SWFW_SYNC ||
-	    status == IXGBE_ERR_I2C ||
-	    status == IXGBE_ERR_SFP_NOT_PRESENT)
+	if (status != 0)
 		goto err_read_i2c_eeprom;
 
 	/* LAN ID is needed for sfp_type determination */
@@ -872,26 +868,20 @@
 						     IXGBE_SFF_1GBE_COMP_CODES,
 						     &comp_codes_1g);
 
-		if (status == IXGBE_ERR_SWFW_SYNC ||
-		    status == IXGBE_ERR_I2C ||
-		    status == IXGBE_ERR_SFP_NOT_PRESENT)
+		if (status != 0)
 			goto err_read_i2c_eeprom;
 
 		status = hw->phy.ops.read_i2c_eeprom(hw,
 						     IXGBE_SFF_10GBE_COMP_CODES,
 						     &comp_codes_10g);
 
-		if (status == IXGBE_ERR_SWFW_SYNC ||
-		    status == IXGBE_ERR_I2C ||
-		    status == IXGBE_ERR_SFP_NOT_PRESENT)
+		if (status != 0)
 			goto err_read_i2c_eeprom;
 		status = hw->phy.ops.read_i2c_eeprom(hw,
 						     IXGBE_SFF_CABLE_TECHNOLOGY,
 						     &cable_tech);
 
-		if (status == IXGBE_ERR_SWFW_SYNC ||
-		    status == IXGBE_ERR_I2C ||
-		    status == IXGBE_ERR_SFP_NOT_PRESENT)
+		if (status != 0)
 			goto err_read_i2c_eeprom;
 
 		 /* ID Module
@@ -986,30 +976,24 @@
 		if (hw->phy.type != ixgbe_phy_nl) {
 			hw->phy.id = identifier;
 			status = hw->phy.ops.read_i2c_eeprom(hw,
-			                            IXGBE_SFF_VENDOR_OUI_BYTE0,
-			                            &oui_bytes[0]);
+						    IXGBE_SFF_VENDOR_OUI_BYTE0,
+						    &oui_bytes[0]);
 
-			if (status == IXGBE_ERR_SWFW_SYNC ||
-			    status == IXGBE_ERR_I2C ||
-			    status == IXGBE_ERR_SFP_NOT_PRESENT)
+			if (status != 0)
 				goto err_read_i2c_eeprom;
 
 			status = hw->phy.ops.read_i2c_eeprom(hw,
 			                            IXGBE_SFF_VENDOR_OUI_BYTE1,
 			                            &oui_bytes[1]);
 
-			if (status == IXGBE_ERR_SWFW_SYNC ||
-			    status == IXGBE_ERR_I2C ||
-			    status == IXGBE_ERR_SFP_NOT_PRESENT)
+			if (status != 0)
 				goto err_read_i2c_eeprom;
 
 			status = hw->phy.ops.read_i2c_eeprom(hw,
 			                            IXGBE_SFF_VENDOR_OUI_BYTE2,
 			                            &oui_bytes[2]);
 
-			if (status == IXGBE_ERR_SWFW_SYNC ||
-			    status == IXGBE_ERR_I2C ||
-			    status == IXGBE_ERR_SFP_NOT_PRESENT)
+			if (status != 0)
 				goto err_read_i2c_eeprom;
 
 			vendor_oui =
@@ -1206,6 +1190,22 @@
 }
 
 /**
+ *  ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset at address 0xA2
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to SFP module's SFF-8472 data over I2C
+ **/
+s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
+				   u8 *sff8472_data)
+{
+	return hw->phy.ops.read_i2c_byte(hw, byte_offset,
+					 IXGBE_I2C_EEPROM_DEV_ADDR2,
+					 sff8472_data);
+}
+
+/**
  *  ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
  *  @hw: pointer to hardware structure
  *  @byte_offset: EEPROM byte offset to write
@@ -1293,9 +1293,9 @@
 		break;
 
 fail:
+		ixgbe_i2c_bus_clear(hw);
 		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
 		msleep(100);
-		ixgbe_i2c_bus_clear(hw);
 		retry++;
 		if (retry < max_retry)
 			hw_dbg(hw, "I2C byte read error - Retrying.\n");
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index cc18165..886a343 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -30,6 +30,7 @@
 
 #include "ixgbe_type.h"
 #define IXGBE_I2C_EEPROM_DEV_ADDR    0xA0
+#define IXGBE_I2C_EEPROM_DEV_ADDR2   0xA2
 
 /* EEPROM byte offsets */
 #define IXGBE_SFF_IDENTIFIER         0x0
@@ -41,6 +42,8 @@
 #define IXGBE_SFF_10GBE_COMP_CODES   0x3
 #define IXGBE_SFF_CABLE_TECHNOLOGY   0x8
 #define IXGBE_SFF_CABLE_SPEC_COMP    0x3C
+#define IXGBE_SFF_SFF_8472_SWAP      0x5C
+#define IXGBE_SFF_SFF_8472_COMP      0x5E
 
 /* Bitmasks */
 #define IXGBE_SFF_DA_PASSIVE_CABLE           0x4
@@ -51,6 +54,7 @@
 #define IXGBE_SFF_1GBASET_CAPABLE            0x8
 #define IXGBE_SFF_10GBASESR_CAPABLE          0x10
 #define IXGBE_SFF_10GBASELR_CAPABLE          0x20
+#define IXGBE_SFF_ADDRESSING_MODE	     0x4
 #define IXGBE_I2C_EEPROM_READ_MASK           0x100
 #define IXGBE_I2C_EEPROM_STATUS_MASK         0x3
 #define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0
@@ -88,6 +92,9 @@
 #define IXGBE_TN_LASI_STATUS_REG        0x9005
 #define IXGBE_TN_LASI_STATUS_TEMP_ALARM 0x0008
 
+/* SFP+ SFF-8472 Compliance code */
+#define IXGBE_SFF_SFF_8472_UNSUP      0x00
+
 s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
 s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw);
 s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw);
@@ -98,7 +105,6 @@
 s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw);
 s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
                                        ixgbe_link_speed speed,
-                                       bool autoneg,
                                        bool autoneg_wait_to_complete);
 s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
                                                ixgbe_link_speed *speed,
@@ -126,6 +132,8 @@
                                  u8 dev_addr, u8 data);
 s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                   u8 *eeprom_data);
+s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
+				   u8 *sff8472_data);
 s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
                                    u8 eeprom_data);
 #endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index bb9256a..331987d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -96,15 +96,12 @@
 #define IXGBE_MAX_TIMEADJ_VALUE  0x7FFFFFFFFFFFFFFFULL
 
 #define IXGBE_OVERFLOW_PERIOD    (HZ * 30)
+#define IXGBE_PTP_TX_TIMEOUT     (HZ * 15)
 
 #ifndef NSECS_PER_SEC
 #define NSECS_PER_SEC 1000000000ULL
 #endif
 
-static struct sock_filter ptp_filter[] = {
-	PTP_FILTER
-};
-
 /**
  * ixgbe_ptp_setup_sdp
  * @hw: the hardware private structure
@@ -405,149 +402,145 @@
 	}
 }
 
-
 /**
- * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow
- * @work: structure containing information about this work task
+ * ixgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow
+ * @adapter: private adapter struct
  *
- * this work function is scheduled to continue reading the timecounter
+ * this watchdog task periodically reads the timecounter
  * in order to prevent missing when the system time registers wrap
- * around. This needs to be run approximately twice a minute when no
- * PTP activity is occurring.
+ * around. This needs to be run approximately twice a minute.
  */
 void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter)
 {
-	unsigned long elapsed_jiffies = adapter->last_overflow_check - jiffies;
+	bool timeout = time_is_before_jiffies(adapter->last_overflow_check +
+					     IXGBE_OVERFLOW_PERIOD);
 	struct timespec ts;
 
-	if ((adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) &&
-	    (elapsed_jiffies >= IXGBE_OVERFLOW_PERIOD)) {
+	if (timeout) {
 		ixgbe_ptp_gettime(&adapter->ptp_caps, &ts);
 		adapter->last_overflow_check = jiffies;
 	}
 }
 
 /**
- * ixgbe_ptp_match - determine if this skb matches a ptp packet
- * @skb: pointer to the skb
- * @hwtstamp: pointer to the hwtstamp_config to check
+ * ixgbe_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
  *
- * Determine whether the skb should have been timestamped, assuming the
- * hwtstamp was set via the hwtstamp ioctl. Returns non-zero when the packet
- * should have a timestamp waiting in the registers, and 0 otherwise.
- *
- * V1 packets have to check the version type to determine whether they are
- * correct. However, we can't directly access the data because it might be
- * fragmented in the SKB, in paged memory. In order to work around this, we
- * use skb_copy_bits which will properly copy the data whether it is in the
- * paged memory fragments or not. We have to copy the IP header as well as the
- * message type.
+ * this watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
  */
-static int ixgbe_ptp_match(struct sk_buff *skb, int rx_filter)
+void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter)
 {
-	struct iphdr iph;
-	u8 msgtype;
-	unsigned int type, offset;
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct ixgbe_ring *rx_ring;
+	u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+	unsigned long rx_event;
+	int n;
 
-	if (rx_filter == HWTSTAMP_FILTER_NONE)
-		return 0;
-
-	type = sk_run_filter(skb, ptp_filter);
-
-	if (likely(rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT))
-		return type & PTP_CLASS_V2;
-
-	/* For the remaining cases actually check message type */
-	switch (type) {
-	case PTP_CLASS_V1_IPV4:
-		skb_copy_bits(skb, OFF_IHL, &iph, sizeof(iph));
-		offset = ETH_HLEN + (iph.ihl << 2) + UDP_HLEN + OFF_PTP_CONTROL;
-		break;
-	case PTP_CLASS_V1_IPV6:
-		offset = OFF_PTP6 + OFF_PTP_CONTROL;
-		break;
-	default:
-		/* other cases invalid or handled above */
-		return 0;
+	/* if we don't have a valid timestamp in the registers, just update the
+	 * timeout counter and exit
+	 */
+	if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) {
+		adapter->last_rx_ptp_check = jiffies;
+		return;
 	}
 
-	/* Make sure our buffer is long enough */
-	if (skb->len < offset)
-		return 0;
+	/* determine the most recent watchdog or rx_timestamp event */
+	rx_event = adapter->last_rx_ptp_check;
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = adapter->rx_ring[n];
+		if (time_after(rx_ring->last_rx_timestamp, rx_event))
+			rx_event = rx_ring->last_rx_timestamp;
+	}
 
-	skb_copy_bits(skb, offset, &msgtype, sizeof(msgtype));
+	/* only need to read the high RXSTMP register to clear the lock */
+	if (time_is_before_jiffies(rx_event + 5*HZ)) {
+		IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
+		adapter->last_rx_ptp_check = jiffies;
 
-	switch (rx_filter) {
-	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-		return (msgtype == IXGBE_RXMTRL_V1_SYNC_MSG);
-		break;
-	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-		return (msgtype == IXGBE_RXMTRL_V1_DELAY_REQ_MSG);
-		break;
-	default:
-		return 0;
+		e_warn(drv, "clearing RX Timestamp hang");
 	}
 }
 
 /**
  * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
- * @q_vector: structure containing interrupt and ring information
- * @skb: particular skb to send timestamp with
+ * @adapter: the private adapter struct
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the shhwtstamps structure which
  * is passed up the network stack
  */
-void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
-			   struct sk_buff *skb)
+static void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter)
 {
-	struct ixgbe_adapter *adapter;
-	struct ixgbe_hw *hw;
+	struct ixgbe_hw *hw = &adapter->hw;
 	struct skb_shared_hwtstamps shhwtstamps;
 	u64 regval = 0, ns;
-	u32 tsynctxctl;
 	unsigned long flags;
 
-	/* we cannot process timestamps on a ring without a q_vector */
-	if (!q_vector || !q_vector->adapter)
-		return;
-
-	adapter = q_vector->adapter;
-	hw = &adapter->hw;
-
-	tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32;
 
-	/*
-	 * if TX timestamp is not valid, exit after clearing the
-	 * timestamp registers
-	 */
-	if (!(tsynctxctl & IXGBE_TSYNCTXCTL_VALID))
-		return;
-
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
 	ns = timecounter_cyc2time(&adapter->tc, regval);
 	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
 
 	memset(&shhwtstamps, 0, sizeof(shhwtstamps));
 	shhwtstamps.hwtstamp = ns_to_ktime(ns);
-	skb_tstamp_tx(skb, &shhwtstamps);
+	skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
+
+	dev_kfree_skb_any(adapter->ptp_tx_skb);
+	adapter->ptp_tx_skb = NULL;
 }
 
 /**
- * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
+ * ixgbe_ptp_tx_hwtstamp_work
+ * @work: pointer to the work struct
+ *
+ * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware
+ * timestamp has been taken for the current skb. It is necesary, because the
+ * descriptor's "done" bit does not correlate with the timestamp event.
+ */
+static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
+{
+	struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter,
+						     ptp_tx_work);
+	struct ixgbe_hw *hw = &adapter->hw;
+	bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
+					      IXGBE_PTP_TX_TIMEOUT);
+	u32 tsynctxctl;
+
+	/* we have to have a valid skb */
+	if (!adapter->ptp_tx_skb)
+		return;
+
+	if (timeout) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+		e_warn(drv, "clearing Tx Timestamp hang");
+		return;
+	}
+
+	tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
+	if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID)
+		ixgbe_ptp_tx_hwtstamp(adapter);
+	else
+		/* reschedule to keep checking if it's not available yet */
+		schedule_work(&adapter->ptp_tx_work);
+}
+
+/**
+ * __ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
  * @q_vector: structure containing interrupt and ring information
- * @rx_desc: the rx descriptor
  * @skb: particular skb to send timestamp with
  *
  * if the timestamp is valid, we convert it into the timecounter ns
  * value, then store that result into the shhwtstamps structure which
  * is passed up the network stack
  */
-void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
-			   union ixgbe_adv_rx_desc *rx_desc,
-			   struct sk_buff *skb)
+void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+			     struct sk_buff *skb)
 {
 	struct ixgbe_adapter *adapter;
 	struct ixgbe_hw *hw;
@@ -563,37 +556,17 @@
 	adapter = q_vector->adapter;
 	hw = &adapter->hw;
 
-	if (likely(!ixgbe_ptp_match(skb, adapter->rx_hwtstamp_filter)))
-		return;
-
+	/*
+	 * Read the tsyncrxctl register afterwards in order to prevent taking an
+	 * I/O hit on every packet.
+	 */
 	tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
-
-	/* Check if we have a valid timestamp and make sure the skb should
-	 * have been timestamped */
 	if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID))
 		return;
 
-	/*
-	 * Always read the registers, in order to clear a possible fault
-	 * because of stagnant RX timestamp values for a packet that never
-	 * reached the queue.
-	 */
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
 	regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32;
 
-	/*
-	 * If the timestamp bit is set in the packet's descriptor, we know the
-	 * timestamp belongs to this packet. No other packet can be
-	 * timestamped until the registers for timestamping have been read.
-	 * Therefor only one packet with this bit can be in the queue at a
-	 * time, and the rx timestamp values that were in the registers belong
-	 * to this packet.
-	 *
-	 * If nothing went wrong, then it should have a skb_shared_tx that we
-	 * can turn into a skb_shared_hwtstamps.
-	 */
-	if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
-		return;
 
 	spin_lock_irqsave(&adapter->tmreg_lock, flags);
 	ns = timecounter_cyc2time(&adapter->tc, regval);
@@ -698,9 +671,6 @@
 		return 0;
 	}
 
-	/* Store filter value for later use */
-	adapter->rx_hwtstamp_filter = config.rx_filter;
-
 	/* define ethertype filter for timestamping L2 packets */
 	if (is_l2)
 		IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588),
@@ -902,11 +872,8 @@
 		return;
 	}
 
-	/* initialize the ptp filter */
-	if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter)))
-		e_dev_warn("ptp_filter_init failed\n");
-
 	spin_lock_init(&adapter->tmreg_lock);
+	INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work);
 
 	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
 						&adapter->pdev->dev);
@@ -938,6 +905,12 @@
 
 	ixgbe_ptp_setup_sdp(adapter);
 
+	cancel_work_sync(&adapter->ptp_tx_work);
+	if (adapter->ptp_tx_skb) {
+		dev_kfree_skb_any(adapter->ptp_tx_skb);
+		adapter->ptp_tx_skb = NULL;
+	}
+
 	if (adapter->ptp_clock) {
 		ptp_clock_unregister(adapter->ptp_clock);
 		adapter->ptp_clock = NULL;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index 85cddac..d44b4d2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -44,50 +44,11 @@
 #include "ixgbe_sriov.h"
 
 #ifdef CONFIG_PCI_IOV
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
-			 const struct ixgbe_info *ii)
+static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	int num_vf_macvlans, i;
 	struct vf_macvlans *mv_list;
-	int pre_existing_vfs = 0;
-
-	pre_existing_vfs = pci_num_vf(adapter->pdev);
-	if (!pre_existing_vfs && !adapter->num_vfs)
-		return;
-
-	/* If there are pre-existing VFs then we have to force
-	 * use of that many because they were not deleted the last
-	 * time someone removed the PF driver.  That would have
-	 * been because they were allocated to guest VMs and can't
-	 * be removed.  Go ahead and just re-enable the old amount.
-	 * If the user wants to change the number of VFs they can
-	 * use ethtool while making sure no VFs are allocated to
-	 * guest VMs... i.e. the right way.
-	 */
-	if (pre_existing_vfs) {
-		adapter->num_vfs = pre_existing_vfs;
-		dev_warn(&adapter->pdev->dev, "Virtual Functions already "
-			 "enabled for this device - Please reload all "
-			 "VF drivers to avoid spoofed packet errors\n");
-	} else {
-		int err;
-		/*
-		 * The 82599 supports up to 64 VFs per physical function
-		 * but this implementation limits allocation to 63 so that
-		 * basic networking resources are still available to the
-		 * physical function.  If the user requests greater thn
-		 * 63 VFs then it is an error - reset to default of zero.
-		 */
-		adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, 63);
-
-		err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
-		if (err) {
-			e_err(probe, "Failed to enable PCI sriov: %d\n", err);
-			adapter->num_vfs = 0;
-			return;
-		}
-	}
 
 	adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
 	e_info(probe, "SR-IOV enabled with %d VFs\n", adapter->num_vfs);
@@ -128,12 +89,6 @@
 		kcalloc(adapter->num_vfs,
 			sizeof(struct vf_data_storage), GFP_KERNEL);
 	if (adapter->vfinfo) {
-		/* Now that we're sure SR-IOV is enabled
-		 * and memory allocated set up the mailbox parameters
-		 */
-		ixgbe_init_mbx_params_pf(hw);
-		memcpy(&hw->mbx.ops, ii->mbx_ops, sizeof(hw->mbx.ops));
-
 		/* limit trafffic classes based on VFs enabled */
 		if ((adapter->hw.mac.type == ixgbe_mac_82599EB) &&
 		    (adapter->num_vfs < 16)) {
@@ -157,10 +112,62 @@
 		/* enable spoof checking for all VFs */
 		for (i = 0; i < adapter->num_vfs; i++)
 			adapter->vfinfo[i].spoofchk_enabled = true;
-		return;
+		return 0;
 	}
 
-	/* Oh oh */
+	return -ENOMEM;
+}
+
+/* Note this function is called when the user wants to enable SR-IOV
+ * VFs using the now deprecated module parameter
+ */
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
+{
+	int pre_existing_vfs = 0;
+
+	pre_existing_vfs = pci_num_vf(adapter->pdev);
+	if (!pre_existing_vfs && !adapter->num_vfs)
+		return;
+
+	if (!pre_existing_vfs)
+		dev_warn(&adapter->pdev->dev,
+			 "Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
+
+	/* If there are pre-existing VFs then we have to force
+	 * use of that many - over ride any module parameter value.
+	 * This may result from the user unloading the PF driver
+	 * while VFs were assigned to guest VMs or because the VFs
+	 * have been created via the new PCI SR-IOV sysfs interface.
+	 */
+	if (pre_existing_vfs) {
+		adapter->num_vfs = pre_existing_vfs;
+		dev_warn(&adapter->pdev->dev,
+			 "Virtual Functions already enabled for this device - Please reload all VF drivers to avoid spoofed packet errors\n");
+	} else {
+		int err;
+		/*
+		 * The 82599 supports up to 64 VFs per physical function
+		 * but this implementation limits allocation to 63 so that
+		 * basic networking resources are still available to the
+		 * physical function.  If the user requests greater thn
+		 * 63 VFs then it is an error - reset to default of zero.
+		 */
+		adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, 63);
+
+		err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+		if (err) {
+			e_err(probe, "Failed to enable PCI sriov: %d\n", err);
+			adapter->num_vfs = 0;
+			return;
+		}
+	}
+
+	if (!__ixgbe_enable_sriov(adapter))
+		return;
+
+	/* If we have gotten to this point then there is no memory available
+	 * to manage the VF devices - print message and bail.
+	 */
 	e_err(probe, "Unable to allocate memory for VF Data Storage - "
 	      "SRIOV disabled\n");
 	ixgbe_disable_sriov(adapter);
@@ -200,11 +207,12 @@
 }
 
 #endif /* #ifdef CONFIG_PCI_IOV */
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 gpie;
 	u32 vmdctl;
+	int rss;
 
 	/* set num VFs to 0 to prevent access to vfinfo */
 	adapter->num_vfs = 0;
@@ -219,7 +227,7 @@
 
 	/* if SR-IOV is already disabled then there is nothing to do */
 	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-		return;
+		return 0;
 
 #ifdef CONFIG_PCI_IOV
 	/*
@@ -229,7 +237,7 @@
 	 */
 	if (ixgbe_vfs_are_assigned(adapter)) {
 		e_dev_warn("Unloading driver while VFs are assigned - VFs will not be deallocated\n");
-		return;
+		return -EPERM;
 	}
 	/* disable iov and allow time for transactions to clear */
 	pci_disable_sriov(adapter->pdev);
@@ -252,10 +260,94 @@
 		adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
 	adapter->ring_feature[RING_F_VMDQ].offset = 0;
 
+	rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
+	adapter->ring_feature[RING_F_RSS].limit = rss;
+
 	/* take a breather then clean up driver data */
 	msleep(100);
 
 	adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+	return 0;
+}
+
+static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+	struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+	int err = 0;
+	int i;
+	int pre_existing_vfs = pci_num_vf(dev);
+
+	if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+		err = ixgbe_disable_sriov(adapter);
+	else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+		goto out;
+
+	if (err)
+		goto err_out;
+
+	/* While the SR-IOV capability structure reports total VFs to be
+	 * 64 we limit the actual number that can be allocated to 63 so
+	 * that some transmit/receive resources can be reserved to the
+	 * PF.  The PCI bus driver already checks for other values out of
+	 * range.
+	 */
+	if (num_vfs > 63) {
+		err = -EPERM;
+		goto err_out;
+	}
+
+	adapter->num_vfs = num_vfs;
+
+	err = __ixgbe_enable_sriov(adapter);
+	if (err)
+		goto err_out;
+
+	for (i = 0; i < adapter->num_vfs; i++)
+		ixgbe_vf_configuration(dev, (i | 0x10000000));
+
+	err = pci_enable_sriov(dev, num_vfs);
+	if (err) {
+		e_dev_warn("Failed to enable PCI sriov: %d\n", err);
+		goto err_out;
+	}
+	ixgbe_sriov_reinit(adapter);
+
+out:
+	return num_vfs;
+
+err_out:
+	return err;
+#endif
+	return 0;
+}
+
+static int ixgbe_pci_sriov_disable(struct pci_dev *dev)
+{
+	struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+	int err;
+	u32 current_flags = adapter->flags;
+
+	err = ixgbe_disable_sriov(adapter);
+
+	/* Only reinit if no error and state changed */
+	if (!err && current_flags != adapter->flags) {
+		/* ixgbe_disable_sriov() doesn't clear VMDQ flag */
+		adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
+#ifdef CONFIG_PCI_IOV
+		ixgbe_sriov_reinit(adapter);
+#endif
+	}
+
+	return err;
+}
+
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+	if (num_vfs == 0)
+		return ixgbe_pci_sriov_disable(dev);
+	else
+		return ixgbe_pci_sriov_enable(dev, num_vfs);
 }
 
 static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
@@ -447,15 +539,6 @@
 	IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
 }
 
-static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter,
-			    u16 vid, u16 qos, u32 vf)
-{
-	struct ixgbe_hw *hw = &adapter->hw;
-	u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) | IXGBE_VMVIR_VLANA_DEFAULT;
-
-	IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), vmvir);
-}
-
 static void ixgbe_clear_vmvir(struct ixgbe_adapter *adapter, u32 vf)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
index 1be1d30..4713f9f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -41,12 +41,20 @@
 int ixgbe_ndo_get_vf_config(struct net_device *netdev,
 			    int vf, struct ifla_vf_info *ivi);
 void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter);
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
 #ifdef CONFIG_PCI_IOV
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
-			const struct ixgbe_info *ii);
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter);
 #endif
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
 
+static inline void ixgbe_set_vmvir(struct ixgbe_adapter *adapter,
+				   u16 vid, u16 qos, u32 vf)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) | IXGBE_VMVIR_VLANA_DEFAULT;
+
+	IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), vmvir);
+}
 
 #endif /* _IXGBE_SRIOV_H_ */
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
index 16ddf14..d118def 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 9cd8a13..6652e96 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -2822,7 +2822,7 @@
 	void (*disable_tx_laser)(struct ixgbe_hw *);
 	void (*enable_tx_laser)(struct ixgbe_hw *);
 	void (*flap_tx_laser)(struct ixgbe_hw *);
-	s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
+	s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool);
 	s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
 	s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
 	                             bool *);
@@ -2869,12 +2869,12 @@
 	s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *);
 	s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16);
 	s32 (*setup_link)(struct ixgbe_hw *);
-	s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool,
-	                        bool);
+	s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool);
 	s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *);
 	s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *);
 	s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *);
 	s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8);
+	s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *);
 	s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
 	s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
 	s32 (*check_overtemp)(struct ixgbe_hw *);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index c73b929..66c5e94 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2013 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -72,14 +72,13 @@
  *  ixgbe_setup_mac_link_X540 - Set the auto advertised capabilitires
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: true if autonegotiation enabled
  *  @autoneg_wait_to_complete: true when waiting for completion is needed
  **/
 static s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw,
-                                     ixgbe_link_speed speed, bool autoneg,
-                                     bool autoneg_wait_to_complete)
+				     ixgbe_link_speed speed,
+				     bool autoneg_wait_to_complete)
 {
-	return hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+	return hw->phy.ops.setup_link_speed(hw, speed,
 	                                    autoneg_wait_to_complete);
 }
 
@@ -879,6 +878,7 @@
 	.setup_link_speed       = &ixgbe_setup_phy_link_speed_generic,
 	.read_i2c_byte          = &ixgbe_read_i2c_byte_generic,
 	.write_i2c_byte         = &ixgbe_write_i2c_byte_generic,
+	.read_i2c_sff8472	= &ixgbe_read_i2c_sff8472_generic,
 	.read_i2c_eeprom        = &ixgbe_read_i2c_eeprom_generic,
 	.write_i2c_eeprom       = &ixgbe_write_i2c_eeprom_generic,
 	.check_overtemp         = &ixgbe_tn_check_overtemp,
diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index 8f20704..c9d0c12 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -99,6 +99,7 @@
 	ecmd->transceiver = XCVR_DUMMY1;
 	ecmd->port = -1;
 
+	hw->mac.get_link_status = 1;
 	hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
 
 	if (link_up) {
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 257357a..c3db6cd 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -750,12 +750,37 @@
 static irqreturn_t ixgbevf_msix_other(int irq, void *data)
 {
 	struct ixgbevf_adapter *adapter = data;
+	struct pci_dev *pdev = adapter->pdev;
 	struct ixgbe_hw *hw = &adapter->hw;
+	u32 msg;
+	bool got_ack = false;
 
 	hw->mac.get_link_status = 1;
+	if (!hw->mbx.ops.check_for_ack(hw))
+		got_ack = true;
 
-	if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
-		mod_timer(&adapter->watchdog_timer, jiffies);
+	if (!hw->mbx.ops.check_for_msg(hw)) {
+		hw->mbx.ops.read(hw, &msg, 1);
+
+		if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) {
+			mod_timer(&adapter->watchdog_timer,
+				  round_jiffies(jiffies + 1));
+			adapter->link_up = false;
+		}
+
+		if (msg & IXGBE_VT_MSGTYPE_NACK)
+			dev_info(&pdev->dev,
+				 "Last Request of type %2.2x to PF Nacked\n",
+				 msg & 0xFF);
+		hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFSTS;
+	}
+
+	/* checking for the ack clears the PFACK bit.  Place
+	 * it back in the v2p_mailbox cache so that anyone
+	 * polling for an ack will not miss it
+	 */
+	if (got_ack)
+		hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK;
 
 	IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other);
 
@@ -2095,6 +2120,9 @@
 	struct ixgbe_hw *hw = &adapter->hw;
 	int i;
 
+	if (!adapter->link_up)
+		return;
+
 	UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc,
 				adapter->stats.vfgprc);
 	UPDATE_VF_COUNTER_32bit(IXGBE_VFGPTC, adapter->stats.last_vfgptc,
@@ -2217,9 +2245,23 @@
 
 	if (link_up) {
 		if (!netif_carrier_ok(netdev)) {
-			hw_dbg(&adapter->hw, "NIC Link is Up, %u Gbps\n",
-			       (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
-			       10 : 1);
+			char *link_speed_string;
+			switch (link_speed) {
+			case IXGBE_LINK_SPEED_10GB_FULL:
+				link_speed_string = "10 Gbps";
+				break;
+			case IXGBE_LINK_SPEED_1GB_FULL:
+				link_speed_string = "1 Gbps";
+				break;
+			case IXGBE_LINK_SPEED_100_FULL:
+				link_speed_string = "100 Mbps";
+				break;
+			default:
+				link_speed_string = "unknown speed";
+				break;
+			}
+			dev_info(&adapter->pdev->dev,
+				"NIC Link is Up, %s\n", link_speed_string);
 			netif_carrier_on(netdev);
 			netif_tx_wake_all_queues(netdev);
 		}
@@ -2227,7 +2269,7 @@
 		adapter->link_up = false;
 		adapter->link_speed = 0;
 		if (netif_carrier_ok(netdev)) {
-			hw_dbg(&adapter->hw, "NIC Link is Down\n");
+			dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
 			netif_carrier_off(netdev);
 			netif_tx_stop_all_queues(netdev);
 		}
@@ -3328,8 +3370,6 @@
 		goto err_sw_init;
 
 	/* The HW MAC address was set and/or determined in sw_init */
-	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
-
 	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		pr_err("invalid MAC address\n");
 		err = -EIO;
diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
index bc58f1d..5409fe8 100644
--- a/drivers/net/ethernet/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -695,9 +695,9 @@
 {
 	struct korina_private *lp = netdev_priv(dev);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, lp->dev->name);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, lp->dev->name, sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index c124e67..6a21274 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -302,9 +302,9 @@
 static void
 ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, "Lantiq ETOP");
-	strcpy(info->bus_info, "internal");
-	strcpy(info->version, DRV_VERSION);
+	strlcpy(info->driver, "Lantiq ETOP", sizeof(info->driver));
+	strlcpy(info->bus_info, "internal", sizeof(info->bus_info));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int
@@ -393,8 +393,8 @@
 		return -ENODEV;
 	}
 
-	phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
-			0, priv->pldata->mii_mode);
+	phydev = phy_connect(dev, dev_name(&phydev->dev),
+			     &ltq_etop_mdio_link, priv->pldata->mii_mode);
 
 	if (IS_ERR(phydev)) {
 		netdev_err(dev, "Could not attach to PHY\n");
@@ -655,7 +655,7 @@
 
 	/* Set addr_assign_type here, ltq_etop_set_mac_address would reset it. */
 	if (random_mac)
-		dev->addr_assign_type |= NET_ADDR_RANDOM;
+		dev->addr_assign_type = NET_ADDR_RANDOM;
 
 	ltq_etop_set_multicast_list(dev);
 	err = ltq_etop_mdio_init(dev);
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 84c1326..2914050 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -1879,12 +1879,10 @@
 	memset(rxq->rx_desc_area, 0, size);
 
 	rxq->rx_desc_area_size = size;
-	rxq->rx_skb = kmalloc(rxq->rx_ring_size * sizeof(*rxq->rx_skb),
-								GFP_KERNEL);
-	if (rxq->rx_skb == NULL) {
-		netdev_err(mp->dev, "can't allocate rx skb ring\n");
+	rxq->rx_skb = kmalloc_array(rxq->rx_ring_size, sizeof(*rxq->rx_skb),
+				    GFP_KERNEL);
+	if (rxq->rx_skb == NULL)
 		goto out_free;
-	}
 
 	rx_desc = rxq->rx_desc_area;
 	for (i = 0; i < rxq->rx_ring_size; i++) {
@@ -2789,7 +2787,7 @@
 
 	phy_reset(mp);
 
-	phy_attach(mp->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_GMII);
+	phy_attach(mp->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_GMII);
 
 	if (speed == 0) {
 		phy->autoneg = AUTONEG_ENABLE;
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 74f1c15..77b7c80 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -164,7 +164,6 @@
 
 	bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
 	if (!bus->irq) {
-		dev_err(&pdev->dev, "Cannot allocate PHY IRQ array\n");
 		mdiobus_free(bus);
 		return -ENOMEM;
 	}
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 10d678d..037ed86 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -627,7 +627,6 @@
 	if (!is_valid_ether_addr(sa->sa_data))
 		return -EADDRNOTAVAIL;
 	memcpy(oldMac, dev->dev_addr, ETH_ALEN);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
 	netif_addr_lock_bh(dev);
 	update_hash_table_mac_address(pep, oldMac, dev->dev_addr);
@@ -1391,7 +1390,7 @@
 	struct phy_device *phy = pep->phy;
 	ethernet_phy_reset(pep);
 
-	phy_attach(pep->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_MII);
+	phy_attach(pep->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_MII);
 
 	if (speed == 0) {
 		phy->autoneg = AUTONEG_ENABLE;
@@ -1444,10 +1443,10 @@
 static void pxa168_get_drvinfo(struct net_device *dev,
 			       struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, DRIVER_NAME, 32);
-	strncpy(info->version, DRIVER_VERSION, 32);
-	strncpy(info->fw_version, "N/A", 32);
-	strncpy(info->bus_info, "N/A", 32);
+	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+	strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops pxa168_ethtool_ops = {
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 5544a1f..171f4b3 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -3855,7 +3855,6 @@
 
 	/* read the mac address */
 	memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	return dev;
 }
@@ -3917,10 +3916,9 @@
 	/* space for skge@pci:0000:04:00.0 */
 	hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:")
 		     + strlen(pci_name(pdev)) + 1, GFP_KERNEL);
-	if (!hw) {
-		dev_err(&pdev->dev, "cannot allocate hardware struct\n");
+	if (!hw)
 		goto err_out_free_regions;
-	}
+
 	sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev));
 
 	hw->pdev = pdev;
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 3269eb3..fc07ca3 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4801,7 +4801,6 @@
 
 	/* read the mac address */
 	memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	return dev;
 }
@@ -4970,10 +4969,8 @@
 
 	hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:")
 		     + strlen(pci_name(pdev)) + 1, GFP_KERNEL);
-	if (!hw) {
-		dev_err(&pdev->dev, "cannot allocate hardware struct\n");
+	if (!hw)
 		goto err_out_free_regions;
-	}
 
 	hw->pdev = pdev;
 	sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev));
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 03447da..00f25b5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -35,6 +35,8 @@
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/mlx4/driver.h>
+#include <linux/in.h>
+#include <net/ip.h>
 
 #include "mlx4_en.h"
 #include "en_port.h"
@@ -494,7 +496,7 @@
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
 		port_up = 1;
-		mlx4_en_stop_port(dev);
+		mlx4_en_stop_port(dev, 1);
 	}
 
 	mlx4_en_free_resources(priv);
@@ -589,7 +591,7 @@
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
 		port_up = 1;
-		mlx4_en_stop_port(dev);
+		mlx4_en_stop_port(dev, 1);
 	}
 
 	priv->prof->rss_rings = rss_rings;
@@ -664,27 +666,90 @@
 
 	if ((cmd->fs.flow_type & FLOW_EXT)) {
 		if (cmd->fs.m_ext.vlan_etype ||
-		    !(cmd->fs.m_ext.vlan_tci == 0 ||
-		      cmd->fs.m_ext.vlan_tci == cpu_to_be16(0xfff)))
+		    !((cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) ==
+		      0 ||
+		      (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) ==
+		      cpu_to_be16(VLAN_VID_MASK)))
 			return -EINVAL;
+
+		if (cmd->fs.m_ext.vlan_tci) {
+			if (be16_to_cpu(cmd->fs.h_ext.vlan_tci) >= VLAN_N_VID)
+				return -EINVAL;
+
+		}
 	}
 
 	return 0;
 }
 
-static int add_ip_rule(struct mlx4_en_priv *priv,
-			struct ethtool_rxnfc *cmd,
-			struct list_head *list_h)
+static int mlx4_en_ethtool_add_mac_rule(struct ethtool_rxnfc *cmd,
+					struct list_head *rule_list_h,
+					struct mlx4_spec_list *spec_l2,
+					unsigned char *mac)
 {
-	struct mlx4_spec_list *spec_l3;
-	struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec;
+	int err = 0;
+	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
 
-	spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL);
-	if (!spec_l3) {
-		en_err(priv, "Fail to alloc ethtool rule.\n");
-		return -ENOMEM;
+	spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
+	memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
+	memcpy(spec_l2->eth.dst_mac, mac, ETH_ALEN);
+
+	if ((cmd->fs.flow_type & FLOW_EXT) &&
+	    (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK))) {
+		spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
+		spec_l2->eth.vlan_id_msk = cpu_to_be16(VLAN_VID_MASK);
 	}
 
+	list_add_tail(&spec_l2->list, rule_list_h);
+
+	return err;
+}
+
+static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv,
+						struct ethtool_rxnfc *cmd,
+						struct list_head *rule_list_h,
+						struct mlx4_spec_list *spec_l2,
+						__be32 ipv4_dst)
+{
+#ifdef CONFIG_INET
+	unsigned char mac[ETH_ALEN];
+
+	if (!ipv4_is_multicast(ipv4_dst)) {
+		if (cmd->fs.flow_type & FLOW_MAC_EXT)
+			memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
+		else
+			memcpy(&mac, priv->dev->dev_addr, ETH_ALEN);
+	} else {
+		ip_eth_mc_map(ipv4_dst, mac);
+	}
+
+	return mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &mac[0]);
+#else
+	return -EINVAL;
+#endif
+}
+
+static int add_ip_rule(struct mlx4_en_priv *priv,
+		       struct ethtool_rxnfc *cmd,
+		       struct list_head *list_h)
+{
+	int err;
+	struct mlx4_spec_list *spec_l2 = NULL;
+	struct mlx4_spec_list *spec_l3 = NULL;
+	struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec;
+
+	spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
+	spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
+	if (!spec_l2 || !spec_l3) {
+		err = -ENOMEM;
+		goto free_spec;
+	}
+
+	err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, spec_l2,
+						   cmd->fs.h_u.
+						   usr_ip4_spec.ip4dst);
+	if (err)
+		goto free_spec;
 	spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
 	spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src;
 	if (l3_mask->ip4src)
@@ -695,34 +760,52 @@
 	list_add_tail(&spec_l3->list, list_h);
 
 	return 0;
+
+free_spec:
+	kfree(spec_l2);
+	kfree(spec_l3);
+	return err;
 }
 
 static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
 			     struct ethtool_rxnfc *cmd,
 			     struct list_head *list_h, int proto)
 {
-	struct mlx4_spec_list *spec_l3;
-	struct mlx4_spec_list *spec_l4;
+	int err;
+	struct mlx4_spec_list *spec_l2 = NULL;
+	struct mlx4_spec_list *spec_l3 = NULL;
+	struct mlx4_spec_list *spec_l4 = NULL;
 	struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec;
 
-	spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL);
-	spec_l4 = kzalloc(sizeof *spec_l4, GFP_KERNEL);
-	if (!spec_l4 || !spec_l3) {
-		en_err(priv, "Fail to alloc ethtool rule.\n");
-		kfree(spec_l3);
-		kfree(spec_l4);
-		return -ENOMEM;
+	spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
+	spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
+	spec_l4 = kzalloc(sizeof(*spec_l4), GFP_KERNEL);
+	if (!spec_l2 || !spec_l3 || !spec_l4) {
+		err = -ENOMEM;
+		goto free_spec;
 	}
 
 	spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
 
 	if (proto == TCP_V4_FLOW) {
+		err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
+							   spec_l2,
+							   cmd->fs.h_u.
+							   tcp_ip4_spec.ip4dst);
+		if (err)
+			goto free_spec;
 		spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP;
 		spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src;
 		spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst;
 		spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc;
 		spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst;
 	} else {
+		err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
+							   spec_l2,
+							   cmd->fs.h_u.
+							   udp_ip4_spec.ip4dst);
+		if (err)
+			goto free_spec;
 		spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP;
 		spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src;
 		spec_l3->ipv4.dst_ip = cmd->fs.h_u.udp_ip4_spec.ip4dst;
@@ -744,6 +827,12 @@
 	list_add_tail(&spec_l4->list, list_h);
 
 	return 0;
+
+free_spec:
+	kfree(spec_l2);
+	kfree(spec_l3);
+	kfree(spec_l4);
+	return err;
 }
 
 static int mlx4_en_ethtool_to_net_trans_rule(struct net_device *dev,
@@ -751,43 +840,23 @@
 					     struct list_head *rule_list_h)
 {
 	int err;
-	__be64 be_mac;
 	struct ethhdr *eth_spec;
-	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_spec_list *spec_l2;
-	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
+	struct mlx4_en_priv *priv = netdev_priv(dev);
 
 	err = mlx4_en_validate_flow(dev, cmd);
 	if (err)
 		return err;
 
-	spec_l2 = kzalloc(sizeof *spec_l2, GFP_KERNEL);
-	if (!spec_l2)
-		return -ENOMEM;
-
-	if (cmd->fs.flow_type & FLOW_MAC_EXT) {
-		memcpy(&be_mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
-	} else {
-		u64 mac = priv->mac & MLX4_MAC_MASK;
-		be_mac = cpu_to_be64(mac << 16);
-	}
-
-	spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
-	memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
-	if ((cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) != ETHER_FLOW)
-		memcpy(spec_l2->eth.dst_mac, &be_mac, ETH_ALEN);
-
-	if ((cmd->fs.flow_type & FLOW_EXT) && cmd->fs.m_ext.vlan_tci) {
-		spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
-		spec_l2->eth.vlan_id_msk = cpu_to_be16(0xfff);
-	}
-
-	list_add_tail(&spec_l2->list, rule_list_h);
-
 	switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
 	case ETHER_FLOW:
+		spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
+		if (!spec_l2)
+			return -ENOMEM;
+
 		eth_spec = &cmd->fs.h_u.ether_spec;
-		memcpy(&spec_l2->eth.dst_mac, eth_spec->h_dest, ETH_ALEN);
+		mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2,
+					     &eth_spec->h_dest[0]);
 		spec_l2->eth.ether_type = eth_spec->h_proto;
 		if (eth_spec->h_proto)
 			spec_l2->eth.ether_type_enable = 1;
@@ -861,6 +930,7 @@
 		loc_rule->id = 0;
 		memset(&loc_rule->flow_spec, 0,
 		       sizeof(struct ethtool_rx_flow_spec));
+		list_del(&loc_rule->list);
 	}
 	err = mlx4_flow_attach(priv->mdev->dev, &rule, &reg_id);
 	if (err) {
@@ -871,6 +941,7 @@
 	loc_rule->id = reg_id;
 	memcpy(&loc_rule->flow_spec, &cmd->fs,
 	       sizeof(struct ethtool_rx_flow_spec));
+	list_add_tail(&loc_rule->list, &priv->ethtool_list);
 
 out_free_list:
 	list_for_each_entry_safe(spec, tmp_spec, &rule.list, list) {
@@ -904,6 +975,7 @@
 	}
 	rule->id = 0;
 	memset(&rule->flow_spec, 0, sizeof(struct ethtool_rx_flow_spec));
+	list_del(&rule->list);
 out:
 	return err;
 
@@ -952,7 +1024,8 @@
 	if ((cmd->cmd == ETHTOOL_GRXCLSRLCNT ||
 	     cmd->cmd == ETHTOOL_GRXCLSRULE ||
 	     cmd->cmd == ETHTOOL_GRXCLSRLALL) &&
-	    mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
+	    (mdev->dev->caps.steering_mode !=
+	     MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up))
 		return -EINVAL;
 
 	switch (cmd->cmd) {
@@ -988,7 +1061,8 @@
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_dev *mdev = priv->mdev;
 
-	if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
+	if (mdev->dev->caps.steering_mode !=
+	    MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up)
 		return -EINVAL;
 
 	switch (cmd->cmd) {
@@ -1037,7 +1111,7 @@
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
 		port_up = 1;
-		mlx4_en_stop_port(dev);
+		mlx4_en_stop_port(dev, 1);
 	}
 
 	mlx4_en_free_resources(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index 3a2b8c6..e3c3d12 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -95,6 +95,28 @@
 	return i;
 }
 
+void mlx4_en_update_loopback_state(struct net_device *dev,
+				   netdev_features_t features)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+
+	priv->flags &= ~(MLX4_EN_FLAG_RX_FILTER_NEEDED|
+			MLX4_EN_FLAG_ENABLE_HW_LOOPBACK);
+
+	/* Drop the packet if SRIOV is not enabled
+	 * and not performing the selftest or flb disabled
+	 */
+	if (mlx4_is_mfunc(priv->mdev->dev) &&
+	    !(features & NETIF_F_LOOPBACK) && !priv->validate_loopback)
+		priv->flags |= MLX4_EN_FLAG_RX_FILTER_NEEDED;
+
+	/* Set dmac in Tx WQE if we are in SRIOV mode or if loopback selftest
+	 * is requested
+	 */
+	if (mlx4_is_mfunc(priv->mdev->dev) || priv->validate_loopback)
+		priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK;
+}
+
 static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
 	struct mlx4_en_profile *params = &mdev->profile;
@@ -191,10 +213,8 @@
 
 	printk_once(KERN_INFO "%s", mlx4_en_version);
 
-	mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
 	if (!mdev) {
-		dev_err(&dev->pdev->dev, "Device struct alloc failed, "
-			"aborting.\n");
 		err = -ENOMEM;
 		goto err_free_res;
 	}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 75a3f46..5088dc5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -132,17 +132,14 @@
 		.priority = MLX4_DOMAIN_RFS,
 	};
 	int rc;
-	__be64 mac;
 	__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
 
 	list_add_tail(&spec_eth.list, &rule.list);
 	list_add_tail(&spec_ip.list, &rule.list);
 	list_add_tail(&spec_tcp.list, &rule.list);
 
-	mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16);
-
 	rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn;
-	memcpy(spec_eth.eth.dst_mac, &mac, ETH_ALEN);
+	memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN);
 	memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
 
 	filter->activated = 0;
@@ -413,6 +410,235 @@
 	return 0;
 }
 
+static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
+{
+	unsigned int i;
+	for (i = ETH_ALEN - 1; i; --i) {
+		dst_mac[i] = src_mac & 0xff;
+		src_mac >>= 8;
+	}
+	memset(&dst_mac[ETH_ALEN], 0, 2);
+}
+
+static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv,
+				unsigned char *mac, int *qpn, u64 *reg_id)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	int err;
+
+	switch (dev->caps.steering_mode) {
+	case MLX4_STEERING_MODE_B0: {
+		struct mlx4_qp qp;
+		u8 gid[16] = {0};
+
+		qp.qpn = *qpn;
+		memcpy(&gid[10], mac, ETH_ALEN);
+		gid[5] = priv->port;
+
+		err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
+		break;
+	}
+	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+		struct mlx4_spec_list spec_eth = { {NULL} };
+		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
+
+		struct mlx4_net_trans_rule rule = {
+			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
+			.exclusive = 0,
+			.allow_loopback = 1,
+			.promisc_mode = MLX4_FS_PROMISC_NONE,
+			.priority = MLX4_DOMAIN_NIC,
+		};
+
+		rule.port = priv->port;
+		rule.qpn = *qpn;
+		INIT_LIST_HEAD(&rule.list);
+
+		spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
+		memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN);
+		memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
+		list_add_tail(&spec_eth.list, &rule.list);
+
+		err = mlx4_flow_attach(dev, &rule, reg_id);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+	if (err)
+		en_warn(priv, "Failed Attaching Unicast\n");
+
+	return err;
+}
+
+static void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv,
+				     unsigned char *mac, int qpn, u64 reg_id)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+
+	switch (dev->caps.steering_mode) {
+	case MLX4_STEERING_MODE_B0: {
+		struct mlx4_qp qp;
+		u8 gid[16] = {0};
+
+		qp.qpn = qpn;
+		memcpy(&gid[10], mac, ETH_ALEN);
+		gid[5] = priv->port;
+
+		mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
+		break;
+	}
+	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+		mlx4_flow_detach(dev, reg_id);
+		break;
+	}
+	default:
+		en_err(priv, "Invalid steering mode.\n");
+	}
+}
+
+static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	struct mlx4_mac_entry *entry;
+	int index = 0;
+	int err = 0;
+	u64 reg_id;
+	int *qpn = &priv->base_qpn;
+	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+
+	en_dbg(DRV, priv, "Registering MAC: %pM for adding\n",
+	       priv->dev->dev_addr);
+	index = mlx4_register_mac(dev, priv->port, mac);
+	if (index < 0) {
+		err = index;
+		en_err(priv, "Failed adding MAC: %pM\n",
+		       priv->dev->dev_addr);
+		return err;
+	}
+
+	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
+		int base_qpn = mlx4_get_base_qpn(dev, priv->port);
+		*qpn = base_qpn + index;
+		return 0;
+	}
+
+	err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
+	en_dbg(DRV, priv, "Reserved qp %d\n", *qpn);
+	if (err) {
+		en_err(priv, "Failed to reserve qp for mac registration\n");
+		goto qp_err;
+	}
+
+	err = mlx4_en_uc_steer_add(priv, priv->dev->dev_addr, qpn, &reg_id);
+	if (err)
+		goto steer_err;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		err = -ENOMEM;
+		goto alloc_err;
+	}
+	memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
+	entry->reg_id = reg_id;
+
+	hlist_add_head_rcu(&entry->hlist,
+			   &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]);
+
+	return 0;
+
+alloc_err:
+	mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id);
+
+steer_err:
+	mlx4_qp_release_range(dev, *qpn, 1);
+
+qp_err:
+	mlx4_unregister_mac(dev, priv->port, mac);
+	return err;
+}
+
+static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	int qpn = priv->base_qpn;
+	u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+
+	en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
+	       priv->dev->dev_addr);
+	mlx4_unregister_mac(dev, priv->port, mac);
+
+	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+		struct mlx4_mac_entry *entry;
+		struct hlist_node *n, *tmp;
+		struct hlist_head *bucket;
+		unsigned int mac_hash;
+
+		mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX];
+		bucket = &priv->mac_hash[mac_hash];
+		hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+			if (ether_addr_equal_64bits(entry->mac,
+						    priv->dev->dev_addr)) {
+				en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
+				       priv->port, priv->dev->dev_addr, qpn);
+				mlx4_en_uc_steer_release(priv, entry->mac,
+							 qpn, entry->reg_id);
+				mlx4_qp_release_range(dev, qpn, 1);
+
+				hlist_del_rcu(&entry->hlist);
+				kfree_rcu(entry, rcu);
+				break;
+			}
+		}
+	}
+}
+
+static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
+			       unsigned char *new_mac, unsigned char *prev_mac)
+{
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_dev *dev = mdev->dev;
+	int err = 0;
+	u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
+
+	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+		struct hlist_head *bucket;
+		unsigned int mac_hash;
+		struct mlx4_mac_entry *entry;
+		struct hlist_node *n, *tmp;
+		u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac);
+
+		bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
+		hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+			if (ether_addr_equal_64bits(entry->mac, prev_mac)) {
+				mlx4_en_uc_steer_release(priv, entry->mac,
+							 qpn, entry->reg_id);
+				mlx4_unregister_mac(dev, priv->port,
+						    prev_mac_u64);
+				hlist_del_rcu(&entry->hlist);
+				synchronize_rcu();
+				memcpy(entry->mac, new_mac, ETH_ALEN);
+				entry->reg_id = 0;
+				mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX];
+				hlist_add_head_rcu(&entry->hlist,
+						   &priv->mac_hash[mac_hash]);
+				mlx4_register_mac(dev, priv->port, new_mac_u64);
+				err = mlx4_en_uc_steer_add(priv, new_mac,
+							   &qpn,
+							   &entry->reg_id);
+				return err;
+			}
+		}
+		return -EINVAL;
+	}
+
+	return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
+}
+
 u64 mlx4_en_mac_to_u64(u8 *addr)
 {
 	u64 mac = 0;
@@ -435,7 +661,6 @@
 		return -EADDRNOTAVAIL;
 
 	memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
-	priv->mac = mlx4_en_mac_to_u64(dev->dev_addr);
 	queue_work(mdev->workqueue, &priv->mac_task);
 	return 0;
 }
@@ -450,13 +675,14 @@
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
 		/* Remove old MAC and insert the new one */
-		err = mlx4_replace_mac(mdev->dev, priv->port,
-				       priv->base_qpn, priv->mac);
+		err = mlx4_en_replace_mac(priv, priv->base_qpn,
+					  priv->dev->dev_addr, priv->prev_mac);
 		if (err)
 			en_err(priv, "Failed changing HW MAC address\n");
+		memcpy(priv->prev_mac, priv->dev->dev_addr,
+		       sizeof(priv->prev_mac));
 	} else
-		en_dbg(HW, priv, "Port is down while "
-				 "registering mac, exiting...\n");
+		en_dbg(HW, priv, "Port is down while registering mac, exiting...\n");
 
 	mutex_unlock(&mdev->state_lock);
 }
@@ -482,7 +708,6 @@
 	netdev_for_each_mc_addr(ha, dev) {
 		tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC);
 		if (!tmp) {
-			en_err(priv, "failed to allocate multicast list\n");
 			mlx4_en_clear_list(dev);
 			return;
 		}
@@ -526,181 +751,153 @@
 			}
 		}
 		if (!found) {
-			new_mc = kmalloc(sizeof(struct mlx4_en_mc_list),
+			new_mc = kmemdup(src_tmp,
+					 sizeof(struct mlx4_en_mc_list),
 					 GFP_KERNEL);
-			if (!new_mc) {
-				en_err(priv, "Failed to allocate current multicast list\n");
+			if (!new_mc)
 				return;
-			}
-			memcpy(new_mc, src_tmp,
-			       sizeof(struct mlx4_en_mc_list));
+
 			new_mc->action = MCLIST_ADD;
 			list_add_tail(&new_mc->list, dst);
 		}
 	}
 }
 
-static void mlx4_en_set_multicast(struct net_device *dev)
+static void mlx4_en_set_rx_mode(struct net_device *dev)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 
 	if (!priv->port_up)
 		return;
 
-	queue_work(priv->mdev->workqueue, &priv->mcast_task);
+	queue_work(priv->mdev->workqueue, &priv->rx_mode_task);
 }
 
-static void mlx4_en_do_set_multicast(struct work_struct *work)
+static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv,
+				     struct mlx4_en_dev *mdev)
 {
-	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
-						 mcast_task);
-	struct mlx4_en_dev *mdev = priv->mdev;
-	struct net_device *dev = priv->dev;
-	struct mlx4_en_mc_list *mclist, *tmp;
-	u64 mcast_addr = 0;
-	u8 mc_list[16] = {0};
 	int err = 0;
 
-	mutex_lock(&mdev->state_lock);
-	if (!mdev->device_up) {
-		en_dbg(HW, priv, "Card is not up, "
-				 "ignoring multicast change.\n");
-		goto out;
-	}
-	if (!priv->port_up) {
-		en_dbg(HW, priv, "Port is down, "
-				 "ignoring  multicast change.\n");
-		goto out;
-	}
-
-	if (!netif_carrier_ok(dev)) {
-		if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
-			if (priv->port_state.link_state) {
-				priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
-				netif_carrier_on(dev);
-				en_dbg(LINK, priv, "Link Up\n");
-			}
-		}
-	}
-
-	/*
-	 * Promsicuous mode: disable all filters
-	 */
-
-	if (dev->flags & IFF_PROMISC) {
-		if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
-			if (netif_msg_rx_status(priv))
-				en_warn(priv, "Entering promiscuous mode\n");
-			priv->flags |= MLX4_EN_FLAG_PROMISC;
-
-			/* Enable promiscouos mode */
-			switch (mdev->dev->caps.steering_mode) {
-			case MLX4_STEERING_MODE_DEVICE_MANAGED:
-				err = mlx4_flow_steer_promisc_add(mdev->dev,
-								  priv->port,
-								  priv->base_qpn,
-								  MLX4_FS_PROMISC_UPLINK);
-				if (err)
-					en_err(priv, "Failed enabling promiscuous mode\n");
-				priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
-				break;
-
-			case MLX4_STEERING_MODE_B0:
-				err = mlx4_unicast_promisc_add(mdev->dev,
-							       priv->base_qpn,
-							       priv->port);
-				if (err)
-					en_err(priv, "Failed enabling unicast promiscuous mode\n");
-
-				/* Add the default qp number as multicast
-				 * promisc
-				 */
-				if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
-					err = mlx4_multicast_promisc_add(mdev->dev,
-									 priv->base_qpn,
-									 priv->port);
-					if (err)
-						en_err(priv, "Failed enabling multicast promiscuous mode\n");
-					priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
-				}
-				break;
-
-			case MLX4_STEERING_MODE_A0:
-				err = mlx4_SET_PORT_qpn_calc(mdev->dev,
-							     priv->port,
-							     priv->base_qpn,
-							     1);
-				if (err)
-					en_err(priv, "Failed enabling promiscuous mode\n");
-				break;
-			}
-
-			/* Disable port multicast filter (unconditionally) */
-			err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
-						  0, MLX4_MCAST_DISABLE);
-			if (err)
-				en_err(priv, "Failed disabling "
-					     "multicast filter\n");
-
-			/* Disable port VLAN filter */
-			err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
-			if (err)
-				en_err(priv, "Failed disabling VLAN filter\n");
-		}
-		goto out;
-	}
-
-	/*
-	 * Not in promiscuous mode
-	 */
-
-	if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+	if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
 		if (netif_msg_rx_status(priv))
-			en_warn(priv, "Leaving promiscuous mode\n");
-		priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+			en_warn(priv, "Entering promiscuous mode\n");
+		priv->flags |= MLX4_EN_FLAG_PROMISC;
 
-		/* Disable promiscouos mode */
+		/* Enable promiscouos mode */
 		switch (mdev->dev->caps.steering_mode) {
 		case MLX4_STEERING_MODE_DEVICE_MANAGED:
-			err = mlx4_flow_steer_promisc_remove(mdev->dev,
-							     priv->port,
-							     MLX4_FS_PROMISC_UPLINK);
+			err = mlx4_flow_steer_promisc_add(mdev->dev,
+							  priv->port,
+							  priv->base_qpn,
+							  MLX4_FS_PROMISC_UPLINK);
 			if (err)
-				en_err(priv, "Failed disabling promiscuous mode\n");
-			priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+				en_err(priv, "Failed enabling promiscuous mode\n");
+			priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
 			break;
 
 		case MLX4_STEERING_MODE_B0:
-			err = mlx4_unicast_promisc_remove(mdev->dev,
-							  priv->base_qpn,
-							  priv->port);
+			err = mlx4_unicast_promisc_add(mdev->dev,
+						       priv->base_qpn,
+						       priv->port);
 			if (err)
-				en_err(priv, "Failed disabling unicast promiscuous mode\n");
-			/* Disable Multicast promisc */
-			if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
-				err = mlx4_multicast_promisc_remove(mdev->dev,
-								    priv->base_qpn,
-								    priv->port);
+				en_err(priv, "Failed enabling unicast promiscuous mode\n");
+
+			/* Add the default qp number as multicast
+			 * promisc
+			 */
+			if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
+				err = mlx4_multicast_promisc_add(mdev->dev,
+								 priv->base_qpn,
+								 priv->port);
 				if (err)
-					en_err(priv, "Failed disabling multicast promiscuous mode\n");
-				priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+					en_err(priv, "Failed enabling multicast promiscuous mode\n");
+				priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
 			}
 			break;
 
 		case MLX4_STEERING_MODE_A0:
 			err = mlx4_SET_PORT_qpn_calc(mdev->dev,
 						     priv->port,
-						     priv->base_qpn, 0);
+						     priv->base_qpn,
+						     1);
 			if (err)
-				en_err(priv, "Failed disabling promiscuous mode\n");
+				en_err(priv, "Failed enabling promiscuous mode\n");
 			break;
 		}
 
-		/* Enable port VLAN filter */
+		/* Disable port multicast filter (unconditionally) */
+		err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+					  0, MLX4_MCAST_DISABLE);
+		if (err)
+			en_err(priv, "Failed disabling multicast filter\n");
+
+		/* Disable port VLAN filter */
 		err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
 		if (err)
-			en_err(priv, "Failed enabling VLAN filter\n");
+			en_err(priv, "Failed disabling VLAN filter\n");
 	}
+}
+
+static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv,
+				       struct mlx4_en_dev *mdev)
+{
+	int err = 0;
+
+	if (netif_msg_rx_status(priv))
+		en_warn(priv, "Leaving promiscuous mode\n");
+	priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+	/* Disable promiscouos mode */
+	switch (mdev->dev->caps.steering_mode) {
+	case MLX4_STEERING_MODE_DEVICE_MANAGED:
+		err = mlx4_flow_steer_promisc_remove(mdev->dev,
+						     priv->port,
+						     MLX4_FS_PROMISC_UPLINK);
+		if (err)
+			en_err(priv, "Failed disabling promiscuous mode\n");
+		priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+		break;
+
+	case MLX4_STEERING_MODE_B0:
+		err = mlx4_unicast_promisc_remove(mdev->dev,
+						  priv->base_qpn,
+						  priv->port);
+		if (err)
+			en_err(priv, "Failed disabling unicast promiscuous mode\n");
+		/* Disable Multicast promisc */
+		if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+			err = mlx4_multicast_promisc_remove(mdev->dev,
+							    priv->base_qpn,
+							    priv->port);
+			if (err)
+				en_err(priv, "Failed disabling multicast promiscuous mode\n");
+			priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+		}
+		break;
+
+	case MLX4_STEERING_MODE_A0:
+		err = mlx4_SET_PORT_qpn_calc(mdev->dev,
+					     priv->port,
+					     priv->base_qpn, 0);
+		if (err)
+			en_err(priv, "Failed disabling promiscuous mode\n");
+		break;
+	}
+
+	/* Enable port VLAN filter */
+	err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
+	if (err)
+		en_err(priv, "Failed enabling VLAN filter\n");
+}
+
+static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
+				 struct net_device *dev,
+				 struct mlx4_en_dev *mdev)
+{
+	struct mlx4_en_mc_list *mclist, *tmp;
+	u64 mcast_addr = 0;
+	u8 mc_list[16] = {0};
+	int err = 0;
 
 	/* Enable/disable the multicast filter according to IFF_ALLMULTI */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -767,9 +964,9 @@
 
 		/* Update multicast list - we cache all addresses so they won't
 		 * change while HW is updated holding the command semaphor */
-		netif_tx_lock_bh(dev);
+		netif_addr_lock_bh(dev);
 		mlx4_en_cache_mclist(dev);
-		netif_tx_unlock_bh(dev);
+		netif_addr_unlock_bh(dev);
 		list_for_each_entry(mclist, &priv->mc_list, list) {
 			mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
 			mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
@@ -814,6 +1011,170 @@
 			}
 		}
 	}
+}
+
+static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
+				 struct net_device *dev,
+				 struct mlx4_en_dev *mdev)
+{
+	struct netdev_hw_addr *ha;
+	struct mlx4_mac_entry *entry;
+	struct hlist_node *n, *tmp;
+	bool found;
+	u64 mac;
+	int err = 0;
+	struct hlist_head *bucket;
+	unsigned int i;
+	int removed = 0;
+	u32 prev_flags;
+
+	/* Note that we do not need to protect our mac_hash traversal with rcu,
+	 * since all modification code is protected by mdev->state_lock
+	 */
+
+	/* find what to remove */
+	for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
+		bucket = &priv->mac_hash[i];
+		hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+			found = false;
+			netdev_for_each_uc_addr(ha, dev) {
+				if (ether_addr_equal_64bits(entry->mac,
+							    ha->addr)) {
+					found = true;
+					break;
+				}
+			}
+
+			/* MAC address of the port is not in uc list */
+			if (ether_addr_equal_64bits(entry->mac, dev->dev_addr))
+				found = true;
+
+			if (!found) {
+				mac = mlx4_en_mac_to_u64(entry->mac);
+				mlx4_en_uc_steer_release(priv, entry->mac,
+							 priv->base_qpn,
+							 entry->reg_id);
+				mlx4_unregister_mac(mdev->dev, priv->port, mac);
+
+				hlist_del_rcu(&entry->hlist);
+				kfree_rcu(entry, rcu);
+				en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n",
+				       entry->mac, priv->port);
+				++removed;
+			}
+		}
+	}
+
+	/* if we didn't remove anything, there is no use in trying to add
+	 * again once we are in a forced promisc mode state
+	 */
+	if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed)
+		return;
+
+	prev_flags = priv->flags;
+	priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;
+
+	/* find what to add */
+	netdev_for_each_uc_addr(ha, dev) {
+		found = false;
+		bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]];
+		hlist_for_each_entry(entry, n, bucket, hlist) {
+			if (ether_addr_equal_64bits(entry->mac, ha->addr)) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+			if (!entry) {
+				en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n",
+				       ha->addr, priv->port);
+				priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+				break;
+			}
+			mac = mlx4_en_mac_to_u64(ha->addr);
+			memcpy(entry->mac, ha->addr, ETH_ALEN);
+			err = mlx4_register_mac(mdev->dev, priv->port, mac);
+			if (err < 0) {
+				en_err(priv, "Failed registering MAC %pM on port %d: %d\n",
+				       ha->addr, priv->port, err);
+				kfree(entry);
+				priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+				break;
+			}
+			err = mlx4_en_uc_steer_add(priv, ha->addr,
+						   &priv->base_qpn,
+						   &entry->reg_id);
+			if (err) {
+				en_err(priv, "Failed adding MAC %pM on port %d: %d\n",
+				       ha->addr, priv->port, err);
+				mlx4_unregister_mac(mdev->dev, priv->port, mac);
+				kfree(entry);
+				priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+				break;
+			} else {
+				unsigned int mac_hash;
+				en_dbg(DRV, priv, "Added MAC %pM on port:%d\n",
+				       ha->addr, priv->port);
+				mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX];
+				bucket = &priv->mac_hash[mac_hash];
+				hlist_add_head_rcu(&entry->hlist, bucket);
+			}
+		}
+	}
+
+	if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) {
+		en_warn(priv, "Forcing promiscuous mode on port:%d\n",
+			priv->port);
+	} else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) {
+		en_warn(priv, "Stop forcing promiscuous mode on port:%d\n",
+			priv->port);
+	}
+}
+
+static void mlx4_en_do_set_rx_mode(struct work_struct *work)
+{
+	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+						 rx_mode_task);
+	struct mlx4_en_dev *mdev = priv->mdev;
+	struct net_device *dev = priv->dev;
+
+	mutex_lock(&mdev->state_lock);
+	if (!mdev->device_up) {
+		en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n");
+		goto out;
+	}
+	if (!priv->port_up) {
+		en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n");
+		goto out;
+	}
+
+	if (!netif_carrier_ok(dev)) {
+		if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
+			if (priv->port_state.link_state) {
+				priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
+				netif_carrier_on(dev);
+				en_dbg(LINK, priv, "Link Up\n");
+			}
+		}
+	}
+
+	if (dev->priv_flags & IFF_UNICAST_FLT)
+		mlx4_en_do_uc_filter(priv, dev, mdev);
+
+	/* Promsicuous mode: disable all filters */
+	if ((dev->flags & IFF_PROMISC) ||
+	    (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) {
+		mlx4_en_set_promisc_mode(priv, mdev);
+		goto out;
+	}
+
+	/* Not in promiscuous mode */
+	if (priv->flags & MLX4_EN_FLAG_PROMISC)
+		mlx4_en_clear_promisc_mode(priv, mdev);
+
+	mlx4_en_do_multicast(priv, dev, mdev);
 out:
 	mutex_unlock(&mdev->state_lock);
 }
@@ -876,9 +1237,8 @@
 	priv->rx_usecs = MLX4_EN_RX_COAL_TIME;
 	priv->tx_frames = MLX4_EN_TX_COAL_PKTS;
 	priv->tx_usecs = MLX4_EN_TX_COAL_TIME;
-	en_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
-			   "rx_frames:%d rx_usecs:%d\n",
-		 priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
+	en_dbg(INTR, priv, "Default coalesing params for mtu:%d - rx_frames:%d rx_usecs:%d\n",
+	       priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
 
 	/* Setup cq moderation params */
 	for (i = 0; i < priv->rx_ring_num; i++) {
@@ -959,8 +1319,8 @@
 			cq->moder_time = moder_time;
 			err = mlx4_en_set_cq_moder(priv, cq);
 			if (err)
-				en_err(priv, "Failed modifying moderation "
-					     "for cq:%d\n", ring);
+				en_err(priv, "Failed modifying moderation for cq:%d\n",
+				       ring);
 		}
 		priv->last_moder_packets[ring] = rx_packets;
 		priv->last_moder_bytes[ring] = rx_bytes;
@@ -977,12 +1337,12 @@
 	struct mlx4_en_dev *mdev = priv->mdev;
 	int err;
 
-	err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
-	if (err)
-		en_dbg(HW, priv, "Could not update stats\n");
-
 	mutex_lock(&mdev->state_lock);
 	if (mdev->device_up) {
+		err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
+		if (err)
+			en_dbg(HW, priv, "Could not update stats\n");
+
 		if (priv->port_up)
 			mlx4_en_auto_moderation(priv);
 
@@ -1039,6 +1399,9 @@
 
 	INIT_LIST_HEAD(&priv->mc_list);
 	INIT_LIST_HEAD(&priv->curr_list);
+	INIT_LIST_HEAD(&priv->ethtool_list);
+	memset(&priv->ethtool_rules[0], 0,
+	       sizeof(struct ethtool_flow_id) * MAX_NUM_OF_FS_RULES);
 
 	/* Calculate Rx buf size */
 	dev->mtu = min(dev->mtu, priv->max_mtu);
@@ -1074,8 +1437,7 @@
 
 	/* Set qp number */
 	en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port);
-	err = mlx4_get_eth_qp(mdev->dev, priv->port,
-				priv->mac, &priv->base_qpn);
+	err = mlx4_en_get_qp(priv);
 	if (err) {
 		en_err(priv, "Failed getting eth qp\n");
 		goto cq_err;
@@ -1138,8 +1500,8 @@
 				    priv->prof->rx_pause,
 				    priv->prof->rx_ppp);
 	if (err) {
-		en_err(priv, "Failed setting port general configurations "
-			     "for port %d, with error %d\n", priv->port, err);
+		en_err(priv, "Failed setting port general configurations for port %d, with error %d\n",
+		       priv->port, err);
 		goto tx_err;
 	}
 	/* Set default qp number */
@@ -1167,23 +1529,16 @@
 
 	/* Must redo promiscuous mode setup. */
 	priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC);
-	if (mdev->dev->caps.steering_mode ==
-	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
-		mlx4_flow_steer_promisc_remove(mdev->dev,
-					       priv->port,
-					       MLX4_FS_PROMISC_UPLINK);
-		mlx4_flow_steer_promisc_remove(mdev->dev,
-					       priv->port,
-					       MLX4_FS_PROMISC_ALL_MULTI);
-	}
 
 	/* Schedule multicast task to populate multicast list */
-	queue_work(mdev->workqueue, &priv->mcast_task);
+	queue_work(mdev->workqueue, &priv->rx_mode_task);
 
 	mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
 
 	priv->port_up = true;
 	netif_tx_start_all_queues(dev);
+	netif_device_attach(dev);
+
 	return 0;
 
 tx_err:
@@ -1195,7 +1550,7 @@
 rss_err:
 	mlx4_en_release_rss_steer(priv);
 mac_err:
-	mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
+	mlx4_en_put_qp(priv);
 cq_err:
 	while (rx_index--)
 		mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
@@ -1206,11 +1561,12 @@
 }
 
 
-void mlx4_en_stop_port(struct net_device *dev)
+void mlx4_en_stop_port(struct net_device *dev, int detach)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_mc_list *mclist, *tmp;
+	struct ethtool_flow_id *flow, *tmp_flow;
 	int i;
 	u8 mc_list[16] = {0};
 
@@ -1221,12 +1577,42 @@
 
 	/* Synchronize with tx routine */
 	netif_tx_lock_bh(dev);
+	if (detach)
+		netif_device_detach(dev);
 	netif_tx_stop_all_queues(dev);
 	netif_tx_unlock_bh(dev);
 
+	netif_tx_disable(dev);
+
 	/* Set port as not active */
 	priv->port_up = false;
 
+	/* Promsicuous mode */
+	if (mdev->dev->caps.steering_mode ==
+	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
+		priv->flags &= ~(MLX4_EN_FLAG_PROMISC |
+				 MLX4_EN_FLAG_MC_PROMISC);
+		mlx4_flow_steer_promisc_remove(mdev->dev,
+					       priv->port,
+					       MLX4_FS_PROMISC_UPLINK);
+		mlx4_flow_steer_promisc_remove(mdev->dev,
+					       priv->port,
+					       MLX4_FS_PROMISC_ALL_MULTI);
+	} else if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+		priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+		/* Disable promiscouos mode */
+		mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn,
+					    priv->port);
+
+		/* Disable Multicast promisc */
+		if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+			mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
+						      priv->port);
+			priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+		}
+	}
+
 	/* Detach All multicasts */
 	memset(&mc_list[10], 0xff, ETH_ALEN);
 	mc_list[5] = priv->port; /* needed for B0 steering support */
@@ -1263,8 +1649,20 @@
 	mlx4_en_release_rss_steer(priv);
 
 	/* Unregister Mac address for the port */
-	mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
-	mdev->mac_removed[priv->port] = 1;
+	mlx4_en_put_qp(priv);
+	if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))
+		mdev->mac_removed[priv->port] = 1;
+
+	/* Remove flow steering rules for the port*/
+	if (mdev->dev->caps.steering_mode ==
+	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
+		ASSERT_RTNL();
+		list_for_each_entry_safe(flow, tmp_flow,
+					 &priv->ethtool_list, list) {
+			mlx4_flow_detach(mdev->dev, flow->id);
+			list_del(&flow->list);
+		}
+	}
 
 	/* Free RX Rings */
 	for (i = 0; i < priv->rx_ring_num; i++) {
@@ -1284,15 +1682,12 @@
 						 watchdog_task);
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct net_device *dev = priv->dev;
-	int i;
 
 	en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port);
 
 	mutex_lock(&mdev->state_lock);
 	if (priv->port_up) {
-		mlx4_en_stop_port(dev);
-		for (i = 0; i < priv->tx_ring_num; i++)
-			netdev_tx_reset_queue(priv->tx_ring[i].tx_queue);
+		mlx4_en_stop_port(dev, 1);
 		if (mlx4_en_start_port(dev))
 			en_err(priv, "Failed restarting port %d\n", priv->port);
 	}
@@ -1362,7 +1757,7 @@
 
 	mutex_lock(&mdev->state_lock);
 
-	mlx4_en_stop_port(dev);
+	mlx4_en_stop_port(dev, 0);
 	netif_carrier_off(dev);
 
 	mutex_unlock(&mdev->state_lock);
@@ -1437,9 +1832,6 @@
 	priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num);
 	if (!priv->dev->rx_cpu_rmap)
 		goto err;
-
-	INIT_LIST_HEAD(&priv->filters);
-	spin_lock_init(&priv->filters_lock);
 #endif
 
 	return 0;
@@ -1503,7 +1895,7 @@
 			 * the port */
 			en_dbg(DRV, priv, "Change MTU called with card down!?\n");
 		} else {
-			mlx4_en_stop_port(dev);
+			mlx4_en_stop_port(dev, 1);
 			err = mlx4_en_start_port(dev);
 			if (err) {
 				en_err(priv, "Failed restarting port:%d\n",
@@ -1527,17 +1919,92 @@
 		priv->ctrl_flags &=
 			cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK);
 
+	mlx4_en_update_loopback_state(netdev, features);
+
 	return 0;
 
 }
 
+static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			   struct net_device *dev,
+			   const unsigned char *addr, u16 flags)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_dev *mdev = priv->mdev->dev;
+	int err;
+
+	if (!mlx4_is_mfunc(mdev))
+		return -EOPNOTSUPP;
+
+	/* Hardware does not support aging addresses, allow only
+	 * permanent addresses if ndm_state is given
+	 */
+	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+		en_info(priv, "Add FDB only supports static addresses\n");
+		return -EINVAL;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_add_excl(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_add_excl(dev, addr);
+	else
+		err = -EINVAL;
+
+	/* Only return duplicate errors if NLM_F_EXCL is set */
+	if (err == -EEXIST && !(flags & NLM_F_EXCL))
+		err = 0;
+
+	return err;
+}
+
+static int mlx4_en_fdb_del(struct ndmsg *ndm,
+			   struct nlattr *tb[],
+			   struct net_device *dev,
+			   const unsigned char *addr)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_dev *mdev = priv->mdev->dev;
+	int err;
+
+	if (!mlx4_is_mfunc(mdev))
+		return -EOPNOTSUPP;
+
+	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+		en_info(priv, "Del FDB only supports static addresses\n");
+		return -EINVAL;
+	}
+
+	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+		err = dev_uc_del(dev, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_del(dev, addr);
+	else
+		err = -EINVAL;
+
+	return err;
+}
+
+static int mlx4_en_fdb_dump(struct sk_buff *skb,
+			    struct netlink_callback *cb,
+			    struct net_device *dev, int idx)
+{
+	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_dev *mdev = priv->mdev->dev;
+
+	if (mlx4_is_mfunc(mdev))
+		idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
+
+	return idx;
+}
+
 static const struct net_device_ops mlx4_netdev_ops = {
 	.ndo_open		= mlx4_en_open,
 	.ndo_stop		= mlx4_en_close,
 	.ndo_start_xmit		= mlx4_en_xmit,
 	.ndo_select_queue	= mlx4_en_select_queue,
 	.ndo_get_stats		= mlx4_en_get_stats,
-	.ndo_set_rx_mode	= mlx4_en_set_multicast,
+	.ndo_set_rx_mode	= mlx4_en_set_rx_mode,
 	.ndo_set_mac_address	= mlx4_en_set_mac,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_change_mtu		= mlx4_en_change_mtu,
@@ -1552,6 +2019,9 @@
 #ifdef CONFIG_RFS_ACCEL
 	.ndo_rx_flow_steer	= mlx4_en_filter_rfs,
 #endif
+	.ndo_fdb_add		= mlx4_en_fdb_add,
+	.ndo_fdb_del		= mlx4_en_fdb_del,
+	.ndo_fdb_dump		= mlx4_en_fdb_dump,
 };
 
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
@@ -1608,7 +2078,7 @@
 	priv->mac_index = -1;
 	priv->msg_enable = MLX4_EN_MSG_LEVEL;
 	spin_lock_init(&priv->stats_lock);
-	INIT_WORK(&priv->mcast_task, mlx4_en_do_set_multicast);
+	INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
 	INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac);
 	INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
 	INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
@@ -1618,22 +2088,35 @@
 		dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
 #endif
 
+	for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
+		INIT_HLIST_HEAD(&priv->mac_hash[i]);
+
 	/* Query for default mac and max mtu */
 	priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
-	priv->mac = mdev->dev->caps.def_mac[priv->port];
-	if (ILLEGAL_MAC(priv->mac)) {
-		en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n",
-			 priv->port, priv->mac);
+
+	/* Set default MAC */
+	dev->addr_len = ETH_ALEN;
+	mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
+		       priv->port, dev->dev_addr);
 		err = -EINVAL;
 		goto out;
 	}
 
+	memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac));
+
 	priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
 					  DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
 	err = mlx4_en_alloc_resources(priv);
 	if (err)
 		goto out;
 
+#ifdef CONFIG_RFS_ACCEL
+	INIT_LIST_HEAD(&priv->filters);
+	spin_lock_init(&priv->filters_lock);
+#endif
+
 	/* Allocate page for receive rings */
 	err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
 				MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
@@ -1653,13 +2136,6 @@
 
 	SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
 
-	/* Set defualt MAC */
-	dev->addr_len = ETH_ALEN;
-	for (i = 0; i < ETH_ALEN; i++) {
-		dev->dev_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
-		dev->perm_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
-	}
-
 	/*
 	 * Set driver features
 	 */
@@ -1679,6 +2155,9 @@
 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
 		dev->hw_features |= NETIF_F_NTUPLE;
 
+	if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
+		dev->priv_flags |= IFF_UNICAST_FLT;
+
 	mdev->pndev[port] = dev;
 
 	netif_carrier_off(dev);
@@ -1692,6 +2171,8 @@
 	en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
 	en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
+	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
 	/* Configure port */
 	mlx4_en_calc_rx_buf(dev);
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index fed26d8..ce38654 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -563,9 +563,6 @@
 	unsigned int length;
 	int polled = 0;
 	int ip_summed;
-	struct ethhdr *ethh;
-	dma_addr_t dma;
-	u64 s_mac;
 	int factor = priv->cqe_factor;
 
 	if (!priv->port_up)
@@ -603,21 +600,41 @@
 			goto next;
 		}
 
-		/* Get pointer to first fragment since we haven't skb yet and
-		 * cast it to ethhdr struct */
-		dma = be64_to_cpu(rx_desc->data[0].addr);
-		dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
-					DMA_FROM_DEVICE);
-		ethh = (struct ethhdr *)(page_address(frags[0].page) +
-					 frags[0].offset);
-		s_mac = mlx4_en_mac_to_u64(ethh->h_source);
+		/* Check if we need to drop the packet if SRIOV is not enabled
+		 * and not performing the selftest or flb disabled
+		 */
+		if (priv->flags & MLX4_EN_FLAG_RX_FILTER_NEEDED) {
+			struct ethhdr *ethh;
+			dma_addr_t dma;
+			/* Get pointer to first fragment since we haven't
+			 * skb yet and cast it to ethhdr struct
+			 */
+			dma = be64_to_cpu(rx_desc->data[0].addr);
+			dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
+						DMA_FROM_DEVICE);
+			ethh = (struct ethhdr *)(page_address(frags[0].page) +
+						 frags[0].offset);
 
-		/* If source MAC is equal to our own MAC and not performing
-		 * the selftest or flb disabled - drop the packet */
-		if (s_mac == priv->mac &&
-		    !((dev->features & NETIF_F_LOOPBACK) ||
-		      priv->validate_loopback))
-			goto next;
+			if (is_multicast_ether_addr(ethh->h_dest)) {
+				struct mlx4_mac_entry *entry;
+				struct hlist_node *n;
+				struct hlist_head *bucket;
+				unsigned int mac_hash;
+
+				/* Drop the packet, since HW loopback-ed it */
+				mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
+				bucket = &priv->mac_hash[mac_hash];
+				rcu_read_lock();
+				hlist_for_each_entry_rcu(entry, n, bucket, hlist) {
+					if (ether_addr_equal_64bits(entry->mac,
+								    ethh->h_source)) {
+						rcu_read_unlock();
+						goto next;
+					}
+				}
+				rcu_read_unlock();
+			}
+		}
 
 		/*
 		 * Packet is OK - process it.
@@ -835,11 +852,9 @@
 	struct mlx4_qp_context *context;
 	int err = 0;
 
-	context = kmalloc(sizeof *context , GFP_KERNEL);
-	if (!context) {
-		en_err(priv, "Failed to allocate qp context\n");
+	context = kmalloc(sizeof(*context), GFP_KERNEL);
+	if (!context)
 		return -ENOMEM;
-	}
 
 	err = mlx4_qp_alloc(mdev->dev, qpn, qp);
 	if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index bf2e5d3..3488c6d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -87,6 +87,8 @@
         priv->loopback_ok = 0;
 	priv->validate_loopback = 1;
 
+	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
 	/* xmit */
 	if (mlx4_en_test_loopback_xmit(priv)) {
 		en_err(priv, "Transmitting loopback packet failed\n");
@@ -107,6 +109,7 @@
 mlx4_en_test_loopback_exit:
 
 	priv->validate_loopback = 0;
+	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
 	return !loopback_ok;
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 6771b69..49308cc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -294,6 +294,8 @@
 		cnt++;
 	}
 
+	netdev_tx_reset_queue(ring->tx_queue);
+
 	if (cnt)
 		en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt);
 
@@ -515,10 +517,6 @@
 		wmb();
 		inl->byte_count = cpu_to_be32(1 << 31 | (skb->len - spc));
 	}
-	tx_desc->ctrl.vlan_tag = cpu_to_be16(*vlan_tag);
-	tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
-		(!!vlan_tx_tag_present(skb));
-	tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
 }
 
 u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
@@ -592,7 +590,21 @@
 		netif_tx_stop_queue(ring->tx_queue);
 		priv->port_stats.queue_stopped++;
 
-		return NETDEV_TX_BUSY;
+		/* If queue was emptied after the if, and before the
+		 * stop_queue - need to wake the queue, or else it will remain
+		 * stopped forever.
+		 * Need a memory barrier to make sure ring->cons was not
+		 * updated before queue was stopped.
+		 */
+		wmb();
+
+		if (unlikely(((int)(ring->prod - ring->cons)) <=
+			     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
+			netif_tx_wake_queue(ring->tx_queue);
+			priv->port_stats.wake_queue++;
+		} else {
+			return NETDEV_TX_BUSY;
+		}
 	}
 
 	/* Track current inflight packets for performance analysis */
@@ -630,7 +642,7 @@
 		ring->tx_csum++;
 	}
 
-	if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) {
+	if (priv->flags & MLX4_EN_FLAG_ENABLE_HW_LOOPBACK) {
 		/* Copy dst mac address to wqe. This allows loopback in eSwitch,
 		 * so that VFs and PF can communicate with each other
 		 */
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 8b3d051..38b62c7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -127,7 +127,8 @@
 		[0] = "RSS support",
 		[1] = "RSS Toeplitz Hash Function support",
 		[2] = "RSS XOR Hash Function support",
-		[3] = "Device manage flow steering support"
+		[3] = "Device manage flow steering support",
+		[4] = "Automatic mac reassignment support"
 	};
 	int i;
 
@@ -478,6 +479,7 @@
 #define QUERY_DEV_CAP_BMME_FLAGS_OFFSET		0x94
 #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET		0x98
 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET		0xa0
+#define QUERY_DEV_CAP_FW_REASSIGN_MAC		0x9d
 
 	dev_cap->flags2 = 0;
 	mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -637,6 +639,9 @@
 		 QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
 	MLX4_GET(dev_cap->reserved_lkey, outbox,
 		 QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
+	MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
+	if (field & 1<<6)
+		dev_cap->flags2 |= MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN;
 	MLX4_GET(dev_cap->max_icm_sz, outbox,
 		 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
 	if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
@@ -1287,14 +1292,14 @@
 		/* Enable Ethernet flow steering
 		 * with udp unicast and tcp unicast
 		 */
-		MLX4_PUT(inbox, param->fs_hash_enable_bits,
+		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
 			 INIT_HCA_FS_ETH_BITS_OFFSET);
 		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
 			 INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
 		/* Enable IPoIB flow steering
 		 * with udp unicast and tcp unicast
 		 */
-		MLX4_PUT(inbox, param->fs_hash_enable_bits,
+		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
 			 INIT_HCA_FS_IB_BITS_OFFSET);
 		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
 			 INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index dbf2f69..3af33ff 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -171,7 +171,6 @@
 	u8  log_mpt_sz;
 	u8  log_uar_sz;
 	u8  uar_page_sz; /* log pg sz in 4k chunks */
-	u8  fs_hash_enable_bits;
 	u8  steering_mode; /* for QUERY_HCA */
 	u64 dev_cap_enabled;
 };
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 5163af3..b9dde13 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1415,22 +1415,6 @@
 		if (mlx4_is_master(dev))
 			mlx4_parav_master_pf_caps(dev);
 
-		priv->fs_hash_mode = MLX4_FS_L2_HASH;
-
-		switch (priv->fs_hash_mode) {
-		case MLX4_FS_L2_HASH:
-			init_hca.fs_hash_enable_bits = 0;
-			break;
-
-		case MLX4_FS_L2_L3_L4_HASH:
-			/* Enable flow steering with
-			 * udp unicast and tcp unicast
-			 */
-			init_hca.fs_hash_enable_bits =
-				MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN;
-			break;
-		}
-
 		profile = default_profile;
 		if (dev->caps.steering_mode ==
 		    MLX4_STEERING_MODE_DEVICE_MANAGED)
@@ -1849,12 +1833,9 @@
 	info->dev = dev;
 	info->port = port;
 	if (!mlx4_is_slave(dev)) {
-		INIT_RADIX_TREE(&info->mac_tree, GFP_KERNEL);
 		mlx4_init_mac_table(dev, &info->mac_table);
 		mlx4_init_vlan_table(dev, &info->vlan_table);
-		info->base_qpn =
-			dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
-			(port - 1) * (1 << log_num_mac);
+		info->base_qpn = mlx4_get_base_qpn(dev, port);
 	}
 
 	sprintf(info->dev_name, "mlx4_port%d", port);
@@ -2070,10 +2051,8 @@
 	/* Allow large DMA segments, up to the firmware limit of 1 GB */
 	dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
 
-	priv = kzalloc(sizeof *priv, GFP_KERNEL);
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
-		dev_err(&pdev->dev, "Device struct alloc failed, "
-			"aborting.\n");
 		err = -ENOMEM;
 		goto err_release_regions;
 	}
@@ -2162,7 +2141,8 @@
 			dev->num_slaves = MLX4_MAX_NUM_SLAVES;
 		else {
 			dev->num_slaves = 0;
-			if (mlx4_multi_func_init(dev)) {
+			err = mlx4_multi_func_init(dev);
+			if (err) {
 				mlx4_err(dev, "Failed to init slave mfunc"
 					 " interface, aborting.\n");
 				goto err_cmd;
@@ -2186,7 +2166,8 @@
 	/* In master functions, the communication channel must be initialized
 	 * after obtaining its address from fw */
 	if (mlx4_is_master(dev)) {
-		if (mlx4_multi_func_init(dev)) {
+		err = mlx4_multi_func_init(dev);
+		if (err) {
 			mlx4_err(dev, "Failed to init master mfunc"
 				 "interface, aborting.\n");
 			goto err_close;
@@ -2203,6 +2184,7 @@
 	mlx4_enable_msi_x(dev);
 	if ((mlx4_is_mfunc(dev)) &&
 	    !(dev->flags & MLX4_FLAG_MSI_X)) {
+		err = -ENOSYS;
 		mlx4_err(dev, "INTx is not supported in multi-function mode."
 			 " aborting.\n");
 		goto err_free_eq;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 1ee4db3..5268552 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -664,7 +664,7 @@
 	dw |= ctrl->priority << 16;
 
 	hw->ctrl = cpu_to_be32(dw);
-	hw->vf_vep_port = cpu_to_be32(ctrl->port);
+	hw->port = ctrl->port;
 	hw->qpn = cpu_to_be32(ctrl->qpn);
 }
 
@@ -1157,7 +1157,7 @@
 			.priority = MLX4_DOMAIN_NIC,
 		};
 
-		rule.allow_loopback = ~block_mcast_loopback;
+		rule.allow_loopback = !block_mcast_loopback;
 		rule.port = port;
 		rule.qpn = qp->qpn;
 		INIT_LIST_HEAD(&rule.list);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 116c5c2..ed4a695 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -60,11 +60,6 @@
 #define MLX4_FS_MGM_LOG_ENTRY_SIZE	7
 #define MLX4_FS_NUM_MCG			(1 << 17)
 
-enum {
-	MLX4_FS_L2_HASH = 0,
-	MLX4_FS_L2_L3_L4_HASH,
-};
-
 #define MLX4_NUM_UP		8
 #define MLX4_NUM_TC		8
 #define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */
@@ -658,11 +653,6 @@
 	__be32 mcast;
 };
 
-struct mlx4_mac_entry {
-	u64 mac;
-	u64 reg_id;
-};
-
 struct mlx4_port_info {
 	struct mlx4_dev	       *dev;
 	int			port;
@@ -672,7 +662,6 @@
 	char			dev_mtu_name[16];
 	struct device_attribute port_mtu_attr;
 	struct mlx4_mac_table	mac_table;
-	struct radix_tree_root	mac_tree;
 	struct mlx4_vlan_table	vlan_table;
 	int			base_qpn;
 };
@@ -696,9 +685,12 @@
 
 struct mlx4_net_trans_rule_hw_ctrl {
 	__be32 ctrl;
-	__be32 vf_vep_port;
+	u8 rsvd1;
+	u8 funcid;
+	u8 vep;
+	u8 port;
 	__be32 qpn;
-	__be32 reserved;
+	__be32 rsvd2;
 };
 
 struct mlx4_net_trans_rule_hw_ib {
@@ -918,7 +910,6 @@
 void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
 int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
 void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
-int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
 int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 		     int start_index, int npages, u64 *page_list);
 int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 8d54412..c313d7e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -198,7 +198,6 @@
  */
 #define ROUNDUP_LOG2(x)		ilog2(roundup_pow_of_two(x))
 #define XNOR(x, y)		(!(x) == !(y))
-#define ILLEGAL_MAC(addr)	(addr == 0xffffffffffffULL || addr == 0x0)
 
 
 struct mlx4_en_tx_info {
@@ -427,10 +426,26 @@
 #endif
 
 struct ethtool_flow_id {
+	struct list_head list;
 	struct ethtool_rx_flow_spec flow_spec;
 	u64 id;
 };
 
+enum {
+	MLX4_EN_FLAG_PROMISC		= (1 << 0),
+	MLX4_EN_FLAG_MC_PROMISC		= (1 << 1),
+	/* whether we need to enable hardware loopback by putting dmac
+	 * in Tx WQE
+	 */
+	MLX4_EN_FLAG_ENABLE_HW_LOOPBACK	= (1 << 2),
+	/* whether we need to drop packets that hardware loopback-ed */
+	MLX4_EN_FLAG_RX_FILTER_NEEDED	= (1 << 3),
+	MLX4_EN_FLAG_FORCE_PROMISC	= (1 << 4)
+};
+
+#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
+#define MLX4_EN_MAC_HASH_IDX 5
+
 struct mlx4_en_priv {
 	struct mlx4_en_dev *mdev;
 	struct mlx4_en_port_profile *prof;
@@ -441,6 +456,8 @@
 	struct mlx4_en_port_state port_state;
 	spinlock_t stats_lock;
 	struct ethtool_flow_id ethtool_rules[MAX_NUM_OF_FS_RULES];
+	/* To allow rules removal while port is going down */
+	struct list_head ethtool_list;
 
 	unsigned long last_moder_packets[MAX_RX_RINGS];
 	unsigned long last_moder_tx_packets;
@@ -469,7 +486,7 @@
 	int registered;
 	int allocated;
 	int stride;
-	u64 mac;
+	unsigned char prev_mac[ETH_ALEN + 2];
 	int mac_index;
 	unsigned max_mtu;
 	int base_qpn;
@@ -478,8 +495,6 @@
 	struct mlx4_en_rss_map rss_map;
 	__be32 ctrl_flags;
 	u32 flags;
-#define MLX4_EN_FLAG_PROMISC	0x1
-#define MLX4_EN_FLAG_MC_PROMISC	0x2
 	u8 num_tx_rings_p_up;
 	u32 tx_ring_num;
 	u32 rx_ring_num;
@@ -493,7 +508,7 @@
 	struct mlx4_en_cq *tx_cq;
 	struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
 	struct mlx4_qp drop_qp;
-	struct work_struct mcast_task;
+	struct work_struct rx_mode_task;
 	struct work_struct mac_task;
 	struct work_struct watchdog_task;
 	struct work_struct linkstate_task;
@@ -510,6 +525,7 @@
 	bool wol;
 	struct device *ddev;
 	int base_tx_qpn;
+	struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
 
 #ifdef CONFIG_MLX4_EN_DCB
 	struct ieee_ets ets;
@@ -529,14 +545,24 @@
 	MLX4_EN_WOL_ENABLED = (1ULL << 62),
 };
 
+struct mlx4_mac_entry {
+	struct hlist_node hlist;
+	unsigned char mac[ETH_ALEN + 2];
+	u64 reg_id;
+	struct rcu_head rcu;
+};
+
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
+void mlx4_en_update_loopback_state(struct net_device *dev,
+				   netdev_features_t features);
+
 void mlx4_en_destroy_netdev(struct net_device *dev);
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 			struct mlx4_en_port_profile *prof);
 
 int mlx4_en_start_port(struct net_device *dev);
-void mlx4_en_stop_port(struct net_device *dev);
+void mlx4_en_stop_port(struct net_device *dev, int detach);
 
 void mlx4_en_free_resources(struct mlx4_en_priv *priv);
 int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 4c51b05..719ead1 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -74,87 +74,6 @@
 	table->total = 0;
 }
 
-static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
-			     u64 mac, int *qpn, u64 *reg_id)
-{
-	__be64 be_mac;
-	int err;
-
-	mac &= MLX4_MAC_MASK;
-	be_mac = cpu_to_be64(mac << 16);
-
-	switch (dev->caps.steering_mode) {
-	case MLX4_STEERING_MODE_B0: {
-		struct mlx4_qp qp;
-		u8 gid[16] = {0};
-
-		qp.qpn = *qpn;
-		memcpy(&gid[10], &be_mac, ETH_ALEN);
-		gid[5] = port;
-
-		err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
-		break;
-	}
-	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
-		struct mlx4_spec_list spec_eth = { {NULL} };
-		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
-
-		struct mlx4_net_trans_rule rule = {
-			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
-			.exclusive = 0,
-			.allow_loopback = 1,
-			.promisc_mode = MLX4_FS_PROMISC_NONE,
-			.priority = MLX4_DOMAIN_NIC,
-		};
-
-		rule.port = port;
-		rule.qpn = *qpn;
-		INIT_LIST_HEAD(&rule.list);
-
-		spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
-		memcpy(spec_eth.eth.dst_mac, &be_mac, ETH_ALEN);
-		memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
-		list_add_tail(&spec_eth.list, &rule.list);
-
-		err = mlx4_flow_attach(dev, &rule, reg_id);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
-	if (err)
-		mlx4_warn(dev, "Failed Attaching Unicast\n");
-
-	return err;
-}
-
-static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
-				  u64 mac, int qpn, u64 reg_id)
-{
-	switch (dev->caps.steering_mode) {
-	case MLX4_STEERING_MODE_B0: {
-		struct mlx4_qp qp;
-		u8 gid[16] = {0};
-		__be64 be_mac;
-
-		qp.qpn = qpn;
-		mac &= MLX4_MAC_MASK;
-		be_mac = cpu_to_be64(mac << 16);
-		memcpy(&gid[10], &be_mac, ETH_ALEN);
-		gid[5] = port;
-
-		mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
-		break;
-	}
-	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
-		mlx4_flow_detach(dev, reg_id);
-		break;
-	}
-	default:
-		mlx4_err(dev, "Invalid steering mode.\n");
-	}
-}
-
 static int validate_index(struct mlx4_dev *dev,
 			  struct mlx4_mac_table *table, int index)
 {
@@ -181,92 +100,6 @@
 	return -EINVAL;
 }
 
-int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn)
-{
-	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
-	struct mlx4_mac_entry *entry;
-	int index = 0;
-	int err = 0;
-	u64 reg_id;
-
-	mlx4_dbg(dev, "Registering MAC: 0x%llx for adding\n",
-			(unsigned long long) mac);
-	index = mlx4_register_mac(dev, port, mac);
-	if (index < 0) {
-		err = index;
-		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
-			 (unsigned long long) mac);
-		return err;
-	}
-
-	if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
-		*qpn = info->base_qpn + index;
-		return 0;
-	}
-
-	err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
-	mlx4_dbg(dev, "Reserved qp %d\n", *qpn);
-	if (err) {
-		mlx4_err(dev, "Failed to reserve qp for mac registration\n");
-		goto qp_err;
-	}
-
-	err = mlx4_uc_steer_add(dev, port, mac, qpn, &reg_id);
-	if (err)
-		goto steer_err;
-
-	entry = kmalloc(sizeof *entry, GFP_KERNEL);
-	if (!entry) {
-		err = -ENOMEM;
-		goto alloc_err;
-	}
-	entry->mac = mac;
-	entry->reg_id = reg_id;
-	err = radix_tree_insert(&info->mac_tree, *qpn, entry);
-	if (err)
-		goto insert_err;
-	return 0;
-
-insert_err:
-	kfree(entry);
-
-alloc_err:
-	mlx4_uc_steer_release(dev, port, mac, *qpn, reg_id);
-
-steer_err:
-	mlx4_qp_release_range(dev, *qpn, 1);
-
-qp_err:
-	mlx4_unregister_mac(dev, port, mac);
-	return err;
-}
-EXPORT_SYMBOL_GPL(mlx4_get_eth_qp);
-
-void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn)
-{
-	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
-	struct mlx4_mac_entry *entry;
-
-	mlx4_dbg(dev, "Registering MAC: 0x%llx for deleting\n",
-		 (unsigned long long) mac);
-	mlx4_unregister_mac(dev, port, mac);
-
-	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
-		entry = radix_tree_lookup(&info->mac_tree, qpn);
-		if (entry) {
-			mlx4_dbg(dev, "Releasing qp: port %d, mac 0x%llx,"
-				 " qpn %d\n", port,
-				 (unsigned long long) mac, qpn);
-			mlx4_uc_steer_release(dev, port, entry->mac,
-					      qpn, entry->reg_id);
-			mlx4_qp_release_range(dev, qpn, 1);
-			radix_tree_delete(&info->mac_tree, qpn);
-			kfree(entry);
-		}
-	}
-}
-EXPORT_SYMBOL_GPL(mlx4_put_eth_qp);
-
 static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
 				   __be64 *entries)
 {
@@ -359,6 +192,12 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_register_mac);
 
+int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
+{
+	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
+			(port - 1) * (1 << dev->caps.log_num_macs);
+}
+EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
 
 void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
 {
@@ -397,29 +236,13 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
 
-int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
+int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
 {
 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
 	struct mlx4_mac_table *table = &info->mac_table;
-	struct mlx4_mac_entry *entry;
 	int index = qpn - info->base_qpn;
 	int err = 0;
 
-	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
-		entry = radix_tree_lookup(&info->mac_tree, qpn);
-		if (!entry)
-			return -EINVAL;
-		mlx4_uc_steer_release(dev, port, entry->mac,
-				      qpn, entry->reg_id);
-		mlx4_unregister_mac(dev, port, entry->mac);
-		entry->mac = new_mac;
-		entry->reg_id = 0;
-		mlx4_register_mac(dev, port, new_mac);
-		err = mlx4_uc_steer_add(dev, port, entry->mac,
-					&qpn, &entry->reg_id);
-		return err;
-	}
-
 	/* CX1 doesn't support multi-functions */
 	mutex_lock(&table->mutex);
 
@@ -439,7 +262,7 @@
 	mutex_unlock(&table->mutex);
 	return err;
 }
-EXPORT_SYMBOL_GPL(mlx4_replace_mac);
+EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
 
 static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
 				    __be32 *entries)
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 561ed2a..5997adc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -3018,7 +3018,7 @@
 	__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
 
 	ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
-	port = be32_to_cpu(ctrl->vf_vep_port) & 0xff;
+	port = ctrl->port;
 	eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1);
 
 	/* Clear a space in the inbox for eth header */
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index b71eb39..fbcb9e7 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -1080,7 +1080,6 @@
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
-	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(netdev->dev_addr, mac, netdev->addr_len);
 
 	ks8842_write_mac_addr(adapter, mac);
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 286816a..33bcb63 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -69,7 +69,6 @@
  * @mii: The MII state information for the mii calls.
  * @rxctrl: RX settings for @rxctrl_work.
  * @tx_work: Work queue for tx packets
- * @irq_work: Work queue for servicing interrupts
  * @rxctrl_work: Work queue for updating RX mode and multicast lists
  * @txq: Queue of packets for transmission.
  * @spi_msg1: pre-setup SPI transfer with one message, @spi_xfer1.
@@ -121,7 +120,6 @@
 	struct ks8851_rxctrl	rxctrl;
 
 	struct work_struct	tx_work;
-	struct work_struct	irq_work;
 	struct work_struct	rxctrl_work;
 
 	struct sk_buff_head	txq;
@@ -444,23 +442,6 @@
 }
 
 /**
- * ks8851_irq - device interrupt handler
- * @irq: Interrupt number passed from the IRQ handler.
- * @pw: The private word passed to register_irq(), our struct ks8851_net.
- *
- * Disable the interrupt from happening again until we've processed the
- * current status by scheduling ks8851_irq_work().
- */
-static irqreturn_t ks8851_irq(int irq, void *pw)
-{
-	struct ks8851_net *ks = pw;
-
-	disable_irq_nosync(irq);
-	schedule_work(&ks->irq_work);
-	return IRQ_HANDLED;
-}
-
-/**
  * ks8851_rdfifo - read data from the receive fifo
  * @ks: The device state.
  * @buff: The buffer address
@@ -595,19 +576,20 @@
 }
 
 /**
- * ks8851_irq_work - work queue handler for dealing with interrupt requests
- * @work: The work structure that was scheduled by schedule_work()
+ * ks8851_irq - IRQ handler for dealing with interrupt requests
+ * @irq: IRQ number
+ * @_ks: cookie
  *
- * This is the handler invoked when the ks8851_irq() is called to find out
- * what happened, as we cannot allow ourselves to sleep whilst waiting for
- * anything other process has the chip's lock.
+ * This handler is invoked when the IRQ line asserts to find out what happened.
+ * As we cannot allow ourselves to sleep in HARDIRQ context, this handler runs
+ * in thread context.
  *
  * Read the interrupt status, work out what needs to be done and then clear
  * any of the interrupts that are not needed.
  */
-static void ks8851_irq_work(struct work_struct *work)
+static irqreturn_t ks8851_irq(int irq, void *_ks)
 {
-	struct ks8851_net *ks = container_of(work, struct ks8851_net, irq_work);
+	struct ks8851_net *ks = _ks;
 	unsigned status;
 	unsigned handled = 0;
 
@@ -688,7 +670,7 @@
 	if (status & IRQ_TXI)
 		netif_wake_queue(ks->netdev);
 
-	enable_irq(ks->netdev->irq);
+	return IRQ_HANDLED;
 }
 
 /**
@@ -896,7 +878,6 @@
 	mutex_unlock(&ks->lock);
 
 	/* stop any outstanding work */
-	flush_work(&ks->irq_work);
 	flush_work(&ks->tx_work);
 	flush_work(&ks->rxctrl_work);
 
@@ -1052,7 +1033,6 @@
 	if (!is_valid_ether_addr(sa->sa_data))
 		return -EADDRNOTAVAIL;
 
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
 	return ks8851_write_mac_addr(dev);
 }
@@ -1438,7 +1418,6 @@
 	spin_lock_init(&ks->statelock);
 
 	INIT_WORK(&ks->tx_work, ks8851_tx_work);
-	INIT_WORK(&ks->irq_work, ks8851_irq_work);
 	INIT_WORK(&ks->rxctrl_work, ks8851_rxctrl_work);
 
 	/* initialise pre-made spi transfer messages */
@@ -1505,8 +1484,9 @@
 	ks8851_read_selftest(ks);
 	ks8851_init_mac(ks);
 
-	ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
-			  ndev->name, ks);
+	ret = request_threaded_irq(spi->irq, NULL, ks8851_irq,
+				   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				   ndev->name, ks);
 	if (ret < 0) {
 		dev_err(&spi->dev, "failed to get irq\n");
 		goto err_irq;
diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index ef8f9f9..a343066 100644
--- a/drivers/net/ethernet/micrel/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -1237,7 +1237,6 @@
 	struct sockaddr *addr = paddr;
 	u8 *da;
 
-	netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
 	da = (u8 *)netdev->dev_addr;
diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c
index a99456c..5d98a9f 100644
--- a/drivers/net/ethernet/microchip/enc28j60.c
+++ b/drivers/net/ethernet/microchip/enc28j60.c
@@ -527,7 +527,6 @@
 	if (!is_valid_ether_addr(address->sa_data))
 		return -EADDRNOTAVAIL;
 
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
 	return enc28j60_set_hw_macaddr(dev);
 }
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index f8408d6..4f9937e 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -664,10 +664,9 @@
 	/* copy header of running firmware from SRAM to host memory to
 	 * validate firmware */
 	hdr = kmalloc(bytes, GFP_KERNEL);
-	if (hdr == NULL) {
-		dev_err(dev, "could not malloc firmware hdr\n");
+	if (hdr == NULL)
 		return -ENOMEM;
-	}
+
 	memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
 	status = myri10ge_validate_firmware(mgp, hdr);
 	kfree(hdr);
diff --git a/drivers/net/ethernet/natsemi/ibmlana.c b/drivers/net/ethernet/natsemi/ibmlana.c
deleted file mode 100644
index 923e640..0000000
--- a/drivers/net/ethernet/natsemi/ibmlana.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
-net-3-driver for the IBM LAN Adapter/A
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
-                                 alfred.arnold@lancom.de)
-
-This driver is based both on the SK_MCA driver, which is itself based on the
-SK_G16 and 3C523 driver.
-
-paper sources:
-  'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
-  Hans-Peter Messmer for the basic Microchannel stuff
-
-  'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
-  for help on Ethernet driver programming
-
-  'DP83934CVUL-20/25 MHz SONIC-T Ethernet Controller Datasheet' by National
-  Semiconductor for info on the MAC chip
-
-  'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0
-   Document Number SC30-3661-00' by IBM for info on the adapter itself
-
-  Also see http://www.national.com/analog 
-
-special acknowledgements to:
-  - Bob Eager for helping me out with documentation from IBM
-  - Jim Shorney for his endless patience with me while I was using
-    him as a beta tester to trace down the address filter bug ;-)
-
-  Missing things:
-
-  -> set debug level via ioctl instead of compile-time switches
-  -> I didn't follow the development of the 2.1.x kernels, so my
-     assumptions about which things changed with which kernel version
-     are probably nonsense
-
-History:
-  Nov 6th, 1999
-  	startup from SK_MCA driver
-  Dec 6th, 1999
-	finally got docs about the card.  A big thank you to Bob Eager!
-  Dec 12th, 1999
-	first packet received
-  Dec 13th, 1999
-	recv queue done, tcpdump works
-  Dec 15th, 1999
-	transmission part works
-  Dec 28th, 1999
-	added usage of the isa_functions for Linux 2.3 .  Things should
-	still work with 2.0.x....
-  Jan 28th, 2000
-	in Linux 2.2.13, the version.h file mysteriously didn't get
-	included.  Added a workaround for this.  Furthermore, it now
-	not only compiles as a modules ;-)
-  Jan 30th, 2000
-	newer kernels automatically probe more than one board, so the
-	'startslot' as a variable is also needed here
-  Apr 12th, 2000
-	the interrupt mask register is not set 'hard' instead of individually
-	setting registers, since this seems to set bits that shouldn't be
-	set
-  May 21st, 2000
-	reset interrupt status immediately after CAM load
-	add a recovery delay after releasing the chip's reset line
-  May 24th, 2000
-	finally found the bug in the address filter setup - damned signed
-        chars!
-  June 1st, 2000
-	corrected version codes, added support for the latest 2.3 changes
-  Oct 28th, 2002
-	cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _IBM_LANA_DRIVER_
-#include "ibmlana.h"
-
-#undef DEBUG
-
-#define DRV_NAME "ibmlana"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] = {
-	"10BaseT", "10Base5", "Unknown", "10Base2"
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-#ifdef DEBUG
-  /* dump all registers */
-
-static void dumpregs(struct net_device *dev)
-{
-	int z;
-
-	for (z = 0; z < 160; z += 2) {
-		if (!(z & 15))
-			printk("REGS: %04x:", z);
-		printk(" %04x", inw(dev->base_addr + z));
-		if ((z & 15) == 14)
-			printk("\n");
-	}
-}
-
-/* dump parts of shared memory - only needed during debugging */
-
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	int z;
-
-	printk("Address %04x:\n", start);
-	for (z = 0; z < len; z++) {
-		if ((z & 15) == 0)
-			printk("%04x:", z);
-		printk(" %02x", readb(priv->base + start + z));
-		if ((z & 15) == 15)
-			printk("\n");
-	}
-	if ((z & 15) != 0)
-		printk("\n");
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	printk("%9d:%06d: ", (int) tv.tv_sec, (int) tv.tv_usec);
-}
-#endif				/* DEBUG */
-
-/* deduce resources out of POS registers */
-
-static void getaddrs(struct mca_device *mdev, int *base, int *memlen,
-		     int *iobase, int *irq, ibmlana_medium *medium)
-{
-	u_char pos0, pos1;
-
-	pos0 = mca_device_read_stored_pos(mdev, 2);
-	pos1 = mca_device_read_stored_pos(mdev, 3);
-
-	*base = 0xc0000 + ((pos1 & 0xf0) << 9);
-	*memlen = (pos1 & 0x01) ? 0x8000 : 0x4000;
-	*iobase = (pos0 & 0xe0) << 7;
-	switch (pos0 & 0x06) {
-	case 0:
-		*irq = 5;
-		break;
-	case 2:
-		*irq = 15;
-		break;
-	case 4:
-		*irq = 10;
-		break;
-	case 6:
-		*irq = 11;
-		break;
-	}
-	*medium = (pos0 & 0x18) >> 3;
-}
-
-/* wait on register value with mask and timeout */
-
-static int wait_timeout(struct net_device *dev, int regoffs, u16 mask,
-			u16 value, int timeout)
-{
-	unsigned long fin = jiffies + timeout;
-
-	while (time_before(jiffies,fin))
-		if ((inw(dev->base_addr + regoffs) & mask) == value)
-			return 1;
-
-	return 0;
-}
-
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
-	unsigned char bcmval;
-
-	/* read original board control value */
-
-	bcmval = inb(dev->base_addr + BCMREG);
-
-	/* set reset bit for a while */
-
-	bcmval |= BCMREG_RESET;
-	outb(bcmval, dev->base_addr + BCMREG);
-	udelay(10);
-	bcmval &= ~BCMREG_RESET;
-	outb(bcmval, dev->base_addr + BCMREG);
-
-	/* switch over to RAM again */
-
-	bcmval |= BCMREG_RAMEN | BCMREG_RAMWIN;
-	outb(bcmval, dev->base_addr + BCMREG);
-}
-
-/* calculate RAM layout & set up descriptors in RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	u32 addr, baddr, raddr;
-	int z;
-	tda_t tda;
-	rda_t rda;
-	rra_t rra;
-
-	/* initialize RAM */
-
-	memset_io(priv->base, 0xaa,
-		      dev->mem_start - dev->mem_start);	/* XXX: typo? */
-
-	/* setup n TX descriptors - independent of RAM size */
-
-	priv->tdastart = addr = 0;
-	priv->txbufstart = baddr = sizeof(tda_t) * TXBUFCNT;
-	for (z = 0; z < TXBUFCNT; z++) {
-		tda.status = 0;
-		tda.config = 0;
-		tda.length = 0;
-		tda.fragcount = 1;
-		tda.startlo = baddr;
-		tda.starthi = 0;
-		tda.fraglength = 0;
-		if (z == TXBUFCNT - 1)
-			tda.link = priv->tdastart;
-		else
-			tda.link = addr + sizeof(tda_t);
-		tda.link |= 1;
-		memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
-		addr += sizeof(tda_t);
-		baddr += PKTSIZE;
-	}
-
-	/* calculate how many receive buffers fit into remaining memory */
-
-	priv->rxbufcnt = (dev->mem_end - dev->mem_start - baddr) / (sizeof(rra_t) + sizeof(rda_t) + PKTSIZE);
-
-	/* calculate receive addresses */
-
-	priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE);
-	priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t));
-	priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t));
-
-	for (z = 0; z < priv->rxbufcnt; z++) {
-		rra.startlo = baddr;
-		rra.starthi = 0;
-		rra.cntlo = PKTSIZE >> 1;
-		rra.cnthi = 0;
-		memcpy_toio(priv->base + raddr, &rra, sizeof(rra_t));
-
-		rda.status = 0;
-		rda.length = 0;
-		rda.startlo = 0;
-		rda.starthi = 0;
-		rda.seqno = 0;
-		if (z < priv->rxbufcnt - 1)
-			rda.link = addr + sizeof(rda_t);
-		else
-			rda.link = 1;
-		rda.inuse = 1;
-		memcpy_toio(priv->base + addr, &rda, sizeof(rda_t));
-
-		baddr += PKTSIZE;
-		raddr += sizeof(rra_t);
-		addr += sizeof(rda_t);
-	}
-
-	/* initialize current pointers */
-
-	priv->nextrxdescr = 0;
-	priv->lastrxdescr = priv->rxbufcnt - 1;
-	priv->nexttxdescr = 0;
-	priv->currtxdescr = 0;
-	priv->txusedcnt = 0;
-	memset(priv->txused, 0, sizeof(priv->txused));
-}
-
-/* set up Rx + Tx descriptors in SONIC */
-
-static int InitSONIC(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-
-	/* set up start & end of resource area */
-
-	outw(0, SONIC_URRA);
-	outw(priv->rrastart, dev->base_addr + SONIC_RSA);
-	outw(priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)), dev->base_addr + SONIC_REA);
-	outw(priv->rrastart, dev->base_addr + SONIC_RRP);
-	outw(priv->rrastart, dev->base_addr + SONIC_RWP);
-
-	/* set EOBC so that only one packet goes into one buffer */
-
-	outw((PKTSIZE - 4) >> 1, dev->base_addr + SONIC_EOBC);
-
-	/* let SONIC read the first RRA descriptor */
-
-	outw(CMDREG_RRRA, dev->base_addr + SONIC_CMDREG);
-	if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_RRRA, 0, 2)) {
-		printk(KERN_ERR "%s: SONIC did not respond on RRRA command - giving up.", dev->name);
-		return 0;
-	}
-
-	/* point SONIC to the first RDA */
-
-	outw(0, dev->base_addr + SONIC_URDA);
-	outw(priv->rdastart, dev->base_addr + SONIC_CRDA);
-
-	/* set upper half of TDA address */
-
-	outw(0, dev->base_addr + SONIC_UTDA);
-
-	return 1;
-}
-
-/* stop SONIC so we can reinitialize it */
-
-static void StopSONIC(struct net_device *dev)
-{
-	/* disable interrupts */
-
-	outb(inb(dev->base_addr + BCMREG) & (~BCMREG_IEN), dev->base_addr + BCMREG);
-	outb(0, dev->base_addr + SONIC_IMREG);
-
-	/* reset the SONIC */
-
-	outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-	udelay(10);
-	outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-}
-
-/* initialize card and SONIC for proper operation */
-
-static void putcam(camentry_t * cams, int *camcnt, char *addr)
-{
-	camentry_t *pcam = cams + (*camcnt);
-	u8 *uaddr = (u8 *) addr;
-
-	pcam->index = *camcnt;
-	pcam->addr0 = (((u16) uaddr[1]) << 8) | uaddr[0];
-	pcam->addr1 = (((u16) uaddr[3]) << 8) | uaddr[2];
-	pcam->addr2 = (((u16) uaddr[5]) << 8) | uaddr[4];
-	(*camcnt)++;
-}
-
-static void InitBoard(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	int camcnt;
-	camentry_t cams[16];
-	u32 cammask;
-	struct netdev_hw_addr *ha;
-	u16 rcrval;
-
-	/* reset the SONIC */
-
-	outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-	udelay(10);
-
-	/* clear all spurious interrupts */
-
-	outw(inw(dev->base_addr + SONIC_ISREG), dev->base_addr + SONIC_ISREG);
-
-	/* set up the SONIC's bus interface - constant for this adapter -
-	   must be done while the SONIC is in reset */
-
-	outw(DCREG_USR1 | DCREG_USR0 | DCREG_WC1 | DCREG_DW32, dev->base_addr + SONIC_DCREG);
-	outw(0, dev->base_addr + SONIC_DCREG2);
-
-	/* remove reset form the SONIC */
-
-	outw(0, dev->base_addr + SONIC_CMDREG);
-	udelay(10);
-
-	/* data sheet requires URRA to be programmed before setting up the CAM contents */
-
-	outw(0, dev->base_addr + SONIC_URRA);
-
-	/* program the CAM entry 0 to the device address */
-
-	camcnt = 0;
-	putcam(cams, &camcnt, dev->dev_addr);
-
-	/* start putting the multicast addresses into the CAM list.  Stop if
-	   it is full. */
-
-	netdev_for_each_mc_addr(ha, dev) {
-		putcam(cams, &camcnt, ha->addr);
-		if (camcnt == 16)
-			break;
-	}
-
-	/* calculate CAM mask */
-
-	cammask = (1 << camcnt) - 1;
-
-	/* feed CDA into SONIC, initialize RCR value (always get broadcasts) */
-
-	memcpy_toio(priv->base, cams, sizeof(camentry_t) * camcnt);
-	memcpy_toio(priv->base + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
-
-#ifdef DEBUG
-	printk("CAM setup:\n");
-	dumpmem(dev, 0, sizeof(camentry_t) * camcnt + sizeof(cammask));
-#endif
-
-	outw(0, dev->base_addr + SONIC_CAMPTR);
-	outw(camcnt, dev->base_addr + SONIC_CAMCNT);
-	outw(CMDREG_LCAM, dev->base_addr + SONIC_CMDREG);
-	if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_LCAM, 0, 2)) {
-		printk(KERN_ERR "%s:SONIC did not respond on LCAM command - giving up.", dev->name);
-		return;
-	} else {
-		/* clear interrupt condition */
-
-		outw(ISREG_LCD, dev->base_addr + SONIC_ISREG);
-
-#ifdef DEBUG
-		printk("Loading CAM done, address pointers %04x:%04x\n",
-		       inw(dev->base_addr + SONIC_URRA),
-		       inw(dev->base_addr + SONIC_CAMPTR));
-		{
-			int z;
-
-			printk("\n-->CAM: PTR %04x CNT %04x\n",
-			       inw(dev->base_addr + SONIC_CAMPTR),
-			       inw(dev->base_addr + SONIC_CAMCNT));
-			outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-			for (z = 0; z < camcnt; z++) {
-				outw(z, dev->base_addr + SONIC_CAMEPTR);
-				printk("Entry %d: %04x %04x %04x\n", z,
-				       inw(dev->base_addr + SONIC_CAMADDR0),
-				       inw(dev->base_addr + SONIC_CAMADDR1),
-				       inw(dev->base_addr + SONIC_CAMADDR2));
-			}
-			outw(0, dev->base_addr + SONIC_CMDREG);
-		}
-#endif
-	}
-
-	rcrval = RCREG_BRD | RCREG_LB_NONE;
-
-	/* if still multicast addresses left or ALLMULTI is set, set the multicast
-	   enable bit */
-
-	if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > camcnt)
-		rcrval |= RCREG_AMC;
-
-	/* promiscuous mode ? */
-
-	if (dev->flags & IFF_PROMISC)
-		rcrval |= RCREG_PRO;
-
-	/* program receive mode */
-
-	outw(rcrval, dev->base_addr + SONIC_RCREG);
-#ifdef DEBUG
-	printk("\nRCRVAL: %04x\n", rcrval);
-#endif
-
-	/* set up descriptors in shared memory + feed them into SONIC registers */
-
-	InitDscrs(dev);
-	if (!InitSONIC(dev))
-		return;
-
-	/* reset all pending interrupts */
-
-	outw(0xffff, dev->base_addr + SONIC_ISREG);
-
-	/* enable transmitter + receiver interrupts */
-
-	outw(CMDREG_RXEN, dev->base_addr + SONIC_CMDREG);
-	outw(IMREG_PRXEN | IMREG_RBEEN | IMREG_PTXEN | IMREG_TXEREN, dev->base_addr + SONIC_IMREG);
-
-	/* turn on card interrupts */
-
-	outb(inb(dev->base_addr + BCMREG) | BCMREG_IEN, dev->base_addr + BCMREG);
-
-#ifdef DEBUG
-	printk("Register dump after initialization:\n");
-	dumpregs(dev);
-#endif
-}
-
-/* start transmission of a descriptor */
-
-static void StartTx(struct net_device *dev, int descr)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	int addr;
-
-	addr = priv->tdastart + (descr * sizeof(tda_t));
-
-	/* put descriptor address into SONIC */
-
-	outw(addr, dev->base_addr + SONIC_CTDA);
-
-	/* trigger transmitter */
-
-	priv->currtxdescr = descr;
-	outw(CMDREG_TXP, dev->base_addr + SONIC_CMDREG);
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* receive buffer area exhausted */
-
-static void irqrbe_handler(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-
-	/* point the SONIC back to the RRA start */
-
-	outw(priv->rrastart, dev->base_addr + SONIC_RRP);
-	outw(priv->rrastart, dev->base_addr + SONIC_RWP);
-}
-
-/* receive interrupt */
-
-static void irqrx_handler(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	rda_t rda;
-	u32 rdaaddr, lrdaaddr;
-
-	/* loop until ... */
-
-	while (1) {
-		/* read descriptor that was next to be filled by SONIC */
-
-		rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t));
-		lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
-		memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
-
-		/* iron out upper word halves of fields we use - SONIC will duplicate
-		   bits 0..15 to 16..31 */
-
-		rda.status &= 0xffff;
-		rda.length &= 0xffff;
-		rda.startlo &= 0xffff;
-
-		/* stop if the SONIC still owns it, i.e. there is no data for us */
-
-		if (rda.inuse)
-			break;
-
-		/* good packet? */
-
-		else if (rda.status & RCREG_PRX) {
-			struct sk_buff *skb;
-
-			/* fetch buffer */
-
-			skb = netdev_alloc_skb(dev, rda.length + 2);
-			if (skb == NULL)
-				dev->stats.rx_dropped++;
-			else {
-				/* copy out data */
-
-				memcpy_fromio(skb_put(skb, rda.length),
-					       priv->base +
-					       rda.startlo, rda.length);
-
-				/* set up skb fields */
-
-				skb->protocol = eth_type_trans(skb, dev);
-				skb_checksum_none_assert(skb);
-
-				/* bookkeeping */
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += rda.length;
-
-				/* pass to the upper layers */
-				netif_rx(skb);
-			}
-		}
-
-		/* otherwise check error status bits and increase statistics */
-
-		else {
-			dev->stats.rx_errors++;
-			if (rda.status & RCREG_FAER)
-				dev->stats.rx_frame_errors++;
-			if (rda.status & RCREG_CRCR)
-				dev->stats.rx_crc_errors++;
-		}
-
-		/* descriptor processed, will become new last descriptor in queue */
-
-		rda.link = 1;
-		rda.inuse = 1;
-		memcpy_toio(priv->base + rdaaddr, &rda,
-			     sizeof(rda_t));
-
-		/* set up link and EOL = 0 in currently last descriptor. Only write
-		   the link field since the SONIC may currently already access the
-		   other fields. */
-
-		memcpy_toio(priv->base + lrdaaddr + 20, &rdaaddr, 4);
-
-		/* advance indices */
-
-		priv->lastrxdescr = priv->nextrxdescr;
-		if ((++priv->nextrxdescr) >= priv->rxbufcnt)
-			priv->nextrxdescr = 0;
-	}
-}
-
-/* transmit interrupt */
-
-static void irqtx_handler(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	tda_t tda;
-
-	/* fetch descriptor (we forgot the size ;-) */
-	memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
-
-	/* update statistics */
-	dev->stats.tx_packets++;
-	dev->stats.tx_bytes += tda.length;
-
-	/* update our pointers */
-	priv->txused[priv->currtxdescr] = 0;
-	priv->txusedcnt--;
-
-	/* if there are more descriptors present in RAM, start them */
-	if (priv->txusedcnt > 0)
-		StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
-
-	/* tell the upper layer we can go on transmitting */
-	netif_wake_queue(dev);
-}
-
-static void irqtxerr_handler(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	tda_t tda;
-
-	/* fetch descriptor to check status */
-	memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
-
-	/* update statistics */
-	dev->stats.tx_errors++;
-	if (tda.status & (TCREG_NCRS | TCREG_CRSL))
-		dev->stats.tx_carrier_errors++;
-	if (tda.status & TCREG_EXC)
-		dev->stats.tx_aborted_errors++;
-	if (tda.status & TCREG_OWC)
-		dev->stats.tx_window_errors++;
-	if (tda.status & TCREG_FU)
-		dev->stats.tx_fifo_errors++;
-
-	/* update our pointers */
-	priv->txused[priv->currtxdescr] = 0;
-	priv->txusedcnt--;
-
-	/* if there are more descriptors present in RAM, start them */
-	if (priv->txusedcnt > 0)
-		StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
-
-	/* tell the upper layer we can go on transmitting */
-	netif_wake_queue(dev);
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int dummy, void *device)
-{
-	struct net_device *dev = device;
-	u16 ival;
-
-	/* in case we're not meant... */
-	if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND))
-		return IRQ_NONE;
-
-	/* loop through the interrupt bits until everything is clear */
-	while (1) {
-		ival = inw(dev->base_addr + SONIC_ISREG);
-
-		if (ival & ISREG_RBE) {
-			irqrbe_handler(dev);
-			outw(ISREG_RBE, dev->base_addr + SONIC_ISREG);
-		}
-		if (ival & ISREG_PKTRX) {
-			irqrx_handler(dev);
-			outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG);
-		}
-		if (ival & ISREG_TXDN) {
-			irqtx_handler(dev);
-			outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG);
-		}
-		if (ival & ISREG_TXER) {
-			irqtxerr_handler(dev);
-			outw(ISREG_TXER, dev->base_addr + SONIC_ISREG);
-		}
-		break;
-	}
-	return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-#if 0 /* info available elsewhere, but this is kept for reference */
-static int ibmlana_getinfo(char *buf, int slot, void *d)
-{
-	int len = 0, i;
-	struct net_device *dev = (struct net_device *) d;
-	ibmlana_priv *priv;
-
-	/* can't say anything about an uninitialized device... */
-
-	if (dev == NULL)
-		return len;
-	priv = netdev_priv(dev);
-
-	/* print info */
-
-	len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
-	len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr);
-	len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, dev->mem_end - 1);
-	len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
-	len += sprintf(buf + len, "Device: %s\n", dev->name);
-	len += sprintf(buf + len, "MAC address:");
-	for (i = 0; i < 6; i++)
-		len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
-	buf[len++] = '\n';
-	buf[len] = 0;
-
-	return len;
-}
-#endif
-
-/* open driver.  Means also initialization and start of LANCE */
-
-static int ibmlana_open(struct net_device *dev)
-{
-	int result;
-	ibmlana_priv *priv = netdev_priv(dev);
-
-	/* register resources - only necessary for IRQ */
-
-	result = request_irq(priv->realirq, irq_handler, IRQF_SHARED,
-			     dev->name, dev);
-	if (result != 0) {
-		printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
-		return result;
-	}
-	dev->irq = priv->realirq;
-
-	/* set up the card and SONIC */
-	InitBoard(dev);
-
-	/* initialize operational flags */
-	netif_start_queue(dev);
-	return 0;
-}
-
-/* close driver.  Shut down board and free allocated resources */
-
-static int ibmlana_close(struct net_device *dev)
-{
-	/* turn off board */
-
-	/* release resources */
-	if (dev->irq != 0)
-		free_irq(dev->irq, dev);
-	dev->irq = 0;
-	return 0;
-}
-
-/* transmit a block. */
-
-static netdev_tx_t ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	int tmplen, addr;
-	unsigned long flags;
-	tda_t tda;
-	int baddr;
-
-	/* find out if there are free slots for a frame to transmit. If not,
-	   the upper layer is in deep desperation and we simply ignore the frame. */
-
-	if (priv->txusedcnt >= TXBUFCNT) {
-		dev->stats.tx_dropped++;
-		goto tx_done;
-	}
-
-	/* copy the frame data into the next free transmit buffer - fillup missing */
-	tmplen = skb->len;
-	if (tmplen < 60)
-		tmplen = 60;
-	baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
-	memcpy_toio(priv->base + baddr, skb->data, skb->len);
-
-	/* copy filler into RAM - in case we're filling up...
-	   we're filling a bit more than necessary, but that doesn't harm
-	   since the buffer is far larger...
-	   Sorry Linus for the filler string but I couldn't resist ;-) */
-
-	if (tmplen > skb->len) {
-		char *fill = "NetBSD is a nice OS too! ";
-		unsigned int destoffs = skb->len, l = strlen(fill);
-
-		while (destoffs < tmplen) {
-			memcpy_toio(priv->base + baddr + destoffs, fill, l);
-			destoffs += l;
-		}
-	}
-
-	/* set up the new frame descriptor */
-	addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));
-	memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t));
-	tda.length = tda.fraglength = tmplen;
-	memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
-
-	/* if there were no active descriptors, trigger the SONIC */
-	spin_lock_irqsave(&priv->lock, flags);
-
-	priv->txusedcnt++;
-	priv->txused[priv->nexttxdescr] = 1;
-
-	/* are all transmission slots used up ? */
-	if (priv->txusedcnt >= TXBUFCNT)
-		netif_stop_queue(dev);
-
-	if (priv->txusedcnt == 1)
-		StartTx(dev, priv->nexttxdescr);
-	priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-tx_done:
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-}
-
-/* switch receiver mode. */
-
-static void ibmlana_set_multicast_list(struct net_device *dev)
-{
-	/* first stop the SONIC... */
-	StopSONIC(dev);
-	/* ...then reinit it with the new flags */
-	InitBoard(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int ibmlana_irq;
-static int ibmlana_io;
-static int startslot;		/* counts through slots when probing multiple devices */
-
-static short ibmlana_adapter_ids[] __initdata = {
-	IBM_LANA_ID,
-	0x0000
-};
-
-static char *ibmlana_adapter_names[] = {
-	"IBM LAN Adapter/A",
-	NULL
-};
-
-
-static const struct net_device_ops ibmlana_netdev_ops = {
-	.ndo_open 		= ibmlana_open,
-	.ndo_stop 		= ibmlana_close,
-	.ndo_start_xmit		= ibmlana_tx,
-	.ndo_set_rx_mode	= ibmlana_set_multicast_list,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int ibmlana_init_one(struct device *kdev)
-{
-	struct mca_device *mdev = to_mca_device(kdev);
-	struct net_device *dev;
-	int slot = mdev->slot, z, rc;
-	int base = 0, irq = 0, iobase = 0, memlen = 0;
-	ibmlana_priv *priv;
-	ibmlana_medium medium;
-
-	dev = alloc_etherdev(sizeof(ibmlana_priv));
-	if (!dev)
-		return -ENOMEM;
-
-	dev->irq = ibmlana_irq;
-	dev->base_addr = ibmlana_io;
-
-	base = dev->mem_start;
-	irq = dev->irq;
-
-	/* deduce card addresses */
-	getaddrs(mdev, &base, &memlen, &iobase, &irq, &medium);
-
-	/* were we looking for something different ? */
-	if (dev->irq && dev->irq != irq) {
-		rc = -ENODEV;
-		goto err_out;
-	}
-	if (dev->mem_start && dev->mem_start != base) {
-		rc = -ENODEV;
-		goto err_out;
-	}
-
-	/* announce success */
-	printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1);
-
-	/* try to obtain I/O range */
-	if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) {
-		printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase);
-		startslot = slot + 1;
-		rc = -EBUSY;
-		goto err_out;
-	}
-
-	priv = netdev_priv(dev);
-	priv->slot = slot;
-	priv->realirq = mca_device_transform_irq(mdev, irq);
-	priv->medium = medium;
-	spin_lock_init(&priv->lock);
-
-	/* set base + irq for this device (irq not allocated so far) */
-
-	dev->irq = 0;
-	dev->mem_start = base;
-	dev->mem_end = base + memlen;
-	dev->base_addr = iobase;
-
-	priv->base = ioremap(base, memlen);
-	if (!priv->base) {
-		printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
-		startslot = slot + 1;
-		rc = -EBUSY;
-		goto err_out_reg;
-	}
-
-	mca_device_set_name(mdev, ibmlana_adapter_names[mdev->index]);
-	mca_device_set_claim(mdev, 1);
-
-	/* set methods */
-	dev->netdev_ops = &ibmlana_netdev_ops;
-	dev->flags |= IFF_MULTICAST;
-
-	/* copy out MAC address */
-
-	for (z = 0; z < ETH_ALEN; z++)
-		dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z);
-
-	/* print config */
-
-	printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
-	       "MAC address %pM.\n",
-	       dev->name, priv->realirq, dev->base_addr,
-	       dev->mem_start, dev->mem_end - 1,
-	       dev->dev_addr);
-	printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
-	/* reset board */
-
-	ResetBoard(dev);
-
-	/* next probe will start at next slot */
-
-	startslot = slot + 1;
-
-	rc = register_netdev(dev);
-	if (rc)
-		goto err_out_claimed;
-
-	dev_set_drvdata(kdev, dev);
-	return 0;
-
-err_out_claimed:
-	mca_device_set_claim(mdev, 0);
-	iounmap(priv->base);
-err_out_reg:
-	release_region(iobase, IBM_LANA_IORANGE);
-err_out:
-	free_netdev(dev);
-	return rc;
-}
-
-static int ibmlana_remove_one(struct device *kdev)
-{
-	struct mca_device *mdev = to_mca_device(kdev);
-	struct net_device *dev = dev_get_drvdata(kdev);
-	ibmlana_priv *priv = netdev_priv(dev);
-
-	unregister_netdev(dev);
-	/*DeinitBoard(dev); */
-	release_region(dev->base_addr, IBM_LANA_IORANGE);
-	mca_device_set_claim(mdev, 0);
-	iounmap(priv->base);
-	free_netdev(dev);
-	return 0;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-module_param_named(irq, ibmlana_irq, int, 0);
-module_param_named(io, ibmlana_io, int, 0);
-MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
-MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
-MODULE_LICENSE("GPL");
-
-static struct mca_driver ibmlana_driver = {
-	.id_table = ibmlana_adapter_ids,
-	.driver = {
-		.name	= "ibmlana",
-		.bus	= &mca_bus_type,
-		.probe	= ibmlana_init_one,
-		.remove	= ibmlana_remove_one,
-	},
-};
-
-static int __init ibmlana_init_module(void)
-{
-	return mca_register_driver(&ibmlana_driver);
-}
-
-static void __exit ibmlana_cleanup_module(void)
-{
-	mca_unregister_driver(&ibmlana_driver);
-}
-
-module_init(ibmlana_init_module);
-module_exit(ibmlana_cleanup_module);
diff --git a/drivers/net/ethernet/natsemi/ibmlana.h b/drivers/net/ethernet/natsemi/ibmlana.h
deleted file mode 100644
index accd5ef..0000000
--- a/drivers/net/ethernet/natsemi/ibmlana.h
+++ /dev/null
@@ -1,278 +0,0 @@
-#ifndef _IBM_LANA_INCLUDE_
-#define _IBM_LANA_INCLUDE_
-
-#ifdef _IBM_LANA_DRIVER_
-
-/* maximum packet size */
-
-#define PKTSIZE 1524
-
-/* number of transmit buffers */
-
-#define TXBUFCNT 4
-
-/* Adapter ID's */
-#define IBM_LANA_ID 0xffe0
-
-/* media enumeration - defined in a way that it fits onto the LAN/A's
-   POS registers... */
-
-typedef enum {
-	Media_10BaseT, Media_10Base5,
-	Media_Unknown, Media_10Base2, Media_Count
-} ibmlana_medium;
-
-/* private structure */
-
-typedef struct {
-	unsigned int slot;		/* MCA-Slot-#                       */
-	int realirq;			/* memorizes actual IRQ, even when
-					   currently not allocated          */
-	ibmlana_medium medium;		/* physical cannector               */
-	u32 	tdastart, txbufstart,	/* addresses                        */
-		rrastart, rxbufstart, rdastart, rxbufcnt, txusedcnt;
-	int 	nextrxdescr,		/* next rx descriptor to be used    */
-		lastrxdescr,		/* last free rx descriptor          */
-		nexttxdescr,		/* last tx descriptor to be used    */
-		currtxdescr,		/* tx descriptor currently tx'ed    */
-		txused[TXBUFCNT];	/* busy flags                       */
-	void __iomem *base;
-	spinlock_t lock;
-} ibmlana_priv;
-
-/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes
-   a full 64K I/O range... */
-
-#define IBM_LANA_IORANGE 0xa0
-
-/* Command Register: */
-
-#define SONIC_CMDREG     0x00
-#define CMDREG_HTX       0x0001	/* halt transmission                */
-#define CMDREG_TXP       0x0002	/* start transmission               */
-#define CMDREG_RXDIS     0x0004	/* disable receiver                 */
-#define CMDREG_RXEN      0x0008	/* enable receiver                  */
-#define CMDREG_STP       0x0010	/* stop timer                       */
-#define CMDREG_ST        0x0020	/* start timer                      */
-#define CMDREG_RST       0x0080	/* software reset                   */
-#define CMDREG_RRRA      0x0100	/* force SONIC to read first RRA    */
-#define CMDREG_LCAM      0x0200	/* force SONIC to read CAM descrs   */
-
-/* Data Configuration Register */
-
-#define SONIC_DCREG      0x02
-#define DCREG_EXBUS      0x8000	/* Extended Bus Mode                */
-#define DCREG_LBR        0x2000	/* Latched Bus Retry                */
-#define DCREG_PO1        0x1000	/* Programmable Outputs             */
-#define DCREG_PO0        0x0800
-#define DCREG_SBUS       0x0400	/* Synchronous Bus Mode             */
-#define DCREG_USR1       0x0200	/* User Definable Pins              */
-#define DCREG_USR0       0x0100
-#define DCREG_WC0        0x0000	/* 0..3 Wait States                 */
-#define DCREG_WC1        0x0040
-#define DCREG_WC2        0x0080
-#define DCREG_WC3        0x00c0
-#define DCREG_DW16       0x0000	/* 16 bit Bus Mode                  */
-#define DCREG_DW32       0x0020	/* 32 bit Bus Mode                  */
-#define DCREG_BMS        0x0010	/* Block Mode Select                */
-#define DCREG_RFT4       0x0000	/* 4/8/16/24 bytes RX  Threshold    */
-#define DCREG_RFT8       0x0004
-#define DCREG_RFT16      0x0008
-#define DCREG_RFT24      0x000c
-#define DCREG_TFT8       0x0000	/* 8/16/24/28 bytes TX Threshold    */
-#define DCREG_TFT16      0x0001
-#define DCREG_TFT24      0x0002
-#define DCREG_TFT28      0x0003
-
-/* Receive Control Register */
-
-#define SONIC_RCREG      0x04
-#define RCREG_ERR        0x8000	/* accept damaged and collided pkts */
-#define RCREG_RNT        0x4000	/* accept packets that are < 64     */
-#define RCREG_BRD        0x2000	/* accept broadcasts                */
-#define RCREG_PRO        0x1000	/* promiscuous mode                  */
-#define RCREG_AMC        0x0800	/* accept all multicasts            */
-#define RCREG_LB_NONE    0x0000	/* no loopback                      */
-#define RCREG_LB_MAC     0x0200	/* MAC loopback                     */
-#define RCREG_LB_ENDEC   0x0400	/* ENDEC loopback                   */
-#define RCREG_LB_XVR     0x0600	/* Transceiver loopback             */
-#define RCREG_MC         0x0100	/* Multicast received               */
-#define RCREG_BC         0x0080	/* Broadcast received               */
-#define RCREG_LPKT       0x0040	/* last packet in RBA               */
-#define RCREG_CRS        0x0020	/* carrier sense present            */
-#define RCREG_COL        0x0010	/* recv'd packet with collision     */
-#define RCREG_CRCR       0x0008	/* recv'd packet with CRC error     */
-#define RCREG_FAER       0x0004	/* recv'd packet with inv. framing  */
-#define RCREG_LBK        0x0002	/* recv'd loopback packet           */
-#define RCREG_PRX        0x0001	/* recv'd packet is OK              */
-
-/* Transmit Control Register */
-
-#define SONIC_TCREG      0x06
-#define TCREG_PINT       0x8000	/* generate interrupt after TDA read */
-#define TCREG_POWC       0x4000	/* timer start out of window detect */
-#define TCREG_CRCI       0x2000	/* inhibit CRC generation           */
-#define TCREG_EXDIS      0x1000	/* disable excessive deferral timer */
-#define TCREG_EXD        0x0400	/* excessive deferral occurred       */
-#define TCREG_DEF        0x0200	/* single deferral occurred          */
-#define TCREG_NCRS       0x0100	/* no carrier detected              */
-#define TCREG_CRSL       0x0080	/* carrier lost                     */
-#define TCREG_EXC        0x0040	/* excessive collisions occurred     */
-#define TCREG_OWC        0x0020	/* out of window collision occurred  */
-#define TCREG_PMB        0x0008	/* packet monitored bad             */
-#define TCREG_FU         0x0004	/* FIFO underrun                    */
-#define TCREG_BCM        0x0002	/* byte count mismatch of fragments */
-#define TCREG_PTX        0x0001	/* packet transmitted OK            */
-
-/* Interrupt Mask Register */
-
-#define SONIC_IMREG      0x08
-#define IMREG_BREN       0x4000	/* interrupt when bus retry occurred */
-#define IMREG_HBLEN      0x2000	/* interrupt when heartbeat lost    */
-#define IMREG_LCDEN      0x1000	/* interrupt when CAM loaded        */
-#define IMREG_PINTEN     0x0800	/* interrupt when PINT in TDA set   */
-#define IMREG_PRXEN      0x0400	/* interrupt when packet received   */
-#define IMREG_PTXEN      0x0200	/* interrupt when packet was sent   */
-#define IMREG_TXEREN     0x0100	/* interrupt when send failed       */
-#define IMREG_TCEN       0x0080	/* interrupt when timer completed   */
-#define IMREG_RDEEN      0x0040	/* interrupt when RDA exhausted     */
-#define IMREG_RBEEN      0x0020	/* interrupt when RBA exhausted     */
-#define IMREG_RBAEEN     0x0010	/* interrupt when RBA too short     */
-#define IMREG_CRCEN      0x0008	/* interrupt when CRC counter rolls */
-#define IMREG_FAEEN      0x0004	/* interrupt when FAE counter rolls */
-#define IMREG_MPEN       0x0002	/* interrupt when MP counter rolls  */
-#define IMREG_RFOEN      0x0001	/* interrupt when Rx FIFO overflows */
-
-/* Interrupt Status Register */
-
-#define SONIC_ISREG      0x0a
-#define ISREG_BR         0x4000	/* bus retry occurred                */
-#define ISREG_HBL        0x2000	/* heartbeat lost                   */
-#define ISREG_LCD        0x1000	/* CAM loaded                       */
-#define ISREG_PINT       0x0800	/* PINT in TDA set                  */
-#define ISREG_PKTRX      0x0400	/* packet received                  */
-#define ISREG_TXDN       0x0200	/* packet was sent                  */
-#define ISREG_TXER       0x0100	/* send failed                      */
-#define ISREG_TC         0x0080	/* timer completed                  */
-#define ISREG_RDE        0x0040	/* RDA exhausted                    */
-#define ISREG_RBE        0x0020	/* RBA exhausted                    */
-#define ISREG_RBAE       0x0010	/* RBA too short for received frame */
-#define ISREG_CRC        0x0008	/* CRC counter rolls over           */
-#define ISREG_FAE        0x0004	/* FAE counter rolls over           */
-#define ISREG_MP         0x0002	/* MP counter rolls  over           */
-#define ISREG_RFO        0x0001	/* Rx FIFO overflows                */
-
-#define SONIC_UTDA       0x0c	/* current transmit descr address   */
-#define SONIC_CTDA       0x0e
-
-#define SONIC_URDA       0x1a	/* current receive descr address    */
-#define SONIC_CRDA       0x1c
-
-#define SONIC_CRBA0      0x1e	/* current receive buffer address   */
-#define SONIC_CRBA1      0x20
-
-#define SONIC_RBWC0      0x22	/* word count in receive buffer     */
-#define SONIC_RBWC1      0x24
-
-#define SONIC_EOBC       0x26	/* minimum space to be free in RBA  */
-
-#define SONIC_URRA       0x28	/* upper address of CDA & Recv Area */
-
-#define SONIC_RSA        0x2a	/* start of receive resource area   */
-
-#define SONIC_REA        0x2c	/* end of receive resource area     */
-
-#define SONIC_RRP        0x2e	/* resource read pointer            */
-
-#define SONIC_RWP        0x30	/* resource write pointer           */
-
-#define SONIC_CAMEPTR    0x42	/* CAM entry pointer                */
-
-#define SONIC_CAMADDR2   0x44	/* CAM address ports                */
-#define SONIC_CAMADDR1   0x46
-#define SONIC_CAMADDR0   0x48
-
-#define SONIC_CAMPTR     0x4c	/* lower address of CDA             */
-
-#define SONIC_CAMCNT     0x4e	/* # of CAM descriptors to load     */
-
-/* Data Configuration Register 2    */
-
-#define SONIC_DCREG2     0x7e
-#define DCREG2_EXPO3     0x8000	/* extended programmable outputs    */
-#define DCREG2_EXPO2     0x4000
-#define DCREG2_EXPO1     0x2000
-#define DCREG2_EXPO0     0x1000
-#define DCREG2_HD        0x0800	/* heartbeat disable                */
-#define DCREG2_JD        0x0200	/* jabber timer disable             */
-#define DCREG2_AUTO      0x0100	/* enable AUI/TP auto selection     */
-#define DCREG2_XWRAP     0x0040	/* TP transceiver loopback          */
-#define DCREG2_PH        0x0010	/* HOLD request timing              */
-#define DCREG2_PCM       0x0004	/* packet compress when matched     */
-#define DCREG2_PCNM      0x0002	/* packet compress when not matched */
-#define DCREG2_RJCM      0x0001	/* inverse packet match via CAM     */
-
-/* Board Control Register: Enable RAM, Interrupts... */
-
-#define BCMREG           0x80
-#define BCMREG_RAMEN     0x80	/* switch over to RAM               */
-#define BCMREG_IPEND     0x40	/* interrupt pending ?              */
-#define BCMREG_RESET     0x08	/* reset board                      */
-#define BCMREG_16BIT     0x04	/* adapter in 16-bit slot           */
-#define BCMREG_RAMWIN    0x02	/* enable RAM window                */
-#define BCMREG_IEN       0x01	/* interrupt enable                 */
-
-/* MAC Address PROM */
-
-#define MACADDRPROM      0x92
-
-/* structure of a CAM entry */
-
-typedef struct {
-	u32 index;		/* pointer into CAM area            */
-	u32 addr0;		/* address part (bits 0..15 used)   */
-	u32 addr1;
-	u32 addr2;
-} camentry_t;
-
-/* structure of a receive resource */
-
-typedef struct {
-	u32 startlo;		/* start address (bits 0..15 used)  */
-	u32 starthi;
-	u32 cntlo;		/* size in 16-bit quantities        */
-	u32 cnthi;
-} rra_t;
-
-/* structure of a receive descriptor */
-
-typedef struct {
-	u32 status;		/* packet status                    */
-	u32 length;		/* length in bytes                  */
-	u32 startlo;		/* start address                    */
-	u32 starthi;
-	u32 seqno;		/* frame sequence                   */
-	u32 link;		/* pointer to next descriptor       */
-	/* bit 0 = EOL                      */
-	u32 inuse;		/* !=0 --> free for SONIC to write  */
-} rda_t;
-
-/* structure of a transmit descriptor */
-
-typedef struct {
-	u32 status;		/* transmit status                  */
-	u32 config;		/* value for TCR                    */
-	u32 length;		/* total length                     */
-	u32 fragcount;		/* number of fragments              */
-	u32 startlo;		/* start address of fragment        */
-	u32 starthi;
-	u32 fraglength;		/* length of this fragment          */
-	/* more address/length triplets may */
-	/* follow here                      */
-	u32 link;		/* pointer to next descriptor       */
-	/* bit 0 = EOL                      */
-} tda_t;
-
-#endif				/* _IBM_LANA_DRIVER_ */
-
-#endif	/* _IBM_LANA_INCLUDE_ */
diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index f4ad60c..7a5e295 100644
--- a/drivers/net/ethernet/natsemi/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -862,9 +862,6 @@
 		prev_eedata = eedata;
 	}
 
-	/* Store MAC Address in perm_addr */
-	memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
-
 	np = netdev_priv(dev);
 	np->ioaddr = ioaddr;
 
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 7c94c08..bfd8873 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -8014,7 +8014,6 @@
 	/*  Set the factory defined MAC address initially   */
 	dev->addr_len = ETH_ALEN;
 	memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
-	memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
 
 	/* initialize number of multicast & unicast MAC entries variables */
 	if (sp->device_type == XFRAME_I_DEVICE) {
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
index 92dd72d..f8f0738 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
@@ -82,9 +82,9 @@
 				  struct ethtool_drvinfo *info)
 {
 	struct vxgedev *vdev = netdev_priv(dev);
-	strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME));
-	strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
-	strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN);
+	strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, vdev->fw_version, sizeof(info->fw_version));
 	strlcpy(info->bus_info, pci_name(vdev->pdev), sizeof(info->bus_info));
 	info->regdump_len = sizeof(struct vxge_hw_vpath_reg)
 				* vdev->no_of_vpath;
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 7c87105..794444e 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -4682,7 +4682,6 @@
 	/* Store the fw version for ethttool option */
 	strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
 	memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
-	memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
 
 	/* Copy the station mac address to the list */
 	for (i = 0; i < vdev->no_of_vpath; i++) {
diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c
index cbd6a52..162da89 100644
--- a/drivers/net/ethernet/nuvoton/w90p910_ether.c
+++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c
@@ -878,8 +878,8 @@
 static void w90p910_get_drvinfo(struct net_device *dev,
 					struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_MODULE_NAME);
-	strcpy(info->version, DRV_MODULE_VERSION);
+	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 87fa591..0b8de12 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -3055,7 +3055,6 @@
 
 	/* synchronized against open : rtnl_lock() held by caller */
 	memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	if (netif_running(dev)) {
 		netif_tx_lock_bh(dev);
@@ -5766,9 +5765,8 @@
 			"%s: set workaround bit for reversed mac addr\n",
 			__func__);
 	}
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-	if (!is_valid_ether_addr(dev->perm_addr)) {
+	if (!is_valid_ether_addr(dev->dev_addr)) {
 		/*
 		 * Bad mac address. At least one bios sets the mac address
 		 * to 01:23:45:67:89:ab
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 3466ca1..c4122c8 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -800,7 +800,7 @@
 	else
 		netdev_info(ndev, "using RMII interface\n");
 	phydev = phy_connect(ndev, dev_name(&phydev->dev),
-			     &lpc_handle_link_change, 0,
+			     &lpc_handle_link_change,
 			     lpc_phy_interface_mode(&pldat->pdev->dev));
 
 	if (IS_ERR(phydev)) {
@@ -1239,9 +1239,10 @@
 static void lpc_eth_ethtool_getdrvinfo(struct net_device *ndev,
 	struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, MODNAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, dev_name(ndev->dev.parent));
+	strlcpy(info->driver, MODNAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, dev_name(ndev->dev.parent),
+		sizeof(info->bus_info));
 }
 
 static u32 lpc_eth_ethtool_getmsglevel(struct net_device *ndev)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index b549919..921729f 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -1350,10 +1350,10 @@
 static void octeon_mgmt_get_drvinfo(struct net_device *netdev,
 				    struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strncpy(info->version, DRV_VERSION, sizeof(info->version));
-	strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
-	strncpy(info->bus_info, "N/A", sizeof(info->bus_info));
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+	strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
 	info->n_stats = 0;
 	info->testinfo_len = 0;
 	info->regdump_len = 0;
@@ -1534,12 +1534,10 @@
 
 	mac = of_get_mac_address(pdev->dev.of_node);
 
-	if (mac && is_valid_ether_addr(mac)) {
+	if (mac && is_valid_ether_addr(mac))
 		memcpy(netdev->dev_addr, mac, ETH_ALEN);
-		netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
-	} else {
+	else
 		eth_hw_addr_random(netdev);
-	}
 
 	p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
 
diff --git a/drivers/net/ethernet/packetengines/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c
index bf829ee..cac33e5 100644
--- a/drivers/net/ethernet/packetengines/hamachi.c
+++ b/drivers/net/ethernet/packetengines/hamachi.c
@@ -1808,9 +1808,10 @@
 static void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct hamachi_private *np = netdev_priv(dev);
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pci_name(np->pci_dev));
+
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int hamachi_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/ethernet/packetengines/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c
index fbaed4f..d28593b 100644
--- a/drivers/net/ethernet/packetengines/yellowfin.c
+++ b/drivers/net/ethernet/packetengines/yellowfin.c
@@ -1326,9 +1326,10 @@
 static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct yellowfin_private *np = netdev_priv(dev);
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pci_name(np->pci_dev));
+
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops ethtool_ops = {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index 7f556a8..1bcaf45 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -201,11 +201,8 @@
 	adapter->mdump.md_template =
 		kmalloc(adapter->mdump.md_template_size, GFP_KERNEL);
 
-	if (!adapter->mdump.md_template) {
-		dev_err(&adapter->pdev->dev, "Unable to allocate memory "
-			"for minidump template.\n");
+	if (!adapter->mdump.md_template)
 		return -ENOMEM;
-	}
 
 	err = netxen_get_minidump_template(adapter);
 	if (err) {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
index 946160f..9fbb1cd 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
@@ -670,11 +670,9 @@
 	}
 
 	cur = kzalloc(sizeof(nx_mac_list_t), GFP_ATOMIC);
-	if (cur == NULL) {
-		printk(KERN_ERR "%s: failed to add mac address filter\n",
-				adapter->netdev->name);
+	if (cur == NULL)
 		return -ENOMEM;
-	}
+
 	memcpy(cur->mac_addr, addr, ETH_ALEN);
 	list_add_tail(&cur->list, &adapter->mac_list);
 	return nx_p3_sre_macaddr_change(adapter,
@@ -2568,16 +2566,10 @@
 					adapter->mdump.md_capture_size;
 	if (!adapter->mdump.md_capture_buff) {
 		adapter->mdump.md_capture_buff =
-				vmalloc(adapter->mdump.md_dump_size);
-		if (!adapter->mdump.md_capture_buff) {
-			dev_info(&adapter->pdev->dev,
-				"Unable to allocate memory for minidump "
-				"capture_buffer(%d bytes).\n",
-					adapter->mdump.md_dump_size);
+				vzalloc(adapter->mdump.md_dump_size);
+		if (!adapter->mdump.md_capture_buff)
 			return;
-		}
-		memset(adapter->mdump.md_capture_buff, 0,
-				adapter->mdump.md_dump_size);
+
 		if (netxen_collect_minidump(adapter)) {
 			adapter->mdump.has_valid_dump = 0;
 			adapter->mdump.md_dump_size = 0;
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 695667d..4782dcf 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -197,41 +197,33 @@
 	struct nx_host_sds_ring *sds_ring;
 	struct nx_host_tx_ring *tx_ring;
 	struct netxen_rx_buffer *rx_buf;
-	int ring, i, size;
+	int ring, i;
 
 	struct netxen_cmd_buffer *cmd_buf_arr;
 	struct net_device *netdev = adapter->netdev;
-	struct pci_dev *pdev = adapter->pdev;
 
-	size = sizeof(struct nx_host_tx_ring);
-	tx_ring = kzalloc(size, GFP_KERNEL);
-	if (tx_ring == NULL) {
-		dev_err(&pdev->dev, "%s: failed to allocate tx ring struct\n",
-		       netdev->name);
+	tx_ring = kzalloc(sizeof(struct nx_host_tx_ring), GFP_KERNEL);
+	if (tx_ring == NULL)
 		return -ENOMEM;
-	}
+
 	adapter->tx_ring = tx_ring;
 
 	tx_ring->num_desc = adapter->num_txd;
 	tx_ring->txq = netdev_get_tx_queue(netdev, 0);
 
 	cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
-	if (cmd_buf_arr == NULL) {
-		dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n",
-		       netdev->name);
+	if (cmd_buf_arr == NULL)
 		goto err_out;
-	}
+
 	tx_ring->cmd_buf_arr = cmd_buf_arr;
 
 	recv_ctx = &adapter->recv_ctx;
 
-	size = adapter->max_rds_rings * sizeof (struct nx_host_rds_ring);
-	rds_ring = kzalloc(size, GFP_KERNEL);
-	if (rds_ring == NULL) {
-		dev_err(&pdev->dev, "%s: failed to allocate rds ring struct\n",
-		       netdev->name);
+	rds_ring = kcalloc(adapter->max_rds_rings,
+			   sizeof(struct nx_host_rds_ring), GFP_KERNEL);
+	if (rds_ring == NULL)
 		goto err_out;
-	}
+
 	recv_ctx->rds_rings = rds_ring;
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 69e321a..501f492 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -501,12 +501,11 @@
 	for (i = 0; i < 6; i++)
 		netdev->dev_addr[i] = *(p + 5 - i);
 
-	memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
 	memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
 
 	/* set station address */
 
-	if (!is_valid_ether_addr(netdev->perm_addr))
+	if (!is_valid_ether_addr(netdev->dev_addr))
 		dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr);
 
 	return 0;
@@ -3177,11 +3176,8 @@
 		}
 
 		cur = kzalloc(sizeof(struct nx_vlan_ip_list), GFP_ATOMIC);
-		if (cur == NULL) {
-			printk(KERN_ERR "%s: failed to add vlan ip to list\n",
-					adapter->netdev->name);
+		if (cur == NULL)
 			return;
-		}
 
 		cur->ip_addr = ifa->ifa_address;
 		list_add_tail(&cur->list, &adapter->vlan_ip_list);
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 67a679a..8fd38cb6 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -2591,13 +2591,11 @@
 	else
 		qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
 
-	qdev->lrg_buf =
-		kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),
-			GFP_KERNEL);
-	if (qdev->lrg_buf == NULL) {
-		netdev_err(qdev->ndev, "qdev->lrg_buf alloc failed\n");
+	qdev->lrg_buf = kmalloc_array(qdev->num_large_buffers,
+				      sizeof(struct ql_rcv_buf_cb),
+				      GFP_KERNEL);
+	if (qdev->lrg_buf == NULL)
 		return -ENOMEM;
-	}
 
 	qdev->lrg_buf_q_alloc_virt_addr =
 		pci_alloc_consistent(qdev->pdev,
@@ -3867,7 +3865,6 @@
 		ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ;
 		ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn0.macAddress);
 	}
-	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
 
 	ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index c4b8ced..7722a20 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -6,4 +6,6 @@
 
 qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
 	qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
-	qlcnic_sysfs.o qlcnic_minidump.o
+	qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \
+	qlcnic_83xx_init.o qlcnic_83xx_vnic.o \
+	qlcnic_minidump.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index bc7ec64..11c3db6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1,6 +1,6 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
@@ -33,11 +33,13 @@
 #include <linux/if_vlan.h>
 
 #include "qlcnic_hdr.h"
+#include "qlcnic_hw.h"
+#include "qlcnic_83xx_hw.h"
 
 #define _QLCNIC_LINUX_MAJOR 5
-#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 30
-#define QLCNIC_LINUX_VERSIONID  "5.0.30"
+#define _QLCNIC_LINUX_MINOR 1
+#define _QLCNIC_LINUX_SUBVERSION 34
+#define QLCNIC_LINUX_VERSIONID  "5.1.34"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -96,7 +98,6 @@
 #define TX_STOP_THRESH		((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
 							+ MGMT_CMD_DESC_RESV)
 #define QLCNIC_MAX_TX_TIMEOUTS	2
-
 /*
  * Following are the states of the Phantom. Phantom will set them and
  * Host will read to check if the fields are correct.
@@ -203,6 +204,7 @@
 
 /* Flash Defines and Structures */
 #define QLCNIC_FLT_LOCATION	0x3F1000
+#define QLCNIC_FDT_LOCATION     0x3F0000
 #define QLCNIC_B0_FW_IMAGE_REGION 0x74
 #define QLCNIC_C0_FW_IMAGE_REGION 0x97
 #define QLCNIC_BOOTLD_REGION    0X72
@@ -223,6 +225,36 @@
 	u32 end_addr;
 };
 
+/* Flash Descriptor Table */
+struct qlcnic_fdt {
+	u32	valid;
+	u16	ver;
+	u16	len;
+	u16	cksum;
+	u16	unused;
+	u8	model[16];
+	u16	mfg_id;
+	u16	id;
+	u8	flag;
+	u8	erase_cmd;
+	u8	alt_erase_cmd;
+	u8	write_enable_cmd;
+	u8	write_enable_bits;
+	u8	write_statusreg_cmd;
+	u8	unprotected_sec_cmd;
+	u8	read_manuf_cmd;
+	u32	block_size;
+	u32	alt_block_size;
+	u32	flash_size;
+	u32	write_enable_data;
+	u8	readid_addr_len;
+	u8	write_disable_bits;
+	u8	read_dev_id_len;
+	u8	chip_erase_cmd;
+	u16	read_timeo;
+	u8	protected_sec_cmd;
+	u8	resvd[65];
+};
 /* Magic number to let user know flash is programmed */
 #define	QLCNIC_BDINFO_MAGIC 0x12345678
 
@@ -267,6 +299,12 @@
 
 extern char qlcnic_driver_name[];
 
+extern int qlcnic_use_msi;
+extern int qlcnic_use_msi_x;
+extern int qlcnic_auto_fw_reset;
+extern int qlcnic_load_fw_file;
+extern int qlcnic_config_npars;
+
 /* Number of status descriptors to handle per interrupt */
 #define MAX_STATUS_HANDLE	(64)
 
@@ -314,6 +352,7 @@
 
 #define QLCNIC_INTR_DEFAULT			0x04
 #define QLCNIC_CONFIG_INTR_COALESCE		3
+#define QLCNIC_DEV_INFO_SIZE			1
 
 struct qlcnic_nic_intr_coalesce {
 	u8	type;
@@ -337,6 +376,7 @@
 	u32	sys_info[3];
 	u32	saved_state[16];
 	u32	cap_sizes[8];
+	u32	ocm_wnd_reg[16];
 	u32	rsvd[0];
 };
 
@@ -396,12 +436,24 @@
 	u16 act_pci_func;
 
 	u32 capabilities;
+	u32 capabilities2;
 	u32 temp;
 	u32 int_vec_bit;
 	u32 fw_hal_version;
+	u32 port_config;
 	struct qlcnic_hardware_ops *hw_ops;
 	struct qlcnic_nic_intr_coalesce coal;
 	struct qlcnic_fw_dump fw_dump;
+	struct qlcnic_fdt fdt;
+	struct qlc_83xx_reset reset;
+	struct qlc_83xx_idc idc;
+	struct qlc_83xx_fw_info fw_info;
+	struct qlcnic_intrpt_config *intr_tbl;
+	u32 *reg_tbl;
+	u32 *ext_reg_tbl;
+	u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
+	u32 mbox_reg[4];
+	spinlock_t mbx_lock;
 };
 
 struct qlcnic_adapter_stats {
@@ -422,6 +474,8 @@
 	u64  null_rxbuf;
 	u64  rx_dma_map_error;
 	u64  tx_dma_map_error;
+	u64  spurious_intr;
+	u64  mac_filter_limit_overrun;
 };
 
 /*
@@ -460,12 +514,17 @@
 } ____cacheline_internodealigned_in_smp;
 
 struct qlcnic_host_tx_ring {
+	int irq;
+	void __iomem *crb_intr_mask;
+	char name[IFNAMSIZ+4];
 	u16 ctx_id;
 	u32 producer;
 	u32 sw_consumer;
 	u32 num_desc;
 	void __iomem *crb_cmd_producer;
 	struct cmd_desc_type0 *desc_head;
+	struct qlcnic_adapter *adapter;
+	struct napi_struct napi;
 	struct qlcnic_cmd_buffer *cmd_buf_arr;
 	__le32 *hw_consumer;
 
@@ -492,8 +551,6 @@
 /* HW context creation */
 
 #define QLCNIC_OS_CRB_RETRY_COUNT	4000
-#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \
-	(((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16))
 
 #define QLCNIC_CDRP_CMD_BIT		0x80000000
 
@@ -513,43 +570,6 @@
  * the crb QLCNIC_CDRP_CRB_OFFSET.
  */
 #define QLCNIC_CDRP_FORM_CMD(cmd)	(QLCNIC_CDRP_CMD_BIT | (cmd))
-#define QLCNIC_CDRP_IS_CMD(cmd)	(((cmd) & QLCNIC_CDRP_CMD_BIT) != 0)
-
-#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES     0x00000001
-#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX    0x00000002
-#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX    0x00000003
-#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX  0x00000004
-#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX         0x00000005
-#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX         0x00000006
-#define QLCNIC_CDRP_CMD_CREATE_RX_CTX           0x00000007
-#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX          0x00000008
-#define QLCNIC_CDRP_CMD_CREATE_TX_CTX           0x00000009
-#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX          0x0000000a
-#define QLCNIC_CDRP_CMD_INTRPT_TEST		0x00000011
-#define QLCNIC_CDRP_CMD_SET_MTU                 0x00000012
-#define QLCNIC_CDRP_CMD_READ_PHY		0x00000013
-#define QLCNIC_CDRP_CMD_WRITE_PHY		0x00000014
-#define QLCNIC_CDRP_CMD_READ_HW_REG		0x00000015
-#define QLCNIC_CDRP_CMD_GET_FLOW_CTL		0x00000016
-#define QLCNIC_CDRP_CMD_SET_FLOW_CTL		0x00000017
-#define QLCNIC_CDRP_CMD_READ_MAX_MTU		0x00000018
-#define QLCNIC_CDRP_CMD_READ_MAX_LRO		0x00000019
-#define QLCNIC_CDRP_CMD_MAC_ADDRESS		0x0000001f
-
-#define QLCNIC_CDRP_CMD_GET_PCI_INFO		0x00000020
-#define QLCNIC_CDRP_CMD_GET_NIC_INFO		0x00000021
-#define QLCNIC_CDRP_CMD_SET_NIC_INFO		0x00000022
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY	0x00000024
-#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH		0x00000025
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS	0x00000026
-#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING	0x00000027
-#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH	0x00000028
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG	0x00000029
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS	0x0000002a
-#define QLCNIC_CDRP_CMD_CONFIG_PORT		0x0000002E
-#define QLCNIC_CDRP_CMD_TEMP_SIZE		0x0000002f
-#define QLCNIC_CDRP_CMD_GET_TEMP_HDR		0x00000030
-#define QLCNIC_CDRP_CMD_GET_MAC_STATS		0x00000037
 
 #define QLCNIC_RCODE_SUCCESS		0
 #define QLCNIC_RCODE_INVALID_ARGS	6
@@ -726,6 +746,11 @@
 	uint8_t mac_addr[ETH_ALEN+2];
 };
 
+/* MAC Learn */
+#define NO_MAC_LEARN		0
+#define DRV_MAC_LEARN		1
+#define FDB_MAC_LEARN		2
+
 #define QLCNIC_HOST_REQUEST	0x13
 #define QLCNIC_REQUEST		0x14
 
@@ -762,7 +787,7 @@
  */
 
 #define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK		0x8f
-#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE	141
+#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE	0x8D
 
 #define VPORT_MISS_MODE_DROP		0 /* drop all unmatched */
 #define VPORT_MISS_MODE_ACCEPT_ALL	1 /* accept all packets */
@@ -779,6 +804,8 @@
 #define QLCNIC_FW_CAPABILITY_MORE_CAPS		BIT_31
 
 #define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG	BIT_2
+#define QLCNIC_FW_CAP2_HW_LRO_IPV6		BIT_3
+#define QLCNIC_FW_CAPABILITY_2_OCBB		BIT_5
 
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT			1
@@ -855,7 +882,7 @@
 
 #define QLCNIC_MSI_ENABLED		0x02
 #define QLCNIC_MSIX_ENABLED		0x04
-#define QLCNIC_LRO_ENABLED		0x08
+#define QLCNIC_LRO_ENABLED		0x01
 #define QLCNIC_LRO_DISABLED		0x00
 #define QLCNIC_BRIDGE_ENABLED       	0X10
 #define QLCNIC_DIAG_ENABLED		0x20
@@ -887,6 +914,7 @@
 #define __QLCNIC_AER			5
 #define __QLCNIC_DIAG_RES_ALLOC		6
 #define __QLCNIC_LED_ENABLE		7
+#define __QLCNIC_ELB_INPROGRESS	8
 
 #define QLCNIC_INTERRUPT_TEST		1
 #define QLCNIC_LOOPBACK_TEST		2
@@ -895,12 +923,14 @@
 #define QLCNIC_FILTER_AGE	80
 #define QLCNIC_READD_AGE	20
 #define QLCNIC_LB_MAX_FILTERS	64
+#define QLCNIC_LB_BUCKET_SIZE	32
 
 /* QLCNIC Driver Error Code */
 #define QLCNIC_FW_NOT_RESPOND		51
 #define QLCNIC_TEST_IN_PROGRESS		52
 #define QLCNIC_UNDEFINED_ERROR		53
 #define QLCNIC_LB_CABLE_NOT_CONN	54
+#define QLCNIC_ILB_MAX_RCV_LOOP	10
 
 struct qlcnic_filter {
 	struct hlist_node fnode;
@@ -912,7 +942,8 @@
 struct qlcnic_filter_hash {
 	struct hlist_head *fhead;
 	u8 fnum;
-	u8 fmax;
+	u16 fmax;
+	u16 fbucket_size;
 };
 
 struct qlcnic_adapter {
@@ -934,6 +965,7 @@
 
 	u8 max_rds_rings;
 	u8 max_sds_rings;
+	u8 rx_csum;
 	u8 portnum;
 
 	u8 fw_wait_cnt;
@@ -954,8 +986,10 @@
 	u8 mac_addr[ETH_ALEN];
 
 	u64 dev_rst_time;
-	u8 mac_learn;
+	bool drv_mac_learn;
+	bool fdb_mac_learn;
 	unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
+	u8 flash_mfg_id;
 	struct qlcnic_npar_info *npars;
 	struct qlcnic_eswitch *eswitch;
 	struct qlcnic_nic_template *nic_ops;
@@ -969,12 +1003,17 @@
 	void __iomem	*isr_int_vec;
 
 	struct msix_entry *msix_entries;
+	struct workqueue_struct *qlcnic_wq;
 	struct delayed_work fw_work;
+	struct delayed_work idc_aen_work;
 
 	struct qlcnic_filter_hash fhash;
+	struct qlcnic_filter_hash rx_fhash;
 
 	spinlock_t tx_clean_lock;
 	spinlock_t mac_learn_lock;
+	/* spinlock for catching rcv filters for eswitch traffic */
+	spinlock_t rx_mac_learn_lock;
 	u32 file_prd_off;	/*File fw product offset*/
 	u32 fw_version;
 	const struct firmware *fw;
@@ -995,7 +1034,24 @@
 	__le16	max_rx_ques;
 	__le16	min_tx_bw;
 	__le16	max_tx_bw;
-	u8	reserved2[104];
+	__le32  op_type;
+	__le16  max_bw_reg_offset;
+	__le16  max_linkspeed_reg_offset;
+	__le32  capability1;
+	__le32  capability2;
+	__le32  capability3;
+	__le16  max_tx_mac_filters;
+	__le16  max_rx_mcast_mac_filters;
+	__le16  max_rx_ucast_mac_filters;
+	__le16  max_rx_ip_addr;
+	__le16  max_rx_lro_flow;
+	__le16  max_rx_status_rings;
+	__le16  max_rx_buf_rings;
+	__le16  max_tx_vlan_keys;
+	u8      total_pf;
+	u8      total_rss_engines;
+	__le16  max_vports;
+	u8      reserved2[64];
 } __packed;
 
 struct qlcnic_info {
@@ -1005,12 +1061,28 @@
 	u16	switch_mode;
 	u32	capabilities;
 	u8	max_mac_filters;
-	u8	reserved1;
 	u16	max_mtu;
 	u16	max_tx_ques;
 	u16	max_rx_ques;
 	u16	min_tx_bw;
 	u16	max_tx_bw;
+	u32	op_type;
+	u16	max_bw_reg_offset;
+	u16	max_linkspeed_reg_offset;
+	u32	capability1;
+	u32	capability2;
+	u32	capability3;
+	u16	max_tx_mac_filters;
+	u16	max_rx_mcast_mac_filters;
+	u16	max_rx_ucast_mac_filters;
+	u16	max_rx_ip_addr;
+	u16	max_rx_lro_flow;
+	u16	max_rx_status_rings;
+	u16	max_rx_buf_rings;
+	u16	max_tx_vlan_keys;
+	u8      total_pf;
+	u8      total_rss_engines;
+	u16	max_vports;
 };
 
 struct qlcnic_pci_info_le {
@@ -1024,7 +1096,9 @@
 	__le16	reserved1[2];
 
 	u8	mac[ETH_ALEN];
-	u8	reserved2[106];
+	__le16  func_count;
+	u8      reserved2[104];
+
 } __packed;
 
 struct qlcnic_pci_info {
@@ -1035,6 +1109,7 @@
 	u16	tx_min_bw;
 	u16	tx_max_bw;
 	u8	mac[ETH_ALEN];
+	u16  func_count;
 };
 
 struct qlcnic_npar_info {
@@ -1266,10 +1341,8 @@
 #define QLCNIC_RESET_QUIESCENT		0xadd00020
 
 struct _cdrp_cmd {
-	u32 cmd;
-	u32 arg1;
-	u32 arg2;
-	u32 arg3;
+	u32 num;
+	u32 *arg;
 };
 
 struct qlcnic_cmd_args {
@@ -1279,9 +1352,6 @@
 
 int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
 int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
-
-int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
-int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
 int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
 int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
 void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *, u64, u64 *);
@@ -1291,9 +1361,10 @@
 	(((addr) < (high)) && ((addr) >= (low)))
 
 #define QLCRD32(adapter, off) \
-	(qlcnic_hw_read_wx_2M(adapter, off))
+	(adapter->ahw->hw_ops->read_reg)(adapter, off)
+
 #define QLCWR32(adapter, off, val) \
-	(qlcnic_hw_write_wx_2M(adapter, off, val))
+	adapter->ahw->hw_ops->write_reg(adapter, off, val)
 
 int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32);
 void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
@@ -1306,10 +1377,6 @@
 	qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID)
 #define qlcnic_phy_unlock(a)	\
 	qlcnic_pcie_sem_unlock((a), 3)
-#define qlcnic_api_lock(a)	\
-	qlcnic_pcie_sem_lock((a), 5, 0)
-#define qlcnic_api_unlock(a)	\
-	qlcnic_pcie_sem_unlock((a), 5)
 #define qlcnic_sw_lock(a)	\
 	qlcnic_pcie_sem_lock((a), 6, 0)
 #define qlcnic_sw_unlock(a)	\
@@ -1324,14 +1391,13 @@
 
 #define MAX_CTL_CHECK 1000
 
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
 int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
-int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
 void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
 void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
 int qlcnic_dump_fw(struct qlcnic_adapter *);
 
 /* Functions from qlcnic_init.c */
+void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int);
 int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
 int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
 void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
@@ -1361,54 +1427,42 @@
 int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);
 void qlcnic_watchdog_task(struct work_struct *work);
 void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
-		struct qlcnic_host_rds_ring *rds_ring);
+		struct qlcnic_host_rds_ring *rds_ring, u8 ring_id);
 int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
 void qlcnic_set_multi(struct net_device *netdev);
+int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *);
+int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
 void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd);
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
-void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
 
 int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *);
 int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
 netdev_features_t qlcnic_fix_features(struct net_device *netdev,
 	netdev_features_t features);
 int qlcnic_set_features(struct net_device *netdev, netdev_features_t features);
-int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
 int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
 int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *);
-void qlcnic_fetch_mac(u32, u32, u8, u8 *);
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter);
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode);
 
 /* Functions from qlcnic_ethtool.c */
-int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
+int qlcnic_check_loopback_buff(unsigned char *, u8 []);
+int qlcnic_do_lb_test(struct qlcnic_adapter *, u8);
+int qlcnic_loopback_test(struct net_device *, u8);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
-void qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *);
 void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
-void qlcnic_dev_request_reset(struct qlcnic_adapter *);
+int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
+int qlcnic_validate_max_rss(u8, u8);
 void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
-
-/* Management functions */
-int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
-int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
-int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
-int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
 
 /*  eSwitch management functions */
 int qlcnic_config_switch_port(struct qlcnic_adapter *,
 				struct qlcnic_esw_func_cfg *);
+
 int qlcnic_get_eswitch_port_config(struct qlcnic_adapter *,
 				struct qlcnic_esw_func_cfg *);
 int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
@@ -1418,14 +1472,12 @@
 					struct __qlcnic_esw_statistics *);
 int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
 int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
-extern int qlcnic_config_tso;
 
-int qlcnic_napi_add(struct qlcnic_adapter *, struct net_device *);
-void qlcnic_napi_del(struct qlcnic_adapter *adapter);
-void qlcnic_napi_enable(struct qlcnic_adapter *adapter);
-void qlcnic_napi_disable(struct qlcnic_adapter *adapter);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd);
+
 int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *, int);
 void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
+void qlcnic_advert_link_change(struct qlcnic_adapter *, int);
 void qlcnic_free_tx_rings(struct qlcnic_adapter *);
 int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
 
@@ -1433,6 +1485,9 @@
 void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter);
+
 int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
 int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
 void qlcnic_set_vlan_config(struct qlcnic_adapter *,
@@ -1440,6 +1495,22 @@
 void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *,
 				      struct qlcnic_esw_func_cfg *);
 
+void qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+int qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void __qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_detach(struct qlcnic_adapter *);
+void qlcnic_teardown_intr(struct qlcnic_adapter *);
+int qlcnic_attach(struct qlcnic_adapter *);
+int __qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_restore_indev_addr(struct net_device *, unsigned long);
+
+int qlcnic_check_temp(struct qlcnic_adapter *);
+int qlcnic_init_pci_info(struct qlcnic_adapter *);
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_reset_npar_config(struct qlcnic_adapter *);
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
+void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int,
+			  __le16);
 /*
  * QLOGIC Board information
  */
@@ -1462,6 +1533,277 @@
 				tx_ring->producer;
 }
 
+struct qlcnic_nic_template {
+	int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+	int (*config_led) (struct qlcnic_adapter *, u32, u32);
+	int (*start_firmware) (struct qlcnic_adapter *);
+	int (*init_driver) (struct qlcnic_adapter *);
+	void (*request_reset) (struct qlcnic_adapter *, u32);
+	void (*cancel_idc_work) (struct qlcnic_adapter *);
+	int (*napi_add)(struct qlcnic_adapter *, struct net_device *);
+	void (*napi_del)(struct qlcnic_adapter *);
+	void (*config_ipaddr)(struct qlcnic_adapter *, __be32, int);
+	irqreturn_t (*clear_legacy_intr)(struct qlcnic_adapter *);
+};
+
+/* Adapter hardware abstraction */
+struct qlcnic_hardware_ops {
+	void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+	void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+	int (*read_reg) (struct qlcnic_adapter *, ulong);
+	int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
+	void (*get_ocm_win) (struct qlcnic_hardware_context *);
+	int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
+	int (*setup_intr) (struct qlcnic_adapter *, u8);
+	int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
+			      struct qlcnic_adapter *, u32);
+	int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+	void (*get_func_no) (struct qlcnic_adapter *);
+	int (*api_lock) (struct qlcnic_adapter *);
+	void (*api_unlock) (struct qlcnic_adapter *);
+	void (*add_sysfs) (struct qlcnic_adapter *);
+	void (*remove_sysfs) (struct qlcnic_adapter *);
+	void (*process_lb_rcv_ring_diag) (struct qlcnic_host_sds_ring *);
+	int (*create_rx_ctx) (struct qlcnic_adapter *);
+	int (*create_tx_ctx) (struct qlcnic_adapter *,
+	struct qlcnic_host_tx_ring *, int);
+	int (*setup_link_event) (struct qlcnic_adapter *, int);
+	int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8);
+	int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *);
+	int (*set_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *);
+	int (*change_macvlan) (struct qlcnic_adapter *, u8*, __le16, u8);
+	void (*napi_enable) (struct qlcnic_adapter *);
+	void (*napi_disable) (struct qlcnic_adapter *);
+	void (*config_intr_coal) (struct qlcnic_adapter *);
+	int (*config_rss) (struct qlcnic_adapter *, int);
+	int (*config_hw_lro) (struct qlcnic_adapter *, int);
+	int (*config_loopback) (struct qlcnic_adapter *, u8);
+	int (*clear_loopback) (struct qlcnic_adapter *, u8);
+	int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
+	void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, __le16);
+	int (*get_board_info) (struct qlcnic_adapter *);
+};
+
+extern struct qlcnic_nic_template qlcnic_vf_ops;
+
+static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+{
+	return adapter->nic_ops->start_firmware(adapter);
+}
+
+static inline void qlcnic_read_crb(struct qlcnic_adapter *adapter, char *buf,
+				   loff_t offset, size_t size)
+{
+	adapter->ahw->hw_ops->read_crb(adapter, buf, offset, size);
+}
+
+static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
+				    loff_t offset, size_t size)
+{
+	adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
+}
+
+static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter,
+				       ulong off)
+{
+	return adapter->ahw->hw_ops->read_reg(adapter, off);
+}
+
+static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
+					ulong off, u32 data)
+{
+	return adapter->ahw->hw_ops->write_reg(adapter, off, data);
+}
+
+static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter,
+					 u8 *mac)
+{
+	return adapter->ahw->hw_ops->get_mac_address(adapter, mac);
+}
+
+static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+	return adapter->ahw->hw_ops->setup_intr(adapter, num_intr);
+}
+
+static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+					struct qlcnic_adapter *adapter, u32 arg)
+{
+	return adapter->ahw->hw_ops->alloc_mbx_args(mbx, adapter, arg);
+}
+
+static inline int qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+				   struct qlcnic_cmd_args *cmd)
+{
+	return adapter->ahw->hw_ops->mbx_cmd(adapter, cmd);
+}
+
+static inline void qlcnic_get_func_no(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->get_func_no(adapter);
+}
+
+static inline int qlcnic_api_lock(struct qlcnic_adapter *adapter)
+{
+	return adapter->ahw->hw_ops->api_lock(adapter);
+}
+
+static inline void qlcnic_api_unlock(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->api_unlock(adapter);
+}
+
+static inline void qlcnic_add_sysfs(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->add_sysfs(adapter);
+}
+
+static inline void qlcnic_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->remove_sysfs(adapter);
+}
+
+static inline void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+	sds_ring->adapter->ahw->hw_ops->process_lb_rcv_ring_diag(sds_ring);
+}
+
+static inline int qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+	return adapter->ahw->hw_ops->create_rx_ctx(adapter);
+}
+
+static inline int qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+					      struct qlcnic_host_tx_ring *ptr,
+					      int ring)
+{
+	return adapter->ahw->hw_ops->create_tx_ctx(adapter, ptr, ring);
+}
+
+static inline int qlcnic_linkevent_request(struct qlcnic_adapter *adapter,
+					   int enable)
+{
+	return adapter->ahw->hw_ops->setup_link_event(adapter, enable);
+}
+
+static inline int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+				      struct qlcnic_info *info, u8 id)
+{
+	return adapter->ahw->hw_ops->get_nic_info(adapter, info, id);
+}
+
+static inline int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+				      struct qlcnic_pci_info *info)
+{
+	return adapter->ahw->hw_ops->get_pci_info(adapter, info);
+}
+
+static inline int qlcnic_set_nic_info(struct qlcnic_adapter *adapter,
+				      struct qlcnic_info *info)
+{
+	return adapter->ahw->hw_ops->set_nic_info(adapter, info);
+}
+
+static inline int qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter,
+					    u8 *addr, __le16 id, u8 cmd)
+{
+	return adapter->ahw->hw_ops->change_macvlan(adapter, addr, id, cmd);
+}
+
+static inline int qlcnic_napi_add(struct qlcnic_adapter *adapter,
+				  struct net_device *netdev)
+{
+	return adapter->nic_ops->napi_add(adapter, netdev);
+}
+
+static inline void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+{
+	adapter->nic_ops->napi_del(adapter);
+}
+
+static inline void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->napi_enable(adapter);
+}
+
+static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->napi_disable(adapter);
+}
+
+static inline void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->hw_ops->config_intr_coal(adapter);
+}
+
+static inline int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+	return adapter->ahw->hw_ops->config_rss(adapter, enable);
+}
+
+static inline int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter,
+				       int enable)
+{
+	return adapter->ahw->hw_ops->config_hw_lro(adapter, enable);
+}
+
+static inline int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+	return adapter->ahw->hw_ops->config_loopback(adapter, mode);
+}
+
+static inline int qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+	return adapter->ahw->hw_ops->config_loopback(adapter, mode);
+}
+
+static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter,
+					 u32 mode)
+{
+	return adapter->ahw->hw_ops->config_promisc_mode(adapter, mode);
+}
+
+static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+					u64 *addr, __le16 id)
+{
+	adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id);
+}
+
+static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+{
+	return adapter->ahw->hw_ops->get_board_info(adapter);
+}
+
+static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
+					    u32 key)
+{
+	adapter->nic_ops->request_reset(adapter, key);
+}
+
+static inline void qlcnic_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+	adapter->nic_ops->cancel_idc_work(adapter);
+}
+
+static inline irqreturn_t
+qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+	return adapter->nic_ops->clear_legacy_intr(adapter);
+}
+
+static inline int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state,
+				    u32 rate)
+{
+	return adapter->nic_ops->config_led(adapter, state, rate);
+}
+
+static inline void qlcnic_config_ipaddr(struct qlcnic_adapter *adapter,
+					__be32 ip, int cmd)
+{
+	adapter->nic_ops->config_ipaddr(adapter, ip, cmd);
+}
+
 static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
 {
 	writel(0, sds_ring->crb_intr_mask);
@@ -1480,12 +1822,6 @@
 extern const struct ethtool_ops qlcnic_ethtool_ops;
 extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
 
-struct qlcnic_nic_template {
-	int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
-	int (*config_led) (struct qlcnic_adapter *, u32, u32);
-	int (*start_firmware) (struct qlcnic_adapter *);
-};
-
 #define QLCDB(adapter, lvl, _fmt, _args...) do {	\
 	if (NETIF_MSG_##lvl & adapter->ahw->msg_enable)	\
 		printk(KERN_INFO "%s: %s: " _fmt,	\
@@ -1493,6 +1829,7 @@
 			__func__, ##_args);		\
 	} while (0)
 
+#define PCI_DEVICE_ID_QLOGIC_QLE834X    0x8030
 #define PCI_DEVICE_ID_QLOGIC_QLE824X	0x8020
 static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
 {
@@ -1500,4 +1837,11 @@
 	return (device == PCI_DEVICE_ID_QLOGIC_QLE824X) ? true : false;
 }
 
+static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter)
+{
+	unsigned short device = adapter->pdev->device;
+	return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false;
+}
+
+
 #endif				/* __QLCNIC_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
new file mode 100644
index 0000000..cd5ae88
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -0,0 +1,3011 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic.h"
+#include <linux/if_vlan.h>
+#include <linux/ipv6.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+
+#define QLCNIC_MAX_TX_QUEUES		1
+#define RSS_HASHTYPE_IP_TCP		0x3
+
+/* status descriptor mailbox data
+ * @phy_addr: physical address of buffer
+ * @sds_ring_size: buffer size
+ * @intrpt_id: interrupt id
+ * @intrpt_val: source of interrupt
+ */
+struct qlcnic_sds_mbx {
+	u64	phy_addr;
+	u8	rsvd1[16];
+	u16	sds_ring_size;
+	u16	rsvd2[3];
+	u16	intrpt_id;
+	u8	intrpt_val;
+	u8	rsvd3[5];
+} __packed;
+
+/* receive descriptor buffer data
+ * phy_addr_reg: physical address of regular buffer
+ * phy_addr_jmb: physical address of jumbo buffer
+ * reg_ring_sz: size of regular buffer
+ * reg_ring_len: no. of entries in regular buffer
+ * jmb_ring_len: no. of entries in jumbo buffer
+ * jmb_ring_sz: size of jumbo buffer
+ */
+struct qlcnic_rds_mbx {
+	u64	phy_addr_reg;
+	u64	phy_addr_jmb;
+	u16	reg_ring_sz;
+	u16	reg_ring_len;
+	u16	jmb_ring_sz;
+	u16	jmb_ring_len;
+} __packed;
+
+/* host producers for regular and jumbo rings */
+struct __host_producer_mbx {
+	u32	reg_buf;
+	u32	jmb_buf;
+} __packed;
+
+/* Receive context mailbox data outbox registers
+ * @state: state of the context
+ * @vport_id: virtual port id
+ * @context_id: receive context id
+ * @num_pci_func: number of pci functions of the port
+ * @phy_port: physical port id
+ */
+struct qlcnic_rcv_mbx_out {
+	u8	rcv_num;
+	u8	sts_num;
+	u16	ctx_id;
+	u8	state;
+	u8	num_pci_func;
+	u8	phy_port;
+	u8	vport_id;
+	u32	host_csmr[QLCNIC_MAX_RING_SETS];
+	struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+struct qlcnic_add_rings_mbx_out {
+	u8      rcv_num;
+	u8      sts_num;
+	u16  ctx_id;
+	u32  host_csmr[QLCNIC_MAX_RING_SETS];
+	struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+/* Transmit context mailbox inbox registers
+ * @phys_addr: DMA address of the transmit buffer
+ * @cnsmr_index: host consumer index
+ * @size: legth of transmit buffer ring
+ * @intr_id: interrput id
+ * @src: src of interrupt
+ */
+struct qlcnic_tx_mbx {
+	u64	phys_addr;
+	u64	cnsmr_index;
+	u16	size;
+	u16	intr_id;
+	u8	src;
+	u8	rsvd[3];
+} __packed;
+
+/* Transmit context mailbox outbox registers
+ * @host_prod: host producer index
+ * @ctx_id: transmit context id
+ * @state: state of the transmit context
+ */
+struct qlcnic_tx_mbx_out {
+	u32	host_prod;
+	u16	ctx_id;
+	u8	state;
+	u8	rsvd;
+} __packed;
+
+static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
+	{QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
+	{QLCNIC_CMD_CONFIG_INTRPT, 18, 34},
+	{QLCNIC_CMD_CREATE_RX_CTX, 136, 27},
+	{QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
+	{QLCNIC_CMD_CREATE_TX_CTX, 54, 18},
+	{QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
+	{QLCNIC_CMD_CONFIGURE_MAC_LEARNING, 2, 1},
+	{QLCNIC_CMD_INTRPT_TEST, 22, 12},
+	{QLCNIC_CMD_SET_MTU, 3, 1},
+	{QLCNIC_CMD_READ_PHY, 4, 2},
+	{QLCNIC_CMD_WRITE_PHY, 5, 1},
+	{QLCNIC_CMD_READ_HW_REG, 4, 1},
+	{QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
+	{QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
+	{QLCNIC_CMD_READ_MAX_MTU, 4, 2},
+	{QLCNIC_CMD_READ_MAX_LRO, 4, 2},
+	{QLCNIC_CMD_MAC_ADDRESS, 4, 3},
+	{QLCNIC_CMD_GET_PCI_INFO, 1, 66},
+	{QLCNIC_CMD_GET_NIC_INFO, 2, 19},
+	{QLCNIC_CMD_SET_NIC_INFO, 32, 1},
+	{QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
+	{QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
+	{QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
+	{QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
+	{QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
+	{QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
+	{QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
+	{QLCNIC_CMD_CONFIG_PORT, 4, 1},
+	{QLCNIC_CMD_TEMP_SIZE, 1, 4},
+	{QLCNIC_CMD_GET_TEMP_HDR, 5, 5},
+	{QLCNIC_CMD_GET_LINK_EVENT, 2, 1},
+	{QLCNIC_CMD_CONFIG_MAC_VLAN, 4, 3},
+	{QLCNIC_CMD_CONFIG_INTR_COAL, 6, 1},
+	{QLCNIC_CMD_CONFIGURE_RSS, 14, 1},
+	{QLCNIC_CMD_CONFIGURE_LED, 2, 1},
+	{QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, 2, 1},
+	{QLCNIC_CMD_CONFIGURE_HW_LRO, 2, 1},
+	{QLCNIC_CMD_GET_STATISTICS, 2, 80},
+	{QLCNIC_CMD_SET_PORT_CONFIG, 2, 1},
+	{QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},
+	{QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
+	{QLCNIC_CMD_IDC_ACK, 5, 1},
+	{QLCNIC_CMD_INIT_NIC_FUNC, 2, 1},
+	{QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
+	{QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
+	{QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
+	{QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
+};
+
+static const u32 qlcnic_83xx_ext_reg_tbl[] = {
+	0x38CC,		/* Global Reset */
+	0x38F0,		/* Wildcard */
+	0x38FC,		/* Informant */
+	0x3038,		/* Host MBX ctrl */
+	0x303C,		/* FW MBX ctrl */
+	0x355C,		/* BOOT LOADER ADDRESS REG */
+	0x3560,		/* BOOT LOADER SIZE REG */
+	0x3564,		/* FW IMAGE ADDR REG */
+	0x1000,		/* MBX intr enable */
+	0x1200,		/* Default Intr mask */
+	0x1204,		/* Default Interrupt ID */
+	0x3780,		/* QLC_83XX_IDC_MAJ_VERSION */
+	0x3784,		/* QLC_83XX_IDC_DEV_STATE */
+	0x3788,		/* QLC_83XX_IDC_DRV_PRESENCE */
+	0x378C,		/* QLC_83XX_IDC_DRV_ACK */
+	0x3790,		/* QLC_83XX_IDC_CTRL */
+	0x3794,		/* QLC_83XX_IDC_DRV_AUDIT */
+	0x3798,		/* QLC_83XX_IDC_MIN_VERSION */
+	0x379C,		/* QLC_83XX_RECOVER_DRV_LOCK */
+	0x37A0,		/* QLC_83XX_IDC_PF_0 */
+	0x37A4,		/* QLC_83XX_IDC_PF_1 */
+	0x37A8,		/* QLC_83XX_IDC_PF_2 */
+	0x37AC,		/* QLC_83XX_IDC_PF_3 */
+	0x37B0,		/* QLC_83XX_IDC_PF_4 */
+	0x37B4,		/* QLC_83XX_IDC_PF_5 */
+	0x37B8,		/* QLC_83XX_IDC_PF_6 */
+	0x37BC,		/* QLC_83XX_IDC_PF_7 */
+	0x37C0,		/* QLC_83XX_IDC_PF_8 */
+	0x37C4,		/* QLC_83XX_IDC_PF_9 */
+	0x37C8,		/* QLC_83XX_IDC_PF_10 */
+	0x37CC,		/* QLC_83XX_IDC_PF_11 */
+	0x37D0,		/* QLC_83XX_IDC_PF_12 */
+	0x37D4,		/* QLC_83XX_IDC_PF_13 */
+	0x37D8,		/* QLC_83XX_IDC_PF_14 */
+	0x37DC,		/* QLC_83XX_IDC_PF_15 */
+	0x37E0,		/* QLC_83XX_IDC_DEV_PARTITION_INFO_1 */
+	0x37E4,		/* QLC_83XX_IDC_DEV_PARTITION_INFO_2 */
+	0x37F0,		/* QLC_83XX_DRV_OP_MODE */
+	0x37F4,		/* QLC_83XX_VNIC_STATE */
+	0x3868,		/* QLC_83XX_DRV_LOCK */
+	0x386C,		/* QLC_83XX_DRV_UNLOCK */
+	0x3504,		/* QLC_83XX_DRV_LOCK_ID */
+	0x34A4,		/* QLC_83XX_ASIC_TEMP */
+};
+
+static const u32 qlcnic_83xx_reg_tbl[] = {
+	0x34A8,		/* PEG_HALT_STAT1 */
+	0x34AC,		/* PEG_HALT_STAT2 */
+	0x34B0,		/* FW_HEARTBEAT */
+	0x3500,		/* FLASH LOCK_ID */
+	0x3528,		/* FW_CAPABILITIES */
+	0x3538,		/* Driver active, DRV_REG0 */
+	0x3540,		/* Device state, DRV_REG1 */
+	0x3544,		/* Driver state, DRV_REG2 */
+	0x3548,		/* Driver scratch, DRV_REG3 */
+	0x354C,		/* Device partiton info, DRV_REG4 */
+	0x3524,		/* Driver IDC ver, DRV_REG5 */
+	0x3550,		/* FW_VER_MAJOR */
+	0x3554,		/* FW_VER_MINOR */
+	0x3558,		/* FW_VER_SUB */
+	0x359C,		/* NPAR STATE */
+	0x35FC,		/* FW_IMG_VALID */
+	0x3650,		/* CMD_PEG_STATE */
+	0x373C,		/* RCV_PEG_STATE */
+	0x37B4,		/* ASIC TEMP */
+	0x356C,		/* FW API */
+	0x3570,		/* DRV OP MODE */
+	0x3850,		/* FLASH LOCK */
+	0x3854,		/* FLASH UNLOCK */
+};
+
+static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
+	.read_crb			= qlcnic_83xx_read_crb,
+	.write_crb			= qlcnic_83xx_write_crb,
+	.read_reg			= qlcnic_83xx_rd_reg_indirect,
+	.write_reg			= qlcnic_83xx_wrt_reg_indirect,
+	.get_mac_address		= qlcnic_83xx_get_mac_address,
+	.setup_intr			= qlcnic_83xx_setup_intr,
+	.alloc_mbx_args			= qlcnic_83xx_alloc_mbx_args,
+	.mbx_cmd			= qlcnic_83xx_mbx_op,
+	.get_func_no			= qlcnic_83xx_get_func_no,
+	.api_lock			= qlcnic_83xx_cam_lock,
+	.api_unlock			= qlcnic_83xx_cam_unlock,
+	.add_sysfs			= qlcnic_83xx_add_sysfs,
+	.remove_sysfs			= qlcnic_83xx_remove_sysfs,
+	.process_lb_rcv_ring_diag	= qlcnic_83xx_process_rcv_ring_diag,
+	.create_rx_ctx			= qlcnic_83xx_create_rx_ctx,
+	.create_tx_ctx			= qlcnic_83xx_create_tx_ctx,
+	.setup_link_event		= qlcnic_83xx_setup_link_event,
+	.get_nic_info			= qlcnic_83xx_get_nic_info,
+	.get_pci_info			= qlcnic_83xx_get_pci_info,
+	.set_nic_info			= qlcnic_83xx_set_nic_info,
+	.change_macvlan			= qlcnic_83xx_sre_macaddr_change,
+	.napi_enable			= qlcnic_83xx_napi_enable,
+	.napi_disable			= qlcnic_83xx_napi_disable,
+	.config_intr_coal		= qlcnic_83xx_config_intr_coal,
+	.config_rss			= qlcnic_83xx_config_rss,
+	.config_hw_lro			= qlcnic_83xx_config_hw_lro,
+	.config_promisc_mode		= qlcnic_83xx_nic_set_promisc,
+	.change_l2_filter		= qlcnic_83xx_change_l2_filter,
+	.get_board_info			= qlcnic_83xx_get_port_info,
+};
+
+static struct qlcnic_nic_template qlcnic_83xx_ops = {
+	.config_bridged_mode	= qlcnic_config_bridged_mode,
+	.config_led		= qlcnic_config_led,
+	.request_reset          = qlcnic_83xx_idc_request_reset,
+	.cancel_idc_work        = qlcnic_83xx_idc_exit,
+	.napi_add		= qlcnic_83xx_napi_add,
+	.napi_del		= qlcnic_83xx_napi_del,
+	.config_ipaddr		= qlcnic_83xx_config_ipaddr,
+	.clear_legacy_intr	= qlcnic_83xx_clear_legacy_intr,
+};
+
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *ahw)
+{
+	ahw->hw_ops		= &qlcnic_83xx_hw_ops;
+	ahw->reg_tbl		= (u32 *)qlcnic_83xx_reg_tbl;
+	ahw->ext_reg_tbl	= (u32 *)qlcnic_83xx_ext_reg_tbl;
+}
+
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *adapter)
+{
+	u32 fw_major, fw_minor, fw_build;
+	struct pci_dev *pdev = adapter->pdev;
+
+	fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+	fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+	fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
+	adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
+
+	dev_info(&pdev->dev, "Driver v%s, firmware version %d.%d.%d\n",
+		 QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
+	return adapter->fw_version;
+}
+
+static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
+{
+	void __iomem *base;
+	u32 val;
+
+	base = adapter->ahw->pci_base0 +
+	       QLC_83XX_CRB_WIN_FUNC(adapter->ahw->pci_func);
+	writel(addr, base);
+	val = readl(base);
+	if (val != addr)
+		return -EIO;
+
+	return 0;
+}
+
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr)
+{
+	int ret;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	ret = __qlcnic_set_win_base(adapter, (u32) addr);
+	if (!ret) {
+		return QLCRDX(ahw, QLCNIC_WILDCARD);
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"%s failed, addr = 0x%x\n", __func__, (int)addr);
+		return -EIO;
+	}
+}
+
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+				 u32 data)
+{
+	int err;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	err = __qlcnic_set_win_base(adapter, (u32) addr);
+	if (!err) {
+		QLCWRX(ahw, QLCNIC_WILDCARD, data);
+		return 0;
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"%s failed, addr = 0x%x data = 0x%x\n",
+			__func__, (int)addr, data);
+		return err;
+	}
+}
+
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+	int err, i, num_msix;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (!num_intr)
+		num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+	num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
+					      num_intr));
+	/* account for AEN interrupt MSI-X based interrupts */
+	num_msix += 1;
+	num_msix += adapter->max_drv_tx_rings;
+	err = qlcnic_enable_msix(adapter, num_msix);
+	if (err == -ENOMEM)
+		return err;
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		num_msix = adapter->ahw->num_msix;
+	else
+		num_msix = 1;
+	/* setup interrupt mapping table for fw */
+	ahw->intr_tbl = vzalloc(num_msix *
+				sizeof(struct qlcnic_intrpt_config));
+	if (!ahw->intr_tbl)
+		return -ENOMEM;
+	if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+		/* MSI-X enablement failed, use legacy interrupt */
+		adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR;
+		adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK;
+		adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR;
+		adapter->msix_entries[0].vector = adapter->pdev->irq;
+		dev_info(&adapter->pdev->dev, "using legacy interrupt\n");
+	}
+
+	for (i = 0; i < num_msix; i++) {
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;
+		else
+			ahw->intr_tbl[i].type = QLCNIC_INTRPT_INTX;
+		ahw->intr_tbl[i].id = i;
+		ahw->intr_tbl[i].src = 0;
+	}
+	return 0;
+}
+
+inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
+{
+	writel(0, adapter->tgt_mask_reg);
+}
+
+/* Enable MSI-x and INT-x interrupts */
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
+			     struct qlcnic_host_sds_ring *sds_ring)
+{
+	writel(0, sds_ring->crb_intr_mask);
+}
+
+/* Disable MSI-x and INT-x interrupts */
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter,
+			      struct qlcnic_host_sds_ring *sds_ring)
+{
+	writel(1, sds_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter
+						    *adapter)
+{
+	u32 mask;
+
+	/* Mailbox in MSI-x mode and Legacy Interrupt share the same
+	 * source register. We could be here before contexts are created
+	 * and sds_ring->crb_intr_mask has not been initialized, calculate
+	 * BAR offset for Interrupt Source Register
+	 */
+	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+	writel(0, adapter->ahw->pci_base0 + mask);
+}
+
+inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)
+{
+	u32 mask;
+
+	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+	writel(1, adapter->ahw->pci_base0 + mask);
+}
+
+static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
+				     struct qlcnic_cmd_args *cmd)
+{
+	int i;
+	for (i = 0; i < cmd->rsp.num; i++)
+		cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));
+}
+
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+	u32 intr_val;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int retries = 0;
+
+	intr_val = readl(adapter->tgt_status_reg);
+
+	if (!QLC_83XX_VALID_INTX_BIT31(intr_val))
+		return IRQ_NONE;
+
+	if (QLC_83XX_INTX_FUNC(intr_val) != adapter->ahw->pci_func) {
+		adapter->stats.spurious_intr++;
+		return IRQ_NONE;
+	}
+	/* The barrier is required to ensure writes to the registers */
+	wmb();
+
+	/* clear the interrupt trigger control register */
+	writel(0, adapter->isr_int_vec);
+	intr_val = readl(adapter->isr_int_vec);
+	do {
+		intr_val = readl(adapter->tgt_status_reg);
+		if (QLC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)
+			break;
+		retries++;
+	} while (QLC_83XX_VALID_INTX_BIT30(intr_val) &&
+		 (retries < QLC_83XX_LEGACY_INTX_MAX_RETRY));
+
+	return IRQ_HANDLED;
+}
+
+static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
+{
+	u32 resp, event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+
+	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+	if (!(resp & QLCNIC_SET_OWNER))
+		goto out;
+
+	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
+	if (event &  QLCNIC_MBX_ASYNC_EVENT)
+		qlcnic_83xx_process_aen(adapter);
+out:
+	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+}
+
+irqreturn_t qlcnic_83xx_intr(int irq, void *data)
+{
+	struct qlcnic_adapter *adapter = data;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (qlcnic_83xx_clear_legacy_intr(adapter) == IRQ_NONE)
+		return IRQ_NONE;
+
+	qlcnic_83xx_poll_process_aen(adapter);
+
+	if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+		ahw->diag_cnt++;
+		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+		return IRQ_HANDLED;
+	}
+
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+	} else {
+		sds_ring = &adapter->recv_ctx->sds_rings[0];
+		napi_schedule(&sds_ring->napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data)
+{
+	struct qlcnic_host_sds_ring *sds_ring = data;
+	struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		goto done;
+
+	if (adapter->nic_ops->clear_legacy_intr(adapter) == IRQ_NONE)
+		return IRQ_NONE;
+
+done:
+	adapter->ahw->diag_cnt++;
+	qlcnic_83xx_enable_intr(adapter, sds_ring);
+
+	return IRQ_HANDLED;
+}
+
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
+{
+	u32 val = 0, num_msix = adapter->ahw->num_msix - 1;
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		num_msix = adapter->ahw->num_msix - 1;
+	else
+		num_msix = 0;
+
+	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+
+	qlcnic_83xx_disable_mbx_intr(adapter);
+
+	msleep(20);
+	synchronize_irq(adapter->msix_entries[num_msix].vector);
+	free_irq(adapter->msix_entries[num_msix].vector, adapter);
+}
+
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
+{
+	irq_handler_t handler;
+	u32 val;
+	char name[32];
+	int err = 0;
+	unsigned long flags = 0;
+
+	if (!(adapter->flags & QLCNIC_MSI_ENABLED) &&
+	    !(adapter->flags & QLCNIC_MSIX_ENABLED))
+		flags |= IRQF_SHARED;
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+		handler = qlcnic_83xx_handle_aen;
+		val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
+		snprintf(name, (IFNAMSIZ + 4),
+			 "%s[%s]", "qlcnic", "aen");
+		err = request_irq(val, handler, flags, name, adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"failed to register MBX interrupt\n");
+			return err;
+		}
+	} else {
+		handler = qlcnic_83xx_intr;
+		val = adapter->msix_entries[0].vector;
+		err = request_irq(val, handler, flags, "qlcnic", adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"failed to register INTx interrupt\n");
+			return err;
+		}
+		qlcnic_83xx_clear_legacy_intr_mask(adapter);
+	}
+
+	/* Enable mailbox interrupt */
+	qlcnic_83xx_enable_mbx_intrpt(adapter);
+
+	return err;
+}
+
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+	u32 val = QLCRDX(adapter->ahw, QLCNIC_INFORMANT);
+	adapter->ahw->pci_func = val & 0xf;
+}
+
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *adapter)
+{
+	void __iomem *addr;
+	u32 val, limit = 0;
+
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	addr = ahw->pci_base0 + QLC_83XX_SEM_LOCK_FUNC(ahw->pci_func);
+	do {
+		val = readl(addr);
+		if (val) {
+			/* write the function number to register */
+			QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
+					    ahw->pci_func);
+			return 0;
+		}
+		usleep_range(1000, 2000);
+	} while (++limit <= QLCNIC_PCIE_SEM_TIMEOUT);
+
+	return -EIO;
+}
+
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
+{
+	void __iomem *addr;
+	u32 val;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	addr = ahw->pci_base0 + QLC_83XX_SEM_UNLOCK_FUNC(ahw->pci_func);
+	val = readl(addr);
+}
+
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+			  loff_t offset, size_t size)
+{
+	int ret;
+	u32 data;
+
+	if (qlcnic_api_lock(adapter)) {
+		dev_err(&adapter->pdev->dev,
+			"%s: failed to acquire lock. addr offset 0x%x\n",
+			__func__, (u32)offset);
+		return;
+	}
+
+	ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset);
+	qlcnic_api_unlock(adapter);
+
+	if (ret == -EIO) {
+		dev_err(&adapter->pdev->dev,
+			"%s: failed. addr offset 0x%x\n",
+			__func__, (u32)offset);
+		return;
+	}
+	data = ret;
+	memcpy(buf, &data, size);
+}
+
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+			   loff_t offset, size_t size)
+{
+	u32 data;
+
+	memcpy(&data, buf, size);
+	qlcnic_83xx_wrt_reg_indirect(adapter, (u32) offset, data);
+}
+
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
+{
+	int status;
+
+	status = qlcnic_83xx_get_port_config(adapter);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"Get Port Info failed\n");
+	} else {
+		if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
+			adapter->ahw->port_type = QLCNIC_XGBE;
+		else
+			adapter->ahw->port_type = QLCNIC_GBE;
+
+		if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
+			adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+	}
+	return status;
+}
+
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
+{
+	u32 val;
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		val = BIT_2 | ((adapter->ahw->num_msix - 1) << 8);
+	else
+		val = BIT_2;
+
+	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+}
+
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
+			  const struct pci_device_id *ent)
+{
+	u32 op_mode, priv_level;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	ahw->fw_hal_version = 2;
+	qlcnic_get_func_no(adapter);
+
+	/* Determine function privilege level */
+	op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+	if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+		priv_level = QLCNIC_MGMT_FUNC;
+	else
+		priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+							 ahw->pci_func);
+
+	if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+		ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+		dev_info(&adapter->pdev->dev,
+			 "HAL Version: %d Non Privileged function\n",
+			 ahw->fw_hal_version);
+		adapter->nic_ops = &qlcnic_vf_ops;
+	} else {
+		adapter->nic_ops = &qlcnic_83xx_ops;
+	}
+}
+
+static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
+					u32 data[]);
+static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
+					    u32 data[]);
+
+static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
+			    struct qlcnic_cmd_args *cmd)
+{
+	int i;
+
+	dev_info(&adapter->pdev->dev,
+		 "Host MBX regs(%d)\n", cmd->req.num);
+	for (i = 0; i < cmd->req.num; i++) {
+		if (i && !(i % 8))
+			pr_info("\n");
+		pr_info("%08x ", cmd->req.arg[i]);
+	}
+	pr_info("\n");
+	dev_info(&adapter->pdev->dev,
+		 "FW MBX regs(%d)\n", cmd->rsp.num);
+	for (i = 0; i < cmd->rsp.num; i++) {
+		if (i && !(i % 8))
+			pr_info("\n");
+		pr_info("%08x ", cmd->rsp.arg[i]);
+	}
+	pr_info("\n");
+}
+
+/* Mailbox response for mac rcode */
+static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
+{
+	u32 fw_data;
+	u8 mac_cmd_rcode;
+
+	fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
+	mac_cmd_rcode = (u8)fw_data;
+	if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
+	    mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
+	    mac_cmd_rcode == QLC_83XX_MAC_ABSENT)
+		return QLCNIC_RCODE_SUCCESS;
+	return 1;
+}
+
+static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
+{
+	u32 data;
+	unsigned long wait_time = 0;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	/* wait for mailbox completion */
+	do {
+		data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
+		if (++wait_time > QLCNIC_MBX_TIMEOUT) {
+			data = QLCNIC_RCODE_TIMEOUT;
+			break;
+		}
+		mdelay(1);
+	} while (!data);
+	return data;
+}
+
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
+		       struct qlcnic_cmd_args *cmd)
+{
+	int i;
+	u16 opcode;
+	u8 mbx_err_code;
+	unsigned long flags;
+	u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	opcode = LSW(cmd->req.arg[0]);
+	if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+		dev_info(&adapter->pdev->dev,
+			 "Mailbox cmd attempted, 0x%x\n", opcode);
+		dev_info(&adapter->pdev->dev, "Mailbox detached\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+	mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+
+	if (mbx_val) {
+		QLCDB(adapter, DRV,
+		      "Mailbox cmd attempted, 0x%x\n", opcode);
+		QLCDB(adapter, DRV,
+		      "Mailbox not available, 0x%x, collect FW dump\n",
+		      mbx_val);
+		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+		spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+		return cmd->rsp.arg[0];
+	}
+
+	/* Fill in mailbox registers */
+	mbx_cmd = cmd->req.arg[0];
+	writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+	for (i = 1; i < cmd->req.num; i++)
+		writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
+
+	/* Signal FW about the impending command */
+	QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
+poll:
+	rsp = qlcnic_83xx_mbx_poll(adapter);
+	if (rsp != QLCNIC_RCODE_TIMEOUT) {
+		/* Get the FW response data */
+		fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
+		if (fw_data &  QLCNIC_MBX_ASYNC_EVENT) {
+			qlcnic_83xx_process_aen(adapter);
+			mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+			if (mbx_val)
+				goto poll;
+		}
+		mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
+		rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
+		opcode = QLCNIC_MBX_RSP(fw_data);
+		qlcnic_83xx_get_mbx_data(adapter, cmd);
+
+		switch (mbx_err_code) {
+		case QLCNIC_MBX_RSP_OK:
+		case QLCNIC_MBX_PORT_RSP_OK:
+			rsp = QLCNIC_RCODE_SUCCESS;
+			break;
+		default:
+			if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
+				rsp = qlcnic_83xx_mac_rcode(adapter);
+				if (!rsp)
+					goto out;
+			}
+			dev_err(&adapter->pdev->dev,
+				"MBX command 0x%x failed with err:0x%x\n",
+				opcode, mbx_err_code);
+			rsp = mbx_err_code;
+			qlcnic_dump_mbx(adapter, cmd);
+			break;
+		}
+		goto out;
+	}
+
+	dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
+		QLCNIC_MBX_RSP(mbx_cmd));
+	rsp = QLCNIC_RCODE_TIMEOUT;
+out:
+	/* clear fw mbx control register */
+	QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+	return rsp;
+}
+
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+			       struct qlcnic_adapter *adapter, u32 type)
+{
+	int i, size;
+	u32 temp;
+	const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+	mbx_tbl = qlcnic_83xx_mbx_tbl;
+	size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
+	for (i = 0; i < size; i++) {
+		if (type == mbx_tbl[i].cmd) {
+			mbx->req.num = mbx_tbl[i].in_args;
+			mbx->rsp.num = mbx_tbl[i].out_args;
+			mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
+					       GFP_ATOMIC);
+			if (!mbx->req.arg)
+				return -ENOMEM;
+			mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
+					       GFP_ATOMIC);
+			if (!mbx->rsp.arg) {
+				kfree(mbx->req.arg);
+				mbx->req.arg = NULL;
+				return -ENOMEM;
+			}
+			memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+			memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+			temp = adapter->ahw->fw_hal_version << 29;
+			mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
+			break;
+		}
+	}
+	return 0;
+}
+
+void qlcnic_83xx_idc_aen_work(struct work_struct *work)
+{
+	struct qlcnic_adapter *adapter;
+	struct qlcnic_cmd_args cmd;
+	int i, err = 0;
+
+	adapter = container_of(work, struct qlcnic_adapter, idc_aen_work.work);
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);
+
+	for (i = 1; i < QLC_83XX_MBX_AEN_CNT; i++)
+		cmd.req.arg[i] = adapter->ahw->mbox_aen[i];
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_info(&adapter->pdev->dev,
+			 "%s: Mailbox IDC ACK failed.\n", __func__);
+	qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
+					    u32 data[])
+{
+	dev_dbg(&adapter->pdev->dev, "Completion AEN:0x%x.\n",
+		QLCNIC_MBX_RSP(data[0]));
+	clear_bit(QLC_83XX_IDC_COMP_AEN, &adapter->ahw->idc.status);
+	return;
+}
+
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
+{
+	u32 event[QLC_83XX_MBX_AEN_CNT];
+	int i;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+		event[i] = readl(QLCNIC_MBX_FW(ahw, i));
+
+	switch (QLCNIC_MBX_RSP(event[0])) {
+
+	case QLCNIC_MBX_LINK_EVENT:
+		qlcnic_83xx_handle_link_aen(adapter, event);
+		break;
+	case QLCNIC_MBX_COMP_EVENT:
+		qlcnic_83xx_handle_idc_comp_aen(adapter, event);
+		break;
+	case QLCNIC_MBX_REQUEST_EVENT:
+		for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+			adapter->ahw->mbox_aen[i] = QLCNIC_MBX_RSP(event[i]);
+		queue_delayed_work(adapter->qlcnic_wq,
+				   &adapter->idc_aen_work, 0);
+		break;
+	case QLCNIC_MBX_TIME_EXTEND_EVENT:
+		break;
+	case QLCNIC_MBX_SFP_INSERT_EVENT:
+		dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
+			 QLCNIC_MBX_RSP(event[0]));
+		break;
+	case QLCNIC_MBX_SFP_REMOVE_EVENT:
+		dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n",
+			 QLCNIC_MBX_RSP(event[0]));
+		break;
+	default:
+		dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n",
+			QLCNIC_MBX_RSP(event[0]));
+		break;
+	}
+
+	QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+}
+
+static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
+{
+	int index, i, err, sds_mbx_size;
+	u32 *buf, intrpt_id, intr_mask;
+	u16 context_id;
+	u8 num_sds;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_host_sds_ring *sds;
+	struct qlcnic_sds_mbx sds_mbx;
+	struct qlcnic_add_rings_mbx_out *mbx_out;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+	context_id = recv_ctx->context_id;
+	num_sds = (adapter->max_sds_rings - QLCNIC_MAX_RING_SETS);
+	ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+				    QLCNIC_CMD_ADD_RCV_RINGS);
+	cmd.req.arg[1] = 0 | (num_sds << 8) | (context_id << 16);
+
+	/* set up status rings, mbx 2-81 */
+	index = 2;
+	for (i = 8; i < adapter->max_sds_rings; i++) {
+		memset(&sds_mbx, 0, sds_mbx_size);
+		sds = &recv_ctx->sds_rings[i];
+		sds->consumer = 0;
+		memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+		sds_mbx.phy_addr = sds->phys_addr;
+		sds_mbx.sds_ring_size = sds->num_desc;
+
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			intrpt_id = ahw->intr_tbl[i].id;
+		else
+			intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+
+		if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+			sds_mbx.intrpt_id = intrpt_id;
+		else
+			sds_mbx.intrpt_id = 0xffff;
+		sds_mbx.intrpt_val = 0;
+		buf = &cmd.req.arg[index];
+		memcpy(buf, &sds_mbx, sds_mbx_size);
+		index += sds_mbx_size / sizeof(u32);
+	}
+
+	/* send the mailbox command */
+	err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to add rings %d\n", err);
+		goto out;
+	}
+
+	mbx_out = (struct qlcnic_add_rings_mbx_out *)&cmd.rsp.arg[1];
+	index = 0;
+	/* status descriptor ring */
+	for (i = 8; i < adapter->max_sds_rings; i++) {
+		sds = &recv_ctx->sds_rings[i];
+		sds->crb_sts_consumer = ahw->pci_base0 +
+					mbx_out->host_csmr[index];
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			intr_mask = ahw->intr_tbl[i].src;
+		else
+			intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+
+		sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+		index++;
+	}
+out:
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+	int i, err, index, sds_mbx_size, rds_mbx_size;
+	u8 num_sds, num_rds;
+	u32 *buf, intrpt_id, intr_mask, cap = 0;
+	struct qlcnic_host_sds_ring *sds;
+	struct qlcnic_host_rds_ring *rds;
+	struct qlcnic_sds_mbx sds_mbx;
+	struct qlcnic_rds_mbx rds_mbx;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_rcv_mbx_out *mbx_out;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	num_rds = adapter->max_rds_rings;
+
+	if (adapter->max_sds_rings <= QLCNIC_MAX_RING_SETS)
+		num_sds = adapter->max_sds_rings;
+	else
+		num_sds = QLCNIC_MAX_RING_SETS;
+
+	sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+	rds_mbx_size = sizeof(struct qlcnic_rds_mbx);
+	cap = QLCNIC_CAP0_LEGACY_CONTEXT;
+
+	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+		cap |= QLC_83XX_FW_CAP_LRO_MSS;
+
+	/* set mailbox hdr and capabilities */
+	qlcnic_alloc_mbx_args(&cmd, adapter,
+			      QLCNIC_CMD_CREATE_RX_CTX);
+	cmd.req.arg[1] = cap;
+	cmd.req.arg[5] = 1 | (num_rds << 5) | (num_sds << 8) |
+			 (QLC_83XX_HOST_RDS_MODE_UNIQUE << 16);
+	/* set up status rings, mbx 8-57/87 */
+	index = QLC_83XX_HOST_SDS_MBX_IDX;
+	for (i = 0; i < num_sds; i++) {
+		memset(&sds_mbx, 0, sds_mbx_size);
+		sds = &recv_ctx->sds_rings[i];
+		sds->consumer = 0;
+		memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+		sds_mbx.phy_addr = sds->phys_addr;
+		sds_mbx.sds_ring_size = sds->num_desc;
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			intrpt_id = ahw->intr_tbl[i].id;
+		else
+			intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+		if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+			sds_mbx.intrpt_id = intrpt_id;
+		else
+			sds_mbx.intrpt_id = 0xffff;
+		sds_mbx.intrpt_val = 0;
+		buf = &cmd.req.arg[index];
+		memcpy(buf, &sds_mbx, sds_mbx_size);
+		index += sds_mbx_size / sizeof(u32);
+	}
+	/* set up receive rings, mbx 88-111/135 */
+	index = QLCNIC_HOST_RDS_MBX_IDX;
+	rds = &recv_ctx->rds_rings[0];
+	rds->producer = 0;
+	memset(&rds_mbx, 0, rds_mbx_size);
+	rds_mbx.phy_addr_reg = rds->phys_addr;
+	rds_mbx.reg_ring_sz = rds->dma_size;
+	rds_mbx.reg_ring_len = rds->num_desc;
+	/* Jumbo ring */
+	rds = &recv_ctx->rds_rings[1];
+	rds->producer = 0;
+	rds_mbx.phy_addr_jmb = rds->phys_addr;
+	rds_mbx.jmb_ring_sz = rds->dma_size;
+	rds_mbx.jmb_ring_len = rds->num_desc;
+	buf = &cmd.req.arg[index];
+	memcpy(buf, &rds_mbx, rds_mbx_size);
+
+	/* send the mailbox command */
+	err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to create Rx ctx in firmware%d\n", err);
+		goto out;
+	}
+	mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd.rsp.arg[1];
+	recv_ctx->context_id = mbx_out->ctx_id;
+	recv_ctx->state = mbx_out->state;
+	recv_ctx->virt_port = mbx_out->vport_id;
+	dev_info(&adapter->pdev->dev, "Rx Context[%d] Created, state:0x%x\n",
+		 recv_ctx->context_id, recv_ctx->state);
+	/* Receive descriptor ring */
+	/* Standard ring */
+	rds = &recv_ctx->rds_rings[0];
+	rds->crb_rcv_producer = ahw->pci_base0 +
+				mbx_out->host_prod[0].reg_buf;
+	/* Jumbo ring */
+	rds = &recv_ctx->rds_rings[1];
+	rds->crb_rcv_producer = ahw->pci_base0 +
+				mbx_out->host_prod[0].jmb_buf;
+	/* status descriptor ring */
+	for (i = 0; i < num_sds; i++) {
+		sds = &recv_ctx->sds_rings[i];
+		sds->crb_sts_consumer = ahw->pci_base0 +
+					mbx_out->host_csmr[i];
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			intr_mask = ahw->intr_tbl[i].src;
+		else
+			intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+		sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+	}
+
+	if (adapter->max_sds_rings > QLCNIC_MAX_RING_SETS)
+		err = qlcnic_83xx_add_rings(adapter);
+out:
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
+			      struct qlcnic_host_tx_ring *tx, int ring)
+{
+	int err;
+	u16 msix_id;
+	u32 *buf, intr_mask;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_tx_mbx mbx;
+	struct qlcnic_tx_mbx_out *mbx_out;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	/* Reset host resources */
+	tx->producer = 0;
+	tx->sw_consumer = 0;
+	*(tx->hw_consumer) = 0;
+
+	memset(&mbx, 0, sizeof(struct qlcnic_tx_mbx));
+
+	/* setup mailbox inbox registerss */
+	mbx.phys_addr = tx->phys_addr;
+	mbx.cnsmr_index = tx->hw_cons_phys_addr;
+	mbx.size = tx->num_desc;
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		msix_id = ahw->intr_tbl[adapter->max_sds_rings + ring].id;
+	else
+		msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+		mbx.intr_id = msix_id;
+	else
+		mbx.intr_id = 0xffff;
+	mbx.src = 0;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+	cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT;
+	cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES;
+	buf = &cmd.req.arg[6];
+	memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));
+	/* send the mailbox command*/
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to create Tx ctx in firmware 0x%x\n", err);
+		goto out;
+	}
+	mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2];
+	tx->crb_cmd_producer = ahw->pci_base0 + mbx_out->host_prod;
+	tx->ctx_id = mbx_out->ctx_id;
+	if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+		intr_mask = ahw->intr_tbl[adapter->max_sds_rings + ring].src;
+		tx->crb_intr_mask = ahw->pci_base0 + intr_mask;
+	}
+	dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n",
+		 tx->ctx_id, mbx_out->state);
+out:
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_host_rds_ring *rds_ring;
+	u8 ring;
+	int ret;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		__qlcnic_down(adapter, netdev);
+
+	qlcnic_detach(adapter);
+
+	adapter->max_sds_rings = 1;
+	adapter->ahw->diag_test = test;
+	adapter->ahw->linkup = 0;
+
+	ret = qlcnic_attach(adapter);
+	if (ret) {
+		netif_device_attach(netdev);
+		return ret;
+	}
+
+	ret = qlcnic_fw_create_ctx(adapter);
+	if (ret) {
+		qlcnic_detach(adapter);
+		netif_device_attach(netdev);
+		return ret;
+	}
+
+	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+		rds_ring = &adapter->recv_ctx->rds_rings[ring];
+		qlcnic_post_rx_buffers(adapter, rds_ring, ring);
+	}
+
+	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+			sds_ring = &adapter->recv_ctx->sds_rings[ring];
+			qlcnic_83xx_enable_intr(adapter, sds_ring);
+		}
+	}
+
+	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+		/* disable and free mailbox interrupt */
+		qlcnic_83xx_free_mbx_intr(adapter);
+		adapter->ahw->loopback_state = 0;
+		adapter->ahw->hw_ops->setup_link_event(adapter, 1);
+	}
+
+	set_bit(__QLCNIC_DEV_UP, &adapter->state);
+	return 0;
+}
+
+static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
+					int max_sds_rings)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	struct qlcnic_host_sds_ring *sds_ring;
+	int ring, err;
+
+	clear_bit(__QLCNIC_DEV_UP, &adapter->state);
+	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+			sds_ring = &adapter->recv_ctx->sds_rings[ring];
+			qlcnic_83xx_disable_intr(adapter, sds_ring);
+		}
+	}
+
+	qlcnic_fw_destroy_ctx(adapter);
+	qlcnic_detach(adapter);
+
+	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+		err = qlcnic_83xx_setup_mbx_intr(adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"%s: failed to setup mbx interrupt\n",
+				__func__);
+			goto out;
+		}
+	}
+	adapter->ahw->diag_test = 0;
+	adapter->max_sds_rings = max_sds_rings;
+
+	if (qlcnic_attach(adapter))
+		goto out;
+
+	if (netif_running(netdev))
+		__qlcnic_up(adapter, netdev);
+out:
+	netif_device_attach(netdev);
+}
+
+int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
+			   u32 beacon)
+{
+	struct qlcnic_cmd_args cmd;
+	u32 mbx_in;
+	int i, status = 0;
+
+	if (state) {
+		/* Get LED configuration */
+		qlcnic_alloc_mbx_args(&cmd, adapter,
+				      QLCNIC_CMD_GET_LED_CONFIG);
+		status = qlcnic_issue_cmd(adapter, &cmd);
+		if (status) {
+			dev_err(&adapter->pdev->dev,
+				"Get led config failed.\n");
+			goto mbx_err;
+		} else {
+			for (i = 0; i < 4; i++)
+				adapter->ahw->mbox_reg[i] = cmd.rsp.arg[i+1];
+		}
+		qlcnic_free_mbx_args(&cmd);
+		/* Set LED Configuration */
+		mbx_in = (LSW(QLC_83XX_LED_CONFIG) << 16) |
+			  LSW(QLC_83XX_LED_CONFIG);
+		qlcnic_alloc_mbx_args(&cmd, adapter,
+				      QLCNIC_CMD_SET_LED_CONFIG);
+		cmd.req.arg[1] = mbx_in;
+		cmd.req.arg[2] = mbx_in;
+		cmd.req.arg[3] = mbx_in;
+		if (beacon)
+			cmd.req.arg[4] = QLC_83XX_ENABLE_BEACON;
+		status = qlcnic_issue_cmd(adapter, &cmd);
+		if (status) {
+			dev_err(&adapter->pdev->dev,
+				"Set led config failed.\n");
+		}
+mbx_err:
+		qlcnic_free_mbx_args(&cmd);
+		return status;
+
+	} else {
+		/* Restoring default LED configuration */
+		qlcnic_alloc_mbx_args(&cmd, adapter,
+				      QLCNIC_CMD_SET_LED_CONFIG);
+		cmd.req.arg[1] = adapter->ahw->mbox_reg[0];
+		cmd.req.arg[2] = adapter->ahw->mbox_reg[1];
+		cmd.req.arg[3] = adapter->ahw->mbox_reg[2];
+		if (beacon)
+			cmd.req.arg[4] = adapter->ahw->mbox_reg[3];
+		status = qlcnic_issue_cmd(adapter, &cmd);
+		if (status)
+			dev_err(&adapter->pdev->dev,
+				"Restoring led config failed.\n");
+		qlcnic_free_mbx_args(&cmd);
+		return status;
+	}
+}
+
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,
+				       int enable)
+{
+	struct qlcnic_cmd_args cmd;
+	int status;
+
+	if (enable) {
+		qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INIT_NIC_FUNC);
+		cmd.req.arg[1] = BIT_0 | BIT_31;
+	} else {
+		qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+		cmd.req.arg[1] = BIT_0 | BIT_31;
+	}
+	status = qlcnic_issue_cmd(adapter, &cmd);
+	if (status)
+		dev_err(&adapter->pdev->dev,
+			"Failed to %s in NIC IDC function event.\n",
+			(enable ? "register" : "unregister"));
+
+	qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_cmd_args cmd;
+	int err;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORT_CONFIG);
+	cmd.req.arg[1] = adapter->ahw->port_config;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_info(&adapter->pdev->dev, "Set Port Config failed.\n");
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_cmd_args cmd;
+	int err;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PORT_CONFIG);
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_info(&adapter->pdev->dev, "Get Port config failed\n");
+	else
+		adapter->ahw->port_config = cmd.rsp.arg[1];
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)
+{
+	int err;
+	u32 temp;
+	struct qlcnic_cmd_args cmd;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_EVENT);
+	temp = adapter->recv_ctx->context_id << 16;
+	cmd.req.arg[1] = (enable ? 1 : 0) | BIT_8 | temp;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_info(&adapter->pdev->dev,
+			 "Setup linkevent mailbox failed\n");
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+{
+	int err;
+	u32 temp;
+	struct qlcnic_cmd_args cmd;
+
+	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+		return -EIO;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
+	temp = adapter->recv_ctx->context_id << 16;
+	cmd.req.arg[1] = (mode ? 1 : 0) | temp;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_info(&adapter->pdev->dev,
+			 "Promiscous mode config failed\n");
+	qlcnic_free_mbx_args(&cmd);
+
+	return err;
+}
+
+int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings;
+
+	QLCDB(adapter, DRV, "%s loopback test in progress\n",
+	      mode == QLCNIC_ILB_MODE ? "internal" : "external");
+	if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+		dev_warn(&adapter->pdev->dev,
+			 "Loopback test not supported for non privilege function\n");
+		return ret;
+	}
+
+	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		return -EBUSY;
+
+	ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+	if (ret)
+		goto fail_diag_alloc;
+
+	ret = qlcnic_83xx_set_lb_mode(adapter, mode);
+	if (ret)
+		goto free_diag_res;
+
+	/* Poll for link up event before running traffic */
+	do {
+		msleep(500);
+		qlcnic_83xx_process_aen(adapter);
+		if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+			dev_info(&adapter->pdev->dev,
+				 "Firmware didn't sent link up event to loopback request\n");
+			ret = -QLCNIC_FW_NOT_RESPOND;
+			qlcnic_83xx_clear_lb_mode(adapter, mode);
+			goto free_diag_res;
+		}
+	} while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
+
+	ret = qlcnic_do_lb_test(adapter, mode);
+
+	qlcnic_83xx_clear_lb_mode(adapter, mode);
+
+free_diag_res:
+	qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_alloc:
+	adapter->max_sds_rings = max_sds_rings;
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	return ret;
+}
+
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int status = 0, loop = 0;
+	u32 config;
+
+	status = qlcnic_83xx_get_port_config(adapter);
+	if (status)
+		return status;
+
+	config = ahw->port_config;
+	set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+
+	if (mode == QLCNIC_ILB_MODE)
+		ahw->port_config |= QLC_83XX_CFG_LOOPBACK_HSS;
+	if (mode == QLCNIC_ELB_MODE)
+		ahw->port_config |= QLC_83XX_CFG_LOOPBACK_EXT;
+
+	status = qlcnic_83xx_set_port_config(adapter);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to Set Loopback Mode = 0x%x.\n",
+			ahw->port_config);
+		ahw->port_config = config;
+		clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+		return status;
+	}
+
+	/* Wait for Link and IDC Completion AEN */
+	do {
+		msleep(300);
+		qlcnic_83xx_process_aen(adapter);
+		if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+			dev_err(&adapter->pdev->dev,
+				"FW did not generate IDC completion AEN\n");
+			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+			qlcnic_83xx_clear_lb_mode(adapter, mode);
+			return -EIO;
+		}
+	} while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+	qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+				  QLCNIC_MAC_ADD);
+	return status;
+}
+
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int status = 0, loop = 0;
+	u32 config = ahw->port_config;
+
+	set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+	if (mode == QLCNIC_ILB_MODE)
+		ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS;
+	if (mode == QLCNIC_ELB_MODE)
+		ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_EXT;
+
+	status = qlcnic_83xx_set_port_config(adapter);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to Clear Loopback Mode = 0x%x.\n",
+			ahw->port_config);
+		ahw->port_config = config;
+		clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+		return status;
+	}
+
+	/* Wait for Link and IDC Completion AEN */
+	do {
+		msleep(300);
+		qlcnic_83xx_process_aen(adapter);
+		if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+			dev_err(&adapter->pdev->dev,
+				"Firmware didn't sent IDC completion AEN\n");
+			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+			return -EIO;
+		}
+	} while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+	qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+				  QLCNIC_MAC_DEL);
+	return status;
+}
+
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,
+			       int mode)
+{
+	int err;
+	u32 temp, temp_ip;
+	struct qlcnic_cmd_args cmd;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_IP_ADDR);
+	if (mode == QLCNIC_IP_UP) {
+		temp = adapter->recv_ctx->context_id << 16;
+		cmd.req.arg[1] = 1 | temp;
+	} else {
+		temp = adapter->recv_ctx->context_id << 16;
+		cmd.req.arg[1] = 2 | temp;
+	}
+
+	/*
+	 * Adapter needs IP address in network byte order.
+	 * But hardware mailbox registers go through writel(), hence IP address
+	 * gets swapped on big endian architecture.
+	 * To negate swapping of writel() on big endian architecture
+	 * use swab32(value).
+	 */
+
+	temp_ip = swab32(ntohl(ip));
+	memcpy(&cmd.req.arg[2], &temp_ip, sizeof(u32));
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err != QLCNIC_RCODE_SUCCESS)
+		dev_err(&adapter->netdev->dev,
+			"could not notify %s IP 0x%x request\n",
+			(mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+	qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *adapter, int mode)
+{
+	int err;
+	u32 temp, arg1;
+	struct qlcnic_cmd_args cmd;
+	int lro_bit_mask;
+
+	lro_bit_mask = (mode ? (BIT_0 | BIT_1 | BIT_2 | BIT_3) : 0);
+
+	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+		return 0;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_HW_LRO);
+	temp = adapter->recv_ctx->context_id << 16;
+	arg1 = lro_bit_mask | temp;
+	cmd.req.arg[1] = arg1;
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_info(&adapter->pdev->dev, "LRO config failed\n");
+	qlcnic_free_mbx_args(&cmd);
+
+	return err;
+}
+
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+	int err;
+	u32 word;
+	struct qlcnic_cmd_args cmd;
+	const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+			    0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+			    0x255b0ec26d5a56daULL };
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_RSS);
+
+	/*
+	 * RSS request:
+	 * bits 3-0: Rsvd
+	 *      5-4: hash_type_ipv4
+	 *	7-6: hash_type_ipv6
+	 *	  8: enable
+	 *        9: use indirection table
+	 *    16-31: indirection table mask
+	 */
+	word =  ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+		((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+		((u32)(enable & 0x1) << 8) |
+		((0x7ULL) << 16);
+	cmd.req.arg[1] = (adapter->recv_ctx->context_id);
+	cmd.req.arg[2] = word;
+	memcpy(&cmd.req.arg[4], key, sizeof(key));
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	if (err)
+		dev_info(&adapter->pdev->dev, "RSS config failed\n");
+	qlcnic_free_mbx_args(&cmd);
+
+	return err;
+
+}
+
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+				   __le16 vlan_id, u8 op)
+{
+	int err;
+	u32 *buf;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_macvlan_mbx mv;
+
+	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+		return -EIO;
+
+	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
+	if (err)
+		return err;
+	cmd.req.arg[1] = op | (1 << 8) |
+			(adapter->recv_ctx->context_id << 16);
+
+	mv.vlan = le16_to_cpu(vlan_id);
+	memcpy(&mv.mac, addr, ETH_ALEN);
+	buf = &cmd.req.arg[2];
+	memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
+		dev_err(&adapter->pdev->dev,
+			"MAC-VLAN %s to CAM failed, err=%d.\n",
+			((op == 1) ? "add " : "delete "), err);
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
+				  __le16 vlan_id)
+{
+	u8 mac[ETH_ALEN];
+	memcpy(&mac, addr, ETH_ALEN);
+	qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD);
+}
+
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac,
+			       u8 type, struct qlcnic_cmd_args *cmd)
+{
+	switch (type) {
+	case QLCNIC_SET_STATION_MAC:
+	case QLCNIC_SET_FAC_DEF_MAC:
+		memcpy(&cmd->req.arg[2], mac, sizeof(u32));
+		memcpy(&cmd->req.arg[3], &mac[4], sizeof(u16));
+		break;
+	}
+	cmd->req.arg[1] = type;
+}
+
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+	int err, i;
+	struct qlcnic_cmd_args cmd;
+	u32 mac_low, mac_high;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+	qlcnic_83xx_configure_mac(adapter, mac, QLCNIC_GET_CURRENT_MAC, &cmd);
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		mac_low = cmd.rsp.arg[1];
+		mac_high = cmd.rsp.arg[2];
+
+		for (i = 0; i < 2; i++)
+			mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+		for (i = 2; i < 6; i++)
+			mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+	} else {
+		dev_err(&adapter->pdev->dev, "Failed to get mac address%d\n",
+			err);
+		err = -EIO;
+	}
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
+{
+	int err;
+	u32 temp;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
+
+	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+		return;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);
+	cmd.req.arg[1] = 1 | (adapter->recv_ctx->context_id << 16);
+	cmd.req.arg[3] = coal->flag;
+	temp = coal->rx_time_us << 16;
+	cmd.req.arg[2] = coal->rx_packets | temp;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err != QLCNIC_RCODE_SUCCESS)
+		dev_info(&adapter->pdev->dev,
+			 "Failed to send interrupt coalescence parameters\n");
+	qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
+					u32 data[])
+{
+	u8 link_status, duplex;
+	/* link speed */
+	link_status = LSB(data[3]) & 1;
+	adapter->ahw->link_speed = MSW(data[2]);
+	adapter->ahw->link_autoneg = MSB(MSW(data[3]));
+	adapter->ahw->module_type = MSB(LSW(data[3]));
+	duplex = LSB(MSW(data[3]));
+	if (duplex)
+		adapter->ahw->link_duplex = DUPLEX_FULL;
+	else
+		adapter->ahw->link_duplex = DUPLEX_HALF;
+	adapter->ahw->has_link_events = 1;
+	qlcnic_advert_link_change(adapter, link_status);
+}
+
+irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
+{
+	struct qlcnic_adapter *adapter = data;
+	unsigned long flags;
+	u32 mask, resp, event;
+
+	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+	if (!(resp & QLCNIC_SET_OWNER))
+		goto out;
+
+	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
+	if (event &  QLCNIC_MBX_ASYNC_EVENT)
+		qlcnic_83xx_process_aen(adapter);
+out:
+	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+	writel(0, adapter->ahw->pci_base0 + mask);
+	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable)
+{
+	int err = -EIO;
+	struct qlcnic_cmd_args cmd;
+
+	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Error, invoked by non management func\n",
+			__func__);
+		return err;
+	}
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH);
+	cmd.req.arg[1] = (port & 0xf) | BIT_4;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev, "Failed to enable eswitch%d\n",
+			err);
+		err = -EIO;
+	}
+	qlcnic_free_mbx_args(&cmd);
+
+	return err;
+
+}
+
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,
+			     struct qlcnic_info *nic)
+{
+	int i, err = -EIO;
+	struct qlcnic_cmd_args cmd;
+
+	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Error, invoked by non management func\n",
+			__func__);
+		return err;
+	}
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+	cmd.req.arg[1] = (nic->pci_func << 16);
+	cmd.req.arg[2] = 0x1 << 16;
+	cmd.req.arg[3] = nic->phys_port | (nic->switch_mode << 16);
+	cmd.req.arg[4] = nic->capabilities;
+	cmd.req.arg[5] = (nic->max_mac_filters & 0xFF) | ((nic->max_mtu) << 16);
+	cmd.req.arg[6] = (nic->max_tx_ques) | ((nic->max_rx_ques) << 16);
+	cmd.req.arg[7] = (nic->min_tx_bw) | ((nic->max_tx_bw) << 16);
+	for (i = 8; i < 32; i++)
+		cmd.req.arg[i] = 0;
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev, "Failed to set nic info%d\n",
+			err);
+		err = -EIO;
+	}
+
+	qlcnic_free_mbx_args(&cmd);
+
+	return err;
+}
+
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,
+			     struct qlcnic_info *npar_info, u8 func_id)
+{
+	int err;
+	u32 temp;
+	u8 op = 0;
+	struct qlcnic_cmd_args cmd;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+	if (func_id != adapter->ahw->pci_func) {
+		temp = func_id << 16;
+		cmd.req.arg[1] = op | BIT_31 | temp;
+	} else {
+		cmd.req.arg[1] = adapter->ahw->pci_func << 16;
+	}
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err) {
+		dev_info(&adapter->pdev->dev,
+			 "Failed to get nic info %d\n", err);
+		goto out;
+	}
+
+	npar_info->op_type = cmd.rsp.arg[1];
+	npar_info->pci_func = cmd.rsp.arg[2] & 0xFFFF;
+	npar_info->op_mode = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;
+	npar_info->phys_port = cmd.rsp.arg[3] & 0xFFFF;
+	npar_info->switch_mode = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;
+	npar_info->capabilities = cmd.rsp.arg[4];
+	npar_info->max_mac_filters = cmd.rsp.arg[5] & 0xFF;
+	npar_info->max_mtu = (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;
+	npar_info->max_tx_ques = cmd.rsp.arg[6] & 0xFFFF;
+	npar_info->max_rx_ques = (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;
+	npar_info->min_tx_bw = cmd.rsp.arg[7] & 0xFFFF;
+	npar_info->max_tx_bw = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;
+	if (cmd.rsp.arg[8] & 0x1)
+		npar_info->max_bw_reg_offset = (cmd.rsp.arg[8] & 0x7FFE) >> 1;
+	if (cmd.rsp.arg[8] & 0x10000) {
+		temp = (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;
+		npar_info->max_linkspeed_reg_offset = temp;
+	}
+
+out:
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
+			     struct qlcnic_pci_info *pci_info)
+{
+	int i, err = 0, j = 0;
+	u32 temp;
+	struct qlcnic_cmd_args cmd;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	adapter->ahw->act_pci_func = 0;
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		pci_info->func_count = cmd.rsp.arg[1] & 0xFF;
+		dev_info(&adapter->pdev->dev,
+			 "%s: total functions = %d\n",
+			 __func__, pci_info->func_count);
+		for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) {
+			pci_info->id = cmd.rsp.arg[i] & 0xFFFF;
+			pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+			i++;
+			pci_info->type = cmd.rsp.arg[i] & 0xFFFF;
+			if (pci_info->type == QLCNIC_TYPE_NIC)
+				adapter->ahw->act_pci_func++;
+			temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+			pci_info->default_port = temp;
+			i++;
+			pci_info->tx_min_bw = cmd.rsp.arg[i] & 0xFFFF;
+			temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+			pci_info->tx_max_bw = temp;
+			i = i + 2;
+			memcpy(pci_info->mac, &cmd.rsp.arg[i], ETH_ALEN - 2);
+			i++;
+			memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);
+			i = i + 3;
+
+			dev_info(&adapter->pdev->dev, "%s:\n"
+				 "\tid = %d active = %d type = %d\n"
+				 "\tport = %d min bw = %d max bw = %d\n"
+				 "\tmac_addr =  %pM\n", __func__,
+				 pci_info->id, pci_info->active, pci_info->type,
+				 pci_info->default_port, pci_info->tx_min_bw,
+				 pci_info->tx_max_bw, pci_info->mac);
+		}
+	} else {
+		dev_err(&adapter->pdev->dev, "Failed to get PCI Info%d\n",
+			err);
+		err = -EIO;
+	}
+
+	qlcnic_free_mbx_args(&cmd);
+
+	return err;
+}
+
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
+{
+	int i, index, err;
+	bool type;
+	u8 max_ints;
+	u32 val, temp;
+	struct qlcnic_cmd_args cmd;
+
+	max_ints = adapter->ahw->num_msix - 1;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
+	cmd.req.arg[1] = max_ints;
+	for (i = 0, index = 2; i < max_ints; i++) {
+		type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
+		val = type | (adapter->ahw->intr_tbl[i].type << 4);
+		if (adapter->ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
+			val |= (adapter->ahw->intr_tbl[i].id << 16);
+		cmd.req.arg[index++] = val;
+	}
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to configure interrupts 0x%x\n", err);
+		goto out;
+	}
+
+	max_ints = cmd.rsp.arg[1];
+	for (i = 0, index = 2; i < max_ints; i++, index += 2) {
+		val = cmd.rsp.arg[index];
+		if (LSB(val)) {
+			dev_info(&adapter->pdev->dev,
+				 "Can't configure interrupt %d\n",
+				 adapter->ahw->intr_tbl[i].id);
+			continue;
+		}
+		if (op_type) {
+			adapter->ahw->intr_tbl[i].id = MSW(val);
+			adapter->ahw->intr_tbl[i].enabled = 1;
+			temp = cmd.rsp.arg[index + 1];
+			adapter->ahw->intr_tbl[i].src = temp;
+		} else {
+			adapter->ahw->intr_tbl[i].id = i;
+			adapter->ahw->intr_tbl[i].enabled = 0;
+			adapter->ahw->intr_tbl[i].src = 0;
+		}
+	}
+out:
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *adapter)
+{
+	int id, timeout = 0;
+	u32 status = 0;
+
+	while (status == 0) {
+		status = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
+		if (status)
+			break;
+
+		if (++timeout >= QLC_83XX_FLASH_LOCK_TIMEOUT) {
+			id = QLC_SHARED_REG_RD32(adapter,
+						 QLCNIC_FLASH_LOCK_OWNER);
+			dev_err(&adapter->pdev->dev,
+				"%s: failed, lock held by %d\n", __func__, id);
+			return -EIO;
+		}
+		usleep_range(1000, 2000);
+	}
+
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->portnum);
+	return 0;
+}
+
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *adapter)
+{
+	QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, 0xFF);
+}
+
+int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
+				      u32 flash_addr, u8 *p_data,
+				      int count)
+{
+	int i, ret;
+	u32 word, range, flash_offset, addr = flash_addr;
+	ulong indirect_add, direct_window;
+
+	flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
+	if (addr & 0x3) {
+		dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+		return -EIO;
+	}
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW,
+				     (addr));
+
+	range = flash_offset + (count * sizeof(u32));
+	/* Check if data is spread across multiple sectors */
+	if (range > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+
+		/* Multi sector read */
+		for (i = 0; i < count; i++) {
+			indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
+			ret = qlcnic_83xx_rd_reg_indirect(adapter,
+							  indirect_add);
+			if (ret == -EIO)
+				return -EIO;
+
+			word = ret;
+			*(u32 *)p_data  = word;
+			p_data = p_data + 4;
+			addr = addr + 4;
+			flash_offset = flash_offset + 4;
+
+			if (flash_offset > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+				direct_window = QLC_83XX_FLASH_DIRECT_WINDOW;
+				/* This write is needed once for each sector */
+				qlcnic_83xx_wrt_reg_indirect(adapter,
+							     direct_window,
+							     (addr));
+				flash_offset = 0;
+			}
+		}
+	} else {
+		/* Single sector read */
+		for (i = 0; i < count; i++) {
+			indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
+			ret = qlcnic_83xx_rd_reg_indirect(adapter,
+							  indirect_add);
+			if (ret == -EIO)
+				return -EIO;
+
+			word = ret;
+			*(u32 *)p_data  = word;
+			p_data = p_data + 4;
+			addr = addr + 4;
+		}
+	}
+
+	return 0;
+}
+
+static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+	u32 status;
+	int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+
+	do {
+		status = qlcnic_83xx_rd_reg_indirect(adapter,
+						     QLC_83XX_FLASH_STATUS);
+		if ((status & QLC_83XX_FLASH_STATUS_READY) ==
+		    QLC_83XX_FLASH_STATUS_READY)
+			break;
+
+		msleep(QLC_83XX_FLASH_STATUS_REG_POLL_DELAY);
+	} while (--retries);
+
+	if (!retries)
+		return -EIO;
+
+	return 0;
+}
+
+static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+	int ret;
+	u32 cmd;
+	cmd = adapter->ahw->fdt.write_statusreg_cmd;
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG | cmd));
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+				     adapter->ahw->fdt.write_enable_bits);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
+static int qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+	int ret;
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |
+				     adapter->ahw->fdt.write_statusreg_cmd));
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+				     adapter->ahw->fdt.write_disable_bits);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
+{
+	int ret, mfg_id;
+
+	if (qlcnic_83xx_lock_flash(adapter))
+		return -EIO;
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_READ_CTRL);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret) {
+		qlcnic_83xx_unlock_flash(adapter);
+		return -EIO;
+	}
+
+	mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
+	if (mfg_id == -EIO)
+		return -EIO;
+
+	adapter->flash_mfg_id = (mfg_id & 0xFF);
+	qlcnic_83xx_unlock_flash(adapter);
+
+	return 0;
+}
+
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)
+{
+	int count, fdt_size, ret = 0;
+
+	fdt_size = sizeof(struct qlcnic_fdt);
+	count = fdt_size / sizeof(u32);
+
+	if (qlcnic_83xx_lock_flash(adapter))
+		return -EIO;
+
+	memset(&adapter->ahw->fdt, 0, fdt_size);
+	ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION,
+						(u8 *)&adapter->ahw->fdt,
+						count);
+
+	qlcnic_83xx_unlock_flash(adapter);
+	return ret;
+}
+
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
+				   u32 sector_start_addr)
+{
+	u32 reversed_addr, addr1, addr2, cmd;
+	int ret = -EIO;
+
+	if (qlcnic_83xx_lock_flash(adapter) != 0)
+		return -EIO;
+
+	if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+		ret = qlcnic_83xx_enable_flash_write_op(adapter);
+		if (ret) {
+			qlcnic_83xx_unlock_flash(adapter);
+			dev_err(&adapter->pdev->dev,
+				"%s failed at %d\n",
+				__func__, __LINE__);
+			return ret;
+		}
+	}
+
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret) {
+		qlcnic_83xx_unlock_flash(adapter);
+		dev_err(&adapter->pdev->dev,
+			"%s: failed at %d\n", __func__, __LINE__);
+		return -EIO;
+	}
+
+	addr1 = (sector_start_addr & 0xFF) << 16;
+	addr2 = (sector_start_addr & 0xFF0000) >> 16;
+	reversed_addr = addr1 | addr2;
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+				     reversed_addr);
+	cmd = QLC_83XX_FLASH_FDT_ERASE_DEF_SIG | adapter->ahw->fdt.erase_cmd;
+	if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id)
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, cmd);
+	else
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+					     QLC_83XX_FLASH_OEM_ERASE_SIG);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret) {
+		qlcnic_83xx_unlock_flash(adapter);
+		dev_err(&adapter->pdev->dev,
+			"%s: failed at %d\n", __func__, __LINE__);
+		return -EIO;
+	}
+
+	if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+		ret = qlcnic_83xx_disable_flash_write_op(adapter);
+		if (ret) {
+			qlcnic_83xx_unlock_flash(adapter);
+			dev_err(&adapter->pdev->dev,
+				"%s: failed at %d\n", __func__, __LINE__);
+			return ret;
+		}
+	}
+
+	qlcnic_83xx_unlock_flash(adapter);
+
+	return 0;
+}
+
+int qlcnic_83xx_flash_write32(struct qlcnic_adapter *adapter, u32 addr,
+			      u32 *p_data)
+{
+	int ret = -EIO;
+	u32 addr1 = 0x00800000 | (addr >> 2);
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, addr1);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret) {
+		dev_err(&adapter->pdev->dev,
+			"%s: failed at %d\n", __func__, __LINE__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
+				 u32 *p_data, int count)
+{
+	u32 temp;
+	int ret = -EIO;
+
+	if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) ||
+	    (count > QLC_83XX_FLASH_BULK_WRITE_MAX)) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Invalid word count\n", __func__);
+		return -EIO;
+	}
+
+	temp = qlcnic_83xx_rd_reg_indirect(adapter,
+					   QLC_83XX_FLASH_SPI_CONTROL);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,
+				     (temp | QLC_83XX_FLASH_SPI_CTRL));
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     QLC_83XX_FLASH_ADDR_TEMP_VAL);
+
+	/* First DWORD write */
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_FIRST_MS_PATTERN);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret) {
+		dev_err(&adapter->pdev->dev,
+			"%s: failed at %d\n", __func__, __LINE__);
+		return -EIO;
+	}
+
+	count--;
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL);
+	/* Second to N-1 DWORD writes */
+	while (count != 1) {
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+					     *p_data++);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+					     QLC_83XX_FLASH_SECOND_MS_PATTERN);
+		ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+		if (ret) {
+			dev_err(&adapter->pdev->dev,
+				"%s: failed at %d\n", __func__, __LINE__);
+			return -EIO;
+		}
+		count--;
+	}
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     QLC_83XX_FLASH_ADDR_TEMP_VAL |
+				     (addr >> 2));
+	/* Last DWORD write */
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_LAST_MS_PATTERN);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret) {
+		dev_err(&adapter->pdev->dev,
+			"%s: failed at %d\n", __func__, __LINE__);
+		return -EIO;
+	}
+
+	ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS);
+	if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {
+		dev_err(&adapter->pdev->dev, "%s: failed at %d\n",
+			__func__, __LINE__);
+		/* Operation failed, clear error bit */
+		temp = qlcnic_83xx_rd_reg_indirect(adapter,
+						   QLC_83XX_FLASH_SPI_CONTROL);
+		qlcnic_83xx_wrt_reg_indirect(adapter,
+					     QLC_83XX_FLASH_SPI_CONTROL,
+					     (temp | QLC_83XX_FLASH_SPI_CTRL));
+	}
+
+	return 0;
+}
+
+static void qlcnic_83xx_recover_driver_lock(struct qlcnic_adapter *adapter)
+{
+	u32 val, id;
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+
+	/* Check if recovery need to be performed by the calling function */
+	if ((val & QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK) == 0) {
+		val = val & ~0x3F;
+		val = val | ((adapter->portnum << 2) |
+			     QLC_83XX_NEED_DRV_LOCK_RECOVERY);
+		QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+		dev_info(&adapter->pdev->dev,
+			 "%s: lock recovery initiated\n", __func__);
+		msleep(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
+		val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+		id = ((val >> 2) & 0xF);
+		if (id == adapter->portnum) {
+			val = val & ~QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK;
+			val = val | QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS;
+			QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+			/* Force release the lock */
+			QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+			/* Clear recovery bits */
+			val = val & ~0x3F;
+			QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+			dev_info(&adapter->pdev->dev,
+				 "%s: lock recovery completed\n", __func__);
+		} else {
+			dev_info(&adapter->pdev->dev,
+				 "%s: func %d to resume lock recovery process\n",
+				 __func__, id);
+		}
+	} else {
+		dev_info(&adapter->pdev->dev,
+			 "%s: lock recovery initiated by other functions\n",
+			 __func__);
+	}
+}
+
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *adapter)
+{
+	u32 lock_alive_counter, val, id, i = 0, status = 0, temp = 0;
+	int max_attempt = 0;
+
+	while (status == 0) {
+		status = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK);
+		if (status)
+			break;
+
+		msleep(QLC_83XX_DRV_LOCK_WAIT_DELAY);
+		i++;
+
+		if (i == 1)
+			temp = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+
+		if (i == QLC_83XX_DRV_LOCK_WAIT_COUNTER) {
+			val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+			if (val == temp) {
+				id = val & 0xFF;
+				dev_info(&adapter->pdev->dev,
+					 "%s: lock to be recovered from %d\n",
+					 __func__, id);
+				qlcnic_83xx_recover_driver_lock(adapter);
+				i = 0;
+				max_attempt++;
+			} else {
+				dev_err(&adapter->pdev->dev,
+					"%s: failed to get lock\n", __func__);
+				return -EIO;
+			}
+		}
+
+		/* Force exit from while loop after few attempts */
+		if (max_attempt == QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT) {
+			dev_err(&adapter->pdev->dev,
+				"%s: failed to get lock\n", __func__);
+			return -EIO;
+		}
+	}
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+	lock_alive_counter = val >> 8;
+	lock_alive_counter++;
+	val = lock_alive_counter << 8 | adapter->portnum;
+	QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+
+	return 0;
+}
+
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *adapter)
+{
+	u32 val, lock_alive_counter, id;
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+	id = val & 0xFF;
+	lock_alive_counter = val >> 8;
+
+	if (id != adapter->portnum)
+		dev_err(&adapter->pdev->dev,
+			"%s:Warning func %d is unlocking lock owned by %d\n",
+			__func__, adapter->portnum, id);
+
+	val = (lock_alive_counter << 8) | 0xFF;
+	QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+	QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+}
+
+int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
+				u32 *data, u32 count)
+{
+	int i, j, ret = 0;
+	u32 temp;
+
+	/* Check alignment */
+	if (addr & 0xF)
+		return -EIO;
+
+	mutex_lock(&adapter->ahw->mem_lock);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_HI, 0);
+
+	for (i = 0; i < count; i++, addr += 16) {
+		if (!((ADDR_IN_RANGE(addr, QLCNIC_ADDR_QDR_NET,
+				     QLCNIC_ADDR_QDR_NET_MAX)) ||
+		      (ADDR_IN_RANGE(addr, QLCNIC_ADDR_DDR_NET,
+				     QLCNIC_ADDR_DDR_NET_MAX)))) {
+			mutex_unlock(&adapter->ahw->mem_lock);
+			return -EIO;
+		}
+
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_LO, addr);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_LO,
+					     *data++);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_HI,
+					     *data++);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_ULO,
+					     *data++);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_UHI,
+					     *data++);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+					     QLCNIC_TA_WRITE_ENABLE);
+		qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+					     QLCNIC_TA_WRITE_START);
+
+		for (j = 0; j < MAX_CTL_CHECK; j++) {
+			temp = qlcnic_83xx_rd_reg_indirect(adapter,
+							   QLCNIC_MS_CTRL);
+			if ((temp & TA_CTL_BUSY) == 0)
+				break;
+		}
+
+		/* Status check failure */
+		if (j >= MAX_CTL_CHECK) {
+			printk_ratelimited(KERN_WARNING
+					   "MS memory write failed\n");
+			mutex_unlock(&adapter->ahw->mem_lock);
+			return -EIO;
+		}
+	}
+
+	mutex_unlock(&adapter->ahw->mem_lock);
+
+	return ret;
+}
+
+int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
+			     u8 *p_data, int count)
+{
+	int i, ret;
+	u32 word, addr = flash_addr;
+	ulong  indirect_addr;
+
+	if (qlcnic_83xx_lock_flash(adapter) != 0)
+		return -EIO;
+
+	if (addr & 0x3) {
+		dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+		qlcnic_83xx_unlock_flash(adapter);
+		return -EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (qlcnic_83xx_wrt_reg_indirect(adapter,
+						 QLC_83XX_FLASH_DIRECT_WINDOW,
+						 (addr))) {
+			qlcnic_83xx_unlock_flash(adapter);
+			return -EIO;
+		}
+
+		indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
+		ret = qlcnic_83xx_rd_reg_indirect(adapter,
+						  indirect_addr);
+		if (ret == -EIO)
+			return -EIO;
+		word = ret;
+		*(u32 *)p_data  = word;
+		p_data = p_data + 4;
+		addr = addr + 4;
+	}
+
+	qlcnic_83xx_unlock_flash(adapter);
+
+	return 0;
+}
+
+int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
+{
+	int err;
+	u32 config = 0, state;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func));
+	if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)) {
+		dev_info(&adapter->pdev->dev, "link state down\n");
+		return config;
+	}
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err) {
+		dev_info(&adapter->pdev->dev,
+			 "Get Link Status Command failed: 0x%x\n", err);
+		goto out;
+	} else {
+		config = cmd.rsp.arg[1];
+		switch (QLC_83XX_CURRENT_LINK_SPEED(config)) {
+		case QLC_83XX_10M_LINK:
+			ahw->link_speed = SPEED_10;
+			break;
+		case QLC_83XX_100M_LINK:
+			ahw->link_speed = SPEED_100;
+			break;
+		case QLC_83XX_1G_LINK:
+			ahw->link_speed = SPEED_1000;
+			break;
+		case QLC_83XX_10G_LINK:
+			ahw->link_speed = SPEED_10000;
+			break;
+		default:
+			ahw->link_speed = 0;
+			break;
+		}
+		config = cmd.rsp.arg[3];
+		if (config & 1)
+			err = 1;
+	}
+out:
+	qlcnic_free_mbx_args(&cmd);
+	return config;
+}
+
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
+{
+	u32 config = 0;
+	int status = 0;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	/* Get port configuration info */
+	status = qlcnic_83xx_get_port_info(adapter);
+	/* Get Link Status related info */
+	config = qlcnic_83xx_test_link(adapter);
+	ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
+	/* hard code until there is a way to get it from flash */
+	ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
+	return status;
+}
+
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
+			     struct ethtool_cmd *ecmd)
+{
+	int status = 0;
+	u32 config = adapter->ahw->port_config;
+
+	if (ecmd->autoneg)
+		adapter->ahw->port_config |= BIT_15;
+
+	switch (ethtool_cmd_speed(ecmd)) {
+	case SPEED_10:
+		adapter->ahw->port_config |= BIT_8;
+		break;
+	case SPEED_100:
+		adapter->ahw->port_config |= BIT_9;
+		break;
+	case SPEED_1000:
+		adapter->ahw->port_config |= BIT_10;
+		break;
+	case SPEED_10000:
+		adapter->ahw->port_config |= BIT_11;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	status = qlcnic_83xx_set_port_config(adapter);
+	if (status) {
+		dev_info(&adapter->pdev->dev,
+			 "Faild to Set Link Speed and autoneg.\n");
+		adapter->ahw->port_config = config;
+	}
+	return status;
+}
+
+static inline u64 *qlcnic_83xx_copy_stats(struct qlcnic_cmd_args *cmd,
+					  u64 *data, int index)
+{
+	u32 low, hi;
+	u64 val;
+
+	low = cmd->rsp.arg[index];
+	hi = cmd->rsp.arg[index + 1];
+	val = (((u64) low) | (((u64) hi) << 32));
+	*data++ = val;
+	return data;
+}
+
+static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
+				   struct qlcnic_cmd_args *cmd, u64 *data,
+				   int type, int *ret)
+{
+	int err, k, total_regs;
+
+	*ret = 0;
+	err = qlcnic_issue_cmd(adapter, cmd);
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_info(&adapter->pdev->dev,
+			 "Error in get statistics mailbox command\n");
+		*ret = -EIO;
+		return data;
+	}
+	total_regs = cmd->rsp.num;
+	switch (type) {
+	case QLC_83XX_STAT_MAC:
+		/* fill in MAC tx counters */
+		for (k = 2; k < 28; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		/* skip 24 bytes of reserved area */
+		/* fill in MAC rx counters */
+		for (k += 6; k < 60; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		/* skip 24 bytes of reserved area */
+		/* fill in MAC rx frame stats */
+		for (k += 6; k < 80; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		break;
+	case QLC_83XX_STAT_RX:
+		for (k = 2; k < 8; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		/* skip 8 bytes of reserved data */
+		for (k += 2; k < 24; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		/* skip 8 bytes containing RE1FBQ error data */
+		for (k += 2; k < total_regs; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		break;
+	case QLC_83XX_STAT_TX:
+		for (k = 2; k < 10; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		/* skip 8 bytes of reserved data */
+		for (k += 2; k < total_regs; k += 2)
+			data = qlcnic_83xx_copy_stats(cmd, data, k);
+		break;
+	default:
+		dev_warn(&adapter->pdev->dev, "Unknown get statistics mode\n");
+		*ret = -EIO;
+	}
+	return data;
+}
+
+void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
+{
+	struct qlcnic_cmd_args cmd;
+	int ret = 0;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
+	/* Get Tx stats */
+	cmd.req.arg[1] = BIT_1 | (adapter->tx_ring->ctx_id << 16);
+	cmd.rsp.num = QLC_83XX_TX_STAT_REGS;
+	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+				      QLC_83XX_STAT_TX, &ret);
+	if (ret) {
+		dev_info(&adapter->pdev->dev, "Error getting MAC stats\n");
+		goto out;
+	}
+	/* Get MAC stats */
+	cmd.req.arg[1] = BIT_2 | (adapter->portnum << 16);
+	cmd.rsp.num = QLC_83XX_MAC_STAT_REGS;
+	memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+				      QLC_83XX_STAT_MAC, &ret);
+	if (ret) {
+		dev_info(&adapter->pdev->dev,
+			 "Error getting Rx stats\n");
+		goto out;
+	}
+	/* Get Rx stats */
+	cmd.req.arg[1] = adapter->recv_ctx->context_id << 16;
+	cmd.rsp.num = QLC_83XX_RX_STAT_REGS;
+	memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+	data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+				      QLC_83XX_STAT_RX, &ret);
+	if (ret)
+		dev_info(&adapter->pdev->dev,
+			 "Error getting Tx stats\n");
+out:
+	qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)
+{
+	u32 major, minor, sub;
+
+	major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+	minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+	sub = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+	if (adapter->fw_version != QLCNIC_VERSION_CODE(major, minor, sub)) {
+		dev_info(&adapter->pdev->dev, "%s: Reg test failed\n",
+			 __func__);
+		return 1;
+	}
+	return 0;
+}
+
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)
+{
+	return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) *
+		sizeof(adapter->ahw->ext_reg_tbl)) +
+		(ARRAY_SIZE(qlcnic_83xx_reg_tbl) +
+		sizeof(adapter->ahw->reg_tbl));
+}
+
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
+{
+	int i, j = 0;
+
+	for (i = QLCNIC_DEV_INFO_SIZE + 1;
+	     j < ARRAY_SIZE(qlcnic_83xx_reg_tbl); i++, j++)
+		regs_buff[i] = QLC_SHARED_REG_RD32(adapter, j);
+
+	for (j = 0; j < ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl); j++)
+		regs_buff[i++] = QLCRDX(adapter->ahw, j);
+	return i;
+}
+
+int qlcnic_83xx_interrupt_test(struct net_device *netdev)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_cmd_args cmd;
+	u32 data;
+	u16 intrpt_id, id;
+	u8 val;
+	int ret, max_sds_rings = adapter->max_sds_rings;
+
+	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		return -EIO;
+
+	ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
+	if (ret)
+		goto fail_diag_irq;
+
+	ahw->diag_cnt = 0;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		intrpt_id = ahw->intr_tbl[0].id;
+	else
+		intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+
+	cmd.req.arg[1] = 1;
+	cmd.req.arg[2] = intrpt_id;
+	cmd.req.arg[3] = BIT_0;
+
+	ret = qlcnic_issue_cmd(adapter, &cmd);
+	data = cmd.rsp.arg[2];
+	id = LSW(data);
+	val = LSB(MSW(data));
+	if (id != intrpt_id)
+		dev_info(&adapter->pdev->dev,
+			 "Interrupt generated: 0x%x, requested:0x%x\n",
+			 id, intrpt_id);
+	if (val)
+		dev_err(&adapter->pdev->dev,
+			 "Interrupt test error: 0x%x\n", val);
+	if (ret)
+		goto done;
+
+	msleep(20);
+	ret = !ahw->diag_cnt;
+
+done:
+	qlcnic_free_mbx_args(&cmd);
+	qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_irq:
+	adapter->max_sds_rings = max_sds_rings;
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	return ret;
+}
+
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,
+				struct ethtool_pauseparam *pause)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int status = 0;
+	u32 config;
+
+	status = qlcnic_83xx_get_port_config(adapter);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Get Pause Config failed\n", __func__);
+		return;
+	}
+	config = ahw->port_config;
+	if (config & QLC_83XX_CFG_STD_PAUSE) {
+		if (config & QLC_83XX_CFG_STD_TX_PAUSE)
+			pause->tx_pause = 1;
+		if (config & QLC_83XX_CFG_STD_RX_PAUSE)
+			pause->rx_pause = 1;
+	}
+
+	if (QLC_83XX_AUTONEG(config))
+		pause->autoneg = 1;
+}
+
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
+			       struct ethtool_pauseparam *pause)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int status = 0;
+	u32 config;
+
+	status = qlcnic_83xx_get_port_config(adapter);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Get Pause Config failed.\n", __func__);
+		return status;
+	}
+	config = ahw->port_config;
+
+	if (ahw->port_type == QLCNIC_GBE) {
+		if (pause->autoneg)
+			ahw->port_config |= QLC_83XX_ENABLE_AUTONEG;
+		if (!pause->autoneg)
+			ahw->port_config &= ~QLC_83XX_ENABLE_AUTONEG;
+	} else if ((ahw->port_type == QLCNIC_XGBE) && (pause->autoneg)) {
+		return -EOPNOTSUPP;
+	}
+
+	if (!(config & QLC_83XX_CFG_STD_PAUSE))
+		ahw->port_config |= QLC_83XX_CFG_STD_PAUSE;
+
+	if (pause->rx_pause && pause->tx_pause) {
+		ahw->port_config |= QLC_83XX_CFG_STD_TX_RX_PAUSE;
+	} else if (pause->rx_pause && !pause->tx_pause) {
+		ahw->port_config &= ~QLC_83XX_CFG_STD_TX_PAUSE;
+		ahw->port_config |= QLC_83XX_CFG_STD_RX_PAUSE;
+	} else if (pause->tx_pause && !pause->rx_pause) {
+		ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;
+		ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;
+	} else if (!pause->rx_pause && !pause->tx_pause) {
+		ahw->port_config &= ~QLC_83XX_CFG_STD_TX_RX_PAUSE;
+	}
+	status = qlcnic_83xx_set_port_config(adapter);
+	if (status) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Set Pause Config failed.\n", __func__);
+		ahw->port_config = config;
+	}
+	return status;
+}
+
+static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+	int ret;
+
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+				     QLC_83XX_FLASH_OEM_READ_SIG);
+	qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+				     QLC_83XX_FLASH_READ_CTRL);
+	ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+	if (ret)
+		return -EIO;
+
+	ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
+	return ret & 0xFF;
+}
+
+int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
+{
+	int status;
+
+	status = qlcnic_83xx_read_flash_status_reg(adapter);
+	if (status == -EIO) {
+		dev_info(&adapter->pdev->dev, "%s: EEPROM test failed.\n",
+			 __func__);
+		return 1;
+	}
+	return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
new file mode 100644
index 0000000..61f81f6
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -0,0 +1,438 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#ifndef __QLCNIC_83XX_HW_H
+#define __QLCNIC_83XX_HW_H
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include "qlcnic_hw.h"
+
+/* Directly mapped registers */
+#define QLC_83XX_CRB_WIN_BASE		0x3800
+#define QLC_83XX_CRB_WIN_FUNC(f)	(QLC_83XX_CRB_WIN_BASE+((f)*4))
+#define QLC_83XX_SEM_LOCK_BASE		0x3840
+#define QLC_83XX_SEM_UNLOCK_BASE	0x3844
+#define QLC_83XX_SEM_LOCK_FUNC(f)	(QLC_83XX_SEM_LOCK_BASE+((f)*8))
+#define QLC_83XX_SEM_UNLOCK_FUNC(f)	(QLC_83XX_SEM_UNLOCK_BASE+((f)*8))
+#define QLC_83XX_LINK_STATE(f)		(0x3698+((f) > 7 ? 4 : 0))
+#define QLC_83XX_LINK_SPEED(f)		(0x36E0+(((f) >> 2) * 4))
+#define QLC_83XX_LINK_SPEED_FACTOR	10
+#define QLC_83xx_FUNC_VAL(v, f)	((v) & (1 << (f * 4)))
+#define QLC_83XX_INTX_PTR		0x38C0
+#define QLC_83XX_INTX_TRGR		0x38C4
+#define QLC_83XX_INTX_MASK		0x38C8
+
+#define QLC_83XX_DRV_LOCK_WAIT_COUNTER			100
+#define QLC_83XX_DRV_LOCK_WAIT_DELAY			20
+#define QLC_83XX_NEED_DRV_LOCK_RECOVERY		1
+#define QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS		2
+#define QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT		3
+#define QLC_83XX_DRV_LOCK_RECOVERY_DELAY		200
+#define QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK		0x3
+
+#define QLC_83XX_NO_NIC_RESOURCE	0x5
+#define QLC_83XX_MAC_PRESENT		0xC
+#define QLC_83XX_MAC_ABSENT		0xD
+
+
+#define QLC_83XX_FLASH_SECTOR_SIZE		(64 * 1024)
+
+/* PEG status definitions */
+#define QLC_83XX_CMDPEG_COMPLETE		0xff01
+#define QLC_83XX_VALID_INTX_BIT30(val)		((val) & BIT_30)
+#define QLC_83XX_VALID_INTX_BIT31(val)		((val) & BIT_31)
+#define QLC_83XX_INTX_FUNC(val)		((val) & 0xFF)
+#define QLC_83XX_LEGACY_INTX_MAX_RETRY		100
+#define QLC_83XX_LEGACY_INTX_DELAY		4
+#define QLC_83XX_REG_DESC			1
+#define QLC_83XX_LRO_DESC			2
+#define QLC_83XX_CTRL_DESC			3
+#define QLC_83XX_FW_CAPABILITY_TSO		BIT_6
+#define QLC_83XX_FW_CAP_LRO_MSS		BIT_17
+#define QLC_83XX_HOST_RDS_MODE_UNIQUE		0
+#define QLC_83XX_HOST_SDS_MBX_IDX		8
+
+#define QLCNIC_HOST_RDS_MBX_IDX			88
+#define QLCNIC_MAX_RING_SETS			8
+
+/* Pause control registers */
+#define QLC_83XX_SRE_SHIM_REG		0x0D200284
+#define QLC_83XX_PORT0_THRESHOLD	0x0B2003A4
+#define QLC_83XX_PORT1_THRESHOLD	0x0B2013A4
+#define QLC_83XX_PORT0_TC_MC_REG	0x0B200388
+#define QLC_83XX_PORT1_TC_MC_REG	0x0B201388
+#define QLC_83XX_PORT0_TC_STATS		0x0B20039C
+#define QLC_83XX_PORT1_TC_STATS		0x0B20139C
+#define QLC_83XX_PORT2_IFB_THRESHOLD	0x0B200704
+#define QLC_83XX_PORT3_IFB_THRESHOLD	0x0B201704
+
+/* Peg PC status registers */
+#define QLC_83XX_CRB_PEG_NET_0		0x3400003c
+#define QLC_83XX_CRB_PEG_NET_1		0x3410003c
+#define QLC_83XX_CRB_PEG_NET_2		0x3420003c
+#define QLC_83XX_CRB_PEG_NET_3		0x3430003c
+#define QLC_83XX_CRB_PEG_NET_4		0x34b0003c
+
+/* Firmware image definitions */
+#define QLC_83XX_BOOTLOADER_FLASH_ADDR	0x10000
+#define QLC_83XX_FW_FILE_NAME		"83xx_fw.bin"
+#define QLC_83XX_BOOT_FROM_FLASH	0
+#define QLC_83XX_BOOT_FROM_FILE		0x12345678
+
+#define QLC_83XX_MAX_RESET_SEQ_ENTRIES	16
+
+struct qlcnic_intrpt_config {
+	u8	type;
+	u8	enabled;
+	u16	id;
+	u32	src;
+};
+
+struct qlcnic_macvlan_mbx {
+	u8	mac[ETH_ALEN];
+	u16	vlan;
+};
+
+struct qlc_83xx_fw_info {
+	const struct firmware	*fw;
+	u16	major_fw_version;
+	u8	minor_fw_version;
+	u8	sub_fw_version;
+	u8	fw_build_num;
+	u8	load_from_file;
+};
+
+struct qlc_83xx_reset {
+	struct qlc_83xx_reset_hdr *hdr;
+	int	seq_index;
+	int	seq_error;
+	int	array_index;
+	u32	array[QLC_83XX_MAX_RESET_SEQ_ENTRIES];
+	u8	*buff;
+	u8	*stop_offset;
+	u8	*start_offset;
+	u8	*init_offset;
+	u8	seq_end;
+	u8	template_end;
+};
+
+#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY		0x1
+#define QLC_83XX_IDC_GRACEFULL_RESET			0x2
+#define QLC_83XX_IDC_TIMESTAMP				0
+#define QLC_83XX_IDC_DURATION				1
+#define QLC_83XX_IDC_INIT_TIMEOUT_SECS			30
+#define QLC_83XX_IDC_RESET_ACK_TIMEOUT_SECS		10
+#define QLC_83XX_IDC_RESET_TIMEOUT_SECS		10
+#define QLC_83XX_IDC_QUIESCE_ACK_TIMEOUT_SECS		20
+#define QLC_83XX_IDC_FW_POLL_DELAY			(1 * HZ)
+#define QLC_83XX_IDC_FW_FAIL_THRESH			2
+#define QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO	8
+#define QLC_83XX_IDC_MAX_CNA_FUNCTIONS			16
+#define QLC_83XX_IDC_MAJOR_VERSION			1
+#define QLC_83XX_IDC_MINOR_VERSION			0
+#define QLC_83XX_IDC_FLASH_PARAM_ADDR			0x3e8020
+
+struct qlcnic_adapter;
+struct qlc_83xx_idc {
+	int (*state_entry) (struct qlcnic_adapter *);
+	u64		sec_counter;
+	u64		delay;
+	unsigned long	status;
+	int		err_code;
+	int		collect_dump;
+	u8		curr_state;
+	u8		prev_state;
+	u8		vnic_state;
+	u8		vnic_wait_limit;
+	u8		quiesce_req;
+	char		**name;
+};
+
+#define QLCNIC_MBX_RSP(reg)		LSW(reg)
+#define QLCNIC_MBX_NUM_REGS(reg)	(MSW(reg) & 0x1FF)
+#define QLCNIC_MBX_STATUS(reg)		(((reg) >> 25) & 0x7F)
+#define QLCNIC_MBX_HOST(ahw, i)	((ahw)->pci_base0 + ((i) * 4))
+#define QLCNIC_MBX_FW(ahw, i)		((ahw)->pci_base0 + 0x800 + ((i) * 4))
+
+/* Mailbox process AEN count */
+#define QLC_83XX_IDC_COMP_AEN			3
+#define QLC_83XX_MBX_AEN_CNT			5
+#define QLC_83XX_MODULE_LOADED			1
+#define QLC_83XX_MBX_READY			2
+#define QLC_83XX_MBX_AEN_ACK			3
+#define QLC_83XX_SFP_PRESENT(data)		((data) & 3)
+#define QLC_83XX_SFP_ERR(data)			(((data) >> 2) & 3)
+#define QLC_83XX_SFP_MODULE_TYPE(data)		(((data) >> 4) & 0x1F)
+#define QLC_83XX_SFP_CU_LENGTH(data)		(LSB((data) >> 16))
+#define QLC_83XX_SFP_TX_FAULT(data)		((data) & BIT_10)
+#define QLC_83XX_SFP_10G_CAPABLE(data)		((data) & BIT_11)
+#define QLC_83XX_LINK_STATS(data)		((data) & BIT_0)
+#define QLC_83XX_CURRENT_LINK_SPEED(data)	(((data) >> 3) & 7)
+#define QLC_83XX_LINK_PAUSE(data)		(((data) >> 6) & 3)
+#define QLC_83XX_LINK_LB(data)			(((data) >> 8) & 7)
+#define QLC_83XX_LINK_FEC(data)		((data) & BIT_12)
+#define QLC_83XX_LINK_EEE(data)		((data) & BIT_13)
+#define QLC_83XX_DCBX(data)			(((data) >> 28) & 7)
+#define QLC_83XX_AUTONEG(data)			((data) & BIT_15)
+#define QLC_83XX_CFG_STD_PAUSE			(1 << 5)
+#define QLC_83XX_CFG_STD_TX_PAUSE		(1 << 20)
+#define QLC_83XX_CFG_STD_RX_PAUSE		(2 << 20)
+#define QLC_83XX_CFG_STD_TX_RX_PAUSE		(3 << 20)
+#define QLC_83XX_ENABLE_AUTONEG		(1 << 15)
+#define QLC_83XX_CFG_LOOPBACK_HSS		(2 << 1)
+#define QLC_83XX_CFG_LOOPBACK_PHY		(3 << 1)
+#define QLC_83XX_CFG_LOOPBACK_EXT		(4 << 1)
+
+/* LED configuration settings */
+#define QLC_83XX_ENABLE_BEACON		0xe
+#define QLC_83XX_LED_RATE		0xff
+#define QLC_83XX_LED_ACT		(1 << 10)
+#define QLC_83XX_LED_MOD		(0 << 13)
+#define QLC_83XX_LED_CONFIG	(QLC_83XX_LED_RATE | QLC_83XX_LED_ACT |	\
+				 QLC_83XX_LED_MOD)
+
+#define QLC_83XX_10M_LINK	1
+#define QLC_83XX_100M_LINK	2
+#define QLC_83XX_1G_LINK	3
+#define QLC_83XX_10G_LINK	4
+#define QLC_83XX_STAT_TX	3
+#define QLC_83XX_STAT_RX	2
+#define QLC_83XX_STAT_MAC	1
+#define QLC_83XX_TX_STAT_REGS	14
+#define QLC_83XX_RX_STAT_REGS	40
+#define QLC_83XX_MAC_STAT_REGS	80
+
+#define QLC_83XX_GET_FUNC_PRIVILEGE(VAL, FN)	(0x3 & ((VAL) >> (FN * 2)))
+#define QLC_83XX_SET_FUNC_OPMODE(VAL, FN)	((VAL) << (FN * 2))
+#define QLC_83XX_DEFAULT_OPMODE			0x55555555
+#define QLC_83XX_PRIVLEGED_FUNC			0x1
+#define QLC_83XX_VIRTUAL_FUNC				0x2
+
+#define QLC_83XX_LB_MAX_FILTERS			2048
+#define QLC_83XX_LB_BUCKET_SIZE			256
+#define QLC_83XX_MINIMUM_VECTOR			3
+
+#define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val)	(val & 0x80000000)
+#define QLC_83XX_GET_LRO_CAPABILITY(val)		(val & 0x20)
+#define QLC_83XX_GET_LSO_CAPABILITY(val)		(val & 0x40)
+#define QLC_83XX_GET_LSO_CAPABILITY(val)		(val & 0x40)
+#define QLC_83XX_GET_HW_LRO_CAPABILITY(val)		(val & 0x400)
+#define QLC_83XX_GET_VLAN_ALIGN_CAPABILITY(val)	(val & 0x4000)
+#define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val)	(val & 0x20000)
+#define QLC_83XX_VIRTUAL_NIC_MODE			0xFF
+#define QLC_83XX_DEFAULT_MODE				0x0
+#define QLCNIC_BRDTYPE_83XX_10G			0x0083
+
+#define QLC_83XX_FLASH_SPI_STATUS		0x2808E010
+#define QLC_83XX_FLASH_SPI_CONTROL		0x2808E014
+#define QLC_83XX_FLASH_STATUS			0x42100004
+#define QLC_83XX_FLASH_CONTROL			0x42110004
+#define QLC_83XX_FLASH_ADDR			0x42110008
+#define QLC_83XX_FLASH_WRDATA			0x4211000C
+#define QLC_83XX_FLASH_RDDATA			0x42110018
+#define QLC_83XX_FLASH_DIRECT_WINDOW		0x42110030
+#define QLC_83XX_FLASH_DIRECT_DATA(DATA)	(0x42150000 | (0x0000FFFF&DATA))
+#define QLC_83XX_FLASH_SECTOR_ERASE_CMD	0xdeadbeef
+#define QLC_83XX_FLASH_WRITE_CMD		0xdacdacda
+#define QLC_83XX_FLASH_BULK_WRITE_CMD		0xcadcadca
+#define QLC_83XX_FLASH_READ_RETRY_COUNT	5000
+#define QLC_83XX_FLASH_STATUS_READY		0x6
+#define QLC_83XX_FLASH_BULK_WRITE_MIN		2
+#define QLC_83XX_FLASH_BULK_WRITE_MAX		64
+#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY	1
+#define QLC_83XX_ERASE_MODE			1
+#define QLC_83XX_WRITE_MODE			2
+#define QLC_83XX_BULK_WRITE_MODE		3
+#define QLC_83XX_FLASH_FDT_WRITE_DEF_SIG	0xFD0100
+#define QLC_83XX_FLASH_FDT_ERASE_DEF_SIG	0xFD0300
+#define QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL	0xFD009F
+#define QLC_83XX_FLASH_OEM_ERASE_SIG		0xFD03D8
+#define QLC_83XX_FLASH_OEM_WRITE_SIG		0xFD0101
+#define QLC_83XX_FLASH_OEM_READ_SIG		0xFD0005
+#define QLC_83XX_FLASH_ADDR_TEMP_VAL		0x00800000
+#define QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL	0x00800001
+#define QLC_83XX_FLASH_WRDATA_DEF		0x0
+#define QLC_83XX_FLASH_READ_CTRL		0x3F
+#define QLC_83XX_FLASH_SPI_CTRL		0x4
+#define QLC_83XX_FLASH_FIRST_ERASE_MS_VAL	0x2
+#define QLC_83XX_FLASH_SECOND_ERASE_MS_VAL	0x5
+#define QLC_83XX_FLASH_LAST_ERASE_MS_VAL	0x3D
+#define QLC_83XX_FLASH_FIRST_MS_PATTERN	0x43
+#define QLC_83XX_FLASH_SECOND_MS_PATTERN	0x7F
+#define QLC_83XX_FLASH_LAST_MS_PATTERN		0x7D
+#define QLC_83xx_FLASH_MAX_WAIT_USEC		100
+#define QLC_83XX_FLASH_LOCK_TIMEOUT		10000
+
+/* Additional registers in 83xx */
+enum qlc_83xx_ext_regs {
+	QLCNIC_GLOBAL_RESET = 0,
+	QLCNIC_WILDCARD,
+	QLCNIC_INFORMANT,
+	QLCNIC_HOST_MBX_CTRL,
+	QLCNIC_FW_MBX_CTRL,
+	QLCNIC_BOOTLOADER_ADDR,
+	QLCNIC_BOOTLOADER_SIZE,
+	QLCNIC_FW_IMAGE_ADDR,
+	QLCNIC_MBX_INTR_ENBL,
+	QLCNIC_DEF_INT_MASK,
+	QLCNIC_DEF_INT_ID,
+	QLC_83XX_IDC_MAJ_VERSION,
+	QLC_83XX_IDC_DEV_STATE,
+	QLC_83XX_IDC_DRV_PRESENCE,
+	QLC_83XX_IDC_DRV_ACK,
+	QLC_83XX_IDC_CTRL,
+	QLC_83XX_IDC_DRV_AUDIT,
+	QLC_83XX_IDC_MIN_VERSION,
+	QLC_83XX_RECOVER_DRV_LOCK,
+	QLC_83XX_IDC_PF_0,
+	QLC_83XX_IDC_PF_1,
+	QLC_83XX_IDC_PF_2,
+	QLC_83XX_IDC_PF_3,
+	QLC_83XX_IDC_PF_4,
+	QLC_83XX_IDC_PF_5,
+	QLC_83XX_IDC_PF_6,
+	QLC_83XX_IDC_PF_7,
+	QLC_83XX_IDC_PF_8,
+	QLC_83XX_IDC_PF_9,
+	QLC_83XX_IDC_PF_10,
+	QLC_83XX_IDC_PF_11,
+	QLC_83XX_IDC_PF_12,
+	QLC_83XX_IDC_PF_13,
+	QLC_83XX_IDC_PF_14,
+	QLC_83XX_IDC_PF_15,
+	QLC_83XX_IDC_DEV_PARTITION_INFO_1,
+	QLC_83XX_IDC_DEV_PARTITION_INFO_2,
+	QLC_83XX_DRV_OP_MODE,
+	QLC_83XX_VNIC_STATE,
+	QLC_83XX_DRV_LOCK,
+	QLC_83XX_DRV_UNLOCK,
+	QLC_83XX_DRV_LOCK_ID,
+	QLC_83XX_ASIC_TEMP,
+};
+
+/* 83xx funcitons */
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *);
+int qlcnic_send_ctrl_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *, u32);
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong);
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, __le16);
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int);
+
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_83xx_napi_del(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);
+int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);
+int qlcnic_ind_rd(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *,
+			      struct qlcnic_host_tx_ring *, int);
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int);
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *);
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,
+			       struct qlcnic_cmd_args *);
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+			       struct qlcnic_adapter *, u32);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *);
+void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,
+			  struct qlcnic_info *);
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_handle_aen(int, void *);
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_intr(int, void *);
+irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *,
+			     struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *,
+			     struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
+			  const struct pci_device_id *);
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
+int qlcnic_83xx_get_port_config(struct qlcnic_adapter *);
+int qlcnic_83xx_set_port_config(struct qlcnic_adapter *);
+int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *);
+int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *);
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *);
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *);
+void qlcnic_83xx_idc_aen_work(struct work_struct *);
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *, __be32, int);
+
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *, u32, u32 *, int);
+int qlcnic_83xx_flash_write32(struct qlcnic_adapter *, u32, u32 *);
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *);
+int qlcnic_83xx_save_flash_status(struct qlcnic_adapter *);
+int qlcnic_83xx_restore_flash_status(struct qlcnic_adapter *, int);
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *);
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *);
+int qlcnic_83xx_flash_read32(struct qlcnic_adapter *, u32, u8 *, int);
+int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *,
+				      u32, u8 *, int);
+int qlcnic_83xx_init(struct qlcnic_adapter *);
+int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
+void qlcnic_83xx_idc_poll_dev_state(struct work_struct *);
+int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *);
+void qlcnic_83xx_idc_exit(struct qlcnic_adapter *);
+void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *);
+int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32);
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,
+				    struct qlcnic_info *, u8);
+int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
+
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);
+void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data);
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *,
+				struct ethtool_pauseparam *);
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *,
+			       struct ethtool_pauseparam *);
+int qlcnic_83xx_test_link(struct qlcnic_adapter *);
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *);
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
+int qlcnic_83xx_loopback_test(struct net_device *, u8);
+int qlcnic_83xx_interrupt_test(struct net_device *);
+int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
+#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
new file mode 100644
index 0000000..c53832b
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -0,0 +1,2054 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+/* Reset template definitions */
+#define QLC_83XX_RESTART_TEMPLATE_SIZE		0x2000
+#define QLC_83XX_RESET_TEMPLATE_ADDR		0x4F0000
+#define QLC_83XX_RESET_SEQ_VERSION		0x0101
+
+#define QLC_83XX_OPCODE_NOP			0x0000
+#define QLC_83XX_OPCODE_WRITE_LIST		0x0001
+#define QLC_83XX_OPCODE_READ_WRITE_LIST		0x0002
+#define QLC_83XX_OPCODE_POLL_LIST		0x0004
+#define QLC_83XX_OPCODE_POLL_WRITE_LIST		0x0008
+#define QLC_83XX_OPCODE_READ_MODIFY_WRITE	0x0010
+#define QLC_83XX_OPCODE_SEQ_PAUSE		0x0020
+#define QLC_83XX_OPCODE_SEQ_END			0x0040
+#define QLC_83XX_OPCODE_TMPL_END		0x0080
+#define QLC_83XX_OPCODE_POLL_READ_LIST		0x0100
+
+static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
+static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
+static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
+static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
+
+/* Template header */
+struct qlc_83xx_reset_hdr {
+	u16	version;
+	u16	signature;
+	u16	size;
+	u16	entries;
+	u16	hdr_size;
+	u16	checksum;
+	u16	init_offset;
+	u16	start_offset;
+} __packed;
+
+/* Command entry header. */
+struct qlc_83xx_entry_hdr {
+	u16 cmd;
+	u16 size;
+	u16 count;
+	u16 delay;
+} __packed;
+
+/* Generic poll command */
+struct qlc_83xx_poll {
+	u32	mask;
+	u32	status;
+} __packed;
+
+/* Read modify write command */
+struct qlc_83xx_rmw {
+	u32	mask;
+	u32	xor_value;
+	u32	or_value;
+	u8	shl;
+	u8	shr;
+	u8	index_a;
+	u8	rsvd;
+} __packed;
+
+/* Generic command with 2 DWORD */
+struct qlc_83xx_entry {
+	u32 arg1;
+	u32 arg2;
+} __packed;
+
+/* Generic command with 4 DWORD */
+struct qlc_83xx_quad_entry {
+	u32 dr_addr;
+	u32 dr_value;
+	u32 ar_addr;
+	u32 ar_value;
+} __packed;
+static const char *const qlc_83xx_idc_states[] = {
+	"Unknown",
+	"Cold",
+	"Init",
+	"Ready",
+	"Need Reset",
+	"Need Quiesce",
+	"Failed",
+	"Quiesce"
+};
+
+/* Device States */
+enum qlcnic_83xx_states {
+	QLC_83XX_IDC_DEV_UNKNOWN,
+	QLC_83XX_IDC_DEV_COLD,
+	QLC_83XX_IDC_DEV_INIT,
+	QLC_83XX_IDC_DEV_READY,
+	QLC_83XX_IDC_DEV_NEED_RESET,
+	QLC_83XX_IDC_DEV_NEED_QUISCENT,
+	QLC_83XX_IDC_DEV_FAILED,
+	QLC_83XX_IDC_DEV_QUISCENT
+};
+
+static int
+qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter)
+{
+	u32 val;
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+	if ((val & 0xFFFF))
+		return 1;
+	else
+		return 0;
+}
+
+static void qlcnic_83xx_idc_log_state_history(struct qlcnic_adapter *adapter)
+{
+	u32 cur, prev;
+	cur = adapter->ahw->idc.curr_state;
+	prev = adapter->ahw->idc.prev_state;
+
+	dev_info(&adapter->pdev->dev,
+		 "current state  = %s,  prev state = %s\n",
+		 adapter->ahw->idc.name[cur],
+		 adapter->ahw->idc.name[prev]);
+}
+
+static int qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter,
+					    u8 mode, int lock)
+{
+	u32 val;
+	int seconds;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	val = adapter->portnum & 0xf;
+	val |= mode << 7;
+	if (mode)
+		seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
+	else
+		seconds = jiffies / HZ;
+
+	val |= seconds << 8;
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT, val);
+	adapter->ahw->idc.sec_counter = jiffies / HZ;
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static void qlcnic_83xx_idc_update_minor_version(struct qlcnic_adapter *adapter)
+{
+	u32 val;
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION);
+	val = val & ~(0x3 << (adapter->portnum * 2));
+	val = val | (QLC_83XX_IDC_MINOR_VERSION << (adapter->portnum * 2));
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION, val);
+}
+
+static int qlcnic_83xx_idc_update_major_version(struct qlcnic_adapter *adapter,
+						int lock)
+{
+	u32 val;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+	val = val & ~0xFF;
+	val = val | QLC_83XX_IDC_MAJOR_VERSION;
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION, val);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int
+qlcnic_83xx_idc_update_drv_presence_reg(struct qlcnic_adapter *adapter,
+					int status, int lock)
+{
+	u32 val;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+
+	if (status)
+		val = val | (1 << adapter->portnum);
+	else
+		val = val & ~(1 << adapter->portnum);
+
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+	qlcnic_83xx_idc_update_minor_version(adapter);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_check_major_version(struct qlcnic_adapter *adapter)
+{
+	u32 val;
+	u8 version;
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+	version = val & 0xFF;
+
+	if (version != QLC_83XX_IDC_MAJOR_VERSION) {
+		dev_info(&adapter->pdev->dev,
+			 "%s:mismatch. version 0x%x, expected version 0x%x\n",
+			 __func__, version, QLC_83XX_IDC_MAJOR_VERSION);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_clear_registers(struct qlcnic_adapter *adapter,
+					   int lock)
+{
+	u32 val;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, 0);
+	/* Clear gracefull reset bit */
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+	val &= ~QLC_83XX_IDC_GRACEFULL_RESET;
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_update_drv_ack_reg(struct qlcnic_adapter *adapter,
+					      int flag, int lock)
+{
+	u32 val;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+	if (flag)
+		val = val | (1 << adapter->portnum);
+	else
+		val = val & ~(1 << adapter->portnum);
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, val);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_check_timeout(struct qlcnic_adapter *adapter,
+					 int time_limit)
+{
+	u64 seconds;
+
+	seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
+	if (seconds <= time_limit)
+		return 0;
+	else
+		return -EBUSY;
+}
+
+/**
+ * qlcnic_83xx_idc_check_reset_ack_reg
+ *
+ * @adapter: adapter structure
+ *
+ * Check ACK wait limit and clear the functions which failed to ACK
+ *
+ * Return 0 if all functions have acknowledged the reset request.
+ **/
+static int qlcnic_83xx_idc_check_reset_ack_reg(struct qlcnic_adapter *adapter)
+{
+	int timeout;
+	u32 ack, presence, val;
+
+	timeout = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+	ack = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+	presence = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+	dev_info(&adapter->pdev->dev,
+		 "%s: ack = 0x%x, presence = 0x%x\n", __func__, ack, presence);
+	if (!((ack & presence) == presence)) {
+		if (qlcnic_83xx_idc_check_timeout(adapter, timeout)) {
+			/* Clear functions which failed to ACK */
+			dev_info(&adapter->pdev->dev,
+				 "%s: ACK wait exceeds time limit\n", __func__);
+			val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+			val = val & ~(ack ^ presence);
+			if (qlcnic_83xx_lock_driver(adapter))
+				return -EBUSY;
+			QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+			dev_info(&adapter->pdev->dev,
+				 "%s: updated drv presence reg = 0x%x\n",
+				 __func__, val);
+			qlcnic_83xx_unlock_driver(adapter);
+			return 0;
+
+		} else {
+			return 1;
+		}
+	} else {
+		dev_info(&adapter->pdev->dev,
+			 "%s: Reset ACK received from all functions\n",
+			 __func__);
+		return 0;
+	}
+}
+
+/**
+ * qlcnic_83xx_idc_tx_soft_reset
+ *
+ * @adapter: adapter structure
+ *
+ * Handle context deletion and recreation request from transmit routine
+ *
+ * Returns -EBUSY  or Success (0)
+ *
+ **/
+static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		return -EBUSY;
+
+	netif_device_detach(netdev);
+	qlcnic_down(adapter, netdev);
+	qlcnic_up(adapter, netdev);
+	netif_device_attach(netdev);
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	dev_err(&adapter->pdev->dev, "%s:\n", __func__);
+
+	adapter->netdev->trans_start = jiffies;
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_detach_driver
+ *
+ * @adapter: adapter structure
+ * Detach net interface, stop TX and cleanup resources before the HW reset.
+ * Returns: None
+ *
+ **/
+static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
+{
+	int i;
+	struct net_device *netdev = adapter->netdev;
+
+	netif_device_detach(netdev);
+	/* Disable mailbox interrupt */
+	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);
+	qlcnic_down(adapter, netdev);
+	for (i = 0; i < adapter->ahw->num_msix; i++) {
+		adapter->ahw->intr_tbl[i].id = i;
+		adapter->ahw->intr_tbl[i].enabled = 0;
+		adapter->ahw->intr_tbl[i].src = 0;
+	}
+}
+
+/**
+ * qlcnic_83xx_idc_attach_driver
+ *
+ * @adapter: adapter structure
+ *
+ * Re-attach and re-enable net interface
+ * Returns: None
+ *
+ **/
+static void qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if (netif_running(netdev)) {
+		if (qlcnic_up(adapter, netdev))
+			goto done;
+		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+	}
+done:
+	netif_device_attach(netdev);
+	if (netif_running(netdev)) {
+		netif_carrier_on(netdev);
+		netif_wake_queue(netdev);
+	}
+}
+
+static int qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter *adapter,
+					      int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	qlcnic_83xx_idc_clear_registers(adapter, 0);
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_FAILED);
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	qlcnic_83xx_idc_log_state_history(adapter);
+	dev_info(&adapter->pdev->dev, "Device will enter failed state\n");
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_enter_init_state(struct qlcnic_adapter *adapter,
+					    int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_INIT);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_enter_need_quiesce(struct qlcnic_adapter *adapter,
+					      int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+	       QLC_83XX_IDC_DEV_NEED_QUISCENT);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int
+qlcnic_83xx_idc_enter_need_reset_state(struct qlcnic_adapter *adapter, int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+	       QLC_83XX_IDC_DEV_NEED_RESET);
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_enter_ready_state(struct qlcnic_adapter *adapter,
+					     int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_READY);
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_find_reset_owner_id
+ *
+ * @adapter: adapter structure
+ *
+ * NIC gets precedence over ISCSI and ISCSI has precedence over FCOE.
+ * Within the same class, function with lowest PCI ID assumes ownership
+ *
+ * Returns: reset owner id or failure indication (-EIO)
+ *
+ **/
+static int qlcnic_83xx_idc_find_reset_owner_id(struct qlcnic_adapter *adapter)
+{
+	u32 reg, reg1, reg2, i, j, owner, class;
+
+	reg1 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_1);
+	reg2 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_2);
+	owner = QLCNIC_TYPE_NIC;
+	i = 0;
+	j = 0;
+	reg = reg1;
+
+	do {
+		class = (((reg & (0xF << j * 4)) >> j * 4) & 0x3);
+		if (class == owner)
+			break;
+		if (i == (QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO - 1)) {
+			reg = reg2;
+			j = 0;
+		} else {
+			j++;
+		}
+
+		if (i == (QLC_83XX_IDC_MAX_CNA_FUNCTIONS - 1)) {
+			if (owner == QLCNIC_TYPE_NIC)
+				owner = QLCNIC_TYPE_ISCSI;
+			else if (owner == QLCNIC_TYPE_ISCSI)
+				owner = QLCNIC_TYPE_FCOE;
+			else if (owner == QLCNIC_TYPE_FCOE)
+				return -EIO;
+			reg = reg1;
+			j = 0;
+			i = 0;
+		}
+	} while (i++ < QLC_83XX_IDC_MAX_CNA_FUNCTIONS);
+
+	return i;
+}
+
+static int qlcnic_83xx_idc_restart_hw(struct qlcnic_adapter *adapter, int lock)
+{
+	int ret = 0;
+
+	ret = qlcnic_83xx_restart_hw(adapter);
+
+	if (ret) {
+		qlcnic_83xx_idc_enter_failed_state(adapter, lock);
+	} else {
+		qlcnic_83xx_idc_clear_registers(adapter, lock);
+		ret = qlcnic_83xx_idc_enter_ready_state(adapter, lock);
+	}
+
+	return ret;
+}
+
+static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
+{
+	u32 status;
+
+	status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+
+	if (status & QLCNIC_RCODE_FATAL_ERROR) {
+		dev_err(&adapter->pdev->dev,
+			"peg halt status1=0x%x\n", status);
+		if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
+			dev_err(&adapter->pdev->dev,
+				"On board active cooling fan failed. "
+				"Device has been halted.\n");
+			dev_err(&adapter->pdev->dev,
+				"Replace the adapter.\n");
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
+{
+	/* register for NIC IDC AEN Events */
+	qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+	qlcnic_83xx_enable_mbx_intrpt(adapter);
+	if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+		if (qlcnic_83xx_config_intrpt(adapter, 1)) {
+			netdev_err(adapter->netdev,
+				   "Failed to enable mbx intr\n");
+			return -EIO;
+		}
+	}
+
+	if (qlcnic_83xx_configure_opmode(adapter)) {
+		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+		return -EIO;
+	}
+
+	if (adapter->nic_ops->init_driver(adapter)) {
+		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+		return -EIO;
+	}
+
+	qlcnic_83xx_idc_attach_driver(adapter);
+
+	return 0;
+}
+
+static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
+{
+	qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+	qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+	set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+	adapter->ahw->idc.quiesce_req = 0;
+	adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+	adapter->ahw->idc.err_code = 0;
+	adapter->ahw->idc.collect_dump = 0;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Perform ready state initialization, this routine will get invoked only
+ * once from READY state.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) {
+		qlcnic_83xx_idc_update_idc_params(adapter);
+		/* Re-attach the device if required */
+		if ((ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) ||
+		    (ahw->idc.prev_state == QLC_83XX_IDC_DEV_INIT)) {
+			if (qlcnic_83xx_idc_reattach_driver(adapter))
+				return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_vnic_pf_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Ensure vNIC mode privileged function starts only after vNIC mode is
+ * enabled by management function.
+ * If vNIC mode is ready, start initialization.
+ *
+ * Returns: -EIO or 0
+ *
+ **/
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *adapter)
+{
+	u32 state;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	/* Privileged function waits till mgmt function enables VNIC mode */
+	state = QLCRDX(adapter->ahw, QLC_83XX_VNIC_STATE);
+	if (state != QLCNIC_DEV_NPAR_OPER) {
+		if (!ahw->idc.vnic_wait_limit--) {
+			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+			return -EIO;
+		}
+		dev_info(&adapter->pdev->dev, "vNIC mode disabled\n");
+		return -EIO;
+
+	} else {
+		/* Perform one time initialization from ready state */
+		if (ahw->idc.vnic_state != QLCNIC_DEV_NPAR_OPER) {
+			qlcnic_83xx_idc_update_idc_params(adapter);
+
+			/* If the previous state is UNKNOWN, device will be
+			   already attached properly by Init routine*/
+			if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_UNKNOWN) {
+				if (qlcnic_83xx_idc_reattach_driver(adapter))
+					return -EIO;
+			}
+			adapter->ahw->idc.vnic_state =  QLCNIC_DEV_NPAR_OPER;
+			dev_info(&adapter->pdev->dev, "vNIC mode enabled\n");
+		}
+	}
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
+{
+	adapter->ahw->idc.err_code = -EIO;
+	dev_err(&adapter->pdev->dev,
+		"%s: Device in unknown state\n", __func__);
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_cold_state
+ *
+ * @adapter: adapter structure
+ *
+ * If HW is up and running device will enter READY state.
+ * If firmware image from host needs to be loaded, device is
+ * forced to start with the file firmware image.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_cold_state_handler(struct qlcnic_adapter *adapter)
+{
+	qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 0);
+	qlcnic_83xx_idc_update_audit_reg(adapter, 1, 0);
+
+	if (qlcnic_load_fw_file) {
+		qlcnic_83xx_idc_restart_hw(adapter, 0);
+	} else {
+		if (qlcnic_83xx_check_hw_status(adapter)) {
+			qlcnic_83xx_idc_enter_failed_state(adapter, 0);
+			return -EIO;
+		} else {
+			qlcnic_83xx_idc_enter_ready_state(adapter, 0);
+		}
+	}
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_init_state
+ *
+ * @adapter: adapter structure
+ *
+ * Reset owner will restart the device from this state.
+ * Device will enter failed state if it remains
+ * in this state for more than DEV_INIT time limit.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter)
+{
+	int timeout, ret = 0;
+	u32 owner;
+
+	timeout = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+	if (adapter->ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) {
+		owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
+		if (adapter->ahw->pci_func == owner)
+			ret = qlcnic_83xx_idc_restart_hw(adapter, 1);
+	} else {
+		ret = qlcnic_83xx_idc_check_timeout(adapter, timeout);
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state
+ *
+ * @adapter: adapter structure
+ *
+ * Perform IDC protocol specicifed actions after monitoring device state and
+ * events.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
+{
+	u32 val;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int ret = 0;
+
+	/* Perform NIC configuration based ready state entry actions */
+	if (ahw->idc.state_entry(adapter))
+		return -EIO;
+
+	if (qlcnic_check_temp(adapter)) {
+		if (ahw->temp == QLCNIC_TEMP_PANIC) {
+			qlcnic_83xx_idc_check_fan_failure(adapter);
+			dev_err(&adapter->pdev->dev,
+				"Error: device temperature %d above limits\n",
+				adapter->ahw->temp);
+			clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+			set_bit(__QLCNIC_RESETTING, &adapter->state);
+			qlcnic_83xx_idc_detach_driver(adapter);
+			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+			return -EIO;
+		}
+	}
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+	ret = qlcnic_83xx_check_heartbeat(adapter);
+	if (ret) {
+		adapter->flags |= QLCNIC_FW_HANG;
+		if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+			clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+			set_bit(__QLCNIC_RESETTING, &adapter->state);
+			qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+		}
+		return -EIO;
+	}
+
+	if ((val & QLC_83XX_IDC_GRACEFULL_RESET) || ahw->idc.collect_dump) {
+		/* Move to need reset state and prepare for reset */
+		qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+		return ret;
+	}
+
+	/* Check for soft reset request */
+	if (ahw->reset_context &&
+	    !(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+		qlcnic_83xx_idc_tx_soft_reset(adapter);
+		return ret;
+	}
+
+	/* Move to need quiesce state if requested */
+	if (adapter->ahw->idc.quiesce_req) {
+		qlcnic_83xx_idc_enter_need_quiesce(adapter, 1);
+		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_need_reset_state
+ *
+ * @adapter: adapter structure
+ *
+ * Device will remain in this state until:
+ *	Reset request ACK's are recieved from all the functions
+ *	Wait time exceeds max time limit
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
+{
+	int ret = 0;
+
+	if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
+		qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+		set_bit(__QLCNIC_RESETTING, &adapter->state);
+		clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+		if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
+			qlcnic_83xx_disable_vnic_mode(adapter, 1);
+		qlcnic_83xx_idc_detach_driver(adapter);
+	}
+
+	/* Check ACK from other functions */
+	ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+	if (ret) {
+		dev_info(&adapter->pdev->dev,
+			 "%s: Waiting for reset ACK\n", __func__);
+		return 0;
+	}
+
+	/* Transit to INIT state and restart the HW */
+	qlcnic_83xx_idc_enter_init_state(adapter, 1);
+
+	return ret;
+}
+
+static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)
+{
+	dev_err(&adapter->pdev->dev, "%s: TBD\n", __func__);
+	return 0;
+}
+
+static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
+{
+	dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__);
+	adapter->ahw->idc.err_code = -EIO;
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter)
+{
+	dev_info(&adapter->pdev->dev, "%s: TBD\n", __func__);
+	return 0;
+}
+
+static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
+						u32 state)
+{
+	u32 cur, prev, next;
+
+	cur = adapter->ahw->idc.curr_state;
+	prev = adapter->ahw->idc.prev_state;
+	next = state;
+
+	if ((next < QLC_83XX_IDC_DEV_COLD) ||
+	    (next > QLC_83XX_IDC_DEV_QUISCENT)) {
+		dev_err(&adapter->pdev->dev,
+			"%s: curr %d, prev %d, next state %d is  invalid\n",
+			__func__, cur, prev, state);
+		return 1;
+	}
+
+	if ((cur == QLC_83XX_IDC_DEV_UNKNOWN) &&
+	    (prev == QLC_83XX_IDC_DEV_UNKNOWN)) {
+		if ((next != QLC_83XX_IDC_DEV_COLD) &&
+		    (next != QLC_83XX_IDC_DEV_READY)) {
+			dev_err(&adapter->pdev->dev,
+				"%s: failed, cur %d prev %d next %d\n",
+				__func__, cur, prev, next);
+			return 1;
+		}
+	}
+
+	if (next == QLC_83XX_IDC_DEV_INIT) {
+		if ((prev != QLC_83XX_IDC_DEV_INIT) &&
+		    (prev != QLC_83XX_IDC_DEV_COLD) &&
+		    (prev != QLC_83XX_IDC_DEV_NEED_RESET)) {
+			dev_err(&adapter->pdev->dev,
+				"%s: failed, cur %d prev %d next %d\n",
+				__func__, cur, prev, next);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
+{
+	if (adapter->fhash.fnum)
+		qlcnic_prune_lb_filters(adapter);
+}
+
+/**
+ * qlcnic_83xx_idc_poll_dev_state
+ *
+ * @work: kernel work queue structure used to schedule the function
+ *
+ * Poll device state periodically and perform state specific
+ * actions defined by Inter Driver Communication (IDC) protocol.
+ *
+ * Returns: None
+ *
+ **/
+void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
+{
+	struct qlcnic_adapter *adapter;
+	u32 state;
+
+	adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
+	state =	QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+
+	if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
+		qlcnic_83xx_idc_log_state_history(adapter);
+		adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+	} else {
+		adapter->ahw->idc.curr_state = state;
+	}
+
+	switch (adapter->ahw->idc.curr_state) {
+	case QLC_83XX_IDC_DEV_READY:
+		qlcnic_83xx_idc_ready_state(adapter);
+		break;
+	case QLC_83XX_IDC_DEV_NEED_RESET:
+		qlcnic_83xx_idc_need_reset_state(adapter);
+		break;
+	case QLC_83XX_IDC_DEV_NEED_QUISCENT:
+		qlcnic_83xx_idc_need_quiesce_state(adapter);
+		break;
+	case QLC_83XX_IDC_DEV_FAILED:
+		qlcnic_83xx_idc_failed_state(adapter);
+		return;
+	case QLC_83XX_IDC_DEV_INIT:
+		qlcnic_83xx_idc_init_state(adapter);
+		break;
+	case QLC_83XX_IDC_DEV_QUISCENT:
+		qlcnic_83xx_idc_quiesce_state(adapter);
+		break;
+	default:
+		qlcnic_83xx_idc_unknown_state(adapter);
+		return;
+	}
+	adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
+	qlcnic_83xx_periodic_tasks(adapter);
+
+	/* Re-schedule the function */
+	if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
+		qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
+				     adapter->ahw->idc.delay);
+}
+
+static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter)
+{
+	u32 idc_params, val;
+
+	if (qlcnic_83xx_lockless_flash_read32(adapter,
+					      QLC_83XX_IDC_FLASH_PARAM_ADDR,
+					      (u8 *)&idc_params, 1)) {
+		dev_info(&adapter->pdev->dev,
+			 "%s:failed to get IDC params from flash\n", __func__);
+		adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+		adapter->reset_ack_timeo = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+	} else {
+		adapter->dev_init_timeo = idc_params & 0xFFFF;
+		adapter->reset_ack_timeo = ((idc_params >> 16) & 0xFFFF);
+	}
+
+	adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+	adapter->ahw->idc.prev_state = QLC_83XX_IDC_DEV_UNKNOWN;
+	adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+	adapter->ahw->idc.err_code = 0;
+	adapter->ahw->idc.collect_dump = 0;
+	adapter->ahw->idc.name = (char **)qlc_83xx_idc_states;
+
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+	set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+
+	/* Check if reset recovery is disabled */
+	if (!qlcnic_auto_fw_reset) {
+		/* Propagate do not reset request to other functions */
+		val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+		val = val | QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+		QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+	}
+}
+
+static int
+qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
+{
+	u32 state, val;
+
+	if (qlcnic_83xx_lock_driver(adapter))
+		return -EIO;
+
+	/* Clear driver lock register */
+	QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, 0);
+	if (qlcnic_83xx_idc_update_major_version(adapter, 0)) {
+		qlcnic_83xx_unlock_driver(adapter);
+		return -EIO;
+	}
+
+	state =	QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+	if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
+		qlcnic_83xx_unlock_driver(adapter);
+		return -EIO;
+	}
+
+	if (state != QLC_83XX_IDC_DEV_COLD && qlcnic_load_fw_file) {
+		QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+		       QLC_83XX_IDC_DEV_COLD);
+		state = QLC_83XX_IDC_DEV_COLD;
+	}
+
+	adapter->ahw->idc.curr_state = state;
+	/* First to load function should cold boot the device */
+	if (state == QLC_83XX_IDC_DEV_COLD)
+		qlcnic_83xx_idc_cold_state_handler(adapter);
+
+	/* Check if reset recovery is enabled */
+	if (qlcnic_auto_fw_reset) {
+		val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+		val = val & ~QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+		QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+	}
+
+	qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
+{
+	int ret = -EIO;
+
+	qlcnic_83xx_setup_idc_parameters(adapter);
+
+	if (qlcnic_83xx_get_reset_instruction_template(adapter))
+		return ret;
+
+	if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
+		if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
+			return -EIO;
+	} else {
+		if (qlcnic_83xx_idc_check_major_version(adapter))
+			return -EIO;
+	}
+
+	qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+
+	return 0;
+}
+
+void qlcnic_83xx_idc_exit(struct qlcnic_adapter *adapter)
+{
+	int id;
+	u32 val;
+
+	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		usleep_range(10000, 11000);
+
+	id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+	id = id & 0xFF;
+
+	if (id == adapter->portnum) {
+		dev_err(&adapter->pdev->dev,
+			"%s: wait for lock recovery.. %d\n", __func__, id);
+		msleep(20);
+		id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+		id = id & 0xFF;
+	}
+
+	/* Clear driver presence bit */
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+	val = val & ~(1 << adapter->portnum);
+	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+	clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+	cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)
+{
+	u32 val;
+
+	if (qlcnic_83xx_lock_driver(adapter)) {
+		dev_err(&adapter->pdev->dev,
+			"%s:failed, please retry\n", __func__);
+		return;
+	}
+
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+	if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) ||
+	    !qlcnic_auto_fw_reset) {
+		dev_err(&adapter->pdev->dev,
+			"%s:failed, device in non reset mode\n", __func__);
+		qlcnic_83xx_unlock_driver(adapter);
+		return;
+	}
+
+	if (key == QLCNIC_FORCE_FW_RESET) {
+		val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+		val = val | QLC_83XX_IDC_GRACEFULL_RESET;
+		QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+	} else if (key == QLCNIC_FORCE_FW_DUMP_KEY) {
+		adapter->ahw->idc.collect_dump = 1;
+	}
+
+	qlcnic_83xx_unlock_driver(adapter);
+	return;
+}
+
+static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)
+{
+	u8 *p_cache;
+	u32 src, size;
+	u64 dest;
+	int ret = -EIO;
+
+	src = QLC_83XX_BOOTLOADER_FLASH_ADDR;
+	dest = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_ADDR);
+	size = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_SIZE);
+
+	/* alignment check */
+	if (size & 0xF)
+		size = (size + 16) & ~0xF;
+
+	p_cache = kzalloc(size, GFP_KERNEL);
+	if (p_cache == NULL)
+		return -ENOMEM;
+
+	ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache,
+						size / sizeof(u32));
+	if (ret) {
+		kfree(p_cache);
+		return ret;
+	}
+	/* 16 byte write to MS memory */
+	ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache,
+					  size / 16);
+	if (ret) {
+		kfree(p_cache);
+		return ret;
+	}
+	kfree(p_cache);
+
+	return ret;
+}
+
+static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
+{
+	u32 dest, *p_cache;
+	u64 addr;
+	u8 data[16];
+	size_t size;
+	int i, ret = -EIO;
+
+	dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
+	size = (adapter->ahw->fw_info.fw->size & ~0xF);
+	p_cache = (u32 *)adapter->ahw->fw_info.fw->data;
+	addr = (u64)dest;
+
+	ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
+					  (u32 *)p_cache, size / 16);
+	if (ret) {
+		dev_err(&adapter->pdev->dev, "MS memory write failed\n");
+		release_firmware(adapter->ahw->fw_info.fw);
+		adapter->ahw->fw_info.fw = NULL;
+		return -EIO;
+	}
+
+	/* alignment check */
+	if (adapter->ahw->fw_info.fw->size & 0xF) {
+		addr = dest + size;
+		for (i = 0; i < (adapter->ahw->fw_info.fw->size & 0xF); i++)
+			data[i] = adapter->ahw->fw_info.fw->data[size + i];
+		for (; i < 16; i++)
+			data[i] = 0;
+		ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
+						  (u32 *)data, 1);
+		if (ret) {
+			dev_err(&adapter->pdev->dev,
+				"MS memory write failed\n");
+			release_firmware(adapter->ahw->fw_info.fw);
+			adapter->ahw->fw_info.fw = NULL;
+			return -EIO;
+		}
+	}
+	release_firmware(adapter->ahw->fw_info.fw);
+	adapter->ahw->fw_info.fw = NULL;
+
+	return 0;
+}
+
+static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
+{
+	int i, j;
+	u32 val = 0, val1 = 0, reg = 0;
+
+	val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG);
+	dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
+
+	for (j = 0; j < 2; j++) {
+		if (j == 0) {
+			dev_info(&adapter->pdev->dev,
+				 "Port 0 RxB Pause Threshold Regs[TC7..TC0]:");
+			reg = QLC_83XX_PORT0_THRESHOLD;
+		} else if (j == 1) {
+			dev_info(&adapter->pdev->dev,
+				 "Port 1 RxB Pause Threshold Regs[TC7..TC0]:");
+			reg = QLC_83XX_PORT1_THRESHOLD;
+		}
+		for (i = 0; i < 8; i++) {
+			val = QLCRD32(adapter, reg + (i * 0x4));
+			dev_info(&adapter->pdev->dev, "0x%x  ", val);
+		}
+		dev_info(&adapter->pdev->dev, "\n");
+	}
+
+	for (j = 0; j < 2; j++) {
+		if (j == 0) {
+			dev_info(&adapter->pdev->dev,
+				 "Port 0 RxB TC Max Cell Registers[4..1]:");
+			reg = QLC_83XX_PORT0_TC_MC_REG;
+		} else if (j == 1) {
+			dev_info(&adapter->pdev->dev,
+				 "Port 1 RxB TC Max Cell Registers[4..1]:");
+			reg = QLC_83XX_PORT1_TC_MC_REG;
+		}
+		for (i = 0; i < 4; i++) {
+			val = QLCRD32(adapter, reg + (i * 0x4));
+			 dev_info(&adapter->pdev->dev, "0x%x  ", val);
+		}
+		dev_info(&adapter->pdev->dev, "\n");
+	}
+
+	for (j = 0; j < 2; j++) {
+		if (j == 0) {
+			dev_info(&adapter->pdev->dev,
+				 "Port 0 RxB Rx TC Stats[TC7..TC0]:");
+			reg = QLC_83XX_PORT0_TC_STATS;
+		} else if (j == 1) {
+			dev_info(&adapter->pdev->dev,
+				 "Port 1 RxB Rx TC Stats[TC7..TC0]:");
+			reg = QLC_83XX_PORT1_TC_STATS;
+		}
+		for (i = 7; i >= 0; i--) {
+			val = QLCRD32(adapter, reg);
+			val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
+			QLCWR32(adapter, reg, (val | (i << 29)));
+			val = QLCRD32(adapter, reg);
+			dev_info(&adapter->pdev->dev, "0x%x  ", val);
+		}
+		dev_info(&adapter->pdev->dev, "\n");
+	}
+
+	val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD);
+	val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD);
+	dev_info(&adapter->pdev->dev,
+		 "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
+		 val, val1);
+}
+
+
+static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
+{
+	u32 reg = 0, i, j;
+
+	if (qlcnic_83xx_lock_driver(adapter)) {
+		dev_err(&adapter->pdev->dev,
+			"%s:failed to acquire driver lock\n", __func__);
+		return;
+	}
+
+	qlcnic_83xx_dump_pause_control_regs(adapter);
+	QLCWR32(adapter, QLC_83XX_SRE_SHIM_REG, 0x0);
+
+	for (j = 0; j < 2; j++) {
+		if (j == 0)
+			reg = QLC_83XX_PORT0_THRESHOLD;
+		else if (j == 1)
+			reg = QLC_83XX_PORT1_THRESHOLD;
+
+		for (i = 0; i < 8; i++)
+			QLCWR32(adapter, reg + (i * 0x4), 0x0);
+	}
+
+	for (j = 0; j < 2; j++) {
+		if (j == 0)
+			reg = QLC_83XX_PORT0_TC_MC_REG;
+		else if (j == 1)
+			reg = QLC_83XX_PORT1_TC_MC_REG;
+
+		for (i = 0; i < 4; i++)
+			QLCWR32(adapter, reg + (i * 0x4), 0x03FF03FF);
+	}
+
+	QLCWR32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, 0);
+	QLCWR32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, 0);
+	dev_info(&adapter->pdev->dev,
+		 "Disabled pause frames successfully on all ports\n");
+	qlcnic_83xx_unlock_driver(adapter);
+}
+
+static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
+{
+	u32 heartbeat, peg_status;
+	int retries, ret = -EIO;
+
+	retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
+	p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
+					       QLCNIC_PEG_ALIVE_COUNTER);
+
+	do {
+		msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
+		heartbeat = QLC_SHARED_REG_RD32(p_dev,
+						QLCNIC_PEG_ALIVE_COUNTER);
+		if (heartbeat != p_dev->heartbeat) {
+			ret = QLCNIC_RCODE_SUCCESS;
+			break;
+		}
+	} while (--retries);
+
+	if (ret) {
+		dev_err(&p_dev->pdev->dev, "firmware hang detected\n");
+		qlcnic_83xx_disable_pause_frames(p_dev);
+		peg_status = QLC_SHARED_REG_RD32(p_dev,
+						 QLCNIC_PEG_HALT_STATUS1);
+		dev_info(&p_dev->pdev->dev, "Dumping HW/FW registers\n"
+			 "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+			 "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+			 "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+			 "PEG_NET_4_PC: 0x%x\n", peg_status,
+			 QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
+			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0),
+			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1),
+			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2),
+			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3),
+			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4));
+
+		if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
+			dev_err(&p_dev->pdev->dev,
+				"Device is being reset err code 0x00006700.\n");
+	}
+
+	return ret;
+}
+
+static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev)
+{
+	int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
+	u32 val;
+
+	do {
+		val = QLC_SHARED_REG_RD32(p_dev, QLCNIC_CMDPEG_STATE);
+		if (val == QLC_83XX_CMDPEG_COMPLETE)
+			return 0;
+		msleep(QLCNIC_CMDPEG_CHECK_DELAY);
+	} while (--retries);
+
+	dev_err(&p_dev->pdev->dev, "%s: failed, state = 0x%x\n", __func__, val);
+	return -EIO;
+}
+
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
+{
+	int err;
+
+	err = qlcnic_83xx_check_cmd_peg_status(p_dev);
+	if (err)
+		return err;
+
+	err = qlcnic_83xx_check_heartbeat(p_dev);
+	if (err)
+		return err;
+
+	return err;
+}
+
+static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
+				int duration, u32 mask, u32 status)
+{
+	u32 value;
+	int timeout_error;
+	u8 retries;
+
+	value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+	retries = duration / 10;
+
+	do {
+		if ((value & mask) != status) {
+			timeout_error = 1;
+			msleep(duration / 10);
+			value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+		} else {
+			timeout_error = 0;
+			break;
+		}
+	} while (retries--);
+
+	if (timeout_error) {
+		p_dev->ahw->reset.seq_error++;
+		dev_err(&p_dev->pdev->dev,
+			"%s: Timeout Err, entry_num = %d\n",
+			__func__, p_dev->ahw->reset.seq_index);
+		dev_err(&p_dev->pdev->dev,
+			"0x%08x 0x%08x 0x%08x\n",
+			value, mask, status);
+	}
+
+	return timeout_error;
+}
+
+static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
+{
+	u32 sum = 0;
+	u16 *buff = (u16 *)p_dev->ahw->reset.buff;
+	int count = p_dev->ahw->reset.hdr->size / sizeof(u16);
+
+	while (count-- > 0)
+		sum += *buff++;
+
+	while (sum >> 16)
+		sum = (sum & 0xFFFF) + (sum >> 16);
+
+	if (~sum) {
+		return 0;
+	} else {
+		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+		return -1;
+	}
+}
+
+int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
+{
+	u8 *p_buff;
+	u32 addr, count;
+	struct qlcnic_hardware_context *ahw = p_dev->ahw;
+
+	ahw->reset.seq_error = 0;
+	ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
+	if (p_dev->ahw->reset.buff == NULL)
+		return -ENOMEM;
+
+	p_buff = p_dev->ahw->reset.buff;
+	addr = QLC_83XX_RESET_TEMPLATE_ADDR;
+	count = sizeof(struct qlc_83xx_reset_hdr) / sizeof(u32);
+
+	/* Copy template header from flash */
+	if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
+		dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+		return -EIO;
+	}
+	ahw->reset.hdr = (struct qlc_83xx_reset_hdr *)ahw->reset.buff;
+	addr = QLC_83XX_RESET_TEMPLATE_ADDR + ahw->reset.hdr->hdr_size;
+	p_buff = ahw->reset.buff + ahw->reset.hdr->hdr_size;
+	count = (ahw->reset.hdr->size - ahw->reset.hdr->hdr_size) / sizeof(u32);
+
+	/* Copy rest of the template */
+	if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
+		dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+		return -EIO;
+	}
+
+	if (qlcnic_83xx_reset_template_checksum(p_dev))
+		return -EIO;
+	/* Get Stop, Start and Init command offsets */
+	ahw->reset.init_offset = ahw->reset.buff + ahw->reset.hdr->init_offset;
+	ahw->reset.start_offset = ahw->reset.buff +
+				  ahw->reset.hdr->start_offset;
+	ahw->reset.stop_offset = ahw->reset.buff + ahw->reset.hdr->hdr_size;
+	return 0;
+}
+
+/* Read Write HW register command */
+static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
+					   u32 raddr, u32 waddr)
+{
+	int value;
+
+	value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+	qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Read Modify Write HW register command */
+static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
+				    u32 raddr, u32 waddr,
+				    struct qlc_83xx_rmw *p_rmw_hdr)
+{
+	int value;
+
+	if (p_rmw_hdr->index_a)
+		value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
+	else
+		value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+
+	value &= p_rmw_hdr->mask;
+	value <<= p_rmw_hdr->shl;
+	value >>= p_rmw_hdr->shr;
+	value |= p_rmw_hdr->or_value;
+	value ^= p_rmw_hdr->xor_value;
+	qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Write HW register command */
+static void qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
+				   struct qlc_83xx_entry_hdr *p_hdr)
+{
+	int i;
+	struct qlc_83xx_entry *entry;
+
+	entry = (struct qlc_83xx_entry *)((char *)p_hdr +
+					  sizeof(struct qlc_83xx_entry_hdr));
+
+	for (i = 0; i < p_hdr->count; i++, entry++) {
+		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->arg1,
+					     entry->arg2);
+		if (p_hdr->delay)
+			udelay((u32)(p_hdr->delay));
+	}
+}
+
+/* Read and Write instruction */
+static void qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
+					struct qlc_83xx_entry_hdr *p_hdr)
+{
+	int i;
+	struct qlc_83xx_entry *entry;
+
+	entry = (struct qlc_83xx_entry *)((char *)p_hdr +
+					  sizeof(struct qlc_83xx_entry_hdr));
+
+	for (i = 0; i < p_hdr->count; i++, entry++) {
+		qlcnic_83xx_read_write_crb_reg(p_dev, entry->arg1,
+					       entry->arg2);
+		if (p_hdr->delay)
+			udelay((u32)(p_hdr->delay));
+	}
+}
+
+/* Poll HW register command */
+static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
+				  struct qlc_83xx_entry_hdr *p_hdr)
+{
+	long delay;
+	struct qlc_83xx_entry *entry;
+	struct qlc_83xx_poll *poll;
+	int i;
+	unsigned long arg1, arg2;
+
+	poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+					sizeof(struct qlc_83xx_entry_hdr));
+
+	entry = (struct qlc_83xx_entry *)((char *)poll +
+					  sizeof(struct qlc_83xx_poll));
+	delay = (long)p_hdr->delay;
+
+	if (!delay) {
+		for (i = 0; i < p_hdr->count; i++, entry++)
+			qlcnic_83xx_poll_reg(p_dev, entry->arg1,
+					     delay, poll->mask,
+					     poll->status);
+	} else {
+		for (i = 0; i < p_hdr->count; i++, entry++) {
+			arg1 = entry->arg1;
+			arg2 = entry->arg2;
+			if (delay) {
+				if (qlcnic_83xx_poll_reg(p_dev,
+							 arg1, delay,
+							 poll->mask,
+							 poll->status)){
+					qlcnic_83xx_rd_reg_indirect(p_dev,
+								    arg1);
+					qlcnic_83xx_rd_reg_indirect(p_dev,
+								    arg2);
+				}
+			}
+		}
+	}
+}
+
+/* Poll and write HW register command */
+static void qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
+					struct qlc_83xx_entry_hdr *p_hdr)
+{
+	int i;
+	long delay;
+	struct qlc_83xx_quad_entry *entry;
+	struct qlc_83xx_poll *poll;
+
+	poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+					sizeof(struct qlc_83xx_entry_hdr));
+	entry = (struct qlc_83xx_quad_entry *)((char *)poll +
+					       sizeof(struct qlc_83xx_poll));
+	delay = (long)p_hdr->delay;
+
+	for (i = 0; i < p_hdr->count; i++, entry++) {
+		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->dr_addr,
+					     entry->dr_value);
+		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
+					     entry->ar_value);
+		if (delay)
+			qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
+					     poll->mask, poll->status);
+	}
+}
+
+/* Read Modify Write register command */
+static void qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
+					  struct qlc_83xx_entry_hdr *p_hdr)
+{
+	int i;
+	struct qlc_83xx_entry *entry;
+	struct qlc_83xx_rmw *rmw_hdr;
+
+	rmw_hdr = (struct qlc_83xx_rmw *)((char *)p_hdr +
+					  sizeof(struct qlc_83xx_entry_hdr));
+
+	entry = (struct qlc_83xx_entry *)((char *)rmw_hdr +
+					  sizeof(struct qlc_83xx_rmw));
+
+	for (i = 0; i < p_hdr->count; i++, entry++) {
+		qlcnic_83xx_rmw_crb_reg(p_dev, entry->arg1,
+					entry->arg2, rmw_hdr);
+		if (p_hdr->delay)
+			udelay((u32)(p_hdr->delay));
+	}
+}
+
+static void qlcnic_83xx_pause(struct qlc_83xx_entry_hdr *p_hdr)
+{
+	if (p_hdr->delay)
+		mdelay((u32)((long)p_hdr->delay));
+}
+
+/* Read and poll register command */
+static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
+				       struct qlc_83xx_entry_hdr *p_hdr)
+{
+	long delay;
+	int index, i, j;
+	struct qlc_83xx_quad_entry *entry;
+	struct qlc_83xx_poll *poll;
+	unsigned long addr;
+
+	poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+					sizeof(struct qlc_83xx_entry_hdr));
+
+	entry = (struct qlc_83xx_quad_entry *)((char *)poll +
+					       sizeof(struct qlc_83xx_poll));
+	delay = (long)p_hdr->delay;
+
+	for (i = 0; i < p_hdr->count; i++, entry++) {
+		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
+					     entry->ar_value);
+		if (delay) {
+			if (!qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
+						  poll->mask, poll->status)){
+				index = p_dev->ahw->reset.array_index;
+				addr = entry->dr_addr;
+				j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+				p_dev->ahw->reset.array[index++] = j;
+
+				if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
+					p_dev->ahw->reset.array_index = 1;
+			}
+		}
+	}
+}
+
+static inline void qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev)
+{
+	p_dev->ahw->reset.seq_end = 1;
+}
+
+static void qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev)
+{
+	p_dev->ahw->reset.template_end = 1;
+	if (p_dev->ahw->reset.seq_error == 0)
+		dev_err(&p_dev->pdev->dev,
+			"HW restart process completed successfully.\n");
+	else
+		dev_err(&p_dev->pdev->dev,
+			"HW restart completed with timeout errors.\n");
+}
+
+/**
+* qlcnic_83xx_exec_template_cmd
+*
+* @p_dev: adapter structure
+* @p_buff: Poiter to instruction template
+*
+* Template provides instructions to stop, restart and initalize firmware.
+* These instructions are abstracted as a series of read, write and
+* poll operations on hardware registers. Register information and operation
+* specifics are not exposed to the driver. Driver reads the template from
+* flash and executes the instructions located at pre-defined offsets.
+*
+* Returns: None
+* */
+static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
+					  char *p_buff)
+{
+	int index, entries;
+	struct qlc_83xx_entry_hdr *p_hdr;
+	char *entry = p_buff;
+
+	p_dev->ahw->reset.seq_end = 0;
+	p_dev->ahw->reset.template_end = 0;
+	entries = p_dev->ahw->reset.hdr->entries;
+	index = p_dev->ahw->reset.seq_index;
+
+	for (; (!p_dev->ahw->reset.seq_end) && (index < entries); index++) {
+		p_hdr = (struct qlc_83xx_entry_hdr *)entry;
+
+		switch (p_hdr->cmd) {
+		case QLC_83XX_OPCODE_NOP:
+			break;
+		case QLC_83XX_OPCODE_WRITE_LIST:
+			qlcnic_83xx_write_list(p_dev, p_hdr);
+			break;
+		case QLC_83XX_OPCODE_READ_WRITE_LIST:
+			qlcnic_83xx_read_write_list(p_dev, p_hdr);
+			break;
+		case QLC_83XX_OPCODE_POLL_LIST:
+			qlcnic_83xx_poll_list(p_dev, p_hdr);
+			break;
+		case QLC_83XX_OPCODE_POLL_WRITE_LIST:
+			qlcnic_83xx_poll_write_list(p_dev, p_hdr);
+			break;
+		case QLC_83XX_OPCODE_READ_MODIFY_WRITE:
+			qlcnic_83xx_read_modify_write(p_dev, p_hdr);
+			break;
+		case QLC_83XX_OPCODE_SEQ_PAUSE:
+			qlcnic_83xx_pause(p_hdr);
+			break;
+		case QLC_83XX_OPCODE_SEQ_END:
+			qlcnic_83xx_seq_end(p_dev);
+			break;
+		case QLC_83XX_OPCODE_TMPL_END:
+			qlcnic_83xx_template_end(p_dev);
+			break;
+		case QLC_83XX_OPCODE_POLL_READ_LIST:
+			qlcnic_83xx_poll_read_list(p_dev, p_hdr);
+			break;
+		default:
+			dev_err(&p_dev->pdev->dev,
+				"%s: Unknown opcode 0x%04x in template %d\n",
+				__func__, p_hdr->cmd, index);
+			break;
+		}
+		entry += p_hdr->size;
+	}
+	p_dev->ahw->reset.seq_index = index;
+}
+
+static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
+{
+	p_dev->ahw->reset.seq_index = 0;
+
+	qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.stop_offset);
+	if (p_dev->ahw->reset.seq_end != 1)
+		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
+{
+	qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.start_offset);
+	if (p_dev->ahw->reset.template_end != 1)
+		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
+{
+	qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.init_offset);
+	if (p_dev->ahw->reset.seq_end != 1)
+		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	if (request_firmware(&adapter->ahw->fw_info.fw,
+			     QLC_83XX_FW_FILE_NAME, &(adapter->pdev->dev))) {
+		dev_err(&adapter->pdev->dev,
+			"No file FW image, loading flash FW image.\n");
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+				    QLC_83XX_BOOT_FROM_FLASH);
+	} else {
+		if (qlcnic_83xx_copy_fw_file(adapter))
+			return err;
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+				    QLC_83XX_BOOT_FROM_FILE);
+	}
+
+	return 0;
+}
+
+static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
+{
+	u32 val;
+	int err = -EIO;
+
+	qlcnic_83xx_stop_hw(adapter);
+
+	/* Collect FW register dump if required */
+	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+	if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))
+		qlcnic_dump_fw(adapter);
+	qlcnic_83xx_init_hw(adapter);
+
+	if (qlcnic_83xx_copy_bootloader(adapter))
+		return err;
+	/* Boot either flash image or firmware image from host file system */
+	if (qlcnic_load_fw_file) {
+		if (qlcnic_83xx_load_fw_image_from_host(adapter))
+			return err;
+	} else {
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+				    QLC_83XX_BOOT_FROM_FLASH);
+	}
+
+	qlcnic_83xx_start_hw(adapter);
+	if (qlcnic_83xx_check_hw_status(adapter))
+		return -EIO;
+
+	return 0;
+}
+
+/**
+* qlcnic_83xx_config_default_opmode
+*
+* @adapter: adapter structure
+*
+* Configure default driver operating mode
+*
+* Returns: Error code or Success(0)
+* */
+int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter)
+{
+	u32 op_mode;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	qlcnic_get_func_no(adapter);
+	op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE);
+
+	if (op_mode == QLC_83XX_DEFAULT_OPMODE) {
+		adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;
+		ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+	} else {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
+{
+	int err;
+	struct qlcnic_info nic_info;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	memset(&nic_info, 0, sizeof(struct qlcnic_info));
+	err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
+	if (err)
+		return -EIO;
+
+	ahw->physical_port = (u8) nic_info.phys_port;
+	ahw->switch_mode = nic_info.switch_mode;
+	ahw->max_tx_ques = nic_info.max_tx_ques;
+	ahw->max_rx_ques = nic_info.max_rx_ques;
+	ahw->capabilities = nic_info.capabilities;
+	ahw->max_mac_filters = nic_info.max_mac_filters;
+	ahw->max_mtu = nic_info.max_mtu;
+
+	if (ahw->capabilities & BIT_23)
+		ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE;
+	else
+		ahw->nic_mode = QLC_83XX_DEFAULT_MODE;
+
+	return ahw->nic_mode;
+}
+
+static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
+{
+	int ret;
+
+	ret = qlcnic_83xx_get_nic_configuration(adapter);
+	if (ret == -EIO)
+		return -EIO;
+
+	if (ret == QLC_83XX_VIRTUAL_NIC_MODE) {
+		if (qlcnic_83xx_config_vnic_opmode(adapter))
+			return -EIO;
+	} else if (ret == QLC_83XX_DEFAULT_MODE) {
+		if (qlcnic_83xx_config_default_opmode(adapter))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static void qlcnic_83xx_config_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (ahw->port_type == QLCNIC_XGBE) {
+		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+		adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
+		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+	} else if (ahw->port_type == QLCNIC_GBE) {
+		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+		adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+	}
+	adapter->num_txd = MAX_CMD_DESCRIPTORS;
+	adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	qlcnic_83xx_get_minidump_template(adapter);
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+	dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
+		 adapter->ahw->fw_hal_version);
+
+	return 0;
+}
+
+#define IS_QLC_83XX_USED(a, b, c) (((1 << a->portnum) & b) || ((c >> 6) & 0x1))
+static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_cmd_args cmd;
+	u32 presence_mask, audit_mask;
+	int status;
+
+	presence_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+	audit_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
+
+	if (IS_QLC_83XX_USED(adapter, presence_mask, audit_mask)) {
+		qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+		cmd.req.arg[1] = BIT_31;
+		status = qlcnic_issue_cmd(adapter, &cmd);
+		if (status)
+			dev_err(&adapter->pdev->dev,
+				"Failed to clean up the function resources\n");
+		qlcnic_free_mbx_args(&cmd);
+	}
+}
+
+int qlcnic_83xx_init(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (qlcnic_83xx_check_hw_status(adapter))
+		return -EIO;
+
+	/* Initilaize 83xx mailbox spinlock */
+	spin_lock_init(&ahw->mbx_lock);
+
+	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+	qlcnic_83xx_clear_function_resources(adapter);
+
+	/* register for NIC IDC AEN Events */
+	qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+	if (!qlcnic_83xx_read_flash_descriptor_table(adapter))
+		qlcnic_83xx_read_flash_mfg_id(adapter);
+
+	if (qlcnic_83xx_idc_init(adapter))
+		return -EIO;
+
+	/* Configure default, SR-IOV or Virtual NIC mode of operation */
+	if (qlcnic_83xx_configure_opmode(adapter))
+		return -EIO;
+
+	/* Perform operating mode specific initialization */
+	if (adapter->nic_ops->init_driver(adapter))
+		return -EIO;
+
+	INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
+	/* Periodically monitor device status */
+	qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
+
+	return adapter->ahw->idc.err_code;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
new file mode 100644
index 0000000..b0c3de9
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -0,0 +1,225 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+	QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_OPER);
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (lock) {
+		if (qlcnic_83xx_lock_driver(adapter))
+			return -EBUSY;
+	}
+
+	QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+	ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+
+	if (lock)
+		qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+	u8 id;
+	int i, ret = -EBUSY;
+	u32 data = QLCNIC_MGMT_FUNC;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (qlcnic_83xx_lock_driver(adapter))
+		return ret;
+
+	if (qlcnic_config_npars) {
+		for (i = 0; i < ahw->act_pci_func; i++) {
+			id = adapter->npars[i].pci_func;
+			if (id == ahw->pci_func)
+				continue;
+			data |= qlcnic_config_npars &
+				QLC_83XX_SET_FUNC_OPMODE(0x3, id);
+		}
+	} else {
+		data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+		data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
+		       QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
+						ahw->pci_func);
+	}
+	QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
+
+	qlcnic_83xx_unlock_driver(adapter);
+
+	return 0;
+}
+
+static void
+qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (ahw->port_type == QLCNIC_XGBE) {
+		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+		adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+	} else if (ahw->port_type == QLCNIC_GBE) {
+		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+		adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+	}
+	adapter->num_txd = MAX_CMD_DESCRIPTORS;
+	adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+
+/**
+ * qlcnic_83xx_init_mgmt_vnic
+ *
+ * @adapter: adapter structure
+ * Management virtual NIC sets the operational mode of other vNIC's and
+ * configures embedded switch (ESWITCH).
+ * Returns: Success(0) or error code.
+ *
+ **/
+static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	qlcnic_83xx_get_minidump_template(adapter);
+	if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {
+		if (qlcnic_init_pci_info(adapter))
+			return err;
+
+		if (qlcnic_83xx_set_vnic_opmode(adapter))
+			return err;
+
+		if (qlcnic_set_default_offload_settings(adapter))
+			return err;
+	} else {
+		if (qlcnic_reset_npar_config(adapter))
+			return err;
+	}
+
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+	qlcnic_83xx_enable_vnic_mode(adapter, 1);
+
+	dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n",
+		 adapter->ahw->fw_hal_version);
+
+	return 0;
+}
+
+static int qlcnic_83xx_init_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	qlcnic_83xx_get_minidump_template(adapter);
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+	dev_info(&adapter->pdev->dev,
+		 "HAL Version: %d, Privileged function\n",
+		 adapter->ahw->fw_hal_version);
+	return 0;
+}
+
+static int qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+	int err = -EIO;
+
+	qlcnic_83xx_get_fw_version(adapter);
+	if (qlcnic_set_eswitch_port_config(adapter))
+		return err;
+
+	if (qlcnic_83xx_get_port_info(adapter))
+		return err;
+
+	qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+	dev_info(&adapter->pdev->dev, "HAL Version: %d, Virtual function\n",
+		 adapter->ahw->fw_hal_version);
+
+	return 0;
+}
+
+/**
+ * qlcnic_83xx_vnic_opmode
+ *
+ * @adapter: adapter structure
+ * Identify virtual NIC operational modes.
+ *
+ * Returns: Success(0) or error code.
+ *
+ **/
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+	u32 op_mode, priv_level;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_nic_template *nic_ops = adapter->nic_ops;
+
+	qlcnic_get_func_no(adapter);
+	op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+	if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+		priv_level = QLCNIC_MGMT_FUNC;
+	else
+		priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+							 ahw->pci_func);
+
+	if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+		ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+		ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+		nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic;
+	} else if (priv_level == QLCNIC_PRIV_FUNC) {
+		ahw->op_mode = QLCNIC_PRIV_FUNC;
+		ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry;
+		nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic;
+	} else if (priv_level == QLCNIC_MGMT_FUNC) {
+		ahw->op_mode = QLCNIC_MGMT_FUNC;
+		ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+		nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic;
+	} else {
+		return -EIO;
+	}
+
+	if (ahw->capabilities & BIT_23)
+		adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+	else
+		adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+	adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+	adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index b14b8f0..a69097c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -1,12 +1,92 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
 
 #include "qlcnic.h"
 
+static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
+	{QLCNIC_CMD_CREATE_RX_CTX, 4, 1},
+	{QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
+	{QLCNIC_CMD_CREATE_TX_CTX, 4, 1},
+	{QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
+	{QLCNIC_CMD_INTRPT_TEST, 4, 1},
+	{QLCNIC_CMD_SET_MTU, 4, 1},
+	{QLCNIC_CMD_READ_PHY, 4, 2},
+	{QLCNIC_CMD_WRITE_PHY, 5, 1},
+	{QLCNIC_CMD_READ_HW_REG, 4, 1},
+	{QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
+	{QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
+	{QLCNIC_CMD_READ_MAX_MTU, 4, 2},
+	{QLCNIC_CMD_READ_MAX_LRO, 4, 2},
+	{QLCNIC_CMD_MAC_ADDRESS, 4, 3},
+	{QLCNIC_CMD_GET_PCI_INFO, 4, 1},
+	{QLCNIC_CMD_GET_NIC_INFO, 4, 1},
+	{QLCNIC_CMD_SET_NIC_INFO, 4, 1},
+	{QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
+	{QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
+	{QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
+	{QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
+	{QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
+	{QLCNIC_CMD_GET_MAC_STATS, 4, 1},
+	{QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
+	{QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
+	{QLCNIC_CMD_CONFIG_PORT, 4, 1},
+	{QLCNIC_CMD_TEMP_SIZE, 4, 4},
+	{QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
+	{QLCNIC_CMD_SET_DRV_VER, 4, 1},
+};
+
+static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
+{
+	return (ahw->pci_func & 0xff) | ((ahw->fw_hal_version & 0xff) << 8) |
+	       (0xcafe << 16);
+}
+
+/* Allocate mailbox registers */
+int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+			       struct qlcnic_adapter *adapter, u32 type)
+{
+	int i, size;
+	const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+	mbx_tbl = qlcnic_mbx_tbl;
+	size = ARRAY_SIZE(qlcnic_mbx_tbl);
+	for (i = 0; i < size; i++) {
+		if (type == mbx_tbl[i].cmd) {
+			mbx->req.num = mbx_tbl[i].in_args;
+			mbx->rsp.num = mbx_tbl[i].out_args;
+			mbx->req.arg = kcalloc(mbx->req.num,
+					       sizeof(u32), GFP_ATOMIC);
+			if (!mbx->req.arg)
+				return -ENOMEM;
+			mbx->rsp.arg = kcalloc(mbx->rsp.num,
+					       sizeof(u32), GFP_ATOMIC);
+			if (!mbx->rsp.arg) {
+				kfree(mbx->req.arg);
+				mbx->req.arg = NULL;
+				return -ENOMEM;
+			}
+			memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+			memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+			mbx->req.arg[0] = type;
+			break;
+		}
+	}
+	return 0;
+}
+
+/* Free up mailbox registers */
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd)
+{
+	kfree(cmd->req.arg);
+	cmd->req.arg = NULL;
+	kfree(cmd->rsp.arg);
+	cmd->rsp.arg = NULL;
+}
+
 static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
 {
 	int i;
@@ -38,194 +118,123 @@
 	return rsp;
 }
 
-void
-qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
+int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
+			  struct qlcnic_cmd_args *cmd)
 {
+	int i;
 	u32 rsp;
 	u32 signature;
 	struct pci_dev *pdev = adapter->pdev;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	const char *fmt;
 
-	signature = QLCNIC_CDRP_SIGNATURE_MAKE(ahw->pci_func,
-					       adapter->ahw->fw_hal_version);
+	signature = qlcnic_get_cmd_signature(ahw);
 
 	/* Acquire semaphore before accessing CRB */
 	if (qlcnic_api_lock(adapter)) {
-		cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
-		return;
+		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+		return cmd->rsp.arg[0];
 	}
 
 	QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
-	QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, cmd->req.arg1);
-	QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, cmd->req.arg2);
-	QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, cmd->req.arg3);
+	for (i = 1; i < QLCNIC_CDRP_MAX_ARGS; i++)
+		QLCWR32(adapter, QLCNIC_CDRP_ARG(i), cmd->req.arg[i]);
 	QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET,
-		QLCNIC_CDRP_FORM_CMD(cmd->req.cmd));
-
+		QLCNIC_CDRP_FORM_CMD(cmd->req.arg[0]));
 	rsp = qlcnic_poll_rsp(adapter);
 
 	if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
-		dev_err(&pdev->dev, "CDRP response timeout.\n");
-		cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
+		dev_err(&pdev->dev, "card response timeout.\n");
+		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
 	} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
-		cmd->rsp.cmd = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
-		switch (cmd->rsp.cmd) {
+		cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
+		switch (cmd->rsp.arg[0]) {
 		case QLCNIC_RCODE_INVALID_ARGS:
-			dev_err(&pdev->dev, "CDRP invalid args: 0x%x.\n",
-				cmd->rsp.cmd);
+			fmt = "CDRP invalid args: [%d]\n";
 			break;
 		case QLCNIC_RCODE_NOT_SUPPORTED:
 		case QLCNIC_RCODE_NOT_IMPL:
-			dev_err(&pdev->dev,
-				"CDRP command not supported: 0x%x.\n",
-				cmd->rsp.cmd);
+			fmt = "CDRP command not supported: [%d]\n";
 			break;
 		case QLCNIC_RCODE_NOT_PERMITTED:
-			dev_err(&pdev->dev,
-				"CDRP requested action not permitted: 0x%x.\n",
-				cmd->rsp.cmd);
+			fmt = "CDRP requested action not permitted: [%d]\n";
 			break;
 		case QLCNIC_RCODE_INVALID:
-			dev_err(&pdev->dev,
-				"CDRP invalid or unknown cmd received: 0x%x.\n",
-				cmd->rsp.cmd);
+			fmt = "CDRP invalid or unknown cmd received: [%d]\n";
 			break;
 		case QLCNIC_RCODE_TIMEOUT:
-			dev_err(&pdev->dev, "CDRP command timeout: 0x%x.\n",
-				cmd->rsp.cmd);
+			fmt = "CDRP command timeout: [%d]\n";
 			break;
 		default:
-			dev_err(&pdev->dev, "CDRP command failed: 0x%x.\n",
-				cmd->rsp.cmd);
+			fmt = "CDRP command failed: [%d]\n";
+			break;
 		}
-	} else if (rsp == QLCNIC_CDRP_RSP_OK) {
-		cmd->rsp.cmd = QLCNIC_RCODE_SUCCESS;
-		if (cmd->rsp.arg2)
-			cmd->rsp.arg2 = QLCRD32(adapter,
-				QLCNIC_ARG2_CRB_OFFSET);
-		if (cmd->rsp.arg3)
-			cmd->rsp.arg3 = QLCRD32(adapter,
-				QLCNIC_ARG3_CRB_OFFSET);
-	}
-	if (cmd->rsp.arg1)
-		cmd->rsp.arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+		dev_err(&pdev->dev, fmt, cmd->rsp.arg[0]);
+	} else if (rsp == QLCNIC_CDRP_RSP_OK)
+		cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
+
+	for (i = 1; i < cmd->rsp.num; i++)
+		cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
 
 	/* Release semaphore */
 	qlcnic_api_unlock(adapter);
-
+	return cmd->rsp.arg[0];
 }
 
-static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter)
 {
-	uint64_t sum = 0;
-	int count = temp_size / sizeof(uint32_t);
-	while (count-- > 0)
-		sum += *temp_buffer++;
-	while (sum >> 32)
-		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
-	return ~sum;
-}
-
-int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
-{
-	int err, i;
-	void *tmp_addr;
-	u32 temp_size, version, csum, *template;
-	__le32 *tmp_buf;
 	struct qlcnic_cmd_args cmd;
-	struct qlcnic_hardware_context *ahw;
-	struct qlcnic_dump_template_hdr *tmpl_hdr;
-	dma_addr_t tmp_addr_t = 0;
+	u32 arg1, arg2, arg3;
+	char drv_string[12];
+	int err = 0;
 
-	ahw = adapter->ahw;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_TEMP_SIZE;
-	memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
-	qlcnic_issue_cmd(adapter, &cmd);
-	if (cmd.rsp.cmd != QLCNIC_RCODE_SUCCESS) {
+	memset(drv_string, 0, sizeof(drv_string));
+	snprintf(drv_string, sizeof(drv_string), "%d"".""%d"".""%d",
+		 _QLCNIC_LINUX_MAJOR, _QLCNIC_LINUX_MINOR,
+		 _QLCNIC_LINUX_SUBVERSION);
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_DRV_VER);
+	memcpy(&arg1, drv_string, sizeof(u32));
+	memcpy(&arg2, drv_string + 4, sizeof(u32));
+	memcpy(&arg3, drv_string + 8, sizeof(u32));
+
+	cmd.req.arg[1] = arg1;
+	cmd.req.arg[2] = arg2;
+	cmd.req.arg[3] = arg3;
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err) {
 		dev_info(&adapter->pdev->dev,
-			"Can't get template size %d\n", cmd.rsp.cmd);
-		err = -EIO;
-		return err;
-	}
-	temp_size = cmd.rsp.arg2;
-	version = cmd.rsp.arg3;
-	dev_info(&adapter->pdev->dev,
-		 "minidump template version = 0x%x", version);
-	if (!temp_size)
+			 "Failed to set driver version in firmware\n");
 		return -EIO;
-
-	tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
-			&tmp_addr_t, GFP_KERNEL);
-	if (!tmp_addr) {
-		dev_err(&adapter->pdev->dev,
-			"Can't get memory for FW dump template\n");
-		return -ENOMEM;
-	}
-	memset(&cmd.rsp, 0, sizeof(struct _cdrp_cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_TEMP_HDR;
-	cmd.req.arg1 = LSD(tmp_addr_t);
-	cmd.req.arg2 = MSD(tmp_addr_t);
-	cmd.req.arg3 = temp_size;
-	qlcnic_issue_cmd(adapter, &cmd);
-
-	err = cmd.rsp.cmd;
-	if (err != QLCNIC_RCODE_SUCCESS) {
-		dev_err(&adapter->pdev->dev,
-			"Failed to get mini dump template header %d\n", err);
-		err = -EIO;
-		goto error;
-	}
-	ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
-	if (!ahw->fw_dump.tmpl_hdr) {
-		err = -EIO;
-		goto error;
-	}
-	tmp_buf = tmp_addr;
-	template = (u32 *) ahw->fw_dump.tmpl_hdr;
-	for (i = 0; i < temp_size/sizeof(u32); i++)
-		*template++ = __le32_to_cpu(*tmp_buf++);
-
-	csum = qlcnic_temp_checksum((u32 *)ahw->fw_dump.tmpl_hdr, temp_size);
-	if (csum) {
-		dev_err(&adapter->pdev->dev,
-			"Template header checksum validation failed\n");
-		err = -EIO;
-		goto error;
-	}
-
-	tmpl_hdr = ahw->fw_dump.tmpl_hdr;
-	tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
-	ahw->fw_dump.enable = 1;
-error:
-	dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
-	return err;
-}
-
-int
-qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
-{
-	struct qlcnic_cmd_args cmd;
-	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_SET_MTU;
-	cmd.req.arg1 = recv_ctx->context_id;
-	cmd.req.arg2 = mtu;
-	cmd.req.arg3 = 0;
-	if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
-		qlcnic_issue_cmd(adapter, &cmd);
-		if (cmd.rsp.cmd) {
-			dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
-			return -EIO;
-		}
 	}
 
 	return 0;
 }
 
-static int
-qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+int
+qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
+{
+	int err = 0;
+	struct qlcnic_cmd_args cmd;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+	if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE)
+		return err;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_MTU);
+	cmd.req.arg[1] = recv_ctx->context_id;
+	cmd.req.arg[2] = mtu;
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err) {
+		dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
+		err = -EIO;
+	}
+	qlcnic_free_mbx_args(&cmd);
+	return err;
+}
+
+int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 {
 	void *addr;
 	struct qlcnic_hostrq_rx_ctx *prq;
@@ -242,10 +251,10 @@
 	u64 phys_addr;
 
 	u8 i, nrds_rings, nsds_rings;
+	u16 temp_u16;
 	size_t rq_size, rsp_size;
 	u32 cap, reg, val, reg2;
 	int err;
-	u16 temp;
 
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
@@ -279,11 +288,8 @@
 						| QLCNIC_CAP0_VALIDOFF);
 	cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
 
-	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
-		cap |= QLCNIC_CAP0_LRO_MSS;
-
-	temp = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
-	prq->valid_field_offset = cpu_to_le16(temp);
+	temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
+	prq->valid_field_offset = cpu_to_le16(temp_u16);
 	prq->txrx_sds_binding = nsds_rings - 1;
 
 	prq->capabilities[0] = cpu_to_le32(cap);
@@ -329,20 +335,17 @@
 	}
 
 	phys_addr = hostrq_phys_addr;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.arg1 = (u32) (phys_addr >> 32);
-	cmd.req.arg2 = (u32) (phys_addr & 0xffffffff);
-	cmd.req.arg3 = rq_size;
-	cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_RX_CTX;
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX);
+	cmd.req.arg[1] = MSD(phys_addr);
+	cmd.req.arg[2] = LSD(phys_addr);
+	cmd.req.arg[3] = rq_size;
+	err = qlcnic_issue_cmd(adapter, &cmd);
 	if (err) {
 		dev_err(&adapter->pdev->dev,
 			"Failed to create rx ctx in firmware%d\n", err);
 		goto out_free_rsp;
 	}
 
-
 	prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
 			 &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
 
@@ -373,6 +376,7 @@
 out_free_rsp:
 	dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
 		cardrsp_phys_addr);
+	qlcnic_free_mbx_args(&cmd);
 out_free_rq:
 	dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
 	return err;
@@ -381,24 +385,24 @@
 static void
 qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
 {
+	int err;
 	struct qlcnic_cmd_args cmd;
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.arg1 = recv_ctx->context_id;
-	cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
-	cmd.req.arg3 = 0;
-	cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_RX_CTX;
-	qlcnic_issue_cmd(adapter, &cmd);
-	if (cmd.rsp.cmd)
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX);
+	cmd.req.arg[1] = recv_ctx->context_id;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err)
 		dev_err(&adapter->pdev->dev,
 			"Failed to destroy rx ctx in firmware\n");
 
 	recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
+	qlcnic_free_mbx_args(&cmd);
 }
 
-static int
-qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+				     struct qlcnic_host_tx_ring *tx_ring,
+				     int ring)
 {
 	struct qlcnic_hostrq_tx_ctx	*prq;
 	struct qlcnic_hostrq_cds_ring	*prq_cds;
@@ -410,7 +414,6 @@
 	int	err;
 	u64	phys_addr;
 	dma_addr_t	rq_phys_addr, rsp_phys_addr;
-	struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
 	/* reset host resources */
 	tx_ring->producer = 0;
@@ -445,9 +448,9 @@
 
 	prq->host_int_crb_mode =
 		cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+	prq->msi_index = 0;
 
 	prq->interrupt_ctl = 0;
-	prq->msi_index = 0;
 	prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
 
 	prq_cds = &prq->cds_ring;
@@ -456,19 +459,17 @@
 	prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
 
 	phys_addr = rq_phys_addr;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.arg1 = (u32)(phys_addr >> 32);
-	cmd.req.arg2 = ((u32)phys_addr & 0xffffffff);
-	cmd.req.arg3 = rq_size;
-	cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_TX_CTX;
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+	cmd.req.arg[1] = MSD(phys_addr);
+	cmd.req.arg[2] = LSD(phys_addr);
+	cmd.req.arg[3] = rq_size;
+	err = qlcnic_issue_cmd(adapter, &cmd);
 
 	if (err == QLCNIC_RCODE_SUCCESS) {
 		temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
 		tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
-
-		adapter->tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
+		tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
 	} else {
 		dev_err(&adapter->pdev->dev,
 			"Failed to create tx ctx in firmware%d\n", err);
@@ -476,77 +477,82 @@
 	}
 
 	dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr,
-		rsp_phys_addr);
+			  rsp_phys_addr);
 
 out_free_rq:
 	dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
+	qlcnic_free_mbx_args(&cmd);
 
 	return err;
 }
 
 static void
-qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
+qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter,
+			     struct qlcnic_host_tx_ring *tx_ring)
 {
 	struct qlcnic_cmd_args cmd;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.arg1 = adapter->tx_ring->ctx_id;
-	cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
-	cmd.req.arg3 = 0;
-	cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_TX_CTX;
-	qlcnic_issue_cmd(adapter, &cmd);
-	if (cmd.rsp.cmd)
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
+	cmd.req.arg[1] = tx_ring->ctx_id;
+	if (qlcnic_issue_cmd(adapter, &cmd))
 		dev_err(&adapter->pdev->dev,
 			"Failed to destroy tx ctx in firmware\n");
+	qlcnic_free_mbx_args(&cmd);
 }
 
 int
 qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
 {
+	int err;
 	struct qlcnic_cmd_args cmd;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.arg1 = config;
-	cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIG_PORT;
-	qlcnic_issue_cmd(adapter, &cmd);
-
-	return cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_PORT);
+	cmd.req.arg[1] = config;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	qlcnic_free_mbx_args(&cmd);
+	return err;
 }
 
 int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
 {
 	void *addr;
-	int err;
-	int ring;
+	int err, ring;
 	struct qlcnic_recv_context *recv_ctx;
 	struct qlcnic_host_rds_ring *rds_ring;
 	struct qlcnic_host_sds_ring *sds_ring;
 	struct qlcnic_host_tx_ring *tx_ring;
+	__le32 *ptr;
 
 	struct pci_dev *pdev = adapter->pdev;
 
 	recv_ctx = adapter->recv_ctx;
-	tx_ring = adapter->tx_ring;
 
-	tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev,
-		sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL);
-	if (tx_ring->hw_consumer == NULL) {
-		dev_err(&pdev->dev, "failed to allocate tx consumer\n");
-		return -ENOMEM;
+	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+		tx_ring = &adapter->tx_ring[ring];
+		ptr = (__le32 *)dma_alloc_coherent(&pdev->dev, sizeof(u32),
+						   &tx_ring->hw_cons_phys_addr,
+						   GFP_KERNEL);
+
+		if (ptr == NULL) {
+			dev_err(&pdev->dev, "failed to allocate tx consumer\n");
+			return -ENOMEM;
+		}
+		tx_ring->hw_consumer = ptr;
+		/* cmd desc ring */
+		addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
+					  &tx_ring->phys_addr,
+					  GFP_KERNEL);
+
+		if (addr == NULL) {
+			dev_err(&pdev->dev,
+				"failed to allocate tx desc ring\n");
+			err = -ENOMEM;
+			goto err_out_free;
+		}
+
+		tx_ring->desc_head = addr;
 	}
 
-	/* cmd desc ring */
-	addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
-			&tx_ring->phys_addr, GFP_KERNEL);
-
-	if (addr == NULL) {
-		dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
-		err = -ENOMEM;
-		goto err_out_free;
-	}
-
-	tx_ring->desc_head = addr;
-
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
 		rds_ring = &recv_ctx->rds_rings[ring];
 		addr = dma_alloc_coherent(&adapter->pdev->dev,
@@ -584,36 +590,70 @@
 	return err;
 }
 
-
-int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
 {
-	int err;
+	int i, err, ring;
 
-	if (adapter->flags & QLCNIC_NEED_FLR) {
-		pci_reset_function(adapter->pdev);
-		adapter->flags &= ~QLCNIC_NEED_FLR;
+	if (dev->flags & QLCNIC_NEED_FLR) {
+		pci_reset_function(dev->pdev);
+		dev->flags &= ~QLCNIC_NEED_FLR;
 	}
 
-	err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+	if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
+		if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+			err = qlcnic_83xx_config_intrpt(dev, 1);
+			if (err)
+				return err;
+		}
+	}
+
+	err = qlcnic_fw_cmd_create_rx_ctx(dev);
 	if (err)
-		return err;
+		goto err_out;
 
-	err = qlcnic_fw_cmd_create_tx_ctx(adapter);
-	if (err) {
-		qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-		return err;
+	for (ring = 0; ring < dev->max_drv_tx_rings; ring++) {
+		err = qlcnic_fw_cmd_create_tx_ctx(dev,
+						  &dev->tx_ring[ring],
+						  ring);
+		if (err) {
+			qlcnic_fw_cmd_destroy_rx_ctx(dev);
+			if (ring == 0)
+				goto err_out;
+
+			for (i = 0; i < ring; i++)
+				qlcnic_fw_cmd_destroy_tx_ctx(dev,
+							     &dev->tx_ring[i]);
+
+			goto err_out;
+		}
 	}
 
-	set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+	set_bit(__QLCNIC_FW_ATTACHED, &dev->state);
 	return 0;
+
+err_out:
+	if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
+		if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+			qlcnic_83xx_config_intrpt(dev, 0);
+	}
+	return err;
 }
 
 void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
 {
+	int ring;
+
 	if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
 		qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-		qlcnic_fw_cmd_destroy_tx_ctx(adapter);
+		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
+			qlcnic_fw_cmd_destroy_tx_ctx(adapter,
+						     &adapter->tx_ring[ring]);
 
+		if (qlcnic_83xx_check(adapter) &&
+		    (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+			if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+				qlcnic_83xx_config_intrpt(adapter, 0);
+		}
 		/* Allow dma queues to drain after context reset */
 		mdelay(20);
 	}
@@ -629,20 +669,23 @@
 
 	recv_ctx = adapter->recv_ctx;
 
-	tx_ring = adapter->tx_ring;
-	if (tx_ring->hw_consumer != NULL) {
-		dma_free_coherent(&adapter->pdev->dev,
-				sizeof(u32),
-				tx_ring->hw_consumer,
-				tx_ring->hw_cons_phys_addr);
-		tx_ring->hw_consumer = NULL;
-	}
+	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+		tx_ring = &adapter->tx_ring[ring];
+		if (tx_ring->hw_consumer != NULL) {
+			dma_free_coherent(&adapter->pdev->dev, sizeof(u32),
+					  tx_ring->hw_consumer,
+					  tx_ring->hw_cons_phys_addr);
 
-	if (tx_ring->desc_head != NULL) {
-		dma_free_coherent(&adapter->pdev->dev,
-				TX_DESC_RINGSIZE(tx_ring),
-				tx_ring->desc_head, tx_ring->phys_addr);
-		tx_ring->desc_head = NULL;
+			tx_ring->hw_consumer = NULL;
+		}
+
+		if (tx_ring->desc_head != NULL) {
+			dma_free_coherent(&adapter->pdev->dev,
+					  TX_DESC_RINGSIZE(tx_ring),
+					  tx_ring->desc_head,
+					  tx_ring->phys_addr);
+			tx_ring->desc_head = NULL;
+		}
 	}
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
@@ -671,40 +714,43 @@
 }
 
 
-/* Get MAC address of a NIC partition */
-int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
 {
-	int err;
+	int err, i;
 	struct qlcnic_cmd_args cmd;
+	u32 mac_low, mac_high;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.arg1 = adapter->ahw->pci_func | BIT_8;
-	cmd.req.cmd = QLCNIC_CDRP_CMD_MAC_ADDRESS;
-	cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+	cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
+	err = qlcnic_issue_cmd(adapter, &cmd);
 
-	if (err == QLCNIC_RCODE_SUCCESS)
-		qlcnic_fetch_mac(cmd.rsp.arg1, cmd.rsp.arg2, 0, mac);
-	else {
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		mac_low = cmd.rsp.arg[1];
+		mac_high = cmd.rsp.arg[2];
+
+		for (i = 0; i < 2; i++)
+			mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+		for (i = 2; i < 6; i++)
+			mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+	} else {
 		dev_err(&adapter->pdev->dev,
 			"Failed to get mac address%d\n", err);
 		err = -EIO;
 	}
-
+	qlcnic_free_mbx_args(&cmd);
 	return err;
 }
 
 /* Get info of a NIC partition */
-int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
-				struct qlcnic_info *npar_info, u8 func_id)
+int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
+			     struct qlcnic_info *npar_info, u8 func_id)
 {
 	int	err;
 	dma_addr_t nic_dma_t;
-	struct qlcnic_info_le *nic_info;
+	const struct qlcnic_info_le *nic_info;
 	void *nic_info_addr;
 	struct qlcnic_cmd_args cmd;
-	size_t	nic_size = sizeof(struct qlcnic_info_le);
+	size_t  nic_size = sizeof(struct qlcnic_info_le);
 
 	nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
 				&nic_dma_t, GFP_KERNEL);
@@ -713,47 +759,39 @@
 	memset(nic_info_addr, 0, nic_size);
 
 	nic_info = nic_info_addr;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_NIC_INFO;
-	cmd.req.arg1 = MSD(nic_dma_t);
-	cmd.req.arg2 = LSD(nic_dma_t);
-	cmd.req.arg3 = (func_id << 16 | nic_size);
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
 
-	if (err == QLCNIC_RCODE_SUCCESS) {
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+	cmd.req.arg[1] = MSD(nic_dma_t);
+	cmd.req.arg[2] = LSD(nic_dma_t);
+	cmd.req.arg[3] = (func_id << 16 | nic_size);
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		dev_err(&adapter->pdev->dev,
+			"Failed to get nic info%d\n", err);
+		err = -EIO;
+	} else {
 		npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
 		npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+		npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+		npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
 		npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
 		npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
 		npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
 		npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
-		npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
-		npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
 		npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
 		npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
-
-		dev_info(&adapter->pdev->dev,
-			"phy port: %d switch_mode: %d,\n"
-			"\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
-			"\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
-			npar_info->phys_port, npar_info->switch_mode,
-			npar_info->max_tx_ques, npar_info->max_rx_ques,
-			npar_info->min_tx_bw, npar_info->max_tx_bw,
-			npar_info->max_mtu, npar_info->capabilities);
-	} else {
-		dev_err(&adapter->pdev->dev,
-			"Failed to get nic info%d\n", err);
-		err = -EIO;
 	}
 
 	dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
-		nic_dma_t);
+			  nic_dma_t);
+	qlcnic_free_mbx_args(&cmd);
+
 	return err;
 }
 
 /* Configure a NIC partition */
-int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
+			     struct qlcnic_info *nic)
 {
 	int err = -EIO;
 	dma_addr_t nic_dma_t;
@@ -784,13 +822,11 @@
 	nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
 	nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_SET_NIC_INFO;
-	cmd.req.arg1 = MSD(nic_dma_t);
-	cmd.req.arg2 = LSD(nic_dma_t);
-	cmd.req.arg3 = ((nic->pci_func << 16) | nic_size);
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+	cmd.req.arg[1] = MSD(nic_dma_t);
+	cmd.req.arg[2] = LSD(nic_dma_t);
+	cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size);
+	err = qlcnic_issue_cmd(adapter, &cmd);
 
 	if (err != QLCNIC_RCODE_SUCCESS) {
 		dev_err(&adapter->pdev->dev,
@@ -800,12 +836,14 @@
 
 	dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
 		nic_dma_t);
+	qlcnic_free_mbx_args(&cmd);
+
 	return err;
 }
 
 /* Get PCI Info of a partition */
-int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
-				struct qlcnic_pci_info *pci_info)
+int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
+			     struct qlcnic_pci_info *pci_info)
 {
 	int err = 0, i;
 	struct qlcnic_cmd_args cmd;
@@ -822,13 +860,11 @@
 	memset(pci_info_addr, 0, pci_size);
 
 	npar = pci_info_addr;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_PCI_INFO;
-	cmd.req.arg1 = MSD(pci_info_dma_t);
-	cmd.req.arg2 = LSD(pci_info_dma_t);
-	cmd.req.arg3 = pci_size;
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+	cmd.req.arg[1] = MSD(pci_info_dma_t);
+	cmd.req.arg[2] = LSD(pci_info_dma_t);
+	cmd.req.arg[3] = pci_size;
+	err = qlcnic_issue_cmd(adapter, &cmd);
 
 	adapter->ahw->act_pci_func = 0;
 	if (err == QLCNIC_RCODE_SUCCESS) {
@@ -854,6 +890,8 @@
 
 	dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
 		pci_info_dma_t);
+	qlcnic_free_mbx_args(&cmd);
+
 	return err;
 }
 
@@ -872,21 +910,19 @@
 	arg1 = id | (enable_mirroring ? BIT_4 : 0);
 	arg1 |= pci_func << 8;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_SET_PORTMIRRORING;
-	cmd.req.arg1 = arg1;
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORTMIRRORING);
+	cmd.req.arg[1] = arg1;
+	err = qlcnic_issue_cmd(adapter, &cmd);
 
-	if (err != QLCNIC_RCODE_SUCCESS) {
+	if (err != QLCNIC_RCODE_SUCCESS)
 		dev_err(&adapter->pdev->dev,
 			"Failed to configure port mirroring%d on eswitch:%d\n",
 			pci_func, id);
-	} else {
+	else
 		dev_info(&adapter->pdev->dev,
 			"Configured eSwitch %d for port mirroring:%d\n",
 			id, pci_func);
-	}
+	qlcnic_free_mbx_args(&cmd);
 
 	return err;
 }
@@ -923,13 +959,11 @@
 	arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
 	arg1 |= rx_tx << 15 | stats_size << 16;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
-	cmd.req.arg1 = arg1;
-	cmd.req.arg2 = MSD(stats_dma_t);
-	cmd.req.arg3 = LSD(stats_dma_t);
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+	cmd.req.arg[1] = arg1;
+	cmd.req.arg[2] = MSD(stats_dma_t);
+	cmd.req.arg[3] = LSD(stats_dma_t);
+	err = qlcnic_issue_cmd(adapter, &cmd);
 
 	if (!err) {
 		stats = stats_addr;
@@ -949,6 +983,8 @@
 
 	dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
 		stats_dma_t);
+	qlcnic_free_mbx_args(&cmd);
+
 	return err;
 }
 
@@ -963,6 +999,9 @@
 	void *stats_addr;
 	int err;
 
+	if (mac_stats == NULL)
+		return -ENOMEM;
+
 	stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
 			&stats_dma_t, GFP_KERNEL);
 	if (!stats_addr) {
@@ -971,15 +1010,11 @@
 		return -ENOMEM;
 	}
 	memset(stats_addr, 0, stats_size);
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS;
-	cmd.req.arg1 = stats_size << 16;
-	cmd.req.arg2 = MSD(stats_dma_t);
-	cmd.req.arg3 = LSD(stats_dma_t);
-
-	qlcnic_issue_cmd(adapter, &cmd);
-	err = cmd.rsp.cmd;
-
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
+	cmd.req.arg[1] = stats_size << 16;
+	cmd.req.arg[2] = MSD(stats_dma_t);
+	cmd.req.arg[3] = LSD(stats_dma_t);
+	err = qlcnic_issue_cmd(adapter, &cmd);
 	if (!err) {
 		stats = stats_addr;
 		mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames);
@@ -1001,10 +1036,16 @@
 		mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
 		mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
 		mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
+	} else {
+		dev_err(&adapter->pdev->dev,
+			"%s: Get mac stats failed, err=%d.\n", __func__, err);
 	}
 
 	dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
 		stats_dma_t);
+
+	qlcnic_free_mbx_args(&cmd);
+
 	return err;
 }
 
@@ -1065,7 +1106,7 @@
 int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
 		const u8 port, const u8 rx_tx)
 {
-
+	int err;
 	u32 arg1;
 	struct qlcnic_cmd_args cmd;
 
@@ -1088,15 +1129,16 @@
 	arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
 	arg1 |= BIT_14 | rx_tx << 15;
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
-	cmd.req.arg1 = arg1;
-	qlcnic_issue_cmd(adapter, &cmd);
-	return cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+	cmd.req.arg[1] = arg1;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	qlcnic_free_mbx_args(&cmd);
+	return err;
 
 err_ret:
-	dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
-		"rx_ctx=%d\n", func_esw, port, rx_tx);
+	dev_err(&adapter->pdev->dev,
+		"Invalid args func_esw %d port %d rx_ctx %d\n",
+		func_esw, port, rx_tx);
 	return -EIO;
 }
 
@@ -1109,22 +1151,21 @@
 	u8 pci_func;
 	pci_func = (*arg1 >> 8);
 
-	cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG;
-	cmd.req.arg1 = *arg1;
-	cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
-	qlcnic_issue_cmd(adapter, &cmd);
-	*arg1 = cmd.rsp.arg1;
-	*arg2 = cmd.rsp.arg2;
-	err = cmd.rsp.cmd;
+	qlcnic_alloc_mbx_args(&cmd, adapter,
+			      QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
+	cmd.req.arg[1] = *arg1;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	*arg1 = cmd.rsp.arg[1];
+	*arg2 = cmd.rsp.arg[2];
+	qlcnic_free_mbx_args(&cmd);
 
-	if (err == QLCNIC_RCODE_SUCCESS) {
+	if (err == QLCNIC_RCODE_SUCCESS)
 		dev_info(&adapter->pdev->dev,
-			"eSwitch port config for pci func %d\n", pci_func);
-	} else {
+			 "eSwitch port config for pci func %d\n", pci_func);
+	else
 		dev_err(&adapter->pdev->dev,
 			"Failed to get eswitch port config for pci func %d\n",
 								pci_func);
-	}
 	return err;
 }
 /* Configure eSwitch port
@@ -1189,20 +1230,18 @@
 		return err;
 	}
 
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH;
-	cmd.req.arg1 = arg1;
-	cmd.req.arg2 = arg2;
-	qlcnic_issue_cmd(adapter, &cmd);
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_ESWITCH);
+	cmd.req.arg[1] = arg1;
+	cmd.req.arg[2] = arg2;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	qlcnic_free_mbx_args(&cmd);
 
-	err = cmd.rsp.cmd;
-	if (err != QLCNIC_RCODE_SUCCESS) {
+	if (err != QLCNIC_RCODE_SUCCESS)
 		dev_err(&adapter->pdev->dev,
 			"Failed to configure eswitch pci func %d\n", pci_func);
-	} else {
+	else
 		dev_info(&adapter->pdev->dev,
-			"Configured eSwitch for pci func %d\n", pci_func);
-	}
+			 "Configured eSwitch for pci func %d\n", pci_func);
 
 	return err;
 }
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 74b9811..5641f8e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -1,6 +1,6 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
@@ -22,42 +22,37 @@
 
 #define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
 #define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
+static const u32 qlcnic_fw_dump_level[] = {
+	0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
+};
 
 static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
-	{"xmit_called",
-		QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
-	{"xmit_finished",
-		QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
-	{"rx_dropped",
-		QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
-	{"tx_dropped",
-		QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
-	{"csummed",
-		QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
-	{"rx_pkts",
-		QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
-	{"lro_pkts",
-		QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
-	{"rx_bytes",
-		QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
-	{"tx_bytes",
-		QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
-	{"lrobytes",
-		QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
-	{"lso_frames",
-		QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
-	{"xmit_on",
-		QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
-	{"xmit_off",
-		QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
+	{"xmit_called", QLC_SIZEOF(stats.xmitcalled),
+		QLC_OFF(stats.xmitcalled)},
+	{"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
+		QLC_OFF(stats.xmitfinished)},
+	{"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+	{"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
+	{"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+	{"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
+	{"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
+	{"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
+	{"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
+	{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
+	{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
+	{"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
+	{"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
 	{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
-		QLC_OFF(stats.skb_alloc_failure)},
-	{"null rxbuf",
-		QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
+	 QLC_OFF(stats.skb_alloc_failure)},
+	{"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
 	{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
 					 QLC_OFF(stats.rx_dma_map_error)},
 	{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
 					 QLC_OFF(stats.tx_dma_map_error)},
+	{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
+				QLC_OFF(stats.mac_filter_limit_overrun)},
+	{"spurious intr", QLC_SIZEOF(stats.spurious_intr),
+	 QLC_OFF(stats.spurious_intr)},
 
 };
 
@@ -78,7 +73,15 @@
 	"tx numbytes",
 };
 
-static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
+static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
+	"ctx_tx_bytes",
+	"ctx_tx_pkts",
+	"ctx_tx_errors",
+	"ctx_tx_dropped_pkts",
+	"ctx_tx_num_buffers",
+};
+
+static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
 	"mac_tx_frames",
 	"mac_tx_bytes",
 	"mac_tx_mcast_pkts",
@@ -110,35 +113,70 @@
 	"mac_rx_length_large",
 	"mac_rx_jabber",
 	"mac_rx_dropped",
-	"mac_rx_crc_error",
+	"mac_crc_error",
 	"mac_align_error",
 };
 
-#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
-#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
-#define QLCNIC_DEVICE_STATS_LEN	ARRAY_SIZE(qlcnic_device_gstrings_stats)
-#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
+#define QLCNIC_STATS_LEN	ARRAY_SIZE(qlcnic_gstrings_stats)
+static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
+	"ctx_rx_bytes",
+	"ctx_rx_pkts",
+	"ctx_lro_pkt_cnt",
+	"ctx_ip_csum_error",
+	"ctx_rx_pkts_wo_ctx",
+	"ctx_rx_pkts_dropped_wo_sts",
+	"ctx_rx_osized_pkts",
+	"ctx_rx_pkts_dropped_wo_rds",
+	"ctx_rx_unexpected_mcast_pkts",
+	"ctx_invalid_mac_address",
+	"ctx_rx_rds_ring_prim_attemoted",
+	"ctx_rx_rds_ring_prim_success",
+	"ctx_num_lro_flows_added",
+	"ctx_num_lro_flows_removed",
+	"ctx_num_lro_flows_active",
+	"ctx_pkts_dropped_unknown",
+};
 
 static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register_Test_on_offline",
 	"Link_Test_on_offline",
 	"Interrupt_Test_offline",
 	"Internal_Loopback_offline",
-	"External_Loopback_offline"
+	"EEPROM_Test_offline"
 };
 
 #define QLCNIC_TEST_LEN	ARRAY_SIZE(qlcnic_gstrings_test)
 
+static inline int qlcnic_82xx_statistics(void)
+{
+	return QLCNIC_STATS_LEN + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+}
+
+static inline int qlcnic_83xx_statistics(void)
+{
+	return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
+	       ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
+	       ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+}
+
+static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
+{
+	if (qlcnic_82xx_check(adapter))
+		return qlcnic_82xx_statistics();
+	else if (qlcnic_83xx_check(adapter))
+		return qlcnic_83xx_statistics();
+	else
+		return -1;
+}
+
 #define QLCNIC_RING_REGS_COUNT	20
 #define QLCNIC_RING_REGS_LEN	(QLCNIC_RING_REGS_COUNT * sizeof(u32))
 #define QLCNIC_MAX_EEPROM_LEN   1024
 
 static const u32 diag_registers[] = {
-	CRB_CMDPEG_STATE,
-	CRB_RCVPEG_STATE,
-	CRB_XG_STATE_P3P,
-	CRB_FW_CAPABILITIES_1,
-	ISR_INT_STATE_REG,
+	QLCNIC_CMDPEG_STATE,
+	QLCNIC_RCVPEG_STATE,
+	QLCNIC_FW_CAPABILITIES,
 	QLCNIC_CRB_DRV_ACTIVE,
 	QLCNIC_CRB_DEV_STATE,
 	QLCNIC_CRB_DRV_STATE,
@@ -148,6 +186,13 @@
 	QLCNIC_PEG_ALIVE_COUNTER,
 	QLCNIC_PEG_HALT_STATUS1,
 	QLCNIC_PEG_HALT_STATUS2,
+	-1
+};
+
+
+static const u32 ext_diag_registers[] = {
+	CRB_XG_STATE_P3P,
+	ISR_INT_STATE_REG,
 	QLCNIC_CRB_PEG_NET_0+0x3c,
 	QLCNIC_CRB_PEG_NET_1+0x3c,
 	QLCNIC_CRB_PEG_NET_2+0x3c,
@@ -156,12 +201,19 @@
 };
 
 #define QLCNIC_MGMT_API_VERSION	2
-#define QLCNIC_DEV_INFO_SIZE	1
-#define QLCNIC_ETHTOOL_REGS_VER	2
+#define QLCNIC_ETHTOOL_REGS_VER	3
+
 static int qlcnic_get_regs_len(struct net_device *dev)
 {
-	return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
-				QLCNIC_DEV_INFO_SIZE + 1;
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+	u32 len;
+
+	if (qlcnic_83xx_check(adapter))
+		len = qlcnic_83xx_get_regs_len(adapter);
+	else
+		len = sizeof(ext_diag_registers) + sizeof(diag_registers);
+
+	return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
 }
 
 static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -174,10 +226,9 @@
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 fw_major, fw_minor, fw_build;
-
-	fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
-	fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
-	fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+	fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+	fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+	fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
 		"%d.%d.%d", fw_major, fw_minor, fw_build);
 
@@ -192,7 +243,10 @@
 qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	u32 speed, reg;
 	int check_sfp_module = 0;
+	u16 pcifn = ahw->pci_func;
 
 	/* read which mode */
 	if (adapter->ahw->port_type == QLCNIC_GBE) {
@@ -213,9 +267,12 @@
 		ecmd->autoneg = adapter->ahw->link_autoneg;
 
 	} else if (adapter->ahw->port_type == QLCNIC_XGBE) {
-		u32 val;
+		u32 val = 0;
+		if (qlcnic_83xx_check(adapter))
+			qlcnic_83xx_get_settings(adapter);
+		else
+			val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
 
-		val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
 		if (val == QLCNIC_PORT_MODE_802_3_AP) {
 			ecmd->supported = SUPPORTED_1000baseT_Full;
 			ecmd->advertising = ADVERTISED_1000baseT_Full;
@@ -225,6 +282,12 @@
 		}
 
 		if (netif_running(dev) && adapter->ahw->has_link_events) {
+			if (qlcnic_82xx_check(adapter)) {
+				reg = QLCRD32(adapter,
+					      P3P_LINK_SPEED_REG(pcifn));
+				speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+				ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+			}
 			ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
 			ecmd->autoneg = adapter->ahw->link_autoneg;
 			ecmd->duplex = adapter->ahw->link_duplex;
@@ -294,6 +357,13 @@
 			ecmd->port = PORT_TP;
 		}
 		break;
+	case QLCNIC_BRDTYPE_83XX_10G:
+		ecmd->autoneg = AUTONEG_DISABLE;
+		ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+		ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
+		ecmd->port = PORT_FIBRE;
+		check_sfp_module = netif_running(dev) && ahw->has_link_events;
+		break;
 	default:
 		dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
 			adapter->ahw->board_type);
@@ -321,16 +391,10 @@
 	return 0;
 }
 
-static int
-qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
+				  struct ethtool_cmd *ecmd)
 {
-	u32 config = 0;
-	u32 ret = 0;
-	struct qlcnic_adapter *adapter = netdev_priv(dev);
-
-	if (adapter->ahw->port_type != QLCNIC_GBE)
-		return -EOPNOTSUPP;
-
+	u32 ret = 0, config = 0;
 	/* read which mode */
 	if (ecmd->duplex)
 		config |= 0x1;
@@ -358,6 +422,24 @@
 		return -EOPNOTSUPP;
 	else if (ret)
 		return -EIO;
+	return ret;
+}
+
+static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u32 ret = 0;
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+	if (adapter->ahw->port_type != QLCNIC_GBE)
+		return -EOPNOTSUPP;
+
+	if (qlcnic_83xx_check(adapter))
+		ret = qlcnic_83xx_set_settings(adapter, ecmd);
+	else
+		ret = qlcnic_set_port_config(adapter, ecmd);
+
+	if (!ret)
+		return ret;
 
 	adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
 	adapter->ahw->link_duplex = ecmd->duplex;
@@ -370,6 +452,19 @@
 	return dev->netdev_ops->ndo_open(dev);
 }
 
+static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
+				     u32 *regs_buff)
+{
+	int i, j = 0;
+
+	for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
+		regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
+	j = 0;
+	while (ext_diag_registers[j] != -1)
+		regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
+	return i;
+}
+
 static void
 qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 {
@@ -377,17 +472,20 @@
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 	struct qlcnic_host_sds_ring *sds_ring;
 	u32 *regs_buff = p;
-	int ring, i = 0, j = 0;
+	int ring, i = 0;
 
 	memset(p, 0, qlcnic_get_regs_len(dev));
+
 	regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
 		(adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
 
 	regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
 	regs_buff[1] = QLCNIC_MGMT_API_VERSION;
 
-	for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
-		regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
+	if (qlcnic_82xx_check(adapter))
+		i = qlcnic_82xx_get_registers(adapter, regs_buff);
+	else
+		i = qlcnic_83xx_get_registers(adapter, regs_buff);
 
 	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
 		return;
@@ -415,6 +513,10 @@
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 val;
 
+	if (qlcnic_83xx_check(adapter)) {
+		val = qlcnic_83xx_test_link(adapter);
+		return (val & 1) ? 0 : 1;
+	}
 	val = QLCRD32(adapter, CRB_XG_STATE_P3P);
 	val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
 	return (val == XG_LINK_UP_P3P) ? 0 : 1;
@@ -426,8 +528,10 @@
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	int offset;
-	int ret;
+	int ret = -1;
 
+	if (qlcnic_83xx_check(adapter))
+		return 0;
 	if (eeprom->len == 0)
 		return -EINVAL;
 
@@ -435,8 +539,9 @@
 			((adapter->pdev)->device << 16);
 	offset = eeprom->offset;
 
-	ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
-						eeprom->len);
+	if (qlcnic_82xx_check(adapter))
+		ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+						 eeprom->len);
 	if (ret < 0)
 		return ret;
 
@@ -529,11 +634,11 @@
 	    channel->tx_count != channel->max_tx)
 		return -EINVAL;
 
-	err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
+	err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
 	if (err)
 		return err;
 
-	err = qlcnic_set_max_rss(adapter, channel->rx_count);
+	err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
 	netdev_info(dev, "allocated 0x%x sds rings\n",
 				 adapter->max_sds_rings);
 	return err;
@@ -547,6 +652,10 @@
 	int port = adapter->ahw->physical_port;
 	__u32 val;
 
+	if (qlcnic_83xx_check(adapter)) {
+		qlcnic_83xx_get_pauseparam(adapter, pause);
+		return;
+	}
 	if (adapter->ahw->port_type == QLCNIC_GBE) {
 		if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
 			return;
@@ -592,6 +701,9 @@
 	int port = adapter->ahw->physical_port;
 	__u32 val;
 
+	if (qlcnic_83xx_check(adapter))
+		return qlcnic_83xx_set_pauseparam(adapter, pause);
+
 	/* read mode */
 	if (adapter->ahw->port_type == QLCNIC_GBE) {
 		if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
@@ -606,6 +718,7 @@
 
 		QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
 				val);
+		QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
 		/* set autoneg */
 		val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
 		switch (port) {
@@ -668,6 +781,9 @@
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 data_read;
 
+	if (qlcnic_83xx_check(adapter))
+		return qlcnic_83xx_reg_test(adapter);
+
 	data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
 	if ((data_read & 0xffff) != adapter->pdev->vendor)
 		return 1;
@@ -675,16 +791,30 @@
 	return 0;
 }
 
+static int qlcnic_eeprom_test(struct net_device *dev)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+	if (qlcnic_82xx_check(adapter))
+		return 0;
+
+	return qlcnic_83xx_flash_test(adapter);
+}
+
 static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 {
+	int len;
+
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	switch (sset) {
 	case ETH_SS_TEST:
 		return QLCNIC_TEST_LEN;
 	case ETH_SS_STATS:
-		if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-			return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
-		return QLCNIC_TOTAL_STATS_LEN;
+		len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
+		if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+		    qlcnic_83xx_check(adapter))
+			return len;
+		return qlcnic_82xx_statistics();
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -693,35 +823,36 @@
 static int qlcnic_irq_test(struct net_device *netdev)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
-	int max_sds_rings = adapter->max_sds_rings;
-	int ret;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	struct qlcnic_cmd_args cmd;
+	int ret, max_sds_rings = adapter->max_sds_rings;
+
+	if (qlcnic_83xx_check(adapter))
+		return qlcnic_83xx_interrupt_test(netdev);
 
 	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
 		return -EIO;
 
 	ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
 	if (ret)
-		goto clear_it;
+		goto clear_diag_irq;
 
-	adapter->ahw->diag_cnt = 0;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
-	cmd.req.arg1 = adapter->ahw->pci_func;
-	qlcnic_issue_cmd(adapter, &cmd);
-	ret = cmd.rsp.cmd;
+	ahw->diag_cnt = 0;
+	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
 
+	cmd.req.arg[1] = ahw->pci_func;
+	ret = qlcnic_issue_cmd(adapter, &cmd);
 	if (ret)
 		goto done;
 
-	msleep(10);
-
-	ret = !adapter->ahw->diag_cnt;
+	usleep_range(1000, 12000);
+	ret = !ahw->diag_cnt;
 
 done:
+	qlcnic_free_mbx_args(&cmd);
 	qlcnic_diag_free_res(netdev, max_sds_rings);
 
-clear_it:
+clear_diag_irq:
 	adapter->max_sds_rings = max_sds_rings;
 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
 	return ret;
@@ -750,7 +881,7 @@
 	return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
 }
 
-static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
 {
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 	struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
@@ -761,11 +892,10 @@
 		skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
 		qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
 		skb_put(skb, QLCNIC_ILB_PKT_SIZE);
-
 		adapter->ahw->diag_cnt = 0;
 		qlcnic_xmit_frame(skb, adapter->netdev);
-
 		loop = 0;
+
 		do {
 			msleep(1);
 			qlcnic_process_rcv_ring_diag(sds_ring);
@@ -776,42 +906,46 @@
 		dev_kfree_skb_any(skb);
 
 		if (!adapter->ahw->diag_cnt)
-			QLCDB(adapter, DRV,
-			"LB Test: packet #%d was not received\n", i + 1);
+			dev_warn(&adapter->pdev->dev,
+				 "LB Test: packet #%d was not received\n",
+				 i + 1);
 		else
 			cnt++;
 	}
 	if (cnt != i) {
-		dev_warn(&adapter->pdev->dev, "LB Test failed\n");
-		if (mode != QLCNIC_ILB_MODE) {
+		dev_err(&adapter->pdev->dev,
+			"LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
+		if (mode != QLCNIC_ILB_MODE)
 			dev_warn(&adapter->pdev->dev,
-				"WARNING: Please make sure external"
-				"loopback connector is plugged in\n");
-		}
+				 "WARNING: Please check loopback cable\n");
 		return -1;
 	}
 	return 0;
 }
 
-static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
+int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	int max_sds_rings = adapter->max_sds_rings;
 	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	int loop = 0;
 	int ret;
 
-	if (!(adapter->ahw->capabilities &
-	      QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
-		netdev_info(netdev, "Firmware is not loopback test capable\n");
+	if (qlcnic_83xx_check(adapter))
+		return qlcnic_83xx_loopback_test(netdev, mode);
+
+	if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
+		dev_info(&adapter->pdev->dev,
+			 "Firmware do not support loopback test\n");
 		return -EOPNOTSUPP;
 	}
 
-	QLCDB(adapter, DRV, "%s loopback test in progress\n",
-		   mode == QLCNIC_ILB_MODE ? "internal" : "external");
-	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
-		netdev_warn(netdev, "Loopback test not supported for non "
-				"privilege function\n");
+	dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
+		 mode == QLCNIC_ILB_MODE ? "internal" : "external");
+	if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+		dev_warn(&adapter->pdev->dev,
+			 "Loopback test not supported in nonprivileged mode\n");
 		return 0;
 	}
 
@@ -823,12 +957,11 @@
 		goto clear_it;
 
 	sds_ring = &adapter->recv_ctx->sds_rings[0];
-
 	ret = qlcnic_set_lb_mode(adapter, mode);
 	if (ret)
 		goto free_res;
 
-	adapter->ahw->diag_cnt = 0;
+	ahw->diag_cnt = 0;
 	do {
 		msleep(500);
 		qlcnic_process_rcv_ring_diag(sds_ring);
@@ -841,11 +974,11 @@
 			ret = adapter->ahw->diag_cnt;
 			goto free_res;
 		}
-	} while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
+	} while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
 
 	ret = qlcnic_do_lb_test(adapter, mode);
 
-	qlcnic_clear_lb_mode(adapter);
+	qlcnic_clear_lb_mode(adapter, mode);
 
  free_res:
 	qlcnic_diag_free_res(netdev, max_sds_rings);
@@ -878,20 +1011,18 @@
 		data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
 		if (data[3])
 			eth_test->flags |= ETH_TEST_FL_FAILED;
-		if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
-			data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
-			if (data[4])
-				eth_test->flags |= ETH_TEST_FL_FAILED;
-			eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
-		}
+
+		data[4] = qlcnic_eeprom_test(dev);
+		if (data[4])
+			eth_test->flags |= ETH_TEST_FL_FAILED;
 	}
 }
 
 static void
-qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
-	int index, i, j;
+	int index, i, num_stats;
 
 	switch (stringset) {
 	case ETH_SS_TEST:
@@ -904,14 +1035,34 @@
 			       qlcnic_gstrings_stats[index].stat_string,
 			       ETH_GSTRING_LEN);
 		}
-		for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
-			memcpy(data + index * ETH_GSTRING_LEN,
-			       qlcnic_mac_stats_strings[j],
-			       ETH_GSTRING_LEN);
+		if (qlcnic_83xx_check(adapter)) {
+			num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_tx_stats_strings[i],
+				       ETH_GSTRING_LEN);
+			num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_mac_stats_strings[i],
+				       ETH_GSTRING_LEN);
+			num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_rx_stats_strings[i],
+				       ETH_GSTRING_LEN);
+			return;
+		} else {
+			num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+			for (i = 0; i < num_stats; i++, index++)
+				memcpy(data + index * ETH_GSTRING_LEN,
+				       qlcnic_83xx_mac_stats_strings[i],
+				       ETH_GSTRING_LEN);
 		}
 		if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
 			return;
-		for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
+		num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
+		for (i = 0; i < num_stats; index++, i++) {
 			memcpy(data + index * ETH_GSTRING_LEN,
 			       qlcnic_device_gstrings_stats[i],
 			       ETH_GSTRING_LEN);
@@ -920,89 +1071,84 @@
 }
 
 static void
-qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
+qlcnic_fill_stats(u64 *data, void *stats, int type)
 {
-	int ind = *index;
-
 	if (type == QLCNIC_MAC_STATS) {
 		struct qlcnic_mac_statistics *mac_stats =
 					(struct qlcnic_mac_statistics *)stats;
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
-		data[ind++] =
-			QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
-		data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
+		*data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
 	} else if (type == QLCNIC_ESW_STATS) {
 		struct __qlcnic_esw_statistics *esw_stats =
 				(struct __qlcnic_esw_statistics *)stats;
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
-		data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->errors);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
+		*data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
 	}
-
-	*index = ind;
 }
 
-static void
-qlcnic_get_ethtool_stats(struct net_device *dev,
-			     struct ethtool_stats *stats, u64 * data)
+static void qlcnic_get_ethtool_stats(struct net_device *dev,
+				     struct ethtool_stats *stats, u64 *data)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	struct qlcnic_esw_statistics port_stats;
 	struct qlcnic_mac_statistics mac_stats;
-	int index, ret;
+	int index, ret, length, size;
+	char *p;
 
-	for (index = 0; index < QLCNIC_STATS_LEN; index++) {
-		char *p =
-		    (char *)adapter +
-		    qlcnic_gstrings_stats[index].stat_offset;
-		data[index] =
-		    (qlcnic_gstrings_stats[index].sizeof_stat ==
-		     sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
+	memset(data, 0, stats->n_stats * sizeof(u64));
+	length = QLCNIC_STATS_LEN;
+	for (index = 0; index < length; index++) {
+		p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
+		size = qlcnic_gstrings_stats[index].sizeof_stat;
+		*data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
 	}
 
-	/* Retrieve MAC statistics from firmware */
-	memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
-	qlcnic_get_mac_stats(adapter, &mac_stats);
-	qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
+	if (qlcnic_83xx_check(adapter)) {
+		if (adapter->ahw->linkup)
+			qlcnic_83xx_get_stats(adapter, data);
+		return;
+	} else {
+		/* Retrieve MAC statistics from firmware */
+		memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
+		qlcnic_get_mac_stats(adapter, &mac_stats);
+		qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
+	}
 
 	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
 		return;
@@ -1013,14 +1159,13 @@
 	if (ret)
 		return;
 
-	qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
-
+	qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
 	ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
 			QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
 	if (ret)
 		return;
 
-	qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
+	qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
 }
 
 static int qlcnic_set_led(struct net_device *dev,
@@ -1030,6 +1175,8 @@
 	int max_sds_rings = adapter->max_sds_rings;
 	int err = -EIO, active = 1;
 
+	if (qlcnic_83xx_check(adapter))
+		return -EOPNOTSUPP;
 	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
 		netdev_warn(dev, "LED test not supported for non "
 				"privilege function\n");
@@ -1096,6 +1243,8 @@
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 wol_cfg;
 
+	if (qlcnic_83xx_check(adapter))
+		return;
 	wol->supported = 0;
 	wol->wolopts = 0;
 
@@ -1114,8 +1263,10 @@
 	struct qlcnic_adapter *adapter = netdev_priv(dev);
 	u32 wol_cfg;
 
-	if (wol->wolopts & ~WAKE_MAGIC)
+	if (qlcnic_83xx_check(adapter))
 		return -EOPNOTSUPP;
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
 
 	wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
 	if (!(wol_cfg & (1 << adapter->portnum)))
@@ -1307,7 +1458,7 @@
 			return 0;
 		}
 		netdev_info(netdev, "Forcing a FW dump\n");
-		qlcnic_dev_request_reset(adapter);
+		qlcnic_dev_request_reset(adapter, val->flag);
 		break;
 	case QLCNIC_DISABLE_FW_DUMP:
 		if (fw_dump->enable && fw_dump->tmpl_hdr) {
@@ -1327,7 +1478,7 @@
 		return 0;
 	case QLCNIC_FORCE_FW_RESET:
 		netdev_info(netdev, "Forcing a FW reset\n");
-		qlcnic_dev_request_reset(adapter);
+		qlcnic_dev_request_reset(adapter, val->flag);
 		adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
 		return 0;
 	case QLCNIC_SET_QUIESCENT:
@@ -1341,8 +1492,8 @@
 			netdev_err(netdev, "FW dump not supported\n");
 			return -ENOTSUPP;
 		}
-		for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
-			if (val->flag == FW_DUMP_LEVELS[i]) {
+		for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
+			if (val->flag == qlcnic_fw_dump_level[i]) {
 				fw_dump->tmpl_hdr->drv_cap_mask =
 							val->flag;
 				netdev_info(netdev, "Driver mask changed to: 0x%x\n",
@@ -1386,10 +1537,3 @@
 	.get_dump_data = qlcnic_get_dump_data,
 	.set_dump = qlcnic_set_dump,
 };
-
-const struct ethtool_ops qlcnic_ethtool_failed_ops = {
-	.get_settings = qlcnic_get_settings,
-	.get_drvinfo = qlcnic_get_drvinfo,
-	.set_msglevel = qlcnic_set_msglevel,
-	.get_msglevel = qlcnic_get_msglevel,
-};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index 49cc1ac..44197ca 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -1,6 +1,6 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
@@ -11,6 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+#include "qlcnic_hw.h"
+
 /*
  * The basic unit of access when reading/writing control registers.
  */
@@ -387,9 +389,6 @@
 #define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
 #define QLCNIC_ROMUSB_ROM_RDATA		(ROMUSB_ROM + 0x0018)
 
-/* Lock IDs for ROM lock */
-#define ROM_LOCK_DRIVER	0x0d417340
-
 /******************************************************************************
 *
 *    Definitions specific to M25P flash
@@ -449,13 +448,10 @@
 #define ISR_INT_TARGET_STATUS_F7   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
 #define ISR_INT_TARGET_MASK_F7     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
 
-#define QLCNIC_PCI_MN_2M	(0)
-#define QLCNIC_PCI_MS_2M	(0x80000)
 #define QLCNIC_PCI_OCM0_2M	(0x000c0000UL)
 #define QLCNIC_PCI_CRBSPACE	(0x06000000UL)
 #define QLCNIC_PCI_CAMQM	(0x04800000UL)
 #define QLCNIC_PCI_CAMQM_END	(0x04800800UL)
-#define QLCNIC_PCI_2MB_SIZE	(0x00200000UL)
 #define QLCNIC_PCI_CAMQM_2M_BASE	(0x000ff800UL)
 
 #define QLCNIC_CRB_CAM	QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
@@ -491,7 +487,7 @@
 #define QLCNIC_NIU_GB_MAC_CONFIG_1(I)		\
 		(QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000)
 
-
+#define MAX_CTL_CHECK	1000
 #define TEST_AGT_CTRL	(0x00)
 
 #define TA_CTL_START	BIT_0
@@ -499,44 +495,6 @@
 #define TA_CTL_WRITE	BIT_2
 #define TA_CTL_BUSY	BIT_3
 
-/*
- *   Register offsets for MN
- */
-#define MIU_TEST_AGT_BASE		(0x90)
-
-#define MIU_TEST_AGT_ADDR_LO		(0x04)
-#define MIU_TEST_AGT_ADDR_HI		(0x08)
-#define MIU_TEST_AGT_WRDATA_LO		(0x10)
-#define MIU_TEST_AGT_WRDATA_HI		(0x14)
-#define MIU_TEST_AGT_WRDATA_UPPER_LO	(0x20)
-#define MIU_TEST_AGT_WRDATA_UPPER_HI	(0x24)
-#define MIU_TEST_AGT_WRDATA(i)		(0x10+(0x10*((i)>>1))+(4*((i)&1)))
-#define MIU_TEST_AGT_RDDATA_LO		(0x18)
-#define MIU_TEST_AGT_RDDATA_HI		(0x1c)
-#define MIU_TEST_AGT_RDDATA_UPPER_LO	(0x28)
-#define MIU_TEST_AGT_RDDATA_UPPER_HI	(0x2c)
-#define MIU_TEST_AGT_RDDATA(i)		(0x18+(0x10*((i)>>1))+(4*((i)&1)))
-
-#define MIU_TEST_AGT_ADDR_MASK		0xfffffff8
-#define MIU_TEST_AGT_UPPER_ADDR(off)	(0)
-
-/*
- *   Register offsets for MS
- */
-#define SIU_TEST_AGT_BASE		(0x60)
-
-#define SIU_TEST_AGT_ADDR_LO		(0x04)
-#define SIU_TEST_AGT_ADDR_HI		(0x18)
-#define SIU_TEST_AGT_WRDATA_LO		(0x08)
-#define SIU_TEST_AGT_WRDATA_HI		(0x0c)
-#define SIU_TEST_AGT_WRDATA(i)		(0x08+(4*(i)))
-#define SIU_TEST_AGT_RDDATA_LO		(0x10)
-#define SIU_TEST_AGT_RDDATA_HI		(0x14)
-#define SIU_TEST_AGT_RDDATA(i)		(0x10+(4*(i)))
-
-#define SIU_TEST_AGT_ADDR_MASK		0x3ffff8
-#define SIU_TEST_AGT_UPPER_ADDR(off)	((off)>>22)
-
 /* XG Link status */
 #define XG_LINK_UP	0x10
 #define XG_LINK_DOWN	0x20
@@ -556,9 +514,6 @@
 
 #define QLCNIC_CAM_RAM_BASE	(QLCNIC_CRB_CAM + 0x02000)
 #define QLCNIC_CAM_RAM(reg)	(QLCNIC_CAM_RAM_BASE + (reg))
-#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150))
-#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154))
-#define QLCNIC_FW_VERSION_SUB	(QLCNIC_CAM_RAM(0x158))
 #define QLCNIC_ROM_LOCK_ID	(QLCNIC_CAM_RAM(0x100))
 #define QLCNIC_PHY_LOCK_ID	(QLCNIC_CAM_RAM(0x120))
 #define QLCNIC_CRB_WIN_LOCK_ID	(QLCNIC_CAM_RAM(0x124))
@@ -568,28 +523,17 @@
 #define QLCNIC_REG(X)		(NIC_CRB_BASE+(X))
 #define QLCNIC_REG_2(X) 	(NIC_CRB_BASE_2+(X))
 
-#define QLCNIC_CDRP_CRB_OFFSET		(QLCNIC_REG(0x18))
-#define QLCNIC_ARG1_CRB_OFFSET		(QLCNIC_REG(0x1c))
-#define QLCNIC_ARG2_CRB_OFFSET		(QLCNIC_REG(0x20))
-#define QLCNIC_ARG3_CRB_OFFSET		(QLCNIC_REG(0x24))
-#define QLCNIC_SIGN_CRB_OFFSET		(QLCNIC_REG(0x28))
+#define QLCNIC_CDRP_MAX_ARGS	4
+#define QLCNIC_CDRP_ARG(i)	(QLCNIC_REG(0x18 + ((i) * 4)))
 
-#define CRB_CMDPEG_STATE		(QLCNIC_REG(0x50))
-#define CRB_RCVPEG_STATE		(QLCNIC_REG(0x13c))
+#define QLCNIC_CDRP_CRB_OFFSET		(QLCNIC_REG(0x18))
+#define QLCNIC_SIGN_CRB_OFFSET		(QLCNIC_REG(0x28))
 
 #define CRB_XG_STATE_P3P		(QLCNIC_REG(0x98))
 #define CRB_PF_LINK_SPEED_1		(QLCNIC_REG(0xe8))
-#define CRB_PF_LINK_SPEED_2		(QLCNIC_REG(0xec))
-
-#define CRB_TEMP_STATE			(QLCNIC_REG(0x1b4))
-
-#define CRB_V2P_0			(QLCNIC_REG(0x290))
-#define CRB_V2P(port)			(CRB_V2P_0+((port)*4))
 #define CRB_DRIVER_VERSION		(QLCNIC_REG(0x2a0))
 
-#define CRB_FW_CAPABILITIES_1		(QLCNIC_CAM_RAM(0x128))
 #define CRB_FW_CAPABILITIES_2		(QLCNIC_CAM_RAM(0x12c))
-#define CRB_MAC_BLOCK_START		(QLCNIC_CAM_RAM(0x1c0))
 
 /*
  * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
@@ -616,11 +560,6 @@
 /* Lock IDs for PHY lock */
 #define PHY_LOCK_DRIVER		0x44524956
 
-/* Used for PS PCI Memory access */
-#define PCIX_PS_OP_ADDR_LO	(0x10000)
-/*   via CRB  (PS side only)     */
-#define PCIX_PS_OP_ADDR_HI	(0x10004)
-
 #define PCIX_INT_VECTOR 	(0x10100)
 #define PCIX_INT_MASK		(0x10104)
 
@@ -682,17 +621,6 @@
 #define QLCNIC_PEG_TUNE_CAPABILITY	(QLCNIC_CAM_RAM(0x02c))
 
 #define QLCNIC_DMA_WATCHDOG_CTRL	(QLCNIC_CAM_RAM(0x14))
-#define QLCNIC_PEG_ALIVE_COUNTER	(QLCNIC_CAM_RAM(0xb0))
-#define QLCNIC_PEG_HALT_STATUS1 	(QLCNIC_CAM_RAM(0xa8))
-#define QLCNIC_PEG_HALT_STATUS2 	(QLCNIC_CAM_RAM(0xac))
-#define QLCNIC_CRB_DRV_ACTIVE	(QLCNIC_CAM_RAM(0x138))
-#define QLCNIC_CRB_DEV_STATE		(QLCNIC_CAM_RAM(0x140))
-
-#define QLCNIC_CRB_DRV_STATE		(QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH		(QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO	(QLCNIC_CAM_RAM(0x14c))
-#define QLCNIC_CRB_DRV_IDC_VER		(QLCNIC_CAM_RAM(0x174))
-#define QLCNIC_CRB_DEV_NPAR_STATE	(QLCNIC_CAM_RAM(0x19c))
 #define QLCNIC_ROM_DEV_INIT_TIMEOUT	(0x3e885c)
 #define QLCNIC_ROM_DRV_RESET_TIMEOUT	(0x3e8860)
 
@@ -711,7 +639,6 @@
 #define QLCNIC_DEV_NPAR_OPER		1 /* NPAR Operational */
 #define QLCNIC_DEV_NPAR_OPER_TIMEO	30 /* Operational time out */
 
-#define QLC_DEV_CHECK_ACTIVE(VAL, FN)		((VAL) & (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)		((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)		((VAL) &= ~(1 << (FN * 4)))
 #define QLC_DEV_SET_RST_RDY(VAL, FN)		((VAL) |= (1 << (FN * 4)))
@@ -744,6 +671,9 @@
 #define QLCNIC_HEARTBEAT_PERIOD_MSECS	200
 #define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT	45
 
+#define QLCNIC_MAX_MC_COUNT		38
+#define QLCNIC_WATCHDOG_TIMEOUTVALUE	5
+
 #define	ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)	(((VAL) & 0x300) == 0x200)
 
@@ -766,26 +696,13 @@
 	u32	pci_int_reg;
 };
 
-#define QLCNIC_FW_API		0x1b216c
-#define QLCNIC_DRV_OP_MODE	0x1b2170
 #define QLCNIC_MSIX_BASE	0x132110
 #define QLCNIC_MAX_PCI_FUNC	8
 #define QLCNIC_MAX_VLAN_FILTERS	64
 
-/* FW dump defines */
-#define MIU_TEST_CTR		0x41000090
-#define MIU_TEST_ADDR_LO	0x41000094
-#define MIU_TEST_ADDR_HI	0x41000098
 #define FLASH_ROM_WINDOW	0x42110030
 #define FLASH_ROM_DATA		0x42150000
 
-
-static const u32 FW_DUMP_LEVELS[] = {
-	0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
-
-static const u32 MIU_TEST_READ_DATA[] = {
-	0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
-
 #define QLCNIC_FW_DUMP_REG1	0x00130060
 #define QLCNIC_FW_DUMP_REG2	0x001e0000
 #define QLCNIC_FLASH_SEM2_LK	0x0013C010
@@ -796,7 +713,8 @@
 enum {
 	QLCNIC_MGMT_FUNC	= 0,
 	QLCNIC_PRIV_FUNC	= 1,
-	QLCNIC_NON_PRIV_FUNC	= 2
+	QLCNIC_NON_PRIV_FUNC	= 2,
+	QLCNIC_UNKNOWN_FUNC_MODE = 3
 };
 
 enum {
@@ -1013,6 +931,8 @@
 #define QLCNIC_NIU_PROMISC_MODE		1
 #define QLCNIC_NIU_ALLMULTI_MODE	2
 
+#define QLCNIC_PCIE_SEM_TIMEOUT	10000
+
 struct crb_128M_2M_sub_block_map {
 	unsigned valid;
 	unsigned start_128M;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 7a6d5eb..325e11e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -1,6 +1,6 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
@@ -344,21 +344,26 @@
 	QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
 }
 
-static int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
+int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
 {
 	u32 data;
 
 	if (qlcnic_82xx_check(adapter))
 		qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
-	else
-		return -EIO;
+	else {
+		data = qlcnic_83xx_rd_reg_indirect(adapter, addr);
+		if (data == -EIO)
+			return -EIO;
+	}
 	return data;
 }
 
-static void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
+void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
 {
 	if (qlcnic_82xx_check(adapter))
 		qlcnic_write_window_reg(addr, adapter->ahw->pci_base0, data);
+	else
+		qlcnic_83xx_wrt_reg_indirect(adapter, addr, data);
 }
 
 static int
@@ -417,9 +422,8 @@
 	return 0;
 }
 
-static int
-qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
-				__le16 vlan_id, unsigned op)
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+				   __le16 vlan_id, u8 op)
 {
 	struct qlcnic_nic_req req;
 	struct qlcnic_mac_req *mac_req;
@@ -442,7 +446,29 @@
 	return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
 }
 
-static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+{
+	struct list_head *head;
+	struct qlcnic_mac_list_s *cur;
+	int err = -EINVAL;
+
+	/* Delete MAC from the existing list */
+	list_for_each(head, &adapter->mac_list) {
+		cur = list_entry(head, struct qlcnic_mac_list_s, list);
+		if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) {
+			err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+							0, QLCNIC_MAC_DEL);
+			if (err)
+				return err;
+			list_del(&cur->list);
+			kfree(cur);
+			return err;
+		}
+	}
+	return err;
+}
+
+int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
 {
 	struct list_head *head;
 	struct qlcnic_mac_list_s *cur;
@@ -455,11 +481,9 @@
 	}
 
 	cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC);
-	if (cur == NULL) {
-		dev_err(&adapter->netdev->dev,
-			"failed to add mac address filter\n");
+	if (cur == NULL)
 		return -ENOMEM;
-	}
+
 	memcpy(cur->mac_addr, addr, ETH_ALEN);
 
 	if (qlcnic_sre_macaddr_change(adapter,
@@ -506,17 +530,17 @@
 	}
 
 send_fw_cmd:
-	if (mode == VPORT_MISS_MODE_ACCEPT_ALL) {
+	if (mode == VPORT_MISS_MODE_ACCEPT_ALL && !adapter->fdb_mac_learn) {
 		qlcnic_alloc_lb_filters_mem(adapter);
-		adapter->mac_learn = 1;
+		adapter->drv_mac_learn = true;
 	} else {
-		adapter->mac_learn = 0;
+		adapter->drv_mac_learn = false;
 	}
 
 	qlcnic_nic_set_promisc(adapter, mode);
 }
 
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
 {
 	struct qlcnic_nic_req req;
 	u64 word;
@@ -555,18 +579,20 @@
 	struct hlist_node *tmp_hnode, *n;
 	struct hlist_head *head;
 	int i;
+	unsigned long time;
+	u8 cmd;
 
-	for (i = 0; i < adapter->fhash.fmax; i++) {
+	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
 		head = &(adapter->fhash.fhead[i]);
-
-		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
-		{
-			if (jiffies >
-				(QLCNIC_FILTER_AGE * HZ + tmp_fil->ftime)) {
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+						  QLCNIC_MAC_DEL;
+			time = tmp_fil->ftime;
+			if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
 				qlcnic_sre_macaddr_change(adapter,
-					tmp_fil->faddr, tmp_fil->vlan_id,
-					tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
-					QLCNIC_MAC_DEL);
+							  tmp_fil->faddr,
+							  tmp_fil->vlan_id,
+							  cmd);
 				spin_lock_bh(&adapter->mac_learn_lock);
 				adapter->fhash.fnum--;
 				hlist_del(&tmp_fil->fnode);
@@ -575,6 +601,21 @@
 			}
 		}
 	}
+	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) {
+		head = &(adapter->rx_fhash.fhead[i]);
+
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
+		{
+			time = tmp_fil->ftime;
+			if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
+				spin_lock_bh(&adapter->rx_mac_learn_lock);
+				adapter->rx_fhash.fnum--;
+				hlist_del(&tmp_fil->fnode);
+				spin_unlock_bh(&adapter->rx_mac_learn_lock);
+				kfree(tmp_fil);
+			}
+		}
+	}
 }
 
 void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
@@ -583,14 +624,17 @@
 	struct hlist_node *tmp_hnode, *n;
 	struct hlist_head *head;
 	int i;
+	u8 cmd;
 
-	for (i = 0; i < adapter->fhash.fmax; i++) {
+	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
 		head = &(adapter->fhash.fhead[i]);
-
 		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
-			qlcnic_sre_macaddr_change(adapter, tmp_fil->faddr,
-				tmp_fil->vlan_id, tmp_fil->vlan_id ?
-				QLCNIC_MAC_VLAN_DEL :  QLCNIC_MAC_DEL);
+			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+						  QLCNIC_MAC_DEL;
+			qlcnic_sre_macaddr_change(adapter,
+						  tmp_fil->faddr,
+						  tmp_fil->vlan_id,
+						  cmd);
 			spin_lock_bh(&adapter->mac_learn_lock);
 			adapter->fhash.fnum--;
 			hlist_del(&tmp_fil->fnode);
@@ -620,12 +664,13 @@
 	return rv;
 }
 
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 {
 	if (qlcnic_set_fw_loopback(adapter, mode))
 		return -EIO;
 
-	if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
+	if (qlcnic_nic_set_promisc(adapter,
+				   VPORT_MISS_MODE_ACCEPT_ALL)) {
 		qlcnic_set_fw_loopback(adapter, 0);
 		return -EIO;
 	}
@@ -634,11 +679,11 @@
 	return 0;
 }
 
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 {
-	int mode = VPORT_MISS_MODE_DROP;
 	struct net_device *netdev = adapter->netdev;
 
+	mode = VPORT_MISS_MODE_DROP;
 	qlcnic_set_fw_loopback(adapter, 0);
 
 	if (netdev->flags & IFF_PROMISC)
@@ -648,12 +693,13 @@
 
 	qlcnic_nic_set_promisc(adapter, mode);
 	msleep(1000);
+	return 0;
 }
 
 /*
  * Send the interrupt coalescing parameter set by ethtool to the card.
  */
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_nic_req req;
 	int rv;
@@ -675,10 +721,14 @@
 	if (rv != 0)
 		dev_err(&adapter->netdev->dev,
 			"Could not send interrupt coalescing parameters\n");
-	return rv;
 }
 
-int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
+#define QLCNIC_ENABLE_IPV4_LRO		1
+#define QLCNIC_ENABLE_IPV6_LRO		2
+#define QLCNIC_NO_DEST_IPV4_CHECK	(1 << 8)
+#define QLCNIC_NO_DEST_IPV6_CHECK	(2 << 8)
+
+int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
 {
 	struct qlcnic_nic_req req;
 	u64 word;
@@ -694,7 +744,15 @@
 	word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
 	req.req_hdr = cpu_to_le64(word);
 
-	req.words[0] = cpu_to_le64(enable);
+	word = 0;
+	if (enable) {
+		word = QLCNIC_ENABLE_IPV4_LRO | QLCNIC_NO_DEST_IPV4_CHECK;
+		if (adapter->ahw->capabilities2 & QLCNIC_FW_CAP2_HW_LRO_IPV6)
+			word |= QLCNIC_ENABLE_IPV6_LRO |
+				QLCNIC_NO_DEST_IPV6_CHECK;
+	}
+
+	req.words[0] = cpu_to_le64(word);
 
 	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
 	if (rv != 0)
@@ -734,9 +792,12 @@
 }
 
 
-#define RSS_HASHTYPE_IP_TCP	0x3
+#define QLCNIC_RSS_HASHTYPE_IP_TCP	0x3
+#define QLCNIC_ENABLE_TYPE_C_RSS	BIT_10
+#define QLCNIC_RSS_FEATURE_FLAG	(1ULL << 63)
+#define QLCNIC_RSS_IND_TABLE_MASK	0x7ULL
 
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int enable)
 {
 	struct qlcnic_nic_req req;
 	u64 word;
@@ -761,13 +822,19 @@
 	 *	7-6: hash_type_ipv6
 	 *	  8: enable
 	 *        9: use indirection table
-	 *    47-10: reserved
-	 *    63-48: indirection table mask
+	 *       10: type-c rss
+	 *	 11: udp rss
+	 *    47-12: reserved
+	 *    62-48: indirection table mask
+	 *	 63: feature flag
 	 */
-	word =  ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
-		((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+	word =  ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+		((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
 		((u64)(enable & 0x1) << 8) |
-		((0x7ULL) << 48);
+		((u64)QLCNIC_RSS_IND_TABLE_MASK << 48) |
+		(u64)QLCNIC_ENABLE_TYPE_C_RSS |
+		(u64)QLCNIC_RSS_FEATURE_FLAG;
+
 	req.words[0] = cpu_to_le64(word);
 	for (i = 0; i < 5; i++)
 		req.words[i+1] = cpu_to_le64(key[i]);
@@ -779,7 +846,8 @@
 	return rv;
 }
 
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
+void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
+			       __be32 ip, int cmd)
 {
 	struct qlcnic_nic_req req;
 	struct qlcnic_ipaddr *ipa;
@@ -801,23 +869,19 @@
 		dev_err(&adapter->netdev->dev,
 				"could not notify %s IP 0x%x reuqest\n",
 				(cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
-
-	return rv;
 }
 
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable)
 {
 	struct qlcnic_nic_req req;
 	u64 word;
 	int rv;
-
 	memset(&req, 0, sizeof(struct qlcnic_nic_req));
 	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
 
 	word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
 	req.req_hdr = cpu_to_le64(word);
 	req.words[0] = cpu_to_le64(enable | (enable << 8));
-
 	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
 	if (rv != 0)
 		dev_err(&adapter->netdev->dev,
@@ -882,7 +946,8 @@
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
-	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+	if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
+	    qlcnic_82xx_check(adapter)) {
 		netdev_features_t changed = features ^ netdev->features;
 		features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
 	}
@@ -903,13 +968,15 @@
 	if (!(changed & NETIF_F_LRO))
 		return 0;
 
-	netdev->features = features ^ NETIF_F_LRO;
+	netdev->features ^= NETIF_F_LRO;
 
 	if (qlcnic_config_hw_lro(adapter, hw_lro))
 		return -EIO;
 
-	if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
-		return -EIO;
+	if (!hw_lro && qlcnic_82xx_check(adapter)) {
+		if (qlcnic_send_lro_cleanup(adapter))
+			return -EIO;
+	}
 
 	return 0;
 }
@@ -981,8 +1048,8 @@
 	return 0;
 }
 
-int
-qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
+			       u32 data)
 {
 	unsigned long flags;
 	int rv;
@@ -1013,7 +1080,7 @@
 	return -EIO;
 }
 
-int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
 {
 	unsigned long flags;
 	int rv;
@@ -1042,7 +1109,6 @@
 	return -1;
 }
 
-
 void __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw,
 				u32 offset)
 {
@@ -1268,7 +1334,7 @@
 	return ret;
 }
 
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
 {
 	int offset, board_type, magic;
 	struct pci_dev *pdev = adapter->pdev;
@@ -1341,7 +1407,7 @@
 	return 0;
 }
 
-int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
 {
 	struct qlcnic_nic_req   req;
 	int rv;
@@ -1353,7 +1419,7 @@
 	word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
 	req.req_hdr = cpu_to_le64(word);
 
-	req.words[0] = cpu_to_le64((u64)rate << 32);
+	req.words[0] = cpu_to_le64(((u64)rate << 32) | adapter->portnum);
 	req.words[1] = cpu_to_le64(state);
 
 	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
@@ -1362,3 +1428,56 @@
 
 	return rv;
 }
+
+void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+	void __iomem *msix_base_addr;
+	u32 func;
+	u32 msix_base;
+
+	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+	msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
+	msix_base = readl(msix_base_addr);
+	func = (func - msix_base) / QLCNIC_MSIX_TBL_PGSIZE;
+	adapter->ahw->pci_func = func;
+}
+
+void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+			  loff_t offset, size_t size)
+{
+	u32 data;
+	u64 qmdata;
+
+	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+		qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
+		memcpy(buf, &qmdata, size);
+	} else {
+		data = QLCRD32(adapter, offset);
+		memcpy(buf, &data, size);
+	}
+}
+
+void qlcnic_82xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+			   loff_t offset, size_t size)
+{
+	u32 data;
+	u64 qmdata;
+
+	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+		memcpy(&qmdata, buf, size);
+		qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
+	} else {
+		memcpy(&data, buf, size);
+		QLCWR32(adapter, offset, data);
+	}
+}
+
+int qlcnic_82xx_api_lock(struct qlcnic_adapter *adapter)
+{
+	return qlcnic_pcie_sem_lock(adapter, 5, 0);
+}
+
+void qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter)
+{
+	qlcnic_pcie_sem_unlock(adapter, 5);
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
new file mode 100644
index 0000000..5b8749e
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -0,0 +1,194 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#ifndef __QLCNIC_HW_H
+#define __QLCNIC_HW_H
+
+/* Common registers in 83xx and 82xx */
+enum qlcnic_regs {
+	QLCNIC_PEG_HALT_STATUS1 = 0,
+	QLCNIC_PEG_HALT_STATUS2,
+	QLCNIC_PEG_ALIVE_COUNTER,
+	QLCNIC_FLASH_LOCK_OWNER,
+	QLCNIC_FW_CAPABILITIES,
+	QLCNIC_CRB_DRV_ACTIVE,
+	QLCNIC_CRB_DEV_STATE,
+	QLCNIC_CRB_DRV_STATE,
+	QLCNIC_CRB_DRV_SCRATCH,
+	QLCNIC_CRB_DEV_PARTITION_INFO,
+	QLCNIC_CRB_DRV_IDC_VER,
+	QLCNIC_FW_VERSION_MAJOR,
+	QLCNIC_FW_VERSION_MINOR,
+	QLCNIC_FW_VERSION_SUB,
+	QLCNIC_CRB_DEV_NPAR_STATE,
+	QLCNIC_FW_IMG_VALID,
+	QLCNIC_CMDPEG_STATE,
+	QLCNIC_RCVPEG_STATE,
+	QLCNIC_ASIC_TEMP,
+	QLCNIC_FW_API,
+	QLCNIC_DRV_OP_MODE,
+	QLCNIC_FLASH_LOCK,
+	QLCNIC_FLASH_UNLOCK,
+};
+
+/* Read from an address offset from BAR0, existing registers */
+#define QLC_SHARED_REG_RD32(a, addr)			\
+	readl(((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Write to an address offset from BAR0, existing registers */
+#define QLC_SHARED_REG_WR32(a, addr, value)		\
+	writel(value, ((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Read from a direct address offset from BAR0, additional registers */
+#define QLCRDX(ahw, addr)	\
+	readl(((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr]))
+
+/* Write to a direct address offset from BAR0, additional registers */
+#define QLCWRX(ahw, addr, value)	\
+	writel(value, (((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr])))
+
+#define QLCNIC_CMD_CONFIGURE_IP_ADDR		0x1
+#define QLCNIC_CMD_CONFIG_INTRPT		0x2
+#define QLCNIC_CMD_CREATE_RX_CTX		0x7
+#define QLCNIC_CMD_DESTROY_RX_CTX		0x8
+#define QLCNIC_CMD_CREATE_TX_CTX		0x9
+#define QLCNIC_CMD_DESTROY_TX_CTX		0xa
+#define QLCNIC_CMD_CONFIGURE_LRO		0xC
+#define QLCNIC_CMD_CONFIGURE_MAC_LEARNING	0xD
+#define QLCNIC_CMD_GET_STATISTICS		0xF
+#define QLCNIC_CMD_INTRPT_TEST			0x11
+#define QLCNIC_CMD_SET_MTU			0x12
+#define QLCNIC_CMD_READ_PHY			0x13
+#define QLCNIC_CMD_WRITE_PHY			0x14
+#define QLCNIC_CMD_READ_HW_REG			0x15
+#define QLCNIC_CMD_GET_FLOW_CTL			0x16
+#define QLCNIC_CMD_SET_FLOW_CTL			0x17
+#define QLCNIC_CMD_READ_MAX_MTU			0x18
+#define QLCNIC_CMD_READ_MAX_LRO			0x19
+#define QLCNIC_CMD_MAC_ADDRESS			0x1f
+#define QLCNIC_CMD_GET_PCI_INFO			0x20
+#define QLCNIC_CMD_GET_NIC_INFO			0x21
+#define QLCNIC_CMD_SET_NIC_INFO			0x22
+#define QLCNIC_CMD_GET_ESWITCH_CAPABILITY	0x24
+#define QLCNIC_CMD_TOGGLE_ESWITCH		0x25
+#define QLCNIC_CMD_GET_ESWITCH_STATUS		0x26
+#define QLCNIC_CMD_SET_PORTMIRRORING		0x27
+#define QLCNIC_CMD_CONFIGURE_ESWITCH		0x28
+#define QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG	0x29
+#define QLCNIC_CMD_GET_ESWITCH_STATS		0x2a
+#define QLCNIC_CMD_CONFIG_PORT			0x2e
+#define QLCNIC_CMD_TEMP_SIZE			0x2f
+#define QLCNIC_CMD_GET_TEMP_HDR			0x30
+#define QLCNIC_CMD_GET_MAC_STATS		0x37
+#define QLCNIC_CMD_SET_DRV_VER			0x38
+#define QLCNIC_CMD_CONFIGURE_RSS		0x41
+#define QLCNIC_CMD_CONFIG_INTR_COAL		0x43
+#define QLCNIC_CMD_CONFIGURE_LED		0x44
+#define QLCNIC_CMD_CONFIG_MAC_VLAN		0x45
+#define QLCNIC_CMD_GET_LINK_EVENT		0x48
+#define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE	0x49
+#define QLCNIC_CMD_CONFIGURE_HW_LRO		0x4A
+#define QLCNIC_CMD_INIT_NIC_FUNC		0x60
+#define QLCNIC_CMD_STOP_NIC_FUNC		0x61
+#define QLCNIC_CMD_IDC_ACK			0x63
+#define QLCNIC_CMD_SET_PORT_CONFIG		0x66
+#define QLCNIC_CMD_GET_PORT_CONFIG		0x67
+#define QLCNIC_CMD_GET_LINK_STATUS		0x68
+#define QLCNIC_CMD_SET_LED_CONFIG		0x69
+#define QLCNIC_CMD_GET_LED_CONFIG		0x6A
+#define QLCNIC_CMD_ADD_RCV_RINGS		0x0B
+
+#define QLCNIC_INTRPT_INTX			1
+#define QLCNIC_INTRPT_MSIX			3
+#define QLCNIC_INTRPT_ADD			1
+#define QLCNIC_INTRPT_DEL			2
+
+#define QLCNIC_GET_CURRENT_MAC			1
+#define QLCNIC_SET_STATION_MAC			2
+#define QLCNIC_GET_DEFAULT_MAC			3
+#define QLCNIC_GET_FAC_DEF_MAC			4
+#define QLCNIC_SET_FAC_DEF_MAC			5
+
+#define QLCNIC_MBX_LINK_EVENT		0x8001
+#define QLCNIC_MBX_COMP_EVENT		0x8100
+#define QLCNIC_MBX_REQUEST_EVENT	0x8101
+#define QLCNIC_MBX_TIME_EXTEND_EVENT	0x8102
+#define QLCNIC_MBX_SFP_INSERT_EVENT	0x8130
+#define QLCNIC_MBX_SFP_REMOVE_EVENT	0x8131
+
+struct qlcnic_mailbox_metadata {
+	u32 cmd;
+	u32 in_args;
+	u32 out_args;
+};
+
+/* Mailbox ownership */
+#define QLCNIC_GET_OWNER(val)	((val) & (BIT_0 | BIT_1))
+
+#define QLCNIC_SET_OWNER        1
+#define QLCNIC_CLR_OWNER        0
+#define QLCNIC_MBX_TIMEOUT      10000
+
+#define QLCNIC_MBX_RSP_OK	1
+#define QLCNIC_MBX_PORT_RSP_OK	0x1a
+#define QLCNIC_MBX_ASYNC_EVENT	BIT_15
+
+struct qlcnic_pci_info;
+struct qlcnic_info;
+struct qlcnic_cmd_args;
+struct ethtool_stats;
+struct pci_device_id;
+struct qlcnic_host_sds_ring;
+struct qlcnic_host_tx_ring;
+struct qlcnic_host_tx_ring;
+struct qlcnic_hardware_context;
+struct qlcnic_adapter;
+
+int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong);
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
+int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
+int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
+int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
+			 struct net_device *netdev);
+void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
+			       u64 *uaddr, __le16 vlan_id);
+void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter);
+int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int);
+void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
+			       __be32, int);
+int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int);
+void qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8);
+int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8);
+void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8);
+irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
+int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
+			  struct qlcnic_cmd_args *);
+int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *,
+				     struct qlcnic_host_tx_ring *tx_ring, int);
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+			       struct qlcnic_adapter *, u32);
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
+int qlcnic_82xx_get_board_info(struct qlcnic_adapter *);
+int qlcnic_82xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_82xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_82xx_api_lock(struct qlcnic_adapter *);
+void qlcnic_82xx_api_unlock(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_disable(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_del(struct qlcnic_adapter *);
+#endif				/* __QLCNIC_HW_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index de79cde..d28336f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1,15 +1,12 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
 
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/if_vlan.h>
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 struct crb_addr_pair {
 	u32 addr;
@@ -166,13 +163,12 @@
 {
 	struct qlcnic_recv_context *recv_ctx;
 	struct qlcnic_host_rds_ring *rds_ring;
-	struct qlcnic_host_tx_ring *tx_ring;
 	int ring;
 
 	recv_ctx = adapter->recv_ctx;
 
 	if (recv_ctx->rds_rings == NULL)
-		goto skip_rds;
+		return;
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
 		rds_ring = &recv_ctx->rds_rings[ring];
@@ -180,16 +176,6 @@
 		rds_ring->rx_buf_arr = NULL;
 	}
 	kfree(recv_ctx->rds_rings);
-
-skip_rds:
-	if (adapter->tx_ring == NULL)
-		return;
-
-	tx_ring = adapter->tx_ring;
-	vfree(tx_ring->cmd_buf_arr);
-	tx_ring->cmd_buf_arr = NULL;
-	kfree(adapter->tx_ring);
-	adapter->tx_ring = NULL;
 }
 
 int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
@@ -197,39 +183,16 @@
 	struct qlcnic_recv_context *recv_ctx;
 	struct qlcnic_host_rds_ring *rds_ring;
 	struct qlcnic_host_sds_ring *sds_ring;
-	struct qlcnic_host_tx_ring *tx_ring;
 	struct qlcnic_rx_buffer *rx_buf;
-	int ring, i, size;
-
-	struct qlcnic_cmd_buffer *cmd_buf_arr;
-	struct net_device *netdev = adapter->netdev;
-
-	size = sizeof(struct qlcnic_host_tx_ring);
-	tx_ring = kzalloc(size, GFP_KERNEL);
-	if (tx_ring == NULL) {
-		dev_err(&netdev->dev, "failed to allocate tx ring struct\n");
-		return -ENOMEM;
-	}
-	adapter->tx_ring = tx_ring;
-
-	tx_ring->num_desc = adapter->num_txd;
-	tx_ring->txq = netdev_get_tx_queue(netdev, 0);
-
-	cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
-	if (cmd_buf_arr == NULL) {
-		dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
-		goto err_out;
-	}
-	tx_ring->cmd_buf_arr = cmd_buf_arr;
+	int ring, i;
 
 	recv_ctx = adapter->recv_ctx;
 
-	size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring);
-	rds_ring = kzalloc(size, GFP_KERNEL);
-	if (rds_ring == NULL) {
-		dev_err(&netdev->dev, "failed to allocate rds ring struct\n");
+	rds_ring = kcalloc(adapter->max_rds_rings,
+			   sizeof(struct qlcnic_host_rds_ring), GFP_KERNEL);
+	if (rds_ring == NULL)
 		goto err_out;
-	}
+
 	recv_ctx->rds_rings = rds_ring;
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
@@ -255,11 +218,9 @@
 			break;
 		}
 		rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring));
-		if (rds_ring->rx_buf_arr == NULL) {
-			dev_err(&netdev->dev, "Failed to allocate "
-				"rx buffer ring %d\n", ring);
+		if (rds_ring->rx_buf_arr == NULL)
 			goto err_out;
-		}
+
 		INIT_LIST_HEAD(&rds_ring->free_list);
 		/*
 		 * Now go through all of them, set reference handles
@@ -327,7 +288,6 @@
 	long done = 0;
 
 	cond_resched();
-
 	while (done == 0) {
 		done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
 		done &= 2;
@@ -416,8 +376,8 @@
 	u32 off;
 	struct pci_dev *pdev = adapter->pdev;
 
-	QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
-	QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_RCVPEG_STATE, 0);
 
 	/* Halt all the indiviual PEGs and other blocks */
 	/* disable all I2Q */
@@ -482,10 +442,8 @@
 	}
 
 	buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
-	if (buf == NULL) {
-		dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n");
+	if (buf == NULL)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < n; i++) {
 		if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 ||
@@ -564,8 +522,8 @@
 	QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
 	msleep(1);
 
-	QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
-	QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
 
 	return 0;
 }
@@ -576,7 +534,7 @@
 	int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
 
 	do {
-		val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+		val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CMDPEG_STATE);
 
 		switch (val) {
 		case PHAN_INITIALIZE_COMPLETE:
@@ -592,7 +550,8 @@
 
 	} while (--retries);
 
-	QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE,
+			    PHAN_INITIALIZE_FAILED);
 
 out_err:
 	dev_err(&adapter->pdev->dev, "Command Peg initialization not "
@@ -607,7 +566,7 @@
 	int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT;
 
 	do {
-		val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+		val = QLC_SHARED_REG_RD32(adapter, QLCNIC_RCVPEG_STATE);
 
 		if (val == PHAN_PEG_RCV_INITIALIZED)
 			return 0;
@@ -638,7 +597,7 @@
 	if (err)
 		return err;
 
-	QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
 
 	return err;
 }
@@ -649,7 +608,7 @@
 	int timeo;
 	u32 val;
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
 	val = QLC_DEV_GET_DRV(val, adapter->portnum);
 	if ((val & 0x3) != QLCNIC_TYPE_NIC) {
 		dev_err(&adapter->pdev->dev,
@@ -689,11 +648,9 @@
 	}
 
 	entry_size = flt_hdr.len - sizeof(struct qlcnic_flt_header);
-	flt_entry = (struct qlcnic_flt_entry *)vzalloc(entry_size);
-	if (flt_entry == NULL) {
-		dev_warn(&adapter->pdev->dev, "error allocating memory\n");
+	flt_entry = vzalloc(entry_size);
+	if (flt_entry == NULL)
 		return -EIO;
-	}
 
 	ret = qlcnic_rom_fast_read_words(adapter, QLCNIC_FLT_LOCATION +
 					 sizeof(struct qlcnic_flt_header),
@@ -1096,11 +1053,13 @@
 	u32 heartbeat, ret = -EIO;
 	int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
 
-	adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+	adapter->heartbeat = QLC_SHARED_REG_RD32(adapter,
+						 QLCNIC_PEG_ALIVE_COUNTER);
 
 	do {
 		msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
-		heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+		heartbeat = QLC_SHARED_REG_RD32(adapter,
+						QLCNIC_PEG_ALIVE_COUNTER);
 		if (heartbeat != adapter->heartbeat) {
 			ret = QLCNIC_RCODE_SUCCESS;
 			break;
@@ -1270,7 +1229,7 @@
 		return -EINVAL;
 	}
 
-	QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID, QLCNIC_BDINFO_MAGIC);
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 6f82812..6387e0c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -1,3 +1,10 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 #include <net/ip.h>
@@ -5,9 +12,6 @@
 
 #include "qlcnic.h"
 
-#define QLCNIC_MAC_HASH(MAC)\
-	((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
-
 #define TX_ETHER_PKT	0x01
 #define TX_TCP_PKT	0x02
 #define TX_UDP_PKT	0x03
@@ -84,6 +88,8 @@
 #define qlcnic_get_lro_sts_mss(sts_data1)		\
 	((sts_data1 >> 32) & 0x0FFFF)
 
+#define qlcnic_83xx_get_lro_sts_mss(sts) ((sts) & 0xffff)
+
 /* opcode field in status_desc */
 #define QLCNIC_SYN_OFFLOAD	0x03
 #define QLCNIC_RXPKT_DESC  	0x04
@@ -91,18 +97,152 @@
 #define QLCNIC_RESPONSE_DESC	0x05
 #define QLCNIC_LRO_DESC  	0x12
 
+#define QLCNIC_TX_POLL_BUDGET		128
+#define QLCNIC_TCP_HDR_SIZE		20
+#define QLCNIC_TCP_TS_OPTION_SIZE	12
+#define QLCNIC_FETCH_RING_ID(handle)	((handle) >> 63)
+#define QLCNIC_DESC_OWNER_FW		cpu_to_le64(STATUS_OWNER_PHANTOM)
+
+#define QLCNIC_TCP_TS_HDR_SIZE (QLCNIC_TCP_HDR_SIZE + QLCNIC_TCP_TS_OPTION_SIZE)
+
 /* for status field in status_desc */
 #define STATUS_CKSUM_LOOP	0
 #define STATUS_CKSUM_OK		2
 
-static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
-				 u64 uaddr, __le16 vlan_id,
-				 struct qlcnic_host_tx_ring *tx_ring)
+#define qlcnic_83xx_pktln(sts)		((sts >> 32) & 0x3FFF)
+#define qlcnic_83xx_hndl(sts)		((sts >> 48) & 0x7FFF)
+#define qlcnic_83xx_csum_status(sts)	((sts >> 39) & 7)
+#define qlcnic_83xx_opcode(sts)	((sts >> 42) & 0xF)
+#define qlcnic_83xx_vlan_tag(sts)	(((sts) >> 48) & 0xFFFF)
+#define qlcnic_83xx_lro_pktln(sts)	(((sts) >> 32) & 0x3FFF)
+#define qlcnic_83xx_l2_hdr_off(sts)	(((sts) >> 16) & 0xFF)
+#define qlcnic_83xx_l4_hdr_off(sts)	(((sts) >> 24) & 0xFF)
+#define qlcnic_83xx_pkt_cnt(sts)	(((sts) >> 16) & 0x7)
+#define qlcnic_83xx_is_tstamp(sts)	(((sts) >> 40) & 1)
+#define qlcnic_83xx_is_psh_bit(sts)	(((sts) >> 41) & 1)
+#define qlcnic_83xx_is_ip_align(sts)	(((sts) >> 46) & 1)
+#define qlcnic_83xx_has_vlan_tag(sts)	(((sts) >> 47) & 1)
+
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *,
+				     struct qlcnic_host_rds_ring *, u16, u16);
+
+inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter,
+				       struct qlcnic_host_tx_ring *tx_ring)
+{
+	writel(0, tx_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter,
+					struct qlcnic_host_tx_ring *tx_ring)
+{
+	writel(1, tx_ring->crb_intr_mask);
+}
+
+static inline u8 qlcnic_mac_hash(u64 mac)
+{
+	return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff));
+}
+
+static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
+					u16 handle, u8 ring_id)
+{
+	if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X)
+		return handle | (ring_id << 15);
+	else
+		return handle;
+}
+
+static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
+{
+	return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
+}
+
+void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
+			  int loopback_pkt, __le16 vlan_id)
+{
+	struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+	struct qlcnic_filter *fil, *tmp_fil;
+	struct hlist_node *tmp_hnode, *n;
+	struct hlist_head *head;
+	unsigned long time;
+	u64 src_addr = 0;
+	u8 hindex, found = 0, op;
+	int ret;
+
+	memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+
+	if (loopback_pkt) {
+		if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
+			return;
+
+		hindex = qlcnic_mac_hash(src_addr) &
+			 (adapter->fhash.fbucket_size - 1);
+		head = &(adapter->rx_fhash.fhead[hindex]);
+
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+			if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+			    tmp_fil->vlan_id == vlan_id) {
+				time = tmp_fil->ftime;
+				if (jiffies > (QLCNIC_READD_AGE * HZ + time))
+					tmp_fil->ftime = jiffies;
+				return;
+			}
+		}
+
+		fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+		if (!fil)
+			return;
+
+		fil->ftime = jiffies;
+		memcpy(fil->faddr, &src_addr, ETH_ALEN);
+		fil->vlan_id = vlan_id;
+		spin_lock(&adapter->rx_mac_learn_lock);
+		hlist_add_head(&(fil->fnode), head);
+		adapter->rx_fhash.fnum++;
+		spin_unlock(&adapter->rx_mac_learn_lock);
+	} else {
+		hindex = qlcnic_mac_hash(src_addr) &
+			 (adapter->fhash.fbucket_size - 1);
+		head = &(adapter->rx_fhash.fhead[hindex]);
+		spin_lock(&adapter->rx_mac_learn_lock);
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+			if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+			    tmp_fil->vlan_id == vlan_id) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			spin_unlock(&adapter->rx_mac_learn_lock);
+			return;
+		}
+
+		op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+		ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
+						vlan_id, op);
+		if (!ret) {
+			op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
+			ret = qlcnic_sre_macaddr_change(adapter,
+							(u8 *)&src_addr,
+							vlan_id, op);
+			if (!ret) {
+				hlist_del(&(tmp_fil->fnode));
+				adapter->rx_fhash.fnum--;
+			}
+		}
+		spin_unlock(&adapter->rx_mac_learn_lock);
+	}
+}
+
+void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
+			       __le16 vlan_id)
 {
 	struct cmd_desc_type0 *hwdesc;
 	struct qlcnic_nic_req *req;
 	struct qlcnic_mac_req *mac_req;
 	struct qlcnic_vlan_req *vlan_req;
+	struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 	u32 producer;
 	u64 word;
 
@@ -128,14 +268,14 @@
 }
 
 static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
-			       struct qlcnic_host_tx_ring *tx_ring,
 			       struct cmd_desc_type0 *first_desc,
 			       struct sk_buff *skb)
 {
-	struct ethhdr *phdr = (struct ethhdr *)(skb->data);
 	struct qlcnic_filter *fil, *tmp_fil;
 	struct hlist_node *tmp_hnode, *n;
 	struct hlist_head *head;
+	struct net_device *netdev = adapter->netdev;
+	struct ethhdr *phdr = (struct ethhdr *)(skb->data);
 	u64 src_addr = 0;
 	__le16 vlan_id = 0;
 	u8 hindex;
@@ -143,23 +283,23 @@
 	if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
 		return;
 
-	if (adapter->fhash.fnum >= adapter->fhash.fmax)
+	if (adapter->fhash.fnum >= adapter->fhash.fmax) {
+		adapter->stats.mac_filter_limit_overrun++;
+		netdev_info(netdev, "Can not add more than %d mac addresses\n",
+			    adapter->fhash.fmax);
 		return;
+	}
 
-	/* Only NPAR capable devices support vlan based learning*/
-	if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-		vlan_id = first_desc->vlan_TCI;
 	memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-	hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
+	hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
 	head = &(adapter->fhash.fhead[hindex]);
 
 	hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
 		if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-			    tmp_fil->vlan_id == vlan_id) {
-
+		    tmp_fil->vlan_id == vlan_id) {
 			if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
-				qlcnic_change_filter(adapter, src_addr, vlan_id,
-						     tx_ring);
+				qlcnic_change_filter(adapter, &src_addr,
+						     vlan_id);
 			tmp_fil->ftime = jiffies;
 			return;
 		}
@@ -169,17 +309,13 @@
 	if (!fil)
 		return;
 
-	qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
-
+	qlcnic_change_filter(adapter, &src_addr, vlan_id);
 	fil->ftime = jiffies;
 	fil->vlan_id = vlan_id;
 	memcpy(fil->faddr, &src_addr, ETH_ALEN);
-
 	spin_lock(&adapter->mac_learn_lock);
-
 	hlist_add_head(&(fil->fnode), head);
 	adapter->fhash.fnum++;
-
 	spin_unlock(&adapter->mac_learn_lock);
 }
 
@@ -474,8 +610,8 @@
 	if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
 		goto unwind_buff;
 
-	if (adapter->mac_learn)
-		qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+	if (adapter->drv_mac_learn)
+		qlcnic_send_filter(adapter, first_desc, skb);
 
 	adapter->stats.txbytes += skb->len;
 	adapter->stats.xmitcalled++;
@@ -528,8 +664,8 @@
 	}
 
 	skb_reserve(skb, NET_IP_ALIGN);
-	dma = pci_map_single(pdev, skb->data, rds_ring->dma_size,
-			     PCI_DMA_FROMDEVICE);
+	dma = pci_map_single(pdev, skb->data,
+			     rds_ring->dma_size, PCI_DMA_FROMDEVICE);
 
 	if (pci_dma_mapping_error(pdev, dma)) {
 		adapter->stats.rx_dma_map_error++;
@@ -544,12 +680,13 @@
 }
 
 static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
-					 struct qlcnic_host_rds_ring *rds_ring)
+					struct qlcnic_host_rds_ring *rds_ring,
+					u8 ring_id)
 {
 	struct rcv_desc *pdesc;
 	struct qlcnic_rx_buffer *buffer;
 	int  count = 0;
-	uint32_t producer;
+	uint32_t producer, handle;
 	struct list_head *head;
 
 	if (!spin_trylock(&rds_ring->lock))
@@ -557,7 +694,6 @@
 
 	producer = rds_ring->producer;
 	head = &rds_ring->free_list;
-
 	while (!list_empty(head)) {
 		buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
 
@@ -565,28 +701,29 @@
 			if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
 				break;
 		}
-
 		count++;
 		list_del(&buffer->list);
 
 		/* make a rcv descriptor  */
 		pdesc = &rds_ring->desc_head[producer];
-		pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+		handle = qlcnic_get_ref_handle(adapter,
+					       buffer->ref_handle, ring_id);
+		pdesc->reference_handle = cpu_to_le16(handle);
 		pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
 		pdesc->addr_buffer = cpu_to_le64(buffer->dma);
 		producer = get_next_index(producer, rds_ring->num_desc);
 	}
-
 	if (count) {
 		rds_ring->producer = producer;
 		writel((producer - 1) & (rds_ring->num_desc - 1),
 		       rds_ring->crb_rcv_producer);
 	}
-
 	spin_unlock(&rds_ring->lock);
 }
 
-static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
+				   struct qlcnic_host_tx_ring *tx_ring,
+				   int budget)
 {
 	u32 sw_consumer, hw_consumer;
 	int i, done, count = 0;
@@ -594,7 +731,6 @@
 	struct pci_dev *pdev = adapter->pdev;
 	struct net_device *netdev = adapter->netdev;
 	struct qlcnic_skb_frag *frag;
-	struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
 	if (!spin_trylock(&adapter->tx_clean_lock))
 		return 1;
@@ -615,22 +751,19 @@
 					       PCI_DMA_TODEVICE);
 				frag->dma = 0ULL;
 			}
-
 			adapter->stats.xmitfinished++;
 			dev_kfree_skb_any(buffer->skb);
 			buffer->skb = NULL;
 		}
 
 		sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
-		if (++count >= MAX_STATUS_HANDLE)
+		if (++count >= budget)
 			break;
 	}
 
 	if (count && netif_running(netdev)) {
 		tx_ring->sw_consumer = sw_consumer;
-
 		smp_mb();
-
 		if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
 			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
 				netif_wake_queue(netdev);
@@ -654,7 +787,6 @@
 	 */
 	hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
 	done = (sw_consumer == hw_consumer);
-
 	spin_unlock(&adapter->tx_clean_lock);
 
 	return done;
@@ -662,16 +794,15 @@
 
 static int qlcnic_poll(struct napi_struct *napi, int budget)
 {
+	int tx_complete, work_done;
 	struct qlcnic_host_sds_ring *sds_ring;
 	struct qlcnic_adapter *adapter;
-	int tx_complete, work_done;
 
 	sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
 	adapter = sds_ring->adapter;
-
-	tx_complete = qlcnic_process_cmd_ring(adapter);
+	tx_complete = qlcnic_process_cmd_ring(adapter, adapter->tx_ring,
+					      budget);
 	work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
 	if ((work_done < budget) && tx_complete) {
 		napi_complete(&sds_ring->napi);
 		if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
@@ -804,26 +935,23 @@
 	}
 }
 
-static struct sk_buff *
-qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
-		     struct qlcnic_host_rds_ring *rds_ring, u16 index,
-		     u16 cksum)
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+				     struct qlcnic_host_rds_ring *ring,
+				     u16 index, u16 cksum)
 {
 	struct qlcnic_rx_buffer *buffer;
 	struct sk_buff *skb;
 
-	buffer = &rds_ring->rx_buf_arr[index];
-
+	buffer = &ring->rx_buf_arr[index];
 	if (unlikely(buffer->skb == NULL)) {
 		WARN_ON(1);
 		return NULL;
 	}
 
-	pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+	pci_unmap_single(adapter->pdev, buffer->dma, ring->dma_size,
 			 PCI_DMA_FROMDEVICE);
 
 	skb = buffer->skb;
-
 	if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
 		   (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
 		adapter->stats.csummed++;
@@ -832,6 +960,7 @@
 		skb_checksum_none_assert(skb);
 	}
 
+
 	buffer->skb = NULL;
 
 	return skb;
@@ -871,8 +1000,8 @@
 	struct qlcnic_rx_buffer *buffer;
 	struct sk_buff *skb;
 	struct qlcnic_host_rds_ring *rds_ring;
-	int index, length, cksum, pkt_offset;
-	u16 vid = 0xffff;
+	int index, length, cksum, pkt_offset, is_lb_pkt;
+	u16 vid = 0xffff, t_vid;
 
 	if (unlikely(ring >= adapter->max_rds_rings))
 		return NULL;
@@ -892,6 +1021,14 @@
 	if (!skb)
 		return buffer;
 
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+
 	if (length > rds_ring->skb_size)
 		skb_put(skb, rds_ring->skb_size);
 	else
@@ -933,10 +1070,11 @@
 	struct sk_buff *skb;
 	struct qlcnic_host_rds_ring *rds_ring;
 	struct iphdr *iph;
+	struct ipv6hdr *ipv6h;
 	struct tcphdr *th;
 	bool push, timestamp;
-	int index, l2_hdr_offset, l4_hdr_offset;
-	u16 lro_length, length, data_offset, vid = 0xffff;
+	int index, l2_hdr_offset, l4_hdr_offset, is_lb_pkt;
+	u16 lro_length, length, data_offset, t_vid, vid = 0xffff;
 	u32 seq_number;
 
 	if (unlikely(ring > adapter->max_rds_rings))
@@ -961,6 +1099,14 @@
 	if (!skb)
 		return buffer;
 
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+
 	if (timestamp)
 		data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
 	else
@@ -976,18 +1122,32 @@
 	}
 
 	skb->protocol = eth_type_trans(skb, netdev);
-	iph = (struct iphdr *)skb->data;
-	th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
-	length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
-	iph->tot_len = htons(length);
-	iph->check = 0;
-	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+	if (ntohs(skb->protocol) == ETH_P_IPV6) {
+		ipv6h = (struct ipv6hdr *)skb->data;
+		th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+		length = (th->doff << 2) + lro_length;
+		ipv6h->payload_len = htons(length);
+	} else {
+		iph = (struct iphdr *)skb->data;
+		th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+		length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+		iph->tot_len = htons(length);
+		iph->check = 0;
+		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+	}
+
 	th->psh = push;
 	th->seq = htonl(seq_number);
 	length = skb->len;
 
-	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) {
 		skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+		if (skb->protocol == htons(ETH_P_IPV6))
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+		else
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+	}
 
 	if (vid != 0xffff)
 		__vlan_hwaccel_put_tag(skb, vid);
@@ -1006,9 +1166,9 @@
 	struct list_head *cur;
 	struct status_desc *desc;
 	struct qlcnic_rx_buffer *rxbuf;
+	int opcode, desc_cnt, count = 0;
 	u64 sts_data0, sts_data1;
-	__le64 owner_phantom = cpu_to_le64(STATUS_OWNER_PHANTOM);
-	int opcode, ring, desc_cnt, count = 0;
+	u8 ring;
 	u32 consumer = sds_ring->consumer;
 
 	while (count < max) {
@@ -1020,7 +1180,6 @@
 
 		desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
 		opcode = qlcnic_get_sts_opcode(sts_data0);
-
 		switch (opcode) {
 		case QLCNIC_RXPKT_DESC:
 		case QLCNIC_OLD_RXPKT_DESC:
@@ -1040,18 +1199,16 @@
 		default:
 			goto skip;
 		}
-
 		WARN_ON(desc_cnt > 1);
 
 		if (likely(rxbuf))
 			list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
 		else
 			adapter->stats.null_rxbuf++;
-
 skip:
 		for (; desc_cnt > 0; desc_cnt--) {
 			desc = &sds_ring->desc_head[consumer];
-			desc->status_desc_data[0] = owner_phantom;
+			desc->status_desc_data[0] = QLCNIC_DESC_OWNER_FW;
 			consumer = get_next_index(consumer, sds_ring->num_desc);
 		}
 		count++;
@@ -1059,7 +1216,6 @@
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
 		rds_ring = &adapter->recv_ctx->rds_rings[ring];
-
 		if (!list_empty(&sds_ring->free_list[ring])) {
 			list_for_each(cur, &sds_ring->free_list[ring]) {
 				rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
@@ -1072,7 +1228,7 @@
 			spin_unlock(&rds_ring->lock);
 		}
 
-		qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
+		qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
 	}
 
 	if (count) {
@@ -1084,12 +1240,12 @@
 }
 
 void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
-			    struct qlcnic_host_rds_ring *rds_ring)
+			    struct qlcnic_host_rds_ring *rds_ring, u8 ring_id)
 {
 	struct rcv_desc *pdesc;
 	struct qlcnic_rx_buffer *buffer;
 	int count = 0;
-	u32 producer;
+	u32 producer, handle;
 	struct list_head *head;
 
 	producer = rds_ring->producer;
@@ -1110,7 +1266,9 @@
 		/* make a rcv descriptor  */
 		pdesc = &rds_ring->desc_head[producer];
 		pdesc->addr_buffer = cpu_to_le64(buffer->dma);
-		pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+		handle = qlcnic_get_ref_handle(adapter, buffer->ref_handle,
+					       ring_id);
+		pdesc->reference_handle = cpu_to_le16(handle);
 		pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
 		producer = get_next_index(producer, rds_ring->num_desc);
 	}
@@ -1180,7 +1338,7 @@
 	return;
 }
 
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+void qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
 {
 	struct qlcnic_adapter *adapter = sds_ring->adapter;
 	struct status_desc *desc;
@@ -1217,26 +1375,8 @@
 	writel(consumer, sds_ring->crb_sts_consumer);
 }
 
-void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
-{
-	u32 mac_low, mac_high;
-	int i;
-
-	mac_low = off1;
-	mac_high = off2;
-
-	if (alt_mac) {
-		mac_low |= (mac_low >> 16) | (mac_high << 16);
-		mac_high >>= 16;
-	}
-
-	for (i = 0; i < 2; i++)
-		mac[i] = (u8)(mac_high >> ((1 - i) * 8));
-	for (i = 2; i < 6; i++)
-		mac[i] = (u8)(mac_low >> ((5 - i) * 8));
-}
-
-int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
+			 struct net_device *netdev)
 {
 	int ring, max_sds_rings;
 	struct qlcnic_host_sds_ring *sds_ring;
@@ -1249,8 +1389,7 @@
 
 	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 		sds_ring = &recv_ctx->sds_rings[ring];
-
-		if (ring == max_sds_rings - 1)
+		if (ring == adapter->max_sds_rings - 1)
 			netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
 				       QLCNIC_NETDEV_WEIGHT / max_sds_rings);
 		else
@@ -1258,10 +1397,15 @@
 				       QLCNIC_NETDEV_WEIGHT*2);
 	}
 
+	if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+		qlcnic_free_sds_rings(recv_ctx);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
-void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)
 {
 	int ring;
 	struct qlcnic_host_sds_ring *sds_ring;
@@ -1273,9 +1417,10 @@
 	}
 
 	qlcnic_free_sds_rings(adapter->recv_ctx);
+	qlcnic_free_tx_rings(adapter);
 }
 
-void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)
 {
 	int ring;
 	struct qlcnic_host_sds_ring *sds_ring;
@@ -1291,7 +1436,7 @@
 	}
 }
 
-void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
 {
 	int ring;
 	struct qlcnic_host_sds_ring *sds_ring;
@@ -1307,3 +1452,481 @@
 		napi_disable(&sds_ring->napi);
 	}
 }
+
+#define QLC_83XX_NORMAL_LB_PKT	(1ULL << 36)
+#define QLC_83XX_LRO_LB_PKT	(1ULL << 46)
+
+static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
+{
+	if (lro_pkt)
+		return (sts_data & QLC_83XX_LRO_LB_PKT) ? 1 : 0;
+	else
+		return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
+			struct qlcnic_host_sds_ring *sds_ring,
+			u8 ring, u64 sts_data[])
+{
+	struct net_device *netdev = adapter->netdev;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_rx_buffer *buffer;
+	struct sk_buff *skb;
+	struct qlcnic_host_rds_ring *rds_ring;
+	int index, length, cksum, is_lb_pkt;
+	u16 vid = 0xffff, t_vid;
+
+	if (unlikely(ring >= adapter->max_rds_rings))
+		return NULL;
+
+	rds_ring = &recv_ctx->rds_rings[ring];
+
+	index = qlcnic_83xx_hndl(sts_data[0]);
+	if (unlikely(index >= rds_ring->num_desc))
+		return NULL;
+
+	buffer = &rds_ring->rx_buf_arr[index];
+	length = qlcnic_83xx_pktln(sts_data[0]);
+	cksum  = qlcnic_83xx_csum_status(sts_data[1]);
+	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+	if (!skb)
+		return buffer;
+
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+
+	if (length > rds_ring->skb_size)
+		skb_put(skb, rds_ring->skb_size);
+	else
+		skb_put(skb, length);
+
+	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+		adapter->stats.rxdropped++;
+		dev_kfree_skb(skb);
+		return buffer;
+	}
+
+	skb->protocol = eth_type_trans(skb, netdev);
+
+	if (vid != 0xffff)
+		__vlan_hwaccel_put_tag(skb, vid);
+
+	napi_gro_receive(&sds_ring->napi, skb);
+
+	adapter->stats.rx_pkts++;
+	adapter->stats.rxbytes += length;
+
+	return buffer;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
+			u8 ring, u64 sts_data[])
+{
+	struct net_device *netdev = adapter->netdev;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_rx_buffer *buffer;
+	struct sk_buff *skb;
+	struct qlcnic_host_rds_ring *rds_ring;
+	struct iphdr *iph;
+	struct ipv6hdr *ipv6h;
+	struct tcphdr *th;
+	bool push;
+	int l2_hdr_offset, l4_hdr_offset;
+	int index, is_lb_pkt;
+	u16 lro_length, length, data_offset, gso_size;
+	u16 vid = 0xffff, t_vid;
+
+	if (unlikely(ring > adapter->max_rds_rings))
+		return NULL;
+
+	rds_ring = &recv_ctx->rds_rings[ring];
+
+	index = qlcnic_83xx_hndl(sts_data[0]);
+	if (unlikely(index > rds_ring->num_desc))
+		return NULL;
+
+	buffer = &rds_ring->rx_buf_arr[index];
+
+	lro_length = qlcnic_83xx_lro_pktln(sts_data[0]);
+	l2_hdr_offset = qlcnic_83xx_l2_hdr_off(sts_data[1]);
+	l4_hdr_offset = qlcnic_83xx_l4_hdr_off(sts_data[1]);
+	push = qlcnic_83xx_is_psh_bit(sts_data[1]);
+
+	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+	if (!skb)
+		return buffer;
+
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+	if (qlcnic_83xx_is_tstamp(sts_data[1]))
+		data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
+	else
+		data_offset = l4_hdr_offset + QLCNIC_TCP_HDR_SIZE;
+
+	skb_put(skb, lro_length + data_offset);
+	skb_pull(skb, l2_hdr_offset);
+
+	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+		adapter->stats.rxdropped++;
+		dev_kfree_skb(skb);
+		return buffer;
+	}
+
+	skb->protocol = eth_type_trans(skb, netdev);
+	if (ntohs(skb->protocol) == ETH_P_IPV6) {
+		ipv6h = (struct ipv6hdr *)skb->data;
+		th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+
+		length = (th->doff << 2) + lro_length;
+		ipv6h->payload_len = htons(length);
+	} else {
+		iph = (struct iphdr *)skb->data;
+		th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+		length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+		iph->tot_len = htons(length);
+		iph->check = 0;
+		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+	}
+
+	th->psh = push;
+	length = skb->len;
+
+	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) {
+		gso_size = qlcnic_83xx_get_lro_sts_mss(sts_data[0]);
+		skb_shinfo(skb)->gso_size = gso_size;
+		if (skb->protocol == htons(ETH_P_IPV6))
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+		else
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+	}
+
+	if (vid != 0xffff)
+		__vlan_hwaccel_put_tag(skb, vid);
+
+	netif_receive_skb(skb);
+
+	adapter->stats.lro_pkts++;
+	adapter->stats.lrobytes += length;
+	return buffer;
+}
+
+static int qlcnic_83xx_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring,
+					int max)
+{
+	struct qlcnic_host_rds_ring *rds_ring;
+	struct qlcnic_adapter *adapter = sds_ring->adapter;
+	struct list_head *cur;
+	struct status_desc *desc;
+	struct qlcnic_rx_buffer *rxbuf = NULL;
+	u8 ring;
+	u64 sts_data[2];
+	int count = 0, opcode;
+	u32 consumer = sds_ring->consumer;
+
+	while (count < max) {
+		desc = &sds_ring->desc_head[consumer];
+		sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+		opcode = qlcnic_83xx_opcode(sts_data[1]);
+		if (!opcode)
+			break;
+		sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+		ring = QLCNIC_FETCH_RING_ID(sts_data[0]);
+
+		switch (opcode) {
+		case QLC_83XX_REG_DESC:
+			rxbuf = qlcnic_83xx_process_rcv(adapter, sds_ring,
+							ring, sts_data);
+			break;
+		case QLC_83XX_LRO_DESC:
+			rxbuf = qlcnic_83xx_process_lro(adapter, ring,
+							sts_data);
+			break;
+		default:
+			dev_info(&adapter->pdev->dev,
+				 "Unkonwn opcode: 0x%x\n", opcode);
+			goto skip;
+		}
+
+		if (likely(rxbuf))
+			list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+		else
+			adapter->stats.null_rxbuf++;
+skip:
+		desc = &sds_ring->desc_head[consumer];
+		/* Reset the descriptor */
+		desc->status_desc_data[1] = 0;
+		consumer = get_next_index(consumer, sds_ring->num_desc);
+		count++;
+	}
+	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+		rds_ring = &adapter->recv_ctx->rds_rings[ring];
+		if (!list_empty(&sds_ring->free_list[ring])) {
+			list_for_each(cur, &sds_ring->free_list[ring]) {
+				rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
+						   list);
+				qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+			}
+			spin_lock(&rds_ring->lock);
+			list_splice_tail_init(&sds_ring->free_list[ring],
+					      &rds_ring->free_list);
+			spin_unlock(&rds_ring->lock);
+		}
+		qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
+	}
+	if (count) {
+		sds_ring->consumer = consumer;
+		writel(consumer, sds_ring->crb_sts_consumer);
+	}
+	return count;
+}
+
+static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
+{
+	int tx_complete;
+	int work_done;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_adapter *adapter;
+	struct qlcnic_host_tx_ring *tx_ring;
+
+	sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+	adapter = sds_ring->adapter;
+	/* tx ring count = 1 */
+	tx_ring = adapter->tx_ring;
+
+	tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+	if ((work_done < budget) && tx_complete) {
+		napi_complete(&sds_ring->napi);
+		qlcnic_83xx_enable_intr(adapter, sds_ring);
+	}
+
+	return work_done;
+}
+
+static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)
+{
+	int work_done;
+	struct qlcnic_host_tx_ring *tx_ring;
+	struct qlcnic_adapter *adapter;
+
+	budget = QLCNIC_TX_POLL_BUDGET;
+	tx_ring = container_of(napi, struct qlcnic_host_tx_ring, napi);
+	adapter = tx_ring->adapter;
+	work_done = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+	if (work_done) {
+		napi_complete(&tx_ring->napi);
+		if (test_bit(__QLCNIC_DEV_UP , &adapter->state))
+			qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+	}
+
+	return work_done;
+}
+
+static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget)
+{
+	int work_done;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_adapter *adapter;
+
+	sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+	adapter = sds_ring->adapter;
+	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+	if (work_done < budget) {
+		napi_complete(&sds_ring->napi);
+		if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+			qlcnic_83xx_enable_intr(adapter, sds_ring);
+	}
+
+	return work_done;
+}
+
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
+{
+	int ring;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_host_tx_ring *tx_ring;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+		return;
+
+	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+		sds_ring = &recv_ctx->sds_rings[ring];
+		napi_enable(&sds_ring->napi);
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			qlcnic_83xx_enable_intr(adapter, sds_ring);
+	}
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+			tx_ring = &adapter->tx_ring[ring];
+			napi_enable(&tx_ring->napi);
+			qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+		}
+	}
+}
+
+void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
+{
+	int ring;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_host_tx_ring *tx_ring;
+
+	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+		return;
+
+	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+		sds_ring = &recv_ctx->sds_rings[ring];
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			qlcnic_83xx_disable_intr(adapter, sds_ring);
+		napi_synchronize(&sds_ring->napi);
+		napi_disable(&sds_ring->napi);
+	}
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+			tx_ring = &adapter->tx_ring[ring];
+			qlcnic_83xx_disable_tx_intr(adapter, tx_ring);
+			napi_synchronize(&tx_ring->napi);
+			napi_disable(&tx_ring->napi);
+		}
+	}
+}
+
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,
+			 struct net_device *netdev)
+{
+	int ring, max_sds_rings;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_host_tx_ring *tx_ring;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+	if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+		return -ENOMEM;
+
+	max_sds_rings = adapter->max_sds_rings;
+	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+		sds_ring = &recv_ctx->sds_rings[ring];
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			netif_napi_add(netdev, &sds_ring->napi,
+				       qlcnic_83xx_rx_poll,
+				       QLCNIC_NETDEV_WEIGHT * 2);
+		else
+			netif_napi_add(netdev, &sds_ring->napi,
+				       qlcnic_83xx_poll,
+				       QLCNIC_NETDEV_WEIGHT / max_sds_rings);
+	}
+
+	if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+		qlcnic_free_sds_rings(recv_ctx);
+		return -ENOMEM;
+	}
+
+	if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+			tx_ring = &adapter->tx_ring[ring];
+			netif_napi_add(netdev, &tx_ring->napi,
+				       qlcnic_83xx_msix_tx_poll,
+				       QLCNIC_NETDEV_WEIGHT);
+		}
+	}
+
+	return 0;
+}
+
+void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)
+{
+	int ring;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct qlcnic_host_tx_ring *tx_ring;
+
+	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+		sds_ring = &recv_ctx->sds_rings[ring];
+		netif_napi_del(&sds_ring->napi);
+	}
+
+	qlcnic_free_sds_rings(adapter->recv_ctx);
+
+	if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+			tx_ring = &adapter->tx_ring[ring];
+			netif_napi_del(&tx_ring->napi);
+		}
+	}
+
+	qlcnic_free_tx_rings(adapter);
+}
+
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter,
+				  int ring, u64 sts_data[])
+{
+	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+	struct sk_buff *skb;
+	struct qlcnic_host_rds_ring *rds_ring;
+	int index, length;
+
+	if (unlikely(ring >= adapter->max_rds_rings))
+		return;
+
+	rds_ring = &recv_ctx->rds_rings[ring];
+	index = qlcnic_83xx_hndl(sts_data[0]);
+	if (unlikely(index >= rds_ring->num_desc))
+		return;
+
+	length = qlcnic_83xx_pktln(sts_data[0]);
+
+	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+	if (!skb)
+		return;
+
+	if (length > rds_ring->skb_size)
+		skb_put(skb, rds_ring->skb_size);
+	else
+		skb_put(skb, length);
+
+	if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+		adapter->ahw->diag_cnt++;
+	else
+		dump_skb(skb, adapter);
+
+	dev_kfree_skb_any(skb);
+	return;
+}
+
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+	struct qlcnic_adapter *adapter = sds_ring->adapter;
+	struct status_desc *desc;
+	u64 sts_data[2];
+	int ring, opcode;
+	u32 consumer = sds_ring->consumer;
+
+	desc = &sds_ring->desc_head[consumer];
+	sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+	sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+	opcode = qlcnic_83xx_opcode(sts_data[1]);
+	if (!opcode)
+		return;
+
+	ring = QLCNIC_FETCH_RING_ID(qlcnic_83xx_hndl(sts_data[0]));
+	qlcnic_83xx_process_rcv_diag(adapter, ring, sts_data);
+	desc = &sds_ring->desc_head[consumer];
+	desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+	consumer = get_next_index(consumer, sds_ring->num_desc);
+	sds_ring->consumer = consumer;
+	writel(consumer, sds_ring->crb_sts_consumer);
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index d833f59..5d5fd06 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1,24 +1,25 @@
 /*
  * QLogic qlcnic NIC Driver
- * Copyright (c)  2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
  *
  * See LICENSE.qlcnic for copyright and licensing details.
  */
 
-#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 #include <linux/swab.h>
 #include <linux/dma-mapping.h>
+#include <linux/if_vlan.h>
 #include <net/ip.h>
 #include <linux/ipv6.h>
 #include <linux/inetdevice.h>
-#include <linux/sysfs.h>
 #include <linux/aer.h>
 #include <linux/log2.h>
+#include <linux/pci.h>
 
 MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
 MODULE_LICENSE("GPL");
@@ -29,28 +30,28 @@
 static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
 	"Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
 
-static struct workqueue_struct *qlcnic_wq;
 static int qlcnic_mac_learn;
 module_param(qlcnic_mac_learn, int, 0444);
-MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
+MODULE_PARM_DESC(qlcnic_mac_learn,
+		 "Mac Filter (0=learning is disabled, 1=Driver learning is enabled, 2=FDB learning is enabled)");
 
-static int qlcnic_use_msi = 1;
+int qlcnic_use_msi = 1;
 MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
 module_param_named(use_msi, qlcnic_use_msi, int, 0444);
 
-static int qlcnic_use_msi_x = 1;
+int qlcnic_use_msi_x = 1;
 MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
 module_param_named(use_msi_x, qlcnic_use_msi_x, int, 0444);
 
-static int qlcnic_auto_fw_reset = 1;
+int qlcnic_auto_fw_reset = 1;
 MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
 module_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
 
-static int qlcnic_load_fw_file;
+int qlcnic_load_fw_file;
 MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
 module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
 
-static int qlcnic_config_npars;
+int qlcnic_config_npars;
 module_param(qlcnic_config_npars, int, 0444);
 MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
 
@@ -62,9 +63,6 @@
 static void qlcnic_attach_work(struct work_struct *work);
 static void qlcnic_fwinit_work(struct work_struct *work);
 static void qlcnic_fw_poll_work(struct work_struct *work);
-static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
-		work_func_t func, int delay);
-static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev);
 #endif
@@ -77,9 +75,9 @@
 static irqreturn_t qlcnic_intr(int irq, void *data);
 static irqreturn_t qlcnic_msi_intr(int irq, void *data);
 static irqreturn_t qlcnic_msix_intr(int irq, void *data);
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data);
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
-static void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long);
 static int qlcnic_start_firmware(struct qlcnic_adapter *);
 
 static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
@@ -93,15 +91,24 @@
 #define QLCNIC_IS_TSO_CAPABLE(adapter)	\
 	((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
 
+static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X)
+		return ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX;
+	else
+		return 1;
+}
+
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
 	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
 	.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
 
-#define PCI_DEVICE_ID_QLOGIC_QLE824X  0x8020
-
 static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
 	ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
+	ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
 	{0,}
 };
 
@@ -120,6 +127,32 @@
 	ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
 };
 
+static const u32 qlcnic_reg_tbl[] = {
+	0x1B20A8,	/* PEG_HALT_STAT1 */
+	0x1B20AC,	/* PEG_HALT_STAT2 */
+	0x1B20B0,	/* FW_HEARTBEAT */
+	0x1B2100,	/* LOCK ID */
+	0x1B2128,	/* FW_CAPABILITIES */
+	0x1B2138,	/* drv active */
+	0x1B2140,	/* dev state */
+	0x1B2144,	/* drv state */
+	0x1B2148,	/* drv scratch */
+	0x1B214C,	/* dev partition info */
+	0x1B2174,	/* drv idc ver */
+	0x1B2150,	/* fw version major */
+	0x1B2154,	/* fw version minor */
+	0x1B2158,	/* fw version sub */
+	0x1B219C,	/* npar state */
+	0x1B21FC,	/* FW_IMG_VALID */
+	0x1B2250,	/* CMD_PEG_STATE */
+	0x1B233C,	/* RCV_PEG_STATE */
+	0x1B23B4,	/* ASIC TEMP */
+	0x1B216C,	/* FW api */
+	0x1B2170,	/* drv op mode */
+	0x13C010,	/* flash lock */
+	0x13C014,	/* flash unlock */
+};
+
 static const struct qlcnic_board_info qlcnic_boards[] = {
 	{0x1077, 0x8020, 0x1077, 0x203,
 	 "8200 Series Single Port 10GbE Converged Network Adapter"
@@ -143,6 +176,7 @@
 };
 
 #define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
+#define QLC_MAX_SDS_RINGS	8
 
 static const
 struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
@@ -164,35 +198,6 @@
 	recv_ctx->sds_rings = NULL;
 }
 
-static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
-{
-	memset(&adapter->stats, 0, sizeof(adapter->stats));
-}
-
-static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
-{
-	u32 control;
-	int pos;
-
-	pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-	if (pos) {
-		pci_read_config_dword(pdev, pos, &control);
-		if (enable)
-			control |= PCI_MSIX_FLAGS_ENABLE;
-		else
-			control = 0;
-		pci_write_config_dword(pdev, pos, control);
-	}
-}
-
-static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
-{
-	int i;
-
-	for (i = 0; i < count; i++)
-		adapter->msix_entries[i].entry = i;
-}
-
 static int
 qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
 {
@@ -204,12 +209,11 @@
 		return -EIO;
 
 	memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
-	memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
 	memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
 
 	/* set station address */
 
-	if (!is_valid_ether_addr(netdev->perm_addr))
+	if (!is_valid_ether_addr(netdev->dev_addr))
 		dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
 					netdev->dev_addr);
 
@@ -225,7 +229,7 @@
 		return -EOPNOTSUPP;
 
 	if (!is_valid_ether_addr(addr->sa_data))
-		return -EADDRNOTAVAIL;
+		return -EINVAL;
 
 	if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
 		netif_device_detach(netdev);
@@ -243,6 +247,85 @@
 	return 0;
 }
 
+static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+			struct net_device *netdev, const unsigned char *addr)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	int err = -EOPNOTSUPP;
+
+	if (!adapter->fdb_mac_learn) {
+		pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+			__func__);
+		return err;
+	}
+
+	if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
+		if (is_unicast_ether_addr(addr))
+			err = qlcnic_nic_del_mac(adapter, addr);
+		else if (is_multicast_ether_addr(addr))
+			err = dev_mc_del(netdev, addr);
+		else
+			err =  -EINVAL;
+	}
+	return err;
+}
+
+static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+			struct net_device *netdev,
+			const unsigned char *addr, u16 flags)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+	int err = 0;
+
+	if (!adapter->fdb_mac_learn) {
+		pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+			__func__);
+		return -EOPNOTSUPP;
+	}
+
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		pr_info("%s: FDB e-switch is not enabled\n", __func__);
+		return -EOPNOTSUPP;
+	}
+
+	if (ether_addr_equal(addr, adapter->mac_addr))
+		return err;
+
+	if (is_unicast_ether_addr(addr))
+		err = qlcnic_nic_add_mac(adapter, addr);
+	else if (is_multicast_ether_addr(addr))
+		err = dev_mc_add_excl(netdev, addr);
+	else
+		err = -EINVAL;
+
+	return err;
+}
+
+static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
+			struct net_device *netdev, int idx)
+{
+	struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+	if (!adapter->fdb_mac_learn) {
+		pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+			__func__);
+		return -EOPNOTSUPP;
+	}
+
+	if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+		idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
+
+	return idx;
+}
+
+static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+		usleep_range(10000, 11000);
+
+	cancel_delayed_work_sync(&adapter->fw_work);
+}
+
 static const struct net_device_ops qlcnic_netdev_ops = {
 	.ndo_open	   = qlcnic_open,
 	.ndo_stop	   = qlcnic_close,
@@ -257,6 +340,9 @@
 	.ndo_tx_timeout	   = qlcnic_tx_timeout,
 	.ndo_vlan_rx_add_vid	= qlcnic_vlan_rx_add,
 	.ndo_vlan_rx_kill_vid	= qlcnic_vlan_rx_del,
+	.ndo_fdb_add		= qlcnic_fdb_add,
+	.ndo_fdb_del		= qlcnic_fdb_del,
+	.ndo_fdb_dump		= qlcnic_fdb_dump,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller = qlcnic_poll_controller,
 #endif
@@ -267,50 +353,125 @@
 };
 
 static struct qlcnic_nic_template qlcnic_ops = {
-	.config_bridged_mode = qlcnic_config_bridged_mode,
-	.config_led = qlcnic_config_led,
-	.start_firmware = qlcnic_start_firmware
+	.config_bridged_mode	= qlcnic_config_bridged_mode,
+	.config_led		= qlcnic_82xx_config_led,
+	.start_firmware		= qlcnic_82xx_start_firmware,
+	.request_reset		= qlcnic_82xx_dev_request_reset,
+	.cancel_idc_work	= qlcnic_82xx_cancel_idc_work,
+	.napi_add		= qlcnic_82xx_napi_add,
+	.napi_del		= qlcnic_82xx_napi_del,
+	.config_ipaddr		= qlcnic_82xx_config_ipaddr,
+	.clear_legacy_intr	= qlcnic_82xx_clear_legacy_intr,
 };
 
-static struct qlcnic_nic_template qlcnic_vf_ops = {
-	.config_bridged_mode = qlcnicvf_config_bridged_mode,
-	.config_led = qlcnicvf_config_led,
-	.start_firmware = qlcnicvf_start_firmware
+struct qlcnic_nic_template qlcnic_vf_ops = {
+	.config_bridged_mode	= qlcnicvf_config_bridged_mode,
+	.config_led		= qlcnicvf_config_led,
+	.start_firmware		= qlcnicvf_start_firmware
 };
 
-static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
+static struct qlcnic_hardware_ops qlcnic_hw_ops = {
+	.read_crb			= qlcnic_82xx_read_crb,
+	.write_crb			= qlcnic_82xx_write_crb,
+	.read_reg			= qlcnic_82xx_hw_read_wx_2M,
+	.write_reg			= qlcnic_82xx_hw_write_wx_2M,
+	.get_mac_address		= qlcnic_82xx_get_mac_address,
+	.setup_intr			= qlcnic_82xx_setup_intr,
+	.alloc_mbx_args			= qlcnic_82xx_alloc_mbx_args,
+	.mbx_cmd			= qlcnic_82xx_issue_cmd,
+	.get_func_no			= qlcnic_82xx_get_func_no,
+	.api_lock			= qlcnic_82xx_api_lock,
+	.api_unlock			= qlcnic_82xx_api_unlock,
+	.add_sysfs			= qlcnic_82xx_add_sysfs,
+	.remove_sysfs			= qlcnic_82xx_remove_sysfs,
+	.process_lb_rcv_ring_diag	= qlcnic_82xx_process_rcv_ring_diag,
+	.create_rx_ctx			= qlcnic_82xx_fw_cmd_create_rx_ctx,
+	.create_tx_ctx			= qlcnic_82xx_fw_cmd_create_tx_ctx,
+	.setup_link_event		= qlcnic_82xx_linkevent_request,
+	.get_nic_info			= qlcnic_82xx_get_nic_info,
+	.get_pci_info			= qlcnic_82xx_get_pci_info,
+	.set_nic_info			= qlcnic_82xx_set_nic_info,
+	.change_macvlan			= qlcnic_82xx_sre_macaddr_change,
+	.napi_enable			= qlcnic_82xx_napi_enable,
+	.napi_disable			= qlcnic_82xx_napi_disable,
+	.config_intr_coal		= qlcnic_82xx_config_intr_coalesce,
+	.config_rss			= qlcnic_82xx_config_rss,
+	.config_hw_lro			= qlcnic_82xx_config_hw_lro,
+	.config_loopback		= qlcnic_82xx_set_lb_mode,
+	.clear_loopback			= qlcnic_82xx_clear_lb_mode,
+	.config_promisc_mode		= qlcnic_82xx_nic_set_promisc,
+	.change_l2_filter		= qlcnic_82xx_change_filter,
+	.get_board_info			= qlcnic_82xx_get_board_info,
+};
+
+int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
 {
 	struct pci_dev *pdev = adapter->pdev;
-	int err = -1;
+	int err = -1, i;
+	int max_tx_rings;
+
+	if (!adapter->msix_entries) {
+		adapter->msix_entries = kcalloc(num_msix,
+						sizeof(struct msix_entry),
+						GFP_KERNEL);
+		if (!adapter->msix_entries)
+			return -ENOMEM;
+	}
 
 	adapter->max_sds_rings = 1;
 	adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
-	qlcnic_set_msix_bit(pdev, 0);
 
 	if (adapter->ahw->msix_supported) {
  enable_msix:
-		qlcnic_init_msix_entries(adapter, num_msix);
+		for (i = 0; i < num_msix; i++)
+			adapter->msix_entries[i].entry = i;
 		err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
 		if (err == 0) {
 			adapter->flags |= QLCNIC_MSIX_ENABLED;
-			qlcnic_set_msix_bit(pdev, 1);
-
-			adapter->max_sds_rings = num_msix;
-
+			if (qlcnic_83xx_check(adapter)) {
+				adapter->ahw->num_msix = num_msix;
+				/* subtract mail box and tx ring vectors */
+				max_tx_rings = adapter->max_drv_tx_rings;
+				adapter->max_sds_rings = num_msix -
+							 max_tx_rings - 1;
+			} else {
+				adapter->max_sds_rings = num_msix;
+			}
 			dev_info(&pdev->dev, "using msi-x interrupts\n");
 			return err;
-		}
-		if (err > 0) {
-			num_msix = rounddown_pow_of_two(err);
-			if (num_msix)
+		} else if (err > 0) {
+			dev_info(&pdev->dev,
+				 "Unable to allocate %d MSI-X interrupt vectors\n",
+				 num_msix);
+			if (qlcnic_83xx_check(adapter)) {
+				if (err < QLC_83XX_MINIMUM_VECTOR)
+					return err;
+				err -= (adapter->max_drv_tx_rings + 1);
+				num_msix = rounddown_pow_of_two(err);
+				num_msix += (adapter->max_drv_tx_rings + 1);
+			} else {
+				num_msix = rounddown_pow_of_two(err);
+			}
+
+			if (num_msix) {
+				dev_info(&pdev->dev,
+					 "Trying to allocate %d MSI-X interrupt vectors\n",
+					 num_msix);
 				goto enable_msix;
+			}
+		} else {
+			dev_info(&pdev->dev,
+				 "Unable to allocate %d MSI-X interrupt vectors\n",
+				 num_msix);
 		}
 	}
+
 	return err;
 }
 
-static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
+static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
 {
+	int err = 0;
 	u32 offset, mask_reg;
 	const struct qlcnic_legacy_intr_set *legacy_intrp;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -323,8 +484,10 @@
 							    offset);
 		dev_info(&pdev->dev, "using msi interrupts\n");
 		adapter->msix_entries[0].vector = pdev->irq;
-		return;
+		return err;
 	}
+	if (qlcnic_use_msi || qlcnic_use_msi_x)
+		return -EOPNOTSUPP;
 
 	legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
 	adapter->ahw->int_vec_bit = legacy_intrp->int_vec_bit;
@@ -336,32 +499,47 @@
 	adapter->crb_int_state_reg = qlcnic_get_ioaddr(ahw, ISR_INT_STATE_REG);
 	dev_info(&pdev->dev, "using legacy interrupts\n");
 	adapter->msix_entries[0].vector = pdev->irq;
+	return err;
 }
 
-static void
-qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
 {
-	int num_msix;
+	int num_msix, err = 0;
 
-	if (adapter->ahw->msix_supported) {
+	if (!num_intr)
+		num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+
+	if (adapter->ahw->msix_supported)
 		num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
-				QLCNIC_DEF_NUM_STS_DESC_RINGS));
-	} else
+						num_intr));
+	else
 		num_msix = 1;
 
-	if (!qlcnic_enable_msix(adapter, num_msix))
-		return;
+	err = qlcnic_enable_msix(adapter, num_msix);
+	if (err == -ENOMEM || !err)
+		return err;
 
-	qlcnic_enable_msi_legacy(adapter);
+	err = qlcnic_enable_msi_legacy(adapter);
+	if (!err)
+		return err;
+
+	return -EIO;
 }
 
-static void
-qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
+void qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
 {
 	if (adapter->flags & QLCNIC_MSIX_ENABLED)
 		pci_disable_msix(adapter->pdev);
 	if (adapter->flags & QLCNIC_MSI_ENABLED)
 		pci_disable_msi(adapter->pdev);
+
+	kfree(adapter->msix_entries);
+	adapter->msix_entries = NULL;
+
+	if (adapter->ahw->intr_tbl) {
+		vfree(adapter->ahw->intr_tbl);
+		adapter->ahw->intr_tbl = NULL;
+	}
 }
 
 static void
@@ -371,7 +549,36 @@
 		iounmap(adapter->ahw->pci_base0);
 }
 
-static int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_pci_info *pci_info;
+	int ret;
+
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		switch (adapter->ahw->port_type) {
+		case QLCNIC_GBE:
+			adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_GBE_PORTS;
+			break;
+		case QLCNIC_XGBE:
+			adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_XG_PORTS;
+			break;
+		}
+		return 0;
+	}
+
+	if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+		return 0;
+
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
+	ret = qlcnic_get_pci_info(adapter, pci_info);
+	kfree(pci_info);
+	return ret;
+}
+
+int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_pci_info *pci_info;
 	int i, ret = 0, j = 0;
@@ -423,8 +630,11 @@
 		j++;
 	}
 
-	for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+	for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) {
 		adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+		if (qlcnic_83xx_check(adapter))
+			qlcnic_enable_eswitch(adapter, i, 1);
+	}
 
 	kfree(pci_info);
 	return 0;
@@ -462,40 +672,31 @@
 					QLC_DEV_SET_DRV(0xf, id));
 		}
 	} else {
-		data = QLCRD32(adapter, QLCNIC_DRV_OP_MODE);
+		data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
 		data = (data & ~QLC_DEV_SET_DRV(0xf, ahw->pci_func)) |
 			(QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
 					 ahw->pci_func));
 	}
-	QLCWR32(adapter, QLCNIC_DRV_OP_MODE, data);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data);
 	qlcnic_api_unlock(adapter);
 err_lock:
 	return ret;
 }
 
-static void
-qlcnic_check_vf(struct qlcnic_adapter *adapter)
+static void qlcnic_check_vf(struct qlcnic_adapter *adapter,
+			    const struct pci_device_id *ent)
 {
-	void __iomem *msix_base_addr;
-	void __iomem *priv_op;
-	u32 func;
-	u32 msix_base;
 	u32 op_mode, priv_level;
 
 	/* Determine FW API version */
-	adapter->ahw->fw_hal_version = readl(adapter->ahw->pci_base0 +
-					     QLCNIC_FW_API);
+	adapter->ahw->fw_hal_version = QLC_SHARED_REG_RD32(adapter,
+							   QLCNIC_FW_API);
 
 	/* Find PCI function number */
-	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
-	msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
-	msix_base = readl(msix_base_addr);
-	func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
-	adapter->ahw->pci_func = func;
+	qlcnic_get_func_no(adapter);
 
 	/* Determine function privilege level */
-	priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
-	op_mode = readl(priv_op);
+	op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
 	if (op_mode == QLC_DEV_DRV_DEFAULT)
 		priv_level = QLCNIC_MGMT_FUNC;
 	else
@@ -512,12 +713,16 @@
 }
 
 #define QLCNIC_82XX_BAR0_LENGTH 0x00200000UL
+#define QLCNIC_83XX_BAR0_LENGTH 0x4000
 static void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
 {
 	switch (dev_id) {
 	case PCI_DEVICE_ID_QLOGIC_QLE824X:
 		*bar = QLCNIC_82XX_BAR0_LENGTH;
 		break;
+	case PCI_DEVICE_ID_QLOGIC_QLE834X:
+		*bar = QLCNIC_83XX_BAR0_LENGTH;
+		break;
 	default:
 		*bar = 0;
 	}
@@ -547,6 +752,7 @@
 	}
 
 	dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+
 	ahw->pci_base0 = mem_ptr0;
 	ahw->pci_len0 = pci_len0;
 	offset = QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func));
@@ -581,19 +787,26 @@
 static void
 qlcnic_check_options(struct qlcnic_adapter *adapter)
 {
+	int err;
 	u32 fw_major, fw_minor, fw_build, prev_fw_version;
 	struct pci_dev *pdev = adapter->pdev;
-	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
 
 	prev_fw_version = adapter->fw_version;
 
-	fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
-	fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
-	fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+	fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+	fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+	fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
 
 	adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
 
-	if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
+	err = qlcnic_get_board_info(adapter);
+	if (err) {
+		dev_err(&pdev->dev, "Error getting board config info.\n");
+		return;
+	}
+	if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
 		if (fw_dump->tmpl_hdr == NULL ||
 				adapter->fw_version > prev_fw_version) {
 			if (fw_dump->tmpl_hdr)
@@ -604,8 +817,9 @@
 		}
 	}
 
-	dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
-			fw_major, fw_minor, fw_build);
+	dev_info(&pdev->dev, "Driver v%s, firmware v%d.%d.%d\n",
+		 QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
 	if (adapter->ahw->port_type == QLCNIC_XGBE) {
 		if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
 			adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
@@ -648,9 +862,19 @@
 	adapter->ahw->max_tx_ques = nic_info.max_tx_ques;
 	adapter->ahw->max_rx_ques = nic_info.max_rx_ques;
 	adapter->ahw->capabilities = nic_info.capabilities;
+
+	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+		u32 temp;
+		temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+		adapter->ahw->capabilities2 = temp;
+	}
 	adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
 	adapter->ahw->max_mtu = nic_info.max_mtu;
 
+	/* Disable NPAR for 83XX */
+	if (qlcnic_83xx_check(adapter))
+		return err;
+
 	if (adapter->ahw->capabilities & BIT_6)
 		adapter->flags |= QLCNIC_ESWITCH_ENABLED;
 	else
@@ -709,7 +933,7 @@
 	qlcnic_set_netdev_features(adapter, esw_cfg);
 }
 
-static int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_esw_func_cfg esw_cfg;
 
@@ -730,14 +954,17 @@
 		struct qlcnic_esw_func_cfg *esw_cfg)
 {
 	struct net_device *netdev = adapter->netdev;
-	netdev_features_t features, vlan_features;
+	unsigned long features, vlan_features;
+
+	if (qlcnic_83xx_check(adapter))
+		return;
 
 	features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
-			NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+		    NETIF_F_IPV6_CSUM | NETIF_F_GRO);
 	vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
-			NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER);
+			NETIF_F_IPV6_CSUM);
 
-	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+	if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
 		features |= (NETIF_F_TSO | NETIF_F_TSO6);
 		vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
 	}
@@ -747,12 +974,19 @@
 
 	if (esw_cfg->offload_flags & BIT_0) {
 		netdev->features |= features;
-		if (!(esw_cfg->offload_flags & BIT_1))
+		adapter->rx_csum = 1;
+		if (!(esw_cfg->offload_flags & BIT_1)) {
 			netdev->features &= ~NETIF_F_TSO;
-		if (!(esw_cfg->offload_flags & BIT_2))
+			features &= ~NETIF_F_TSO;
+		}
+		if (!(esw_cfg->offload_flags & BIT_2)) {
 			netdev->features &= ~NETIF_F_TSO6;
+			features &= ~NETIF_F_TSO6;
+		}
 	} else {
 		netdev->features &= ~features;
+		features &= ~features;
+		adapter->rx_csum = 0;
 	}
 
 	netdev->vlan_features = (features & vlan_features);
@@ -761,7 +995,6 @@
 static int
 qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
 {
-	void __iomem *priv_op;
 	u32 op_mode, priv_level;
 	int err = 0;
 
@@ -772,8 +1005,7 @@
 	if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
 		return 0;
 
-	priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
-	op_mode = readl(priv_op);
+	op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
 	priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
 
 	if (op_mode == QLC_DEV_DRV_DEFAULT)
@@ -805,7 +1037,7 @@
 	return err;
 }
 
-static int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_esw_func_cfg esw_cfg;
 	struct qlcnic_npar_info *npar;
@@ -838,6 +1070,7 @@
 	return 0;
 }
 
+
 static int
 qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
 			struct qlcnic_npar_info *npar, int pci_func)
@@ -861,7 +1094,7 @@
 	return 0;
 }
 
-static int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
+int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
 {
 	int i, err;
 	struct qlcnic_npar_info *npar;
@@ -877,8 +1110,7 @@
 		npar = &adapter->npars[i];
 		pci_func = npar->pci_func;
 		memset(&nic_info, 0, sizeof(struct qlcnic_info));
-		err = qlcnic_get_nic_info(adapter,
-					  &nic_info, pci_func);
+		err = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
 		if (err)
 			return err;
 		nic_info.min_tx_bw = npar->min_bw;
@@ -909,10 +1141,12 @@
 	if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
 		return 0;
 
-	npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+	npar_state = QLC_SHARED_REG_RD32(adapter,
+					 QLCNIC_CRB_DEV_NPAR_STATE);
 	while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
 		msleep(1000);
-		npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+		npar_state = QLC_SHARED_REG_RD32(adapter,
+						 QLCNIC_CRB_DEV_NPAR_STATE);
 	}
 	if (!npar_opt_timeo) {
 		dev_err(&adapter->pdev->dev,
@@ -944,8 +1178,7 @@
 	return err;
 }
 
-static int
-qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter)
 {
 	int err;
 
@@ -985,9 +1218,8 @@
 	if (err)
 		goto err_out;
 
-	QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
 	qlcnic_idc_debug_info(adapter, 1);
-
 	err = qlcnic_check_eswitch_mode(adapter);
 	if (err) {
 		dev_err(&adapter->pdev->dev,
@@ -1005,7 +1237,7 @@
 	return 0;
 
 err_out:
-	QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
 	dev_err(&adapter->pdev->dev, "Device state set to failed\n");
 
 	qlcnic_release_firmware(adapter);
@@ -1017,6 +1249,7 @@
 {
 	irq_handler_t handler;
 	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_host_tx_ring *tx_ring;
 	int err, ring;
 
 	unsigned long flags = 0;
@@ -1024,7 +1257,8 @@
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
 	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
-		handler = qlcnic_tmp_intr;
+		if (qlcnic_82xx_check(adapter))
+			handler = qlcnic_tmp_intr;
 		if (!QLCNIC_IS_MSI_FAMILY(adapter))
 			flags |= IRQF_SHARED;
 
@@ -1035,20 +1269,44 @@
 			handler = qlcnic_msi_intr;
 		else {
 			flags |= IRQF_SHARED;
-			handler = qlcnic_intr;
+			if (qlcnic_82xx_check(adapter))
+				handler = qlcnic_intr;
+			else
+				handler = qlcnic_83xx_intr;
 		}
 	}
 	adapter->irq = netdev->irq;
 
-	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-		sds_ring = &recv_ctx->sds_rings[ring];
-		sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
-		err = request_irq(sds_ring->irq, handler,
-				  flags, sds_ring->name, sds_ring);
-		if (err)
-			return err;
+	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+		if (qlcnic_82xx_check(adapter) ||
+		    (qlcnic_83xx_check(adapter) &&
+		     (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+			for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+				sds_ring = &recv_ctx->sds_rings[ring];
+				snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
+					 "%s[%d]", netdev->name, ring);
+				err = request_irq(sds_ring->irq, handler, flags,
+						  sds_ring->name, sds_ring);
+				if (err)
+					return err;
+			}
+		}
+		if (qlcnic_83xx_check(adapter) &&
+		    (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+			handler = qlcnic_msix_tx_intr;
+			for (ring = 0; ring < adapter->max_drv_tx_rings;
+			     ring++) {
+				tx_ring = &adapter->tx_ring[ring];
+				snprintf(tx_ring->name, sizeof(int) + IFNAMSIZ,
+					 "%s[%d]", netdev->name,
+					 adapter->max_sds_rings + ring);
+				err = request_irq(tx_ring->irq, handler, flags,
+						  tx_ring->name, tx_ring);
+				if (err)
+					return err;
+			}
+		}
 	}
-
 	return 0;
 }
 
@@ -1057,21 +1315,48 @@
 {
 	int ring;
 	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_host_tx_ring *tx_ring;
 
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-		sds_ring = &recv_ctx->sds_rings[ring];
-		free_irq(sds_ring->irq, sds_ring);
+	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+		if (qlcnic_82xx_check(adapter) ||
+		    (qlcnic_83xx_check(adapter) &&
+		     (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+			for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+				sds_ring = &recv_ctx->sds_rings[ring];
+				free_irq(sds_ring->irq, sds_ring);
+			}
+		}
+		if (qlcnic_83xx_check(adapter)) {
+			for (ring = 0; ring < adapter->max_drv_tx_rings;
+			     ring++) {
+				tx_ring = &adapter->tx_ring[ring];
+				if (tx_ring->irq)
+					free_irq(tx_ring->irq, tx_ring);
+			}
+		}
 	}
 }
 
-static int
-__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter)
+{
+	u32 capab = 0;
+
+	if (qlcnic_82xx_check(adapter)) {
+		if (adapter->ahw->capabilities2 &
+		    QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+	} else {
+		capab = adapter->ahw->capabilities;
+		if (QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(capab))
+			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+	}
+}
+
+int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
 	int ring;
-	u32 capab2;
-
 	struct qlcnic_host_rds_ring *rds_ring;
 
 	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1081,19 +1366,14 @@
 		return 0;
 	if (qlcnic_set_eswitch_port_config(adapter))
 		return -EIO;
-
-	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
-		capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
-		if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
-			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
-	}
+	qlcnic_get_lro_mss_capability(adapter);
 
 	if (qlcnic_fw_create_ctx(adapter))
 		return -EIO;
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
 		rds_ring = &adapter->recv_ctx->rds_rings[ring];
-		qlcnic_post_rx_buffers(adapter, rds_ring);
+		qlcnic_post_rx_buffers(adapter, rds_ring, ring);
 	}
 
 	qlcnic_set_multi(netdev);
@@ -1118,10 +1398,7 @@
 	return 0;
 }
 
-/* Usage: During resume and firmware recovery module.*/
-
-static int
-qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
 	int err = 0;
 
@@ -1133,8 +1410,7 @@
 	return err;
 }
 
-static void
-__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
 	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
 		return;
@@ -1166,8 +1442,7 @@
 
 /* Usage: During suspend and firmware recovery module */
 
-static void
-qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
 	rtnl_lock();
 	if (netif_running(netdev))
@@ -1176,7 +1451,7 @@
 
 }
 
-static int
+int
 qlcnic_attach(struct qlcnic_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
@@ -1222,8 +1497,7 @@
 	return err;
 }
 
-static void
-qlcnic_detach(struct qlcnic_adapter *adapter)
+void qlcnic_detach(struct qlcnic_adapter *adapter)
 {
 	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
 		return;
@@ -1272,21 +1546,9 @@
 static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
 {
 	int err = 0;
-	adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context),
-				GFP_KERNEL);
-	if (!adapter->ahw) {
-		dev_err(&adapter->pdev->dev,
-			"Failed to allocate recv ctx resources for adapter\n");
-		err = -ENOMEM;
-		goto err_out;
-	}
 	adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
 				GFP_KERNEL);
 	if (!adapter->recv_ctx) {
-		dev_err(&adapter->pdev->dev,
-			"Failed to allocate recv ctx resources for adapter\n");
-		kfree(adapter->ahw);
-		adapter->ahw = NULL;
 		err = -ENOMEM;
 		goto err_out;
 	}
@@ -1294,6 +1556,8 @@
 	adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
 	adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
 	adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+	/* clear stats */
+	memset(&adapter->stats, 0, sizeof(adapter->stats));
 err_out:
 	return err;
 }
@@ -1307,8 +1571,9 @@
 		vfree(adapter->ahw->fw_dump.tmpl_hdr);
 		adapter->ahw->fw_dump.tmpl_hdr = NULL;
 	}
-	kfree(adapter->ahw);
-	adapter->ahw = NULL;
+
+	kfree(adapter->ahw->reset.buff);
+	adapter->ahw->fw_dump.tmpl_hdr = NULL;
 }
 
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
@@ -1328,6 +1593,7 @@
 
 	adapter->max_sds_rings = 1;
 	adapter->ahw->diag_test = test;
+	adapter->ahw->linkup = 0;
 
 	ret = qlcnic_attach(adapter);
 	if (ret) {
@@ -1344,7 +1610,7 @@
 
 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
 		rds_ring = &adapter->recv_ctx->rds_rings[ring];
-		qlcnic_post_rx_buffers(adapter, rds_ring);
+		qlcnic_post_rx_buffers(adapter, rds_ring, ring);
 	}
 
 	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
@@ -1382,6 +1648,7 @@
 	netif_device_attach(netdev);
 
 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
+	dev_err(&adapter->pdev->dev, "%s:\n", __func__);
 	return 0;
 }
 
@@ -1425,34 +1692,40 @@
 	int err;
 	struct pci_dev *pdev = adapter->pdev;
 
+	adapter->rx_csum = 1;
 	adapter->ahw->mc_enabled = 0;
-	adapter->ahw->max_mc_count = 38;
+	adapter->ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
 
 	netdev->netdev_ops	   = &qlcnic_netdev_ops;
-	netdev->watchdog_timeo     = 5*HZ;
+	netdev->watchdog_timeo     = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ;
 
 	qlcnic_change_mtu(netdev, netdev->mtu);
 
 	SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
 
-	netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
-		NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+			     NETIF_F_IPV6_CSUM | NETIF_F_GRO |
+			     NETIF_F_HW_VLAN_RX);
+	netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+				  NETIF_F_IPV6_CSUM);
 
-	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
-		netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
-	if (pci_using_dac == 1)
-		netdev->hw_features |= NETIF_F_HIGHDMA;
+	if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
+		netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+		netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+	}
 
-	netdev->vlan_features = netdev->hw_features;
+	if (pci_using_dac) {
+		netdev->features |= NETIF_F_HIGHDMA;
+		netdev->vlan_features |= NETIF_F_HIGHDMA;
+	}
 
-	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
-		netdev->hw_features |= NETIF_F_HW_VLAN_TX;
+	if (qlcnic_vlan_tx_check(adapter))
+		netdev->features |= (NETIF_F_HW_VLAN_TX);
+
 	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
-		netdev->hw_features |= NETIF_F_LRO;
+		netdev->features |= NETIF_F_LRO;
 
-	netdev->features |= netdev->hw_features |
-		NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
-
+	netdev->hw_features = netdev->features;
 	netdev->irq = adapter->msix_entries[0].vector;
 
 	err = register_netdev(netdev);
@@ -1480,17 +1753,61 @@
 	return 0;
 }
 
-static int
-qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
+void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)
 {
-	adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
-					GFP_KERNEL);
+	int ring;
+	struct qlcnic_host_tx_ring *tx_ring;
 
-	if (adapter->msix_entries)
-		return 0;
+	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+		tx_ring = &adapter->tx_ring[ring];
+		if (tx_ring && tx_ring->cmd_buf_arr != NULL) {
+			vfree(tx_ring->cmd_buf_arr);
+			tx_ring->cmd_buf_arr = NULL;
+		}
+	}
+	if (adapter->tx_ring != NULL)
+		kfree(adapter->tx_ring);
+}
 
-	dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
-	return -ENOMEM;
+int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
+			  struct net_device *netdev)
+{
+	int ring, vector, index;
+	struct qlcnic_host_tx_ring *tx_ring;
+	struct qlcnic_cmd_buffer *cmd_buf_arr;
+
+	tx_ring = kcalloc(adapter->max_drv_tx_rings,
+			  sizeof(struct qlcnic_host_tx_ring), GFP_KERNEL);
+	if (tx_ring == NULL)
+		return -ENOMEM;
+
+	adapter->tx_ring = tx_ring;
+
+	for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+		tx_ring = &adapter->tx_ring[ring];
+		tx_ring->num_desc = adapter->num_txd;
+		tx_ring->txq = netdev_get_tx_queue(netdev, ring);
+		cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
+		if (cmd_buf_arr == NULL) {
+			qlcnic_free_tx_rings(adapter);
+			return -ENOMEM;
+		}
+		memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
+		tx_ring->cmd_buf_arr = cmd_buf_arr;
+	}
+
+	if (qlcnic_83xx_check(adapter)) {
+		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+			tx_ring = &adapter->tx_ring[ring];
+			tx_ring->adapter = adapter;
+			if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+				index = adapter->max_sds_rings + ring;
+				vector = adapter->msix_entries[index].vector;
+				tx_ring->irq = vector;
+			}
+		}
+	}
+	return 0;
 }
 
 static int
@@ -1498,9 +1815,10 @@
 {
 	struct net_device *netdev = NULL;
 	struct qlcnic_adapter *adapter = NULL;
+	struct qlcnic_hardware_context *ahw;
 	int err, pci_using_dac = -1;
-	uint8_t revision_id;
-	char board_name[QLCNIC_MAX_BOARD_NAME_LEN];
+	u32 capab2;
+	char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -1522,10 +1840,27 @@
 	pci_set_master(pdev);
 	pci_enable_pcie_error_reporting(pdev);
 
+	ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL);
+	if (!ahw)
+		goto err_out_free_res;
+
+	if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE824X) {
+		ahw->hw_ops = &qlcnic_hw_ops;
+		ahw->reg_tbl = (u32 *)qlcnic_reg_tbl;
+	} else if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+		qlcnic_83xx_register_map(ahw);
+	} else {
+		goto err_out_free_hw_res;
+	}
+
+	err = qlcnic_setup_pci_map(pdev, ahw);
+	if (err)
+		goto err_out_free_hw_res;
+
 	netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
 	if (!netdev) {
 		err = -ENOMEM;
-		goto err_out_free_res;
+		goto err_out_iounmap;
 	}
 
 	SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -1533,15 +1868,25 @@
 	adapter = netdev_priv(netdev);
 	adapter->netdev  = netdev;
 	adapter->pdev    = pdev;
+	adapter->ahw = ahw;
+
+	adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic");
+	if (adapter->qlcnic_wq == NULL) {
+		dev_err(&pdev->dev, "Failed to create workqueue\n");
+		goto err_out_free_netdev;
+	}
 
 	err = qlcnic_alloc_adapter_resources(adapter);
 	if (err)
 		goto err_out_free_netdev;
 
 	adapter->dev_rst_time = jiffies;
-	revision_id = pdev->revision;
-	adapter->ahw->revision_id = revision_id;
-	adapter->mac_learn = qlcnic_mac_learn;
+	adapter->ahw->revision_id = pdev->revision;
+	if (qlcnic_mac_learn == FDB_MAC_LEARN)
+		adapter->fdb_mac_learn = true;
+	else if (qlcnic_mac_learn == DRV_MAC_LEARN)
+		adapter->drv_mac_learn = true;
+	adapter->max_drv_tx_rings = 1;
 
 	rwlock_init(&adapter->ahw->crb_lock);
 	mutex_init(&adapter->ahw->mem_lock);
@@ -1549,31 +1894,32 @@
 	spin_lock_init(&adapter->tx_clean_lock);
 	INIT_LIST_HEAD(&adapter->mac_list);
 
-	err = qlcnic_setup_pci_map(pdev, adapter->ahw);
-	if (err)
+	if (qlcnic_82xx_check(adapter)) {
+		qlcnic_check_vf(adapter, ent);
+		adapter->portnum = adapter->ahw->pci_func;
+		err = qlcnic_start_firmware(adapter);
+		if (err) {
+			dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
+			goto err_out_free_hw;
+		}
+
+		err = qlcnic_setup_idc_param(adapter);
+		if (err)
+			goto err_out_free_hw;
+
+		adapter->flags |= QLCNIC_NEED_FLR;
+	} else if (qlcnic_83xx_check(adapter)) {
+		qlcnic_83xx_check_vf(adapter, ent);
+		adapter->portnum = adapter->ahw->pci_func;
+		err = qlcnic_83xx_init(adapter);
+		if (err) {
+			dev_err(&pdev->dev, "%s: failed\n", __func__);
+			goto err_out_free_hw;
+		}
+	} else {
+		dev_err(&pdev->dev,
+			"%s: failed. Please Reboot\n", __func__);
 		goto err_out_free_hw;
-	qlcnic_check_vf(adapter);
-
-	/* This will be reset for mezz cards  */
-	adapter->portnum = adapter->ahw->pci_func;
-
-	err = qlcnic_get_board_info(adapter);
-	if (err) {
-		dev_err(&pdev->dev, "Error getting board config info.\n");
-		goto err_out_iounmap;
-	}
-
-	err = qlcnic_setup_idc_param(adapter);
-	if (err)
-		goto err_out_iounmap;
-
-	adapter->flags |= QLCNIC_NEED_FLR;
-
-	err = adapter->nic_ops->start_firmware(adapter);
-	if (err) {
-		dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
-			"\t\tIf reboot doesn't help, try flashing the card\n");
-		goto err_out_maintenance_mode;
 	}
 
 	if (qlcnic_read_mac_addr(adapter))
@@ -1581,22 +1927,34 @@
 
 	if (adapter->portnum == 0) {
 		qlcnic_get_board_name(adapter, board_name);
+
 		pr_info("%s: %s Board Chip rev 0x%x\n",
 			module_name(THIS_MODULE),
 			board_name, adapter->ahw->revision_id);
 	}
+	err = qlcnic_setup_intr(adapter, 0);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to setup interrupt\n");
+		goto err_out_disable_msi;
+	}
 
-	qlcnic_clear_stats(adapter);
-
-	err = qlcnic_alloc_msix_entries(adapter, adapter->ahw->max_rx_ques);
-	if (err)
-		goto err_out_decr_ref;
-
-	qlcnic_setup_intr(adapter);
+	if (qlcnic_83xx_check(adapter)) {
+		err = qlcnic_83xx_setup_mbx_intr(adapter);
+		if (err)
+			goto err_out_disable_msi;
+	}
 
 	err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
 	if (err)
-		goto err_out_disable_msi;
+		goto err_out_disable_mbx_intr;
+
+	if (qlcnic_82xx_check(adapter)) {
+		if (ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+			capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+			if (capab2 & QLCNIC_FW_CAPABILITY_2_OCBB)
+				qlcnic_fw_cmd_set_drv_version(adapter);
+		}
+	}
 
 	pci_set_drvdata(pdev, adapter);
 
@@ -1615,29 +1973,37 @@
 		break;
 	}
 
-	if (adapter->mac_learn)
+	if (qlcnic_get_act_pci_func(adapter))
+		goto err_out_disable_mbx_intr;
+
+	if (adapter->drv_mac_learn)
 		qlcnic_alloc_lb_filters_mem(adapter);
 
-	qlcnic_create_diag_entries(adapter);
+	qlcnic_add_sysfs(adapter);
 
 	return 0;
 
+err_out_disable_mbx_intr:
+	if (qlcnic_83xx_check(adapter))
+		qlcnic_83xx_free_mbx_intr(adapter);
+
 err_out_disable_msi:
 	qlcnic_teardown_intr(adapter);
-	kfree(adapter->msix_entries);
-
-err_out_decr_ref:
+	qlcnic_cancel_idc_work(adapter);
 	qlcnic_clr_all_drv_state(adapter, 0);
 
-err_out_iounmap:
-	qlcnic_cleanup_pci_map(adapter);
-
 err_out_free_hw:
 	qlcnic_free_adapter_resources(adapter);
 
 err_out_free_netdev:
 	free_netdev(netdev);
 
+err_out_iounmap:
+	qlcnic_cleanup_pci_map(adapter);
+
+err_out_free_hw_res:
+	kfree(ahw);
+
 err_out_free_res:
 	pci_release_regions(pdev);
 
@@ -1645,24 +2011,13 @@
 	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
 	return err;
-
-err_out_maintenance_mode:
-	netdev->netdev_ops = &qlcnic_netdev_failed_ops;
-	SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
-	err = register_netdev(netdev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to register net device\n");
-		goto err_out_decr_ref;
-	}
-	pci_set_drvdata(pdev, adapter);
-	qlcnic_create_diag_entries(adapter);
-	return 0;
 }
 
 static void qlcnic_remove(struct pci_dev *pdev)
 {
 	struct qlcnic_adapter *adapter;
 	struct net_device *netdev;
+	struct qlcnic_hardware_context *ahw;
 
 	adapter = pci_get_drvdata(pdev);
 	if (adapter == NULL)
@@ -1670,10 +2025,17 @@
 
 	netdev = adapter->netdev;
 
-	qlcnic_cancel_fw_work(adapter);
+	qlcnic_cancel_idc_work(adapter);
+	ahw = adapter->ahw;
 
 	unregister_netdev(netdev);
 
+	if (qlcnic_83xx_check(adapter)) {
+		qlcnic_83xx_free_mbx_intr(adapter);
+		qlcnic_83xx_register_nic_idc_func(adapter, 0);
+		cancel_delayed_work_sync(&adapter->idc_aen_work);
+	}
+
 	qlcnic_detach(adapter);
 
 	if (adapter->npars != NULL)
@@ -1689,9 +2051,8 @@
 	qlcnic_free_lb_filters_mem(adapter);
 
 	qlcnic_teardown_intr(adapter);
-	kfree(adapter->msix_entries);
 
-	qlcnic_remove_diag_entries(adapter);
+	qlcnic_remove_sysfs(adapter);
 
 	qlcnic_cleanup_pci_map(adapter);
 
@@ -1702,7 +2063,12 @@
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 
+	if (adapter->qlcnic_wq) {
+		destroy_workqueue(adapter->qlcnic_wq);
+		adapter->qlcnic_wq = NULL;
+	}
 	qlcnic_free_adapter_resources(adapter);
+	kfree(ahw);
 	free_netdev(netdev);
 }
 static int __qlcnic_shutdown(struct pci_dev *pdev)
@@ -1713,7 +2079,7 @@
 
 	netif_device_detach(netdev);
 
-	qlcnic_cancel_fw_work(adapter);
+	qlcnic_cancel_idc_work(adapter);
 
 	if (netif_running(netdev))
 		qlcnic_down(adapter, netdev);
@@ -1726,7 +2092,6 @@
 	retval = pci_save_state(pdev);
 	if (retval)
 		return retval;
-
 	if (qlcnic_82xx_check(adapter)) {
 		if (qlcnic_wol_supported(adapter)) {
 			pci_enable_wake(pdev, PCI_D3cold, 1);
@@ -1774,7 +2139,7 @@
 	pci_set_master(pdev);
 	pci_restore_state(pdev);
 
-	err = adapter->nic_ops->start_firmware(adapter);
+	err = qlcnic_start_firmware(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "failed to start firmware\n");
 		return err;
@@ -1797,14 +2162,8 @@
 static int qlcnic_open(struct net_device *netdev)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
-	u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 	int err;
 
-	if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
-		netdev_err(netdev, "Device in FAILED state\n");
-		return -EIO;
-	}
-
 	netif_carrier_off(netdev);
 
 	err = qlcnic_attach(adapter);
@@ -1832,6 +2191,7 @@
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
 	__qlcnic_down(adapter, netdev);
+
 	return 0;
 }
 
@@ -1839,22 +2199,53 @@
 {
 	void *head;
 	int i;
+	struct net_device *netdev = adapter->netdev;
+	u32 filter_size = 0;
+	u16 act_pci_func = 0;
 
 	if (adapter->fhash.fmax && adapter->fhash.fhead)
 		return;
 
+	act_pci_func = adapter->ahw->act_pci_func;
 	spin_lock_init(&adapter->mac_learn_lock);
+	spin_lock_init(&adapter->rx_mac_learn_lock);
 
-	head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
-								GFP_KERNEL);
+	if (qlcnic_82xx_check(adapter)) {
+		filter_size = QLCNIC_LB_MAX_FILTERS;
+		adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE;
+	} else {
+		filter_size = QLC_83XX_LB_MAX_FILTERS;
+		adapter->fhash.fbucket_size = QLC_83XX_LB_BUCKET_SIZE;
+	}
+
+	head = kcalloc(adapter->fhash.fbucket_size,
+		       sizeof(struct hlist_head), GFP_ATOMIC);
+
 	if (!head)
 		return;
 
-	adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
+	adapter->fhash.fmax = (filter_size / act_pci_func);
 	adapter->fhash.fhead = head;
 
-	for (i = 0; i < adapter->fhash.fmax; i++)
+	netdev_info(netdev, "active nic func = %d, mac filter size=%d\n",
+		    act_pci_func, adapter->fhash.fmax);
+
+	for (i = 0; i < adapter->fhash.fbucket_size; i++)
 		INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
+
+	adapter->rx_fhash.fbucket_size = adapter->fhash.fbucket_size;
+
+	head = kcalloc(adapter->rx_fhash.fbucket_size,
+		       sizeof(struct hlist_head), GFP_ATOMIC);
+
+	if (!head)
+		return;
+
+	adapter->rx_fhash.fmax = (filter_size / act_pci_func);
+	adapter->rx_fhash.fhead = head;
+
+	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++)
+		INIT_HLIST_HEAD(&adapter->rx_fhash.fhead[i]);
 }
 
 static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
@@ -1864,16 +2255,25 @@
 
 	adapter->fhash.fhead = NULL;
 	adapter->fhash.fmax = 0;
+
+	if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead)
+		kfree(adapter->rx_fhash.fhead);
+
+	adapter->rx_fhash.fmax = 0;
+	adapter->rx_fhash.fhead = NULL;
 }
 
-static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
+int qlcnic_check_temp(struct qlcnic_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
 	u32 temp_state, temp_val, temp = 0;
 	int rv = 0;
 
+	if (qlcnic_83xx_check(adapter))
+		temp = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
+
 	if (qlcnic_82xx_check(adapter))
-		temp = QLCRD32(adapter, CRB_TEMP_STATE);
+		temp = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP);
 
 	temp_state = qlcnic_get_temp_state(temp);
 	temp_val = qlcnic_get_temp_val(temp);
@@ -1933,7 +2333,7 @@
 	return stats;
 }
 
-static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 {
 	u32 status;
 
@@ -2009,6 +2409,14 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)
+{
+	struct qlcnic_host_tx_ring *tx_ring = data;
+
+	napi_schedule(&tx_ring->napi);
+	return IRQ_HANDLED;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev)
 {
@@ -2035,7 +2443,7 @@
 	val |= encoding << 7;
 	val |= (jiffies - adapter->dev_rst_time) << 8;
 
-	QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
 	adapter->dev_rst_time = jiffies;
 }
 
@@ -2050,14 +2458,14 @@
 	if (qlcnic_api_lock(adapter))
 		return -EIO;
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 
 	if (state == QLCNIC_DEV_NEED_RESET)
 		QLC_DEV_SET_RST_RDY(val, adapter->portnum);
 	else if (state == QLCNIC_DEV_NEED_QUISCENT)
 		QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
 
-	QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
 	qlcnic_api_unlock(adapter);
 
@@ -2072,9 +2480,9 @@
 	if (qlcnic_api_lock(adapter))
 		return -EBUSY;
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 	QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
-	QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
 	qlcnic_api_unlock(adapter);
 
@@ -2089,20 +2497,22 @@
 	if (qlcnic_api_lock(adapter))
 		goto err;
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
 	QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
-	QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
 
 	if (failed) {
-		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+				    QLCNIC_DEV_FAILED);
 		dev_info(&adapter->pdev->dev,
 				"Device state set to Failed. Please Reboot\n");
 	} else if (!(val & 0x11111111))
-		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+				    QLCNIC_DEV_COLD);
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 	QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
-	QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
 	qlcnic_api_unlock(adapter);
 err:
@@ -2117,12 +2527,13 @@
 qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 {
 	int act, state, active_mask;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-	state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-	act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
+	act = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
 
 	if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
-		active_mask = (~(1 << (adapter->ahw->pci_func * 4)));
+		active_mask = (~(1 << (ahw->pci_func * 4)));
 		act = act & active_mask;
 	}
 
@@ -2135,7 +2546,7 @@
 
 static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
 {
-	u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
+	u32 val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
 
 	if (val != QLCNIC_DRV_IDC_VER) {
 		dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
@@ -2159,19 +2570,21 @@
 	if (qlcnic_api_lock(adapter))
 		return -1;
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
 	if (!(val & (1 << (portnum * 4)))) {
 		QLC_DEV_SET_REF_CNT(val, portnum);
-		QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
 	}
 
-	prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+	prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 	QLCDB(adapter, HW, "Device state = %u\n", prev_state);
 
 	switch (prev_state) {
 	case QLCNIC_DEV_COLD:
-		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
-		QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+				    QLCNIC_DEV_INITIALIZING);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_IDC_VER,
+				    QLCNIC_DRV_IDC_VER);
 		qlcnic_idc_debug_info(adapter, 0);
 		qlcnic_api_unlock(adapter);
 		return 1;
@@ -2182,15 +2595,15 @@
 		return ret;
 
 	case QLCNIC_DEV_NEED_RESET:
-		val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+		val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 		QLC_DEV_SET_RST_RDY(val, portnum);
-		QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 		break;
 
 	case QLCNIC_DEV_NEED_QUISCENT:
-		val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+		val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 		QLC_DEV_SET_QSCNT_RDY(val, portnum);
-		QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 		break;
 
 	case QLCNIC_DEV_FAILED:
@@ -2207,7 +2620,7 @@
 
 	do {
 		msleep(1000);
-		prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+		prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 
 		if (prev_state == QLCNIC_DEV_QUISCENT)
 			continue;
@@ -2222,9 +2635,9 @@
 	if (qlcnic_api_lock(adapter))
 		return -1;
 
-	val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+	val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
 	QLC_DEV_CLR_RST_QSCNT(val, portnum);
-	QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
 	ret = qlcnic_check_idc_ver(adapter);
 	qlcnic_api_unlock(adapter);
@@ -2243,7 +2656,7 @@
 	if (qlcnic_api_lock(adapter))
 		goto err_ret;
 
-	dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+	dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 	if (dev_state == QLCNIC_DEV_QUISCENT ||
 	    dev_state == QLCNIC_DEV_NEED_QUISCENT) {
 		qlcnic_api_unlock(adapter);
@@ -2272,17 +2685,19 @@
 
 	if (!qlcnic_check_drv_state(adapter)) {
 skip_ack_check:
-		dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+		dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 
 		if (dev_state == QLCNIC_DEV_NEED_RESET) {
-			QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
-						QLCNIC_DEV_INITIALIZING);
+			QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+					    QLCNIC_DEV_INITIALIZING);
 			set_bit(__QLCNIC_START_FW, &adapter->state);
 			QLCDB(adapter, DRV, "Restarting fw\n");
 			qlcnic_idc_debug_info(adapter, 0);
-			val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+			val = QLC_SHARED_REG_RD32(adapter,
+						  QLCNIC_CRB_DRV_STATE);
 			QLC_DEV_SET_RST_RDY(val, adapter->portnum);
-			QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+			QLC_SHARED_REG_WR32(adapter,
+					    QLCNIC_CRB_DRV_STATE, val);
 		}
 
 		qlcnic_api_unlock(adapter);
@@ -2308,12 +2723,12 @@
 	qlcnic_api_unlock(adapter);
 
 wait_npar:
-	dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+	dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 	QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
 	switch (dev_state) {
 	case QLCNIC_DEV_READY:
-		if (!adapter->nic_ops->start_firmware(adapter)) {
+		if (!qlcnic_start_firmware(adapter)) {
 			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
 			adapter->fw_wait_cnt = 0;
 			return;
@@ -2350,7 +2765,7 @@
 	} else
 		qlcnic_down(adapter, netdev);
 
-	status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+	status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
 
 	if (status & QLCNIC_RCODE_FATAL_ERROR) {
 		dev_err(&adapter->pdev->dev,
@@ -2401,19 +2816,18 @@
 {
 	u32 state;
 
-	state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
 	if (state == QLCNIC_DEV_NPAR_NON_OPER)
 		return;
 
 	if (qlcnic_api_lock(adapter))
 		return;
-	QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+			    QLCNIC_DEV_NPAR_NON_OPER);
 	qlcnic_api_unlock(adapter);
 }
 
-/*Transit to RESET state from READY state only */
-void
-qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
 {
 	u32 state, xg_val = 0, gb_val = 0;
 
@@ -2428,25 +2842,22 @@
 	dev_info(&adapter->pdev->dev, "Pause control frames disabled"
 				" on all ports\n");
 	adapter->need_fw_reset = 1;
+
 	if (qlcnic_api_lock(adapter))
 		return;
 
-	state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-	if (state  == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
-		netdev_err(adapter->netdev,
-				"Device is in FAILED state, Please Reboot\n");
-		qlcnic_api_unlock(adapter);
-		return;
-	}
+	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 
 	if (state == QLCNIC_DEV_READY) {
-		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+				    QLCNIC_DEV_NEED_RESET);
 		adapter->flags |= QLCNIC_FW_RESET_OWNER;
 		QLCDB(adapter, DRV, "NEED_RESET state set\n");
 		qlcnic_idc_debug_info(adapter, 0);
 	}
 
-	QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+			    QLCNIC_DEV_NPAR_NON_OPER);
 	qlcnic_api_unlock(adapter);
 }
 
@@ -2457,34 +2868,22 @@
 	if (qlcnic_api_lock(adapter))
 		return;
 
-	QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+			    QLCNIC_DEV_NPAR_OPER);
 	QLCDB(adapter, DRV, "NPAR operational state set\n");
 
 	qlcnic_api_unlock(adapter);
 }
 
-static void
-qlcnic_schedule_work(struct qlcnic_adapter *adapter,
-		work_func_t func, int delay)
+void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+			  work_func_t func, int delay)
 {
 	if (test_bit(__QLCNIC_AER, &adapter->state))
 		return;
 
 	INIT_DELAYED_WORK(&adapter->fw_work, func);
-	queue_delayed_work(qlcnic_wq, &adapter->fw_work,
-					round_jiffies_relative(delay));
-}
-
-static void
-qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
-{
-	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
-		msleep(10);
-
-	if (!adapter->fw_work.work.func)
-		return;
-
-	cancel_delayed_work_sync(&adapter->fw_work);
+	queue_delayed_work(adapter->qlcnic_wq, &adapter->fw_work,
+			   round_jiffies_relative(delay));
 }
 
 static void
@@ -2496,7 +2895,8 @@
 	u32 npar_state;
 
 	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
-		npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+		npar_state = QLC_SHARED_REG_RD32(adapter,
+						 QLCNIC_CRB_DEV_NPAR_STATE);
 		if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
 			qlcnic_clr_all_drv_state(adapter, 0);
 		else if (npar_state != QLCNIC_DEV_NPAR_OPER)
@@ -2536,16 +2936,16 @@
 		goto detach;
 
 	if (adapter->need_fw_reset)
-		qlcnic_dev_request_reset(adapter);
+		qlcnic_dev_request_reset(adapter, 0);
 
-	state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
 	if (state == QLCNIC_DEV_NEED_RESET) {
 		qlcnic_set_npar_non_operational(adapter);
 		adapter->need_fw_reset = 1;
 	} else if (state == QLCNIC_DEV_NEED_QUISCENT)
 		goto detach;
 
-	heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+	heartbeat = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
 	if (heartbeat != adapter->heartbeat) {
 		adapter->heartbeat = heartbeat;
 		adapter->fw_fail_cnt = 0;
@@ -2565,25 +2965,25 @@
 
 	adapter->flags |= QLCNIC_FW_HANG;
 
-	qlcnic_dev_request_reset(adapter);
+	qlcnic_dev_request_reset(adapter, 0);
 
 	if (qlcnic_auto_fw_reset)
 		clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
 
 	dev_err(&adapter->pdev->dev, "firmware hang detected\n");
+	peg_status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
 	dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
 			"PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
 			"PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
 			"PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
 			"PEG_NET_4_PC: 0x%x\n",
-			QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1),
-			QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS2),
+			peg_status,
+			QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
 			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
 			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
 			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
 			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
 			QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
-	peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
 	if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
 		dev_err(&adapter->pdev->dev,
 			"Firmware aborted with error code 0x00006700. "
@@ -2667,17 +3067,39 @@
 	if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
 		adapter->need_fw_reset = 1;
 		set_bit(__QLCNIC_START_FW, &adapter->state);
-		QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+		QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+				    QLCNIC_DEV_INITIALIZING);
 		QLCDB(adapter, DRV, "Restarting fw\n");
 	}
 	qlcnic_api_unlock(adapter);
 
-	err = adapter->nic_ops->start_firmware(adapter);
+	err = qlcnic_start_firmware(adapter);
 	if (err)
 		return err;
 
 	qlcnic_clr_drv_state(adapter);
-	qlcnic_setup_intr(adapter);
+	kfree(adapter->msix_entries);
+	adapter->msix_entries = NULL;
+	err = qlcnic_setup_intr(adapter, 0);
+
+	if (err) {
+		kfree(adapter->msix_entries);
+		netdev_err(netdev, "failed to setup interrupt\n");
+		return err;
+	}
+
+	if (qlcnic_83xx_check(adapter)) {
+		/* register for NIC IDC AEN Events */
+		qlcnic_83xx_register_nic_idc_func(adapter, 1);
+		err = qlcnic_83xx_setup_mbx_intr(adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"failed to setup mbx interrupt\n");
+			qlcnic_clr_all_drv_state(adapter, 1);
+			clear_bit(__QLCNIC_AER, &adapter->state);
+			goto done;
+		}
+	}
 
 	if (netif_running(netdev)) {
 		err = qlcnic_attach(adapter);
@@ -2719,6 +3141,12 @@
 	if (netif_running(netdev))
 		qlcnic_down(adapter, netdev);
 
+	if (qlcnic_83xx_check(adapter)) {
+		qlcnic_83xx_free_mbx_intr(adapter);
+		qlcnic_83xx_register_nic_idc_func(adapter, 0);
+		cancel_delayed_work_sync(&adapter->idc_aen_work);
+	}
+
 	qlcnic_detach(adapter);
 	qlcnic_teardown_intr(adapter);
 
@@ -2738,12 +3166,13 @@
 
 static void qlcnic_io_resume(struct pci_dev *pdev)
 {
+	u32 state;
 	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
 
 	pci_cleanup_aer_uncorrect_error_status(pdev);
-
-	if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
-	    test_and_clear_bit(__QLCNIC_AER, &adapter->state))
+	state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+	if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER,
+							    &adapter->state))
 		qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
 						FW_POLL_DELAY);
 }
@@ -2776,39 +3205,59 @@
 	return err;
 }
 
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
+int qlcnic_validate_max_rss(u8 max_hw, u8 val)
 {
-	if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
-		netdev_info(netdev, "no msix or msi support, hence no rss\n");
-		return -EINVAL;
+	u32 max_allowed;
+
+	if (max_hw > QLC_MAX_SDS_RINGS) {
+		max_hw = QLC_MAX_SDS_RINGS;
+		pr_info("max rss reset to %d\n", QLC_MAX_SDS_RINGS);
 	}
 
-	if ((val > max_hw) || (val <  2) || !is_power_of_2(val)) {
-		netdev_info(netdev, "rss_ring valid range [2 - %x] in "
-			" powers of 2\n", max_hw);
+	max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
+						 num_online_cpus()));
+	if ((val > max_allowed) || (val < 2) || !is_power_of_2(val)) {
+		pr_info("rss_ring valid range [2 - %x] in powers of 2\n",
+			max_allowed);
 		return -EINVAL;
 	}
 	return 0;
-
 }
 
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
 {
+	int err;
 	struct net_device *netdev = adapter->netdev;
-	int err = 0;
 
-	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+	if (test_bit(__QLCNIC_RESETTING, &adapter->state))
 		return -EBUSY;
 
 	netif_device_detach(netdev);
 	if (netif_running(netdev))
 		__qlcnic_down(adapter, netdev);
-	qlcnic_detach(adapter);
-	qlcnic_teardown_intr(adapter);
 
-	if (qlcnic_enable_msix(adapter, data)) {
-		netdev_info(netdev, "failed setting max_rss; rss disabled\n");
-		qlcnic_enable_msi_legacy(adapter);
+	qlcnic_detach(adapter);
+
+	if (qlcnic_83xx_check(adapter))
+		qlcnic_83xx_free_mbx_intr(adapter);
+
+	qlcnic_teardown_intr(adapter);
+	err = qlcnic_setup_intr(adapter, data);
+	if (err) {
+		kfree(adapter->msix_entries);
+		netdev_err(netdev, "failed to setup interrupt\n");
+		return err;
+	}
+
+	if (qlcnic_83xx_check(adapter)) {
+		/* register for NIC IDC AEN Events */
+		qlcnic_83xx_register_nic_idc_func(adapter, 1);
+		err = qlcnic_83xx_setup_mbx_intr(adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"failed to setup mbx interrupt\n");
+			goto done;
+		}
 	}
 
 	if (netif_running(netdev)) {
@@ -2820,6 +3269,7 @@
 			goto done;
 		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
 	}
+	err = len;
  done:
 	netif_device_attach(netdev);
 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -2858,8 +3308,7 @@
 	in_dev_put(indev);
 }
 
-static void
-qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
+void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
 {
 	struct qlcnic_adapter *adapter = netdev_priv(netdev);
 	struct net_device *dev;
@@ -2867,12 +3316,14 @@
 
 	qlcnic_config_indev_addr(adapter, netdev, event);
 
+	rcu_read_lock();
 	for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
 		dev = __vlan_find_dev_deep(netdev, vid);
 		if (!dev)
 			continue;
 		qlcnic_config_indev_addr(adapter, dev, event);
 	}
+	rcu_read_unlock();
 }
 
 static int qlcnic_netdev_event(struct notifier_block *this,
@@ -2940,9 +3391,11 @@
 	switch (event) {
 	case NETDEV_UP:
 		qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
+
 		break;
 	case NETDEV_DOWN:
 		qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
+
 		break;
 	default:
 		break;
@@ -2960,11 +3413,10 @@
 	.notifier_call = qlcnic_inetaddr_event,
 };
 #else
-static void
-qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
+void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
 { }
 #endif
-static struct pci_error_handlers qlcnic_err_handler = {
+static const struct pci_error_handlers qlcnic_err_handler = {
 	.error_detected = qlcnic_io_error_detected,
 	.slot_reset = qlcnic_io_slot_reset,
 	.resume = qlcnic_io_resume,
@@ -2990,12 +3442,6 @@
 
 	printk(KERN_INFO "%s\n", qlcnic_driver_string);
 
-	qlcnic_wq = create_singlethread_workqueue("qlcnic");
-	if (qlcnic_wq == NULL) {
-		printk(KERN_ERR "qlcnic: cannot create workqueue\n");
-		return -ENOMEM;
-	}
-
 #ifdef CONFIG_INET
 	register_netdevice_notifier(&qlcnic_netdev_cb);
 	register_inetaddr_notifier(&qlcnic_inetaddr_cb);
@@ -3007,7 +3453,6 @@
 		unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
 		unregister_netdevice_notifier(&qlcnic_netdev_cb);
 #endif
-		destroy_workqueue(qlcnic_wq);
 	}
 
 	return ret;
@@ -3017,14 +3462,12 @@
 
 static void __exit qlcnic_exit_module(void)
 {
-
 	pci_unregister_driver(&qlcnic_driver);
 
 #ifdef CONFIG_INET
 	unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
 	unregister_netdevice_notifier(&qlcnic_netdev_cb);
 #endif
-	destroy_workqueue(qlcnic_wq);
 }
 
 module_exit(qlcnic_exit_module);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index 0b8d862..abbd22c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -1,8 +1,25 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
 #include "qlcnic.h"
 #include "qlcnic_hdr.h"
+#include "qlcnic_83xx_hw.h"
+#include "qlcnic_hw.h"
 
 #include <net/ip.h>
 
+#define QLC_83XX_MINIDUMP_FLASH		0x520000
+#define QLC_83XX_OCM_INDEX			3
+#define QLC_83XX_PCI_INDEX			0
+
+static const u32 qlcnic_ms_read_data[] = {
+	0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC
+};
+
 #define QLCNIC_DUMP_WCRB	BIT_0
 #define QLCNIC_DUMP_RWCRB	BIT_1
 #define QLCNIC_DUMP_ANDCRB	BIT_2
@@ -102,16 +119,55 @@
 	u8	rsvd3[2];
 } __packed;
 
+struct __pollrd {
+	u32	sel_addr;
+	u32	read_addr;
+	u32	sel_val;
+	u16	sel_val_stride;
+	u16	no_ops;
+	u32	poll_wait;
+	u32	poll_mask;
+	u32	data_size;
+	u8	rsvd[4];
+} __packed;
+
+struct __mux2 {
+	u32	sel_addr1;
+	u32	sel_addr2;
+	u32	sel_val1;
+	u32	sel_val2;
+	u32	no_ops;
+	u32	sel_val_mask;
+	u32	read_addr;
+	u8	sel_val_stride;
+	u8	data_size;
+	u8	rsvd[2];
+} __packed;
+
+struct __pollrdmwr {
+	u32	addr1;
+	u32	addr2;
+	u32	val1;
+	u32	val2;
+	u32	poll_wait;
+	u32	poll_mask;
+	u32	mod_mask;
+	u32	data_size;
+} __packed;
+
 struct qlcnic_dump_entry {
 	struct qlcnic_common_entry_hdr hdr;
 	union {
-		struct __crb	crb;
-		struct __cache	cache;
-		struct __ocm	ocm;
-		struct __mem	mem;
-		struct __mux	mux;
-		struct __queue	que;
-		struct __ctrl	ctrl;
+		struct __crb		crb;
+		struct __cache		cache;
+		struct __ocm		ocm;
+		struct __mem		mem;
+		struct __mux		mux;
+		struct __queue		que;
+		struct __ctrl		ctrl;
+		struct __pollrdmwr	pollrdmwr;
+		struct __mux2		mux2;
+		struct __pollrd		pollrd;
 	} region;
 } __packed;
 
@@ -131,6 +187,9 @@
 	QLCNIC_DUMP_L2_ITAG	= 22,
 	QLCNIC_DUMP_L2_DATA	= 23,
 	QLCNIC_DUMP_L2_INST	= 24,
+	QLCNIC_DUMP_POLL_RD	= 35,
+	QLCNIC_READ_MUX2	= 36,
+	QLCNIC_READ_POLLRDMWR	= 37,
 	QLCNIC_DUMP_READ_ROM	= 71,
 	QLCNIC_DUMP_READ_MEM	= 72,
 	QLCNIC_DUMP_READ_CTRL	= 98,
@@ -144,46 +203,17 @@
 		       __le32 *);
 };
 
-static void qlcnic_read_dump_reg(u32 addr, void __iomem *bar0, u32 *data)
-{
-	u32 dest;
-	void __iomem *window_reg;
-
-	dest = addr & 0xFFFF0000;
-	window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
-	writel(dest, window_reg);
-	readl(window_reg);
-	window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
-	*data = readl(window_reg);
-}
-
-static void qlcnic_write_dump_reg(u32 addr, void __iomem *bar0, u32 data)
-{
-	u32 dest;
-	void __iomem *window_reg;
-
-	dest = addr & 0xFFFF0000;
-	window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
-	writel(dest, window_reg);
-	readl(window_reg);
-	window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
-	writel(data, window_reg);
-	readl(window_reg);
-}
-
-/* FW dump related functions */
 static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
 			   struct qlcnic_dump_entry *entry, __le32 *buffer)
 {
 	int i;
 	u32 addr, data;
 	struct __crb *crb = &entry->region.crb;
-	void __iomem *base = adapter->ahw->pci_base0;
 
 	addr = crb->addr;
 
 	for (i = 0; i < crb->no_ops; i++) {
-		qlcnic_read_dump_reg(addr, base, &data);
+		data = qlcnic_ind_rd(adapter, addr);
 		*buffer++ = cpu_to_le32(addr);
 		*buffer++ = cpu_to_le32(data);
 		addr += crb->stride;
@@ -195,7 +225,6 @@
 			    struct qlcnic_dump_entry *entry, __le32 *buffer)
 {
 	int i, k, timeout = 0;
-	void __iomem *base = adapter->ahw->pci_base0;
 	u32 addr, data;
 	u8 no_ops;
 	struct __ctrl *ctr = &entry->region.ctrl;
@@ -211,28 +240,28 @@
 				continue;
 			switch (1 << k) {
 			case QLCNIC_DUMP_WCRB:
-				qlcnic_write_dump_reg(addr, base, ctr->val1);
+				qlcnic_ind_wr(adapter, addr, ctr->val1);
 				break;
 			case QLCNIC_DUMP_RWCRB:
-				qlcnic_read_dump_reg(addr, base, &data);
-				qlcnic_write_dump_reg(addr, base, data);
+				data = qlcnic_ind_rd(adapter, addr);
+				qlcnic_ind_wr(adapter, addr, data);
 				break;
 			case QLCNIC_DUMP_ANDCRB:
-				qlcnic_read_dump_reg(addr, base, &data);
-				qlcnic_write_dump_reg(addr, base,
-						      data & ctr->val2);
+				data = qlcnic_ind_rd(adapter, addr);
+				qlcnic_ind_wr(adapter, addr,
+					      (data & ctr->val2));
 				break;
 			case QLCNIC_DUMP_ORCRB:
-				qlcnic_read_dump_reg(addr, base, &data);
-				qlcnic_write_dump_reg(addr, base,
-						      data | ctr->val3);
+				data = qlcnic_ind_rd(adapter, addr);
+				qlcnic_ind_wr(adapter, addr,
+					      (data | ctr->val3));
 				break;
 			case QLCNIC_DUMP_POLLCRB:
 				while (timeout <= ctr->timeout) {
-					qlcnic_read_dump_reg(addr, base, &data);
+					data = qlcnic_ind_rd(adapter, addr);
 					if ((data & ctr->val2) == ctr->val1)
 						break;
-					msleep(1);
+					usleep_range(1000, 2000);
 					timeout++;
 				}
 				if (timeout > ctr->timeout) {
@@ -244,7 +273,7 @@
 			case QLCNIC_DUMP_RD_SAVE:
 				if (ctr->index_a)
 					addr = t_hdr->saved_state[ctr->index_a];
-				qlcnic_read_dump_reg(addr, base, &data);
+				data = qlcnic_ind_rd(adapter, addr);
 				t_hdr->saved_state[ctr->index_v] = data;
 				break;
 			case QLCNIC_DUMP_WRT_SAVED:
@@ -254,7 +283,7 @@
 					data = ctr->val1;
 				if (ctr->index_a)
 					addr = t_hdr->saved_state[ctr->index_a];
-				qlcnic_write_dump_reg(addr, base, data);
+				qlcnic_ind_wr(adapter, addr, data);
 				break;
 			case QLCNIC_DUMP_MOD_SAVE_ST:
 				data = t_hdr->saved_state[ctr->index_v];
@@ -283,12 +312,11 @@
 	int loop;
 	u32 val, data = 0;
 	struct __mux *mux = &entry->region.mux;
-	void __iomem *base = adapter->ahw->pci_base0;
 
 	val = mux->val;
 	for (loop = 0; loop < mux->no_ops; loop++) {
-		qlcnic_write_dump_reg(mux->addr, base, val);
-		qlcnic_read_dump_reg(mux->read_addr, base, &data);
+		qlcnic_ind_wr(adapter, mux->addr, val);
+		data = qlcnic_ind_rd(adapter, mux->read_addr);
 		*buffer++ = cpu_to_le32(val);
 		*buffer++ = cpu_to_le32(data);
 		val += mux->val_stride;
@@ -301,17 +329,16 @@
 {
 	int i, loop;
 	u32 cnt, addr, data, que_id = 0;
-	void __iomem *base = adapter->ahw->pci_base0;
 	struct __queue *que = &entry->region.que;
 
 	addr = que->read_addr;
 	cnt = que->read_addr_cnt;
 
 	for (loop = 0; loop < que->no_ops; loop++) {
-		qlcnic_write_dump_reg(que->sel_addr, base, que_id);
+		qlcnic_ind_wr(adapter, que->sel_addr, que_id);
 		addr = que->read_addr;
 		for (i = 0; i < cnt; i++) {
-			qlcnic_read_dump_reg(addr, base, &data);
+			data = qlcnic_ind_rd(adapter, addr);
 			*buffer++ = cpu_to_le32(data);
 			addr += que->read_addr_stride;
 		}
@@ -343,27 +370,27 @@
 	int i, count = 0;
 	u32 fl_addr, size, val, lck_val, addr;
 	struct __mem *rom = &entry->region.mem;
-	void __iomem *base = adapter->ahw->pci_base0;
 
 	fl_addr = rom->addr;
-	size = rom->size/4;
+	size = rom->size / 4;
 lock_try:
-	lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
+	lck_val = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
 	if (!lck_val && count < MAX_CTL_CHECK) {
-		msleep(10);
+		usleep_range(10000, 11000);
 		count++;
 		goto lock_try;
 	}
-	writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
+	QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
+			    adapter->ahw->pci_func);
 	for (i = 0; i < size; i++) {
 		addr = fl_addr & 0xFFFF0000;
-		qlcnic_write_dump_reg(FLASH_ROM_WINDOW, base, addr);
+		qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
 		addr = LSW(fl_addr) + FLASH_ROM_DATA;
-		qlcnic_read_dump_reg(addr, base, &val);
+		val = qlcnic_ind_rd(adapter, addr);
 		fl_addr += 4;
 		*buffer++ = cpu_to_le32(val);
 	}
-	readl(base + QLCNIC_FLASH_SEM2_ULK);
+	QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
 	return rom->size;
 }
 
@@ -372,18 +399,17 @@
 {
 	int i;
 	u32 cnt, val, data, addr;
-	void __iomem *base = adapter->ahw->pci_base0;
 	struct __cache *l1 = &entry->region.cache;
 
 	val = l1->init_tag_val;
 
 	for (i = 0; i < l1->no_ops; i++) {
-		qlcnic_write_dump_reg(l1->addr, base, val);
-		qlcnic_write_dump_reg(l1->ctrl_addr, base, LSW(l1->ctrl_val));
+		qlcnic_ind_wr(adapter, l1->addr, val);
+		qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
 		addr = l1->read_addr;
 		cnt = l1->read_addr_num;
 		while (cnt) {
-			qlcnic_read_dump_reg(addr, base, &data);
+			data = qlcnic_ind_rd(adapter, addr);
 			*buffer++ = cpu_to_le32(data);
 			addr += l1->read_addr_stride;
 			cnt--;
@@ -399,7 +425,6 @@
 	int i;
 	u32 cnt, val, data, addr;
 	u8 poll_mask, poll_to, time_out = 0;
-	void __iomem *base = adapter->ahw->pci_base0;
 	struct __cache *l2 = &entry->region.cache;
 
 	val = l2->init_tag_val;
@@ -407,17 +432,17 @@
 	poll_to = MSB(MSW(l2->ctrl_val));
 
 	for (i = 0; i < l2->no_ops; i++) {
-		qlcnic_write_dump_reg(l2->addr, base, val);
+		qlcnic_ind_wr(adapter, l2->addr, val);
 		if (LSW(l2->ctrl_val))
-			qlcnic_write_dump_reg(l2->ctrl_addr, base,
-					      LSW(l2->ctrl_val));
+			qlcnic_ind_wr(adapter, l2->ctrl_addr,
+				      LSW(l2->ctrl_val));
 		if (!poll_mask)
 			goto skip_poll;
 		do {
-			qlcnic_read_dump_reg(l2->ctrl_addr, base, &data);
+			data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
 			if (!(data & poll_mask))
 				break;
-			msleep(1);
+			usleep_range(1000, 2000);
 			time_out++;
 		} while (time_out <= poll_to);
 
@@ -431,7 +456,7 @@
 		addr = l2->read_addr;
 		cnt = l2->read_addr_num;
 		while (cnt) {
-			qlcnic_read_dump_reg(addr, base, &data);
+			data = qlcnic_ind_rd(adapter, addr);
 			*buffer++ = cpu_to_le32(data);
 			addr += l2->read_addr_stride;
 			cnt--;
@@ -447,7 +472,6 @@
 	u32 addr, data, test, ret = 0;
 	int i, reg_read;
 	struct __mem *mem = &entry->region.mem;
-	void __iomem *base = adapter->ahw->pci_base0;
 
 	reg_read = mem->size;
 	addr = mem->addr;
@@ -462,13 +486,12 @@
 	mutex_lock(&adapter->ahw->mem_lock);
 
 	while (reg_read != 0) {
-		qlcnic_write_dump_reg(MIU_TEST_ADDR_LO, base, addr);
-		qlcnic_write_dump_reg(MIU_TEST_ADDR_HI, base, 0);
-		qlcnic_write_dump_reg(MIU_TEST_CTR, base,
-				      TA_CTL_ENABLE | TA_CTL_START);
+		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
+		qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
+		qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_START_ENABLE);
 
 		for (i = 0; i < MAX_CTL_CHECK; i++) {
-			qlcnic_read_dump_reg(MIU_TEST_CTR, base, &test);
+			test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
 			if (!(test & TA_CTL_BUSY))
 				break;
 		}
@@ -481,8 +504,7 @@
 			}
 		}
 		for (i = 0; i < 4; i++) {
-			qlcnic_read_dump_reg(MIU_TEST_READ_DATA[i], base,
-					     &data);
+			data = qlcnic_ind_rd(adapter, qlcnic_ms_read_data[i]);
 			*buffer++ = cpu_to_le32(data);
 		}
 		addr += 16;
@@ -501,48 +523,388 @@
 	return 0;
 }
 
-static const struct qlcnic_dump_operations fw_dump_ops[] = {
-	{ QLCNIC_DUMP_NOP, qlcnic_dump_nop },
-	{ QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
-	{ QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
-	{ QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
-	{ QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
-	{ QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
-	{ QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
-	{ QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
-	{ QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
-	{ QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
-	{ QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
-	{ QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
-	{ QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
-	{ QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
-	{ QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
-	{ QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
-	{ QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
-	{ QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
-	{ QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
-	{ QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
-};
-
-/* Walk the template and collect dump for each entry in the dump template */
-static int
-qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
-			u32 size)
+static int qlcnic_valid_dump_entry(struct device *dev,
+				   struct qlcnic_dump_entry *entry, u32 size)
 {
 	int ret = 1;
 	if (size != entry->hdr.cap_size) {
-		dev_info(dev,
-			 "Invalid dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
-		entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
-		dev_info(dev, "Aborting further dump capture\n");
+		dev_err(dev,
+			"Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+			entry->hdr.type, entry->hdr.mask, size,
+			entry->hdr.cap_size);
 		ret = 0;
 	}
 	return ret;
 }
 
+static u32 qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
+				 struct qlcnic_dump_entry *entry,
+				 __le32 *buffer)
+{
+	struct __pollrdmwr *poll = &entry->region.pollrdmwr;
+	u32 data, wait_count, poll_wait, temp;
+
+	poll_wait = poll->poll_wait;
+
+	qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
+	wait_count = 0;
+
+	while (wait_count < poll_wait) {
+		data = qlcnic_ind_rd(adapter, poll->addr1);
+		if ((data & poll->poll_mask) != 0)
+			break;
+		wait_count++;
+	}
+
+	if (wait_count == poll_wait) {
+		dev_err(&adapter->pdev->dev,
+			"Timeout exceeded in %s, aborting dump\n",
+			__func__);
+		return 0;
+	}
+
+	data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
+	qlcnic_ind_wr(adapter, poll->addr2, data);
+	qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
+	wait_count = 0;
+
+	while (wait_count < poll_wait) {
+		temp = qlcnic_ind_rd(adapter, poll->addr1);
+		if ((temp & poll->poll_mask) != 0)
+			break;
+		wait_count++;
+	}
+
+	*buffer++ = cpu_to_le32(poll->addr2);
+	*buffer++ = cpu_to_le32(data);
+
+	return 2 * sizeof(u32);
+
+}
+
+static u32 qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
+			      struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+	struct __pollrd *pollrd = &entry->region.pollrd;
+	u32 data, wait_count, poll_wait, sel_val;
+	int i;
+
+	poll_wait = pollrd->poll_wait;
+	sel_val = pollrd->sel_val;
+
+	for (i = 0; i < pollrd->no_ops; i++) {
+		qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
+		wait_count = 0;
+		while (wait_count < poll_wait) {
+			data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
+			if ((data & pollrd->poll_mask) != 0)
+				break;
+			wait_count++;
+		}
+
+		if (wait_count == poll_wait) {
+			dev_err(&adapter->pdev->dev,
+				"Timeout exceeded in %s, aborting dump\n",
+				__func__);
+			return 0;
+		}
+
+		data = qlcnic_ind_rd(adapter, pollrd->read_addr);
+		*buffer++ = cpu_to_le32(sel_val);
+		*buffer++ = cpu_to_le32(data);
+		sel_val += pollrd->sel_val_stride;
+	}
+	return pollrd->no_ops * (2 * sizeof(u32));
+}
+
+static u32 qlcnic_read_mux2(struct qlcnic_adapter *adapter,
+			    struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+	struct __mux2 *mux2 = &entry->region.mux2;
+	u32 data;
+	u32 t_sel_val, sel_val1, sel_val2;
+	int i;
+
+	sel_val1 = mux2->sel_val1;
+	sel_val2 = mux2->sel_val2;
+
+	for (i = 0; i < mux2->no_ops; i++) {
+		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
+		t_sel_val = sel_val1 & mux2->sel_val_mask;
+		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+		data = qlcnic_ind_rd(adapter, mux2->read_addr);
+		*buffer++ = cpu_to_le32(t_sel_val);
+		*buffer++ = cpu_to_le32(data);
+		qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
+		t_sel_val = sel_val2 & mux2->sel_val_mask;
+		qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+		data = qlcnic_ind_rd(adapter, mux2->read_addr);
+		*buffer++ = cpu_to_le32(t_sel_val);
+		*buffer++ = cpu_to_le32(data);
+		sel_val1 += mux2->sel_val_stride;
+		sel_val2 += mux2->sel_val_stride;
+	}
+
+	return mux2->no_ops * (4 * sizeof(u32));
+}
+
+static u32 qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
+				struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+	u32 fl_addr, size;
+	struct __mem *rom = &entry->region.mem;
+
+	fl_addr = rom->addr;
+	size = rom->size / 4;
+
+	if (!qlcnic_83xx_lockless_flash_read32(adapter, fl_addr,
+					       (u8 *)buffer, size))
+		return rom->size;
+
+	return 0;
+}
+
+static const struct qlcnic_dump_operations qlcnic_fw_dump_ops[] = {
+	{QLCNIC_DUMP_NOP, qlcnic_dump_nop},
+	{QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
+	{QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
+	{QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
+	{QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom},
+	{QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
+	{QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
+	{QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_READ_ROM, qlcnic_read_rom},
+	{QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
+	{QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
+	{QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
+	{QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
+};
+
+static const struct qlcnic_dump_operations qlcnic_83xx_fw_dump_ops[] = {
+	{QLCNIC_DUMP_NOP, qlcnic_dump_nop},
+	{QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb},
+	{QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux},
+	{QLCNIC_DUMP_QUEUE, qlcnic_dump_que},
+	{QLCNIC_DUMP_BRD_CONFIG, qlcnic_83xx_dump_rom},
+	{QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm},
+	{QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl},
+	{QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache},
+	{QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache},
+	{QLCNIC_DUMP_POLL_RD, qlcnic_read_pollrd},
+	{QLCNIC_READ_MUX2, qlcnic_read_mux2},
+	{QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr},
+	{QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_rom},
+	{QLCNIC_DUMP_READ_MEM, qlcnic_read_memory},
+	{QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl},
+	{QLCNIC_DUMP_TLHDR, qlcnic_dump_nop},
+	{QLCNIC_DUMP_RDEND, qlcnic_dump_nop},
+};
+
+static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
+{
+	uint64_t sum = 0;
+	int count = temp_size / sizeof(uint32_t);
+	while (count-- > 0)
+		sum += *temp_buffer++;
+	while (sum >> 32)
+		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
+	return ~sum;
+}
+
+static int qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
+					     u8 *buffer, u32 size)
+{
+	int ret = 0;
+
+	if (qlcnic_82xx_check(adapter))
+		return -EIO;
+
+	if (qlcnic_83xx_lock_flash(adapter))
+		return -EIO;
+
+	ret = qlcnic_83xx_lockless_flash_read32(adapter,
+						QLC_83XX_MINIDUMP_FLASH,
+						buffer, size / sizeof(u32));
+
+	qlcnic_83xx_unlock_flash(adapter);
+
+	return ret;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+				       struct qlcnic_cmd_args *cmd)
+{
+	struct qlcnic_dump_template_hdr tmp_hdr;
+	u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+	int ret = 0;
+
+	if (qlcnic_82xx_check(adapter))
+		return -EIO;
+
+	if (qlcnic_83xx_lock_flash(adapter))
+		return -EIO;
+
+	ret = qlcnic_83xx_lockless_flash_read32(adapter,
+						QLC_83XX_MINIDUMP_FLASH,
+						(u8 *)&tmp_hdr, size);
+
+	qlcnic_83xx_unlock_flash(adapter);
+
+	cmd->rsp.arg[2] = tmp_hdr.size;
+	cmd->rsp.arg[3] = tmp_hdr.version;
+
+	return ret;
+}
+
+static int qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+					    u32 *version, u32 *temp_size,
+					    u8 *use_flash_temp)
+{
+	int err = 0;
+	struct qlcnic_cmd_args cmd;
+
+	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TEMP_SIZE))
+		return -ENOMEM;
+
+	err = qlcnic_issue_cmd(adapter, &cmd);
+	if (err != QLCNIC_RCODE_SUCCESS) {
+		if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
+			qlcnic_free_mbx_args(&cmd);
+			return -EIO;
+		}
+		*use_flash_temp = 1;
+	}
+
+	*temp_size = cmd.rsp.arg[2];
+	*version = cmd.rsp.arg[3];
+	qlcnic_free_mbx_args(&cmd);
+
+	if (!(*temp_size))
+		return -EIO;
+
+	return 0;
+}
+
+static int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
+					     u32 *buffer, u32 temp_size)
+{
+	int err = 0, i;
+	void *tmp_addr;
+	__le32 *tmp_buf;
+	struct qlcnic_cmd_args cmd;
+	dma_addr_t tmp_addr_t = 0;
+
+	tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
+				      &tmp_addr_t, GFP_KERNEL);
+	if (!tmp_addr) {
+		dev_err(&adapter->pdev->dev,
+			"Can't get memory for FW dump template\n");
+		return -ENOMEM;
+	}
+
+	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
+		err = -ENOMEM;
+		goto free_mem;
+	}
+
+	cmd.req.arg[1] = LSD(tmp_addr_t);
+	cmd.req.arg[2] = MSD(tmp_addr_t);
+	cmd.req.arg[3] = temp_size;
+	err = qlcnic_issue_cmd(adapter, &cmd);
+
+	tmp_buf = tmp_addr;
+	if (err == QLCNIC_RCODE_SUCCESS) {
+		for (i = 0; i < temp_size / sizeof(u32); i++)
+			*buffer++ = __le32_to_cpu(*tmp_buf++);
+	}
+
+	qlcnic_free_mbx_args(&cmd);
+
+free_mem:
+	dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+
+	return err;
+}
+
+int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+{
+	int err;
+	u32 temp_size = 0;
+	u32 version, csum, *tmp_buf;
+	struct qlcnic_hardware_context *ahw;
+	struct qlcnic_dump_template_hdr *tmpl_hdr;
+	u8 use_flash_temp = 0;
+
+	ahw = adapter->ahw;
+
+	err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
+					       &use_flash_temp);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"Can't get template size %d\n", err);
+		return -EIO;
+	}
+
+	ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
+	if (!ahw->fw_dump.tmpl_hdr)
+		return -ENOMEM;
+
+	tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+	if (use_flash_temp)
+		goto flash_temp;
+
+	err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
+
+	if (err) {
+flash_temp:
+		err = qlcnic_fw_flash_get_minidump_temp(adapter, (u8 *)tmp_buf,
+							temp_size);
+
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"Failed to get minidump template header %d\n",
+				err);
+			vfree(ahw->fw_dump.tmpl_hdr);
+			ahw->fw_dump.tmpl_hdr = NULL;
+			return -EIO;
+		}
+	}
+
+	csum = qlcnic_temp_checksum((uint32_t *)tmp_buf, temp_size);
+
+	if (csum) {
+		dev_err(&adapter->pdev->dev,
+			"Template header checksum validation failed\n");
+		vfree(ahw->fw_dump.tmpl_hdr);
+		ahw->fw_dump.tmpl_hdr = NULL;
+		return -EIO;
+	}
+
+	tmpl_hdr = ahw->fw_dump.tmpl_hdr;
+	tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+	ahw->fw_dump.enable = 1;
+
+	return 0;
+}
+
 int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 {
 	__le32 *buffer;
+	u32 ocm_window;
 	char mesg[64];
 	char *msg[] = {mesg, NULL};
 	int i, k, ops_cnt, ops_index, dump_size = 0;
@@ -550,12 +912,23 @@
 	struct qlcnic_dump_entry *entry;
 	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
 	struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
+	static const struct qlcnic_dump_operations *fw_dump_ops;
+	struct qlcnic_hardware_context *ahw;
+
+	ahw = adapter->ahw;
+
+	if (!fw_dump->enable) {
+		dev_info(&adapter->pdev->dev, "Dump not enabled\n");
+		return -EIO;
+	}
 
 	if (fw_dump->clr) {
 		dev_info(&adapter->pdev->dev,
 			 "Previous dump not cleared, not capturing dump\n");
 		return -EIO;
 	}
+
+	netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
 	/* Calculate the size for dump data area only */
 	for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
 		if (i & tmpl_hdr->drv_cap_mask)
@@ -564,20 +937,27 @@
 		return -EIO;
 
 	fw_dump->data = vzalloc(dump_size);
-	if (!fw_dump->data) {
-		dev_info(&adapter->pdev->dev,
-			 "Unable to allocate (%d KB) for fw dump\n",
-			 dump_size / 1024);
+	if (!fw_dump->data)
 		return -ENOMEM;
-	}
+
 	buffer = fw_dump->data;
 	fw_dump->size = dump_size;
 	no_entries = tmpl_hdr->num_entries;
-	ops_cnt = ARRAY_SIZE(fw_dump_ops);
 	entry_offset = tmpl_hdr->offset;
 	tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
 	tmpl_hdr->sys_info[1] = adapter->fw_version;
 
+	if (qlcnic_82xx_check(adapter)) {
+		ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
+		fw_dump_ops = qlcnic_fw_dump_ops;
+	} else {
+		ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
+		fw_dump_ops = qlcnic_83xx_fw_dump_ops;
+		ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
+		tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
+		tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
+	}
+
 	for (i = 0; i < no_entries; i++) {
 		entry = (void *)tmpl_hdr + entry_offset;
 		if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
@@ -585,6 +965,7 @@
 			entry_offset += entry->hdr.offset;
 			continue;
 		}
+
 		/* Find the handler for this entry */
 		ops_index = 0;
 		while (ops_index < ops_cnt) {
@@ -592,16 +973,17 @@
 				break;
 			ops_index++;
 		}
+
 		if (ops_index == ops_cnt) {
 			dev_info(&adapter->pdev->dev,
 				 "Invalid entry type %d, exiting dump\n",
 				 entry->hdr.type);
 			goto error;
 		}
+
 		/* Collect dump for this entry */
 		dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
-		if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
-						     dump))
+		if (!qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, dump))
 			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
 		buf_offset += entry->hdr.cap_size;
 		entry_offset += entry->hdr.offset;
@@ -616,8 +998,8 @@
 		fw_dump->clr = 1;
 		snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
 			 adapter->netdev->name);
-		dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
-			 fw_dump->size);
+		dev_info(&adapter->pdev->dev, "%s: Dump data, %d bytes captured\n",
+			 adapter->netdev->name, fw_dump->size);
 		/* Send a udev event to notify availability of FW dump */
 		kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
 		return 0;
@@ -626,3 +1008,21 @@
 	vfree(fw_dump->data);
 	return -EINVAL;
 }
+
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
+{
+	u32 prev_version, current_version;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
+	struct pci_dev *pdev = adapter->pdev;
+
+	prev_version = adapter->fw_version;
+	current_version = qlcnic_83xx_get_fw_version(adapter);
+
+	if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
+		if (fw_dump->tmpl_hdr)
+			vfree(fw_dump->tmpl_hdr);
+		if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+			dev_info(&pdev->dev, "Supports FW dump capability\n");
+	}
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 341d37c..987fb6f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -1,8 +1,16 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 #include <linux/swab.h>
 #include <linux/dma-mapping.h>
@@ -13,6 +21,10 @@
 #include <linux/aer.h>
 #include <linux/log2.h>
 
+#include <linux/sysfs.h>
+
+#define QLC_STATUS_UNSUPPORTED_CMD	-2
+
 int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
 {
 	return -EOPNOTSUPP;
@@ -40,7 +52,7 @@
 	if (strict_strtoul(buf, 2, &new))
 		goto err_out;
 
-	if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
+	if (!qlcnic_config_bridged_mode(adapter, !!new))
 		ret = len;
 
 err_out:
@@ -80,9 +92,7 @@
 				     struct device_attribute *attr, char *buf)
 {
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
-	return sprintf(buf, "%d\n",
-		       !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+	return sprintf(buf, "%d\n", !!(adapter->flags & QLCNIC_DIAG_ENABLED));
 }
 
 static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
@@ -111,10 +121,11 @@
 				   const char *buf, size_t len)
 {
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	int max_sds_rings = adapter->max_sds_rings;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int err, max_sds_rings = adapter->max_sds_rings;
 	u16 beacon;
 	u8 b_state, b_rate;
-	int err;
+	unsigned long h_beacon;
 
 	if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
 		dev_warn(dev,
@@ -122,6 +133,41 @@
 		return -EOPNOTSUPP;
 	}
 
+	if (qlcnic_83xx_check(adapter) &&
+	    !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+		if (kstrtoul(buf, 2, &h_beacon))
+			return -EINVAL;
+
+		if (ahw->beacon_state == h_beacon)
+			return len;
+
+		rtnl_lock();
+		if (!ahw->beacon_state) {
+			if (test_and_set_bit(__QLCNIC_LED_ENABLE,
+					     &adapter->state)) {
+				rtnl_unlock();
+				return -EBUSY;
+			}
+		}
+		if (h_beacon) {
+			err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
+			if (err)
+				goto beacon_err;
+		} else {
+			err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
+			if (err)
+				goto beacon_err;
+		}
+		/* set the current beacon state */
+		ahw->beacon_state = h_beacon;
+beacon_err:
+		if (!ahw->beacon_state)
+			clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+		rtnl_unlock();
+		return len;
+	}
+
 	if (len != sizeof(u16))
 		return QL_STATUS_INVALID_PARAM;
 
@@ -154,11 +200,10 @@
 	}
 
 	err = qlcnic_config_led(adapter, b_state, b_rate);
-
-	if (!err) {
+	if (!err)
 		err = len;
-		adapter->ahw->beacon_state = b_state;
-	}
+	else
+		ahw->beacon_state = b_state;
 
 	if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
 		qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
@@ -207,21 +252,13 @@
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 data;
-	u64 qmdata;
 	int ret;
 
 	ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
 	if (ret != 0)
 		return ret;
+	qlcnic_read_crb(adapter, buf, offset, size);
 
-	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
-		qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
-		memcpy(buf, &qmdata, size);
-	} else {
-		data = QLCRD32(adapter, offset);
-		memcpy(buf, &data, size);
-	}
 	return size;
 }
 
@@ -231,21 +268,13 @@
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 data;
-	u64 qmdata;
 	int ret;
 
 	ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
 	if (ret != 0)
 		return ret;
 
-	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
-		memcpy(&qmdata, buf, size);
-		qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
-	} else {
-		memcpy(&data, buf, size);
-		QLCWR32(adapter, offset, data);
-	}
+	qlcnic_write_crb(adapter, buf, offset, size);
 	return size;
 }
 
@@ -303,33 +332,44 @@
 	return size;
 }
 
+static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
+{
+	int i;
+	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+		if (adapter->npars[i].pci_func == pci_func)
+			return i;
+	}
+
+	return -1;
+}
+
 static int validate_pm_config(struct qlcnic_adapter *adapter,
 			      struct qlcnic_pm_func_cfg *pm_cfg, int count)
 {
-	u8 src_pci_func, s_esw_id, d_esw_id, dest_pci_func;
-	int i;
+	u8 src_pci_func, s_esw_id, d_esw_id;
+	u8 dest_pci_func;
+	int i, src_index, dest_index;
 
 	for (i = 0; i < count; i++) {
 		src_pci_func = pm_cfg[i].pci_func;
 		dest_pci_func = pm_cfg[i].dest_npar;
-		if (src_pci_func >= QLCNIC_MAX_PCI_FUNC ||
-		    dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+		src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func);
+
+		if (src_index < 0)
 			return QL_STATUS_INVALID_PARAM;
 
-		if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+		dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func);
+		if (dest_index < 0)
 			return QL_STATUS_INVALID_PARAM;
 
-		if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
-			return QL_STATUS_INVALID_PARAM;
-
-		s_esw_id = adapter->npars[src_pci_func].phy_port;
-		d_esw_id = adapter->npars[dest_pci_func].phy_port;
+		s_esw_id = adapter->npars[src_index].phy_port;
+		d_esw_id = adapter->npars[dest_index].phy_port;
 
 		if (s_esw_id != d_esw_id)
 			return QL_STATUS_INVALID_PARAM;
 	}
-	return 0;
 
+	return 0;
 }
 
 static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
@@ -342,7 +382,7 @@
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_pm_func_cfg *pm_cfg;
 	u32 id, action, pci_func;
-	int count, rem, i, ret;
+	int count, rem, i, ret, index;
 
 	count	= size / sizeof(struct qlcnic_pm_func_cfg);
 	rem	= size % sizeof(struct qlcnic_pm_func_cfg);
@@ -350,26 +390,32 @@
 		return QL_STATUS_INVALID_PARAM;
 
 	pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
-
 	ret = validate_pm_config(adapter, pm_cfg, count);
+
 	if (ret)
 		return ret;
 	for (i = 0; i < count; i++) {
 		pci_func = pm_cfg[i].pci_func;
 		action = !!pm_cfg[i].action;
-		id = adapter->npars[pci_func].phy_port;
-		ret = qlcnic_config_port_mirroring(adapter, id, action,
-						   pci_func);
+		index = qlcnic_is_valid_nic_func(adapter, pci_func);
+		if (index < 0)
+			return QL_STATUS_INVALID_PARAM;
+
+		id = adapter->npars[index].phy_port;
+		ret = qlcnic_config_port_mirroring(adapter, id,
+						   action, pci_func);
 		if (ret)
 			return ret;
 	}
 
 	for (i = 0; i < count; i++) {
 		pci_func = pm_cfg[i].pci_func;
-		id = adapter->npars[pci_func].phy_port;
-		adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
-		adapter->npars[pci_func].dest_npar = id;
+		index = qlcnic_is_valid_nic_func(adapter, pci_func);
+		id = adapter->npars[index].phy_port;
+		adapter->npars[index].enable_pm = !!pm_cfg[i].action;
+		adapter->npars[index].dest_npar = id;
 	}
+
 	return size;
 }
 
@@ -383,16 +429,19 @@
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
 	int i;
+	u8 pci_func;
 
 	if (size != sizeof(pm_cfg))
 		return QL_STATUS_INVALID_PARAM;
 
-	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-			continue;
-		pm_cfg[i].action = adapter->npars[i].enable_pm;
-		pm_cfg[i].dest_npar = 0;
-		pm_cfg[i].pci_func = i;
+	memset(&pm_cfg, 0,
+	       sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+		pci_func = adapter->npars[i].pci_func;
+		pm_cfg[pci_func].action = adapter->npars[i].enable_pm;
+		pm_cfg[pci_func].dest_npar = 0;
+		pm_cfg[pci_func].pci_func = i;
 	}
 	memcpy(buf, &pm_cfg, size);
 
@@ -404,24 +453,33 @@
 {
 	u32 op_mode;
 	u8 pci_func;
-	int i;
+	int i, ret;
 
-	op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+	if (qlcnic_82xx_check(adapter))
+		op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+	else
+		op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
 
 	for (i = 0; i < count; i++) {
 		pci_func = esw_cfg[i].pci_func;
 		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
 			return QL_STATUS_INVALID_PARAM;
 
-		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
-			if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+			if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
 				return QL_STATUS_INVALID_PARAM;
-		}
 
 		switch (esw_cfg[i].op_mode) {
 		case QLCNIC_PORT_DEFAULTS:
-			if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
-					    QLCNIC_NON_PRIV_FUNC) {
+			if (qlcnic_82xx_check(adapter)) {
+				ret = QLC_DEV_GET_DRV(op_mode, pci_func);
+			} else {
+				ret = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+								  pci_func);
+				esw_cfg[i].offload_flags = 0;
+			}
+
+			if (ret != QLCNIC_NON_PRIV_FUNC) {
 				if (esw_cfg[i].mac_anti_spoof != 0)
 					return QL_STATUS_INVALID_PARAM;
 				if (esw_cfg[i].mac_override != 1)
@@ -444,6 +502,7 @@
 			return QL_STATUS_INVALID_PARAM;
 		}
 	}
+
 	return 0;
 }
 
@@ -458,7 +517,8 @@
 	struct qlcnic_esw_func_cfg *esw_cfg;
 	struct qlcnic_npar_info *npar;
 	int count, rem, i, ret;
-	u8 pci_func, op_mode = 0;
+	int index;
+	u8 op_mode = 0, pci_func;
 
 	count	= size / sizeof(struct qlcnic_esw_func_cfg);
 	rem	= size % sizeof(struct qlcnic_esw_func_cfg);
@@ -471,10 +531,9 @@
 		return ret;
 
 	for (i = 0; i < count; i++) {
-		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
+		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
 			if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
 				return QL_STATUS_INVALID_PARAM;
-		}
 
 		if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
 			continue;
@@ -503,7 +562,8 @@
 
 	for (i = 0; i < count; i++) {
 		pci_func = esw_cfg[i].pci_func;
-		npar = &adapter->npars[pci_func];
+		index = qlcnic_is_valid_nic_func(adapter, pci_func);
+		npar = &adapter->npars[index];
 		switch (esw_cfg[i].op_mode) {
 		case QLCNIC_PORT_DEFAULTS:
 			npar->promisc_mode = esw_cfg[i].promisc_mode;
@@ -533,18 +593,21 @@
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
-	u8 i;
+	u8 i, pci_func;
 
 	if (size != sizeof(esw_cfg))
 		return QL_STATUS_INVALID_PARAM;
 
-	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-			continue;
-		esw_cfg[i].pci_func = i;
-		if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
+	memset(&esw_cfg, 0,
+	       sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+		pci_func = adapter->npars[i].pci_func;
+		esw_cfg[pci_func].pci_func = pci_func;
+		if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
 			return QL_STATUS_INVALID_PARAM;
 	}
+
 	memcpy(buf, &esw_cfg, size);
 
 	return size;
@@ -558,10 +621,7 @@
 
 	for (i = 0; i < count; i++) {
 		pci_func = np_cfg[i].pci_func;
-		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
-			return QL_STATUS_INVALID_PARAM;
-
-		if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+		if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
 			return QL_STATUS_INVALID_PARAM;
 
 		if (!IS_VALID_BW(np_cfg[i].min_bw) ||
@@ -581,7 +641,7 @@
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_info nic_info;
 	struct qlcnic_npar_func_cfg *np_cfg;
-	int i, count, rem, ret;
+	int i, count, rem, ret, index;
 	u8 pci_func;
 
 	count	= size / sizeof(struct qlcnic_npar_func_cfg);
@@ -594,8 +654,10 @@
 	if (ret)
 		return ret;
 
-	for (i = 0; i < count ; i++) {
+	for (i = 0; i < count; i++) {
 		pci_func = np_cfg[i].pci_func;
+
+		memset(&nic_info, 0, sizeof(struct qlcnic_info));
 		ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
 		if (ret)
 			return ret;
@@ -605,12 +667,12 @@
 		ret = qlcnic_set_nic_info(adapter, &nic_info);
 		if (ret)
 			return ret;
-		adapter->npars[i].min_bw = nic_info.min_tx_bw;
-		adapter->npars[i].max_bw = nic_info.max_tx_bw;
+		index = qlcnic_is_valid_nic_func(adapter, pci_func);
+		adapter->npars[index].min_bw = nic_info.min_tx_bw;
+		adapter->npars[index].max_bw = nic_info.max_tx_bw;
 	}
 
 	return size;
-
 }
 
 static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
@@ -628,8 +690,12 @@
 	if (size != sizeof(np_cfg))
 		return QL_STATUS_INVALID_PARAM;
 
+	memset(&nic_info, 0, sizeof(struct qlcnic_info));
+	memset(&np_cfg, 0,
+	       sizeof(struct qlcnic_npar_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
 	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+		if (qlcnic_is_valid_nic_func(adapter, i) < 0)
 			continue;
 		ret = qlcnic_get_nic_info(adapter, &nic_info, i);
 		if (ret)
@@ -644,6 +710,7 @@
 		np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
 		np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
 	}
+
 	memcpy(buf, &np_cfg, size);
 	return size;
 }
@@ -659,6 +726,9 @@
 	struct qlcnic_esw_statistics port_stats;
 	int ret;
 
+	if (qlcnic_83xx_check(adapter))
+		return QLC_STATUS_UNSUPPORTED_CMD;
+
 	if (size != sizeof(struct qlcnic_esw_statistics))
 		return QL_STATUS_INVALID_PARAM;
 
@@ -691,6 +761,9 @@
 	struct qlcnic_esw_statistics esw_stats;
 	int ret;
 
+	if (qlcnic_83xx_check(adapter))
+		return QLC_STATUS_UNSUPPORTED_CMD;
+
 	if (size != sizeof(struct qlcnic_esw_statistics))
 		return QL_STATUS_INVALID_PARAM;
 
@@ -722,6 +795,9 @@
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	int ret;
 
+	if (qlcnic_83xx_check(adapter))
+		return QLC_STATUS_UNSUPPORTED_CMD;
+
 	if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
 		return QL_STATUS_INVALID_PARAM;
 
@@ -744,10 +820,14 @@
 					     char *buf, loff_t offset,
 					     size_t size)
 {
+
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	int ret;
 
+	if (qlcnic_83xx_check(adapter))
+		return QLC_STATUS_UNSUPPORTED_CMD;
+
 	if (offset >= QLCNIC_MAX_PCI_FUNC)
 		return QL_STATUS_INVALID_PARAM;
 
@@ -789,7 +869,10 @@
 		return ret;
 	}
 
-	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+	memset(&pci_cfg, 0,
+	       sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
 		pci_cfg[i].pci_func = pci_info[i].id;
 		pci_cfg[i].func_type = pci_info[i].type;
 		pci_cfg[i].port_num = pci_info[i].default_port;
@@ -797,6 +880,7 @@
 		pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
 		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
 	}
+
 	memcpy(buf, &pci_cfg, size);
 	kfree(pci_info);
 	return size;
@@ -897,7 +981,6 @@
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 {
 	struct device *dev = &adapter->pdev->dev;
-	u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
 	if (device_create_bin_file(dev, &bin_attr_port_stats))
 		dev_info(dev, "failed to create port stats sysfs entry");
@@ -911,9 +994,6 @@
 	if (device_create_bin_file(dev, &bin_attr_mem))
 		dev_info(dev, "failed to create mem sysfs entry\n");
 
-	if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-		return;
-
 	if (device_create_bin_file(dev, &bin_attr_pci_config))
 		dev_info(dev, "failed to create pci config sysfs entry");
 	if (device_create_file(dev, &dev_attr_beacon))
@@ -936,7 +1016,6 @@
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
 	struct device *dev = &adapter->pdev->dev;
-	u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
 	device_remove_bin_file(dev, &bin_attr_port_stats);
 
@@ -945,8 +1024,6 @@
 	device_remove_file(dev, &dev_attr_diag_mode);
 	device_remove_bin_file(dev, &bin_attr_crb);
 	device_remove_bin_file(dev, &bin_attr_mem);
-	if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-		return;
 	device_remove_bin_file(dev, &bin_attr_pci_config);
 	device_remove_file(dev, &dev_attr_beacon);
 	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
@@ -958,3 +1035,23 @@
 	device_remove_bin_file(dev, &bin_attr_pm_config);
 	device_remove_bin_file(dev, &bin_attr_esw_stats);
 }
+
+void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+	qlcnic_create_diag_entries(adapter);
+}
+
+void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+	qlcnic_remove_diag_entries(adapter);
+}
+
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+	qlcnic_create_diag_entries(adapter);
+}
+
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+	qlcnic_remove_diag_entries(adapter);
+}
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 3e73742..b13ab54 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -2920,14 +2920,11 @@
 		/*
 		 * Allocate small buffer queue control blocks.
 		 */
-		rx_ring->sbq =
-		    kmalloc(rx_ring->sbq_len * sizeof(struct bq_desc),
-			    GFP_KERNEL);
-		if (rx_ring->sbq == NULL) {
-			netif_err(qdev, ifup, qdev->ndev,
-				  "Small buffer queue control block allocation failed.\n");
+		rx_ring->sbq = kmalloc_array(rx_ring->sbq_len,
+					     sizeof(struct bq_desc),
+					     GFP_KERNEL);
+		if (rx_ring->sbq == NULL)
 			goto err_mem;
-		}
 
 		ql_init_sbq_ring(qdev, rx_ring);
 	}
@@ -2948,14 +2945,11 @@
 		/*
 		 * Allocate large buffer queue control blocks.
 		 */
-		rx_ring->lbq =
-		    kmalloc(rx_ring->lbq_len * sizeof(struct bq_desc),
-			    GFP_KERNEL);
-		if (rx_ring->lbq == NULL) {
-			netif_err(qdev, ifup, qdev->ndev,
-				  "Large buffer queue control block allocation failed.\n");
+		rx_ring->lbq = kmalloc_array(rx_ring->lbq_len,
+					     sizeof(struct bq_desc),
+					     GFP_KERNEL);
+		if (rx_ring->lbq == NULL)
 			goto err_mem;
-		}
 
 		ql_init_lbq_ring(qdev, rx_ring);
 	}
@@ -4572,7 +4566,6 @@
 		qdev->mpi_coredump =
 			vmalloc(sizeof(struct ql_mpi_coredump));
 		if (qdev->mpi_coredump == NULL) {
-			dev_err(&pdev->dev, "Coredump alloc failed.\n");
 			err = -ENOMEM;
 			goto err_out2;
 		}
@@ -4586,7 +4579,6 @@
 		goto err_out2;
 	}
 
-	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
 	/* Keep local copy of current mac address. */
 	memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
 
diff --git a/drivers/net/ethernet/racal/Kconfig b/drivers/net/ethernet/racal/Kconfig
deleted file mode 100644
index 01969e0..0000000
--- a/drivers/net/ethernet/racal/Kconfig
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Racal-Interlan device configuration
-#
-
-config NET_VENDOR_RACAL
-	bool "Racal-Interlan (Micom) NI devices"
-	default y
-	depends on ISA
-	---help---
-	  If you have a network (Ethernet) card belonging to this class, such
-	  as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
-	  available from <http://www.tldp.org/docs.html#howto>.
-
-	  Note that the answer to this question doesn't directly affect the
-	  kernel: saying N will just cause the configurator to skip all
-	  the questions about NI cards. If you say Y, you will be asked for
-	  your specific card in the following questions.
-
-if NET_VENDOR_RACAL
-
-config NI5010
-	tristate "NI5010 support (EXPERIMENTAL)"
-	depends on ISA && EXPERIMENTAL && BROKEN_ON_SMP
-	---help---
-	  If you have a network (Ethernet) card of this type, say Y and read
-	  the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>. Note that this is still
-	  experimental code.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called ni5010.
-
-endif # NET_VENDOR_RACAL
diff --git a/drivers/net/ethernet/racal/Makefile b/drivers/net/ethernet/racal/Makefile
deleted file mode 100644
index 1e210ca..0000000
--- a/drivers/net/ethernet/racal/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Racal-Interlan network device drivers.
-#
-
-obj-$(CONFIG_NI5010) += ni5010.o
diff --git a/drivers/net/ethernet/racal/ni5010.c b/drivers/net/ethernet/racal/ni5010.c
deleted file mode 100644
index 8079822..0000000
--- a/drivers/net/ethernet/racal/ni5010.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/*	ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
- *
- *	Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
- *
- *	This software may be used and distributed according to the terms
- *	of the GNU General Public License, incorporated herein by reference.
- *
- * 	The authors may be reached as:
- *		janpascal@vanbest.org		andi@lisas.de
- *
- *	Sources:
- * 	 	Donald Becker's "skeleton.c"
- *  		Crynwr ni5010 packet driver
- *
- *	Changes:
- *		v0.0: First test version
- *		v0.1: First working version
- *		v0.2:
- *		v0.3->v0.90: Now demand setting io and irq when loading as module
- *	970430	v0.91: modified for Linux 2.1.14
- *		v0.92: Implemented Andreas' (better) NI5010 probe
- *	970503	v0.93: Fixed auto-irq failure on warm reboot (JB)
- *	970623	v1.00: First kernel version (AM)
- *	970814	v1.01: Added detection of onboard receive buffer size (AM)
- *	060611	v1.02: slight cleanup: email addresses, driver modernization.
- *	Bugs:
- *		- not SMP-safe (no locking of I/O accesses)
- *		- Note that you have to patch ifconfig for the new /proc/net/dev
- *		format. It gives incorrect stats otherwise.
- *
- *	To do:
- *		Fix all bugs :-)
- *		Move some stuff to chipset_init()
- *		Handle xmt errors other than collisions
- *		Complete merge with Andreas' driver
- *		Implement ring buffers (Is this useful? You can't squeeze
- *			too many packet in a 2k buffer!)
- *		Implement DMA (Again, is this useful? Some docs say DMA is
- *			slower than programmed I/O)
- *
- *	Compile with:
- *		gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \
- *			-DMODULE -c ni5010.c
- *
- *	Insert with e.g.:
- *		insmod ni5010.ko io=0x300 irq=5
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni5010.h"
-
-static const char boardname[] = "NI5010";
-static char version[] __initdata =
-	"ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
-
-/* bufsize_rcv == 0 means autoprobing */
-static unsigned int bufsize_rcv;
-
-#define JUMPERED_INTERRUPTS	/* IRQ line jumpered on board */
-#undef JUMPERED_DMA		/* No DMA used */
-#undef FULL_IODETECT		/* Only detect in portlist */
-
-#ifndef FULL_IODETECT
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int ports[] __initdata =
-	{ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 };
-#endif
-
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef NI5010_DEBUG
-#define NI5010_DEBUG 0
-#endif
-
-/* Information that needs to be kept for each board. */
-struct ni5010_local {
-	int o_pkt_size;
-	spinlock_t lock;
-};
-
-/* Index to functions, as function prototypes. */
-
-static int	ni5010_probe1(struct net_device *dev, int ioaddr);
-static int	ni5010_open(struct net_device *dev);
-static int	ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
-static void	ni5010_rx(struct net_device *dev);
-static void	ni5010_timeout(struct net_device *dev);
-static int	ni5010_close(struct net_device *dev);
-static void 	ni5010_set_multicast_list(struct net_device *dev);
-static void	reset_receiver(struct net_device *dev);
-
-static int	process_xmt_interrupt(struct net_device *dev);
-#define tx_done(dev) 1
-static void	hardware_send_packet(struct net_device *dev, char *buf, int length, int pad);
-static void 	chipset_init(struct net_device *dev, int startp);
-static void	dump_packet(void *buf, int len);
-static void 	ni5010_show_registers(struct net_device *dev);
-
-static int io;
-static int irq;
-
-struct net_device * __init ni5010_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local));
-	int *port;
-	int err = 0;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-	}
-
-	PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
-
-	if (io > 0x1ff)	{	/* Check a single specified location. */
-		err = ni5010_probe1(dev, io);
-	} else if (io != 0) {	/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-#ifdef FULL_IODETECT
-		for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20)
-			;
-		if (io == 0x400)
-			err = -ENODEV;
-
-#else
-		for (port = ports; *port && ni5010_probe1(dev, *port); port++)
-			;
-		if (!*port)
-			err = -ENODEV;
-#endif	/* FULL_IODETECT */
-	}
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	release_region(dev->base_addr, NI5010_IO_EXTENT);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static inline int rd_port(int ioaddr)
-{
-	inb(IE_RBUF);
-	return inb(IE_SAPROM);
-}
-
-static void __init trigger_irq(int ioaddr)
-{
-		outb(0x00, EDLC_RESET);	/* Clear EDLC hold RESET state */
-		outb(0x00, IE_RESET);	/* Board reset */
-		outb(0x00, EDLC_XMASK);	/* Disable all Xmt interrupts */
-		outb(0x00, EDLC_RMASK); /* Disable all Rcv interrupt */
-		outb(0xff, EDLC_XCLR);	/* Clear all pending Xmt interrupts */
-		outb(0xff, EDLC_RCLR);	/* Clear all pending Rcv interrupts */
-		/*
-		 * Transmit packet mode: Ignore parity, Power xcvr,
-		 * 	Enable loopback
-		 */
-		outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
-		outb(RMD_BROADCAST, EDLC_RMODE); /* Receive normal&broadcast */
-		outb(XM_ALL, EDLC_XMASK);	/* Enable all Xmt interrupts */
-		udelay(50);			/* FIXME: Necessary? */
-		outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */
-}
-
-static const struct net_device_ops ni5010_netdev_ops = {
-	.ndo_open		= ni5010_open,
-	.ndo_stop		= ni5010_close,
-	.ndo_start_xmit		= ni5010_send_packet,
-	.ndo_set_rx_mode	= ni5010_set_multicast_list,
-	.ndo_tx_timeout		= ni5010_timeout,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address	= eth_mac_addr,
-	.ndo_change_mtu		= eth_change_mtu,
-};
-
-/*
- *      This is the real probe routine.  Linux has a history of friendly device
- *      probes on the ISA bus.  A good device probes avoids doing writes, and
- *      verifies that the correct device exists and functions.
- */
-
-static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
-{
-	static unsigned version_printed;
-	struct ni5010_local *lp;
-	int i;
-	unsigned int data = 0;
-	int boguscount = 40;
-	int err = -ENODEV;
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname))
-		return -EBUSY;
-
-	/*
-	 * This is no "official" probe method, I've rather tested which
-	 * probe works best with my seven NI5010 cards
-	 * (they have very different serial numbers)
-	 * Suggestions or failure reports are very, very welcome !
-	 * But I think it is a relatively good probe method
-	 * since it doesn't use any "outb"
-	 * It should be nearly 100% reliable !
-	 * well-known WARNING: this probe method (like many others)
-	 * will hang the system if a NE2000 card region is probed !
-	 *
-	 *   - Andreas
-	 */
-
- 	PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
- 		dev->name, ioaddr));
-
-	if (inb(ioaddr+0) == 0xff)
-		goto out;
-
-	while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) &
-		 rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff)
-	{
-		if (boguscount-- == 0)
-			goto out;
-	}
-
-	PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name));
-
-	for (i=0; i<32; i++)
-		if ( (data = rd_port(ioaddr)) != 0xff) break;
-	if (data==0xff)
-		goto out;
-
-	PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name));
-
-	if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) ||
-	    (rd_port(ioaddr) != SA_ADDR2))
-		goto out;
-
-	for (i=0; i<4; i++)
-		rd_port(ioaddr);
-
-	if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) ||
-	     (rd_port(ioaddr) != NI5010_MAGICVAL2) )
-		goto out;
-
-	PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name));
-
-	if (NI5010_DEBUG && version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-
-	printk("NI5010 ethercard probe at 0x%x: ", ioaddr);
-
-	dev->base_addr = ioaddr;
-
-	for (i=0; i<6; i++) {
-		outw(i, IE_GP);
-		dev->dev_addr[i] = inb(IE_SAPROM);
-	}
-	printk("%pM ", dev->dev_addr);
-
-	PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
-
-#ifdef JUMPERED_INTERRUPTS
-	if (dev->irq == 0xff)
-		;
-	else if (dev->irq < 2) {
-		unsigned long irq_mask;
-
-		PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name));
-
-		irq_mask = probe_irq_on();
-		trigger_irq(ioaddr);
-		mdelay(20);
-		dev->irq = probe_irq_off(irq_mask);
-
-		PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name));
-
-		if (dev->irq == 0) {
-			err = -EAGAIN;
-			printk(KERN_WARNING "%s: no IRQ found!\n", dev->name);
-			goto out;
-		}
-		PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name));
-	} else if (dev->irq == 2) {
-		dev->irq = 9;
-	}
-#endif	/* JUMPERED_INTERRUPTS */
-	PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
-
-	/* DMA is not supported (yet?), so no use detecting it */
-	lp = netdev_priv(dev);
-
-	spin_lock_init(&lp->lock);
-
-	PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name));
-
-/* get the size of the onboard receive buffer
- * higher addresses than bufsize are wrapped into real buffer
- * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer
- */
-	if (!bufsize_rcv) {
-        	outb(1, IE_MMODE);      /* Put Rcv buffer on system bus */
-        	outw(0, IE_GP);		/* Point GP at start of packet */
-        	outb(0, IE_RBUF);	/* set buffer byte 0 to 0 */
-        	for (i = 1; i < 0xff; i++) {
-                	outw(i << 8, IE_GP); /* Point GP at packet size to be tested */
-                	outb(i, IE_RBUF);
-                	outw(0x0, IE_GP); /* Point GP at start of packet */
-                	data = inb(IE_RBUF);
-                	if (data == i) break;
-        	}
-		bufsize_rcv = i << 8;
-        	outw(0, IE_GP);		/* Point GP at start of packet */
-        	outb(0, IE_RBUF);	/* set buffer byte 0 to 0 again */
-	}
-        printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
-
-	dev->netdev_ops		= &ni5010_netdev_ops;
-	dev->watchdog_timeo	= HZ/20;
-
-	dev->flags &= ~IFF_MULTICAST;	/* Multicast doesn't work */
-
-	/* Shut up the ni5010 */
-	outb(0, EDLC_RMASK);	/* Mask all receive interrupts */
-	outb(0, EDLC_XMASK);	/* Mask all xmit interrupts */
-	outb(0xff, EDLC_RCLR);	/* Kill all pending rcv interrupts */
-	outb(0xff, EDLC_XCLR); 	/* Kill all pending xmt interrupts */
-
-	printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
-	if (dev->dma)
-		printk(" & DMA %d", dev->dma);
-	printk(".\n");
-	return 0;
-out:
-	release_region(dev->base_addr, NI5010_IO_EXTENT);
-	return err;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-
-static int ni5010_open(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	int i;
-
-	PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
-
-	if (request_irq(dev->irq, ni5010_interrupt, 0, boardname, dev)) {
-		printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-	PRINTK3((KERN_DEBUG "%s: passed open() #1\n", dev->name));
-        /*
-         * Always allocate the DMA channel after the IRQ,
-         * and clean up on failure.
-         */
-#ifdef JUMPERED_DMA
-        if (request_dma(dev->dma, cardname)) {
-		printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
-                free_irq(dev->irq, NULL);
-                return -EAGAIN;
-        }
-#endif	/* JUMPERED_DMA */
-
-	PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
-	/* Reset the hardware here.  Don't forget to set the station address. */
-
-	outb(RS_RESET, EDLC_RESET);	/* Hold up EDLC_RESET while configing board */
-	outb(0, IE_RESET);		/* Hardware reset of ni5010 board */
-	outb(XMD_LBC, EDLC_XMODE);	/* Only loopback xmits */
-
-	PRINTK3((KERN_DEBUG "%s: passed open() #3\n", dev->name));
-	/* Set the station address */
-	for(i = 0;i < 6; i++) {
-		outb(dev->dev_addr[i], EDLC_ADDR + i);
-	}
-
-	PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
-	outb(0, EDLC_XMASK);	/* No xmit interrupts for now */
-	outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
-				/* Normal packet xmit mode */
-	outb(0xff, EDLC_XCLR);	/* Clear all pending xmit interrupts */
-	outb(RMD_BROADCAST, EDLC_RMODE);
-				/* Receive broadcast and normal packets */
-	reset_receiver(dev);	/* Ready ni5010 for receiving packets */
-
-	outb(0, EDLC_RESET);	/* Un-reset the ni5010 */
-
-	netif_start_queue(dev);
-
-	if (NI5010_DEBUG) ni5010_show_registers(dev);
-
-	PRINTK((KERN_DEBUG "%s: open successful\n", dev->name));
-     	return 0;
-}
-
-static void reset_receiver(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name));
-	outw(0, IE_GP);		/* Receive packet at start of buffer */
-	outb(0xff, EDLC_RCLR);	/* Clear all pending rcv interrupts */
-	outb(0, IE_MMODE);	/* Put EDLC to rcv buffer */
-	outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */
-	outb(0xff, EDLC_RMASK);	/* Enable all rcv interrupts */
-}
-
-static void ni5010_timeout(struct net_device *dev)
-{
-	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
-		   tx_done(dev) ? "IRQ conflict" : "network cable problem");
-	/* Try to restart the adaptor. */
-	/* FIXME: Give it a real kick here */
-	chipset_init(dev, 1);
-	dev->trans_start = jiffies; /* prevent tx timeout */
-	netif_wake_queue(dev);
-}
-
-static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-
-	PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
-
-	/*
-         * Block sending
-	 */
-
-	netif_stop_queue(dev);
-	hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
-	dev_kfree_skb (skb);
-	return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct ni5010_local *lp;
-	int ioaddr, status;
-	int xmit_was_error = 0;
-
-	PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name));
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	spin_lock(&lp->lock);
-	status = inb(IE_ISTAT);
-	PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status));
-
-        if ((status & IS_R_INT) == 0) ni5010_rx(dev);
-
-        if ((status & IS_X_INT) == 0) {
-                xmit_was_error = process_xmt_interrupt(dev);
-        }
-
-        if ((status & IS_DMA_INT) == 0) {
-                PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name));
-                outb(0, IE_DMA_RST); /* Reset DMA int */
-        }
-
-	if (!xmit_was_error)
-		reset_receiver(dev);
-	spin_unlock(&lp->lock);
-	return IRQ_HANDLED;
-}
-
-
-static void dump_packet(void *buf, int len)
-{
-	int i;
-
-	printk(KERN_DEBUG "Packet length = %#4x\n", len);
-	for (i = 0; i < len; i++){
-		if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i);
-		if (i % 2 == 0) printk(" ");
-		printk("%2.2x", ((unsigned char *)buf)[i]);
-		if (i % 16 == 15) printk("\n");
-	}
-	printk("\n");
-}
-
-/* We have a good packet, get it out of the buffer. */
-static void ni5010_rx(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	unsigned char rcv_stat;
-	struct sk_buff *skb;
-	int i_pkt_size;
-
-	PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
-
-	rcv_stat = inb(EDLC_RSTAT);
-	PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
-
-	if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
-		PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
-		dev->stats.rx_errors++;
-		if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
-		if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
-		if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
-		if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
-        	outb(0xff, EDLC_RCLR); /* Clear the interrupt */
-		return;
-	}
-
-        outb(0xff, EDLC_RCLR);  /* Clear the interrupt */
-
-	i_pkt_size = inw(IE_RCNT);
-	if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
-		PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
-			dev->name, i_pkt_size));
-		dev->stats.rx_errors++;
-		dev->stats.rx_length_errors++;
-		return;
-	}
-
-	/* Malloc up new buffer. */
-	skb = netdev_alloc_skb(dev, i_pkt_size + 3);
-	if (skb == NULL) {
-		printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-		dev->stats.rx_dropped++;
-		return;
-	}
-
-	skb_reserve(skb, 2);
-
-	/* Read packet into buffer */
-        outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
-	outw(0, IE_GP);	/* Seek to beginning of packet */
-	insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
-
-	if (NI5010_DEBUG >= 4)
-		dump_packet(skb->data, skb->len);
-
-	skb->protocol = eth_type_trans(skb,dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += i_pkt_size;
-
-	PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
-		dev->name, i_pkt_size));
-}
-
-static int process_xmt_interrupt(struct net_device *dev)
-{
-	struct ni5010_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	int xmit_stat;
-
-	PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name));
-
-	xmit_stat = inb(EDLC_XSTAT);
-	PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat));
-
-	outb(0, EDLC_XMASK);	/* Disable xmit IRQ's */
-	outb(0xff, EDLC_XCLR);	/* Clear all pending xmit IRQ's */
-
-	if (xmit_stat & XS_COLL){
-		PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
-			dev->name));
-		outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP);
-		/* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
-		outb(MM_EN_XMT | MM_MUX, IE_MMODE);
-		outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
-		dev->stats.collisions++;
-		return 1;
-	}
-
-	/* FIXME: handle other xmt error conditions */
-
-	dev->stats.tx_packets++;
-	dev->stats.tx_bytes += lp->o_pkt_size;
-	netif_wake_queue(dev);
-
-	PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
-		dev->name, lp->o_pkt_size));
-
-	return 0;
-}
-
-/* The inverse routine to ni5010_open(). */
-static int ni5010_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef JUMPERED_INTERRUPTS
-	free_irq(dev->irq, NULL);
-#endif
-	/* Put card in held-RESET state */
-	outb(0, IE_MMODE);
-	outb(RS_RESET, EDLC_RESET);
-
-	netif_stop_queue(dev);
-
-	PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
-	return 0;
-
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1      Promiscuous mode, receive all packets
-   num_addrs == 0       Normal mode, clear multicast list
-   num_addrs > 0        Multicast mode, receive normal and MC packets, and do
-                        best-effort filtering.
-*/
-static void ni5010_set_multicast_list(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-
-	PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
-
-	if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
-	    !netdev_mc_empty(dev)) {
-		outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
-		PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
-	} else {
-		PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
-		outb(RMD_BROADCAST, EDLC_RMODE);  /* Disable promiscuous mode, use normal mode */
-	}
-}
-
-static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
-{
-	struct ni5010_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-	unsigned int buf_offs;
-
-	PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name));
-
-        if (length > ETH_FRAME_LEN) {
-                PRINTK((KERN_WARNING "%s: packet too large, not possible\n",
-                        dev->name));
-                return;
-        }
-
-	if (NI5010_DEBUG) ni5010_show_registers(dev);
-
-	if (inb(IE_ISTAT) & IS_EN_XMT) {
-		PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
-			dev->name));
-		return;
-	}
-
-	if (NI5010_DEBUG > 3) dump_packet(buf, length);
-
-	buf_offs = NI5010_BUFSIZE - length - pad;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	lp->o_pkt_size = length + pad;
-
-	outb(0, EDLC_RMASK);	/* Mask all receive interrupts */
-	outb(0, IE_MMODE);	/* Put Xmit buffer on system bus */
-	outb(0xff, EDLC_RCLR);	/* Clear out pending rcv interrupts */
-
-	outw(buf_offs, IE_GP); /* Point GP at start of packet */
-	outsb(IE_XBUF, buf, length); /* Put data in buffer */
-	while(pad--)
-		outb(0, IE_XBUF);
-
-	outw(buf_offs, IE_GP); /* Rewrite where packet starts */
-
-	/* should work without that outb() (Crynwr used it) */
-	/*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */
-	outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */
-	outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */
-
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	netif_wake_queue(dev);
-
-	if (NI5010_DEBUG) ni5010_show_registers(dev);
-}
-
-static void chipset_init(struct net_device *dev, int startp)
-{
-	/* FIXME: Move some stuff here */
-	PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name));
-}
-
-static void ni5010_show_registers(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT)));
-	PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK)));
-	PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT)));
-	PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK)));
-	PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE)));
-	PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE)));
-	PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT)));
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni5010;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "ni5010 I/O base address");
-MODULE_PARM_DESC(irq, "ni5010 IRQ number");
-
-static int __init ni5010_init_module(void)
-{
-	PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
-	/*
-	if(io <= 0 || irq == 0){
-	   	printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname);
-		printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname);
-	   	return -EINVAL;
-	}
-	*/
-	if (io <= 0){
-		printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname);
-	}
-
-	PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io));
-	dev_ni5010 = ni5010_probe(-1);
-	if (IS_ERR(dev_ni5010))
-		return PTR_ERR(dev_ni5010);
-        return 0;
-}
-
-static void __exit ni5010_cleanup_module(void)
-{
-	PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
-	unregister_netdev(dev_ni5010);
-	release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
-	free_netdev(dev_ni5010);
-}
-module_init(ni5010_init_module);
-module_exit(ni5010_cleanup_module);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/racal/ni5010.h b/drivers/net/ethernet/racal/ni5010.h
deleted file mode 100644
index e10e717..0000000
--- a/drivers/net/ethernet/racal/ni5010.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Racal-Interlan ni5010 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl)
- *
- * I have done a look in the following sources:
- *   crynwr-packet-driver by Russ Nelson
- */
-
-#define NI5010_BUFSIZE	2048	/* number of bytes in a buffer */
-
-#define NI5010_MAGICVAL0 0x00  /* magic-values for ni5010 card */
-#define NI5010_MAGICVAL1 0x55
-#define NI5010_MAGICVAL2 0xAA
-
-#define SA_ADDR0 0x02
-#define SA_ADDR1 0x07
-#define SA_ADDR2 0x01
-
-/* The number of low I/O ports used by the ni5010 ethercard. */
-#define NI5010_IO_EXTENT       32
-
-#define PRINTK(x) if (NI5010_DEBUG) printk x
-#define PRINTK2(x) if (NI5010_DEBUG>=2) printk x
-#define PRINTK3(x) if (NI5010_DEBUG>=3) printk x
-
-/* The various IE command registers */
-#define EDLC_XSTAT	(ioaddr + 0x00)	/* EDLC transmit csr */
-#define EDLC_XCLR	(ioaddr + 0x00)	/* EDLC transmit "Clear IRQ" */
-#define EDLC_XMASK	(ioaddr + 0x01)	/* EDLC transmit "IRQ Masks" */
-#define EDLC_RSTAT	(ioaddr + 0x02)	/* EDLC receive csr */
-#define EDLC_RCLR	(ioaddr + 0x02)	/* EDLC receive "Clear IRQ" */
-#define EDLC_RMASK	(ioaddr + 0x03)	/* EDLC receive "IRQ Masks" */
-#define EDLC_XMODE	(ioaddr + 0x04)	/* EDLC transmit Mode */
-#define EDLC_RMODE	(ioaddr + 0x05)	/* EDLC receive Mode */
-#define EDLC_RESET	(ioaddr + 0x06)	/* EDLC RESET register */
-#define EDLC_TDR1	(ioaddr + 0x07)	/* "Time Domain Reflectometry" reg1 */
-#define EDLC_ADDR	(ioaddr + 0x08)	/* EDLC station address, 6 bytes */
-	 			/* 0x0E doesn't exist for r/w */
-#define EDLC_TDR2	(ioaddr + 0x0f)	/* "Time Domain Reflectometry" reg2 */
-#define IE_GP		(ioaddr + 0x10)	/* GP pointer (word register) */
-				/* 0x11 is 2nd byte of GP Pointer */
-#define IE_RCNT		(ioaddr + 0x10)	/* Count of bytes in rcv'd packet */
- 				/* 0x11 is 2nd byte of "Byte Count" */
-#define IE_MMODE	(ioaddr + 0x12)	/* Memory Mode register */
-#define IE_DMA_RST	(ioaddr + 0x13)	/* IE DMA Reset.  write only */
-#define IE_ISTAT	(ioaddr + 0x13)	/* IE Interrupt Status.  read only */
-#define IE_RBUF		(ioaddr + 0x14)	/* IE Receive Buffer port */
-#define IE_XBUF		(ioaddr + 0x15)	/* IE Transmit Buffer port */
-#define IE_SAPROM	(ioaddr + 0x16)	/* window on station addr prom */
-#define IE_RESET	(ioaddr + 0x17)	/* any write causes Board Reset */
-
-/* bits in EDLC_XSTAT, interrupt clear on write, status when read */
-#define XS_TPOK		0x80	/* transmit packet successful */
-#define XS_CS		0x40	/* carrier sense */
-#define XS_RCVD		0x20	/* transmitted packet received */
-#define XS_SHORT	0x10	/* transmission media is shorted */
-#define XS_UFLW		0x08	/* underflow.  iff failed board */
-#define XS_COLL		0x04	/* collision occurred */
-#define XS_16COLL	0x02	/* 16th collision occurred */
-#define XS_PERR		0x01	/* parity error */
-
-#define XS_CLR_UFLW	0x08	/* clear underflow */
-#define XS_CLR_COLL	0x04	/* clear collision */
-#define XS_CLR_16COLL	0x02	/* clear 16th collision */
-#define XS_CLR_PERR	0x01	/* clear parity error */
-
-/* bits in EDLC_XMASK, mask/enable transmit interrupts.  register is r/w */
-#define XM_TPOK		0x80	/* =1 to enable Xmt Pkt OK interrupts */
-#define XM_RCVD		0x20	/* =1 to enable Xmt Pkt Rcvd ints */
-#define XM_UFLW		0x08	/* =1 to enable Xmt Underflow ints */
-#define XM_COLL		0x04	/* =1 to enable Xmt Collision ints */
-#define XM_COLL16	0x02	/* =1 to enable Xmt 16th Coll ints */
-#define XM_PERR		0x01	/* =1 to enable Xmt Parity Error ints */
- 				/* note: always clear this bit */
-#define XM_ALL		(XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16)
-
-/* bits in EDLC_RSTAT, interrupt clear on write, status when read */
-#define RS_PKT_OK	0x80	/* received good packet */
-#define RS_RST_PKT	0x10	/* RESET packet received */
-#define RS_RUNT		0x08	/* Runt Pkt rcvd.  Len < 64 Bytes */
-#define RS_ALIGN	0x04	/* Alignment error. not 8 bit aligned */
-#define RS_CRC_ERR	0x02	/* Bad CRC on rcvd pkt */
-#define RS_OFLW		0x01	/* overflow for rcv FIFO */
-#define RS_VALID_BITS	( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW )
- 				/* all valid RSTAT bits */
-
-#define RS_CLR_PKT_OK	0x80	/* clear rcvd packet interrupt */
-#define RS_CLR_RST_PKT	0x10	/* clear RESET packet received */
-#define RS_CLR_RUNT	0x08	/* clear Runt Pckt received */
-#define RS_CLR_ALIGN	0x04	/* clear Alignment error */
-#define RS_CLR_CRC_ERR	0x02	/* clear CRC error */
-#define RS_CLR_OFLW	0x01	/* clear rcv FIFO Overflow */
-
-/* bits in EDLC_RMASK, mask/enable receive interrupts.  register is r/w */
-#define RM_PKT_OK	0x80	/* =1 to enable rcvd good packet ints */
-#define RM_RST_PKT	0x10	/* =1 to enable RESET packet ints */
-#define RM_RUNT		0x08	/* =1 to enable Runt Pkt rcvd ints */
-#define RM_ALIGN	0x04	/* =1 to enable Alignment error ints */
-#define RM_CRC_ERR	0x02	/* =1 to enable Bad CRC error ints */
-#define RM_OFLW		0x01	/* =1 to enable overflow error ints */
-
-/* bits in EDLC_RMODE, set Receive Packet mode.  register is r/w */
-#define RMD_TEST	0x80	/* =1 for Chip testing.  normally 0 */
-#define RMD_ADD_SIZ	0x10	/* =1 5-byte addr match.  normally 0 */
-#define RMD_EN_RUNT	0x08	/* =1 enable runt rcv.  normally 0 */
-#define RMD_EN_RST	0x04	/* =1 to rcv RESET pkt.  normally 0 */
-
-#define RMD_PROMISC	0x03	/* receive *all* packets.  unusual */
-#define RMD_MULTICAST	0x02	/* receive multicasts too.  unusual */
-#define RMD_BROADCAST	0x01	/* receive broadcasts & normal. usual */
-#define RMD_NO_PACKETS	0x00	/* don't receive any packets. unusual */
-
-/* bits in EDLC_XMODE, set Transmit Packet mode.  register is r/w */
-#define XMD_COLL_CNT	0xf0	/* coll's since success.  read-only */
-#define XMD_IG_PAR	0x08	/* =1 to ignore parity.  ALWAYS set */
-#define XMD_T_MODE	0x04	/* =1 to power xcvr. ALWAYS set this */
-#define XMD_LBC		0x02	/* =1 for loopbakc.  normally set */
-#define XMD_DIS_C	0x01	/* =1 disables contention. normally 0 */
-
-/* bits in EDLC_RESET, write only */
-#define RS_RESET	0x80	/* =1 to hold EDLC in reset state */
-
-/* bits in IE_MMODE, write only */
-#define MM_EN_DMA	0x80	/* =1 begin DMA xfer, Cplt clrs it */
-#define MM_EN_RCV	0x40	/* =1 allows Pkt rcv.  clr'd by rcv */
-#define MM_EN_XMT	0x20	/* =1 begin Xmt pkt.  Cplt clrs it */
-#define MM_BUS_PAGE	0x18	/* =00 ALWAYS.  Used when MUX=1 */
-#define MM_NET_PAGE	0x06	/* =00 ALWAYS.  Used when MUX=0 */
-#define MM_MUX		0x01	/* =1 means Rcv Buff on system bus */
-				/* =0 means Xmt Buff on system bus */
-
-/* bits in IE_ISTAT, read only */
-#define IS_TDIAG	0x80	/* =1 if Diagnostic problem */
-#define IS_EN_RCV	0x20	/* =1 until frame is rcv'd cplt */
-#define IS_EN_XMT	0x10	/* =1 until frame is xmt'd cplt */
-#define IS_EN_DMA	0x08	/* =1 until DMA is cplt or aborted */
-#define IS_DMA_INT	0x04	/* =0 iff DMA done interrupt. */
-#define IS_R_INT	0x02	/* =0 iff unmasked Rcv interrupt */
-#define IS_X_INT	0x01	/* =0 iff unmasked Xmt interrupt */
-
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index 63c1312..5b4103d 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -755,9 +755,6 @@
 	iowrite16(adrp[0], ioaddr + MID_0L);
 	iowrite16(adrp[1], ioaddr + MID_0M);
 	iowrite16(adrp[2], ioaddr + MID_0H);
-
-	/* Store MAC Address in perm_addr */
-	memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
 }
 
 static int r6040_open(struct net_device *dev)
@@ -957,9 +954,9 @@
 {
 	struct r6040_private *rp = netdev_priv(dev);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pci_name(rp->pdev));
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1045,7 +1042,7 @@
 	}
 
 	phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
-				0, PHY_INTERFACE_MODE_MII);
+			     PHY_INTERFACE_MODE_MII);
 
 	if (IS_ERR(phydev)) {
 		dev_err(&lp->pdev->dev, "could not attach to PHY\n");
@@ -1195,9 +1192,8 @@
 	lp->mii_bus->name = "r6040_eth_mii";
 	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
 		dev_name(&pdev->dev), card_idx);
-	lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	lp->mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
 	if (!lp->mii_bus->irq) {
-		dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
 		err = -ENOMEM;
 		goto err_out_mdio;
 	}
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 5ac9332..b62a324 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -1949,7 +1949,6 @@
 	for (i = 0; i < 3; i++)
 		((__le16 *) (dev->dev_addr))[i] =
 		    cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	dev->netdev_ops = &cp_netdev_ops;
 	netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index 5dc1616..1276ac7 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -991,7 +991,6 @@
 	for (i = 0; i < 3; i++)
 		((__le16 *) (dev->dev_addr))[i] =
 		    cpu_to_le16(read_eeprom (ioaddr, i + 7, addr_len));
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	/* The Rtl8139-specific entries in the device structure. */
 	dev->netdev_ops = &rtl8139_netdev_ops;
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 1170232..8900398 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -83,7 +83,7 @@
 #define R8169_REGS_SIZE		256
 #define R8169_NAPI_WEIGHT	64
 #define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
-#define NUM_RX_DESC	256	/* Number of Rx descriptor registers */
+#define NUM_RX_DESC	256U	/* Number of Rx descriptor registers */
 #define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
 #define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 
@@ -450,7 +450,6 @@
 #define PWM_EN				(1 << 22)
 #define RXDV_GATED_EN			(1 << 19)
 #define EARLY_TALLY_EN			(1 << 16)
-#define FORCE_CLK			(1 << 15) /* force clock request */
 };
 
 enum rtl_register_content {
@@ -514,7 +513,6 @@
 	PMEnable	= (1 << 0),	/* Power Management Enable */
 
 	/* Config2 register p. 25 */
-	ClkReqEn	= (1 << 7),	/* Clock Request Enable */
 	MSIEnable	= (1 << 5),	/* 8169 only. Reserved in the 8168. */
 	PCI_Clock_66MHz = 0x01,
 	PCI_Clock_33MHz = 0x00,
@@ -535,7 +533,6 @@
 	Spi_en		= (1 << 3),
 	LanWake		= (1 << 1),	/* LanWake enable/disable */
 	PMEStatus	= (1 << 0),	/* PME status can be reset by PCI RST# */
-	ASPM_en		= (1 << 0),	/* ASPM enable */
 
 	/* TBICSR p.28 */
 	TBIReset	= 0x80000000,
@@ -684,7 +681,6 @@
 	RTL_FEATURE_WOL		= (1 << 0),
 	RTL_FEATURE_MSI		= (1 << 1),
 	RTL_FEATURE_GMII	= (1 << 2),
-	RTL_FEATURE_FW_LOADED	= (1 << 3),
 };
 
 struct rtl8169_counters {
@@ -727,7 +723,6 @@
 	u16 mac_version;
 	u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
 	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
-	u32 dirty_rx;
 	u32 dirty_tx;
 	struct rtl8169_stats rx_stats;
 	struct rtl8169_stats tx_stats;
@@ -2389,10 +2384,8 @@
 	struct rtl_fw *rtl_fw = tp->rtl_fw;
 
 	/* TODO: release firmware once rtl_phy_write_fw signals failures. */
-	if (!IS_ERR_OR_NULL(rtl_fw)) {
+	if (!IS_ERR_OR_NULL(rtl_fw))
 		rtl_phy_write_fw(tp, rtl_fw);
-		tp->features |= RTL_FEATURE_FW_LOADED;
-	}
 }
 
 static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
@@ -2403,31 +2396,6 @@
 		rtl_apply_firmware(tp);
 }
 
-static void r810x_aldps_disable(struct rtl8169_private *tp)
-{
-	rtl_writephy(tp, 0x1f, 0x0000);
-	rtl_writephy(tp, 0x18, 0x0310);
-	msleep(100);
-}
-
-static void r810x_aldps_enable(struct rtl8169_private *tp)
-{
-	if (!(tp->features & RTL_FEATURE_FW_LOADED))
-		return;
-
-	rtl_writephy(tp, 0x1f, 0x0000);
-	rtl_writephy(tp, 0x18, 0x8310);
-}
-
-static void r8168_aldps_enable_1(struct rtl8169_private *tp)
-{
-	if (!(tp->features & RTL_FEATURE_FW_LOADED))
-		return;
-
-	rtl_writephy(tp, 0x1f, 0x0000);
-	rtl_w1w0_phy(tp, 0x15, 0x1000, 0x0000);
-}
-
 static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
 {
 	static const struct phy_reg phy_reg_init[] = {
@@ -3218,8 +3186,6 @@
 	rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
 	rtl_writephy(tp, 0x1f, 0x0000);
 
-	r8168_aldps_enable_1(tp);
-
 	/* Broken BIOS workaround: feed GigaMAC registers with MAC address. */
 	rtl_rar_exgmac_set(tp, tp->dev->dev_addr);
 }
@@ -3294,8 +3260,6 @@
 	rtl_writephy(tp, 0x05, 0x8b85);
 	rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
 	rtl_writephy(tp, 0x1f, 0x0000);
-
-	r8168_aldps_enable_1(tp);
 }
 
 static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
@@ -3303,8 +3267,6 @@
 	rtl_apply_firmware(tp);
 
 	rtl8168f_hw_phy_config(tp);
-
-	r8168_aldps_enable_1(tp);
 }
 
 static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
@@ -3402,8 +3364,6 @@
 	rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
 	rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
 	rtl_writephy(tp, 0x1f, 0x0000);
-
-	r8168_aldps_enable_1(tp);
 }
 
 static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
@@ -3489,19 +3449,21 @@
 	};
 
 	/* Disable ALDPS before ram code */
-	r810x_aldps_disable(tp);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_writephy(tp, 0x18, 0x0310);
+	msleep(100);
 
 	rtl_apply_firmware(tp);
 
 	rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
-
-	r810x_aldps_enable(tp);
 }
 
 static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
 {
 	/* Disable ALDPS before setting firmware */
-	r810x_aldps_disable(tp);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_writephy(tp, 0x18, 0x0310);
+	msleep(20);
 
 	rtl_apply_firmware(tp);
 
@@ -3511,8 +3473,6 @@
 	rtl_writephy(tp, 0x10, 0x401f);
 	rtl_writephy(tp, 0x19, 0x7030);
 	rtl_writephy(tp, 0x1f, 0x0000);
-
-	r810x_aldps_enable(tp);
 }
 
 static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
@@ -3525,7 +3485,9 @@
 	};
 
 	/* Disable ALDPS before ram code */
-	r810x_aldps_disable(tp);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_writephy(tp, 0x18, 0x0310);
+	msleep(100);
 
 	rtl_apply_firmware(tp);
 
@@ -3533,8 +3495,6 @@
 	rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
 
 	rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
-
-	r810x_aldps_enable(tp);
 }
 
 static void rtl_hw_phy_config(struct net_device *dev)
@@ -4175,7 +4135,7 @@
 
 static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
 {
-	tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
+	tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
 }
 
 static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
@@ -5051,6 +5011,8 @@
 
 	RTL_W8(MaxTxPacketSize, EarlySize);
 
+	rtl_disable_clock_request(pdev);
+
 	RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
 	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
 
@@ -5059,8 +5021,7 @@
 
 	RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
 	RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
-	RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en);
-	RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+	RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
 }
 
 static void rtl_hw_start_8168f(struct rtl8169_private *tp)
@@ -5085,12 +5046,13 @@
 
 	RTL_W8(MaxTxPacketSize, EarlySize);
 
+	rtl_disable_clock_request(pdev);
+
 	RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
 	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
 	RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
-	RTL_W32(MISC, RTL_R32(MISC) | PWM_EN | FORCE_CLK);
-	RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en);
-	RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+	RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
+	RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
 }
 
 static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
@@ -5147,10 +5109,8 @@
 	rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
 
 	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
-	RTL_W32(MISC, (RTL_R32(MISC) | FORCE_CLK) & ~RXDV_GATED_EN);
+	RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
 	RTL_W8(MaxTxPacketSize, EarlySize);
-	RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-	RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
 
 	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
 	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
@@ -5366,9 +5326,6 @@
 
 	RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
 	RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
-	RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-	RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
-	RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK);
 
 	rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
 }
@@ -5394,9 +5351,6 @@
 
 	RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
 	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
-	RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-	RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
-	RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK);
 
 	rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
 
@@ -5418,10 +5372,7 @@
 	/* Force LAN exit from ASPM if Rx/Tx are not idle */
 	RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
 
-	RTL_W32(MISC,
-		(RTL_R32(MISC) | DISABLE_LAN_EN | FORCE_CLK) & ~EARLY_TALLY_EN);
-	RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-	RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+	RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
 	RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
 	RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
 }
@@ -5918,7 +5869,7 @@
 		PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
 
 	/* The infamous DAC f*ckup only happens at boot time */
-	if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
+	if ((tp->cp_cmd & PCIDAC) && !tp->cur_rx) {
 		void __iomem *ioaddr = tp->mmio_addr;
 
 		netif_info(tp, intr, dev, "disabling PCI DAC\n");
@@ -6033,10 +5984,8 @@
 	unsigned int count;
 
 	cur_rx = tp->cur_rx;
-	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
-	rx_left = min(rx_left, budget);
 
-	for (; rx_left > 0; rx_left--, cur_rx++) {
+	for (rx_left = min(budget, NUM_RX_DESC); rx_left > 0; rx_left--, cur_rx++) {
 		unsigned int entry = cur_rx % NUM_RX_DESC;
 		struct RxDesc *desc = tp->RxDescArray + entry;
 		u32 status;
@@ -6114,8 +6063,6 @@
 	count = cur_rx - tp->cur_rx;
 	tp->cur_rx = cur_rx;
 
-	tp->dirty_rx += count;
-
 	return count;
 }
 
@@ -6939,7 +6886,6 @@
 	/* Get MAC address */
 	for (i = 0; i < ETH_ALEN; i++)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 3d70586..33e9617 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -891,18 +891,16 @@
 		mdp->rx_buf_sz += NET_IP_ALIGN;
 
 	/* Allocate RX and TX skb rings */
-	mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * mdp->num_rx_ring,
-				GFP_KERNEL);
+	mdp->rx_skbuff = kmalloc_array(mdp->num_rx_ring,
+				       sizeof(*mdp->rx_skbuff), GFP_KERNEL);
 	if (!mdp->rx_skbuff) {
-		dev_err(&ndev->dev, "Cannot allocate Rx skb\n");
 		ret = -ENOMEM;
 		return ret;
 	}
 
-	mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * mdp->num_tx_ring,
-				GFP_KERNEL);
+	mdp->tx_skbuff = kmalloc_array(mdp->num_tx_ring,
+				       sizeof(*mdp->tx_skbuff), GFP_KERNEL);
 	if (!mdp->tx_skbuff) {
-		dev_err(&ndev->dev, "Cannot allocate Tx skb\n");
 		ret = -ENOMEM;
 		goto skb_ring_free;
 	}
@@ -1422,7 +1420,7 @@
 
 	/* Try connect to PHY */
 	phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
-				0, mdp->phy_interface);
+			     mdp->phy_interface);
 	if (IS_ERR(phydev)) {
 		dev_err(&ndev->dev, "phy_connect failed\n");
 		return PTR_ERR(phydev);
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index 72fc57d..21683e2 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -795,7 +795,7 @@
 	struct phy_device *p = NULL;
 	while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
 		i++;
-	p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0,
+	p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link,
 			PHY_INTERFACE_MODE_RGMII);
 	if (IS_ERR(p)) {
 		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
diff --git a/drivers/net/ethernet/seeq/Kconfig b/drivers/net/ethernet/seeq/Kconfig
index 29f1853..a71e1ec 100644
--- a/drivers/net/ethernet/seeq/Kconfig
+++ b/drivers/net/ethernet/seeq/Kconfig
@@ -26,17 +26,6 @@
 	  If you have an Acorn system with one of these network cards, you
 	  should say Y to this option if you wish to use it with Linux.
 
-config SEEQ8005
-	tristate "SEEQ8005 support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	---help---
-	  This is a driver for the SEEQ 8005 network (Ethernet) card.  If this
-	  is for you, read the Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called seeq8005.
-
 config SGISEEQ
 	tristate "SGI Seeq ethernet controller support"
 	depends on SGI_HAS_SEEQ
diff --git a/drivers/net/ethernet/seeq/Makefile b/drivers/net/ethernet/seeq/Makefile
index 3e258a5..0488e99 100644
--- a/drivers/net/ethernet/seeq/Makefile
+++ b/drivers/net/ethernet/seeq/Makefile
@@ -3,5 +3,4 @@
 #
 
 obj-$(CONFIG_ARM_ETHER3) += ether3.o
-obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff --git a/drivers/net/ethernet/seeq/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c
deleted file mode 100644
index d6e50de..0000000
--- a/drivers/net/ethernet/seeq/seeq8005.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/* seeq8005.c: A network driver for linux. */
-/*
-	Based on skeleton.c,
-	Written 1993-94 by Donald Becker.
-	See the skeleton.c file for further copyright information.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as hamish@zot.apana.org.au
-
-	This file is a network device driver for the SEEQ 8005 chipset and
-	the Linux operating system.
-
-*/
-
-static const char version[] =
-	"seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n";
-
-/*
-  Sources:
-  	SEEQ 8005 databook
-
-  Version history:
-  	1.00	Public release. cosmetic changes (no warnings now)
-  	0.68	Turning per- packet,interrupt debug messages off - testing for release.
-  	0.67	timing problems/bad buffer reads seem to be fixed now
-  	0.63	*!@$ protocol=eth_type_trans -- now packets flow
-  	0.56	Send working
-  	0.48	Receive working
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "seeq8005.h"
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int seeq8005_portlist[] __initdata =
-   { 0x300, 0x320, 0x340, 0x360, 0};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	unsigned short receive_ptr;		/* What address in packet memory do we expect a recv_pkt_header? */
-	long open_time;				/* Useless example local info. */
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00
-#define SA_ADDR1 0x80
-#define SA_ADDR2 0x4b
-
-/* Index to functions, as function prototypes. */
-
-static int seeq8005_probe1(struct net_device *dev, int ioaddr);
-static int seeq8005_open(struct net_device *dev);
-static void seeq8005_timeout(struct net_device *dev);
-static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
-					struct net_device *dev);
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
-static void seeq8005_rx(struct net_device *dev);
-static int seeq8005_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/* Example routines you must write ;->. */
-#define tx_done(dev)	(inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
-static void hardware_send_packet(struct net_device *dev, char *buf, int length);
-extern void seeq8005_init(struct net_device *dev, int startp);
-static inline void wait_for_buffer(struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   */
-
-static int io = 0x320;
-static int irq = 10;
-
-struct net_device * __init seeq8005_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	unsigned *port;
-	int err = 0;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-		io = dev->base_addr;
-		irq = dev->irq;
-	}
-
-	if (io > 0x1ff) {	/* Check a single specified location. */
-		err = seeq8005_probe1(dev, io);
-	} else if (io != 0) {	/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (port = seeq8005_portlist; *port; port++) {
-			if (seeq8005_probe1(dev, *port) == 0)
-				break;
-		}
-		if (!*port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-	return dev;
-out1:
-	release_region(dev->base_addr, SEEQ8005_IO_EXTENT);
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-
-static const struct net_device_ops seeq8005_netdev_ops = {
-	.ndo_open		= seeq8005_open,
-	.ndo_stop		= seeq8005_close,
-	.ndo_start_xmit 	= seeq8005_send_packet,
-	.ndo_tx_timeout		= seeq8005_timeout,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_change_mtu		= eth_change_mtu,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/* This is the real probe routine.  Linux has a history of friendly device
-   probes on the ISA bus.  A good device probes avoids doing writes, and
-   verifies that the correct device exists and functions.  */
-
-static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
-{
-	static unsigned version_printed;
-	int i,j;
-	unsigned char SA_prom[32];
-	int old_cfg1;
-	int old_cfg2;
-	int old_stat;
-	int old_dmaar;
-	int old_rear;
-	int retval;
-
-	if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
-		return -ENODEV;
-
-	if (net_debug>1)
-		printk("seeq8005: probing at 0x%x\n",ioaddr);
-
-	old_stat = inw(SEEQ_STATUS);					/* read status register */
-	if (old_stat == 0xffff) {
-		retval = -ENODEV;
-		goto out;						/* assume that 0xffff == no device */
-	}
-	if ( (old_stat & 0x1800) != 0x1800 ) {				/* assume that unused bits are 1, as my manual says */
-		if (net_debug>1) {
-			printk("seeq8005: reserved stat bits != 0x1800\n");
-			printk("          == 0x%04x\n",old_stat);
-		}
-	 	retval = -ENODEV;
-		goto out;
-	}
-
-	old_rear = inw(SEEQ_REA);
-	if (old_rear == 0xffff) {
-		outw(0,SEEQ_REA);
-		if (inw(SEEQ_REA) == 0xffff) {				/* assume that 0xffff == no device */
-			retval = -ENODEV;
-			goto out;
-		}
-	} else if ((old_rear & 0xff00) != 0xff00) {			/* assume that unused bits are 1 */
-		if (net_debug>1) {
-			printk("seeq8005: unused rear bits != 0xff00\n");
-			printk("          == 0x%04x\n",old_rear);
-		}
-		retval = -ENODEV;
-		goto out;
-	}
-
-	old_cfg2 = inw(SEEQ_CFG2);					/* read CFG2 register */
-	old_cfg1 = inw(SEEQ_CFG1);
-	old_dmaar = inw(SEEQ_DMAAR);
-
-	if (net_debug>4) {
-		printk("seeq8005: stat = 0x%04x\n",old_stat);
-		printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
-		printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
-		printk("seeq8005: raer = 0x%04x\n",old_rear);
-		printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
-	}
-
-	outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);	/* setup for reading PROM */
-	outw( 0, SEEQ_DMAAR);						/* set starting PROM address */
-	outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1);				/* set buffer to look at PROM */
-
-
-	j=0;
-	for(i=0; i <32; i++) {
-		j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
-	}
-
-#if 0
-	/* untested because I only have the one card */
-	if ( (j&0xff) != 0 ) {						/* checksum appears to be 8bit = 0 */
-		if (net_debug>1) {					/* check this before deciding that we have a card */
-			printk("seeq8005: prom sum error\n");
-		}
-		outw( old_stat, SEEQ_STATUS);
-		outw( old_dmaar, SEEQ_DMAAR);
-		outw( old_cfg1, SEEQ_CFG1);
-		retval = -ENODEV;
-		goto out;
-	}
-#endif
-
-	outw( SEEQCFG2_RESET, SEEQ_CFG2);				/* reset the card */
-	udelay(5);
-	outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
-	if (net_debug) {
-		printk("seeq8005: prom sum = 0x%08x\n",j);
-		for(j=0; j<32; j+=16) {
-			printk("seeq8005: prom %02x: ",j);
-			for(i=0;i<16;i++) {
-				printk("%02x ",SA_prom[j|i]);
-			}
-			printk(" ");
-			for(i=0;i<16;i++) {
-				if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
-					printk("%c", SA_prom[j|i]);
-				} else {
-					printk(" ");
-				}
-			}
-			printk("\n");
-		}
-	}
-
-#if 0
-	/*
-	 * testing the packet buffer memory doesn't work yet
-	 * but all other buffer accesses do
-	 *			- fixing is not a priority
-	 */
-	if (net_debug>1) {					/* test packet buffer memory */
-		printk("seeq8005: testing packet buffer ... ");
-		outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
-		outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-		outw( 0 , SEEQ_DMAAR);
-		for(i=0;i<32768;i++) {
-			outw(0x5a5a, SEEQ_BUFFER);
-		}
-		j=jiffies+HZ;
-		while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
-			mb();
-		outw( 0 , SEEQ_DMAAR);
-		while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
-			mb();
-		if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
-			outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
-		outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-		j=0;
-		for(i=0;i<32768;i++) {
-			if (inw(SEEQ_BUFFER) != 0x5a5a)
-				j++;
-		}
-		if (j) {
-			printk("%i\n",j);
-		} else {
-			printk("ok.\n");
-		}
-	}
-#endif
-
-	if (net_debug  &&  version_printed++ == 0)
-		printk(version);
-
-	printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
-
-	/* Fill in the 'dev' fields. */
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	/* Retrieve and print the ethernet address. */
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = SA_prom[i+6];
-	printk("%pM", dev->dev_addr);
-
-	if (dev->irq == 0xff)
-		;			/* Do nothing: a user-level program will set it. */
-	else if (dev->irq < 2) {	/* "Auto-IRQ" */
-		unsigned long cookie = probe_irq_on();
-
-		outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
-
-		dev->irq = probe_irq_off(cookie);
-
-		if (net_debug >= 2)
-			printk(" autoirq is %d\n", dev->irq);
-	} else if (dev->irq == 2)
-	  /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
-	   * or don't know which one to set.
-	   */
-	  dev->irq = 9;
-
-#if 0
-	{
-		 int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
-		 if (irqval) {
-			 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
-					 dev->irq, irqval);
-			 retval = -EAGAIN;
-			 goto out;
-		 }
-	}
-#endif
-	dev->netdev_ops = &seeq8005_netdev_ops;
-	dev->watchdog_timeo	= HZ/20;
-	dev->flags &= ~IFF_MULTICAST;
-
-	return 0;
-out:
-	release_region(ioaddr, SEEQ8005_IO_EXTENT);
-	return retval;
-}
-
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-static int seeq8005_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	{
-		 int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
-		 if (irqval) {
-			 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
-					 dev->irq, irqval);
-			 return -EAGAIN;
-		 }
-	}
-
-	/* Reset the hardware here.  Don't forget to set the station address. */
-	seeq8005_init(dev, 1);
-
-	lp->open_time = jiffies;
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-static void seeq8005_timeout(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
-		   tx_done(dev) ? "IRQ conflict" : "network cable problem");
-	/* Try to restart the adaptor. */
-	seeq8005_init(dev, 1);
-	dev->trans_start = jiffies; /* prevent tx timeout */
-	netif_wake_queue(dev);
-}
-
-static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
-					struct net_device *dev)
-{
-	short length = skb->len;
-	unsigned char *buf;
-
-	if (length < ETH_ZLEN) {
-		if (skb_padto(skb, ETH_ZLEN))
-			return NETDEV_TX_OK;
-		length = ETH_ZLEN;
-	}
-	buf = skb->data;
-
-	/* Block a timer-based transmit from overlapping */
-	netif_stop_queue(dev);
-
-	hardware_send_packet(dev, buf, length);
-	dev->stats.tx_bytes += length;
-	dev_kfree_skb (skb);
-	/* You might need to clean up and record Tx statistics here. */
-
-	return NETDEV_TX_OK;
-}
-
-/*
- * wait_for_buffer
- *
- * This routine waits for the SEEQ chip to assert that the FIFO is ready
- * by checking for a window interrupt, and then clearing it. This has to
- * occur in the interrupt handler!
- */
-inline void wait_for_buffer(struct net_device * dev)
-{
-	int ioaddr = dev->base_addr;
-	unsigned long tmp;
-	int status;
-
-	tmp = jiffies + HZ;
-	while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
-		cpu_relax();
-
-	if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
-		outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr, status, boguscount = 0;
-	int handled = 0;
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	status = inw(SEEQ_STATUS);
-	do {
-		if (net_debug >2) {
-			printk("%s: int, status=0x%04x\n",dev->name,status);
-		}
-
-		if (status & SEEQSTAT_WINDOW_INT) {
-			handled = 1;
-			outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-			if (net_debug) {
-				printk("%s: window int!\n",dev->name);
-			}
-		}
-		if (status & SEEQSTAT_TX_INT) {
-			handled = 1;
-			outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-			dev->stats.tx_packets++;
-			netif_wake_queue(dev);	/* Inform upper layers. */
-		}
-		if (status & SEEQSTAT_RX_INT) {
-			handled = 1;
-			/* Got a packet(s). */
-			seeq8005_rx(dev);
-		}
-		status = inw(SEEQ_STATUS);
-	} while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
-
-	if(net_debug>2) {
-		printk("%s: eoi\n",dev->name);
-	}
-	return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void seeq8005_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int boguscount = 10;
-	int pkt_hdr;
-	int ioaddr = dev->base_addr;
-
-	do {
-		int next_packet;
-		int pkt_len;
-		int i;
-		int status;
-
-		status = inw(SEEQ_STATUS);
-	  	outw( lp->receive_ptr, SEEQ_DMAAR);
-		outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-	  	wait_for_buffer(dev);
-	  	next_packet = ntohs(inw(SEEQ_BUFFER));
-	  	pkt_hdr = inw(SEEQ_BUFFER);
-
-		if (net_debug>2) {
-			printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
-		}
-
-		if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) {	/* Read all the frames? */
-			return;							/* Done for now */
-		}
-
-		if ((pkt_hdr & SEEQPKTS_DONE)==0)
-			break;
-
-		if (next_packet < lp->receive_ptr) {
-			pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
-		} else {
-			pkt_len = next_packet - lp->receive_ptr - 4;
-		}
-
-		if (next_packet < ((DEFAULT_TEA+1)<<8)) {			/* is the next_packet address sane? */
-			printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
-			seeq8005_init(dev,1);
-			return;
-		}
-
-		lp->receive_ptr = next_packet;
-
-		if (net_debug>2) {
-			printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
-		}
-
-		if (pkt_hdr & SEEQPKTS_ANY_ERROR) {				/* There was an error. */
-			dev->stats.rx_errors++;
-			if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
-			if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
-			if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
-			if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
-			/* skip over this packet */
-			outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-			outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
-		} else {
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-			unsigned char *buf;
-
-			skb = netdev_alloc_skb(dev, pkt_len);
-			if (skb == NULL) {
-				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-				dev->stats.rx_dropped++;
-				break;
-			}
-			skb_reserve(skb, 2);	/* align data on 16 byte */
-			buf = skb_put(skb,pkt_len);
-
-			insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
-
-			if (net_debug>2) {
-				char * p = buf;
-				printk("%s: recv ",dev->name);
-				for(i=0;i<14;i++) {
-					printk("%02x ",*(p++)&0xff);
-				}
-				printk("\n");
-			}
-
-			skb->protocol=eth_type_trans(skb,dev);
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-			dev->stats.rx_bytes += pkt_len;
-		}
-	} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
-
-	/* If any worth-while packets have been received, netif_rx()
-	   has done a mark_bh(NET_BH) for us and will work on them
-	   when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to net_open(). */
-static int seeq8005_close(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	lp->open_time = 0;
-
-	netif_stop_queue(dev);
-
-	/* Flush the Tx and disable Rx here. */
-	outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
-	free_irq(dev->irq, dev);
-
-	/* Update the statistics here. */
-
-	return 0;
-
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   num_addrs == -1	Promiscuous mode, receive all packets
-   num_addrs == 0	Normal mode, clear multicast list
-   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
-			best-effort filtering.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-/*
- * I _could_ do up to 6 addresses here, but won't (yet?)
- */
-
-#if 0
-	int ioaddr = dev->base_addr;
-/*
- * hmm, not even sure if my matching works _anyway_ - seem to be receiving
- * _everything_ . . .
- */
-
-	if (num_addrs) {			/* Enable promiscuous mode */
-		outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL,  SEEQ_CFG1);
-		dev->flags|=IFF_PROMISC;
-	} else {				/* Disable promiscuous mode, use normal mode */
-		outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
-	}
-#endif
-}
-
-void seeq8005_init(struct net_device *dev, int startp)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	int i;
-
-	outw(SEEQCFG2_RESET, SEEQ_CFG2);	/* reset device */
-	udelay(5);
-
-	outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-	outw( 0, SEEQ_DMAAR);			/* load start address into both low and high byte */
-/*	wait_for_buffer(dev); */		/* I think that you only need a wait for memory buffer */
-	outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
-	for(i=0;i<6;i++) {			/* set Station address */
-		outb(dev->dev_addr[i], SEEQ_BUFFER);
-		udelay(2);
-	}
-
-	outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1);	/* set xmit end area pointer to 16K */
-	outb( DEFAULT_TEA, SEEQ_BUFFER);	/* this gives us 16K of send buffer and 48K of recv buffer */
-
-	lp->receive_ptr = (DEFAULT_TEA+1)<<8;	/* so we can find our packet_header */
-	outw( lp->receive_ptr, SEEQ_RPR);	/* Receive Pointer Register is set to recv buffer memory */
-
-	outw( 0x00ff, SEEQ_REA);		/* Receive Area End */
-
-	if (net_debug>4) {
-		printk("%s: SA0 = ",dev->name);
-
-		outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-		outw( 0, SEEQ_DMAAR);
-		outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
-		for(i=0;i<6;i++) {
-			printk("%02x ",inb(SEEQ_BUFFER));
-		}
-		printk("\n");
-	}
-
-	outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
-	outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
-	outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
-
-	if (net_debug>4) {
-		int old_cfg1;
-		old_cfg1 = inw(SEEQ_CFG1);
-		printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
-		printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
-		printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
-		printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
-		printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
-
-	}
-}
-
-
-static void hardware_send_packet(struct net_device * dev, char *buf, int length)
-{
-	int ioaddr = dev->base_addr;
-	int status = inw(SEEQ_STATUS);
-	int transmit_ptr = 0;
-	unsigned long tmp;
-
-	if (net_debug>4) {
-		printk("%s: send 0x%04x\n",dev->name,length);
-	}
-
-	/* Set FIFO to writemode and set packet-buffer address */
-	outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-	outw( transmit_ptr, SEEQ_DMAAR);
-
-	/* output SEEQ Packet header barfage */
-	outw( htons(length + 4), SEEQ_BUFFER);
-	outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
-
-	/* blat the buffer */
-	outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
-	/* paranoia !! */
-	outw( 0, SEEQ_BUFFER);
-	outw( 0, SEEQ_BUFFER);
-
-	/* set address of start of transmit chain */
-	outw( transmit_ptr, SEEQ_TPR);
-
-	/* drain FIFO */
-	tmp = jiffies;
-	while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
-		mb();
-
-	/* doit ! */
-	outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-
-}
-
-
-#ifdef MODULE
-
-static struct net_device *dev_seeq;
-MODULE_LICENSE("GPL");
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
-MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
-
-int __init init_module(void)
-{
-	dev_seeq = seeq8005_probe(-1);
-	return PTR_RET(dev_seeq);
-}
-
-void __exit cleanup_module(void)
-{
-	unregister_netdev(dev_seeq);
-	release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
-	free_netdev(dev_seeq);
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/seeq/seeq8005.h b/drivers/net/ethernet/seeq/seeq8005.h
deleted file mode 100644
index 5dfb009..0000000
--- a/drivers/net/ethernet/seeq/seeq8005.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * defines, etc for the seeq8005
- */
-
-/*
- * This file is distributed under GPL.
- *
- * This style and layout of this file is also copied
- * from many of the other linux network device drivers.
- */
-
-/* The number of low I/O ports used by the ethercard. */
-#define SEEQ8005_IO_EXTENT	16
-
-#define SEEQ_B		(ioaddr)
-
-#define	SEEQ_CMD	(SEEQ_B)		/* Write only */
-#define	SEEQ_STATUS	(SEEQ_B)		/* Read only */
-#define SEEQ_CFG1	(SEEQ_B + 2)
-#define SEEQ_CFG2	(SEEQ_B + 4)
-#define	SEEQ_REA	(SEEQ_B + 6)		/* Receive End Area Register */
-#define SEEQ_RPR	(SEEQ_B + 10)		/* Receive Pointer Register */
-#define	SEEQ_TPR	(SEEQ_B + 12)		/* Transmit Pointer Register */
-#define	SEEQ_DMAAR	(SEEQ_B + 14)		/* DMA Address Register */
-#define SEEQ_BUFFER	(SEEQ_B + 8)		/* Buffer Window Register */
-
-#define	DEFAULT_TEA	(0x3f)
-
-#define SEEQCMD_DMA_INT_EN	(0x0001)	/* DMA Interrupt Enable */
-#define SEEQCMD_RX_INT_EN	(0x0002)	/* Receive Interrupt Enable */
-#define SEEQCMD_TX_INT_EN	(0x0004)	/* Transmit Interrupt Enable */
-#define SEEQCMD_WINDOW_INT_EN	(0x0008)	/* What the hell is this for?? */
-#define SEEQCMD_INT_MASK	(0x000f)
-
-#define SEEQCMD_DMA_INT_ACK	(0x0010)	/* DMA ack */
-#define SEEQCMD_RX_INT_ACK	(0x0020)
-#define SEEQCMD_TX_INT_ACK	(0x0040)
-#define	SEEQCMD_WINDOW_INT_ACK	(0x0080)
-#define SEEQCMD_ACK_ALL		(0x00f0)
-
-#define SEEQCMD_SET_DMA_ON	(0x0100)	/* Enables DMA Request logic */
-#define SEEQCMD_SET_RX_ON	(0x0200)	/* Enables Packet RX */
-#define SEEQCMD_SET_TX_ON	(0x0400)	/* Starts TX run */
-#define SEEQCMD_SET_DMA_OFF	(0x0800)
-#define SEEQCMD_SET_RX_OFF	(0x1000)
-#define SEEQCMD_SET_TX_OFF	(0x2000)
-#define SEEQCMD_SET_ALL_OFF	(0x3800)	/* set all logic off */
-
-#define SEEQCMD_FIFO_READ	(0x4000)	/* Set FIFO to read mode (read from Buffer) */
-#define SEEQCMD_FIFO_WRITE	(0x8000)	/* Set FIFO to write mode */
-
-#define SEEQSTAT_DMA_INT_EN	(0x0001)	/* Status of interrupt enable */
-#define SEEQSTAT_RX_INT_EN	(0x0002)
-#define SEEQSTAT_TX_INT_EN	(0x0004)
-#define SEEQSTAT_WINDOW_INT_EN	(0x0008)
-
-#define	SEEQSTAT_DMA_INT	(0x0010)	/* Interrupt flagged */
-#define SEEQSTAT_RX_INT		(0x0020)
-#define SEEQSTAT_TX_INT		(0x0040)
-#define	SEEQSTAT_WINDOW_INT	(0x0080)
-#define SEEQSTAT_ANY_INT	(0x00f0)
-
-#define SEEQSTAT_DMA_ON		(0x0100)	/* DMA logic on */
-#define SEEQSTAT_RX_ON		(0x0200)	/* Packet RX on */
-#define SEEQSTAT_TX_ON		(0x0400)	/* TX running */
-
-#define SEEQSTAT_FIFO_FULL	(0x2000)
-#define SEEQSTAT_FIFO_EMPTY	(0x4000)
-#define SEEQSTAT_FIFO_DIR	(0x8000)	/* 1=read, 0=write */
-
-#define SEEQCFG1_BUFFER_MASK	(0x000f)	/* define what maps into the BUFFER register */
-#define SEEQCFG1_BUFFER_MAC0	(0x0000)	/* MAC station addresses 0-5 */
-#define SEEQCFG1_BUFFER_MAC1	(0x0001)
-#define SEEQCFG1_BUFFER_MAC2	(0x0002)
-#define SEEQCFG1_BUFFER_MAC3	(0x0003)
-#define SEEQCFG1_BUFFER_MAC4	(0x0004)
-#define SEEQCFG1_BUFFER_MAC5	(0x0005)
-#define SEEQCFG1_BUFFER_PROM	(0x0006)	/* The Address/CFG PROM */
-#define SEEQCFG1_BUFFER_TEA	(0x0007)	/* Transmit end area */
-#define SEEQCFG1_BUFFER_BUFFER	(0x0008)	/* Packet buffer memory */
-#define SEEQCFG1_BUFFER_INT_VEC	(0x0009)	/* Interrupt Vector */
-
-#define SEEQCFG1_DMA_INTVL_MASK	(0x0030)
-#define SEEQCFG1_DMA_CONT	(0x0000)
-#define SEEQCFG1_DMA_800ns	(0x0010)
-#define SEEQCFG1_DMA_1600ns	(0x0020)
-#define SEEQCFG1_DMA_3200ns	(0x0030)
-
-#define SEEQCFG1_DMA_LEN_MASK	(0x00c0)
-#define SEEQCFG1_DMA_LEN1	(0x0000)
-#define SEEQCFG1_DMA_LEN2	(0x0040)
-#define SEEQCFG1_DMA_LEN4	(0x0080)
-#define SEEQCFG1_DMA_LEN8	(0x00c0)
-
-#define SEEQCFG1_MAC_MASK	(0x3f00)	/* Dis/enable bits for MAC addresses */
-#define SEEQCFG1_MAC0_EN	(0x0100)
-#define SEEQCFG1_MAC1_EN	(0x0200)
-#define SEEQCFG1_MAC2_EN	(0x0400)
-#define SEEQCFG1_MAC3_EN	(0x0800)
-#define	SEEQCFG1_MAC4_EN	(0x1000)
-#define SEEQCFG1_MAC5_EN	(0x2000)
-
-#define	SEEQCFG1_MATCH_MASK	(0xc000)	/* Packet matching logic cfg bits */
-#define SEEQCFG1_MATCH_SPECIFIC	(0x0000)	/* only matching MAC addresses */
-#define SEEQCFG1_MATCH_BROAD	(0x4000)	/* matching and broadcast addresses */
-#define SEEQCFG1_MATCH_MULTI	(0x8000)	/* matching, broadcast and multicast */
-#define SEEQCFG1_MATCH_ALL	(0xc000)	/* Promiscuous mode */
-
-#define SEEQCFG1_DEFAULT	(SEEQCFG1_BUFFER_BUFFER | SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD)
-
-#define SEEQCFG2_BYTE_SWAP	(0x0001)	/* 0=Intel byte-order */
-#define SEEQCFG2_AUTO_REA	(0x0002)	/* if set, Receive End Area will be updated when reading from Buffer */
-
-#define SEEQCFG2_CRC_ERR_EN	(0x0008)	/* enables receiving of packets with CRC errors */
-#define SEEQCFG2_DRIBBLE_EN	(0x0010)	/* enables receiving of non-aligned packets */
-#define SEEQCFG2_SHORT_EN	(0x0020)	/* enables receiving of short packets */
-
-#define	SEEQCFG2_SLOTSEL	(0x0040)	/* 0= standard IEEE802.3, 1= smaller,faster, non-standard */
-#define SEEQCFG2_NO_PREAM	(0x0080)	/* 1= user supplies Xmit preamble bytes */
-#define SEEQCFG2_ADDR_LEN	(0x0100)	/* 1= 2byte addresses */
-#define SEEQCFG2_REC_CRC	(0x0200)	/* 0= received packets will have CRC stripped from them */
-#define SEEQCFG2_XMIT_NO_CRC	(0x0400)	/* don't xmit CRC with each packet (user supplies it) */
-#define SEEQCFG2_LOOPBACK	(0x0800)
-#define SEEQCFG2_CTRLO		(0x1000)
-#define SEEQCFG2_RESET		(0x8000)	/* software Hard-reset bit */
-
-struct seeq_pkt_hdr {
-	unsigned short	next;			/* address of next packet header */
-	unsigned char	babble_int:1,		/* enable int on >1514 byte packet */
-			coll_int:1,		/* enable int on collision */
-			coll_16_int:1,		/* enable int on >15 collision */
-			xmit_int:1,		/* enable int on success (or xmit with <15 collision) */
-			unused:1,
-			data_follows:1,		/* if not set, process this as a header and pointer only */
-			chain_cont:1,		/* if set, more headers in chain 		only cmd bit valid in recv header */
-			xmit_recv:1;		/* if set, a xmit packet, else a receive packet.*/
-	unsigned char	status;
-};
-
-#define SEEQPKTH_BAB_INT_EN	(0x01)		/* xmit only */
-#define SEEQPKTH_COL_INT_EN	(0x02)		/* xmit only */
-#define SEEQPKTH_COL16_INT_EN	(0x04)		/* xmit only */
-#define SEEQPKTH_XMIT_INT_EN	(0x08)		/* xmit only */
-#define SEEQPKTH_DATA_FOLLOWS	(0x20)		/* supposedly in xmit only */
-#define SEEQPKTH_CHAIN		(0x40)		/* more headers follow */
-#define SEEQPKTH_XMIT		(0x80)
-
-#define SEEQPKTS_BABBLE		(0x0100)	/* xmit only */
-#define SEEQPKTS_OVERSIZE	(0x0100)	/* recv only */
-#define SEEQPKTS_COLLISION	(0x0200)	/* xmit only */
-#define SEEQPKTS_CRC_ERR	(0x0200)	/* recv only */
-#define SEEQPKTS_COLL16		(0x0400)	/* xmit only */
-#define SEEQPKTS_DRIB		(0x0400)	/* recv only */
-#define SEEQPKTS_SHORT		(0x0800)	/* recv only */
-#define SEEQPKTS_DONE		(0x8000)
-#define SEEQPKTS_ANY_ERROR	(0x0f00)
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 0767043f..3f93624 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -1439,7 +1439,7 @@
 
 	delta = timespec_sub(*e_ts, time_now);
 
-	efx_phc_adjtime(ptp, timespec_to_ns(&delta));
+	rc = efx_phc_adjtime(ptp, timespec_to_ns(&delta));
 	if (rc != 0)
 		return rc;
 
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index dc171b4..7ed08c3 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -1565,9 +1565,9 @@
 {
 	struct ioc3_private *ip = netdev_priv(dev);
 
-        strcpy (info->driver, IOC3_NAME);
-        strcpy (info->version, IOC3_VERSION);
-        strcpy (info->bus_info, pci_name(ip->pdev));
+	strlcpy(info->driver, IOC3_NAME, sizeof(info->driver));
+	strlcpy(info->version, IOC3_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(ip->pdev), sizeof(info->bus_info));
 }
 
 static int ioc3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/silan/sc92031.c b/drivers/net/ethernet/silan/sc92031.c
index b231532..28f7268 100644
--- a/drivers/net/ethernet/silan/sc92031.c
+++ b/drivers/net/ethernet/silan/sc92031.c
@@ -1458,12 +1458,12 @@
 
 	mac0 = ioread32(port_base + MAC0);
 	mac1 = ioread32(port_base + MAC0 + 4);
-	dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
-	dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
-	dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
-	dev->dev_addr[3] = dev->perm_addr[3] = mac0;
-	dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
-	dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+	dev->dev_addr[0] = mac0 >> 24;
+	dev->dev_addr[1] = mac0 >> 16;
+	dev->dev_addr[2] = mac0 >> 8;
+	dev->dev_addr[3] = mac0;
+	dev->dev_addr[4] = mac1 >> 8;
+	dev->dev_addr[5] = mac1;
 
 	err = register_netdev(dev);
 	if (err < 0)
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 5bffd97..efca14e 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -247,8 +247,7 @@
  *	@net_dev: the net device to get address for
  *
  *	Older SiS900 and friends, use EEPROM to store MAC address.
- *	MAC address is read from read_eeprom() into @net_dev->dev_addr and
- *	@net_dev->perm_addr.
+ *	MAC address is read from read_eeprom() into @net_dev->dev_addr.
  */
 
 static int sis900_get_mac_addr(struct pci_dev *pci_dev,
@@ -271,9 +270,6 @@
 	for (i = 0; i < 3; i++)
 	        ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
 
-	/* Store MAC Address in perm_addr */
-	memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
 	return 1;
 }
 
@@ -284,8 +280,7 @@
  *
  *	SiS630E model, use APC CMOS RAM to store MAC address.
  *	APC CMOS RAM is accessed through ISA bridge.
- *	MAC address is read into @net_dev->dev_addr and
- *	@net_dev->perm_addr.
+ *	MAC address is read into @net_dev->dev_addr.
  */
 
 static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
@@ -311,9 +306,6 @@
 		((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
 	}
 
-	/* Store MAC Address in perm_addr */
-	memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
 	pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
 	pci_dev_put(isa_bridge);
 
@@ -328,7 +320,7 @@
  *
  *	SiS635 model, set MAC Reload Bit to load Mac address from APC
  *	to rfdr. rfdr is accessed through rfcr. MAC address is read into
- *	@net_dev->dev_addr and @net_dev->perm_addr.
+ *	@net_dev->dev_addr.
  */
 
 static int sis635_get_mac_addr(struct pci_dev *pci_dev,
@@ -353,9 +345,6 @@
 		*( ((u16 *)net_dev->dev_addr) + i) = sr16(rfdr);
 	}
 
-	/* Store MAC Address in perm_addr */
-	memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
 	/* enable packet filtering */
 	sw32(rfcr, rfcrSave | RFEN);
 
@@ -375,7 +364,7 @@
  *	EEDONE signal to refuse EEPROM access by LAN.
  *	The EEPROM map of SiS962 or SiS963 is different to SiS900.
  *	The signature field in SiS962 or SiS963 spec is meaningless.
- *	MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr.
+ *	MAC address is read into @net_dev->dev_addr.
  */
 
 static int sis96x_get_mac_addr(struct pci_dev *pci_dev,
@@ -395,9 +384,6 @@
 			for (i = 0; i < 3; i++)
 			        mac[i] = read_eeprom(ioaddr, i + EEPROMMACAddr);
 
-			/* Store MAC Address in perm_addr */
-			memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
 			rc = 1;
 			break;
 		}
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index 59a6f88..9dd842d 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -1522,9 +1522,10 @@
 static void
 smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, CARDNAME, sizeof(info->driver));
-	strncpy(info->version, version, sizeof(info->version));
-	strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+	strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+	strlcpy(info->version, version, sizeof(info->version));
+	strlcpy(info->bus_info, dev_name(dev->dev.parent),
+		sizeof(info->bus_info));
 }
 
 static int smc911x_ethtool_nwayreset(struct net_device *dev)
@@ -2035,7 +2036,7 @@
 	struct net_device *ndev;
 	struct resource *res;
 	struct smc911x_local *lp;
-	unsigned int *addr;
+	void __iomem *addr;
 	int ret;
 
 	DBG(SMC_DEBUG_FUNC, "--> %s\n",  __func__);
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index a670d23..591650a 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -1597,9 +1597,10 @@
 static void
 smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, CARDNAME, sizeof(info->driver));
-	strncpy(info->version, version, sizeof(info->version));
-	strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+	strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+	strlcpy(info->version, version, sizeof(info->version));
+	strlcpy(info->bus_info, dev_name(dev->dev.parent),
+		sizeof(info->bus_info));
 }
 
 static int smc_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index e112877..da5cc9a 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -997,9 +997,8 @@
 	SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X",
 		   phydev->addr, phydev->phy_id);
 
-	ret = phy_connect_direct(dev, phydev,
-			&smsc911x_phy_adjust_link, 0,
-			pdata->config.phy_interface);
+	ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link,
+				 pdata->config.phy_interface);
 
 	if (ret) {
 		netdev_err(dev, "Could not attach to PHY\n");
@@ -1831,7 +1830,6 @@
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 
 	spin_lock_irq(&pdata->mac_lock);
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index 3c58658..d457fa2 100644
--- a/drivers/net/ethernet/smsc/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -1179,7 +1179,7 @@
 		phydev->phy_id);
 
 	phydev = phy_connect(dev, dev_name(&phydev->dev),
-		smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+			     smsc9420_phy_adjust_link, PHY_INTERFACE_MODE_MII);
 
 	if (IS_ERR(phydev)) {
 		pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -1250,12 +1250,11 @@
 
 	BUG_ON(!pd->tx_ring);
 
-	pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
-		TX_RING_SIZE), GFP_KERNEL);
-	if (!pd->tx_buffers) {
-		smsc_warn(IFUP, "Failed to allocated tx_buffers");
+	pd->tx_buffers = kmalloc_array(TX_RING_SIZE,
+				       sizeof(struct smsc9420_ring_info),
+				       GFP_KERNEL);
+	if (!pd->tx_buffers)
 		return -ENOMEM;
-	}
 
 	/* Initialize the TX Ring */
 	for (i = 0; i < TX_RING_SIZE; i++) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 1372ce2..d1ac39c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -210,8 +210,7 @@
 		strlcpy(info->driver, MAC100_ETHTOOL_NAME,
 			sizeof(info->driver));
 
-	strcpy(info->version, DRV_MODULE_VERSION);
-	info->fw_version[0] = '\0';
+	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static int stmmac_ethtool_getsettings(struct net_device *dev,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index f07c061..39c6c55 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -69,7 +69,7 @@
 
 #undef STMMAC_XMIT_DEBUG
 /*#define STMMAC_XMIT_DEBUG*/
-#ifdef STMMAC_TX_DEBUG
+#ifdef STMMAC_XMIT_DEBUG
 #define TX_DBG(fmt, args...)  printk(fmt, ## args)
 #else
 #define TX_DBG(fmt, args...)  do { } while (0)
@@ -428,8 +428,7 @@
 		 priv->plat->phy_addr);
 	pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id_fmt);
 
-	phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, 0,
-			     interface);
+	phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface);
 
 	if (IS_ERR(phydev)) {
 		pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -531,17 +530,18 @@
 	DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
 	    txsize, rxsize, bfsize);
 
-	priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
-	priv->rx_skbuff =
-	    kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
+	priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
+					    GFP_KERNEL);
+	priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
+					GFP_KERNEL);
 	priv->dma_rx =
 	    (struct dma_desc *)dma_alloc_coherent(priv->device,
 						  rxsize *
 						  sizeof(struct dma_desc),
 						  &priv->dma_rx_phy,
 						  GFP_KERNEL);
-	priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
-				       GFP_KERNEL);
+	priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
+					GFP_KERNEL);
 	priv->dma_tx =
 	    (struct dma_desc *)dma_alloc_coherent(priv->device,
 						  txsize *
@@ -2254,7 +2254,7 @@
 		} else if (!strncmp(opt, "pause:", 6)) {
 			if (kstrtoint(opt + 6, 0, &pause))
 				goto err;
-		} else if (!strncmp(opt, "eee_timer:", 6)) {
+		} else if (!strncmp(opt, "eee_timer:", 10)) {
 			if (kstrtoint(opt + 10, 0, &eee_timer))
 				goto err;
 		}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 0376a5e..0b9829f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -188,8 +188,6 @@
 		goto bus_register_fail;
 	}
 
-	priv->mii = new_bus;
-
 	found = 0;
 	for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
 		struct phy_device *phydev = new_bus->phy_map[addr];
@@ -237,8 +235,14 @@
 		}
 	}
 
-	if (!found)
+	if (!found) {
 		pr_warning("%s: No PHY found\n", ndev->name);
+		mdiobus_unregister(new_bus);
+		mdiobus_free(new_bus);
+		return -ENODEV;
+	}
+
+	priv->mii = new_bus;
 
 	return 0;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 064eaac..19b3a25 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -102,6 +102,7 @@
 	priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
 	if (!priv) {
 		pr_err("%s: main driver probe failed", __func__);
+		ret = -ENODEV;
 		goto err_out;
 	}
 	priv->dev->irq = pdev->irq;
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index a0bdf07..e4c1c88 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -4342,7 +4342,7 @@
 {
 	BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64);
 
-	rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *),
+	rp->rxhash = kcalloc(MAX_RBR_RING_SIZE, sizeof(struct page *),
 			     GFP_KERNEL);
 	if (!rp->rxhash)
 		return -ENOMEM;
@@ -8366,14 +8366,12 @@
 		return;
 	}
 
-	memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
+	memcpy(dev->dev_addr, vpd->local_mac, ETH_ALEN);
 
-	val8 = dev->perm_addr[5];
-	dev->perm_addr[5] += np->port;
-	if (dev->perm_addr[5] < val8)
-		dev->perm_addr[4]++;
-
-	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+	val8 = dev->dev_addr[5];
+	dev->dev_addr[5] += np->port;
+	if (dev->dev_addr[5] < val8)
+		dev->dev_addr[4]++;
 }
 
 static int niu_pci_probe_sprom(struct niu *np)
@@ -8470,29 +8468,27 @@
 	val = nr64(ESPC_MAC_ADDR0);
 	netif_printk(np, probe, KERN_DEBUG, np->dev,
 		     "SPROM: MAC_ADDR0[%08llx]\n", (unsigned long long)val);
-	dev->perm_addr[0] = (val >>  0) & 0xff;
-	dev->perm_addr[1] = (val >>  8) & 0xff;
-	dev->perm_addr[2] = (val >> 16) & 0xff;
-	dev->perm_addr[3] = (val >> 24) & 0xff;
+	dev->dev_addr[0] = (val >>  0) & 0xff;
+	dev->dev_addr[1] = (val >>  8) & 0xff;
+	dev->dev_addr[2] = (val >> 16) & 0xff;
+	dev->dev_addr[3] = (val >> 24) & 0xff;
 
 	val = nr64(ESPC_MAC_ADDR1);
 	netif_printk(np, probe, KERN_DEBUG, np->dev,
 		     "SPROM: MAC_ADDR1[%08llx]\n", (unsigned long long)val);
-	dev->perm_addr[4] = (val >>  0) & 0xff;
-	dev->perm_addr[5] = (val >>  8) & 0xff;
+	dev->dev_addr[4] = (val >>  0) & 0xff;
+	dev->dev_addr[5] = (val >>  8) & 0xff;
 
-	if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+	if (!is_valid_ether_addr(&dev->dev_addr[0])) {
 		dev_err(np->device, "SPROM MAC address invalid [ %pM ]\n",
-			dev->perm_addr);
+			dev->dev_addr);
 		return -EINVAL;
 	}
 
-	val8 = dev->perm_addr[5];
-	dev->perm_addr[5] += np->port;
-	if (dev->perm_addr[5] < val8)
-		dev->perm_addr[4]++;
-
-	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+	val8 = dev->dev_addr[5];
+	dev->dev_addr[5] += np->port;
+	if (dev->dev_addr[5] < val8)
+		dev->dev_addr[4]++;
 
 	val = nr64(ESPC_MOD_STR_LEN);
 	netif_printk(np, probe, KERN_DEBUG, np->dev,
@@ -9267,16 +9263,14 @@
 		netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n",
 			   dp->full_name, prop_len);
 	}
-	memcpy(dev->perm_addr, mac_addr, dev->addr_len);
-	if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+	memcpy(dev->dev_addr, mac_addr, dev->addr_len);
+	if (!is_valid_ether_addr(&dev->dev_addr[0])) {
 		netdev_err(dev, "%s: OF MAC address is invalid\n",
 			   dp->full_name);
-		netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->perm_addr);
+		netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->dev_addr);
 		return -EINVAL;
 	}
 
-	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
-
 	model = of_get_property(dp, "model", &prop_len);
 
 	if (model)
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index be82f6d..5fafca0 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -1042,8 +1042,8 @@
 /* Ethtool support... */
 static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, "sunbmac");
-	strcpy(info->version, "2.0");
+	strlcpy(info->driver, "sunbmac", sizeof(info->driver));
+	strlcpy(info->version, "2.0", sizeof(info->version));
 }
 
 static u32 bigmac_get_link(struct net_device *dev)
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 1dcee69..49bf3e2 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -685,13 +685,14 @@
 	struct sunqe *qep = netdev_priv(dev);
 	struct platform_device *op;
 
-	strcpy(info->driver, "sunqe");
-	strcpy(info->version, "3.0");
+	strlcpy(info->driver, "sunqe", sizeof(info->driver));
+	strlcpy(info->version, "3.0", sizeof(info->version));
 
 	op = qep->op;
 	regs = of_get_property(op->dev.of_node, "reg", NULL);
 	if (regs)
-		sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+		snprintf(info->bus_info, sizeof(info->bus_info), "SBUS:%d",
+			 regs->which_io);
 
 }
 
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index e1b8955..289b4ee 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -882,8 +882,8 @@
 static void vnet_get_drvinfo(struct net_device *dev,
 			     struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, DRV_MODULE_NAME);
-	strcpy(info->version, DRV_MODULE_VERSION);
+	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 }
 
 static u32 vnet_get_msglevel(struct net_device *dev)
@@ -1032,8 +1032,6 @@
 	for (i = 0; i < ETH_ALEN; i++)
 		dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
 
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
 	vp = netdev_priv(dev);
 
 	spin_lock_init(&vp->lock);
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 1e4d743..e15cc71 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -2179,10 +2179,10 @@
 {
 	struct bdx_priv *priv = netdev_priv(netdev);
 
-	strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
-	strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
-	strlcat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
-	strlcat(drvinfo->bus_info, pci_name(priv->pdev),
+	strlcpy(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
+	strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+	strlcpy(drvinfo->bus_info, pci_name(priv->pdev),
 		sizeof(drvinfo->bus_info));
 
 	drvinfo->n_stats = ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c
index d9625f6..31bbbca 100644
--- a/drivers/net/ethernet/ti/cpmac.c
+++ b/drivers/net/ethernet/ti/cpmac.c
@@ -904,10 +904,9 @@
 static void cpmac_get_drvinfo(struct net_device *dev,
 			      struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, "cpmac");
-	strcpy(info->version, CPMAC_VERSION);
-	info->fw_version[0] = '\0';
-	sprintf(info->bus_info, "%s", "cpmac");
+	strlcpy(info->driver, "cpmac", sizeof(info->driver));
+	strlcpy(info->version, CPMAC_VERSION, sizeof(info->version));
+	snprintf(info->bus_info, sizeof(info->bus_info), "%s", "cpmac");
 	info->regdump_len = 0;
 }
 
@@ -1173,8 +1172,8 @@
 	snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT,
 						mdio_bus_id, phy_id);
 
-	priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, 0,
-						PHY_INTERFACE_MODE_MII);
+	priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link,
+				PHY_INTERFACE_MODE_MII);
 
 	if (IS_ERR(priv->phy)) {
 		if (netif_msg_drv(priv))
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 40aff68..7e93df6 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -32,6 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_net.h>
 #include <linux/of_device.h>
+#include <linux/if_vlan.h>
 
 #include <linux/platform_data/cpsw.h>
 
@@ -118,6 +119,13 @@
 #define TX_PRIORITY_MAPPING	0x33221100
 #define CPDMA_TX_PRIORITY_MAP	0x76543210
 
+#define CPSW_VLAN_AWARE		BIT(1)
+#define CPSW_ALE_VLAN_AWARE	1
+
+#define CPSW_FIFO_NORMAL_MODE		(0 << 15)
+#define CPSW_FIFO_DUAL_MAC_MODE		(1 << 15)
+#define CPSW_FIFO_RATE_LIMIT_MODE	(2 << 15)
+
 #define cpsw_enable_irq(priv)	\
 	do {			\
 		u32 i;		\
@@ -250,7 +258,7 @@
 struct cpsw_host_regs {
 	u32	max_blks;
 	u32	blk_cnt;
-	u32	flow_thresh;
+	u32	tx_in_ctl;
 	u32	port_vlan;
 	u32	tx_pri_map;
 	u32	cpdma_tx_pri_map;
@@ -277,6 +285,9 @@
 	u32				mac_control;
 	struct cpsw_slave_data		*data;
 	struct phy_device		*phy;
+	struct net_device		*ndev;
+	u32				port_vlan;
+	u32				open_stat;
 };
 
 static inline u32 slave_read(struct cpsw_slave *slave, u32 offset)
@@ -315,16 +326,64 @@
 	/* snapshot of IRQ numbers */
 	u32 irqs_table[4];
 	u32 num_irqs;
-	struct cpts cpts;
+	struct cpts *cpts;
+	u32 emac_port;
 };
 
 #define napi_to_priv(napi)	container_of(napi, struct cpsw_priv, napi)
-#define for_each_slave(priv, func, arg...)			\
-	do {							\
-		int idx;					\
-		for (idx = 0; idx < (priv)->data.slaves; idx++)	\
-			(func)((priv)->slaves + idx, ##arg);	\
+#define for_each_slave(priv, func, arg...)				\
+	do {								\
+		int idx;						\
+		if (priv->data.dual_emac)				\
+			(func)((priv)->slaves + priv->emac_port, ##arg);\
+		else							\
+			for (idx = 0; idx < (priv)->data.slaves; idx++)	\
+				(func)((priv)->slaves + idx, ##arg);	\
 	} while (0)
+#define cpsw_get_slave_ndev(priv, __slave_no__)				\
+	(priv->slaves[__slave_no__].ndev)
+#define cpsw_get_slave_priv(priv, __slave_no__)				\
+	((priv->slaves[__slave_no__].ndev) ?				\
+		netdev_priv(priv->slaves[__slave_no__].ndev) : NULL)	\
+
+#define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb)		\
+	do {								\
+		if (!priv->data.dual_emac)				\
+			break;						\
+		if (CPDMA_RX_SOURCE_PORT(status) == 1) {		\
+			ndev = cpsw_get_slave_ndev(priv, 0);		\
+			priv = netdev_priv(ndev);			\
+			skb->dev = ndev;				\
+		} else if (CPDMA_RX_SOURCE_PORT(status) == 2) {		\
+			ndev = cpsw_get_slave_ndev(priv, 1);		\
+			priv = netdev_priv(ndev);			\
+			skb->dev = ndev;				\
+		}							\
+	} while (0)
+#define cpsw_add_mcast(priv, addr)					\
+	do {								\
+		if (priv->data.dual_emac) {				\
+			struct cpsw_slave *slave = priv->slaves +	\
+						priv->emac_port;	\
+			int slave_port = cpsw_get_slave_port(priv,	\
+						slave->slave_num);	\
+			cpsw_ale_add_mcast(priv->ale, addr,		\
+				1 << slave_port | 1 << priv->host_port,	\
+				ALE_VLAN, slave->port_vlan, 0);		\
+		} else {						\
+			cpsw_ale_add_mcast(priv->ale, addr,		\
+				ALE_ALL_PORTS << priv->host_port,	\
+				0, 0, 0);				\
+		}							\
+	} while (0)
+
+static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
+{
+	if (priv->host_port == 0)
+		return slave_num + 1;
+	else
+		return slave_num;
+}
 
 static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 {
@@ -344,8 +403,7 @@
 
 		/* program multicast address list into ALE register */
 		netdev_for_each_mc_addr(ha, ndev) {
-			cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
-				ALE_ALL_PORTS << priv->host_port, 0, 0);
+			cpsw_add_mcast(priv, (u8 *)ha->addr);
 		}
 	}
 }
@@ -374,9 +432,12 @@
 	struct net_device	*ndev = skb->dev;
 	struct cpsw_priv	*priv = netdev_priv(ndev);
 
+	/* Check whether the queue is stopped due to stalled tx dma, if the
+	 * queue is stopped then start the queue as we have free desc for tx
+	 */
 	if (unlikely(netif_queue_stopped(ndev)))
 		netif_start_queue(ndev);
-	cpts_tx_timestamp(&priv->cpts, skb);
+	cpts_tx_timestamp(priv->cpts, skb);
 	priv->stats.tx_packets++;
 	priv->stats.tx_bytes += len;
 	dev_kfree_skb_any(skb);
@@ -389,6 +450,8 @@
 	struct cpsw_priv	*priv = netdev_priv(ndev);
 	int			ret = 0;
 
+	cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
+
 	/* free and bail if we are shutting down */
 	if (unlikely(!netif_running(ndev)) ||
 			unlikely(!netif_carrier_ok(ndev))) {
@@ -397,7 +460,7 @@
 	}
 	if (likely(status >= 0)) {
 		skb_put(skb, len);
-		cpts_rx_timestamp(&priv->cpts, skb);
+		cpts_rx_timestamp(priv->cpts, skb);
 		skb->protocol = eth_type_trans(skb, ndev);
 		netif_receive_skb(skb);
 		priv->stats.rx_bytes += len;
@@ -417,7 +480,7 @@
 			return;
 
 		ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
-					skb_tailroom(skb), GFP_KERNEL);
+					skb_tailroom(skb), 0, GFP_KERNEL);
 	}
 	WARN_ON(ret < 0);
 }
@@ -430,37 +493,38 @@
 		cpsw_intr_disable(priv);
 		cpsw_disable_irq(priv);
 		napi_schedule(&priv->napi);
+	} else {
+		priv = cpsw_get_slave_priv(priv, 1);
+		if (likely(priv) && likely(netif_running(priv->ndev))) {
+			cpsw_intr_disable(priv);
+			cpsw_disable_irq(priv);
+			napi_schedule(&priv->napi);
+		}
 	}
 	return IRQ_HANDLED;
 }
 
-static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
-{
-	if (priv->host_port == 0)
-		return slave_num + 1;
-	else
-		return slave_num;
-}
-
 static int cpsw_poll(struct napi_struct *napi, int budget)
 {
 	struct cpsw_priv	*priv = napi_to_priv(napi);
 	int			num_tx, num_rx;
 
 	num_tx = cpdma_chan_process(priv->txch, 128);
+	if (num_tx)
+		cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
 	num_rx = cpdma_chan_process(priv->rxch, budget);
+	if (num_rx < budget) {
+		napi_complete(napi);
+		cpsw_intr_enable(priv);
+		cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+		cpsw_enable_irq(priv);
+	}
 
 	if (num_rx || num_tx)
 		cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
 			 num_rx, num_tx);
 
-	if (num_rx < budget) {
-		napi_complete(napi);
-		cpsw_intr_enable(priv);
-		cpdma_ctlr_eoi(priv->dma);
-		cpsw_enable_irq(priv);
-	}
-
 	return num_rx;
 }
 
@@ -559,6 +623,54 @@
 				leader + strlen(name), val);
 }
 
+static int cpsw_common_res_usage_state(struct cpsw_priv *priv)
+{
+	u32 i;
+	u32 usage_count = 0;
+
+	if (!priv->data.dual_emac)
+		return 0;
+
+	for (i = 0; i < priv->data.slaves; i++)
+		if (priv->slaves[i].open_stat)
+			usage_count++;
+
+	return usage_count;
+}
+
+static inline int cpsw_tx_packet_submit(struct net_device *ndev,
+			struct cpsw_priv *priv, struct sk_buff *skb)
+{
+	if (!priv->data.dual_emac)
+		return cpdma_chan_submit(priv->txch, skb, skb->data,
+				  skb->len, 0, GFP_KERNEL);
+
+	if (ndev == cpsw_get_slave_ndev(priv, 0))
+		return cpdma_chan_submit(priv->txch, skb, skb->data,
+				  skb->len, 1, GFP_KERNEL);
+	else
+		return cpdma_chan_submit(priv->txch, skb, skb->data,
+				  skb->len, 2, GFP_KERNEL);
+}
+
+static inline void cpsw_add_dual_emac_def_ale_entries(
+		struct cpsw_priv *priv, struct cpsw_slave *slave,
+		u32 slave_port)
+{
+	u32 port_mask = 1 << slave_port | 1 << priv->host_port;
+
+	if (priv->version == CPSW_VERSION_1)
+		slave_write(slave, slave->port_vlan, CPSW1_PORT_VLAN);
+	else
+		slave_write(slave, slave->port_vlan, CPSW2_PORT_VLAN);
+	cpsw_ale_add_vlan(priv->ale, slave->port_vlan, port_mask,
+			  port_mask, port_mask, 0);
+	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+			   port_mask, ALE_VLAN, slave->port_vlan, 0);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+		priv->host_port, ALE_VLAN, slave->port_vlan);
+}
+
 static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 {
 	char name[32];
@@ -588,11 +700,14 @@
 
 	slave_port = cpsw_get_slave_port(priv, slave->slave_num);
 
-	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << slave_port, 0, ALE_MCAST_FWD_2);
+	if (priv->data.dual_emac)
+		cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port);
+	else
+		cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+				   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
 	slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
-				 &cpsw_adjust_link, 0, slave->data->phy_if);
+				 &cpsw_adjust_link, slave->data->phy_if);
 	if (IS_ERR(slave->phy)) {
 		dev_err(priv->dev, "phy %s not found on slave %d\n",
 			slave->data->phy_id, slave->slave_num);
@@ -604,14 +719,44 @@
 	}
 }
 
+static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
+{
+	const int vlan = priv->data.default_vlan;
+	const int port = priv->host_port;
+	u32 reg;
+	int i;
+
+	reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
+	       CPSW2_PORT_VLAN;
+
+	writel(vlan, &priv->host_port_regs->port_vlan);
+
+	for (i = 0; i < 2; i++)
+		slave_write(priv->slaves + i, vlan, reg);
+
+	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
+			  ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
+			  (ALE_PORT_1 | ALE_PORT_2) << port);
+}
+
 static void cpsw_init_host_port(struct cpsw_priv *priv)
 {
+	u32 control_reg;
+	u32 fifo_mode;
+
 	/* soft reset the controller and initialize ale */
 	soft_reset("cpsw", &priv->regs->soft_reset);
 	cpsw_ale_start(priv->ale);
 
 	/* switch to vlan unaware mode */
-	cpsw_ale_control_set(priv->ale, 0, ALE_VLAN_AWARE, 0);
+	cpsw_ale_control_set(priv->ale, priv->host_port, ALE_VLAN_AWARE,
+			     CPSW_ALE_VLAN_AWARE);
+	control_reg = readl(&priv->regs->control);
+	control_reg |= CPSW_VLAN_AWARE;
+	writel(control_reg, &priv->regs->control);
+	fifo_mode = (priv->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE :
+		     CPSW_FIFO_NORMAL_MODE;
+	writel(fifo_mode, &priv->host_port_regs->tx_in_ctl);
 
 	/* setup host port priority mapping */
 	__raw_writel(CPDMA_TX_PRIORITY_MAP,
@@ -621,9 +766,12 @@
 	cpsw_ale_control_set(priv->ale, priv->host_port,
 			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
 
-	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0);
-	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << priv->host_port, 0, ALE_MCAST_FWD_2);
+	if (!priv->data.dual_emac) {
+		cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port,
+				   0, 0);
+		cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+				   1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
+	}
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
@@ -632,7 +780,8 @@
 	int i, ret;
 	u32 reg;
 
-	cpsw_intr_disable(priv);
+	if (!cpsw_common_res_usage_state(priv))
+		cpsw_intr_disable(priv);
 	netif_carrier_off(ndev);
 
 	pm_runtime_get_sync(&priv->pdev->dev);
@@ -644,43 +793,55 @@
 		 CPSW_RTL_VERSION(reg));
 
 	/* initialize host and slave ports */
-	cpsw_init_host_port(priv);
+	if (!cpsw_common_res_usage_state(priv))
+		cpsw_init_host_port(priv);
 	for_each_slave(priv, cpsw_slave_open, priv);
 
-	/* setup tx dma to fixed prio and zero offset */
-	cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
-	cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
+	/* Add default VLAN */
+	if (!priv->data.dual_emac)
+		cpsw_add_default_vlan(priv);
 
-	/* disable priority elevation and enable statistics on all ports */
-	__raw_writel(0, &priv->regs->ptype);
+	if (!cpsw_common_res_usage_state(priv)) {
+		/* setup tx dma to fixed prio and zero offset */
+		cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
+		cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
 
-	/* enable statistics collection only on the host port */
-	__raw_writel(0x7, &priv->regs->stat_port_en);
+		/* disable priority elevation */
+		__raw_writel(0, &priv->regs->ptype);
 
-	if (WARN_ON(!priv->data.rx_descs))
-		priv->data.rx_descs = 128;
+		/* enable statistics collection only on all ports */
+		__raw_writel(0x7, &priv->regs->stat_port_en);
 
-	for (i = 0; i < priv->data.rx_descs; i++) {
-		struct sk_buff *skb;
+		if (WARN_ON(!priv->data.rx_descs))
+			priv->data.rx_descs = 128;
 
-		ret = -ENOMEM;
-		skb = netdev_alloc_skb_ip_align(priv->ndev,
-						priv->rx_packet_max);
-		if (!skb)
-			break;
-		ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
-					skb_tailroom(skb), GFP_KERNEL);
-		if (WARN_ON(ret < 0))
-			break;
+		for (i = 0; i < priv->data.rx_descs; i++) {
+			struct sk_buff *skb;
+
+			ret = -ENOMEM;
+			skb = netdev_alloc_skb_ip_align(priv->ndev,
+							priv->rx_packet_max);
+			if (!skb)
+				break;
+			ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
+					skb_tailroom(skb), 0, GFP_KERNEL);
+			if (WARN_ON(ret < 0))
+				break;
+		}
+		/* continue even if we didn't manage to submit all
+		 * receive descs
+		 */
+		cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
 	}
-	/* continue even if we didn't manage to submit all receive descs */
-	cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
 
 	cpdma_ctlr_start(priv->dma);
 	cpsw_intr_enable(priv);
 	napi_enable(&priv->napi);
-	cpdma_ctlr_eoi(priv->dma);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
 
+	if (priv->data.dual_emac)
+		priv->slaves[priv->emac_port].open_stat = true;
 	return 0;
 }
 
@@ -701,12 +862,17 @@
 	netif_stop_queue(priv->ndev);
 	napi_disable(&priv->napi);
 	netif_carrier_off(priv->ndev);
-	cpsw_intr_disable(priv);
-	cpdma_ctlr_int_ctrl(priv->dma, false);
-	cpdma_ctlr_stop(priv->dma);
-	cpsw_ale_stop(priv->ale);
+
+	if (cpsw_common_res_usage_state(priv) <= 1) {
+		cpsw_intr_disable(priv);
+		cpdma_ctlr_int_ctrl(priv->dma, false);
+		cpdma_ctlr_stop(priv->dma);
+		cpsw_ale_stop(priv->ale);
+	}
 	for_each_slave(priv, cpsw_slave_stop, priv);
 	pm_runtime_put_sync(&priv->pdev->dev);
+	if (priv->data.dual_emac)
+		priv->slaves[priv->emac_port].open_stat = false;
 	return 0;
 }
 
@@ -724,18 +890,24 @@
 		return NETDEV_TX_OK;
 	}
 
-	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && priv->cpts.tx_enable)
+	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+				priv->cpts->tx_enable)
 		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 
 	skb_tx_timestamp(skb);
 
-	ret = cpdma_chan_submit(priv->txch, skb, skb->data,
-				skb->len, GFP_KERNEL);
+	ret = cpsw_tx_packet_submit(ndev, priv, skb);
 	if (unlikely(ret != 0)) {
 		cpsw_err(priv, tx_err, "desc submit failed\n");
 		goto fail;
 	}
 
+	/* If there is no more tx desc left free then we need to
+	 * tell the kernel to stop sending us tx frames.
+	 */
+	if (unlikely(cpdma_check_free_tx_desc(priv->txch)))
+		netif_stop_queue(ndev);
+
 	return NETDEV_TX_OK;
 fail:
 	priv->stats.tx_dropped++;
@@ -773,7 +945,7 @@
 	struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
 	u32 ts_en, seq_id;
 
-	if (!priv->cpts.tx_enable && !priv->cpts.rx_enable) {
+	if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) {
 		slave_write(slave, 0, CPSW1_TS_CTL);
 		return;
 	}
@@ -781,10 +953,10 @@
 	seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
 	ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS;
 
-	if (priv->cpts.tx_enable)
+	if (priv->cpts->tx_enable)
 		ts_en |= CPSW_V1_TS_TX_EN;
 
-	if (priv->cpts.rx_enable)
+	if (priv->cpts->rx_enable)
 		ts_en |= CPSW_V1_TS_RX_EN;
 
 	slave_write(slave, ts_en, CPSW1_TS_CTL);
@@ -793,16 +965,21 @@
 
 static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
 {
-	struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
+	struct cpsw_slave *slave;
 	u32 ctrl, mtype;
 
+	if (priv->data.dual_emac)
+		slave = &priv->slaves[priv->emac_port];
+	else
+		slave = &priv->slaves[priv->data.cpts_active_slave];
+
 	ctrl = slave_read(slave, CPSW2_CONTROL);
 	ctrl &= ~CTRL_ALL_TS_MASK;
 
-	if (priv->cpts.tx_enable)
+	if (priv->cpts->tx_enable)
 		ctrl |= CTRL_TX_TS_BITS;
 
-	if (priv->cpts.rx_enable)
+	if (priv->cpts->rx_enable)
 		ctrl |= CTRL_RX_TS_BITS;
 
 	mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
@@ -815,7 +992,7 @@
 static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
 	struct cpsw_priv *priv = netdev_priv(dev);
-	struct cpts *cpts = &priv->cpts;
+	struct cpts *cpts = priv->cpts;
 	struct hwtstamp_config cfg;
 
 	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
@@ -901,7 +1078,9 @@
 	cpdma_chan_start(priv->txch);
 	cpdma_ctlr_int_ctrl(priv->dma, true);
 	cpsw_intr_enable(priv);
-	cpdma_ctlr_eoi(priv->dma);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
 }
 
 static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
@@ -920,10 +1099,79 @@
 	cpsw_interrupt(ndev->irq, priv);
 	cpdma_ctlr_int_ctrl(priv->dma, true);
 	cpsw_intr_enable(priv);
-	cpdma_ctlr_eoi(priv->dma);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+	cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
 }
 #endif
 
+static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
+				unsigned short vid)
+{
+	int ret;
+
+	ret = cpsw_ale_add_vlan(priv->ale, vid,
+				ALE_ALL_PORTS << priv->host_port,
+				0, ALE_ALL_PORTS << priv->host_port,
+				(ALE_PORT_1 | ALE_PORT_2) << priv->host_port);
+	if (ret != 0)
+		return ret;
+
+	ret = cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+				 priv->host_port, ALE_VLAN, vid);
+	if (ret != 0)
+		goto clean_vid;
+
+	ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+				 ALE_ALL_PORTS << priv->host_port,
+				 ALE_VLAN, vid, 0);
+	if (ret != 0)
+		goto clean_vlan_ucast;
+	return 0;
+
+clean_vlan_ucast:
+	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+			    priv->host_port, ALE_VLAN, vid);
+clean_vid:
+	cpsw_ale_del_vlan(priv->ale, vid, 0);
+	return ret;
+}
+
+static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
+	return cpsw_add_vlan_ale_entry(priv, vid);
+}
+
+static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+	int ret;
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
+	ret = cpsw_ale_del_vlan(priv->ale, vid, 0);
+	if (ret != 0)
+		return ret;
+
+	ret = cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+				 priv->host_port, ALE_VLAN, vid);
+	if (ret != 0)
+		return ret;
+
+	return cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast,
+				  0, ALE_VLAN, vid);
+}
+
 static const struct net_device_ops cpsw_netdev_ops = {
 	.ndo_open		= cpsw_ndo_open,
 	.ndo_stop		= cpsw_ndo_stop,
@@ -938,15 +1186,18 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= cpsw_ndo_poll_controller,
 #endif
+	.ndo_vlan_rx_add_vid	= cpsw_ndo_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= cpsw_ndo_vlan_rx_kill_vid,
 };
 
 static void cpsw_get_drvinfo(struct net_device *ndev,
 			     struct ethtool_drvinfo *info)
 {
 	struct cpsw_priv *priv = netdev_priv(ndev);
-	strcpy(info->driver, "TI CPSW Driver v1.0");
-	strcpy(info->version, "1.0");
-	strcpy(info->bus_info, priv->pdev->name);
+
+	strlcpy(info->driver, "TI CPSW Driver v1.0", sizeof(info->driver));
+	strlcpy(info->version, "1.0", sizeof(info->version));
+	strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info));
 }
 
 static u32 cpsw_get_msglevel(struct net_device *ndev)
@@ -974,7 +1225,7 @@
 		SOF_TIMESTAMPING_RX_SOFTWARE |
 		SOF_TIMESTAMPING_SOFTWARE |
 		SOF_TIMESTAMPING_RAW_HARDWARE;
-	info->phc_index = priv->cpts.phc_index;
+	info->phc_index = priv->cpts->phc_index;
 	info->tx_types =
 		(1 << HWTSTAMP_TX_OFF) |
 		(1 << HWTSTAMP_TX_ON);
@@ -1011,6 +1262,7 @@
 	slave->data	= data;
 	slave->regs	= regs + slave_reg_ofs;
 	slave->sliver	= regs + sliver_reg_ofs;
+	slave->port_vlan = data->dual_emac_res_vlan;
 }
 
 static int cpsw_probe_dt(struct cpsw_platform_data *data,
@@ -1051,12 +1303,10 @@
 	}
 	data->cpts_clock_shift = prop;
 
-	data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) *
-				   data->slaves, GFP_KERNEL);
-	if (!data->slave_data) {
-		pr_err("Could not allocate slave memory.\n");
+	data->slave_data = kcalloc(data->slaves, sizeof(struct cpsw_slave_data),
+				   GFP_KERNEL);
+	if (!data->slave_data)
 		return -EINVAL;
-	}
 
 	if (of_property_read_u32(node, "cpdma_channels", &prop)) {
 		pr_err("Missing cpdma_channels property in the DT.\n");
@@ -1093,6 +1343,9 @@
 	}
 	data->mac_control = prop;
 
+	if (!of_property_read_u32(node, "dual_emac", &prop))
+		data->dual_emac = prop;
+
 	/*
 	 * Populate all the child nodes here...
 	 */
@@ -1126,6 +1379,18 @@
 		if (mac_addr)
 			memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
 
+		if (data->dual_emac) {
+			if (of_property_read_u32(node, "dual_emac_res_vlan",
+						 &prop)) {
+				pr_err("Missing dual_emac_res_vlan in DT.\n");
+				slave_data->dual_emac_res_vlan = i+1;
+				pr_err("Using %d as Reserved VLAN for %d slave\n",
+				       slave_data->dual_emac_res_vlan, i);
+			} else {
+				slave_data->dual_emac_res_vlan = prop;
+			}
+		}
+
 		i++;
 	}
 
@@ -1136,6 +1401,79 @@
 	return ret;
 }
 
+static int cpsw_probe_dual_emac(struct platform_device *pdev,
+				struct cpsw_priv *priv)
+{
+	struct cpsw_platform_data	*data = &priv->data;
+	struct net_device		*ndev;
+	struct cpsw_priv		*priv_sl2;
+	int ret = 0, i;
+
+	ndev = alloc_etherdev(sizeof(struct cpsw_priv));
+	if (!ndev) {
+		pr_err("cpsw: error allocating net_device\n");
+		return -ENOMEM;
+	}
+
+	priv_sl2 = netdev_priv(ndev);
+	spin_lock_init(&priv_sl2->lock);
+	priv_sl2->data = *data;
+	priv_sl2->pdev = pdev;
+	priv_sl2->ndev = ndev;
+	priv_sl2->dev  = &ndev->dev;
+	priv_sl2->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
+	priv_sl2->rx_packet_max = max(rx_packet_max, 128);
+
+	if (is_valid_ether_addr(data->slave_data[1].mac_addr)) {
+		memcpy(priv_sl2->mac_addr, data->slave_data[1].mac_addr,
+			ETH_ALEN);
+		pr_info("cpsw: Detected MACID = %pM\n", priv_sl2->mac_addr);
+	} else {
+		random_ether_addr(priv_sl2->mac_addr);
+		pr_info("cpsw: Random MACID = %pM\n", priv_sl2->mac_addr);
+	}
+	memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN);
+
+	priv_sl2->slaves = priv->slaves;
+	priv_sl2->clk = priv->clk;
+
+	priv_sl2->cpsw_res = priv->cpsw_res;
+	priv_sl2->regs = priv->regs;
+	priv_sl2->host_port = priv->host_port;
+	priv_sl2->host_port_regs = priv->host_port_regs;
+	priv_sl2->wr_regs = priv->wr_regs;
+	priv_sl2->dma = priv->dma;
+	priv_sl2->txch = priv->txch;
+	priv_sl2->rxch = priv->rxch;
+	priv_sl2->ale = priv->ale;
+	priv_sl2->emac_port = 1;
+	priv->slaves[1].ndev = ndev;
+	priv_sl2->cpts = priv->cpts;
+	priv_sl2->version = priv->version;
+
+	for (i = 0; i < priv->num_irqs; i++) {
+		priv_sl2->irqs_table[i] = priv->irqs_table[i];
+		priv_sl2->num_irqs = priv->num_irqs;
+	}
+
+	ndev->features |= NETIF_F_HW_VLAN_FILTER;
+
+	ndev->netdev_ops = &cpsw_netdev_ops;
+	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
+	netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT);
+
+	/* register the network device */
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+	ret = register_netdev(ndev);
+	if (ret) {
+		pr_err("cpsw: error registering net device\n");
+		free_netdev(ndev);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
 static int cpsw_probe(struct platform_device *pdev)
 {
 	struct cpsw_platform_data	*data = pdev->dev.platform_data;
@@ -1162,6 +1500,11 @@
 	priv->dev  = &ndev->dev;
 	priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
 	priv->rx_packet_max = max(rx_packet_max, 128);
+	priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
+	if (!ndev) {
+		pr_err("error allocating cpts\n");
+		goto clean_ndev_ret;
+	}
 
 	/*
 	 * This may be required here for child devices.
@@ -1194,6 +1537,9 @@
 	for (i = 0; i < data->slaves; i++)
 		priv->slaves[i].slave_num = i;
 
+	priv->slaves[0].ndev = ndev;
+	priv->emac_port = 0;
+
 	priv->clk = clk_get(&pdev->dev, "fck");
 	if (IS_ERR(priv->clk)) {
 		dev_err(&pdev->dev, "fck is not found\n");
@@ -1248,7 +1594,7 @@
 	switch (priv->version) {
 	case CPSW_VERSION_1:
 		priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
-		priv->cpts.reg       = ss_regs + CPSW1_CPTS_OFFSET;
+		priv->cpts->reg       = ss_regs + CPSW1_CPTS_OFFSET;
 		dma_params.dmaregs   = ss_regs + CPSW1_CPDMA_OFFSET;
 		dma_params.txhdp     = ss_regs + CPSW1_STATERAM_OFFSET;
 		ale_params.ale_regs  = ss_regs + CPSW1_ALE_OFFSET;
@@ -1259,7 +1605,7 @@
 		break;
 	case CPSW_VERSION_2:
 		priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
-		priv->cpts.reg       = ss_regs + CPSW2_CPTS_OFFSET;
+		priv->cpts->reg       = ss_regs + CPSW2_CPTS_OFFSET;
 		dma_params.dmaregs   = ss_regs + CPSW2_CPDMA_OFFSET;
 		dma_params.txhdp     = ss_regs + CPSW2_STATERAM_OFFSET;
 		ale_params.ale_regs  = ss_regs + CPSW2_ALE_OFFSET;
@@ -1346,7 +1692,7 @@
 		k++;
 	}
 
-	ndev->flags |= IFF_ALLMULTI;	/* see cpsw_ndo_change_rx_flags() */
+	ndev->features |= NETIF_F_HW_VLAN_FILTER;
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
@@ -1361,13 +1707,21 @@
 		goto clean_irq_ret;
 	}
 
-	if (cpts_register(&pdev->dev, &priv->cpts,
+	if (cpts_register(&pdev->dev, priv->cpts,
 			  data->cpts_clock_mult, data->cpts_clock_shift))
 		dev_err(priv->dev, "error registering cpts device\n");
 
 	cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n",
 		  priv->cpsw_res->start, ndev->irq);
 
+	if (priv->data.dual_emac) {
+		ret = cpsw_probe_dual_emac(pdev, priv);
+		if (ret) {
+			cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
+			goto clean_irq_ret;
+		}
+	}
+
 	return 0;
 
 clean_irq_ret:
@@ -1406,7 +1760,7 @@
 	pr_info("removing device");
 	platform_set_drvdata(pdev, NULL);
 
-	cpts_unregister(&priv->cpts);
+	cpts_unregister(priv->cpts);
 	free_irq(ndev->irq, priv);
 	cpsw_ale_destroy(priv->ale);
 	cpdma_chan_destroy(priv->txch);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 0e9ccc2..7fa60d6 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -148,7 +148,7 @@
 	return idx;
 }
 
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
+int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
 	int type, idx;
@@ -160,6 +160,8 @@
 		type = cpsw_ale_get_entry_type(ale_entry);
 		if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
 			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) != vid)
+			continue;
 		cpsw_ale_get_addr(ale_entry, entry_addr);
 		if (memcmp(entry_addr, addr, 6) == 0)
 			return idx;
@@ -167,6 +169,22 @@
 	return -ENOENT;
 }
 
+int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS];
+	int type, idx;
+
+	for (idx = 0; idx < ale->params.ale_entries; idx++) {
+		cpsw_ale_read(ale, idx, ale_entry);
+		type = cpsw_ale_get_entry_type(ale_entry);
+		if (type != ALE_TYPE_VLAN)
+			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) == vid)
+			return idx;
+	}
+	return -ENOENT;
+}
+
 static int cpsw_ale_match_free(struct cpsw_ale *ale)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
@@ -274,19 +292,32 @@
 	return 0;
 }
 
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
+static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
+						int flags, u16 vid)
+{
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+}
+
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
+
 	cpsw_ale_set_addr(ale_entry, addr);
 	cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
 	cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
 	cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_port_num(ale_entry, port);
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		idx = cpsw_ale_match_free(ale);
 	if (idx < 0)
@@ -298,12 +329,13 @@
 	return 0;
 }
 
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -ENOENT;
 
@@ -313,18 +345,19 @@
 }
 
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state)
+		       int flags, u16 vid, int mcast_state)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx, mask;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx >= 0)
 		cpsw_ale_read(ale, idx, ale_entry);
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
+
 	cpsw_ale_set_addr(ale_entry, addr);
-	cpsw_ale_set_super(ale_entry, super);
+	cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_mcast_state(ale_entry, mcast_state);
 
 	mask = cpsw_ale_get_port_mask(ale_entry);
@@ -342,12 +375,13 @@
 	return 0;
 }
 
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -EINVAL;
 
@@ -362,6 +396,55 @@
 	return 0;
 }
 
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+		      int reg_mcast, int unreg_mcast)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx >= 0)
+		cpsw_ale_read(ale, idx, ale_entry);
+
+	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
+	cpsw_ale_set_vlan_id(ale_entry, vid);
+
+	cpsw_ale_set_vlan_untag_force(ale_entry, untag);
+	cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
+	cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+	cpsw_ale_set_vlan_member_list(ale_entry, port);
+
+	if (idx < 0)
+		idx = cpsw_ale_match_free(ale);
+	if (idx < 0)
+		idx = cpsw_ale_find_ageable(ale);
+	if (idx < 0)
+		return -ENOMEM;
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx < 0)
+		return -ENOENT;
+
+	cpsw_ale_read(ale, idx, ale_entry);
+
+	if (port_mask)
+		cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+	else
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
 struct ale_control_info {
 	const char	*name;
 	int		offset, port_offset;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index 2bd09cb..30daa12 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -64,8 +64,14 @@
 };
 
 /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
-#define ALE_SECURE			1
-#define ALE_BLOCKED			2
+#define ALE_SECURE			BIT(0)
+#define ALE_BLOCKED			BIT(1)
+#define ALE_SUPER			BIT(2)
+#define ALE_VLAN			BIT(3)
+
+#define ALE_PORT_HOST			BIT(0)
+#define ALE_PORT_1			BIT(1)
+#define ALE_PORT_2			BIT(2)
 
 #define ALE_MCAST_FWD			0
 #define ALE_MCAST_BLOCK_LEARN_FWD	1
@@ -81,11 +87,17 @@
 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask);
+		       int flags, u16 vid, int mcast_state);
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid);
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+			int reg_mcast, int unreg_mcast);
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
 
 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
 int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 4995673..68c3418 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -60,6 +60,9 @@
 #define CPDMA_DESC_EOQ		BIT(28)
 #define CPDMA_DESC_TD_COMPLETE	BIT(27)
 #define CPDMA_DESC_PASS_CRC	BIT(26)
+#define CPDMA_DESC_TO_PORT_EN	BIT(20)
+#define CPDMA_TO_PORT_SHIFT	16
+#define CPDMA_DESC_PORT_MASK	(BIT(18) | BIT(17) | BIT(16))
 
 #define CPDMA_TEARDOWN_VALUE	0xfffffffc
 
@@ -105,13 +108,13 @@
 };
 
 struct cpdma_chan {
+	struct cpdma_desc __iomem	*head, *tail;
+	void __iomem			*hdp, *cp, *rxfree;
 	enum cpdma_state		state;
 	struct cpdma_ctlr		*ctlr;
 	int				chan_num;
 	spinlock_t			lock;
-	struct cpdma_desc __iomem	*head, *tail;
 	int				count;
-	void __iomem			*hdp, *cp, *rxfree;
 	u32				mask;
 	cpdma_handler_fn		handler;
 	enum dma_data_direction		dir;
@@ -132,6 +135,14 @@
 #define chan_write(chan, fld, v)	__raw_writel(v, (chan)->fld)
 #define desc_write(desc, fld, v)	__raw_writel((u32)(v), &(desc)->fld)
 
+#define cpdma_desc_to_port(chan, mode, directed)			\
+	do {								\
+		if (!is_rx_chan(chan) && ((directed == 1) ||		\
+					  (directed == 2)))		\
+			mode |= (CPDMA_DESC_TO_PORT_EN |		\
+				 (directed << CPDMA_TO_PORT_SHIFT));	\
+	} while (0)
+
 /*
  * Utility constructs for a cpdma descriptor pool.  Some devices (e.g. davinci
  * emac) have dedicated on-chip memory for these descriptors.  Some other
@@ -217,17 +228,27 @@
 }
 
 static struct cpdma_desc __iomem *
-cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
+cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx)
 {
 	unsigned long flags;
 	int index;
+	int desc_start;
+	int desc_end;
 	struct cpdma_desc __iomem *desc = NULL;
 
 	spin_lock_irqsave(&pool->lock, flags);
 
-	index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
-					   num_desc, 0);
-	if (index < pool->num_desc) {
+	if (is_rx) {
+		desc_start = 0;
+		desc_end = pool->num_desc/2;
+	 } else {
+		desc_start = pool->num_desc/2;
+		desc_end = pool->num_desc;
+	}
+
+	index = bitmap_find_next_zero_area(pool->bitmap,
+				desc_end, desc_start, num_desc, 0);
+	if (index < desc_end) {
 		bitmap_set(pool->bitmap, index, num_desc);
 		desc = pool->iomap + pool->desc_size * index;
 		pool->used_desc++;
@@ -439,10 +460,8 @@
 	if (ctlr->state != CPDMA_STATE_IDLE)
 		cpdma_ctlr_stop(ctlr);
 
-	for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
-		if (ctlr->channels[i])
-			cpdma_chan_destroy(ctlr->channels[i]);
-	}
+	for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++)
+		cpdma_chan_destroy(ctlr->channels[i]);
 
 	cpdma_desc_pool_destroy(ctlr->pool);
 	spin_unlock_irqrestore(&ctlr->lock, flags);
@@ -474,9 +493,9 @@
 	return 0;
 }
 
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value)
 {
-	dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
+	dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value);
 }
 
 struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
@@ -652,7 +671,7 @@
 }
 
 int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
-		      int len, gfp_t gfp_mask)
+		      int len, int directed, gfp_t gfp_mask)
 {
 	struct cpdma_ctlr		*ctlr = chan->ctlr;
 	struct cpdma_desc __iomem	*desc;
@@ -668,7 +687,7 @@
 		goto unlock_ret;
 	}
 
-	desc = cpdma_desc_alloc(ctlr->pool, 1);
+	desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan));
 	if (!desc) {
 		chan->stats.desc_alloc_fail++;
 		ret = -ENOMEM;
@@ -682,6 +701,7 @@
 
 	buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
 	mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
+	cpdma_desc_to_port(chan, mode, directed);
 
 	desc_write(desc, hw_next,   0);
 	desc_write(desc, hw_buffer, buffer);
@@ -704,6 +724,29 @@
 }
 EXPORT_SYMBOL_GPL(cpdma_chan_submit);
 
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan)
+{
+	unsigned long flags;
+	int index;
+	bool ret;
+	struct cpdma_ctlr	*ctlr = chan->ctlr;
+	struct cpdma_desc_pool	*pool = ctlr->pool;
+
+	spin_lock_irqsave(&pool->lock, flags);
+
+	index = bitmap_find_next_zero_area(pool->bitmap,
+				pool->num_desc, pool->num_desc/2, 1, 0);
+
+	if (index < pool->num_desc)
+		ret = true;
+	else
+		ret = false;
+
+	spin_unlock_irqrestore(&pool->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc);
+
 static void __cpdma_chan_free(struct cpdma_chan *chan,
 			      struct cpdma_desc __iomem *desc,
 			      int outlen, int status)
@@ -749,7 +792,8 @@
 		status = -EBUSY;
 		goto unlock_ret;
 	}
-	status	= status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE);
+	status	= status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE |
+			    CPDMA_DESC_PORT_MASK);
 
 	chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
 	chan_write(chan, cp, desc_dma);
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index afa19a0..d9bcc60 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -24,6 +24,13 @@
 #define __chan_linear(chan_num)	((chan_num) & (CPDMA_MAX_CHANNELS - 1))
 #define chan_linear(chan)	__chan_linear((chan)->chan_num)
 
+#define CPDMA_RX_SOURCE_PORT(__status__)	((__status__ >> 16) & 0x7)
+
+#define CPDMA_EOI_RX_THRESH	0x0
+#define CPDMA_EOI_RX		0x1
+#define CPDMA_EOI_TX		0x2
+#define CPDMA_EOI_MISC		0x3
+
 struct cpdma_params {
 	struct device		*dev;
 	void __iomem		*dmaregs;
@@ -82,12 +89,13 @@
 int cpdma_chan_get_stats(struct cpdma_chan *chan,
 			 struct cpdma_chan_stats *stats);
 int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
-		      int len, gfp_t gfp_mask);
+		      int len, int directed, gfp_t gfp_mask);
 int cpdma_chan_process(struct cpdma_chan *chan, int quota);
 
 int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value);
 int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan);
 
 enum cpdma_control {
 	CPDMA_CMD_IDLE,			/* write-only */
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 2a3e2c5..52c0536 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -120,7 +120,6 @@
 #define EMAC_DEF_TX_CH			(0) /* Default 0th channel */
 #define EMAC_DEF_RX_CH			(0) /* Default 0th channel */
 #define EMAC_DEF_RX_NUM_DESC		(128)
-#define EMAC_DEF_TX_NUM_DESC		(128)
 #define EMAC_DEF_MAX_TX_CH		(1) /* Max TX channels configured */
 #define EMAC_DEF_MAX_RX_CH		(1) /* Max RX channels configured */
 #define EMAC_POLL_WEIGHT		(64) /* Default NAPI poll weight */
@@ -342,7 +341,6 @@
 	u32 mac_hash2;
 	u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
 	u32 rx_addr_type;
-	atomic_t cur_tx;
 	const char *phy_id;
 #ifdef CONFIG_OF
 	struct device_node *phy_node;
@@ -480,8 +478,8 @@
 static void emac_get_drvinfo(struct net_device *ndev,
 			     struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, emac_version_string);
-	strcpy(info->version, EMAC_MODULE_VERSION);
+	strlcpy(info->driver, emac_version_string, sizeof(info->driver));
+	strlcpy(info->version, EMAC_MODULE_VERSION, sizeof(info->version));
 }
 
 /**
@@ -1039,7 +1037,7 @@
 
 recycle:
 	ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
-			skb_tailroom(skb), GFP_KERNEL);
+			skb_tailroom(skb), 0, GFP_KERNEL);
 
 	WARN_ON(ret == -ENOMEM);
 	if (unlikely(ret < 0))
@@ -1050,10 +1048,10 @@
 {
 	struct sk_buff		*skb = token;
 	struct net_device	*ndev = skb->dev;
-	struct emac_priv	*priv = netdev_priv(ndev);
 
-	atomic_dec(&priv->cur_tx);
-
+	/* Check whether the queue is stopped due to stalled tx dma, if the
+	 * queue is stopped then start the queue as we have free desc for tx
+	 */
 	if (unlikely(netif_queue_stopped(ndev)))
 		netif_start_queue(ndev);
 	ndev->stats.tx_packets++;
@@ -1094,14 +1092,17 @@
 	skb_tx_timestamp(skb);
 
 	ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len,
-				     GFP_KERNEL);
+				     0, GFP_KERNEL);
 	if (unlikely(ret_code != 0)) {
 		if (netif_msg_tx_err(priv) && net_ratelimit())
 			dev_err(emac_dev, "DaVinci EMAC: desc submit failed");
 		goto fail_tx;
 	}
 
-	if (atomic_inc_return(&priv->cur_tx) >= EMAC_DEF_TX_NUM_DESC)
+	/* If there is no more tx desc left free then we need to
+	 * tell the kernel to stop sending us tx frames.
+	 */
+	if (unlikely(cpdma_check_free_tx_desc(priv->txchan)))
 		netif_stop_queue(ndev);
 
 	return NETDEV_TX_OK;
@@ -1264,7 +1265,6 @@
 	/* Store mac addr in priv and rx channel and set it in EMAC hw */
 	memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
 	memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
-	ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	/* MAC address is configured only after the interface is enabled. */
 	if (netif_running(ndev)) {
@@ -1558,7 +1558,7 @@
 			break;
 
 		ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
-					skb_tailroom(skb), GFP_KERNEL);
+					skb_tailroom(skb), 0, GFP_KERNEL);
 		if (WARN_ON(ret < 0))
 			break;
 	}
@@ -1600,7 +1600,7 @@
 
 	if (priv->phy_id && *priv->phy_id) {
 		priv->phydev = phy_connect(ndev, priv->phy_id,
-					   &emac_adjust_link, 0,
+					   &emac_adjust_link,
 					   PHY_INTERFACE_MODE_MII);
 
 		if (IS_ERR(priv->phydev)) {
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index cca2550..d04a622 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -320,10 +320,8 @@
 	int ret, addr;
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		dev_err(dev, "failed to alloc device data\n");
+	if (!data)
 		return -ENOMEM;
-	}
 
 	data->bus = mdiobus_alloc();
 	if (!data->bus) {
diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index 96070e9..3643549 100644
--- a/drivers/net/ethernet/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -2195,7 +2195,6 @@
 
 	/* ISSUE: Note that "dev_addr" is now a pointer. */
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index e321d0b..445c059 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -1226,8 +1226,8 @@
 void gelic_net_get_drvinfo(struct net_device *netdev,
 			   struct ethtool_drvinfo *info)
 {
-	strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
-	strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int gelic_ether_get_settings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/toshiba/spider_net_ethtool.c b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
index 9c288cd..ffe5193 100644
--- a/drivers/net/ethernet/toshiba/spider_net_ethtool.c
+++ b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
@@ -72,11 +72,13 @@
 	card = netdev_priv(netdev);
 
 	/* clear and fill out info */
-	memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
-	strncpy(drvinfo->driver, spider_net_driver_name, 32);
-	strncpy(drvinfo->version, VERSION, 32);
-	strcpy(drvinfo->fw_version, "no information");
-	strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+	strlcpy(drvinfo->driver, spider_net_driver_name,
+		sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, VERSION, sizeof(drvinfo->version));
+	strlcpy(drvinfo->fw_version, "no information",
+		sizeof(drvinfo->fw_version));
+	strlcpy(drvinfo->bus_info, pci_name(card->pdev),
+		sizeof(drvinfo->bus_info));
 }
 
 static void
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index 9819349..fe25609 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -633,9 +633,8 @@
 
 	/* attach the mac to the phy */
 	phydev = phy_connect(dev, dev_name(&phydev->dev),
-			     &tc_handle_link_change, 0,
-			     lp->chiptype == TC35815_TX4939 ?
-			     PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
+			     &tc_handle_link_change,
+			     lp->chiptype == TC35815_TX4939 ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
 	if (IS_ERR(phydev)) {
 		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
 		return PTR_ERR(phydev);
@@ -856,7 +855,6 @@
 	if (rc)
 		goto err_out;
 
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 	printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
 		dev->name,
 		chip_info[ent->driver_data].name,
@@ -1976,9 +1974,10 @@
 static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct tc35815_local *lp = netdev_priv(dev);
-	strcpy(info->driver, MODNAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pci_name(lp->pci_dev));
+
+	strlcpy(info->driver, MODNAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(lp->pci_dev), sizeof(info->bus_info));
 }
 
 static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 78ace59..185c721 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -417,6 +417,12 @@
 	Cmd1NoTxPoll=0x08, Cmd1Reset=0x80,
 };
 
+struct rhine_stats {
+	u64		packets;
+	u64		bytes;
+	struct u64_stats_sync syncp;
+};
+
 struct rhine_private {
 	/* Bit mask for configured VLAN ids */
 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -458,6 +464,8 @@
 	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
+	struct rhine_stats rx_stats;
+	struct rhine_stats tx_stats;
 	u8 wolopts;
 
 	u8 tx_thresh, rx_thresh;
@@ -495,7 +503,8 @@
 static void rhine_tx(struct net_device *dev);
 static int rhine_rx(struct net_device *dev, int limit);
 static void rhine_set_rx_mode(struct net_device *dev);
-static struct net_device_stats *rhine_get_stats(struct net_device *dev);
+static struct rtnl_link_stats64 *rhine_get_stats64(struct net_device *dev,
+	       struct rtnl_link_stats64 *stats);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops netdev_ethtool_ops;
 static int  rhine_close(struct net_device *dev);
@@ -842,7 +851,7 @@
 	.ndo_open		 = rhine_open,
 	.ndo_stop		 = rhine_close,
 	.ndo_start_xmit		 = rhine_start_tx,
-	.ndo_get_stats		 = rhine_get_stats,
+	.ndo_get_stats64	 = rhine_get_stats64,
 	.ndo_set_rx_mode	 = rhine_set_rx_mode,
 	.ndo_change_mtu		 = eth_change_mtu,
 	.ndo_validate_addr	 = eth_validate_addr,
@@ -990,7 +999,6 @@
 		netdev_info(dev, "Using random MAC address: %pM\n",
 			    dev->dev_addr);
 	}
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	/* For Rhine-I/II, phy_id is loaded from EEPROM */
 	if (!phy_id)
@@ -1791,8 +1799,11 @@
 				dev->stats.collisions += txstatus & 0x0F;
 			netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n",
 				  (txstatus >> 3) & 0xF, txstatus & 0xF);
-			dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
-			dev->stats.tx_packets++;
+
+			u64_stats_update_begin(&rp->tx_stats.syncp);
+			rp->tx_stats.bytes += rp->tx_skbuff[entry]->len;
+			rp->tx_stats.packets++;
+			u64_stats_update_end(&rp->tx_stats.syncp);
 		}
 		/* Free the original skb. */
 		if (rp->tx_skbuff_dma[entry]) {
@@ -1924,8 +1935,11 @@
 			if (unlikely(desc_length & DescTag))
 				__vlan_hwaccel_put_tag(skb, vlan_tci);
 			netif_receive_skb(skb);
-			dev->stats.rx_bytes += pkt_len;
-			dev->stats.rx_packets++;
+
+			u64_stats_update_begin(&rp->rx_stats.syncp);
+			rp->rx_stats.bytes += pkt_len;
+			rp->rx_stats.packets++;
+			u64_stats_update_end(&rp->rx_stats.syncp);
 		}
 		entry = (++rp->cur_rx) % RX_RING_SIZE;
 		rp->rx_head_desc = &rp->rx_ring[entry];
@@ -2016,15 +2030,31 @@
 	mutex_unlock(&rp->task_lock);
 }
 
-static struct net_device_stats *rhine_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
 	struct rhine_private *rp = netdev_priv(dev);
+	unsigned int start;
 
 	spin_lock_bh(&rp->lock);
 	rhine_update_rx_crc_and_missed_errord(rp);
 	spin_unlock_bh(&rp->lock);
 
-	return &dev->stats;
+	netdev_stats_to_stats64(stats, &dev->stats);
+
+	do {
+		start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp);
+		stats->rx_packets = rp->rx_stats.packets;
+		stats->rx_bytes = rp->rx_stats.bytes;
+	} while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start));
+
+	do {
+		start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp);
+		stats->tx_packets = rp->tx_stats.packets;
+		stats->tx_bytes = rp->tx_stats.bytes;
+	} while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start));
+
+	return stats;
 }
 
 static void rhine_set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index 3523838..545043c 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -570,7 +570,6 @@
 	if (!is_valid_ether_addr(sock_addr->sa_data))
 		return -EADDRNOTAVAIL;
 	memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
-	ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	w5100_write_macaddr(priv);
 	return 0;
 }
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 9d1d986..7cbd0e6 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -490,7 +490,6 @@
 	if (!is_valid_ether_addr(sock_addr->sa_data))
 		return -EADDRNOTAVAIL;
 	memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
-	ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	w5300_write_macaddr(priv);
 	return 0;
 }
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index aad909d..9fc2ada 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -238,11 +238,9 @@
 	int i;
 
 	lp->rx_skb = kcalloc(RX_BD_NUM, sizeof(*lp->rx_skb), GFP_KERNEL);
-	if (!lp->rx_skb) {
-		dev_err(&ndev->dev,
-				"can't allocate memory for DMA RX buffer\n");
+	if (!lp->rx_skb)
 		goto out;
-	}
+
 	/* allocate the tx and rx ring buffer descriptors. */
 	/* returns a virtual address and a physical address. */
 	lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
@@ -319,18 +317,10 @@
  * net_device_ops
  */
 
-static int temac_set_mac_address(struct net_device *ndev, void *address)
+static void temac_do_set_mac_address(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
 
-	if (address)
-		memcpy(ndev->dev_addr, address, ETH_ALEN);
-
-	if (!is_valid_ether_addr(ndev->dev_addr))
-		eth_hw_addr_random(ndev);
-	else
-		ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
-
 	/* set up unicast MAC address filter set its mac address */
 	mutex_lock(&lp->indirect_mutex);
 	temac_indirect_out32(lp, XTE_UAW0_OFFSET,
@@ -344,15 +334,26 @@
 			     (ndev->dev_addr[4] & 0x000000ff) |
 			     (ndev->dev_addr[5] << 8));
 	mutex_unlock(&lp->indirect_mutex);
+}
 
+static int temac_init_mac_address(struct net_device *ndev, void *address)
+{
+	memcpy(ndev->dev_addr, address, ETH_ALEN);
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		eth_hw_addr_random(ndev);
+	temac_do_set_mac_address(ndev);
 	return 0;
 }
 
-static int netdev_set_mac_address(struct net_device *ndev, void *p)
+static int temac_set_mac_address(struct net_device *ndev, void *p)
 {
 	struct sockaddr *addr = p;
 
-	return temac_set_mac_address(ndev, addr->sa_data);
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+	memcpy(ndev->dev_addr, addr->sa_data, ETH_ALEN);
+	temac_do_set_mac_address(ndev);
+	return 0;
 }
 
 static void temac_set_multicast_list(struct net_device *ndev)
@@ -579,7 +580,7 @@
 	temac_setoptions(ndev,
 			 lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN));
 
-	temac_set_mac_address(ndev, NULL);
+	temac_do_set_mac_address(ndev);
 
 	/* Set address filter table */
 	temac_set_multicast_list(ndev);
@@ -938,7 +939,7 @@
 	.ndo_open = temac_open,
 	.ndo_stop = temac_stop,
 	.ndo_start_xmit = temac_start_xmit,
-	.ndo_set_mac_address = netdev_set_mac_address,
+	.ndo_set_mac_address = temac_set_mac_address,
 	.ndo_validate_addr = eth_validate_addr,
 	.ndo_do_ioctl = temac_ioctl,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1106,7 +1107,7 @@
 		rc = -ENODEV;
 		goto err_iounmap_2;
 	}
-	temac_set_mac_address(ndev, (void *)addr);
+	temac_init_mac_address(ndev, (void *)addr);
 
 	rc = temac_mdio_setup(lp, op->dev.of_node);
 	if (rc)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 6f47100..278c9db 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1124,9 +1124,8 @@
 static void axienet_ethtools_get_drvinfo(struct net_device *ndev,
 					 struct ethtool_drvinfo *ed)
 {
-	memset(ed, 0, sizeof(struct ethtool_drvinfo));
-	strcpy(ed->driver, DRIVER_NAME);
-	strcpy(ed->version, DRIVER_VERSION);
+	strlcpy(ed->driver, DRIVER_NAME, sizeof(ed->driver));
+	strlcpy(ed->version, DRIVER_VERSION, sizeof(ed->version));
 	ed->regdump_len = sizeof(u32) * AXIENET_REGS_N;
 }
 
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 94a1f94..98e09d0 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -1412,7 +1412,8 @@
 			       struct ethtool_drvinfo *info)
 {
 	strlcpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
-	sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+	snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
+		 dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index d3ebb73..6958a5e 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -977,11 +977,12 @@
 			       struct ethtool_drvinfo *info)
 {
 	struct port *port = netdev_priv(dev);
-	strcpy(info->driver, DRV_NAME);
+
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
 	snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u",
 		 port->firmware[0], port->firmware[1],
 		 port->firmware[2], port->firmware[3]);
-	strcpy(info->bus_info, "internal");
+	strlcpy(info->bus_info, "internal", sizeof(info->bus_info));
 }
 
 static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1450,7 +1451,7 @@
 
 	snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
 		mdio_bus->id, plat->phy);
-	port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
+	port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link,
 				   PHY_INTERFACE_MODE_MII);
 	if (IS_ERR(port->phydev)) {
 		err = PTR_ERR(port->phydev);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index c2e5497..02de6c8 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -586,7 +586,8 @@
 static int __init bpq_init_driver(void)
 {
 #ifdef CONFIG_PROC_FS
-	if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) {
+	if (!proc_create("bpqether", S_IRUGO, init_net.proc_net,
+			 &bpq_info_fops)) {
 		printk(KERN_ERR
 			"bpq: cannot create /proc/net/bpqether entry.\n");
 		return -ENOENT;
@@ -610,7 +611,7 @@
 
 	unregister_netdevice_notifier(&bpq_dev_notifier);
 
-	proc_net_remove(&init_net, "bpqether");
+	remove_proc_entry("bpqether", init_net.proc_net);
 
 	rtnl_lock();
 	while (!list_empty(&bpq_devices)) {
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index ce555d9..6636022 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -463,13 +463,8 @@
 
 	/* Initialize what is necessary for write_scc and write_scc_data */
 	info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
-	if (!info) {
-		printk(KERN_ERR "dmascc: "
-		       "could not allocate memory for %s at %#3x\n",
-		       hw[type].name, card_base);
+	if (!info)
 		goto out;
-	}
-
 
 	info->dev[0] = alloc_netdev(0, "", dev_setup);
 	if (!info->dev[0]) {
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 1b4a47b..bc1d521 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -2118,7 +2118,7 @@
 	}
 	rtnl_unlock();
 
-	proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops);
+	proc_create("z8530drv", 0, init_net.proc_net, &scc_net_seq_fops);
 
 	return 0;
 }
@@ -2173,7 +2173,7 @@
 	if (Vector_Latch)
 		release_region(Vector_Latch, 1);
 
-	proc_net_remove(&init_net, "z8530drv");
+	remove_proc_entry("z8530drv", init_net.proc_net);
 }
 
 MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index c6645f1..4cf8f10 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -1167,7 +1167,7 @@
 	yam_timer.expires = jiffies + HZ / 100;
 	add_timer(&yam_timer);
 
-	proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops);
+	proc_create("yam", S_IRUGO, init_net.proc_net, &yam_info_fops);
 	return 0;
  error:
 	while (--i >= 0) {
@@ -1199,7 +1199,7 @@
 		kfree(p);
 	}
 
-	proc_net_remove(&init_net, "yam");
+	remove_proc_entry("yam", init_net.proc_net);
 }
 
 /* --------------------------------------------------------------------- */
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 8264f0e..d5202a4 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -304,9 +304,9 @@
 static void netvsc_get_drvinfo(struct net_device *net,
 			       struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, KBUILD_MODNAME);
-	strcpy(info->version, HV_DRV_VERSION);
-	strcpy(info->fw_version, "N/A");
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strlcpy(info->version, HV_DRV_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 }
 
 static int netvsc_change_mtu(struct net_device *ndev, int mtu)
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index a4a62e1..fc1687e 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -751,16 +751,6 @@
 	return 0;
 }
 
-static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
-{
-	return 0;
-}
-
-static int at86rf230_resume(struct spi_device *spi)
-{
-	return 0;
-}
-
 static int at86rf230_fill_data(struct spi_device *spi)
 {
 	struct at86rf230_local *lp = spi_get_drvdata(spi);
@@ -948,8 +938,6 @@
 	},
 	.probe      = at86rf230_probe,
 	.remove     = at86rf230_remove,
-	.suspend    = at86rf230_suspend,
-	.resume     = at86rf230_resume,
 };
 
 module_spi_driver(at86rf230_driver);
diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c
index 1e9cb0b..8f1c256 100644
--- a/drivers/net/ieee802154/fakehard.c
+++ b/drivers/net/ieee802154/fakehard.c
@@ -372,7 +372,6 @@
 
 	memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
 			dev->addr_len);
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	/*
 	 * For now we'd like to emulate 2.4 GHz-only device,
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 344dceb..8216438 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -90,7 +90,7 @@
 		u64_stats_update_end(&dp->tsync);
 
 		rcu_read_lock();
-		skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif);
+		skb->dev = dev_get_by_index_rcu(dev_net(_dev), skb->skb_iif);
 		if (!skb->dev) {
 			rcu_read_unlock();
 			dev_kfree_skb(skb);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index d3fb97d..defcd8a8 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -29,6 +29,7 @@
 #include <linux/if_vlan.h>
 #include <linux/if_link.h>
 #include <linux/if_macvlan.h>
+#include <linux/hash.h>
 #include <net/rtnetlink.h>
 #include <net/xfrm.h>
 
@@ -126,6 +127,21 @@
 	return vlan->receive(skb);
 }
 
+static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
+{
+	return (u32)(((unsigned long)vlan) >> L1_CACHE_SHIFT);
+}
+
+
+static unsigned int mc_hash(const struct macvlan_dev *vlan,
+			    const unsigned char *addr)
+{
+	u32 val = __get_unaligned_cpu32(addr + 2);
+
+	val ^= macvlan_hash_mix(vlan);
+	return hash_32(val, MACVLAN_MC_FILTER_BITS);
+}
+
 static void macvlan_broadcast(struct sk_buff *skb,
 			      const struct macvlan_port *port,
 			      struct net_device *src,
@@ -137,6 +153,7 @@
 	struct sk_buff *nskb;
 	unsigned int i;
 	int err;
+	unsigned int hash;
 
 	if (skb->protocol == htons(ETH_P_PAUSE))
 		return;
@@ -146,6 +163,9 @@
 			if (vlan->dev == src || !(vlan->mode & mode))
 				continue;
 
+			hash = mc_hash(vlan, eth->h_dest);
+			if (!test_bit(hash, vlan->mc_filter))
+				continue;
 			nskb = skb_clone(skb, GFP_ATOMIC);
 			err = macvlan_broadcast_one(nskb, vlan, eth,
 					 mode == MACVLAN_MODE_BRIDGE);
@@ -375,7 +395,6 @@
 
 	if (!(dev->flags & IFF_UP)) {
 		/* Just copy in the new address */
-		dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 		memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 	} else {
 		/* Rehash and update the device filters */
@@ -406,6 +425,21 @@
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
 
+	if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+		bitmap_fill(vlan->mc_filter, MACVLAN_MC_FILTER_SZ);
+	} else {
+		struct netdev_hw_addr *ha;
+		DECLARE_BITMAP(filter, MACVLAN_MC_FILTER_SZ);
+
+		bitmap_zero(filter, MACVLAN_MC_FILTER_SZ);
+		netdev_for_each_mc_addr(ha, dev) {
+			__set_bit(mc_hash(vlan, ha->addr), filter);
+		}
+
+		__set_bit(mc_hash(vlan, dev->broadcast), filter);
+
+		bitmap_copy(vlan->mc_filter, filter, MACVLAN_MC_FILTER_SZ);
+	}
 	dev_uc_sync(vlan->lowerdev, dev);
 	dev_mc_sync(vlan->lowerdev, dev);
 }
@@ -565,7 +599,7 @@
 	return err;
 }
 
-static int macvlan_fdb_del(struct ndmsg *ndm,
+static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
 			   struct net_device *dev,
 			   const unsigned char *addr)
 {
@@ -586,8 +620,8 @@
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
 					struct ethtool_drvinfo *drvinfo)
 {
-	snprintf(drvinfo->driver, 32, "macvlan");
-	snprintf(drvinfo->version, 32, "0.1");
+	strlcpy(drvinfo->driver, "macvlan", sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, "0.1", sizeof(drvinfo->version));
 }
 
 static int macvlan_ethtool_get_settings(struct net_device *dev,
@@ -765,16 +799,22 @@
 		memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
 	}
 
+	err = netdev_upper_dev_link(lowerdev, dev);
+	if (err)
+		goto destroy_port;
+
 	port->count += 1;
 	err = register_netdevice(dev);
 	if (err < 0)
-		goto destroy_port;
+		goto upper_dev_unlink;
 
 	list_add_tail(&vlan->list, &port->vlans);
 	netif_stacked_transfer_operstate(lowerdev, dev);
 
 	return 0;
 
+upper_dev_unlink:
+	netdev_upper_dev_unlink(lowerdev, dev);
 destroy_port:
 	port->count -= 1;
 	if (!port->count)
@@ -798,6 +838,7 @@
 
 	list_del(&vlan->list);
 	unregister_netdevice_queue(dev, head);
+	netdev_upper_dev_unlink(vlan->lowerdev, dev);
 }
 EXPORT_SYMBOL_GPL(macvlan_dellink);
 
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 0f0f9ce..9724301 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -742,6 +742,7 @@
 	if (zerocopy) {
 		skb_shinfo(skb)->destructor_arg = m->msg_control;
 		skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+		skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
 	}
 	if (vlan)
 		macvlan_start_xmit(skb, vlan->dev);
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 6989ebe..37add21 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -269,12 +269,18 @@
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+	if (nt->np.ipv6)
+		return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+	else
+		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+	if (nt->np.ipv6)
+		return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+	else
+		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 }
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -410,7 +416,22 @@
 		return -EINVAL;
 	}
 
-	nt->np.local_ip = in_aton(buf);
+	if (strnchr(buf, count, ':')) {
+		const char *end;
+		if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
+			if (*end && *end != '\n') {
+				printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+				return -EINVAL;
+			}
+			nt->np.ipv6 = true;
+		} else
+			return -EINVAL;
+	} else {
+		if (!nt->np.ipv6) {
+			nt->np.local_ip.ip = in_aton(buf);
+		} else
+			return -EINVAL;
+	}
 
 	return strnlen(buf, count);
 }
@@ -426,7 +447,22 @@
 		return -EINVAL;
 	}
 
-	nt->np.remote_ip = in_aton(buf);
+	if (strnchr(buf, count, ':')) {
+		const char *end;
+		if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
+			if (*end && *end != '\n') {
+				printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+				return -EINVAL;
+			}
+			nt->np.ipv6 = true;
+		} else
+			return -EINVAL;
+	} else {
+		if (!nt->np.ipv6) {
+			nt->np.remote_ip.ip = in_aton(buf);
+		} else
+			return -EINVAL;
+	}
 
 	return strnlen(buf, count);
 }
diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
index 0c9accb..e91d7d7 100644
--- a/drivers/net/phy/mdio-mux-gpio.c
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -53,7 +53,7 @@
 {
 	enum of_gpio_flags f;
 	struct mdio_mux_gpio_state *s;
-	unsigned int num_gpios;
+	int num_gpios;
 	unsigned int n;
 	int r;
 
@@ -61,7 +61,7 @@
 		return -ENODEV;
 
 	num_gpios = of_gpio_count(pdev->dev.of_node);
-	if (num_gpios == 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
+	if (num_gpios <= 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
 		return -ENODEV;
 
 	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index b983596..2993444 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -5,15 +5,20 @@
  *
  * Author: David J. Choi
  *
- * Copyright (c) 2010 Micrel, Inc.
+ * Copyright (c) 2010-2013 Micrel, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  *
- * Support : ksz9021 1000/100/10 phy from Micrel
- *		ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
+ * Support : Micrel Phys:
+ *		Giga phys: ksz9021, ksz9031
+ *		100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
+ *			   ksz8021, ksz8031, ksz8051,
+ *			   ksz8081, ksz8091,
+ *			   ksz8061,
+ *		Switch : ksz8873, ksz886x
  */
 
 #include <linux/kernel.h>
@@ -176,7 +181,7 @@
 }, {
 	.phy_id		= PHY_ID_KSZ8021,
 	.phy_id_mask	= 0x00ffffff,
-	.name		= "Micrel KSZ8021",
+	.name		= "Micrel KSZ8021 or KSZ8031",
 	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
 			   SUPPORTED_Asym_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
@@ -225,6 +230,30 @@
 	.config_intr	= kszphy_config_intr,
 	.driver		= { .owner = THIS_MODULE,},
 }, {
+	.phy_id		= PHY_ID_KSZ8081,
+	.name		= "Micrel KSZ8081 or KSZ8091",
+	.phy_id_mask	= 0x00fffff0,
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+}, {
+	.phy_id		= PHY_ID_KSZ8061,
+	.name		= "Micrel KSZ8061",
+	.phy_id_mask	= 0x00fffff0,
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= kszphy_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+}, {
 	.phy_id		= PHY_ID_KSZ9021,
 	.phy_id_mask	= 0x000ffffe,
 	.name		= "Micrel KSZ9021 Gigabit PHY",
@@ -238,6 +267,19 @@
 	.config_intr	= ksz9021_config_intr,
 	.driver		= { .owner = THIS_MODULE, },
 }, {
+	.phy_id		= PHY_ID_KSZ9031,
+	.phy_id_mask	= 0x00fffff0,
+	.name		= "Micrel KSZ9031 Gigabit PHY",
+	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
+				| SUPPORTED_Asym_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.ack_interrupt	= kszphy_ack_interrupt,
+	.config_intr	= ksz9021_config_intr,
+	.driver		= { .owner = THIS_MODULE, },
+}, {
 	.phy_id		= PHY_ID_KSZ8873MLL,
 	.phy_id_mask	= 0x00fffff0,
 	.name		= "Micrel KSZ8873MLL Switch",
@@ -247,6 +289,16 @@
 	.config_aneg	= ksz8873mll_config_aneg,
 	.read_status	= ksz8873mll_read_status,
 	.driver		= { .owner = THIS_MODULE, },
+}, {
+	.phy_id		= PHY_ID_KSZ886X,
+	.phy_id_mask	= 0x00fffff0,
+	.name		= "Micrel KSZ886X Switch",
+	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+	.config_init	= kszphy_config_init,
+	.config_aneg	= genphy_config_aneg,
+	.read_status	= genphy_read_status,
+	.driver		= { .owner = THIS_MODULE, },
 } };
 
 static int __init ksphy_init(void)
@@ -270,12 +322,16 @@
 
 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
 	{ PHY_ID_KSZ9021, 0x000ffffe },
+	{ PHY_ID_KSZ9031, 0x00fffff0 },
 	{ PHY_ID_KSZ8001, 0x00ffffff },
 	{ PHY_ID_KS8737, 0x00fffff0 },
 	{ PHY_ID_KSZ8021, 0x00ffffff },
 	{ PHY_ID_KSZ8041, 0x00fffff0 },
 	{ PHY_ID_KSZ8051, 0x00fffff0 },
+	{ PHY_ID_KSZ8061, 0x00fffff0 },
+	{ PHY_ID_KSZ8081, 0x00fffff0 },
 	{ PHY_ID_KSZ8873MLL, 0x00fffff0 },
+	{ PHY_ID_KSZ886X, 0x00fffff0 },
 	{ }
 };
 
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8af46e8..9930f99 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -416,16 +416,15 @@
  * @dev: the network device to connect
  * @phydev: the pointer to the phy device
  * @handler: callback function for state change notifications
- * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  */
 int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
-		       void (*handler)(struct net_device *), u32 flags,
+		       void (*handler)(struct net_device *),
 		       phy_interface_t interface)
 {
 	int rc;
 
-	rc = phy_attach_direct(dev, phydev, flags, interface);
+	rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
 	if (rc)
 		return rc;
 
@@ -443,7 +442,6 @@
  * @dev: the network device to connect
  * @bus_id: the id string of the PHY device to connect
  * @handler: callback function for state change notifications
- * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  *
  * Description: Convenience function for connecting ethernet
@@ -455,7 +453,7 @@
  *   the desired functionality.
  */
 struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
-		void (*handler)(struct net_device *), u32 flags,
+		void (*handler)(struct net_device *),
 		phy_interface_t interface)
 {
 	struct phy_device *phydev;
@@ -471,7 +469,7 @@
 	}
 	phydev = to_phy_device(d);
 
-	rc = phy_connect_direct(dev, phydev, handler, flags, interface);
+	rc = phy_connect_direct(dev, phydev, handler, interface);
 	if (rc)
 		return ERR_PTR(rc);
 
@@ -576,14 +574,13 @@
  * phy_attach - attach a network device to a particular PHY device
  * @dev: network device to attach
  * @bus_id: Bus ID of PHY device to attach
- * @flags: PHY device's dev_flags
  * @interface: PHY device's interface
  *
  * Description: Same as phy_attach_direct() except that a PHY bus_id
  *     string is passed instead of a pointer to a struct phy_device.
  */
 struct phy_device *phy_attach(struct net_device *dev,
-		const char *bus_id, u32 flags, phy_interface_t interface)
+		const char *bus_id, phy_interface_t interface)
 {
 	struct bus_type *bus = &mdio_bus_type;
 	struct phy_device *phydev;
@@ -599,7 +596,7 @@
 	}
 	phydev = to_phy_device(d);
 
-	rc = phy_attach_direct(dev, phydev, flags, interface);
+	rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
 	if (rc)
 		return ERR_PTR(rc);
 
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 72f9347..8e7af83 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -23,6 +23,8 @@
 #define RTL821x_INER_INIT	0x6400
 #define RTL821x_INSR		0x13
 
+#define	RTL8211E_INER_LINK_STAT	0x10
+
 MODULE_DESCRIPTION("Realtek PHY driver");
 MODULE_AUTHOR("Johnson Leung");
 MODULE_LICENSE("GPL");
@@ -36,7 +38,7 @@
 	return (err < 0) ? err : 0;
 }
 
-static int rtl821x_config_intr(struct phy_device *phydev)
+static int rtl8211b_config_intr(struct phy_device *phydev)
 {
 	int err;
 
@@ -49,28 +51,63 @@
 	return err;
 }
 
+static int rtl8211e_config_intr(struct phy_device *phydev)
+{
+	int err;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, RTL821x_INER,
+				RTL8211E_INER_LINK_STAT);
+	else
+		err = phy_write(phydev, RTL821x_INER, 0);
+
+	return err;
+}
+
 /* RTL8211B */
-static struct phy_driver rtl821x_driver = {
+static struct phy_driver rtl8211b_driver = {
 	.phy_id		= 0x001cc912,
-	.name		= "RTL821x Gigabit Ethernet",
+	.name		= "RTL8211B Gigabit Ethernet",
 	.phy_id_mask	= 0x001fffff,
 	.features	= PHY_GBIT_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.config_aneg	= &genphy_config_aneg,
 	.read_status	= &genphy_read_status,
 	.ack_interrupt	= &rtl821x_ack_interrupt,
-	.config_intr	= &rtl821x_config_intr,
+	.config_intr	= &rtl8211b_config_intr,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+/* RTL8211E */
+static struct phy_driver rtl8211e_driver = {
+	.phy_id		= 0x001cc915,
+	.name		= "RTL8211E Gigabit Ethernet",
+	.phy_id_mask	= 0x001fffff,
+	.features	= PHY_GBIT_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_aneg	= &genphy_config_aneg,
+	.read_status	= &genphy_read_status,
+	.ack_interrupt	= &rtl821x_ack_interrupt,
+	.config_intr	= &rtl8211e_config_intr,
+	.suspend	= genphy_suspend,
+	.resume		= genphy_resume,
 	.driver		= { .owner = THIS_MODULE,},
 };
 
 static int __init realtek_init(void)
 {
-	return phy_driver_register(&rtl821x_driver);
+	int ret;
+
+	ret = phy_driver_register(&rtl8211b_driver);
+	if (ret < 0)
+		return -ENODEV;
+	return phy_driver_register(&rtl8211e_driver);
 }
 
 static void __exit realtek_exit(void)
 {
-	phy_driver_unregister(&rtl821x_driver);
+	phy_driver_unregister(&rtl8211b_driver);
+	phy_driver_unregister(&rtl8211e_driver);
 }
 
 module_init(realtek_init);
@@ -78,6 +115,7 @@
 
 static struct mdio_device_id __maybe_unused realtek_tbl[] = {
 	{ 0x001cc912, 0x001fffff },
+	{ 0x001cc915, 0x001fffff },
 	{ }
 };
 
diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c
index 41eb8ff..5c87eef 100644
--- a/drivers/net/phy/spi_ks8995.c
+++ b/drivers/net/phy/spi_ks8995.c
@@ -275,10 +275,8 @@
 	pdata = spi->dev.platform_data;
 
 	ks = kzalloc(sizeof(*ks), GFP_KERNEL);
-	if (!ks) {
-		dev_err(&spi->dev, "no memory for private data\n");
+	if (!ks)
 		return -ENOMEM;
-	}
 
 	mutex_init(&ks->lock);
 	ks->pdata = pdata;
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 0b2706a..3db9131 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1058,7 +1058,15 @@
 	return stats64;
 }
 
+static struct lock_class_key ppp_tx_busylock;
+static int ppp_dev_init(struct net_device *dev)
+{
+	dev->qdisc_tx_busylock = &ppp_tx_busylock;
+	return 0;
+}
+
 static const struct net_device_ops ppp_netdev_ops = {
+	.ndo_init	 = ppp_dev_init,
 	.ndo_start_xmit  = ppp_start_xmit,
 	.ndo_do_ioctl    = ppp_net_ioctl,
 	.ndo_get_stats64 = ppp_get_stats64,
@@ -1805,8 +1813,7 @@
 		/* the filter instructions are constructed assuming
 		   a four-byte PPP header on each packet */
 		if (ppp->pass_filter || ppp->active_filter) {
-			if (skb_cloned(skb) &&
-			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+			if (skb_unclone(skb, GFP_ATOMIC))
 				goto err;
 
 			*skb_push(skb, 2) = 0;
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 20f31d0..bb07ba9 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1134,7 +1134,7 @@
 
 	rwlock_init(&pn->hash_lock);
 
-	pde = proc_net_fops_create(net, "pppoe", S_IRUGO, &pppoe_seq_fops);
+	pde = proc_create("pppoe", S_IRUGO, net->proc_net, &pppoe_seq_fops);
 #ifdef CONFIG_PROC_FS
 	if (!pde)
 		return -ENOMEM;
@@ -1145,7 +1145,7 @@
 
 static __net_exit void pppoe_exit_net(struct net *net)
 {
-	proc_net_remove(net, "pppoe");
+	remove_proc_entry("pppoe", net->proc_net);
 }
 
 static struct pernet_operations pppoe_net_ops = {
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index d8b9b1e..f433b59 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -410,10 +410,10 @@
 {
 	struct rionet_private *rnet = netdev_priv(ndev);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->fw_version, "n/a");
-	strcpy(info->bus_info, rnet->mport->name);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, "n/a", sizeof(info->fw_version));
+	strlcpy(info->bus_info, rnet->mport->name, sizeof(info->bus_info));
 }
 
 static u32 rionet_get_msglevel(struct net_device *ndev)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index ad86660..05c5efe 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -28,6 +28,7 @@
 #include <net/genetlink.h>
 #include <net/netlink.h>
 #include <net/sch_generic.h>
+#include <generated/utsrelease.h>
 #include <linux/if_team.h>
 
 #define DRV_NAME "team"
@@ -507,6 +508,7 @@
 
 static void team_set_no_mode(struct team *team)
 {
+	team->user_carrier_enabled = false;
 	team->mode = &__team_no_mode;
 }
 
@@ -1054,10 +1056,11 @@
 		}
 	}
 
-	err = netdev_set_master(port_dev, dev);
+	err = netdev_master_upper_dev_link(port_dev, dev);
 	if (err) {
-		netdev_err(dev, "Device %s failed to set master\n", portname);
-		goto err_set_master;
+		netdev_err(dev, "Device %s failed to set upper link\n",
+			   portname);
+		goto err_set_upper_link;
 	}
 
 	err = netdev_rx_handler_register(port_dev, team_handle_frame,
@@ -1090,9 +1093,9 @@
 	netdev_rx_handler_unregister(port_dev);
 
 err_handler_register:
-	netdev_set_master(port_dev, NULL);
+	netdev_upper_dev_unlink(port_dev, dev);
 
-err_set_master:
+err_set_upper_link:
 	team_port_disable_netpoll(port);
 
 err_enable_netpoll:
@@ -1129,18 +1132,20 @@
 		return -ENOENT;
 	}
 
-	__team_option_inst_mark_removed_port(team, port);
-	__team_options_change_check(team);
-	__team_option_inst_del_port(team, port);
-	__team_port_change_port_removed(port);
 	team_port_disable(team, port);
 	list_del_rcu(&port->list);
 	netdev_rx_handler_unregister(port_dev);
-	netdev_set_master(port_dev, NULL);
+	netdev_upper_dev_unlink(port_dev, dev);
 	team_port_disable_netpoll(port);
 	vlan_vids_del_by_dev(port_dev, dev);
 	dev_close(port_dev);
 	team_port_leave(team, port);
+
+	__team_option_inst_mark_removed_port(team, port);
+	__team_options_change_check(team);
+	__team_option_inst_del_port(team, port);
+	__team_port_change_port_removed(port);
+
 	team_port_set_orig_dev_addr(port);
 	dev_set_mtu(port_dev, port->orig.mtu);
 	synchronize_rcu();
@@ -1399,13 +1404,11 @@
 
 static int team_open(struct net_device *dev)
 {
-	netif_carrier_on(dev);
 	return 0;
 }
 
 static int team_close(struct net_device *dev)
 {
-	netif_carrier_off(dev);
 	return 0;
 }
 
@@ -1501,7 +1504,6 @@
 	if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 	rcu_read_lock();
 	list_for_each_entry_rcu(port, &team->port_list, list)
 		if (team->ops.port_change_dev_addr)
@@ -1707,6 +1709,19 @@
 	return features;
 }
 
+static int team_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	struct team *team = netdev_priv(dev);
+
+	team->user_carrier_enabled = true;
+
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+
 static const struct net_device_ops team_netdev_ops = {
 	.ndo_init		= team_init,
 	.ndo_uninit		= team_uninit,
@@ -1729,8 +1744,24 @@
 	.ndo_add_slave		= team_add_slave,
 	.ndo_del_slave		= team_del_slave,
 	.ndo_fix_features	= team_fix_features,
+	.ndo_change_carrier     = team_change_carrier,
 };
 
+/***********************
+ * ethtool interface
+ ***********************/
+
+static void team_ethtool_get_drvinfo(struct net_device *dev,
+				     struct ethtool_drvinfo *drvinfo)
+{
+	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+}
+
+static const struct ethtool_ops team_ethtool_ops = {
+	.get_drvinfo		= team_ethtool_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+};
 
 /***********************
  * rt netlink interface
@@ -1746,7 +1777,6 @@
 	dev->mtu = port_dev->mtu;
 	memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
 	memcpy(dev->dev_addr, port_dev->dev_addr, port_dev->addr_len);
-	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
 }
 
 static int team_dev_type_check_change(struct net_device *dev,
@@ -1780,6 +1810,7 @@
 	ether_setup(dev);
 
 	dev->netdev_ops = &team_netdev_ops;
+	dev->ethtool_ops = &team_ethtool_ops;
 	dev->destructor	= team_destructor;
 	dev->tx_queue_len = 0;
 	dev->flags |= IFF_MULTICAST;
@@ -1941,30 +1972,6 @@
 	dev_put(team->dev);
 }
 
-static int team_nl_send_generic(struct genl_info *info, struct team *team,
-				int (*fill_func)(struct sk_buff *skb,
-						 struct genl_info *info,
-						 int flags, struct team *team))
-{
-	struct sk_buff *skb;
-	int err;
-
-	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
-		return -ENOMEM;
-
-	err = fill_func(skb, info, NLM_F_ACK, team);
-	if (err < 0)
-		goto err_fill;
-
-	err = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid);
-	return err;
-
-err_fill:
-	nlmsg_free(skb);
-	return err;
-}
-
 typedef int team_nl_send_func_t(struct sk_buff *skb,
 				struct team *team, u32 portid);
 
@@ -2309,16 +2316,57 @@
 	return err;
 }
 
-static int team_nl_fill_port_list_get(struct sk_buff *skb,
-				      u32 portid, u32 seq, int flags,
-				      struct team *team,
-				      bool fillall)
+static int team_nl_fill_one_port_get(struct sk_buff *skb,
+				     struct team_port *port)
+{
+	struct nlattr *port_item;
+
+	port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
+	if (!port_item)
+		goto nest_cancel;
+	if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex))
+		goto nest_cancel;
+	if (port->changed) {
+		if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED))
+			goto nest_cancel;
+		port->changed = false;
+	}
+	if ((port->removed &&
+	     nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
+	    (port->state.linkup &&
+	     nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
+	    nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
+	    nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
+		goto nest_cancel;
+	nla_nest_end(skb, port_item);
+	return 0;
+
+nest_cancel:
+	nla_nest_cancel(skb, port_item);
+	return -EMSGSIZE;
+}
+
+static int team_nl_send_port_list_get(struct team *team, u32 portid, u32 seq,
+				      int flags, team_nl_send_func_t *send_func,
+				      struct team_port *one_port)
 {
 	struct nlattr *port_list;
+	struct nlmsghdr *nlh;
 	void *hdr;
 	struct team_port *port;
+	int err;
+	struct sk_buff *skb = NULL;
+	bool incomplete;
+	int i;
 
-	hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags,
+	port = list_first_entry(&team->port_list, struct team_port, list);
+
+start_again:
+	err = __send_and_alloc_skb(&skb, team, portid, send_func);
+	if (err)
+		return err;
+
+	hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI,
 			  TEAM_CMD_PORT_LIST_GET);
 	if (!hdr)
 		return -EMSGSIZE;
@@ -2329,47 +2377,54 @@
 	if (!port_list)
 		goto nla_put_failure;
 
-	list_for_each_entry(port, &team->port_list, list) {
-		struct nlattr *port_item;
+	i = 0;
+	incomplete = false;
 
-		/* Include only changed ports if fill all mode is not on */
-		if (!fillall && !port->changed)
-			continue;
-		port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
-		if (!port_item)
-			goto nla_put_failure;
-		if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex))
-			goto nla_put_failure;
-		if (port->changed) {
-			if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED))
-				goto nla_put_failure;
-			port->changed = false;
+	/* If one port is selected, called wants to send port list containing
+	 * only this port. Otherwise go through all listed ports and send all
+	 */
+	if (one_port) {
+		err = team_nl_fill_one_port_get(skb, one_port);
+		if (err)
+			goto errout;
+	} else {
+		list_for_each_entry(port, &team->port_list, list) {
+			err = team_nl_fill_one_port_get(skb, port);
+			if (err) {
+				if (err == -EMSGSIZE) {
+					if (!i)
+						goto errout;
+					incomplete = true;
+					break;
+				}
+				goto errout;
+			}
+			i++;
 		}
-		if ((port->removed &&
-		     nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
-		    (port->state.linkup &&
-		     nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
-		    nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
-		    nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
-			goto nla_put_failure;
-		nla_nest_end(skb, port_item);
 	}
 
 	nla_nest_end(skb, port_list);
-	return genlmsg_end(skb, hdr);
+	genlmsg_end(skb, hdr);
+	if (incomplete)
+		goto start_again;
+
+send_done:
+	nlh = nlmsg_put(skb, portid, seq, NLMSG_DONE, 0, flags | NLM_F_MULTI);
+	if (!nlh) {
+		err = __send_and_alloc_skb(&skb, team, portid, send_func);
+		if (err)
+			goto errout;
+		goto send_done;
+	}
+
+	return send_func(skb, team, portid);
 
 nla_put_failure:
+	err = -EMSGSIZE;
+errout:
 	genlmsg_cancel(skb, hdr);
-	return -EMSGSIZE;
-}
-
-static int team_nl_fill_port_list_get_all(struct sk_buff *skb,
-					  struct genl_info *info, int flags,
-					  struct team *team)
-{
-	return team_nl_fill_port_list_get(skb, info->snd_portid,
-					  info->snd_seq, NLM_F_ACK,
-					  team, true);
+	nlmsg_free(skb);
+	return err;
 }
 
 static int team_nl_cmd_port_list_get(struct sk_buff *skb,
@@ -2382,7 +2437,8 @@
 	if (!team)
 		return -EINVAL;
 
-	err = team_nl_send_generic(info, team, team_nl_fill_port_list_get_all);
+	err = team_nl_send_port_list_get(team, info->snd_portid, info->snd_seq,
+					 NLM_F_ACK, team_nl_send_unicast, NULL);
 
 	team_nl_team_put(team);
 
@@ -2433,27 +2489,11 @@
 					sel_opt_inst_list);
 }
 
-static int team_nl_send_event_port_list_get(struct team *team)
+static int team_nl_send_event_port_get(struct team *team,
+				       struct team_port *port)
 {
-	struct sk_buff *skb;
-	int err;
-	struct net *net = dev_net(team->dev);
-
-	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
-		return -ENOMEM;
-
-	err = team_nl_fill_port_list_get(skb, 0, 0, 0, team, false);
-	if (err < 0)
-		goto err_fill;
-
-	err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
-				      GFP_KERNEL);
-	return err;
-
-err_fill:
-	nlmsg_free(skb);
-	return err;
+	return team_nl_send_port_list_get(team, 0, 0, 0, team_nl_send_multicast,
+					  port);
 }
 
 static int team_nl_init(void)
@@ -2526,28 +2566,53 @@
 	port->state.duplex = 0;
 
 send_event:
-	err = team_nl_send_event_port_list_get(port->team);
+	err = team_nl_send_event_port_get(port->team, port);
 	if (err && err != -ESRCH)
 		netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink (err %d)\n",
 			    port->dev->name, err);
 
 }
 
+static void __team_carrier_check(struct team *team)
+{
+	struct team_port *port;
+	bool team_linkup;
+
+	if (team->user_carrier_enabled)
+		return;
+
+	team_linkup = false;
+	list_for_each_entry(port, &team->port_list, list) {
+		if (port->linkup) {
+			team_linkup = true;
+			break;
+		}
+	}
+
+	if (team_linkup)
+		netif_carrier_on(team->dev);
+	else
+		netif_carrier_off(team->dev);
+}
+
 static void __team_port_change_check(struct team_port *port, bool linkup)
 {
 	if (port->state.linkup != linkup)
 		__team_port_change_send(port, linkup);
+	__team_carrier_check(port->team);
 }
 
 static void __team_port_change_port_added(struct team_port *port, bool linkup)
 {
 	__team_port_change_send(port, linkup);
+	__team_carrier_check(port->team);
 }
 
 static void __team_port_change_port_removed(struct team_port *port)
 {
 	port->removed = true;
 	__team_port_change_send(port, false);
+	__team_carrier_check(port->team);
 }
 
 static void team_port_change_check(struct team_port *port, bool linkup)
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index 6262b4d..40fd338 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -19,6 +19,7 @@
 
 struct ab_priv {
 	struct team_port __rcu *active_port;
+	struct team_option_inst_info *ap_opt_inst_info;
 };
 
 static struct ab_priv *ab_priv(struct team *team)
@@ -54,8 +55,17 @@
 
 static void ab_port_leave(struct team *team, struct team_port *port)
 {
-	if (ab_priv(team)->active_port == port)
+	if (ab_priv(team)->active_port == port) {
 		RCU_INIT_POINTER(ab_priv(team)->active_port, NULL);
+		team_option_inst_set_change(ab_priv(team)->ap_opt_inst_info);
+	}
+}
+
+static int ab_active_port_init(struct team *team,
+			       struct team_option_inst_info *info)
+{
+	ab_priv(team)->ap_opt_inst_info = info;
+	return 0;
 }
 
 static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
@@ -88,6 +98,7 @@
 	{
 		.name = "activeport",
 		.type = TEAM_OPTION_TYPE_U32,
+		.init = ab_active_port_init,
 		.getter = ab_active_port_get,
 		.setter = ab_active_port_set,
 	},
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 2917a86..b6f45c5 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1200,6 +1200,7 @@
 	if (zerocopy) {
 		skb_shinfo(skb)->destructor_arg = msg_control;
 		skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+		skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
 	}
 
 	skb_reset_network_header(skb);
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
index e889631..346c032 100644
--- a/drivers/net/usb/asix.h
+++ b/drivers/net/usb/asix.h
@@ -167,6 +167,20 @@
 	u8 res;
 };
 
+struct asix_rx_fixup_info {
+	struct sk_buff *ax_skb;
+	u32 header;
+	u16 size;
+	bool split_head;
+};
+
+struct asix_common_private {
+	struct asix_rx_fixup_info rx_fixup_info;
+};
+
+/* ASIX specific flags */
+#define FLAG_EEPROM_MAC		(1UL << 0)  /* init device MAC from eeprom */
+
 int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
 		  u16 size, void *data);
 
@@ -176,7 +190,9 @@
 void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
 			  u16 index, u16 size, void *data);
 
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+			   struct asix_rx_fixup_info *rx);
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
 
 struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 			      gfp_t flags);
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 50d1673..f7f623a 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -51,49 +51,89 @@
 			       value, index, data, size);
 }
 
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+			   struct asix_rx_fixup_info *rx)
 {
 	int offset = 0;
 
-	while (offset + sizeof(u32) < skb->len) {
-		struct sk_buff *ax_skb;
-		u16 size;
-		u32 header = get_unaligned_le32(skb->data + offset);
+	while (offset + sizeof(u16) <= skb->len) {
+		u16 remaining = 0;
+		unsigned char *data;
 
-		offset += sizeof(u32);
+		if (!rx->size) {
+			if ((skb->len - offset == sizeof(u16)) ||
+			    rx->split_head) {
+				if(!rx->split_head) {
+					rx->header = get_unaligned_le16(
+							skb->data + offset);
+					rx->split_head = true;
+					offset += sizeof(u16);
+					break;
+				} else {
+					rx->header |= (get_unaligned_le16(
+							skb->data + offset)
+							<< 16);
+					rx->split_head = false;
+					offset += sizeof(u16);
+				}
+			} else {
+				rx->header = get_unaligned_le32(skb->data +
+								offset);
+				offset += sizeof(u32);
+			}
 
-		/* get the packet length */
-		size = (u16) (header & 0x7ff);
-		if (size != ((~header >> 16) & 0x07ff)) {
-			netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
-			return 0;
+			/* get the packet length */
+			rx->size = (u16) (rx->header & 0x7ff);
+			if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
+				netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
+					   rx->header, offset);
+				rx->size = 0;
+				return 0;
+			}
+			rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
+							       rx->size);
+			if (!rx->ax_skb)
+				return 0;
 		}
 
-		if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
-		    (size + offset > skb->len)) {
+		if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
 			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
-				   size);
+				   rx->size);
+			kfree_skb(rx->ax_skb);
 			return 0;
 		}
-		ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
-		if (!ax_skb)
-			return 0;
 
-		skb_put(ax_skb, size);
-		memcpy(ax_skb->data, skb->data + offset, size);
-		usbnet_skb_return(dev, ax_skb);
+		if (rx->size > skb->len - offset) {
+			remaining = rx->size - (skb->len - offset);
+			rx->size = skb->len - offset;
+		}
 
-		offset += (size + 1) & 0xfffe;
+		data = skb_put(rx->ax_skb, rx->size);
+		memcpy(data, skb->data + offset, rx->size);
+		if (!remaining)
+			usbnet_skb_return(dev, rx->ax_skb);
+
+		offset += (rx->size + 1) & 0xfffe;
+		rx->size = remaining;
 	}
 
 	if (skb->len != offset) {
-		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
-			   skb->len);
+		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
+			   skb->len, offset);
 		return 0;
 	}
+
 	return 1;
 }
 
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct asix_common_private *dp = dev->driver_priv;
+	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
+
+	return asix_rx_fixup_internal(dev, skb, rx);
+}
+
 struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 			      gfp_t flags)
 {
@@ -510,8 +550,8 @@
 {
 	/* Inherit standard device info */
 	usbnet_get_drvinfo(net, info);
-	strncpy (info->driver, DRIVER_NAME, sizeof info->driver);
-	strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
 	info->eedump_len = AX_EEPROM_LEN;
 }
 
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 7a6e758..2205dbc 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -422,14 +422,25 @@
 
 static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-	int ret, embd_phy;
+	int ret, embd_phy, i;
 	u8 buf[ETH_ALEN];
 	u32 phyid;
 
 	usbnet_get_endpoints(dev,intf);
 
 	/* Get the MAC address */
-	ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+	if (dev->driver_info->data & FLAG_EEPROM_MAC) {
+		for (i = 0; i < (ETH_ALEN >> 1); i++) {
+			ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i,
+					0, 2, buf + i * 2);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+				0, 0, ETH_ALEN, buf);
+	}
+
 	if (ret < 0) {
 		netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
 		return ret;
@@ -484,9 +495,19 @@
 		dev->rx_urb_size = 2048;
 	}
 
+	dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
+	if (!dev->driver_priv)
+		return -ENOMEM;
+
 	return 0;
 }
 
+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	if (dev->driver_priv)
+		kfree(dev->driver_priv);
+}
+
 static const struct ethtool_ops ax88178_ethtool_ops = {
 	.get_drvinfo		= asix_get_drvinfo,
 	.get_link		= asix_get_link,
@@ -818,6 +839,10 @@
 		dev->rx_urb_size = 2048;
 	}
 
+	dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
+	if (!dev->driver_priv)
+			return -ENOMEM;
+
 	return 0;
 }
 
@@ -864,22 +889,38 @@
 static const struct driver_info ax88772_info = {
 	.description = "ASIX AX88772 USB 2.0 Ethernet",
 	.bind = ax88772_bind,
+	.unbind = ax88772_unbind,
 	.status = asix_status,
 	.link_reset = ax88772_link_reset,
 	.reset = ax88772_reset,
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
-	.rx_fixup = asix_rx_fixup,
+	.rx_fixup = asix_rx_fixup_common,
 	.tx_fixup = asix_tx_fixup,
 };
 
+static const struct driver_info ax88772b_info = {
+	.description = "ASIX AX88772B USB 2.0 Ethernet",
+	.bind = ax88772_bind,
+	.unbind = ax88772_unbind,
+	.status = asix_status,
+	.link_reset = ax88772_link_reset,
+	.reset = ax88772_reset,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+	         FLAG_MULTI_PACKET,
+	.rx_fixup = asix_rx_fixup_common,
+	.tx_fixup = asix_tx_fixup,
+	.data = FLAG_EEPROM_MAC,
+};
+
 static const struct driver_info ax88178_info = {
 	.description = "ASIX AX88178 USB 2.0 Ethernet",
 	.bind = ax88178_bind,
+	.unbind = ax88772_unbind,
 	.status = asix_status,
 	.link_reset = ax88178_link_reset,
 	.reset = ax88178_reset,
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
-	.rx_fixup = asix_rx_fixup,
+	.rx_fixup = asix_rx_fixup_common,
 	.tx_fixup = asix_tx_fixup,
 };
 
@@ -953,7 +994,7 @@
 }, {
 	// ASIX AX88772B 10/100
 	USB_DEVICE (0x0b95, 0x772b),
-	.driver_info = (unsigned long) &ax88772_info,
+	.driver_info = (unsigned long) &ax88772b_info,
 }, {
 	// ASIX AX88772 10/100
 	USB_DEVICE (0x0b95, 0x7720),
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c
index c8e0aa8..d012203 100644
--- a/drivers/net/usb/ax88172a.c
+++ b/drivers/net/usb/ax88172a.c
@@ -35,6 +35,7 @@
 	u16 phy_addr;
 	u16 oldmode;
 	int use_embdphy;
+	struct asix_rx_fixup_info rx_fixup_info;
 };
 
 /* MDIO read and write wrappers for phylib */
@@ -116,7 +117,6 @@
 
 	priv->mdio->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
 	if (!priv->mdio->irq) {
-		netdev_err(dev->net, "Could not allocate mdio->irq\n");
 		ret = -ENOMEM;
 		goto mfree;
 	}
@@ -235,10 +235,9 @@
 	usbnet_get_endpoints(dev, intf);
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		netdev_err(dev->net, "Could not allocate memory for private data\n");
+	if (!priv)
 		return -ENOMEM;
-	}
+
 	dev->driver_priv = priv;
 
 	/* Get the MAC address */
@@ -377,7 +376,7 @@
 
 	priv->phydev = phy_connect(dev->net, priv->phy_name,
 				   &ax88172a_adjust_link,
-				   0, PHY_INTERFACE_MODE_MII);
+				   PHY_INTERFACE_MODE_MII);
 	if (IS_ERR(priv->phydev)) {
 		netdev_err(dev->net, "Could not connect to PHY device %s\n",
 			   priv->phy_name);
@@ -400,6 +399,14 @@
 
 }
 
+static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct ax88172a_private *dp = dev->driver_priv;
+	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
+
+	return asix_rx_fixup_internal(dev, skb, rx);
+}
+
 const struct driver_info ax88172a_info = {
 	.description = "ASIX AX88172A USB 2.0 Ethernet",
 	.bind = ax88172a_bind,
@@ -409,6 +416,6 @@
 	.status = ax88172a_status,
 	.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
 		 FLAG_MULTI_PACKET,
-	.rx_fixup = asix_rx_fixup,
+	.rx_fixup = ax88172a_rx_fixup,
 	.tx_fixup = asix_tx_fixup,
 };
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 18d9579..8d5cac2 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -685,9 +685,9 @@
 			     struct ethtool_drvinfo *info)
 {
 	struct catc *catc = netdev_priv(dev);
-	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
-	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-	usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info);
+	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+	usb_make_path(catc->usbdev, info->bus_info, sizeof(info->bus_info));
 }
 
 static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 3f3d12d..57136dc 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -615,6 +615,13 @@
 	.driver_info = 0,
 },
 
+/* AnyDATA ADU960S - handled by qmi_wwan */
+{
+	USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM,
+			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+	.driver_info = 0,
+},
+
 /*
  * WHITELIST!!!
  *
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 00d3b2d..4a8c25a 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -65,9 +65,9 @@
 {
 	struct usbnet *dev = netdev_priv(net);
 
-	strncpy(info->driver, dev->driver_name, sizeof(info->driver));
-	strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
-	strncpy(info->fw_version, dev->driver_info->description,
+	strlcpy(info->driver, dev->driver_name, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+	strlcpy(info->fw_version, dev->driver_info->description,
 		sizeof(info->fw_version));
 	usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
 }
@@ -576,9 +576,14 @@
 	if ((intf->num_altsetting == 2) &&
 	    !usb_set_interface(dev->udev,
 			       intf->cur_altsetting->desc.bInterfaceNumber,
-			       CDC_NCM_COMM_ALTSETTING_MBIM) &&
-	    cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
-		return -ENODEV;
+			       CDC_NCM_COMM_ALTSETTING_MBIM)) {
+		if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
+			return -ENODEV;
+		else
+			usb_set_interface(dev->udev,
+					  intf->cur_altsetting->desc.bInterfaceNumber,
+					  CDC_NCM_COMM_ALTSETTING_NCM);
+	}
 #endif
 
 	/* NCM data altsetting is always 1 */
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index d7e9944..174e5ec 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -118,7 +118,7 @@
 	dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
 
 	for (i = 0; i < DM_TIMEOUT; i++) {
-		u8 tmp;
+		u8 tmp = 0;
 
 		udelay(1);
 		ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
@@ -161,7 +161,7 @@
 	dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
 
 	for (i = 0; i < DM_TIMEOUT; i++) {
-		u8 tmp;
+		u8 tmp = 0;
 
 		udelay(1);
 		ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cd8ccb2..41e5dfb 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2317,10 +2317,8 @@
 		serial->rx_urb[i]->transfer_buffer_length = 0;
 		serial->rx_data[i] = kzalloc(serial->rx_data_length,
 					     GFP_KERNEL);
-		if (!serial->rx_data[i]) {
-			dev_err(dev, "%s - Out of memory\n", __func__);
+		if (!serial->rx_data[i])
 			goto exit;
-		}
 	}
 
 	/* TX, allocate urb and initialize */
@@ -2336,15 +2334,12 @@
 	serial->tx_buffer_count = 0;
 	serial->tx_data_length = tx_size;
 	serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL);
-	if (!serial->tx_data) {
-		dev_err(dev, "%s - Out of memory\n", __func__);
+	if (!serial->tx_data)
 		goto exit;
-	}
+
 	serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL);
-	if (!serial->tx_buffer) {
-		dev_err(dev, "%s - Out of memory\n", __func__);
+	if (!serial->tx_buffer)
 		goto exit;
-	}
 
 	return 0;
 exit:
@@ -2580,10 +2575,8 @@
 		}
 		hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE,
 							   GFP_KERNEL);
-		if (!hso_net->mux_bulk_rx_buf_pool[i]) {
-			dev_err(&interface->dev, "Could not allocate rx buf\n");
+		if (!hso_net->mux_bulk_rx_buf_pool[i])
 			goto exit;
-		}
 	}
 	hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!hso_net->mux_bulk_tx_urb) {
@@ -2591,10 +2584,8 @@
 		goto exit;
 	}
 	hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL);
-	if (!hso_net->mux_bulk_tx_buf) {
-		dev_err(&interface->dev, "Could not allocate tx buf\n");
+	if (!hso_net->mux_bulk_tx_buf)
 		goto exit;
-	}
 
 	add_net_device(hso_dev);
 
@@ -2818,10 +2809,8 @@
 	mux->shared_intr_buf =
 		kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize),
 			GFP_KERNEL);
-	if (!mux->shared_intr_buf) {
-		dev_err(&interface->dev, "Could not allocate intr buf?\n");
+	if (!mux->shared_intr_buf)
 		goto exit;
-	}
 
 	mutex_init(&mux->shared_int_lock);
 
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 92c49e0..0192073 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -159,7 +159,6 @@
 	}
 
 	memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN);
-	memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN);
 
 	return status;
 }
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index a0b5807..73051d1 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -149,11 +149,9 @@
 	DECLARE_WAITQUEUE(wait, current);
 
 	buffer = kmalloc(size, GFP_KERNEL);
-	if (!buffer) {
-		netif_warn(pegasus, drv, pegasus->net,
-			   "out of memory in %s\n", __func__);
+	if (!buffer)
 		return -ENOMEM;
-	}
+
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -1074,8 +1072,9 @@
 				struct ethtool_drvinfo *info)
 {
 	pegasus_t *pegasus = netdev_priv(dev);
-	strncpy(info->driver, driver_name, sizeof(info->driver) - 1);
-	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+
+	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
 	usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));
 }
 
@@ -1096,6 +1095,7 @@
 {
 	pegasus_t	*pegasus = netdev_priv(dev);
 	u8		reg78 = 0x04;
+	int		ret;
 
 	if (wol->wolopts & ~WOL_SUPPORTED)
 		return -EINVAL;
@@ -1110,7 +1110,12 @@
 	else
 		pegasus->eth_regs[0] &= ~0x10;
 	pegasus->wolopts = wol->wolopts;
-	return set_register(pegasus, WakeupControl, reg78);
+
+	ret = set_register(pegasus, WakeupControl, reg78);
+	if (!ret)
+		ret = device_set_wakeup_enable(&pegasus->usb->dev,
+						wol->wolopts);
+	return ret;
 }
 
 static inline void pegasus_reset_wol(struct net_device *dev)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index c8e05e2..efb5c7c 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -409,8 +409,16 @@
 					      USB_CDC_PROTO_NONE),
 		.driver_info        = (unsigned long)&qmi_wwan_info,
 	},
+	{	/* ADU960S */
+		USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a,
+					      USB_CLASS_COMM,
+					      USB_CDC_SUBCLASS_ETHERNET,
+					      USB_CDC_PROTO_NONE),
+		.driver_info        = (unsigned long)&qmi_wwan_info,
+	},
 
 	/* 3. Combined interface devices matching on interface number */
+	{QMI_FIXED_INTF(0x0408, 0xea42, 4)},	/* Yota / Megafon M100-1 */
 	{QMI_FIXED_INTF(0x12d1, 0x140c, 1)},	/* Huawei E173 */
 	{QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
 	{QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 4a433583..cc49aac 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -431,7 +431,6 @@
 		goto halt_fail_and_release;
 	}
 	memcpy(net->dev_addr, bp, ETH_ALEN);
-	memcpy(net->perm_addr, bp, ETH_ALEN);
 
 	/* set a nonzero filter to enable data transfers */
 	memset(u.set, 0, sizeof *u.set);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 5f39a3b..a491d3a 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -776,9 +776,9 @@
 {
 	rtl8150_t *dev = netdev_priv(netdev);
 
-	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
-	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-	usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
+	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+	usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
 }
 
 static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index 18dd425..79ab243 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -459,11 +459,9 @@
 
 		/* Query the modem for the LSI message */
 		buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL);
-		if (!buf) {
-			netdev_err(dev->net,
-				"failed to allocate buf for LS msg\n");
+		if (!buf)
 			return;
-		}
+
 		ifnum = priv->ifnum;
 		len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
 				USB_CDC_GET_ENCAPSULATED_RESPONSE,
@@ -598,8 +596,8 @@
 {
 	/* Inherit standard device info */
 	usbnet_get_drvinfo(net, info);
-	strncpy(info->driver, driver_name, sizeof info->driver);
-	strncpy(info->version, DRIVER_VERSION, sizeof info->version);
+	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
 }
 
 static u32 sierra_net_get_link(struct net_device *net)
@@ -686,10 +684,8 @@
 	}
 	/* Initialize sierra private data */
 	priv = kzalloc(sizeof *priv, GFP_KERNEL);
-	if (!priv) {
-		dev_err(&dev->udev->dev, "No memory");
+	if (!priv)
 		return -ENOMEM;
-	}
 
 	priv->usbnet = dev;
 	priv->ifnum = ifacenum;
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 251a335..9abe517 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1393,13 +1393,11 @@
 	}
 
 	dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv),
-		GFP_KERNEL);
+					      GFP_KERNEL);
 
 	pdata = (struct smsc75xx_priv *)(dev->data[0]);
-	if (!pdata) {
-		netdev_warn(dev->net, "Unable to allocate smsc75xx_priv\n");
+	if (!pdata)
 		return -ENOMEM;
-	}
 
 	pdata->dev = dev;
 
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 9b73670..ff4fa37 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -55,6 +55,13 @@
 #define FEATURE_PHY_NLP_CROSSOVER	(0x02)
 #define FEATURE_AUTOSUSPEND		(0x04)
 
+#define SUSPEND_SUSPEND0		(0x01)
+#define SUSPEND_SUSPEND1		(0x02)
+#define SUSPEND_SUSPEND2		(0x04)
+#define SUSPEND_SUSPEND3		(0x08)
+#define SUSPEND_ALLMODES		(SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
+					 SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
+
 struct smsc95xx_priv {
 	u32 mac_cr;
 	u32 hash_hi;
@@ -62,6 +69,7 @@
 	u32 wolopts;
 	spinlock_t mac_cr_lock;
 	u8 features;
+	u8 suspend_flags;
 };
 
 static bool turbo_mode = true;
@@ -513,10 +521,8 @@
 	u32 flow, afc_cfg = 0;
 
 	int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading AFC_CFG\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	if (duplex == DUPLEX_FULL) {
 		u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
@@ -541,16 +547,10 @@
 	}
 
 	ret = smsc95xx_write_reg(dev, FLOW, flow);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing FLOW\n");
-		return ret;
-	}
-
-	ret = smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
 	if (ret < 0)
-		netdev_warn(dev->net, "Error writing AFC_CFG\n");
+		return ret;
 
-	return ret;
+	return smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
 }
 
 static int smsc95xx_link_reset(struct usbnet *dev)
@@ -564,16 +564,12 @@
 
 	/* clear interrupt status */
 	ret = smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing INT_STS\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	mii_check_media(mii, 1, 1);
 	mii_ethtool_gset(&dev->mii, &ecmd);
@@ -595,10 +591,8 @@
 	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
 	ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing MAC_CR\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
 	if (ret < 0)
@@ -638,10 +632,8 @@
 	int ret;
 
 	ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	if (features & NETIF_F_HW_CSUM)
 		read_buf |= Tx_COE_EN_;
@@ -654,10 +646,8 @@
 		read_buf &= ~Rx_COE_EN_;
 
 	ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
 	return 0;
@@ -800,16 +790,10 @@
 	int ret;
 
 	ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret);
-		return ret;
-	}
-
-	ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
 	if (ret < 0)
-		netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret);
+		return ret;
 
-	return ret;
+	return smsc95xx_write_reg(dev, ADDRH, addr_hi);
 }
 
 /* starts the TX path */
@@ -825,17 +809,11 @@
 	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
 	ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Enable Tx at SCSRs */
-	ret = smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
-	if (ret < 0)
-		netdev_warn(dev->net, "Failed to write TX_CFG: %d\n", ret);
-
-	return ret;
+	return smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
 }
 
 /* Starts the Receive path */
@@ -843,17 +821,12 @@
 {
 	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
 	unsigned long flags;
-	int ret;
 
 	spin_lock_irqsave(&pdata->mac_cr_lock, flags);
 	pdata->mac_cr |= MAC_CR_RXEN_;
 	spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
-	ret = __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
-	if (ret < 0)
-		netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
-
-	return ret;
+	return __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
 }
 
 static int smsc95xx_phy_initialize(struct usbnet *dev)
@@ -910,19 +883,15 @@
 	netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
 
 	ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	timeout = 0;
 	do {
 		msleep(10);
 		ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+		if (ret < 0)
 			return ret;
-		}
 		timeout++;
 	} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
 
@@ -932,19 +901,15 @@
 	}
 
 	ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	timeout = 0;
 	do {
 		msleep(10);
 		ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
+		if (ret < 0)
 			return ret;
-		}
 		timeout++;
 	} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
 
@@ -961,10 +926,8 @@
 		  dev->net->dev_addr);
 
 	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
 		  read_buf);
@@ -972,16 +935,12 @@
 	read_buf |= HW_CFG_BIR_;
 
 	ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, ifup, dev->net,
 		  "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
@@ -1002,42 +961,32 @@
 		  (ulong)dev->rx_urb_size);
 
 	ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, ifup, dev->net,
 		  "Read Value from BURST_CAP after writing: 0x%08x\n",
 		  read_buf);
 
 	ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, ifup, dev->net,
 		  "Read Value from BULK_IN_DLY after writing: 0x%08x\n",
 		  read_buf);
 
 	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG: 0x%08x\n",
 		  read_buf);
@@ -1051,69 +1000,51 @@
 	read_buf |= NET_IP_ALIGN << 9;
 
 	ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	netif_dbg(dev, ifup, dev->net,
 		  "Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
 
 	ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 	netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
 
 	/* Configure GPIO pins as LED outputs */
 	write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
 		LED_GPIO_CFG_FDX_LED;
 	ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Init Tx */
 	ret = smsc95xx_write_reg(dev, FLOW, 0);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Don't need mac_cr_lock during initialisation */
 	ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Init Rx */
 	/* Set Vlan */
 	ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write VLAN1: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Enable or disable checksum offload engines */
 	ret = smsc95xx_set_features(dev->net, dev->net->features);
@@ -1131,19 +1062,15 @@
 	}
 
 	ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* enable PHY interrupts */
 	read_buf |= INT_EP_CTL_PHY_INT_;
 
 	ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_start_tx_path(dev);
 	if (ret < 0) {
@@ -1189,13 +1116,11 @@
 	}
 
 	dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv),
-		GFP_KERNEL);
+					      GFP_KERNEL);
 
 	pdata = (struct smsc95xx_priv *)(dev->data[0]);
-	if (!pdata) {
-		netdev_warn(dev->net, "Unable to allocate struct smsc95xx_priv\n");
+	if (!pdata)
 		return -ENOMEM;
-	}
 
 	spin_lock_init(&pdata->mac_cr_lock);
 
@@ -1213,10 +1138,8 @@
 
 	/* detect device revision as different features may be available */
 	ret = smsc95xx_read_reg(dev, ID_REV, &val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+	if (ret < 0)
 		return ret;
-	}
 	val >>= 16;
 
 	if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9530_) ||
@@ -1261,17 +1184,13 @@
 
 	/* read to clear */
 	ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	/* enable interrupt source */
 	ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PHY_INT_MASK\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret |= mask;
 
@@ -1287,16 +1206,12 @@
 
 	/* first, a dummy read, needed to latch some MII phys */
 	ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading MII_BMSR\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading MII_BMSR\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	return !!(ret & BMSR_LSTATUS);
 }
@@ -1308,19 +1223,15 @@
 	int ret;
 
 	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PM_CTRL\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
 	val |= PM_CTL_SUS_MODE_0;
 
 	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing PM_CTRL\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	/* clear wol status */
 	val &= ~PM_CTL_WUPS_;
@@ -1331,15 +1242,13 @@
 		val |= PM_CTL_WUPS_ED_;
 
 	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing PM_CTRL\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	/* read back PM_CTRL */
 	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-	if (ret < 0)
-		netdev_warn(dev->net, "Error reading PM_CTRL\n");
+
+	pdata->suspend_flags |= SUSPEND_SUSPEND0;
 
 	return ret;
 }
@@ -1360,10 +1269,8 @@
 
 	/* enable energy detect power-down mode */
 	ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	ret |= MODE_CTRL_STS_EDPWRDOWN_;
 
@@ -1371,52 +1278,133 @@
 
 	/* enter SUSPEND1 mode */
 	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PM_CTRL\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
 	val |= PM_CTL_SUS_MODE_1;
 
 	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing PM_CTRL\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	/* clear wol status, enable energy detection */
 	val &= ~PM_CTL_WUPS_;
 	val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_);
 
 	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-	if (ret < 0)
-		netdev_warn(dev->net, "Error writing PM_CTRL\n");
+
+	pdata->suspend_flags |= SUSPEND_SUSPEND1;
 
 	return ret;
 }
 
 static int smsc95xx_enter_suspend2(struct usbnet *dev)
 {
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
 	u32 val;
 	int ret;
 
 	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PM_CTRL\n");
+	if (ret < 0)
 		return ret;
-	}
 
 	val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
 	val |= PM_CTL_SUS_MODE_2;
 
 	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-	if (ret < 0)
-		netdev_warn(dev->net, "Error writing PM_CTRL\n");
+
+	pdata->suspend_flags |= SUSPEND_SUSPEND2;
 
 	return ret;
 }
 
+static int smsc95xx_enter_suspend3(struct usbnet *dev)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	u32 val;
+	int ret;
+
+	ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val & 0xFFFF) {
+		netdev_info(dev->net, "rx fifo not empty in autosuspend\n");
+		return -EBUSY;
+	}
+
+	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
+	val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
+
+	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+	if (ret < 0)
+		return ret;
+
+	/* clear wol status */
+	val &= ~PM_CTL_WUPS_;
+	val |= PM_CTL_WUPS_WOL_;
+
+	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+	if (ret < 0)
+		return ret;
+
+	pdata->suspend_flags |= SUSPEND_SUSPEND3;
+
+	return 0;
+}
+
+static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	int ret;
+
+	if (!netif_running(dev->net)) {
+		/* interface is ifconfig down so fully power down hw */
+		netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
+		return smsc95xx_enter_suspend2(dev);
+	}
+
+	if (!link_up) {
+		/* link is down so enter EDPD mode, but only if device can
+		 * reliably resume from it.  This check should be redundant
+		 * as current FEATURE_AUTOSUSPEND parts also support
+		 * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */
+		if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) {
+			netdev_warn(dev->net, "EDPD not supported\n");
+			return -EBUSY;
+		}
+
+		netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
+
+		/* enable PHY wakeup events for if cable is attached */
+		ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
+			PHY_INT_MASK_ANEG_COMP_);
+		if (ret < 0) {
+			netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+			return ret;
+		}
+
+		netdev_info(dev->net, "entering SUSPEND1 mode\n");
+		return smsc95xx_enter_suspend1(dev);
+	}
+
+	/* enable PHY wakeup events so we remote wakeup if cable is pulled */
+	ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
+		PHY_INT_MASK_LINK_DOWN_);
+	if (ret < 0) {
+		netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+		return ret;
+	}
+
+	netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
+	return smsc95xx_enter_suspend3(dev);
+}
+
 static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
 {
 	struct usbnet *dev = usb_get_intfdata(intf);
@@ -1424,15 +1412,35 @@
 	u32 val, link_up;
 	int ret;
 
+	/* TODO: don't indicate this feature to usb framework if
+	 * our current hardware doesn't have the capability
+	 */
+	if ((message.event == PM_EVENT_AUTO_SUSPEND) &&
+	    (!(pdata->features & FEATURE_AUTOSUSPEND))) {
+		netdev_warn(dev->net, "autosuspend not supported\n");
+		return -EBUSY;
+	}
+
 	ret = usbnet_suspend(intf, message);
 	if (ret < 0) {
 		netdev_warn(dev->net, "usbnet_suspend error\n");
 		return ret;
 	}
 
+	if (pdata->suspend_flags) {
+		netdev_warn(dev->net, "error during last resume\n");
+		pdata->suspend_flags = 0;
+	}
+
 	/* determine if link is up using only _nopm functions */
 	link_up = smsc95xx_link_ok_nopm(dev);
 
+	if (message.event == PM_EVENT_AUTO_SUSPEND) {
+		ret = smsc95xx_autosuspend(dev, link_up);
+		goto done;
+	}
+
+	/* if we get this far we're not autosuspending */
 	/* if no wol options set, or if link is down and we're not waking on
 	 * PHY activity, enter lowest power SUSPEND2 mode
 	 */
@@ -1442,32 +1450,24 @@
 
 		/* disable energy detect (link up) & wake up events */
 		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error reading WUCSR\n");
+		if (ret < 0)
 			goto done;
-		}
 
 		val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
 
 		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error writing WUCSR\n");
+		if (ret < 0)
 			goto done;
-		}
 
 		ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error reading PM_CTRL\n");
+		if (ret < 0)
 			goto done;
-		}
 
 		val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
 
 		ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error writing PM_CTRL\n");
+		if (ret < 0)
 			goto done;
-		}
 
 		ret = smsc95xx_enter_suspend2(dev);
 		goto done;
@@ -1565,7 +1565,6 @@
 		for (i = 0; i < (wuff_filter_count * 4); i++) {
 			ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
 			if (ret < 0) {
-				netdev_warn(dev->net, "Error writing WUFF\n");
 				kfree(filter_mask);
 				goto done;
 			}
@@ -1574,67 +1573,51 @@
 
 		for (i = 0; i < (wuff_filter_count / 4); i++) {
 			ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
-			if (ret < 0) {
-				netdev_warn(dev->net, "Error writing WUFF\n");
+			if (ret < 0)
 				goto done;
-			}
 		}
 
 		for (i = 0; i < (wuff_filter_count / 4); i++) {
 			ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
-			if (ret < 0) {
-				netdev_warn(dev->net, "Error writing WUFF\n");
+			if (ret < 0)
 				goto done;
-			}
 		}
 
 		for (i = 0; i < (wuff_filter_count / 2); i++) {
 			ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
-			if (ret < 0) {
-				netdev_warn(dev->net, "Error writing WUFF\n");
+			if (ret < 0)
 				goto done;
-			}
 		}
 
 		/* clear any pending pattern match packet status */
 		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error reading WUCSR\n");
+		if (ret < 0)
 			goto done;
-		}
 
 		val |= WUCSR_WUFR_;
 
 		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error writing WUCSR\n");
+		if (ret < 0)
 			goto done;
-		}
 	}
 
 	if (pdata->wolopts & WAKE_MAGIC) {
 		/* clear any pending magic packet status */
 		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error reading WUCSR\n");
+		if (ret < 0)
 			goto done;
-		}
 
 		val |= WUCSR_MPR_;
 
 		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error writing WUCSR\n");
+		if (ret < 0)
 			goto done;
-		}
 	}
 
 	/* enable/disable wakeup sources */
 	ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading WUCSR\n");
+	if (ret < 0)
 		goto done;
-	}
 
 	if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
 		netdev_info(dev->net, "enabling pattern match wakeup\n");
@@ -1653,17 +1636,13 @@
 	}
 
 	ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing WUCSR\n");
+	if (ret < 0)
 		goto done;
-	}
 
 	/* enable wol wakeup source */
 	ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error reading PM_CTRL\n");
+	if (ret < 0)
 		goto done;
-	}
 
 	val |= PM_CTL_WOL_EN_;
 
@@ -1672,10 +1651,8 @@
 		val |= PM_CTL_ED_EN_;
 
 	ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-	if (ret < 0) {
-		netdev_warn(dev->net, "Error writing PM_CTRL\n");
+	if (ret < 0)
 		goto done;
-	}
 
 	/* enable receiver to enable frame reception */
 	smsc95xx_start_rx_path(dev, 1);
@@ -1694,42 +1671,40 @@
 {
 	struct usbnet *dev = usb_get_intfdata(intf);
 	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+	u8 suspend_flags = pdata->suspend_flags;
 	int ret;
 	u32 val;
 
 	BUG_ON(!dev);
 
-	if (pdata->wolopts) {
+	netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
+
+	/* do this first to ensure it's cleared even in error case */
+	pdata->suspend_flags = 0;
+
+	if (suspend_flags & SUSPEND_ALLMODES) {
 		/* clear wake-up sources */
 		ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error reading WUCSR\n");
+		if (ret < 0)
 			return ret;
-		}
 
 		val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
 
 		ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error writing WUCSR\n");
+		if (ret < 0)
 			return ret;
-		}
 
 		/* clear wake-up status */
 		ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error reading PM_CTRL\n");
+		if (ret < 0)
 			return ret;
-		}
 
 		val &= ~PM_CTL_WOL_EN_;
 		val |= PM_CTL_WUPS_;
 
 		ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-		if (ret < 0) {
-			netdev_warn(dev->net, "Error writing PM_CTRL\n");
+		if (ret < 0)
 			return ret;
-		}
 	}
 
 	ret = usbnet_resume(intf);
@@ -1891,6 +1866,26 @@
 	return skb;
 }
 
+static int smsc95xx_manage_power(struct usbnet *dev, int on)
+{
+	struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+	dev->intf->needs_remote_wakeup = on;
+
+	if (pdata->features & FEATURE_AUTOSUSPEND)
+		return 0;
+
+	/* this chip revision doesn't support autosuspend */
+	netdev_info(dev->net, "hardware doesn't support USB autosuspend\n");
+
+	if (on)
+		usb_autopm_get_interface_no_resume(dev->intf);
+	else
+		usb_autopm_put_interface(dev->intf);
+
+	return 0;
+}
+
 static const struct driver_info smsc95xx_info = {
 	.description	= "smsc95xx USB 2.0 Ethernet",
 	.bind		= smsc95xx_bind,
@@ -1900,6 +1895,7 @@
 	.rx_fixup	= smsc95xx_rx_fixup,
 	.tx_fixup	= smsc95xx_tx_fixup,
 	.status		= smsc95xx_status,
+	.manage_power	= smsc95xx_manage_power,
 	.flags		= FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
 };
 
@@ -2007,6 +2003,7 @@
 	.reset_resume	= smsc95xx_resume,
 	.disconnect	= usbnet_disconnect,
 	.disable_hub_initiated_lpm = 1,
+	.supports_autosuspend = 1,
 };
 
 module_usb_driver(smsc95xx_driver);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 5e33606..51f3192 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1813,11 +1813,8 @@
 	}
 
 	req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
-	if (!req) {
-		netdev_err(dev->net, "Failed to allocate memory for %s\n",
-			   __func__);
+	if (!req)
 		goto fail_free_buf;
-	}
 
 	req->bRequestType = reqtype;
 	req->bRequest = cmd;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 95814d9..07a4af0 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -25,18 +25,15 @@
 #define MIN_MTU 68		/* Min L3 MTU */
 #define MAX_MTU 65535		/* Max L3 MTU (arbitrary) */
 
-struct veth_net_stats {
-	u64			rx_packets;
-	u64			rx_bytes;
-	u64			tx_packets;
-	u64			tx_bytes;
-	u64			rx_dropped;
+struct pcpu_vstats {
+	u64			packets;
+	u64			bytes;
 	struct u64_stats_sync	syncp;
 };
 
 struct veth_priv {
-	struct net_device *peer;
-	struct veth_net_stats __percpu *stats;
+	struct net_device __rcu	*peer;
+	atomic64_t		dropped;
 };
 
 /*
@@ -92,10 +89,10 @@
 static void veth_get_ethtool_stats(struct net_device *dev,
 		struct ethtool_stats *stats, u64 *data)
 {
-	struct veth_priv *priv;
+	struct veth_priv *priv = netdev_priv(dev);
+	struct net_device *peer = rtnl_dereference(priv->peer);
 
-	priv = netdev_priv(dev);
-	data[0] = priv->peer->ifindex;
+	data[0] = peer ? peer->ifindex : 0;
 }
 
 static const struct ethtool_ops veth_ethtool_ops = {
@@ -107,50 +104,37 @@
 	.get_ethtool_stats	= veth_get_ethtool_stats,
 };
 
-/*
- * xmit
- */
-
 static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_device *rcv = NULL;
-	struct veth_priv *priv, *rcv_priv;
-	struct veth_net_stats *stats, *rcv_stats;
-	int length;
+	struct veth_priv *priv = netdev_priv(dev);
+	struct net_device *rcv;
+	int length = skb->len;
 
-	priv = netdev_priv(dev);
-	rcv = priv->peer;
-	rcv_priv = netdev_priv(rcv);
-
-	stats = this_cpu_ptr(priv->stats);
-	rcv_stats = this_cpu_ptr(rcv_priv->stats);
-
+	rcu_read_lock();
+	rcv = rcu_dereference(priv->peer);
+	if (unlikely(!rcv)) {
+		kfree_skb(skb);
+		goto drop;
+	}
 	/* don't change ip_summed == CHECKSUM_PARTIAL, as that
-	   will cause bad checksum on forwarded packets */
+	 * will cause bad checksum on forwarded packets
+	 */
 	if (skb->ip_summed == CHECKSUM_NONE &&
 	    rcv->features & NETIF_F_RXCSUM)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-	length = skb->len;
-	if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS)
-		goto rx_drop;
+	if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
+		struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
 
-	u64_stats_update_begin(&stats->syncp);
-	stats->tx_bytes += length;
-	stats->tx_packets++;
-	u64_stats_update_end(&stats->syncp);
-
-	u64_stats_update_begin(&rcv_stats->syncp);
-	rcv_stats->rx_bytes += length;
-	rcv_stats->rx_packets++;
-	u64_stats_update_end(&rcv_stats->syncp);
-
-	return NETDEV_TX_OK;
-
-rx_drop:
-	u64_stats_update_begin(&rcv_stats->syncp);
-	rcv_stats->rx_dropped++;
-	u64_stats_update_end(&rcv_stats->syncp);
+		u64_stats_update_begin(&stats->syncp);
+		stats->bytes += length;
+		stats->packets++;
+		u64_stats_update_end(&stats->syncp);
+	} else {
+drop:
+		atomic64_inc(&priv->dropped);
+	}
+	rcu_read_unlock();
 	return NETDEV_TX_OK;
 }
 
@@ -158,47 +142,63 @@
  * general routines
  */
 
-static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
-						  struct rtnl_link_stats64 *tot)
+static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
 {
 	struct veth_priv *priv = netdev_priv(dev);
 	int cpu;
 
+	result->packets = 0;
+	result->bytes = 0;
 	for_each_possible_cpu(cpu) {
-		struct veth_net_stats *stats = per_cpu_ptr(priv->stats, cpu);
-		u64 rx_packets, rx_bytes, rx_dropped;
-		u64 tx_packets, tx_bytes;
+		struct pcpu_vstats *stats = per_cpu_ptr(dev->vstats, cpu);
+		u64 packets, bytes;
 		unsigned int start;
 
 		do {
 			start = u64_stats_fetch_begin_bh(&stats->syncp);
-			rx_packets = stats->rx_packets;
-			tx_packets = stats->tx_packets;
-			rx_bytes = stats->rx_bytes;
-			tx_bytes = stats->tx_bytes;
-			rx_dropped = stats->rx_dropped;
+			packets = stats->packets;
+			bytes = stats->bytes;
 		} while (u64_stats_fetch_retry_bh(&stats->syncp, start));
-		tot->rx_packets += rx_packets;
-		tot->tx_packets += tx_packets;
-		tot->rx_bytes   += rx_bytes;
-		tot->tx_bytes   += tx_bytes;
-		tot->rx_dropped += rx_dropped;
+		result->packets += packets;
+		result->bytes += bytes;
 	}
+	return atomic64_read(&priv->dropped);
+}
+
+static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
+						  struct rtnl_link_stats64 *tot)
+{
+	struct veth_priv *priv = netdev_priv(dev);
+	struct net_device *peer;
+	struct pcpu_vstats one;
+
+	tot->tx_dropped = veth_stats_one(&one, dev);
+	tot->tx_bytes = one.bytes;
+	tot->tx_packets = one.packets;
+
+	rcu_read_lock();
+	peer = rcu_dereference(priv->peer);
+	if (peer) {
+		tot->rx_dropped = veth_stats_one(&one, peer);
+		tot->rx_bytes = one.bytes;
+		tot->rx_packets = one.packets;
+	}
+	rcu_read_unlock();
 
 	return tot;
 }
 
 static int veth_open(struct net_device *dev)
 {
-	struct veth_priv *priv;
+	struct veth_priv *priv = netdev_priv(dev);
+	struct net_device *peer = rtnl_dereference(priv->peer);
 
-	priv = netdev_priv(dev);
-	if (priv->peer == NULL)
+	if (!peer)
 		return -ENOTCONN;
 
-	if (priv->peer->flags & IFF_UP) {
+	if (peer->flags & IFF_UP) {
 		netif_carrier_on(dev);
-		netif_carrier_on(priv->peer);
+		netif_carrier_on(peer);
 	}
 	return 0;
 }
@@ -206,9 +206,11 @@
 static int veth_close(struct net_device *dev)
 {
 	struct veth_priv *priv = netdev_priv(dev);
+	struct net_device *peer = rtnl_dereference(priv->peer);
 
 	netif_carrier_off(dev);
-	netif_carrier_off(priv->peer);
+	if (peer)
+		netif_carrier_off(peer);
 
 	return 0;
 }
@@ -228,24 +230,16 @@
 
 static int veth_dev_init(struct net_device *dev)
 {
-	struct veth_net_stats __percpu *stats;
-	struct veth_priv *priv;
-
-	stats = alloc_percpu(struct veth_net_stats);
-	if (stats == NULL)
+	dev->vstats = alloc_percpu(struct pcpu_vstats);
+	if (!dev->vstats)
 		return -ENOMEM;
 
-	priv = netdev_priv(dev);
-	priv->stats = stats;
 	return 0;
 }
 
 static void veth_dev_free(struct net_device *dev)
 {
-	struct veth_priv *priv;
-
-	priv = netdev_priv(dev);
-	free_percpu(priv->stats);
+	free_percpu(dev->vstats);
 	free_netdev(dev);
 }
 
@@ -259,6 +253,10 @@
 	.ndo_set_mac_address = eth_mac_addr,
 };
 
+#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO |    \
+		       NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | \
+		       NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)
+
 static void veth_setup(struct net_device *dev)
 {
 	ether_setup(dev);
@@ -269,9 +267,10 @@
 	dev->netdev_ops = &veth_netdev_ops;
 	dev->ethtool_ops = &veth_ethtool_ops;
 	dev->features |= NETIF_F_LLTX;
+	dev->features |= VETH_FEATURES;
 	dev->destructor = veth_dev_free;
 
-	dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
+	dev->hw_features = VETH_FEATURES;
 }
 
 /*
@@ -396,10 +395,10 @@
 	 */
 
 	priv = netdev_priv(dev);
-	priv->peer = peer;
+	rcu_assign_pointer(priv->peer, peer);
 
 	priv = netdev_priv(peer);
-	priv->peer = dev;
+	rcu_assign_pointer(priv->peer, dev);
 	return 0;
 
 err_register_dev:
@@ -420,10 +419,20 @@
 	struct net_device *peer;
 
 	priv = netdev_priv(dev);
-	peer = priv->peer;
+	peer = rtnl_dereference(priv->peer);
 
+	/* Note : dellink() is called from default_device_exit_batch(),
+	 * before a rcu_synchronize() point. The devices are guaranteed
+	 * not being freed before one RCU grace period.
+	 */
+	RCU_INIT_POINTER(priv->peer, NULL);
 	unregister_netdevice_queue(dev, head);
-	unregister_netdevice_queue(peer, head);
+
+	if (peer) {
+		priv = netdev_priv(peer);
+		RCU_INIT_POINTER(priv->peer, NULL);
+		unregister_netdevice_queue(peer, head);
+	}
 }
 
 static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = {
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 35c00c5..192c91c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -227,6 +227,7 @@
 	skb->len += size;
 	skb->truesize += PAGE_SIZE;
 	skb_shinfo(skb)->nr_frags++;
+	skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
 	*len -= size;
 }
 
@@ -760,19 +761,77 @@
 	return NETDEV_TX_OK;
 }
 
+/*
+ * Send command via the control virtqueue and check status.  Commands
+ * supported by the hypervisor, as indicated by feature bits, should
+ * never fail unless improperly formated.
+ */
+static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+				 struct scatterlist *data, int out, int in)
+{
+	struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
+	struct virtio_net_ctrl_hdr ctrl;
+	virtio_net_ctrl_ack status = ~0;
+	unsigned int tmp;
+	int i;
+
+	/* Caller should know better */
+	BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ||
+		(out + in > VIRTNET_SEND_COMMAND_SG_MAX));
+
+	out++; /* Add header */
+	in++; /* Add return status */
+
+	ctrl.class = class;
+	ctrl.cmd = cmd;
+
+	sg_init_table(sg, out + in);
+
+	sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
+	for_each_sg(data, s, out + in - 2, i)
+		sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
+	sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
+
+	BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
+
+	virtqueue_kick(vi->cvq);
+
+	/* Spin for a response, the kick causes an ioport write, trapping
+	 * into the hypervisor, so the request should be handled immediately.
+	 */
+	while (!virtqueue_get_buf(vi->cvq, &tmp))
+		cpu_relax();
+
+	return status == VIRTIO_NET_OK;
+}
+
 static int virtnet_set_mac_address(struct net_device *dev, void *p)
 {
 	struct virtnet_info *vi = netdev_priv(dev);
 	struct virtio_device *vdev = vi->vdev;
 	int ret;
+	struct sockaddr *addr = p;
+	struct scatterlist sg;
 
-	ret = eth_mac_addr(dev, p);
+	ret = eth_prepare_mac_addr_change(dev, p);
 	if (ret)
 		return ret;
 
-	if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
+	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
+		sg_init_one(&sg, addr->sa_data, dev->addr_len);
+		if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
+					  VIRTIO_NET_CTRL_MAC_ADDR_SET,
+					  &sg, 1, 0)) {
+			dev_warn(&vdev->dev,
+				 "Failed to set mac address by vq command.\n");
+			return -EINVAL;
+		}
+	} else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
 		vdev->config->set(vdev, offsetof(struct virtio_net_config, mac),
-		                  dev->dev_addr, dev->addr_len);
+				  addr->sa_data, dev->addr_len);
+	}
+
+	eth_commit_mac_addr_change(dev, p);
 
 	return 0;
 }
@@ -826,51 +885,6 @@
 }
 #endif
 
-/*
- * Send command via the control virtqueue and check status.  Commands
- * supported by the hypervisor, as indicated by feature bits, should
- * never fail unless improperly formated.
- */
-static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
-				 struct scatterlist *data, int out, int in)
-{
-	struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
-	struct virtio_net_ctrl_hdr ctrl;
-	virtio_net_ctrl_ack status = ~0;
-	unsigned int tmp;
-	int i;
-
-	/* Caller should know better */
-	BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ||
-		(out + in > VIRTNET_SEND_COMMAND_SG_MAX));
-
-	out++; /* Add header */
-	in++; /* Add return status */
-
-	ctrl.class = class;
-	ctrl.cmd = cmd;
-
-	sg_init_table(sg, out + in);
-
-	sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
-	for_each_sg(data, s, out + in - 2, i)
-		sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
-	sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
-
-	BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
-
-	virtqueue_kick(vi->cvq);
-
-	/*
-	 * Spin for a response, the kick causes an ioport write, trapping
-	 * into the hypervisor, so the request should be handled immediately.
-	 */
-	while (!virtqueue_get_buf(vi->cvq, &tmp))
-		cpu_relax();
-
-	return status == VIRTIO_NET_OK;
-}
-
 static void virtnet_ack_link_announce(struct virtnet_info *vi)
 {
 	rtnl_lock();
@@ -959,10 +973,8 @@
 	buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) +
 		      (2 * sizeof(mac_data->entries)), GFP_ATOMIC);
 	mac_data = buf;
-	if (!buf) {
-		dev_warn(&dev->dev, "No memory for MAC address buffer\n");
+	if (!buf)
 		return;
-	}
 
 	sg_init_table(sg, 2);
 
@@ -1706,6 +1718,7 @@
 	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
 	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
 	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
+	VIRTIO_NET_F_CTRL_MAC_ADDR,
 };
 
 static struct virtio_driver virtio_net_driver = {
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 12c6440..ffb97b2 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -43,11 +43,7 @@
 
 MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
 
-static atomic_t devices_found;
-
-#define VMXNET3_MAX_DEVICES 10
 static int enable_mq = 1;
-static int irq_share_mode;
 
 static void
 vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac);
@@ -152,8 +148,8 @@
 
 	adapter->link_speed = ret >> 16;
 	if (ret & 1) { /* Link is up. */
-		printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
-		       adapter->netdev->name, adapter->link_speed);
+		netdev_info(adapter->netdev, "NIC Link is Up %d Mbps\n",
+			    adapter->link_speed);
 		netif_carrier_on(adapter->netdev);
 
 		if (affectTxQueue) {
@@ -162,8 +158,7 @@
 						 adapter);
 		}
 	} else {
-		printk(KERN_INFO "%s: NIC Link is Down\n",
-		       adapter->netdev->name);
+		netdev_info(adapter->netdev, "NIC Link is Down\n");
 		netif_carrier_off(adapter->netdev);
 
 		if (affectTxQueue) {
@@ -508,8 +503,7 @@
 			   * sizeof(struct Vmxnet3_TxDesc),
 			   &tq->tx_ring.basePA);
 	if (!tq->tx_ring.base) {
-		printk(KERN_ERR "%s: failed to allocate tx ring\n",
-		       adapter->netdev->name);
+		netdev_err(adapter->netdev, "failed to allocate tx ring\n");
 		goto err;
 	}
 
@@ -518,8 +512,7 @@
 			     sizeof(struct Vmxnet3_TxDataDesc),
 			     &tq->data_ring.basePA);
 	if (!tq->data_ring.base) {
-		printk(KERN_ERR "%s: failed to allocate data ring\n",
-		       adapter->netdev->name);
+		netdev_err(adapter->netdev, "failed to allocate data ring\n");
 		goto err;
 	}
 
@@ -528,8 +521,7 @@
 			     sizeof(struct Vmxnet3_TxCompDesc),
 			     &tq->comp_ring.basePA);
 	if (!tq->comp_ring.base) {
-		printk(KERN_ERR "%s: failed to allocate tx comp ring\n",
-		       adapter->netdev->name);
+		netdev_err(adapter->netdev, "failed to allocate tx comp ring\n");
 		goto err;
 	}
 
@@ -578,15 +570,14 @@
 
 		if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
 			if (rbi->skb == NULL) {
-				rbi->skb = dev_alloc_skb(rbi->len +
-							 NET_IP_ALIGN);
+				rbi->skb = __netdev_alloc_skb_ip_align(adapter->netdev,
+								       rbi->len,
+								       GFP_KERNEL);
 				if (unlikely(rbi->skb == NULL)) {
 					rq->stats.rx_buf_alloc_failure++;
 					break;
 				}
-				rbi->skb->dev = adapter->netdev;
 
-				skb_reserve(rbi->skb, NET_IP_ALIGN);
 				rbi->dma_addr = pci_map_single(adapter->pdev,
 						rbi->skb->data, rbi->len,
 						PCI_DMA_FROMDEVICE);
@@ -627,12 +618,10 @@
 		num_allocated++;
 		vmxnet3_cmd_ring_adv_next2fill(ring);
 	}
-	rq->uncommitted[ring_idx] += num_allocated;
 
-	dev_dbg(&adapter->netdev->dev,
-		"alloc_rx_buf: %d allocated, next2fill %u, next2comp "
-		"%u, uncommitted %u\n", num_allocated, ring->next2fill,
-		ring->next2comp, rq->uncommitted[ring_idx]);
+	netdev_dbg(adapter->netdev,
+		"alloc_rx_buf: %d allocated, next2fill %u, next2comp %u\n",
+		num_allocated, ring->next2fill, ring->next2comp);
 
 	/* so that the device can distinguish a full ring and an empty ring */
 	BUG_ON(num_allocated != 0 && ring->next2fill == ring->next2comp);
@@ -689,7 +678,7 @@
 		tbi = tq->buf_info + tq->tx_ring.next2fill;
 		tbi->map_type = VMXNET3_MAP_NONE;
 
-		dev_dbg(&adapter->netdev->dev,
+		netdev_dbg(adapter->netdev,
 			"txd[%u]: 0x%Lx 0x%x 0x%x\n",
 			tq->tx_ring.next2fill,
 			le64_to_cpu(ctx->sop_txd->txd.addr),
@@ -729,7 +718,7 @@
 		gdesc->dword[2] = cpu_to_le32(dw2);
 		gdesc->dword[3] = 0;
 
-		dev_dbg(&adapter->netdev->dev,
+		netdev_dbg(adapter->netdev,
 			"txd[%u]: 0x%Lx 0x%x 0x%x\n",
 			tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
 			le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
@@ -769,7 +758,7 @@
 			gdesc->dword[2] = cpu_to_le32(dw2);
 			gdesc->dword[3] = 0;
 
-			dev_dbg(&adapter->netdev->dev,
+			netdev_dbg(adapter->netdev,
 				"txd[%u]: 0x%llu %u %u\n",
 				tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
 				le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
@@ -869,7 +858,7 @@
 	tdd = tq->data_ring.base + tq->tx_ring.next2fill;
 
 	memcpy(tdd->data, skb->data, ctx->copy_size);
-	dev_dbg(&adapter->netdev->dev,
+	netdev_dbg(adapter->netdev,
 		"copy %u bytes to dataRing[%u]\n",
 		ctx->copy_size, tq->tx_ring.next2fill);
 	return 1;
@@ -975,7 +964,7 @@
 
 	if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
 		tq->stats.tx_ring_full++;
-		dev_dbg(&adapter->netdev->dev,
+		netdev_dbg(adapter->netdev,
 			"tx queue stopped on %s, next2comp %u"
 			" next2fill %u\n", adapter->netdev->name,
 			tq->tx_ring.next2comp, tq->tx_ring.next2fill);
@@ -1058,7 +1047,7 @@
 			   (struct Vmxnet3_TxDesc *)ctx.sop_txd);
 	gdesc = ctx.sop_txd;
 #endif
-	dev_dbg(&adapter->netdev->dev,
+	netdev_dbg(adapter->netdev,
 		"txd[%u]: SOP 0x%Lx 0x%x 0x%x\n",
 		(u32)(ctx.sop_txd -
 		tq->tx_ring.base), le64_to_cpu(gdesc->txd.addr),
@@ -1211,7 +1200,7 @@
 			if (unlikely(rcd->len == 0)) {
 				/* Pretend the rx buffer is skipped. */
 				BUG_ON(!(rcd->sop && rcd->eop));
-				dev_dbg(&adapter->netdev->dev,
+				netdev_dbg(adapter->netdev,
 					"rxRing[%u][%u] 0 length\n",
 					ring_idx, idx);
 				goto rcd_done;
@@ -1219,7 +1208,8 @@
 
 			skip_page_frags = false;
 			ctx->skb = rbi->skb;
-			new_skb = dev_alloc_skb(rbi->len + NET_IP_ALIGN);
+			new_skb = netdev_alloc_skb_ip_align(adapter->netdev,
+							    rbi->len);
 			if (new_skb == NULL) {
 				/* Skb allocation failed, do not handover this
 				 * skb to stack. Reuse it. Drop the existing pkt
@@ -1234,11 +1224,14 @@
 			pci_unmap_single(adapter->pdev, rbi->dma_addr, rbi->len,
 					 PCI_DMA_FROMDEVICE);
 
+#ifdef VMXNET3_RSS
+			if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE &&
+			    (adapter->netdev->features & NETIF_F_RXHASH))
+				ctx->skb->rxhash = le32_to_cpu(rcd->rssHash);
+#endif
 			skb_put(ctx->skb, rcd->len);
 
 			/* Immediate refill */
-			new_skb->dev = adapter->netdev;
-			skb_reserve(new_skb, NET_IP_ALIGN);
 			rbi->skb = new_skb;
 			rbi->dma_addr = pci_map_single(adapter->pdev,
 						       rbi->skb->data, rbi->len,
@@ -1331,7 +1324,6 @@
 			VMXNET3_WRITE_BAR0_REG(adapter,
 					       rxprod_reg[ring_idx] + rq->qid * 8,
 					       ring->next2fill);
-			rq->uncommitted[ring_idx] = 0;
 		}
 
 		vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
@@ -1376,7 +1368,6 @@
 		rq->rx_ring[ring_idx].gen = VMXNET3_INIT_GEN;
 		rq->rx_ring[ring_idx].next2fill =
 					rq->rx_ring[ring_idx].next2comp = 0;
-		rq->uncommitted[ring_idx] = 0;
 	}
 
 	rq->comp_ring.gen = VMXNET3_INIT_GEN;
@@ -1457,7 +1448,6 @@
 	/* reset internal state and allocate buffers for both rings */
 	for (i = 0; i < 2; i++) {
 		rq->rx_ring[i].next2fill = rq->rx_ring[i].next2comp = 0;
-		rq->uncommitted[i] = 0;
 
 		memset(rq->rx_ring[i].base, 0, rq->rx_ring[i].size *
 		       sizeof(struct Vmxnet3_RxDesc));
@@ -1516,8 +1506,8 @@
 		rq->rx_ring[i].base = pci_alloc_consistent(adapter->pdev, sz,
 							&rq->rx_ring[i].basePA);
 		if (!rq->rx_ring[i].base) {
-			printk(KERN_ERR "%s: failed to allocate rx ring %d\n",
-			       adapter->netdev->name, i);
+			netdev_err(adapter->netdev,
+				   "failed to allocate rx ring %d\n", i);
 			goto err;
 		}
 	}
@@ -1526,8 +1516,7 @@
 	rq->comp_ring.base = pci_alloc_consistent(adapter->pdev, sz,
 						  &rq->comp_ring.basePA);
 	if (!rq->comp_ring.base) {
-		printk(KERN_ERR "%s: failed to allocate rx comp ring\n",
-		       adapter->netdev->name);
+		netdev_err(adapter->netdev, "failed to allocate rx comp ring\n");
 		goto err;
 	}
 
@@ -1819,9 +1808,10 @@
 					  adapter->rx_queue[i].name,
 					  &(adapter->rx_queue[i]));
 			if (err) {
-				printk(KERN_ERR "Failed to request irq for MSIX"
-				       ", %s, error %d\n",
-				       adapter->rx_queue[i].name, err);
+				netdev_err(adapter->netdev,
+					   "Failed to request irq for MSIX, "
+					   "%s, error %d\n",
+					   adapter->rx_queue[i].name, err);
 				return err;
 			}
 
@@ -1850,8 +1840,9 @@
 #endif
 	intr->num_intrs = vector + 1;
 	if (err) {
-		printk(KERN_ERR "Failed to request irq %s (intr type:%d), error"
-		       ":%d\n", adapter->netdev->name, intr->type, err);
+		netdev_err(adapter->netdev,
+			   "Failed to request irq (intr type:%d), error %d\n",
+			   intr->type, err);
 	} else {
 		/* Number of rx queues will not change after this */
 		for (i = 0; i < adapter->num_rx_queues; i++) {
@@ -1872,9 +1863,9 @@
 			adapter->rx_queue[0].comp_ring.intr_idx = 0;
 		}
 
-		printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors "
-		       "allocated\n", adapter->netdev->name, intr->type,
-		       intr->mask_mode, intr->num_intrs);
+		netdev_info(adapter->netdev,
+			    "intr type %u, mode %u, %u vectors allocated\n",
+			    intr->type, intr->mask_mode, intr->num_intrs);
 	}
 
 	return err;
@@ -2040,8 +2031,8 @@
 				rxConf->mfTablePA = cpu_to_le64(virt_to_phys(
 						    new_table));
 			} else {
-				printk(KERN_INFO "%s: failed to copy mcast list"
-				       ", setting ALL_MULTI\n", netdev->name);
+				netdev_info(netdev, "failed to copy mcast list"
+					    ", setting ALL_MULTI\n");
 				new_mode |= VMXNET3_RXM_ALL_MULTI;
 			}
 		}
@@ -2169,6 +2160,14 @@
 
 	if (adapter->rss) {
 		struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+		static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
+			0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
+			0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
+			0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
+			0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
+			0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
+		};
+
 		devRead->misc.uptFeatures |= UPT1_F_RSS;
 		devRead->misc.numRxQueues = adapter->num_rx_queues;
 		rssConf->hashType = UPT1_RSS_HASH_TYPE_TCP_IPV4 |
@@ -2178,7 +2177,8 @@
 		rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ;
 		rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE;
 		rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
-		get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
+		memcpy(rssConf->hashKey, rss_key, sizeof(rss_key));
+
 		for (i = 0; i < rssConf->indTableSize; i++)
 			rssConf->indTable[i] = ethtool_rxfh_indir_default(
 				i, adapter->num_rx_queues);
@@ -2216,7 +2216,7 @@
 	u32 ret;
 	unsigned long flags;
 
-	dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
+	netdev_dbg(adapter->netdev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
 		" ring sizes %u %u %u\n", adapter->netdev->name,
 		adapter->skb_buf_size, adapter->rx_buf_per_pkt,
 		adapter->tx_queue[0].tx_ring.size,
@@ -2226,15 +2226,15 @@
 	vmxnet3_tq_init_all(adapter);
 	err = vmxnet3_rq_init_all(adapter);
 	if (err) {
-		printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
-		       adapter->netdev->name, err);
+		netdev_err(adapter->netdev,
+			   "Failed to init rx queue error %d\n", err);
 		goto rq_err;
 	}
 
 	err = vmxnet3_request_irqs(adapter);
 	if (err) {
-		printk(KERN_ERR "Failed to setup irq for %s: error %d\n",
-		       adapter->netdev->name, err);
+		netdev_err(adapter->netdev,
+			   "Failed to setup irq for error %d\n", err);
 		goto irq_err;
 	}
 
@@ -2251,8 +2251,8 @@
 	spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
 	if (ret != 0) {
-		printk(KERN_ERR "Failed to activate dev %s: error %u\n",
-		       adapter->netdev->name, ret);
+		netdev_err(adapter->netdev,
+			   "Failed to activate dev: error %u\n", ret);
 		err = -EINVAL;
 		goto activate_err;
 	}
@@ -2367,23 +2367,22 @@
 
 	err = pci_enable_device(pdev);
 	if (err) {
-		printk(KERN_ERR "Failed to enable adapter %s: error %d\n",
-		       pci_name(pdev), err);
+		dev_err(&pdev->dev, "Failed to enable adapter: error %d\n", err);
 		return err;
 	}
 
 	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
 		if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
-			printk(KERN_ERR "pci_set_consistent_dma_mask failed "
-			       "for adapter %s\n", pci_name(pdev));
+			dev_err(&pdev->dev,
+				"pci_set_consistent_dma_mask failed\n");
 			err = -EIO;
 			goto err_set_mask;
 		}
 		*dma64 = true;
 	} else {
 		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
-			printk(KERN_ERR "pci_set_dma_mask failed for adapter "
-			       "%s\n",	pci_name(pdev));
+			dev_err(&pdev->dev,
+				"pci_set_dma_mask failed\n");
 			err = -EIO;
 			goto err_set_mask;
 		}
@@ -2393,8 +2392,8 @@
 	err = pci_request_selected_regions(pdev, (1 << 2) - 1,
 					   vmxnet3_driver_name);
 	if (err) {
-		printk(KERN_ERR "Failed to request region for adapter %s: "
-		       "error %d\n", pci_name(pdev), err);
+		dev_err(&pdev->dev,
+			"Failed to request region for adapter: error %d\n", err);
 		goto err_set_mask;
 	}
 
@@ -2404,8 +2403,7 @@
 	mmio_len = pci_resource_len(pdev, 0);
 	adapter->hw_addr0 = ioremap(mmio_start, mmio_len);
 	if (!adapter->hw_addr0) {
-		printk(KERN_ERR "Failed to map bar0 for adapter %s\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "Failed to map bar0\n");
 		err = -EIO;
 		goto err_ioremap;
 	}
@@ -2414,8 +2412,7 @@
 	mmio_len = pci_resource_len(pdev, 1);
 	adapter->hw_addr1 = ioremap(mmio_start, mmio_len);
 	if (!adapter->hw_addr1) {
-		printk(KERN_ERR "Failed to map bar1 for adapter %s\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "Failed to map bar1\n");
 		err = -EIO;
 		goto err_bar1;
 	}
@@ -2522,12 +2519,14 @@
 		err = vmxnet3_rq_create(rq, adapter);
 		if (err) {
 			if (i == 0) {
-				printk(KERN_ERR "Could not allocate any rx"
-				       "queues. Aborting.\n");
+				netdev_err(adapter->netdev,
+					   "Could not allocate any rx queues. "
+					   "Aborting.\n");
 				goto queue_err;
 			} else {
-				printk(KERN_INFO "Number of rx queues changed "
-				       "to : %d.\n", i);
+				netdev_info(adapter->netdev,
+					    "Number of rx queues changed "
+					    "to : %d.\n", i);
 				adapter->num_rx_queues = i;
 				err = 0;
 				break;
@@ -2640,15 +2639,17 @@
 		vmxnet3_adjust_rx_ring_size(adapter);
 		err = vmxnet3_rq_create_all(adapter);
 		if (err) {
-			printk(KERN_ERR "%s: failed to re-create rx queues,"
-				" error %d. Closing it.\n", netdev->name, err);
+			netdev_err(netdev,
+				   "failed to re-create rx queues, "
+				   " error %d. Closing it.\n", err);
 			goto out;
 		}
 
 		err = vmxnet3_activate_dev(adapter);
 		if (err) {
-			printk(KERN_ERR "%s: failed to re-activate, error %d. "
-				"Closing it\n", netdev->name, err);
+			netdev_err(netdev,
+				   "failed to re-activate, error %d. "
+				   "Closing it\n", err);
 			goto out;
 		}
 	}
@@ -2676,10 +2677,6 @@
 	netdev->vlan_features = netdev->hw_features &
 				~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
 	netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_FILTER;
-
-	netdev_info(adapter->netdev,
-		"features: sg csum vlan jf tso tsoIPv6 lro%s\n",
-		dma64 ? " highDMA" : "");
 }
 
 
@@ -2722,7 +2719,7 @@
 			adapter->intr.num_intrs = vectors;
 			return 0;
 		} else if (err < 0) {
-			netdev_err(adapter->netdev,
+			dev_err(&adapter->netdev->dev,
 				   "Failed to enable MSI-X, error: %d\n", err);
 			vectors = 0;
 		} else if (err < vector_threshold) {
@@ -2731,15 +2728,16 @@
 			/* If fails to enable required number of MSI-x vectors
 			 * try enabling minimum number of vectors required.
 			 */
-			netdev_err(adapter->netdev,
-				   "Failed to enable %d MSI-X, trying %d instead\n",
+			dev_err(&adapter->netdev->dev,
+				"Failed to enable %d MSI-X, trying %d instead\n",
 				    vectors, vector_threshold);
 			vectors = vector_threshold;
 		}
 	}
 
-	netdev_info(adapter->netdev,
-		    "Number of MSI-X interrupts which can be allocated are lower than min threshold required.\n");
+	dev_info(&adapter->pdev->dev,
+		 "Number of MSI-X interrupts which can be allocated "
+		 "is lower than min threshold required.\n");
 	return err;
 }
 
@@ -2794,7 +2792,8 @@
 			if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
 			    || adapter->num_rx_queues != 1) {
 				adapter->share_intr = VMXNET3_INTR_TXSHARE;
-				printk(KERN_ERR "Number of rx queues : 1\n");
+				netdev_err(adapter->netdev,
+					   "Number of rx queues : 1\n");
 				adapter->num_rx_queues = 1;
 				adapter->intr.num_intrs =
 						VMXNET3_LINUX_MIN_MSIX_VECT;
@@ -2805,9 +2804,9 @@
 			return;
 
 		/* If we cannot allocate MSIx vectors use only one rx queue */
-		netdev_info(adapter->netdev,
-			    "Failed to enable MSI-X, error %d . Limiting #rx queues to 1, try MSI.\n",
-			    err);
+		dev_info(&adapter->pdev->dev,
+			 "Failed to enable MSI-X, error %d. "
+			 "Limiting #rx queues to 1, try MSI.\n", err);
 
 		adapter->intr.type = VMXNET3_IT_MSI;
 	}
@@ -2824,7 +2823,8 @@
 #endif /* CONFIG_PCI_MSI */
 
 	adapter->num_rx_queues = 1;
-	printk(KERN_INFO "Using INTx interrupt, #Rx queues: 1.\n");
+	dev_info(&adapter->netdev->dev,
+		 "Using INTx interrupt, #Rx queues: 1.\n");
 	adapter->intr.type = VMXNET3_IT_INTX;
 
 	/* INT-X related setting */
@@ -2850,7 +2850,7 @@
 	struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 	adapter->tx_timeout_count++;
 
-	printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
+	netdev_err(adapter->netdev, "tx hang\n");
 	schedule_work(&adapter->work);
 	netif_wake_queue(adapter->netdev);
 }
@@ -2870,12 +2870,12 @@
 	/* if the device is closed, we must leave it alone */
 	rtnl_lock();
 	if (netif_running(adapter->netdev)) {
-		printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
+		netdev_notice(adapter->netdev, "resetting\n");
 		vmxnet3_quiesce_dev(adapter);
 		vmxnet3_reset_dev(adapter);
 		vmxnet3_activate_dev(adapter);
 	} else {
-		printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
+		netdev_info(adapter->netdev, "already closed\n");
 	}
 	rtnl_unlock();
 
@@ -2934,8 +2934,9 @@
 	num_tx_queues = rounddown_pow_of_two(num_tx_queues);
 	netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
 				   max(num_tx_queues, num_rx_queues));
-	printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n",
-	       num_tx_queues, num_rx_queues);
+	dev_info(&pdev->dev,
+		 "# of Tx queues : %d, # of Rx queues : %d\n",
+		 num_tx_queues, num_rx_queues);
 
 	if (!netdev)
 		return -ENOMEM;
@@ -2950,8 +2951,7 @@
 					       sizeof(struct Vmxnet3_DriverShared),
 					       &adapter->shared_pa);
 	if (!adapter->shared) {
-		printk(KERN_ERR "Failed to allocate memory for %s\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "Failed to allocate memory\n");
 		err = -ENOMEM;
 		goto err_alloc_shared;
 	}
@@ -2965,8 +2965,7 @@
 						  &adapter->queue_desc_pa);
 
 	if (!adapter->tqd_start) {
-		printk(KERN_ERR "Failed to allocate memory for %s\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "Failed to allocate memory\n");
 		err = -ENOMEM;
 		goto err_alloc_queue_desc;
 	}
@@ -2996,8 +2995,8 @@
 	if (ver & 1) {
 		VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
 	} else {
-		printk(KERN_ERR "Incompatible h/w version (0x%x) for adapter"
-		       " %s\n",	ver, pci_name(pdev));
+		dev_err(&pdev->dev,
+			"Incompatible h/w version (0x%x) for adapter\n", ver);
 		err = -EBUSY;
 		goto err_ver;
 	}
@@ -3006,8 +3005,8 @@
 	if (ver & 1) {
 		VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_UVRS, 1);
 	} else {
-		printk(KERN_ERR "Incompatible upt version (0x%x) for "
-		       "adapter %s\n", ver, pci_name(pdev));
+		dev_err(&pdev->dev,
+			"Incompatible upt version (0x%x) for adapter\n", ver);
 		err = -EBUSY;
 		goto err_ver;
 	}
@@ -3015,11 +3014,9 @@
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 	vmxnet3_declare_features(adapter, dma64);
 
-	adapter->dev_number = atomic_read(&devices_found);
-
-	adapter->share_intr = irq_share_mode;
-	if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE &&
-	    adapter->num_tx_queues != adapter->num_rx_queues)
+	if (adapter->num_tx_queues == adapter->num_rx_queues)
+		adapter->share_intr = VMXNET3_INTR_BUDDYSHARE;
+	else
 		adapter->share_intr = VMXNET3_INTR_DONTSHARE;
 
 	vmxnet3_alloc_intr_resources(adapter);
@@ -3028,7 +3025,9 @@
 	if (adapter->num_rx_queues > 1 &&
 	    adapter->intr.type == VMXNET3_IT_MSIX) {
 		adapter->rss = true;
-		printk(KERN_INFO "RSS is enabled.\n");
+		netdev->hw_features |= NETIF_F_RXHASH;
+		netdev->features |= NETIF_F_RXHASH;
+		dev_dbg(&pdev->dev, "RSS is enabled.\n");
 	} else {
 		adapter->rss = false;
 	}
@@ -3063,13 +3062,11 @@
 	err = register_netdev(netdev);
 
 	if (err) {
-		printk(KERN_ERR "Failed to register adapter %s\n",
-		       pci_name(pdev));
+		dev_err(&pdev->dev, "Failed to register adapter\n");
 		goto err_register;
 	}
 
 	vmxnet3_check_link(adapter, false);
-	atomic_inc(&devices_found);
 	return 0;
 
 err_register:
@@ -3311,7 +3308,7 @@
 static int __init
 vmxnet3_init_module(void)
 {
-	printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC,
+	pr_info("%s - version %s\n", VMXNET3_DRIVER_DESC,
 		VMXNET3_DRIVER_VERSION_REPORT);
 	return pci_register_driver(&vmxnet3_driver);
 }
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 587a218..9bc542b 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -207,7 +207,7 @@
 		sizeof(drvinfo->version));
 
 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
-		ETHTOOL_BUSINFO_LEN);
+		sizeof(drvinfo->bus_info));
 	drvinfo->n_stats = vmxnet3_get_sset_count(netdev, ETH_SS_STATS);
 	drvinfo->testinfo_len = 0;
 	drvinfo->eedump_len   = 0;
@@ -522,24 +522,23 @@
 		if (err) {
 			/* failed, most likely because of OOM, try default
 			 * size */
-			printk(KERN_ERR "%s: failed to apply new sizes, try the"
-				" default ones\n", netdev->name);
+			netdev_err(netdev, "failed to apply new sizes, "
+				   "try the default ones\n");
 			err = vmxnet3_create_queues(adapter,
 						    VMXNET3_DEF_TX_RING_SIZE,
 						    VMXNET3_DEF_RX_RING_SIZE,
 						    VMXNET3_DEF_RX_RING_SIZE);
 			if (err) {
-				printk(KERN_ERR "%s: failed to create queues "
-					"with default sizes. Closing it\n",
-					netdev->name);
+				netdev_err(netdev, "failed to create queues "
+					   "with default sizes. Closing it\n");
 				goto out;
 			}
 		}
 
 		err = vmxnet3_activate_dev(adapter);
 		if (err)
-			printk(KERN_ERR "%s: failed to re-activate, error %d."
-				" Closing it\n", netdev->name, err);
+			netdev_err(netdev, "failed to re-activate, error %d."
+				   " Closing it\n", err);
 	}
 
 out:
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index fc46a81..3198384 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -276,8 +276,6 @@
 	struct vmxnet3_rx_ctx     rx_ctx;
 	u32 qid;            /* rqID in RCD for buffer from 1st ring */
 	u32 qid2;           /* rqID in RCD for buffer from 2nd ring */
-	u32 uncommitted[2]; /* # of buffers allocated since last RXPROD
-				* update */
 	struct vmxnet3_rx_buf_info     *buf_info[2];
 	struct Vmxnet3_RxQueueCtrl            *shared;
 	struct vmxnet3_rq_driver_stats  stats;
@@ -354,7 +352,6 @@
 
 	unsigned long  state;    /* VMXNET3_STATE_BIT_xxx */
 
-	int dev_number;
 	int share_intr;
 };
 
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 656230e..9d70421cf 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -29,6 +29,7 @@
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
 #include <linux/hash.h>
+#include <linux/ethtool.h>
 #include <net/arp.h>
 #include <net/ndisc.h>
 #include <net/ip.h>
@@ -392,7 +393,8 @@
 }
 
 /* Delete entry (via netlink) */
-static int vxlan_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
+static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
+			    struct net_device *dev,
 			    const unsigned char *addr)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
@@ -1271,6 +1273,18 @@
 	return 0;
 }
 
+static void vxlan_get_drvinfo(struct net_device *netdev,
+			      struct ethtool_drvinfo *drvinfo)
+{
+	strlcpy(drvinfo->version, VXLAN_VERSION, sizeof(drvinfo->version));
+	strlcpy(drvinfo->driver, "vxlan", sizeof(drvinfo->driver));
+}
+
+static const struct ethtool_ops vxlan_ethtool_ops = {
+	.get_drvinfo	= vxlan_get_drvinfo,
+	.get_link	= ethtool_op_get_link,
+};
+
 static int vxlan_newlink(struct net *net, struct net_device *dev,
 			 struct nlattr *tb[], struct nlattr *data[])
 {
@@ -1348,6 +1362,8 @@
 		vxlan->port_max = ntohs(p->high);
 	}
 
+	SET_ETHTOOL_OPS(dev, &vxlan_ethtool_ops);
+
 	err = register_netdevice(dev);
 	if (!err)
 		hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni));
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d58431e..0c077b0 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -356,60 +356,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called sdla.
 
-# Wan router core.
-config WAN_ROUTER_DRIVERS
-	tristate "WAN router drivers"
-	depends on WAN_ROUTER
-	---help---
-	  Connect LAN to WAN via Linux box.
-
-	  Select driver your card and remember to say Y to "Wan Router."
-	  You will need the wan-tools package which is available from
-	  <ftp://ftp.sangoma.com/>.
-
-	  Note that the answer to this question won't directly affect the
-	  kernel except for how subordinate drivers may be built:
-	  saying N will just cause the configurator to skip all
-	  the questions about WAN router drivers.
-
-	  If unsure, say N.
-
-config CYCLADES_SYNC
-	tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)"
-	depends on WAN_ROUTER_DRIVERS && (PCI || ISA)
-	---help---
-	  Cyclom 2X from Cyclades Corporation <http://www.avocent.com/> is an
-	  intelligent multiprotocol WAN adapter with data transfer rates up to
-	  512 Kbps. These cards support the X.25 and SNA related protocols.
-
-	  While no documentation is available at this time please grab the
-	  wanconfig tarball in
-	  <http://www.conectiva.com.br/~acme/cycsyn-devel/> (with minor changes
-	  to make it compile with the current wanrouter include files; efforts
-	  are being made to use the original package available at
-	  <ftp://ftp.sangoma.com/>).
-
-	  Feel free to contact me or the cycsyn-devel mailing list at
-	  <acme@conectiva.com.br> and <cycsyn-devel@bazar.conectiva.com.br> for
-	  additional details, I hope to have documentation available as soon as
-	  possible. (Cyclades Brazil is writing the Documentation).
-
-	  The next questions will ask you about the protocols you want the
-	  driver to support (for now only X.25 is supported).
-
-	  If you have one or more of these cards, say Y to this option.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called cyclomx.
-
-config CYCLOMX_X25
-	bool "Cyclom 2X X.25 support (EXPERIMENTAL)"
-	depends on CYCLADES_SYNC
-	help
-	  Connect a Cyclom 2X card to an X.25 network.
-
-	  Enabling X.25 support will enlarge your kernel by about 11 kB.
-
 # X.25 network drivers
 config LAPBETHER
 	tristate "LAPB over Ethernet driver (EXPERIMENTAL)"
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index df70248..c135ef4 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -5,10 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-cyclomx-y                       := cycx_main.o
-cyclomx-$(CONFIG_CYCLOMX_X25)	+= cycx_x25.o
-cyclomx-objs			:= $(cyclomx-y)  
-
 obj-$(CONFIG_HDLC)		+= hdlc.o
 obj-$(CONFIG_HDLC_RAW)		+= hdlc_raw.o
 obj-$(CONFIG_HDLC_RAW_ETH)	+= hdlc_raw_eth.o
@@ -28,7 +24,6 @@
 
 obj-$(CONFIG_DLCI)		+= dlci.o 
 obj-$(CONFIG_SDLA)		+= sdla.o
-obj-$(CONFIG_CYCLADES_SYNC)	+= cycx_drv.o cyclomx.o
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
 obj-$(CONFIG_N2)		+= n2.o
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 6aed238..0179cef 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -795,8 +795,8 @@
 	if (mutex_lock_interruptible(&chan->rlock))
 		return -ERESTARTSYS;
 	
-	if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) {
-		pr_info("%s: cosa_read() - OOM\n", cosa->name);
+	chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL);
+	if (chan->rxdata == NULL) {
 		mutex_unlock(&chan->rlock);
 		return -ENOMEM;
 	}
@@ -874,9 +874,8 @@
 		count = COSA_MTU;
 	
 	/* Allocate the buffer */
-	if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) {
-		pr_notice("%s: cosa_write() OOM - dropping packet\n",
-			  cosa->name);
+	kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA);
+	if (kbuf == NULL) {
 		up(&chan->wsem);
 		return -ENOMEM;
 	}
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
deleted file mode 100644
index 2a3ecae..0000000
--- a/drivers/net/wan/cycx_drv.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
-* cycx_drv.c	Cyclom 2X Support Module.
-*
-*		This module is a library of common hardware specific
-*		functions used by the Cyclades Cyclom 2X sync card.
-*
-* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdladrv.c by Gene Kozin <genek@compuserve.com>
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* 1999/11/11	acme		set_current_state(TASK_INTERRUPTIBLE), code
-*				cleanup
-* 1999/11/08	acme		init_cyc2x deleted, doing nothing
-* 1999/11/06	acme		back to read[bw], write[bw] and memcpy_to and
-*				fromio to use dpmbase ioremaped
-* 1999/10/26	acme		use isa_read[bw], isa_write[bw] & isa_memcpy_to
-*				& fromio
-* 1999/10/23	acme		cleanup to only supports cyclom2x: all the other
-*				boards are no longer manufactured by cyclades,
-*				if someone wants to support them... be my guest!
-* 1999/05/28    acme		cycx_intack & cycx_intde gone for good
-* 1999/05/18	acme		lots of unlogged work, submitting to Linus...
-* 1999/01/03	acme		more judicious use of data types
-* 1999/01/03	acme		judicious use of data types :>
-*				cycx_inten trying to reset pending interrupts
-*				from cyclom 2x - I think this isn't the way to
-*				go, but for now...
-* 1999/01/02	acme		cycx_intack ok, I think there's nothing to do
-*				to ack an int in cycx_drv.c, only handle it in
-*				cyx_isr (or in the other protocols: cyp_isr,
-*				cyf_isr, when they get implemented.
-* Dec 31, 1998	acme		cycx_data_boot & cycx_code_boot fixed, crossing
-*				fingers to see x25_configure in cycx_x25.c
-*				work... :)
-* Dec 26, 1998	acme		load implementation fixed, seems to work! :)
-*				cycx_2x_dpmbase_options with all the possible
-*				DPM addresses (20).
-*				cycx_intr implemented (test this!)
-*				general code cleanup
-* Dec  8, 1998	Ivan Passos	Cyclom-2X firmware load implementation.
-* Aug  8, 1998	acme		Initial version.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>		/* __init */
-#include <linux/module.h>
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/cycx_drv.h>	/* API definitions */
-#include <linux/cycx_cfm.h>	/* CYCX firmware module definitions */
-#include <linux/delay.h>	/* udelay, msleep_interruptible */
-#include <asm/io.h>		/* read[wl], write[wl], ioremap, iounmap */
-
-#define	MOD_VERSION	0
-#define	MOD_RELEASE	6
-
-MODULE_AUTHOR("Arnaldo Carvalho de Melo");
-MODULE_DESCRIPTION("Cyclom 2x Sync Card Driver");
-MODULE_LICENSE("GPL");
-
-/* Hardware-specific functions */
-static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len);
-static void cycx_bootcfg(struct cycx_hw *hw);
-
-static int reset_cyc2x(void __iomem *addr);
-static int detect_cyc2x(void __iomem *addr);
-
-/* Miscellaneous functions */
-static int get_option_index(const long *optlist, long optval);
-static u16 checksum(u8 *buf, u32 len);
-
-#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
-
-/* Global Data */
-
-/* private data */
-static const char fullname[] = "Cyclom 2X Support Module";
-static const char copyright[] =
-	"(c) 1998-2003 Arnaldo Carvalho de Melo <acme@conectiva.com.br>";
-
-/* Hardware configuration options.
- * These are arrays of configuration options used by verification routines.
- * The first element of each array is its size (i.e. number of options).
- */
-static const long cyc2x_dpmbase_options[] = {
-	20,
-	0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
-	0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
-	0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000
-};
-
-static const long cycx_2x_irq_options[]  = { 7, 3, 5, 9, 10, 11, 12, 15 };
-
-/* Kernel Loadable Module Entry Points */
-/* Module 'insert' entry point.
- * o print announcement
- * o initialize static data
- *
- * Return:	0	Ok
- *		< 0	error.
- * Context:	process */
-
-static int __init cycx_drv_init(void)
-{
-	pr_info("%s v%u.%u %s\n",
-		fullname, MOD_VERSION, MOD_RELEASE, copyright);
-
-	return 0;
-}
-
-/* Module 'remove' entry point.
- * o release all remaining system resources */
-static void cycx_drv_cleanup(void)
-{
-}
-
-/* Kernel APIs */
-/* Set up adapter.
- * o detect adapter type
- * o verify hardware configuration options
- * o check for hardware conflicts
- * o set up adapter shared memory
- * o test adapter memory
- * o load firmware
- * Return:	0	ok.
- *		< 0	error */
-EXPORT_SYMBOL(cycx_setup);
-int cycx_setup(struct cycx_hw *hw, void *cfm, u32 len, unsigned long dpmbase)
-{
-	int err;
-
-	/* Verify IRQ configuration options */
-	if (!get_option_index(cycx_2x_irq_options, hw->irq)) {
-		pr_err("IRQ %d is invalid!\n", hw->irq);
-		return -EINVAL;
-	}
-
-	/* Setup adapter dual-port memory window and test memory */
-	if (!dpmbase) {
-		pr_err("you must specify the dpm address!\n");
- 		return -EINVAL;
-	} else if (!get_option_index(cyc2x_dpmbase_options, dpmbase)) {
-		pr_err("memory address 0x%lX is invalid!\n", dpmbase);
-		return -EINVAL;
-	}
-
-	hw->dpmbase = ioremap(dpmbase, CYCX_WINDOWSIZE);
-	hw->dpmsize = CYCX_WINDOWSIZE;
-
-	if (!detect_cyc2x(hw->dpmbase)) {
-		pr_err("adapter Cyclom 2X not found at address 0x%lX!\n",
-		       dpmbase);
-		return -EINVAL;
-	}
-
-	pr_info("found Cyclom 2X card at address 0x%lX\n", dpmbase);
-
-	/* Load firmware. If loader fails then shut down adapter */
-	err = load_cyc2x(hw, cfm, len);
-
-	if (err)
-		cycx_down(hw);         /* shutdown adapter */
-
-	return err;
-}
-
-EXPORT_SYMBOL(cycx_down);
-int cycx_down(struct cycx_hw *hw)
-{
-	iounmap(hw->dpmbase);
-	return 0;
-}
-
-/* Enable interrupt generation.  */
-static void cycx_inten(struct cycx_hw *hw)
-{
-	writeb(0, hw->dpmbase);
-}
-
-/* Generate an interrupt to adapter's CPU. */
-EXPORT_SYMBOL(cycx_intr);
-void cycx_intr(struct cycx_hw *hw)
-{
-	writew(0, hw->dpmbase + GEN_CYCX_INTR);
-}
-
-/* Execute Adapter Command.
- * o Set exec flag.
- * o Busy-wait until flag is reset. */
-EXPORT_SYMBOL(cycx_exec);
-int cycx_exec(void __iomem *addr)
-{
-	u16 i = 0;
-	/* wait till addr content is zeroed */
-
-	while (readw(addr)) {
-		udelay(1000);
-
-		if (++i > 50)
-			return -1;
-	}
-
-	return 0;
-}
-
-/* Read absolute adapter memory.
- * Transfer data from adapter's memory to data buffer. */
-EXPORT_SYMBOL(cycx_peek);
-int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
-{
-	if (len == 1)
-		*(u8*)buf = readb(hw->dpmbase + addr);
-	else
-		memcpy_fromio(buf, hw->dpmbase + addr, len);
-
-	return 0;
-}
-
-/* Write Absolute Adapter Memory.
- * Transfer data from data buffer to adapter's memory. */
-EXPORT_SYMBOL(cycx_poke);
-int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
-{
-	if (len == 1)
-		writeb(*(u8*)buf, hw->dpmbase + addr);
-	else
-		memcpy_toio(hw->dpmbase + addr, buf, len);
-
-	return 0;
-}
-
-/* Hardware-Specific Functions */
-
-/* Load Aux Routines */
-/* Reset board hardware.
-   return 1 if memory exists at addr and 0 if not. */
-static int memory_exists(void __iomem *addr)
-{
-	int tries = 0;
-
-	for (; tries < 3 ; tries++) {
-		writew(TEST_PATTERN, addr + 0x10);
-
-		if (readw(addr + 0x10) == TEST_PATTERN)
-			if (readw(addr + 0x10) == TEST_PATTERN)
-				return 1;
-
-		msleep_interruptible(1 * 1000);
-	}
-
-	return 0;
-}
-
-/* Load reset code. */
-static void reset_load(void __iomem *addr, u8 *buffer, u32 cnt)
-{
-	void __iomem *pt_code = addr + RESET_OFFSET;
-	u16 i; /*, j; */
-
-	for (i = 0 ; i < cnt ; i++) {
-/*		for (j = 0 ; j < 50 ; j++); Delay - FIXME busy waiting... */
-		writeb(*buffer++, pt_code++);
-	}
-}
-
-/* Load buffer using boot interface.
- * o copy data from buffer to Cyclom-X memory
- * o wait for reset code to copy it to right portion of memory */
-static int buffer_load(void __iomem *addr, u8 *buffer, u32 cnt)
-{
-	memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
-	writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
-
-	return wait_cyc(addr);
-}
-
-/* Set up entry point and kick start Cyclom-X CPU. */
-static void cycx_start(void __iomem *addr)
-{
-	/* put in 0x30 offset the jump instruction to the code entry point */
-	writeb(0xea, addr + 0x30);
-	writeb(0x00, addr + 0x31);
-	writeb(0xc4, addr + 0x32);
-	writeb(0x00, addr + 0x33);
-	writeb(0x00, addr + 0x34);
-
-	/* cmd to start executing code */
-	writew(GEN_START, addr + CMD_OFFSET);
-}
-
-/* Load and boot reset code. */
-static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len)
-{
-	void __iomem *pt_start = addr + START_OFFSET;
-
-	writeb(0xea, pt_start++); /* jmp to f000:3f00 */
-	writeb(0x00, pt_start++);
-	writeb(0xfc, pt_start++);
-	writeb(0x00, pt_start++);
-	writeb(0xf0, pt_start);
-	reset_load(addr, code, len);
-
-	/* 80186 was in hold, go */
-	writeb(0, addr + START_CPU);
-	msleep_interruptible(1 * 1000);
-}
-
-/* Load data.bin file through boot (reset) interface. */
-static int cycx_data_boot(void __iomem *addr, u8 *code, u32 len)
-{
-	void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
-	u32 i;
-
-	/* boot buffer length */
-	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
-	writew(GEN_DEFPAR, pt_boot_cmd);
-
-	if (wait_cyc(addr) < 0)
-		return -1;
-
-	writew(0, pt_boot_cmd + sizeof(u16));
-	writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
-	writew(GEN_SET_SEG, pt_boot_cmd);
-
-	if (wait_cyc(addr) < 0)
-		return -1;
-
-	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
-		if (buffer_load(addr, code + i,
-				min_t(u32, CFM_LOAD_BUFSZ, (len - i))) < 0) {
-			pr_err("Error !!\n");
-			return -1;
-		}
-
-	return 0;
-}
-
-
-/* Load code.bin file through boot (reset) interface. */
-static int cycx_code_boot(void __iomem *addr, u8 *code, u32 len)
-{
-	void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
-	u32 i;
-
-	/* boot buffer length */
-	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
-	writew(GEN_DEFPAR, pt_boot_cmd);
-
-	if (wait_cyc(addr) < 0)
-		return -1;
-
-	writew(0x0000, pt_boot_cmd + sizeof(u16));
-	writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
-	writew(GEN_SET_SEG, pt_boot_cmd);
-
-	if (wait_cyc(addr) < 0)
-		return -1;
-
-	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
-		if (buffer_load(addr, code + i,
-				min_t(u32, CFM_LOAD_BUFSZ, (len - i)))) {
-			pr_err("Error !!\n");
-			return -1;
-		}
-
-	return 0;
-}
-
-/* Load adapter from the memory image of the CYCX firmware module.
- * o verify firmware integrity and compatibility
- * o start adapter up */
-static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len)
-{
-	int i, j;
-	struct cycx_fw_header *img_hdr;
-	u8 *reset_image,
-	   *data_image,
-	   *code_image;
-	void __iomem *pt_cycld = hw->dpmbase + 0x400;
-	u16 cksum;
-
-	/* Announce */
-	pr_info("firmware signature=\"%s\"\n", cfm->signature);
-
-	/* Verify firmware signature */
-	if (strcmp(cfm->signature, CFM_SIGNATURE)) {
-		pr_err("load_cyc2x: not Cyclom-2X firmware!\n");
-		return -EINVAL;
-	}
-
-	pr_info("firmware version=%u\n", cfm->version);
-
-	/* Verify firmware module format version */
-	if (cfm->version != CFM_VERSION) {
-		pr_err("%s: firmware format %u rejected! Expecting %u.\n",
-		       __func__, cfm->version, CFM_VERSION);
-		return -EINVAL;
-	}
-
-	/* Verify firmware module length and checksum */
-	cksum = checksum((u8*)&cfm->info, sizeof(struct cycx_fw_info) +
-					  cfm->info.codesize);
-/*
-	FIXME cfm->info.codesize is off by 2
-	if (((len - sizeof(struct cycx_firmware) - 1) != cfm->info.codesize) ||
-*/
-	if (cksum != cfm->checksum) {
-		pr_err("%s: firmware corrupted!\n", __func__);
-		pr_err(" cdsize = 0x%x (expected 0x%lx)\n",
-		       len - (int)sizeof(struct cycx_firmware) - 1,
-		       cfm->info.codesize);
-		pr_err(" chksum = 0x%x (expected 0x%x)\n",
-		       cksum, cfm->checksum);
-		return -EINVAL;
-	}
-
-	/* If everything is ok, set reset, data and code pointers */
-	img_hdr = (struct cycx_fw_header *)&cfm->image;
-#ifdef FIRMWARE_DEBUG
-	pr_info("%s: image sizes\n", __func__);
-	pr_info(" reset=%lu\n", img_hdr->reset_size);
-	pr_info("  data=%lu\n", img_hdr->data_size);
-	pr_info("  code=%lu\n", img_hdr->code_size);
-#endif
-	reset_image = ((u8 *)img_hdr) + sizeof(struct cycx_fw_header);
-	data_image = reset_image + img_hdr->reset_size;
-	code_image = data_image + img_hdr->data_size;
-
-	/*---- Start load ----*/
-	/* Announce */
-	pr_info("loading firmware %s (ID=%u)...\n",
-		cfm->descr[0] ? cfm->descr : "unknown firmware",
-		cfm->info.codeid);
-
-	for (i = 0 ; i < 5 ; i++) {
-		/* Reset Cyclom hardware */
-		if (!reset_cyc2x(hw->dpmbase)) {
-			pr_err("dpm problem or board not found\n");
-			return -EINVAL;
-		}
-
-		/* Load reset.bin */
-		cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
-		/* reset is waiting for boot */
-		writew(GEN_POWER_ON, pt_cycld);
-		msleep_interruptible(1 * 1000);
-
-		for (j = 0 ; j < 3 ; j++)
-			if (!readw(pt_cycld))
-				goto reset_loaded;
-			else
-				msleep_interruptible(1 * 1000);
-	}
-
-	pr_err("reset not started\n");
-	return -EINVAL;
-
-reset_loaded:
-	/* Load data.bin */
-	if (cycx_data_boot(hw->dpmbase, data_image, img_hdr->data_size)) {
-		pr_err("cannot load data file\n");
-		return -EINVAL;
-	}
-
-	/* Load code.bin */
-	if (cycx_code_boot(hw->dpmbase, code_image, img_hdr->code_size)) {
-		pr_err("cannot load code file\n");
-		return -EINVAL;
-	}
-
-	/* Prepare boot-time configuration data */
-	cycx_bootcfg(hw);
-
-	/* kick-off CPU */
-	cycx_start(hw->dpmbase);
-
-	/* Arthur Ganzert's tip: wait a while after the firmware loading...
-	   seg abr 26 17:17:12 EST 1999 - acme */
-	msleep_interruptible(7 * 1000);
-	pr_info("firmware loaded!\n");
-
-	/* enable interrupts */
-	cycx_inten(hw);
-
-	return 0;
-}
-
-/* Prepare boot-time firmware configuration data.
- * o initialize configuration data area
-   From async.doc - V_3.4.0 - 07/18/1994
-   - As of now, only static buffers are available to the user.
-     So, the bit VD_RXDIRC must be set in 'valid'. That means that user
-     wants to use the static transmission and reception buffers. */
-static void cycx_bootcfg(struct cycx_hw *hw)
-{
-	/* use fixed buffers */
-	writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET);
-}
-
-/* Detect Cyclom 2x adapter.
- *	Following tests are used to detect Cyclom 2x adapter:
- *       to be completed based on the tests done below
- *	Return 1 if detected o.k. or 0 if failed.
- *	Note:	This test is destructive! Adapter will be left in shutdown
- *		state after the test. */
-static int detect_cyc2x(void __iomem *addr)
-{
-	reset_cyc2x(addr);
-
-	return memory_exists(addr);
-}
-
-/* Miscellaneous */
-/* Get option's index into the options list.
- *	Return option's index (1 .. N) or zero if option is invalid. */
-static int get_option_index(const long *optlist, long optval)
-{
-	int i = 1;
-
-	for (; i <= optlist[0]; ++i)
-		if (optlist[i] == optval)
-			return i;
-
-	return 0;
-}
-
-/* Reset adapter's CPU. */
-static int reset_cyc2x(void __iomem *addr)
-{
-	writeb(0, addr + RST_ENABLE);
-	msleep_interruptible(2 * 1000);
-	writeb(0, addr + RST_DISABLE);
-	msleep_interruptible(2 * 1000);
-
-	return memory_exists(addr);
-}
-
-/* Calculate 16-bit CRC using CCITT polynomial. */
-static u16 checksum(u8 *buf, u32 len)
-{
-	u16 crc = 0;
-	u16 mask, flag;
-
-	for (; len; --len, ++buf)
-		for (mask = 0x80; mask; mask >>= 1) {
-			flag = (crc & 0x8000);
-			crc <<= 1;
-			crc |= ((*buf & mask) ? 1 : 0);
-
-			if (flag)
-				crc ^= 0x1021;
-		}
-
-	return crc;
-}
-
-module_init(cycx_drv_init);
-module_exit(cycx_drv_cleanup);
-
-/* End */
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
deleted file mode 100644
index 81fbbad..0000000
--- a/drivers/net/wan/cycx_main.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
-* cycx_main.c	Cyclades Cyclom 2X WAN Link Driver. Main module.
-*
-* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
-*			 Jaspreet Singh	<jaspreet@sangoma.com>
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* Please look at the bitkeeper changelog (or any other scm tool that ends up
-* importing bitkeeper changelog or that replaces bitkeeper in the future as
-* main tool for linux development).
-* 
-* 2001/05/09	acme		Fix MODULE_DESC for debug, .bss nitpicks,
-* 				some cleanups
-* 2000/07/13	acme		remove useless #ifdef MODULE and crap
-*				#if KERNEL_VERSION > blah
-* 2000/07/06	acme		__exit at cyclomx_cleanup
-* 2000/04/02	acme		dprintk and cycx_debug
-* 				module_init/module_exit
-* 2000/01/21	acme		rename cyclomx_open to cyclomx_mod_inc_use_count
-*				and cyclomx_close to cyclomx_mod_dec_use_count
-* 2000/01/08	acme		cleanup
-* 1999/11/06	acme		cycx_down back to life (it needs to be
-*				called to iounmap the dpmbase)
-* 1999/08/09	acme		removed references to enable_tx_int
-*				use spinlocks instead of cli/sti in
-*				cyclomx_set_state
-* 1999/05/19	acme		works directly linked into the kernel
-*				init_waitqueue_head for 2.3.* kernel
-* 1999/05/18	acme		major cleanup (polling not needed), etc
-* 1998/08/28	acme		minor cleanup (ioctls for firmware deleted)
-*				queue_task activated
-* 1998/08/08	acme		Initial version.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/errno.h>	/* return codes */
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>		/* kmalloc(), kfree() */
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>	/* support for loadable modules */
-#include <linux/ioport.h>	/* request_region(), release_region() */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-#include <linux/cyclomx.h>	/* cyclomx common user API definitions */
-#include <linux/init.h>         /* __init (when not using as a module) */
-#include <linux/interrupt.h>
-
-unsigned int cycx_debug;
-
-MODULE_AUTHOR("Arnaldo Carvalho de Melo");
-MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
-MODULE_LICENSE("GPL");
-module_param(cycx_debug, int, 0);
-MODULE_PARM_DESC(cycx_debug, "cyclomx debug level");
-
-/* Defines & Macros */
-
-#define	CYCX_DRV_VERSION	0	/* version number */
-#define	CYCX_DRV_RELEASE	11	/* release (minor version) number */
-#define	CYCX_MAX_CARDS		1	/* max number of adapters */
-
-#define	CONFIG_CYCX_CARDS 1
-
-/* Function Prototypes */
-
-/* WAN link driver entry points */
-static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf);
-static int cycx_wan_shutdown(struct wan_device *wandev);
-
-/* Miscellaneous functions */
-static irqreturn_t cycx_isr(int irq, void *dev_id);
-
-/* Global Data
- * Note: All data must be explicitly initialized!!!
- */
-
-/* private data */
-static const char cycx_drvname[] = "cyclomx";
-static const char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
-static const char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
-			  "<acme@conectiva.com.br>";
-static int cycx_ncards = CONFIG_CYCX_CARDS;
-static struct cycx_device *cycx_card_array;	/* adapter data space */
-
-/* Kernel Loadable Module Entry Points */
-
-/*
- * Module 'insert' entry point.
- * o print announcement
- * o allocate adapter data space
- * o initialize static data
- * o register all cards with WAN router
- * o calibrate Cyclom 2X shared memory access delay.
- *
- * Return:	0	Ok
- *		< 0	error.
- * Context:	process
- */
-static int __init cycx_init(void)
-{
-	int cnt, err = -ENOMEM;
-
-	pr_info("%s v%u.%u %s\n",
-		cycx_fullname, CYCX_DRV_VERSION, CYCX_DRV_RELEASE,
-		cycx_copyright);
-
-	/* Verify number of cards and allocate adapter data space */
-	cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
-	cycx_ncards = max_t(int, cycx_ncards, 1);
-	cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL);
-	if (!cycx_card_array)
-		goto out;
-
-
-	/* Register adapters with WAN router */
-	for (cnt = 0; cnt < cycx_ncards; ++cnt) {
-		struct cycx_device *card = &cycx_card_array[cnt];
-		struct wan_device *wandev = &card->wandev;
-
-		sprintf(card->devname, "%s%d", cycx_drvname, cnt + 1);
-		wandev->magic    = ROUTER_MAGIC;
-		wandev->name     = card->devname;
-		wandev->private  = card;
-		wandev->setup    = cycx_wan_setup;
-		wandev->shutdown = cycx_wan_shutdown;
-		err = register_wan_device(wandev);
-
-		if (err) {
-			pr_err("%s registration failed with error %d!\n",
-			       card->devname, err);
-			break;
-		}
-	}
-
-	err = -ENODEV;
-	if (!cnt) {
-		kfree(cycx_card_array);
-		goto out;
-	}
-	err = 0;
-	cycx_ncards = cnt;	/* adjust actual number of cards */
-out:	return err;
-}
-
-/*
- * Module 'remove' entry point.
- * o unregister all adapters from the WAN router
- * o release all remaining system resources
- */
-static void __exit cycx_exit(void)
-{
-	int i = 0;
-
-	for (; i < cycx_ncards; ++i) {
-		struct cycx_device *card = &cycx_card_array[i];
-		unregister_wan_device(card->devname);
-	}
-
-	kfree(cycx_card_array);
-}
-
-/* WAN Device Driver Entry Points */
-/*
- * Setup/configure WAN link driver.
- * o check adapter state
- * o make sure firmware is present in configuration
- * o allocate interrupt vector
- * o setup Cyclom 2X hardware
- * o call appropriate routine to perform protocol-specific initialization
- *
- * This function is called when router handles ROUTER_SETUP IOCTL. The
- * configuration structure is in kernel memory (including extended data, if
- * any).
- */
-static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf)
-{
-	int rc = -EFAULT;
-	struct cycx_device *card;
-	int irq;
-
-	/* Sanity checks */
-
-	if (!wandev || !wandev->private || !conf)
-		goto out;
-
-	card = wandev->private;
-	rc = -EBUSY;
-	if (wandev->state != WAN_UNCONFIGURED)
-		goto out;
-
-	rc = -EINVAL;
-	if (!conf->data_size || !conf->data) {
-		pr_err("%s: firmware not found in configuration data!\n",
-		       wandev->name);
-		goto out;
-	}
-
-	if (conf->irq <= 0) {
-		pr_err("%s: can't configure without IRQ!\n", wandev->name);
-		goto out;
-	}
-
-	/* Allocate IRQ */
-	irq = conf->irq == 2 ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
-
-	if (request_irq(irq, cycx_isr, 0, wandev->name, card)) {
-		pr_err("%s: can't reserve IRQ %d!\n", wandev->name, irq);
-		goto out;
-	}
-
-	/* Configure hardware, load firmware, etc. */
-	memset(&card->hw, 0, sizeof(card->hw));
-	card->hw.irq	 = irq;
-	card->hw.dpmsize = CYCX_WINDOWSIZE;
-	card->hw.fwid	 = CFID_X25_2X;
-	spin_lock_init(&card->lock);
-	init_waitqueue_head(&card->wait_stats);
-
-	rc = cycx_setup(&card->hw, conf->data, conf->data_size, conf->maddr);
-	if (rc)
-		goto out_irq;
-
-	/* Initialize WAN device data space */
-	wandev->irq       = irq;
-	wandev->dma       = wandev->ioport = 0;
-	wandev->maddr     = (unsigned long)card->hw.dpmbase;
-	wandev->msize     = card->hw.dpmsize;
-	wandev->hw_opt[2] = 0;
-	wandev->hw_opt[3] = card->hw.fwid;
-
-	/* Protocol-specific initialization */
-	switch (card->hw.fwid) {
-#ifdef CONFIG_CYCLOMX_X25
-	case CFID_X25_2X:
-		rc = cycx_x25_wan_init(card, conf);
-		break;
-#endif
-	default:
-		pr_err("%s: this firmware is not supported!\n", wandev->name);
-		rc = -EINVAL;
-	}
-
-	if (rc) {
-		cycx_down(&card->hw);
-		goto out_irq;
-	}
-
-	rc = 0;
-out:
-	return rc;
-out_irq:
-	free_irq(irq, card);
-	goto out;
-}
-
-/*
- * Shut down WAN link driver.
- * o shut down adapter hardware
- * o release system resources.
- *
- * This function is called by the router when device is being unregistered or
- * when it handles ROUTER_DOWN IOCTL.
- */
-static int cycx_wan_shutdown(struct wan_device *wandev)
-{
-	int ret = -EFAULT;
-	struct cycx_device *card;
-
-	/* sanity checks */
-	if (!wandev || !wandev->private)
-		goto out;
-
-	ret = 0;
-	if (wandev->state == WAN_UNCONFIGURED)
-		goto out;
-
-	card = wandev->private;
-	wandev->state = WAN_UNCONFIGURED;
-	cycx_down(&card->hw);
-	pr_info("%s: irq %d being freed!\n", wandev->name, wandev->irq);
-	free_irq(wandev->irq, card);
-out:	return ret;
-}
-
-/* Miscellaneous */
-/*
- * Cyclom 2X Interrupt Service Routine.
- * o acknowledge Cyclom 2X hardware interrupt.
- * o call protocol-specific interrupt service routine, if any.
- */
-static irqreturn_t cycx_isr(int irq, void *dev_id)
-{
-	struct cycx_device *card = dev_id;
-
-	if (card->wandev.state == WAN_UNCONFIGURED)
-		goto out;
-
-	if (card->in_isr) {
-		pr_warn("%s: interrupt re-entrancy on IRQ %d!\n",
-			card->devname, card->wandev.irq);
-		goto out;
-	}
-
-	if (card->isr)
-		card->isr(card);
-	return IRQ_HANDLED;
-out:
-	return IRQ_NONE;
-}
-
-/* Set WAN device state.  */
-void cycx_set_state(struct cycx_device *card, int state)
-{
-	unsigned long flags;
-	char *string_state = NULL;
-
-	spin_lock_irqsave(&card->lock, flags);
-
-	if (card->wandev.state != state) {
-		switch (state) {
-		case WAN_CONNECTED:
-			string_state = "connected!";
-			break;
-		case WAN_DISCONNECTED:
-			string_state = "disconnected!";
-			break;
-		}
-		pr_info("%s: link %s\n", card->devname, string_state);
-		card->wandev.state = state;
-	}
-
-	card->state_tick = jiffies;
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-module_init(cycx_init);
-module_exit(cycx_exit);
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
deleted file mode 100644
index 06f3f63..0000000
--- a/drivers/net/wan/cycx_x25.c
+++ /dev/null
@@ -1,1602 +0,0 @@
-/*
-* cycx_x25.c	Cyclom 2X WAN Link Driver.  X.25 module.
-*
-* Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
-*
-*		This program is free software; you can redistribute it and/or
-*		modify it under the terms of the GNU General Public License
-*		as published by the Free Software Foundation; either version
-*		2 of the License, or (at your option) any later version.
-* ============================================================================
-* 2001/01/12	acme		use dev_kfree_skb_irq on interrupt context
-* 2000/04/02	acme		dprintk, cycx_debug
-* 				fixed the bug introduced in get_dev_by_lcn and
-* 				get_dev_by_dte_addr by the anonymous hacker
-* 				that converted this driver to softnet
-* 2000/01/08	acme		cleanup
-* 1999/10/27	acme		use ARPHRD_HWX25 so that the X.25 stack know
-*				that we have a X.25 stack implemented in
-*				firmware onboard
-* 1999/10/18	acme		support for X.25 sockets in if_send,
-*				beware: socket(AF_X25...) IS WORK IN PROGRESS,
-*				TCP/IP over X.25 via wanrouter not affected,
-*				working.
-* 1999/10/09	acme		chan_disc renamed to chan_disconnect,
-* 				began adding support for X.25 sockets:
-* 				conf->protocol in new_if
-* 1999/10/05	acme		fixed return E... to return -E...
-* 1999/08/10	acme		serialized access to the card thru a spinlock
-*				in x25_exec
-* 1999/08/09	acme		removed per channel spinlocks
-*				removed references to enable_tx_int
-* 1999/05/28	acme		fixed nibble_to_byte, ackvc now properly treated
-*				if_send simplified
-* 1999/05/25	acme		fixed t1, t2, t21 & t23 configuration
-*				use spinlocks instead of cli/sti in some points
-* 1999/05/24	acme		finished the x25_get_stat function
-* 1999/05/23	acme		dev->type = ARPHRD_X25 (tcpdump only works,
-*				AFAIT, with ARPHRD_ETHER). This seems to be
-*				needed to use socket(AF_X25)...
-*				Now the config file must specify a peer media
-*				address for svc channels over a crossover cable.
-*				Removed hold_timeout from x25_channel_t,
-*				not used.
-*				A little enhancement in the DEBUG processing
-* 1999/05/22	acme		go to DISCONNECTED in disconnect_confirm_intr,
-*				instead of chan_disc.
-* 1999/05/16	marcelo		fixed timer initialization in SVCs
-* 1999/01/05	acme		x25_configure now get (most of) all
-*				parameters...
-* 1999/01/05	acme		pktlen now (correctly) uses log2 (value
-*				configured)
-* 1999/01/03	acme		judicious use of data types (u8, u16, u32, etc)
-* 1999/01/03	acme		cyx_isr: reset dpmbase to acknowledge
-*				indication (interrupt from cyclom 2x)
-* 1999/01/02	acme		cyx_isr: first hackings...
-* 1999/01/0203  acme 		when initializing an array don't give less
-*				elements than declared...
-* 				example: char send_cmd[6] = "?\xFF\x10";
-*          			you'll gonna lose a couple hours, 'cause your
-*				brain won't admit that there's an error in the
-*				above declaration...  the side effect is that
-*				memset is put into the unresolved symbols
-*				instead of using the inline memset functions...
-* 1999/01/02    acme 		began chan_connect, chan_send, x25_send
-* 1998/12/31	acme		x25_configure
-*				this code can be compiled as non module
-* 1998/12/27	acme		code cleanup
-*				IPX code wiped out! let's decrease code
-*				complexity for now, remember: I'm learning! :)
-*                               bps_to_speed_code OK
-* 1998/12/26	acme		Minimal debug code cleanup
-* 1998/08/08	acme		Initial version.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define CYCLOMX_X25_DEBUG 1
-
-#include <linux/ctype.h>	/* isdigit() */
-#include <linux/errno.h>	/* return codes */
-#include <linux/if_arp.h>       /* ARPHRD_HWX25 */
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/module.h>
-#include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/sched.h>
-#include <linux/slab.h>		/* kmalloc(), kfree() */
-#include <linux/stddef.h>	/* offsetof(), etc. */
-#include <linux/wanrouter.h>	/* WAN router definitions */
-
-#include <asm/byteorder.h>	/* htons(), etc. */
-
-#include <linux/cyclomx.h>	/* Cyclom 2X common user API definitions */
-#include <linux/cycx_x25.h>	/* X.25 firmware API definitions */
-
-#include <net/x25device.h>
-
-/* Defines & Macros */
-#define CYCX_X25_MAX_CMD_RETRY 5
-#define CYCX_X25_CHAN_MTU 2048	/* unfragmented logical channel MTU */
-
-/* Data Structures */
-/* This is an extension of the 'struct net_device' we create for each network
-   interface to keep the rest of X.25 channel-specific data. */
-struct cycx_x25_channel {
-	/* This member must be first. */
-	struct net_device *slave;	/* WAN slave */
-
-	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
-	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
-	char *local_addr;		/* local media address, ASCIIZ -
-					   svc thru crossover cable */
-	s16 lcn;			/* logical channel number/conn.req.key*/
-	u8 link;
-	struct timer_list timer;	/* timer used for svc channel disc. */
-	u16 protocol;			/* ethertype, 0 - multiplexed */
-	u8 svc;				/* 0 - permanent, 1 - switched */
-	u8 state;			/* channel state */
-	u8 drop_sequence;		/* mark sequence for dropping */
-	u32 idle_tmout;			/* sec, before disconnecting */
-	struct sk_buff *rx_skb;		/* receive socket buffer */
-	struct cycx_device *card;	/* -> owner */
-	struct net_device_stats ifstats;/* interface statistics */
-};
-
-/* Function Prototypes */
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int cycx_wan_update(struct wan_device *wandev),
-	   cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
-			   wanif_conf_t *conf),
-	   cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
-
-/* Network device interface */
-static int cycx_netdevice_init(struct net_device *dev);
-static int cycx_netdevice_open(struct net_device *dev);
-static int cycx_netdevice_stop(struct net_device *dev);
-static int cycx_netdevice_hard_header(struct sk_buff *skb,
-				      struct net_device *dev, u16 type,
-				      const void *daddr, const void *saddr,
-				      unsigned len);
-static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
-static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
-							struct net_device *dev);
-
-static struct net_device_stats *
-			cycx_netdevice_get_stats(struct net_device *dev);
-
-/* Interrupt handlers */
-static void cycx_x25_irq_handler(struct cycx_device *card),
-	    cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_log(struct cycx_device *card,
-			     struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_stat(struct cycx_device *card,
-			      struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_connect_confirm(struct cycx_device *card,
-					 struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
-					    struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_connect(struct cycx_device *card,
-				 struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_disconnect(struct cycx_device *card,
-				    struct cycx_x25_cmd *cmd),
-	    cycx_x25_irq_spurious(struct cycx_device *card,
-				  struct cycx_x25_cmd *cmd);
-
-/* X.25 firmware interface functions */
-static int cycx_x25_configure(struct cycx_device *card,
-			      struct cycx_x25_config *conf),
-	   cycx_x25_get_stats(struct cycx_device *card),
-	   cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
-			 int len, void *buf),
-	   cycx_x25_connect_response(struct cycx_device *card,
-				struct cycx_x25_channel *chan),
-	   cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
-			   		u8 lcn);
-
-/* channel functions */
-static int cycx_x25_chan_connect(struct net_device *dev),
-	   cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb);
-
-static void cycx_x25_chan_disconnect(struct net_device *dev),
-	    cycx_x25_chan_send_event(struct net_device *dev, u8 event);
-
-/* Miscellaneous functions */
-static void cycx_x25_set_chan_state(struct net_device *dev, u8 state),
-	    cycx_x25_chan_timer(unsigned long d);
-
-static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble),
-	    reset_timer(struct net_device *dev);
-
-static u8 bps_to_speed_code(u32 bps);
-static u8 cycx_log2(u32 n);
-
-static unsigned dec_to_uint(u8 *str, int len);
-
-static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
-						  s16 lcn);
-static struct net_device *
-	cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte);
-
-static void cycx_x25_chan_setup(struct net_device *dev);
-
-#ifdef CYCLOMX_X25_DEBUG
-static void hex_dump(char *msg, unsigned char *p, int len);
-static void cycx_x25_dump_config(struct cycx_x25_config *conf);
-static void cycx_x25_dump_stats(struct cycx_x25_stats *stats);
-static void cycx_x25_dump_devs(struct wan_device *wandev);
-#else
-#define hex_dump(msg, p, len)
-#define cycx_x25_dump_config(conf)
-#define cycx_x25_dump_stats(stats)
-#define cycx_x25_dump_devs(wandev)
-#endif
-/* Public Functions */
-
-/* X.25 Protocol Initialization routine.
- *
- * This routine is called by the main Cyclom 2X module during setup.  At this
- * point adapter is completely initialized and X.25 firmware is running.
- *  o configure adapter
- *  o initialize protocol-specific fields of the adapter data space.
- *
- * Return:	0	o.k.
- *		< 0	failure.  */
-int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf)
-{
-	struct cycx_x25_config cfg;
-
-	/* Verify configuration ID */
-	if (conf->config_id != WANCONFIG_X25) {
-		pr_info("%s: invalid configuration ID %u!\n",
-			card->devname, conf->config_id);
-		return -EINVAL;
-	}
-
-	/* Initialize protocol-specific fields */
-	card->mbox  = card->hw.dpmbase + X25_MBOX_OFFS;
-	card->u.x.connection_keys = 0;
-	spin_lock_init(&card->u.x.lock);
-
-	/* Configure adapter. Here we set reasonable defaults, then parse
-	 * device configuration structure and set configuration options.
-	 * Most configuration options are verified and corrected (if
-	 * necessary) since we can't rely on the adapter to do so and don't
-	 * want it to fail either. */
-	memset(&cfg, 0, sizeof(cfg));
-	cfg.link = 0;
-	cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55;
-	cfg.speed = bps_to_speed_code(conf->bps);
-	cfg.n3win = 7;
-	cfg.n2win = 2;
-	cfg.n2 = 5;
-	cfg.nvc = 1;
-	cfg.npvc = 1;
-	cfg.flags = 0x02; /* default = V35 */
-	cfg.t1 = 10;   /* line carrier timeout */
-	cfg.t2 = 29;   /* tx timeout */
-	cfg.t21 = 180; /* CALL timeout */
-	cfg.t23 = 180; /* CLEAR timeout */
-
-	/* adjust MTU */
-	if (!conf->mtu || conf->mtu >= 512)
-		card->wandev.mtu = 512;
-	else if (conf->mtu >= 256)
-		card->wandev.mtu = 256;
-	else if (conf->mtu >= 128)
-		card->wandev.mtu = 128;
-	else
-		card->wandev.mtu = 64;
-
-	cfg.pktlen = cycx_log2(card->wandev.mtu);
-
-	if (conf->station == WANOPT_DTE) {
-		cfg.locaddr = 3; /* DTE */
-		cfg.remaddr = 1; /* DCE */
-	} else {
-		cfg.locaddr = 1; /* DCE */
-		cfg.remaddr = 3; /* DTE */
-	}
-
-	if (conf->interface == WANOPT_RS232)
-	        cfg.flags = 0;      /* FIXME just reset the 2nd bit */
-
-	if (conf->u.x25.hi_pvc) {
-		card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, 4095);
-		card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc);
-	}
-
-	if (conf->u.x25.hi_svc) {
-		card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, 4095);
-		card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc);
-	}
-
-	if (card->u.x.lo_pvc == 255)
-		cfg.npvc = 0;
-	else
-		cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1;
-
-	cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc;
-
-	if (conf->u.x25.hdlc_window)
-		cfg.n2win = min_t(unsigned int, conf->u.x25.hdlc_window, 7);
-
-	if (conf->u.x25.pkt_window)
-		cfg.n3win = min_t(unsigned int, conf->u.x25.pkt_window, 7);
-
-	if (conf->u.x25.t1)
-		cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30);
-
-	if (conf->u.x25.t2)
-		cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 30);
-
-	if (conf->u.x25.t11_t21)
-		cfg.t21 = min_t(unsigned int, conf->u.x25.t11_t21, 30);
-
-	if (conf->u.x25.t13_t23)
-		cfg.t23 = min_t(unsigned int, conf->u.x25.t13_t23, 30);
-
-	if (conf->u.x25.n2)
-		cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30);
-
-	/* initialize adapter */
-	if (cycx_x25_configure(card, &cfg))
-		return -EIO;
-
-	/* Initialize protocol-specific fields of adapter data space */
-	card->wandev.bps	= conf->bps;
-	card->wandev.interface	= conf->interface;
-	card->wandev.clocking	= conf->clocking;
-	card->wandev.station	= conf->station;
-	card->isr		= cycx_x25_irq_handler;
-	card->exec		= NULL;
-	card->wandev.update	= cycx_wan_update;
-	card->wandev.new_if	= cycx_wan_new_if;
-	card->wandev.del_if	= cycx_wan_del_if;
-	card->wandev.state	= WAN_DISCONNECTED;
-
-	return 0;
-}
-
-/* WAN Device Driver Entry Points */
-/* Update device status & statistics. */
-static int cycx_wan_update(struct wan_device *wandev)
-{
-	/* sanity checks */
-	if (!wandev || !wandev->private)
-		return -EFAULT;
-
-	if (wandev->state == WAN_UNCONFIGURED)
-		return -ENODEV;
-
-	cycx_x25_get_stats(wandev->private);
-
-	return 0;
-}
-
-/* Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registration.
- *
- * Return:	0	o.k.
- *		< 0	failure (channel will not be created) */
-static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
-			   wanif_conf_t *conf)
-{
-	struct cycx_device *card = wandev->private;
-	struct cycx_x25_channel *chan;
-	int err = 0;
-
-	if (!conf->name[0] || strlen(conf->name) > WAN_IFNAME_SZ) {
-		pr_info("%s: invalid interface name!\n", card->devname);
-		return -EINVAL;
-	}
-
-	dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name,
-			     cycx_x25_chan_setup);
-	if (!dev)
-		return -ENOMEM;
-
-	chan = netdev_priv(dev);
-	strcpy(chan->name, conf->name);
-	chan->card = card;
-	chan->link = conf->port;
-	chan->protocol = conf->protocol ? ETH_P_X25 : ETH_P_IP;
-	chan->rx_skb = NULL;
-	/* only used in svc connected thru crossover cable */
-	chan->local_addr = NULL;
-
-	if (conf->addr[0] == '@') {	/* SVC */
-		int len = strlen(conf->local_addr);
-
-		if (len) {
-			if (len > WAN_ADDRESS_SZ) {
-				pr_err("%s: %s local addr too long!\n",
-				       wandev->name, chan->name);
-				err = -EINVAL;
-				goto error;
-			} else {
-				chan->local_addr = kmalloc(len + 1, GFP_KERNEL);
-
-				if (!chan->local_addr) {
-					err = -ENOMEM;
-					goto error;
-				}
-			}
-
-			strncpy(chan->local_addr, conf->local_addr,
-				WAN_ADDRESS_SZ);
-		}
-
-		chan->svc = 1;
-		strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
-		init_timer(&chan->timer);
-		chan->timer.function	= cycx_x25_chan_timer;
-		chan->timer.data	= (unsigned long)dev;
-
-		/* Set channel timeouts (default if not specified) */
-		chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
-	} else if (isdigit(conf->addr[0])) {	/* PVC */
-		s16 lcn = dec_to_uint(conf->addr, 0);
-
-		if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
-			chan->lcn = lcn;
-		else {
-			pr_err("%s: PVC %u is out of range on interface %s!\n",
-			       wandev->name, lcn, chan->name);
-			err = -EINVAL;
-			goto error;
-		}
-	} else {
-		pr_err("%s: invalid media address on interface %s!\n",
-		       wandev->name, chan->name);
-		err = -EINVAL;
-		goto error;
-	}
-
-	return 0;
-
-error:
-	free_netdev(dev);
-	return err;
-}
-
-/* Delete logical channel. */
-static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-
-	if (chan->svc) {
-		kfree(chan->local_addr);
-		if (chan->state == WAN_CONNECTED)
-			del_timer(&chan->timer);
-	}
-
-	return 0;
-}
-
-
-/* Network Device Interface */
-
-static const struct header_ops cycx_header_ops = {
-	.create = cycx_netdevice_hard_header,
-	.rebuild = cycx_netdevice_rebuild_header,
-};
-
-static const struct net_device_ops cycx_netdev_ops = {
-	.ndo_init	= cycx_netdevice_init,
-	.ndo_open	= cycx_netdevice_open,
-	.ndo_stop	= cycx_netdevice_stop,
-	.ndo_start_xmit	= cycx_netdevice_hard_start_xmit,
-	.ndo_get_stats	= cycx_netdevice_get_stats,
-};
-
-static void cycx_x25_chan_setup(struct net_device *dev)
-{
-	/* Initialize device driver entry points */
-	dev->netdev_ops		= &cycx_netdev_ops;
-	dev->header_ops		= &cycx_header_ops;
-
-	/* Initialize media-specific parameters */
-	dev->mtu		= CYCX_X25_CHAN_MTU;
-	dev->type		= ARPHRD_HWX25;	/* ARP h/w type */
-	dev->hard_header_len	= 0;		/* media header length */
-	dev->addr_len		= 0;		/* hardware address length */
-}
-
-/* Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration.  Returning anything but zero will fail interface
- * registration. */
-static int cycx_netdevice_init(struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-	struct cycx_device *card = chan->card;
-	struct wan_device *wandev = &card->wandev;
-
-	if (!chan->svc)
-		*(__be16*)dev->dev_addr = htons(chan->lcn);
-
-	/* Initialize hardware parameters (just for reference) */
-	dev->irq		= wandev->irq;
-	dev->dma		= wandev->dma;
-	dev->base_addr		= wandev->ioport;
-	dev->mem_start		= (unsigned long)wandev->maddr;
-	dev->mem_end		= (unsigned long)(wandev->maddr +
-						  wandev->msize - 1);
-	dev->flags		|= IFF_NOARP;
-
-	/* Set transmit buffer queue length */
-	dev->tx_queue_len	= 10;
-
-	/* Initialize socket buffers */
-	cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-
-	return 0;
-}
-
-/* Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
- *
- * Return 0 if O.k. or errno.  */
-static int cycx_netdevice_open(struct net_device *dev)
-{
-	if (netif_running(dev))
-		return -EBUSY; /* only one open is allowed */
-
-	netif_start_queue(dev);
-	return 0;
-}
-
-/* Close network interface.
- * o reset flags.
- * o if there's no more open channels then disconnect physical link. */
-static int cycx_netdevice_stop(struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-
-	netif_stop_queue(dev);
-
-	if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
-		cycx_x25_chan_disconnect(dev);
-
-	return 0;
-}
-
-/* Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it.  If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return:	media header length. */
-static int cycx_netdevice_hard_header(struct sk_buff *skb,
-				      struct net_device *dev, u16 type,
-				      const void *daddr, const void *saddr,
-				      unsigned len)
-{
-	skb->protocol = htons(type);
-
-	return dev->hard_header_len;
-}
-
-/* * Re-build media header.
- * Return:	1	physical address resolved.
- *		0	physical address not resolved */
-static int cycx_netdevice_rebuild_header(struct sk_buff *skb)
-{
-	return 1;
-}
-
-/* Send a packet on a network interface.
- * o set busy flag (marks start of the transmission).
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return:	0	complete (socket buffer must be freed)
- *		non-0	packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- *    bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- *    protocol stack and can be used for flow control with protocol layer. */
-static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
-							struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-	struct cycx_device *card = chan->card;
-
-	if (!chan->svc)
-		chan->protocol = ntohs(skb->protocol);
-
-	if (card->wandev.state != WAN_CONNECTED)
-		++chan->ifstats.tx_dropped;
-	else if (chan->svc && chan->protocol &&
-		 chan->protocol != ntohs(skb->protocol)) {
-		pr_info("%s: unsupported Ethertype 0x%04X on interface %s!\n",
-			card->devname, ntohs(skb->protocol), dev->name);
-		++chan->ifstats.tx_errors;
-	} else if (chan->protocol == ETH_P_IP) {
-		switch (chan->state) {
-		case WAN_DISCONNECTED:
-			if (cycx_x25_chan_connect(dev)) {
-				netif_stop_queue(dev);
-				return NETDEV_TX_BUSY;
-			}
-			/* fall thru */
-		case WAN_CONNECTED:
-			reset_timer(dev);
-			dev->trans_start = jiffies;
-			netif_stop_queue(dev);
-
-			if (cycx_x25_chan_send(dev, skb))
-				return NETDEV_TX_BUSY;
-
-			break;
-		default:
-			++chan->ifstats.tx_dropped;
-			++card->wandev.stats.tx_dropped;
-	}
-	} else { /* chan->protocol == ETH_P_X25 */
-		switch (skb->data[0]) {
-		case X25_IFACE_DATA:
-			break;
-		case X25_IFACE_CONNECT:
-			cycx_x25_chan_connect(dev);
-			goto free_packet;
-		case X25_IFACE_DISCONNECT:
-			cycx_x25_chan_disconnect(dev);
-			goto free_packet;
-	        default:
-			pr_info("%s: unknown %d x25-iface request on %s!\n",
-				card->devname, skb->data[0], dev->name);
-			++chan->ifstats.tx_errors;
-			goto free_packet;
-		}
-
-		skb_pull(skb, 1); /* Remove control byte */
-		reset_timer(dev);
-		dev->trans_start = jiffies;
-		netif_stop_queue(dev);
-
-		if (cycx_x25_chan_send(dev, skb)) {
-			/* prepare for future retransmissions */
-			skb_push(skb, 1);
-			return NETDEV_TX_BUSY;
-		}
-	}
-
-free_packet:
-	dev_kfree_skb(skb);
-
-	return NETDEV_TX_OK;
-}
-
-/* Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats */
-static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-
-	return chan ? &chan->ifstats : NULL;
-}
-
-/* Interrupt Handlers */
-/* X.25 Interrupt Service Routine. */
-static void cycx_x25_irq_handler(struct cycx_device *card)
-{
-	struct cycx_x25_cmd cmd;
-	u16 z = 0;
-
-	card->in_isr = 1;
-	card->buff_int_mode_unbusy = 0;
-	cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));
-
-	switch (cmd.command) {
-	case X25_DATA_INDICATION:
-		cycx_x25_irq_rx(card, &cmd);
-		break;
-	case X25_ACK_FROM_VC:
-		cycx_x25_irq_tx(card, &cmd);
-		break;
-	case X25_LOG:
-		cycx_x25_irq_log(card, &cmd);
-		break;
-	case X25_STATISTIC:
-		cycx_x25_irq_stat(card, &cmd);
-		break;
-	case X25_CONNECT_CONFIRM:
-		cycx_x25_irq_connect_confirm(card, &cmd);
-		break;
-	case X25_CONNECT_INDICATION:
-		cycx_x25_irq_connect(card, &cmd);
-		break;
-	case X25_DISCONNECT_INDICATION:
-		cycx_x25_irq_disconnect(card, &cmd);
-		break;
-	case X25_DISCONNECT_CONFIRM:
-		cycx_x25_irq_disconnect_confirm(card, &cmd);
-		break;
-	case X25_LINE_ON:
-		cycx_set_state(card, WAN_CONNECTED);
-		break;
-	case X25_LINE_OFF:
-		cycx_set_state(card, WAN_DISCONNECTED);
-		break;
-	default:
-		cycx_x25_irq_spurious(card, &cmd);
-		break;
-	}
-
-	cycx_poke(&card->hw, 0, &z, sizeof(z));
-	cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
-	card->in_isr = 0;
-}
-
-/* Transmit interrupt handler.
- *	o Release socket buffer
- *	o Clear 'tbusy' flag */
-static void cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
-{
-	struct net_device *dev;
-	struct wan_device *wandev = &card->wandev;
-	u8 lcn;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-
-	/* unbusy device and then dev_tint(); */
-	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
-	if (dev) {
-		card->buff_int_mode_unbusy = 1;
-		netif_wake_queue(dev);
-	} else
-		pr_err("%s:ackvc for inexistent lcn %d\n", card->devname, lcn);
-}
-
-/* Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map logical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then
- *   decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- *    coming and we have to allocate buffer for the maximum IP packet size
- *    expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- *    socket buffers available) the whole packet sequence must be discarded. */
-static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
-{
-	struct wan_device *wandev = &card->wandev;
-	struct net_device *dev;
-	struct cycx_x25_channel *chan;
-	struct sk_buff *skb;
-	u8 bitm, lcn;
-	int pktlen = cmd->len - 5;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));
-	bitm &= 0x10;
-
-	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
-	if (!dev) {
-		/* Invalid channel, discard packet */
-		pr_info("%s: receiving on orphaned LCN %d!\n",
-			card->devname, lcn);
-		return;
-	}
-
-	chan = netdev_priv(dev);
-	reset_timer(dev);
-
-	if (chan->drop_sequence) {
-		if (!bitm)
-			chan->drop_sequence = 0;
-		else
-			return;
-	}
-
-	if ((skb = chan->rx_skb) == NULL) {
-		/* Allocate new socket buffer */
-		int bufsize = bitm ? dev->mtu : pktlen;
-
-		if ((skb = dev_alloc_skb((chan->protocol == ETH_P_X25 ? 1 : 0) +
-					 bufsize +
-					 dev->hard_header_len)) == NULL) {
-			pr_info("%s: no socket buffers available!\n",
-				card->devname);
-			chan->drop_sequence = 1;
-			++chan->ifstats.rx_dropped;
-			return;
-		}
-
-		if (chan->protocol == ETH_P_X25) /* X.25 socket layer control */
-			/* 0 = data packet (dev_alloc_skb zeroed skb->data) */
-			skb_put(skb, 1);
-
-		skb->dev = dev;
-		skb->protocol = htons(chan->protocol);
-		chan->rx_skb = skb;
-	}
-
-	if (skb_tailroom(skb) < pktlen) {
-		/* No room for the packet. Call off the whole thing! */
-		dev_kfree_skb_irq(skb);
-		chan->rx_skb = NULL;
-
-		if (bitm)
-			chan->drop_sequence = 1;
-
-		pr_info("%s: unexpectedly long packet sequence on interface %s!\n",
-			card->devname, dev->name);
-		++chan->ifstats.rx_length_errors;
-		return;
-	}
-
-	/* Append packet to the socket buffer  */
-	cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen);
-
-	if (bitm)
-		return; /* more data is coming */
-
-	chan->rx_skb = NULL;		/* dequeue packet */
-
-	++chan->ifstats.rx_packets;
-	chan->ifstats.rx_bytes += pktlen;
-
-	skb_reset_mac_header(skb);
-	netif_rx(skb);
-}
-
-/* Connect interrupt handler. */
-static void cycx_x25_irq_connect(struct cycx_device *card,
-				 struct cycx_x25_cmd *cmd)
-{
-	struct wan_device *wandev = &card->wandev;
-	struct net_device *dev = NULL;
-	struct cycx_x25_channel *chan;
-	u8 d[32],
-	   loc[24],
-	   rem[24];
-	u8 lcn, sizeloc, sizerem;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc));
-	cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6);
-
-	sizerem = sizeloc >> 4;
-	sizeloc &= 0x0F;
-
-	loc[0] = rem[0] = '\0';
-
-	if (sizeloc)
-		nibble_to_byte(d, loc, sizeloc, 0);
-
-	if (sizerem)
-		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
-
-	dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n",
-			  __func__, lcn, loc, rem);
-
-	dev = cycx_x25_get_dev_by_dte_addr(wandev, rem);
-	if (!dev) {
-		/* Invalid channel, discard packet */
-		pr_info("%s: connect not expected: remote %s!\n",
-			card->devname, rem);
-		return;
-	}
-
-	chan = netdev_priv(dev);
-	chan->lcn = lcn;
-	cycx_x25_connect_response(card, chan);
-	cycx_x25_set_chan_state(dev, WAN_CONNECTED);
-}
-
-/* Connect confirm interrupt handler. */
-static void cycx_x25_irq_connect_confirm(struct cycx_device *card,
-					 struct cycx_x25_cmd *cmd)
-{
-	struct wan_device *wandev = &card->wandev;
-	struct net_device *dev;
-	struct cycx_x25_channel *chan;
-	u8 lcn, key;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
-	dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n",
-			  card->devname, __func__, lcn, key);
-
-	dev = cycx_x25_get_dev_by_lcn(wandev, -key);
-	if (!dev) {
-		/* Invalid channel, discard packet */
-		clear_bit(--key, (void*)&card->u.x.connection_keys);
-		pr_info("%s: connect confirm not expected: lcn %d, key=%d!\n",
-			card->devname, lcn, key);
-		return;
-	}
-
-	clear_bit(--key, (void*)&card->u.x.connection_keys);
-	chan = netdev_priv(dev);
-	chan->lcn = lcn;
-	cycx_x25_set_chan_state(dev, WAN_CONNECTED);
-}
-
-/* Disconnect confirm interrupt handler. */
-static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
-					    struct cycx_x25_cmd *cmd)
-{
-	struct wan_device *wandev = &card->wandev;
-	struct net_device *dev;
-	u8 lcn;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(1, KERN_INFO "%s: %s:lcn=%d\n",
-			  card->devname, __func__, lcn);
-	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
-	if (!dev) {
-		/* Invalid channel, discard packet */
-		pr_info("%s:disconnect confirm not expected!:lcn %d\n",
-			card->devname, lcn);
-		return;
-	}
-
-	cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-}
-
-/* disconnect interrupt handler. */
-static void cycx_x25_irq_disconnect(struct cycx_device *card,
-				    struct cycx_x25_cmd *cmd)
-{
-	struct wan_device *wandev = &card->wandev;
-	struct net_device *dev;
-	u8 lcn;
-
-	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(1, KERN_INFO "%s:lcn=%d\n", __func__, lcn);
-
-	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
-	if (dev) {
-		struct cycx_x25_channel *chan = netdev_priv(dev);
-
-		cycx_x25_disconnect_response(card, chan->link, lcn);
-		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-	} else
-		cycx_x25_disconnect_response(card, 0, lcn);
-}
-
-/* LOG interrupt handler. */
-static void cycx_x25_irq_log(struct cycx_device *card, struct cycx_x25_cmd *cmd)
-{
-#if CYCLOMX_X25_DEBUG
-	char bf[20];
-	u16 size, toread, link, msg_code;
-	u8 code, routine;
-
-	cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
-	cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
-	cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
-	/* at most 20 bytes are available... thanks to Daniela :) */
-	toread = size < 20 ? size : 20;
-	cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
-	cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
-	cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);
-
-	pr_info("cycx_x25_irq_handler: X25_LOG (0x4500) indic.:\n");
-	pr_info("cmd->buf=0x%X\n", cmd->buf);
-	pr_info("Log message code=0x%X\n", msg_code);
-	pr_info("Link=%d\n", link);
-	pr_info("log code=0x%X\n", code);
-	pr_info("log routine=0x%X\n", routine);
-	pr_info("Message size=%d\n", size);
-	hex_dump("Message", bf, toread);
-#endif
-}
-
-/* STATISTIC interrupt handler. */
-static void cycx_x25_irq_stat(struct cycx_device *card,
-			      struct cycx_x25_cmd *cmd)
-{
-	cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,
-		  sizeof(card->u.x.stats));
-	hex_dump("cycx_x25_irq_stat", (unsigned char*)&card->u.x.stats,
-		 sizeof(card->u.x.stats));
-	cycx_x25_dump_stats(&card->u.x.stats);
-	wake_up_interruptible(&card->wait_stats);
-}
-
-/* Spurious interrupt handler.
- * o print a warning
- * If number of spurious interrupts exceeded some limit, then ??? */
-static void cycx_x25_irq_spurious(struct cycx_device *card,
-				  struct cycx_x25_cmd *cmd)
-{
-	pr_info("%s: spurious interrupt (0x%X)!\n",
-		card->devname, cmd->command);
-}
-#ifdef CYCLOMX_X25_DEBUG
-static void hex_dump(char *msg, unsigned char *p, int len)
-{
-	print_hex_dump(KERN_INFO, msg, DUMP_PREFIX_OFFSET, 16, 1,
-		       p, len, true);
-}
-#endif
-
-/* Cyclom 2X Firmware-Specific Functions */
-/* Exec X.25 command. */
-static int x25_exec(struct cycx_device *card, int command, int link,
-		    void *d1, int len1, void *d2, int len2)
-{
-	struct cycx_x25_cmd c;
-	unsigned long flags;
-	u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;
-	u8 retry = CYCX_X25_MAX_CMD_RETRY;
-	int err = 0;
-
-	c.command = command;
-	c.link = link;
-	c.len = len1 + len2;
-
-	spin_lock_irqsave(&card->u.x.lock, flags);
-
-	/* write command */
-	cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
-
-	/* write X.25 data */
-	if (d1) {
-		cycx_poke(&card->hw, addr, d1, len1);
-
-		if (d2) {
-			if (len2 > 254) {
-				u32 addr1 = 0xA00 + 0x400 * link;
-
-				cycx_poke(&card->hw, addr + len1, d2, 249);
-				cycx_poke(&card->hw, addr1, ((u8*)d2) + 249,
-					  len2 - 249);
-			} else
-				cycx_poke(&card->hw, addr + len1, d2, len2);
-		}
-	}
-
-	/* generate interruption, executing command */
-	cycx_intr(&card->hw);
-
-	/* wait till card->mbox == 0 */
-	do {
-		err = cycx_exec(card->mbox);
-	} while (retry-- && err);
-
-	spin_unlock_irqrestore(&card->u.x.lock, flags);
-
-	return err;
-}
-
-/* Configure adapter. */
-static int cycx_x25_configure(struct cycx_device *card,
-			      struct cycx_x25_config *conf)
-{
-	struct {
-		u16 nlinks;
-		struct cycx_x25_config conf[2];
-	} x25_cmd_conf;
-
-	memset(&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
-	x25_cmd_conf.nlinks = 2;
-	x25_cmd_conf.conf[0] = *conf;
-	/* FIXME: we need to find a way in the wanrouter framework
-		  to configure the second link, for now lets use it
-		  with the same config from the first link, fixing
-		  the interface type to RS232, the speed in 38400 and
-		  the clock to external */
-	x25_cmd_conf.conf[1] = *conf;
-	x25_cmd_conf.conf[1].link = 1;
-	x25_cmd_conf.conf[1].speed = 5; /* 38400 */
-	x25_cmd_conf.conf[1].clock = 8;
-	x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */
-
-	cycx_x25_dump_config(&x25_cmd_conf.conf[0]);
-	cycx_x25_dump_config(&x25_cmd_conf.conf[1]);
-
-	return x25_exec(card, X25_CONFIG, 0,
-			&x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);
-}
-
-/* Get protocol statistics. */
-static int cycx_x25_get_stats(struct cycx_device *card)
-{
-	/* the firmware expects 20 in the size field!!!
-	   thanks to Daniela */
-	int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
-
-	if (err)
-		return err;
-
-	interruptible_sleep_on(&card->wait_stats);
-
-	if (signal_pending(current))
-		return -EINTR;
-
-	card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames;
-	card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors;
-	card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors;
-	card->wandev.stats.rx_length_errors = 0; /* not available from fw */
-	card->wandev.stats.rx_frame_errors = 0; /* not available from fw */
-	card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts;
-	card->wandev.stats.rx_dropped = 0; /* not available from fw */
-	card->wandev.stats.rx_errors = 0; /* not available from fw */
-	card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames;
-	card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts;
-	card->wandev.stats.tx_dropped = 0; /* not available from fw */
-	card->wandev.stats.collisions = 0; /* not available from fw */
-	card->wandev.stats.tx_errors = 0; /* not available from fw */
-
-	cycx_x25_dump_devs(&card->wandev);
-
-	return 0;
-}
-
-/* return the number of nibbles */
-static int byte_to_nibble(u8 *s, u8 *d, char *nibble)
-{
-	int i = 0;
-
-	if (*nibble && *s) {
-		d[i] |= *s++ - '0';
-		*nibble = 0;
-		++i;
-	}
-
-	while (*s) {
-		d[i] = (*s - '0') << 4;
-		if (*(s + 1))
-			d[i] |= *(s + 1) - '0';
-		else {
-			*nibble = 1;
-			break;
-		}
-		++i;
-		s += 2;
-	}
-
-	return i;
-}
-
-static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble)
-{
-	if (nibble) {
-		*d++ = '0' + (*s++ & 0x0F);
-		--len;
-	}
-
-	while (len) {
-		*d++ = '0' + (*s >> 4);
-
-		if (--len) {
-			*d++ = '0' + (*s & 0x0F);
-			--len;
-		} else break;
-
-		++s;
-	}
-
-	*d = '\0';
-}
-
-/* Place X.25 call. */
-static int x25_place_call(struct cycx_device *card,
-			  struct cycx_x25_channel *chan)
-{
-	int err = 0,
-	    len;
-	char d[64],
-	     nibble = 0,
-	     mylen = chan->local_addr ? strlen(chan->local_addr) : 0,
-	     remotelen = strlen(chan->addr);
-	u8 key;
-
-	if (card->u.x.connection_keys == ~0U) {
-		pr_info("%s: too many simultaneous connection requests!\n",
-			card->devname);
-		return -EAGAIN;
-	}
-
-	key = ffz(card->u.x.connection_keys);
-	set_bit(key, (void*)&card->u.x.connection_keys);
-	++key;
-	dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
-	memset(d, 0, sizeof(d));
-	d[1] = key; /* user key */
-	d[2] = 0x10;
-	d[4] = 0x0B;
-
-	len = byte_to_nibble(chan->addr, d + 6, &nibble);
-
-	if (chan->local_addr)
-		len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble);
-
-	if (nibble)
-		++len;
-
-	d[5] = mylen << 4 | remotelen;
-	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */
-
-	if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
-			    &d, 7 + len + 1, NULL, 0)) != 0)
-		clear_bit(--key, (void*)&card->u.x.connection_keys);
-	else
-		chan->lcn = -key;
-
-	return err;
-}
-
-/* Place X.25 CONNECT RESPONSE. */
-static int cycx_x25_connect_response(struct cycx_device *card,
-				     struct cycx_x25_channel *chan)
-{
-	u8 d[8];
-
-	memset(d, 0, sizeof(d));
-	d[0] = d[3] = chan->lcn;
-	d[2] = 0x10;
-	d[4] = 0x0F;
-	d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */
-
-	return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
-}
-
-/* Place X.25 DISCONNECT RESPONSE.  */
-static int cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
-					u8 lcn)
-{
-	char d[5];
-
-	memset(d, 0, sizeof(d));
-	d[0] = d[3] = lcn;
-	d[2] = 0x10;
-	d[4] = 0x17;
-
-	return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
-}
-
-/* Clear X.25 call.  */
-static int x25_clear_call(struct cycx_device *card, u8 link, u8 lcn, u8 cause,
-			  u8 diagn)
-{
-	u8 d[7];
-
-	memset(d, 0, sizeof(d));
-	d[0] = d[3] = lcn;
-	d[2] = 0x10;
-	d[4] = 0x13;
-	d[5] = cause;
-	d[6] = diagn;
-
-	return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);
-}
-
-/* Send X.25 data packet. */
-static int cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
-			 int len, void *buf)
-{
-	u8 d[] = "?\xFF\x10??";
-
-	d[0] = d[3] = lcn;
-	d[4] = bitm;
-
-	return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);
-}
-
-/* Miscellaneous */
-/* Find network device by its channel number.  */
-static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
-						  s16 lcn)
-{
-	struct net_device *dev = wandev->dev;
-	struct cycx_x25_channel *chan;
-
-	while (dev) {
-		chan = netdev_priv(dev);
-
-		if (chan->lcn == lcn)
-			break;
-		dev = chan->slave;
-	}
-	return dev;
-}
-
-/* Find network device by its remote dte address. */
-static struct net_device *
-	cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte)
-{
-	struct net_device *dev = wandev->dev;
-	struct cycx_x25_channel *chan;
-
-	while (dev) {
-		chan = netdev_priv(dev);
-
-		if (!strcmp(chan->addr, dte))
-			break;
-		dev = chan->slave;
-	}
-	return dev;
-}
-
-/* Initiate connection on the logical channel.
- * o for PVC we just get channel configuration
- * o for SVCs place an X.25 call
- *
- * Return:	0	connected
- *		>0	connection in progress
- *		<0	failure */
-static int cycx_x25_chan_connect(struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-	struct cycx_device *card = chan->card;
-
-	if (chan->svc) {
-		if (!chan->addr[0])
-			return -EINVAL; /* no destination address */
-
-		dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
-				  card->devname, chan->addr);
-
-		if (x25_place_call(card, chan))
-			return -EIO;
-
-		cycx_x25_set_chan_state(dev, WAN_CONNECTING);
-		return 1;
-	} else
-		cycx_x25_set_chan_state(dev, WAN_CONNECTED);
-
-	return 0;
-}
-
-/* Disconnect logical channel.
- * o if SVC then clear X.25 call */
-static void cycx_x25_chan_disconnect(struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-
-	if (chan->svc) {
-		x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
-		cycx_x25_set_chan_state(dev, WAN_DISCONNECTING);
-	} else
-		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-}
-
-/* Called by kernel timer */
-static void cycx_x25_chan_timer(unsigned long d)
-{
-	struct net_device *dev = (struct net_device *)d;
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-
-	if (chan->state == WAN_CONNECTED)
-		cycx_x25_chan_disconnect(dev);
-	else
-		pr_err("%s: %s for svc (%s) not connected!\n",
-		       chan->card->devname, __func__, dev->name);
-}
-
-/* Set logical channel state. */
-static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-	struct cycx_device *card = chan->card;
-	unsigned long flags;
-	char *string_state = NULL;
-
-	spin_lock_irqsave(&card->lock, flags);
-
-	if (chan->state != state) {
-		if (chan->svc && chan->state == WAN_CONNECTED)
-			del_timer(&chan->timer);
-
-		switch (state) {
-		case WAN_CONNECTED:
-			string_state = "connected!";
-			*(__be16*)dev->dev_addr = htons(chan->lcn);
-			netif_wake_queue(dev);
-			reset_timer(dev);
-
-			if (chan->protocol == ETH_P_X25)
-				cycx_x25_chan_send_event(dev,
-					X25_IFACE_CONNECT);
-
-			break;
-		case WAN_CONNECTING:
-			string_state = "connecting...";
-			break;
-		case WAN_DISCONNECTING:
-			string_state = "disconnecting...";
-			break;
-		case WAN_DISCONNECTED:
-			string_state = "disconnected!";
-
-			if (chan->svc) {
-				*(unsigned short*)dev->dev_addr = 0;
-				chan->lcn = 0;
-			}
-
-			if (chan->protocol == ETH_P_X25)
-				cycx_x25_chan_send_event(dev,
-					X25_IFACE_DISCONNECT);
-
-			netif_wake_queue(dev);
-			break;
-		}
-
-		pr_info("%s: interface %s %s\n",
-			card->devname, dev->name, string_state);
-		chan->state = state;
-	}
-
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* Send packet on a logical channel.
- *	When this function is called, tx_skb field of the channel data space
- *	points to the transmit socket buffer.  When transmission is complete,
- *	release socket buffer and reset 'tbusy' flag.
- *
- * Return:	0	- transmission complete
- *		1	- busy
- *
- * Notes:
- * 1. If packet length is greater than MTU for this channel, we'll fragment
- *    the packet into 'complete sequence' using M-bit.
- * 2. When transmission is complete, an event notification should be issued
- *    to the router.  */
-static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-	struct cycx_device *card = chan->card;
-	int bitm = 0;		/* final packet */
-	unsigned len = skb->len;
-
-	if (skb->len > card->wandev.mtu) {
-		len = card->wandev.mtu;
-		bitm = 0x10;		/* set M-bit (more data) */
-	}
-
-	if (cycx_x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
-		return 1;
-
-	if (bitm) {
-		skb_pull(skb, len);
-		return 1;
-	}
-
-	++chan->ifstats.tx_packets;
-	chan->ifstats.tx_bytes += len;
-
-	return 0;
-}
-
-/* Send event (connection, disconnection, etc) to X.25 socket layer */
-
-static void cycx_x25_chan_send_event(struct net_device *dev, u8 event)
-{
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		pr_err("%s: out of memory\n", __func__);
-		return;
-	}
-
-	ptr  = skb_put(skb, 1);
-	*ptr = event;
-
-	skb->protocol = x25_type_trans(skb, dev);
-	netif_rx(skb);
-}
-
-/* Convert line speed in bps to a number used by cyclom 2x code. */
-static u8 bps_to_speed_code(u32 bps)
-{
-	u8 number = 0; /* defaults to the lowest (1200) speed ;> */
-
-	     if (bps >= 512000) number = 8;
-	else if (bps >= 256000) number = 7;
-	else if (bps >= 64000)  number = 6;
-	else if (bps >= 38400)  number = 5;
-	else if (bps >= 19200)  number = 4;
-	else if (bps >= 9600)   number = 3;
-	else if (bps >= 4800)   number = 2;
-	else if (bps >= 2400)   number = 1;
-
-	return number;
-}
-
-/* log base 2 */
-static u8 cycx_log2(u32 n)
-{
-	u8 log = 0;
-
-	if (!n)
-		return 0;
-
-	while (n > 1) {
-		n >>= 1;
-		++log;
-	}
-
-	return log;
-}
-
-/* Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted. */
-static unsigned dec_to_uint(u8 *str, int len)
-{
-	unsigned val = 0;
-
-	if (!len)
-		len = strlen(str);
-
-	for (; len && isdigit(*str); ++str, --len)
-		val = (val * 10) + (*str - (unsigned) '0');
-
-	return val;
-}
-
-static void reset_timer(struct net_device *dev)
-{
-	struct cycx_x25_channel *chan = netdev_priv(dev);
-
-	if (chan->svc)
-		mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
-}
-#ifdef CYCLOMX_X25_DEBUG
-static void cycx_x25_dump_config(struct cycx_x25_config *conf)
-{
-	pr_info("X.25 configuration\n");
-	pr_info("-----------------\n");
-	pr_info("link number=%d\n", conf->link);
-	pr_info("line speed=%d\n", conf->speed);
-	pr_info("clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
-	pr_info("# level 2 retransm.=%d\n", conf->n2);
-	pr_info("level 2 window=%d\n", conf->n2win);
-	pr_info("level 3 window=%d\n", conf->n3win);
-	pr_info("# logical channels=%d\n", conf->nvc);
-	pr_info("level 3 pkt len=%d\n", conf->pktlen);
-	pr_info("my address=%d\n", conf->locaddr);
-	pr_info("remote address=%d\n", conf->remaddr);
-	pr_info("t1=%d seconds\n", conf->t1);
-	pr_info("t2=%d seconds\n", conf->t2);
-	pr_info("t21=%d seconds\n", conf->t21);
-	pr_info("# PVCs=%d\n", conf->npvc);
-	pr_info("t23=%d seconds\n", conf->t23);
-	pr_info("flags=0x%x\n", conf->flags);
-}
-
-static void cycx_x25_dump_stats(struct cycx_x25_stats *stats)
-{
-	pr_info("X.25 statistics\n");
-	pr_info("--------------\n");
-	pr_info("rx_crc_errors=%d\n", stats->rx_crc_errors);
-	pr_info("rx_over_errors=%d\n", stats->rx_over_errors);
-	pr_info("n2_tx_frames=%d\n", stats->n2_tx_frames);
-	pr_info("n2_rx_frames=%d\n", stats->n2_rx_frames);
-	pr_info("tx_timeouts=%d\n", stats->tx_timeouts);
-	pr_info("rx_timeouts=%d\n", stats->rx_timeouts);
-	pr_info("n3_tx_packets=%d\n", stats->n3_tx_packets);
-	pr_info("n3_rx_packets=%d\n", stats->n3_rx_packets);
-	pr_info("tx_aborts=%d\n", stats->tx_aborts);
-	pr_info("rx_aborts=%d\n", stats->rx_aborts);
-}
-
-static void cycx_x25_dump_devs(struct wan_device *wandev)
-{
-	struct net_device *dev = wandev->dev;
-
-	pr_info("X.25 dev states\n");
-	pr_info("name: addr:           txoff:  protocol:\n");
-	pr_info("---------------------------------------\n");
-
-	while(dev) {
-		struct cycx_x25_channel *chan = netdev_priv(dev);
-
-		pr_info("%-5.5s %-15.15s   %d     ETH_P_%s\n",
-			chan->name, chan->addr, netif_queue_stopped(dev),
-			chan->protocol == ETH_P_IP ? "IP" : "X25");
-		dev = chan->slave;
-	}
-}
-
-#endif /* CYCLOMX_X25_DEBUG */
-/* End */
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 56941d6..3f0c4f2 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2448,11 +2448,9 @@
 	}
 
 	/* Allocate driver private data */
-	card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
-	if (card == NULL) {
-		pr_err("FarSync card found but insufficient memory for driver storage\n");
+	card = kzalloc(sizeof(struct fst_card_info), GFP_KERNEL);
+	if (card == NULL)
 		return -ENOMEM;
-	}
 
 	/* Try to enable the device */
 	if ((err = pci_enable_device(pdev)) != 0) {
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 10cc7df..a0a932c 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -280,14 +280,13 @@
 	if (!try_module_get(proto->module))
 		return -ENOSYS;
 
-	if (size)
-		if ((dev_to_hdlc(dev)->state = kmalloc(size,
-						       GFP_KERNEL)) == NULL) {
-			netdev_warn(dev,
-				    "Memory squeeze on hdlc_proto_attach()\n");
+	if (size) {
+		dev_to_hdlc(dev)->state = kmalloc(size, GFP_KERNEL);
+		if (dev_to_hdlc(dev)->state == NULL) {
 			module_put(proto->module);
 			return -ENOBUFS;
 		}
+	}
 	dev_to_hdlc(dev)->proto = proto;
 	return 0;
 }
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 44db8b7..5895f19 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -128,7 +128,6 @@
 	rbuff = kmalloc(len + 4, GFP_ATOMIC);
 
 	if (xbuff == NULL || rbuff == NULL) {
-		netdev_warn(dev, "unable to grow X.25 buffers, MTU change cancelled\n");
 		kfree(xbuff);
 		kfree(rbuff);
 		return -ENOMEM;
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index def12b3..c9c711d 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -1055,7 +1055,6 @@
 		result = 0;
 	}
 	net_dev->addr_len = ETH_ALEN;
-	memcpy(net_dev->perm_addr, ack_buf.ack_pl, ETH_ALEN);
 	memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN);
 error_read_mac:
 	d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result);
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 1d76ae8..4889613 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -156,7 +156,7 @@
 	struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
 	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
 	struct device *dev = i2400m_dev(i2400m);
-	struct sk_buff *skb = i2400m->wake_tx_skb;
+	struct sk_buff *skb;
 	unsigned long flags;
 
 	spin_lock_irqsave(&i2400m->tx_lock, flags);
@@ -236,23 +236,26 @@
 void i2400m_net_wake_stop(struct i2400m *i2400m)
 {
 	struct device *dev = i2400m_dev(i2400m);
+	struct sk_buff *wake_tx_skb;
+	unsigned long flags;
 
 	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
-	/* See i2400m_hard_start_xmit(), references are taken there
-	 * and here we release them if the work was still
-	 * pending. Note we can't differentiate work not pending vs
-	 * never scheduled, so the NULL check does that. */
-	if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
-	    && i2400m->wake_tx_skb != NULL) {
-		unsigned long flags;
-		struct sk_buff *wake_tx_skb;
-		spin_lock_irqsave(&i2400m->tx_lock, flags);
-		wake_tx_skb = i2400m->wake_tx_skb;	/* compat help */
-		i2400m->wake_tx_skb = NULL;	/* compat help */
-		spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+	/*
+	 * See i2400m_hard_start_xmit(), references are taken there and
+	 * here we release them if the packet was still pending.
+	 */
+	cancel_work_sync(&i2400m->wake_tx_ws);
+
+	spin_lock_irqsave(&i2400m->tx_lock, flags);
+	wake_tx_skb = i2400m->wake_tx_skb;
+	i2400m->wake_tx_skb = NULL;
+	spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+	if (wake_tx_skb) {
 		i2400m_put(i2400m);
 		kfree_skb(wake_tx_skb);
 	}
+
 	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
 }
 
@@ -288,7 +291,7 @@
 	 * and if pending, release those resources. */
 	result = 0;
 	spin_lock_irqsave(&i2400m->tx_lock, flags);
-	if (!work_pending(&i2400m->wake_tx_ws)) {
+	if (!i2400m->wake_tx_skb) {
 		netif_stop_queue(net_dev);
 		i2400m_get(i2400m);
 		i2400m->wake_tx_skb = skb_get(skb);	/* transfer ref count */
@@ -596,12 +599,12 @@
 {
 	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
 
-	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
-	strncpy(info->fw_version,
-	        i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strlcpy(info->fw_version, i2400m->fw_name ? : "",
+		sizeof(info->fw_version));
 	if (net_dev->dev.parent)
-		strncpy(info->bus_info, dev_name(net_dev->dev.parent),
-			sizeof(info->bus_info) - 1);
+		strlcpy(info->bus_info, dev_name(net_dev->dev.parent),
+			sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops i2400m_ethtool_ops = {
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 37becfc..0b60295 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -1346,29 +1346,22 @@
 int i2400m_rx_setup(struct i2400m *i2400m)
 {
 	int result = 0;
-	struct device *dev = i2400m_dev(i2400m);
 
 	i2400m->rx_reorder = i2400m_rx_reorder_disabled? 0 : 1;
 	if (i2400m->rx_reorder) {
 		unsigned itr;
-		size_t size;
 		struct i2400m_roq_log *rd;
 
 		result = -ENOMEM;
 
-		size = sizeof(i2400m->rx_roq[0]) * (I2400M_RO_CIN + 1);
-		i2400m->rx_roq = kzalloc(size, GFP_KERNEL);
-		if (i2400m->rx_roq == NULL) {
-			dev_err(dev, "RX: cannot allocate %zu bytes for "
-				"reorder queues\n", size);
+		i2400m->rx_roq = kcalloc(I2400M_RO_CIN + 1,
+					 sizeof(i2400m->rx_roq[0]), GFP_KERNEL);
+		if (i2400m->rx_roq == NULL)
 			goto error_roq_alloc;
-		}
 
-		size = sizeof(*i2400m->rx_roq[0].log) * (I2400M_RO_CIN + 1);
-		rd = kzalloc(size, GFP_KERNEL);
+		rd = kcalloc(I2400M_RO_CIN + 1, sizeof(*i2400m->rx_roq[0].log),
+			     GFP_KERNEL);
 		if (rd == NULL) {
-			dev_err(dev, "RX: cannot allocate %zu bytes for "
-				"reorder queues log areas\n", size);
 			result = -ENOMEM;
 			goto error_roq_log_alloc;
 		}
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c
index d44b545..fc1355d 100644
--- a/drivers/net/wimax/i2400m/usb-notif.c
+++ b/drivers/net/wimax/i2400m/usb-notif.c
@@ -199,7 +199,6 @@
 	d_fnstart(4, dev, "(i2400m %p)\n", i2400mu);
 	buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA);
 	if (buf == NULL) {
-		dev_err(dev, "notification: buffer allocation failed\n");
 		ret = -ENOMEM;
 		goto error_buf_alloc;
 	}
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 080f363..cd15a93 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -346,9 +346,9 @@
 	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
 	struct usb_device *udev = i2400mu->usb_dev;
 
-	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
-	strncpy(info->fw_version,
-	        i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	strlcpy(info->fw_version, i2400m->fw_name ? : "",
+		sizeof(info->fw_version));
 	usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
 }
 
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 630577d..956024a 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -69,10 +69,9 @@
 
 	/* Allocate space for private device-specific data */
 	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
-	if (!local) {
-		printk(KERN_ERR "airo_cs: no memory for new device\n");
+	if (!local)
 		return -ENOMEM;
-	}
+
 	p_dev->priv = local;
 
 	return airo_config(p_dev);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 77fa428..5ac5f7a 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2164,10 +2164,8 @@
 
 	buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
 	priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
-	if (!priv->bulk_out_buffer) {
-		dev_err(&interface->dev, "cannot allocate output buffer\n");
+	if (!priv->bulk_out_buffer)
 		return -ENOMEM;
-	}
 
 	at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
 
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 30ca0a6..1d264c0 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -240,13 +240,14 @@
 * Driver Initialization *
 \***********************/
 
-static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+static void ath5k_reg_notifier(struct wiphy *wiphy,
+			       struct regulatory_request *request)
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath5k_hw *ah = hw->priv;
 	struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
 
-	return ath_reg_notifier_apply(wiphy, request, regulatory);
+	ath_reg_notifier_apply(wiphy, request, regulatory);
 }
 
 /********************\
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index ab363f3..a78afa9 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1613,6 +1613,10 @@
 	ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
 
 	ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
+	if (WARN_ON(ee_mode < 0)) {
+		ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
+		return;
+	}
 
 	/* completed NF calibration, test threshold */
 	nf = ath5k_hw_read_measured_noise_floor(ah);
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 4084b10..e2d8b2c 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -985,6 +985,8 @@
 		return;
 
 	ee_mode = ath5k_eeprom_mode_from_channel(channel);
+	if (WARN_ON(ee_mode < 0))
+		return;
 
 	/* Adjust power delta for channel 14 */
 	if (channel->center_freq == 2484)
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 5516a8c..752ffc4 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -427,6 +427,30 @@
 	return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
 }
 
+static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif,
+					      bool enable)
+{
+	int err;
+
+	if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
+		return;
+
+	if (vif->nw_type != INFRA_NETWORK)
+		return;
+
+	if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+		      vif->ar->fw_capabilities))
+		return;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
+		   enable ? "enable" : "disable");
+
+	err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
+					       vif->fw_vif_idx, enable);
+	if (err)
+		ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
+			   enable ? "enable" : "disable", err);
+}
 
 static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 				   struct cfg80211_connect_params *sme)
@@ -616,13 +640,13 @@
 					vif->req_bssid, vif->ch_hint,
 					ar->connect_ctrl_flags, nw_subtype);
 
-	/* disable background scan if period is 0 */
-	if (sme->bg_scan_period == 0)
+	if (sme->bg_scan_period == 0) {
+		/* disable background scan if period is 0 */
 		sme->bg_scan_period = 0xffff;
-
-	/* configure default value if not specified */
-	if (sme->bg_scan_period == -1)
+	} else if (sme->bg_scan_period == -1) {
+		/* configure default value if not specified */
 		sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
+	}
 
 	ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
 				  sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
@@ -767,7 +791,7 @@
 		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
 			   nw_type & ADHOC_CREATOR ? "creator" : "joiner");
 		cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
-		cfg80211_put_bss(bss);
+		cfg80211_put_bss(ar->wiphy, bss);
 		return;
 	}
 
@@ -778,7 +802,7 @@
 					assoc_req_ie, assoc_req_len,
 					assoc_resp_ie, assoc_resp_len,
 					WLAN_STATUS_SUCCESS, GFP_KERNEL);
-		cfg80211_put_bss(bss);
+		cfg80211_put_bss(ar->wiphy, bss);
 	} else if (vif->sme_state == SME_CONNECTED) {
 		/* inform roam event to cfg80211 */
 		cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
@@ -1454,10 +1478,10 @@
 		return -EIO;
 
 	if (pmgmt) {
-		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
 		mode.pwr_mode = REC_POWER;
 	} else {
-		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
+		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
 		mode.pwr_mode = MAX_PERF_POWER;
 	}
 
@@ -1509,7 +1533,7 @@
 	list_del(&vif->list);
 	spin_unlock_bh(&ar->list_lock);
 
-	ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
+	ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
 
 	ath6kl_cfg80211_vif_cleanup(vif);
 
@@ -1559,17 +1583,13 @@
 set_iface_type:
 	switch (type) {
 	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
 		vif->next_mode = INFRA_NETWORK;
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		vif->next_mode = ADHOC_NETWORK;
 		break;
 	case NL80211_IFTYPE_AP:
-		vif->next_mode = AP_NETWORK;
-		break;
-	case NL80211_IFTYPE_P2P_CLIENT:
-		vif->next_mode = INFRA_NETWORK;
-		break;
 	case NL80211_IFTYPE_P2P_GO:
 		vif->next_mode = AP_NETWORK;
 		break;
@@ -1778,14 +1798,14 @@
 
 	if (vif->target_stats.rx_byte) {
 		sinfo->rx_bytes = vif->target_stats.rx_byte;
-		sinfo->filled |= STATION_INFO_RX_BYTES;
+		sinfo->filled |= STATION_INFO_RX_BYTES64;
 		sinfo->rx_packets = vif->target_stats.rx_pkt;
 		sinfo->filled |= STATION_INFO_RX_PACKETS;
 	}
 
 	if (vif->target_stats.tx_byte) {
 		sinfo->tx_bytes = vif->target_stats.tx_byte;
-		sinfo->filled |= STATION_INFO_TX_BYTES;
+		sinfo->filled |= STATION_INFO_TX_BYTES64;
 		sinfo->tx_packets = vif->target_stats.tx_pkt;
 		sinfo->filled |= STATION_INFO_TX_PACKETS;
 	}
@@ -2673,30 +2693,6 @@
 	return 0;
 }
 
-void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
-{
-	int err;
-
-	if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
-		return;
-
-	if (vif->nw_type != INFRA_NETWORK)
-		return;
-
-	if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
-		      vif->ar->fw_capabilities))
-		return;
-
-	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
-		   enable ? "enable" : "disable");
-
-	err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
-					       vif->fw_vif_idx, enable);
-	if (err)
-		ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
-			   enable ? "enable" : "disable", err);
-}
-
 static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
 				u8 *rsn_capab)
 {
@@ -2776,9 +2772,11 @@
 
 	ar->ap_mode_bkey.valid = false;
 
-	/* TODO:
-	 * info->interval
-	 */
+	ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx,
+						 info->beacon_interval);
+
+	if (ret)
+		ath6kl_warn("Failed to set beacon interval: %d\n", ret);
 
 	ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
 					 info->dtim_period);
@@ -3492,8 +3490,8 @@
 		ath6kl_cfg80211_stop(vif);
 }
 
-static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
-				      struct regulatory_request *request)
+static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
+				       struct regulatory_request *request)
 {
 	struct ath6kl *ar = wiphy_priv(wiphy);
 	u32 rates[IEEE80211_NUM_BANDS];
@@ -3506,17 +3504,13 @@
 		   request->processed ? " processed" : "",
 		   request->initiator, request->user_reg_hint_type);
 
-	/*
-	 * As firmware is not able intersect regdoms, we can only listen to
-	 * cellular hints.
-	 */
 	if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
-		return -EOPNOTSUPP;
+		return;
 
 	ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
 	if (ret) {
 		ath6kl_err("failed to set regdomain: %d\n", ret);
-		return ret;
+		return;
 	}
 
 	/*
@@ -3536,10 +3530,8 @@
 	if (ret) {
 		ath6kl_err("failed to start scan for a regdomain change: %d\n",
 			   ret);
-		return ret;
+		return;
 	}
-
-	return 0;
 }
 
 static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
@@ -3563,6 +3555,37 @@
 	return 0;
 }
 
+void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
+{
+	static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	bool discon_issued;
+
+	netif_stop_queue(vif->ndev);
+
+	clear_bit(WLAN_ENABLED, &vif->flags);
+
+	if (wmi_ready) {
+		discon_issued = test_bit(CONNECTED, &vif->flags) ||
+				test_bit(CONNECT_PEND, &vif->flags);
+		ath6kl_disconnect(vif);
+		del_timer(&vif->disconnect_timer);
+
+		if (discon_issued)
+			ath6kl_disconnect_event(vif, DISCONNECT_CMD,
+						(vif->nw_type & AP_NETWORK) ?
+						bcast_mac : vif->bssid,
+						0, NULL, 0);
+	}
+
+	if (vif->scan_req) {
+		cfg80211_scan_done(vif->scan_req, true);
+		vif->scan_req = NULL;
+	}
+
+	/* need to clean up enhanced bmiss detection fw state */
+	ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
+}
+
 void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
 {
 	struct ath6kl *ar = vif->ar;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index e5e70f3..b59becd 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -61,7 +61,5 @@
 
 struct ath6kl *ath6kl_cfg80211_create(void);
 void ath6kl_cfg80211_destroy(struct ath6kl *ar);
-/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
-void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
 
 #endif /* ATH6KL_CFG80211_H */
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 189d8fa..61b2f98 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -940,7 +940,7 @@
 			 bool wait_fot_compltn, bool cold_reset);
 void ath6kl_init_control_info(struct ath6kl_vif *vif);
 struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
-void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready);
+void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready);
 int ath6kl_init_hw_start(struct ath6kl *ar);
 int ath6kl_init_hw_stop(struct ath6kl *ar);
 int ath6kl_init_fetch_firmwares(struct ath6kl *ar);
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index ba6bd49..2813901 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -509,9 +509,7 @@
 {
 	struct sk_buff *skb;
 	skb = packet->skb;
-	if (skb != NULL)
-		dev_kfree_skb(skb);
-
+	dev_kfree_skb(skb);
 	kfree(packet);
 }
 
@@ -969,6 +967,22 @@
 	u16 payload_len;
 	int status = 0;
 
+	/*
+	 * ar->htc_target can be NULL due to a race condition that can occur
+	 * during driver initialization(we do 'ath6kl_hif_power_on' before
+	 * initializing 'ar->htc_target' via 'ath6kl_htc_create').
+	 * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as
+	 * usb_complete_t/callback function for 'usb_fill_bulk_urb'.
+	 * Thus the possibility of ar->htc_target being NULL
+	 * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
+	 */
+	if (WARN_ON_ONCE(!target)) {
+		ath6kl_err("Target not yet initialized\n");
+		status = -EINVAL;
+		goto free_skb;
+	}
+
+
 	netdata = skb->data;
 	netlen = skb->len;
 
@@ -1054,6 +1068,7 @@
 
 		dev_kfree_skb(skb);
 		skb = NULL;
+
 		goto free_skb;
 	}
 
@@ -1089,8 +1104,7 @@
 	skb = NULL;
 
 free_skb:
-	if (skb != NULL)
-		dev_kfree_skb(skb);
+	dev_kfree_skb(skb);
 
 	return status;
 
@@ -1184,7 +1198,7 @@
 		INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
 		INIT_LIST_HEAD(&ep->rx_bufq);
 		ep->target = target;
-		ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */
+		ep->pipe.tx_credit_flow_enabled = true;
 	}
 }
 
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index f21fa32..5d434cf 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1715,38 +1715,6 @@
 	}
 }
 
-/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
-void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
-{
-	static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-	bool discon_issued;
-
-	netif_stop_queue(vif->ndev);
-
-	clear_bit(WLAN_ENABLED, &vif->flags);
-
-	if (wmi_ready) {
-		discon_issued = test_bit(CONNECTED, &vif->flags) ||
-				test_bit(CONNECT_PEND, &vif->flags);
-		ath6kl_disconnect(vif);
-		del_timer(&vif->disconnect_timer);
-
-		if (discon_issued)
-			ath6kl_disconnect_event(vif, DISCONNECT_CMD,
-						(vif->nw_type & AP_NETWORK) ?
-						bcast_mac : vif->bssid,
-						0, NULL, 0);
-	}
-
-	if (vif->scan_req) {
-		cfg80211_scan_done(vif->scan_req, true);
-		vif->scan_req = NULL;
-	}
-
-	/* need to clean up enhanced bmiss detection fw state */
-	ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
-}
-
 void ath6kl_stop_txrx(struct ath6kl *ar)
 {
 	struct ath6kl_vif *vif, *tmp_vif;
@@ -1766,7 +1734,7 @@
 	list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {
 		list_del(&vif->list);
 		spin_unlock_bh(&ar->list_lock);
-		ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
+		ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
 		rtnl_lock();
 		ath6kl_cfg80211_vif_cleanup(vif);
 		rtnl_unlock();
@@ -1801,8 +1769,6 @@
 		   "attempting to reset target on instance destroy\n");
 	ath6kl_reset_device(ar, ar->target_type, true, true);
 
-	clear_bit(WLAN_ENABLED, &ar->flag);
-
 	up(&ar->sem);
 }
 EXPORT_SYMBOL(ath6kl_stop_txrx);
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 62bcc0d..5fcd342 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -159,10 +159,8 @@
 
 static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context)
 {
-	if (urb_context->skb != NULL) {
-		dev_kfree_skb(urb_context->skb);
-		urb_context->skb = NULL;
-	}
+	dev_kfree_skb(urb_context->skb);
+	urb_context->skb = NULL;
 
 	ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
 }
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 998f8b0..d76b5bd 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -751,6 +751,23 @@
 				   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
+				       u32 beacon_intvl)
+{
+	struct sk_buff *skb;
+	struct set_beacon_int_cmd *cmd;
+
+	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct set_beacon_int_cmd *) skb->data;
+
+	cmd->beacon_intvl = cpu_to_le32(beacon_intvl);
+	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+				   WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);
+}
+
 int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
 {
 	struct sk_buff *skb;
@@ -1108,7 +1125,7 @@
 	kfree(mgmt);
 	if (bss == NULL)
 		return -ENOMEM;
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(ar->wiphy, bss);
 
 	/*
 	 * Firmware doesn't return any event when scheduled scan has
@@ -2480,16 +2497,11 @@
 
 free_cmd_skb:
 	/* free up any resources left over (possibly due to an error) */
-	if (skb)
-		dev_kfree_skb(skb);
+	dev_kfree_skb(skb);
 
 free_data_skb:
-	for (index = 0; index < num_pri_streams; index++) {
-		if (data_sync_bufs[index].skb != NULL) {
-			dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
-				      skb);
-		}
-	}
+	for (index = 0; index < num_pri_streams; index++)
+		dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb);
 
 	return ret;
 }
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 98b1755..b5f2265 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1660,6 +1660,10 @@
 	u8 roam_ctrl;
 } __packed;
 
+struct set_beacon_int_cmd {
+	__le32 beacon_intvl;
+} __packed;
+
 struct set_dtim_cmd {
 	__le32 dtim_period;
 } __packed;
@@ -2649,6 +2653,8 @@
 int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
 int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
+int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
+				       u32 beacon_interval);
 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
 int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 7647ed6..17507dc 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -58,6 +58,7 @@
 	bool "Atheros ath9k debugging"
 	depends on ATH9K
 	select MAC80211_DEBUGFS
+	select RELAY
 	---help---
 	  Say Y, if you need access to ath9k's statistics for
 	  interrupts, rate control, etc.
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 3a69804..d1ff3c2 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -86,29 +86,25 @@
 
 	if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "no platform data specified\n");
-		ret = -EINVAL;
-		goto err_out;
+		return -EINVAL;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
 		dev_err(&pdev->dev, "no memory resource found\n");
-		ret = -ENXIO;
-		goto err_out;
+		return -ENXIO;
 	}
 
-	mem = ioremap_nocache(res->start, resource_size(res));
+	mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
 	if (mem == NULL) {
 		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err_out;
+		return -ENOMEM;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res == NULL) {
 		dev_err(&pdev->dev, "no IRQ resource found\n");
-		ret = -ENXIO;
-		goto err_iounmap;
+		return -ENXIO;
 	}
 
 	irq = res->start;
@@ -116,8 +112,7 @@
 	hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
 	if (hw == NULL) {
 		dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
-		ret = -ENOMEM;
-		goto err_iounmap;
+		return -ENOMEM;
 	}
 
 	SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -156,9 +151,6 @@
  err_free_hw:
 	ieee80211_free_hw(hw);
 	platform_set_drvdata(pdev, NULL);
- err_iounmap:
-	iounmap(mem);
- err_out:
 	return ret;
 }
 
@@ -168,12 +160,10 @@
 
 	if (hw) {
 		struct ath_softc *sc = hw->priv;
-		void __iomem *mem = sc->mem;
 
 		ath9k_deinit_device(sc);
 		free_irq(sc->irq, sc);
 		ieee80211_free_hw(sc->hw);
-		iounmap(mem);
 		platform_set_drvdata(pdev, NULL);
 	}
 
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index e09ec40..7ecd40f 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -152,7 +152,8 @@
 	ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
 		aniState->ofdmNoiseImmunityLevel,
 		immunityLevel, BEACON_RSSI(ah),
-		aniState->rssiThrLow, aniState->rssiThrHigh);
+		ATH9K_ANI_RSSI_THR_LOW,
+		ATH9K_ANI_RSSI_THR_HIGH);
 
 	if (!scan)
 		aniState->ofdmNoiseImmunityLevel = immunityLevel;
@@ -173,7 +174,7 @@
 
 	weak_sig = entry_ofdm->ofdm_weak_signal_on;
 	if (ah->opmode == NL80211_IFTYPE_STATION &&
-	    BEACON_RSSI(ah) <= aniState->rssiThrHigh)
+	    BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
 		weak_sig = true;
 
 	if (aniState->ofdmWeakSigDetect != weak_sig)
@@ -216,11 +217,11 @@
 
 	ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
 		aniState->cckNoiseImmunityLevel, immunityLevel,
-		BEACON_RSSI(ah), aniState->rssiThrLow,
-		aniState->rssiThrHigh);
+		BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
+		ATH9K_ANI_RSSI_THR_HIGH);
 
 	if (ah->opmode == NL80211_IFTYPE_STATION &&
-	    BEACON_RSSI(ah) <= aniState->rssiThrLow &&
+	    BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
 	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
 		immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
 
@@ -418,9 +419,6 @@
 		return;
 
 	aniState = &ah->curchan->ani;
-	if (WARN_ON(!aniState))
-		return;
-
 	if (!ath9k_hw_ani_read_counters(ah))
 		return;
 
@@ -489,23 +487,6 @@
 }
 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
-void ath9k_hw_ani_setup(struct ath_hw *ah)
-{
-	int i;
-
-	static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
-	static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
-	static const int coarseLow[] = { -64, -64, -64, -64, -70 };
-	static const int firpwr[] = { -78, -78, -78, -78, -80 };
-
-	for (i = 0; i < 5; i++) {
-		ah->totalSizeDesired[i] = totalSizeDesired[i];
-		ah->coarse_high[i] = coarseHigh[i];
-		ah->coarse_low[i] = coarseLow[i];
-		ah->firpwr[i] = firpwr[i];
-	}
-}
-
 void ath9k_hw_ani_init(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -531,8 +512,6 @@
 
 		ani->ofdmsTurn = true;
 
-		ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
-		ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
 		ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
 		ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
 		ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 1485bf5..dddb136 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -104,7 +104,6 @@
 };
 
 struct ar5416AniState {
-	struct ath9k_channel *c;
 	u8 noiseImmunityLevel;
 	u8 ofdmNoiseImmunityLevel;
 	u8 cckNoiseImmunityLevel;
@@ -113,15 +112,9 @@
 	u8 spurImmunityLevel;
 	u8 firstepLevel;
 	u8 ofdmWeakSigDetect;
-	u8 cckWeakSigThreshold;
 	u32 listenTime;
-	int32_t rssiThrLow;
-	int32_t rssiThrHigh;
 	u32 ofdmPhyErrCount;
 	u32 cckPhyErrCount;
-	int16_t pktRssi[2];
-	int16_t ofdmErrRssi[2];
-	int16_t cckErrRssi[2];
 	struct ath9k_ani_default iniDef;
 };
 
@@ -147,7 +140,6 @@
 
 void ath9k_enable_mib_counters(struct ath_hw *ah);
 void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
-void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
 
 #endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
index f81e7fc..467ccfa 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
@@ -466,7 +466,7 @@
 };
 
 static const u32 ar5416BB_RfGain[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
+	/* Addr      5G          2G        */
 	{0x00009a00, 0x00000000, 0x00000000},
 	{0x00009a04, 0x00000040, 0x00000040},
 	{0x00009a08, 0x00000080, 0x00000080},
@@ -546,12 +546,12 @@
 };
 
 static const u32 ar5416Bank3[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
+	/* Addr      5G          2G        */
 	{0x000098f0, 0x01400018, 0x01c00018},
 };
 
 static const u32 ar5416Bank6[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
+	/* Addr      5G          2G        */
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
@@ -588,7 +588,7 @@
 };
 
 static const u32 ar5416Bank6TPC[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
+	/* Addr      5G          2G        */
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 874186b..fd69376 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -470,16 +470,15 @@
 static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
 {
 #define ATH_ALLOC_BANK(bank, size) do { \
-		bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
-		if (!bank) { \
-			ath_err(common, "Cannot allocate RF banks\n"); \
-			return -ENOMEM; \
-		} \
+		bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \
+		if (!bank) \
+			goto error; \
 	} while (0);
 
 	struct ath_common *common = ath9k_hw_common(ah);
 
-	BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
+	if (AR_SREV_9280_20_OR_LATER(ah))
+	    return 0;
 
 	ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
 	ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
@@ -492,35 +491,12 @@
 
 	return 0;
 #undef ATH_ALLOC_BANK
+error:
+	ath_err(common, "Cannot allocate RF banks\n");
+	return -ENOMEM;
 }
 
 
-/**
- * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
- * @ah: atheros hardware struture
- * For the external AR2133/AR5133 radios banks.
- */
-static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
-#define ATH_FREE_BANK(bank) do { \
-		kfree(bank); \
-		bank = NULL; \
-	} while (0);
-
-	BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
-
-	ATH_FREE_BANK(ah->analogBank0Data);
-	ATH_FREE_BANK(ah->analogBank1Data);
-	ATH_FREE_BANK(ah->analogBank2Data);
-	ATH_FREE_BANK(ah->analogBank3Data);
-	ATH_FREE_BANK(ah->analogBank6Data);
-	ATH_FREE_BANK(ah->analogBank6TPCData);
-	ATH_FREE_BANK(ah->analogBank7Data);
-	ATH_FREE_BANK(ah->bank6Temp);
-
-#undef ATH_FREE_BANK
-}
-
 /* *
  * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
  * @ah: atheros hardware structure
@@ -1380,7 +1356,7 @@
 	conf->radar_inband = 8;
 }
 
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 	static const u32 ar5416_cca_regs[6] = {
@@ -1391,12 +1367,15 @@
 		AR_PHY_CH1_EXT_CCA,
 		AR_PHY_CH2_EXT_CCA
 	};
+	int ret;
+
+	ret = ar5008_hw_rf_alloc_ext_banks(ah);
+	if (ret)
+	    return ret;
 
 	priv_ops->rf_set_freq = ar5008_hw_set_channel;
 	priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
 
-	priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks;
-	priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks;
 	priv_ops->set_rf_regs = ar5008_hw_set_rf_regs;
 	priv_ops->set_channel_regs = ar5008_hw_set_channel_regs;
 	priv_ops->init_bb = ar5008_hw_init_bb;
@@ -1421,4 +1400,5 @@
 	ar5008_hw_set_nf_limits(ah);
 	ar5008_hw_set_radar_conf(ah);
 	memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
+	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index ea4a230..59524e1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -460,7 +460,7 @@
 };
 
 static const u32 ar5416Bank6_9100[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
+	/* Addr      5G          2G        */
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
@@ -497,7 +497,7 @@
 };
 
 static const u32 ar5416Bank6TPC_9100[][3] = {
-	/* Addr      5G_HT20     5G_HT40   */
+	/* Addr      5G          2G        */
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
 	{0x0000989c, 0x00000000, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 648da3e..f053d97 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -23,13 +23,13 @@
 
 /* General hardware code for the A5008/AR9001/AR9002 hadware families */
 
-static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
+static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
 {
 	if (AR_SREV_9271(ah)) {
 		INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271);
 		INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271);
 		INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg);
-		return;
+		return 0;
 	}
 
 	if (ah->config.pcie_clock_req)
@@ -102,9 +102,9 @@
 		u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
 		u32 *data;
 
-		data = kmalloc(size, GFP_KERNEL);
+		data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
 		if (!data)
-			return;
+			return -ENOMEM;
 
 		memcpy(data, addac->ia_array, size);
 		addac->ia_array = data;
@@ -120,6 +120,7 @@
 		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
 		       ar9287Common_japan_2484_cck_fir_coeff_9287_1_1);
 	}
+	return 0;
 }
 
 static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
@@ -409,22 +410,30 @@
 }
 
 /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
-void ar9002_hw_attach_ops(struct ath_hw *ah)
+int ar9002_hw_attach_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+	int ret;
 
-	priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
+	ret = ar9002_hw_init_mode_regs(ah);
+	if (ret)
+		return ret;
+
 	priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
 
 	ops->config_pci_powersave = ar9002_hw_configpcipowersave;
 
-	ar5008_hw_attach_phy_ops(ah);
+	ret = ar5008_hw_attach_phy_ops(ah);
+	if (ret)
+		return ret;
+
 	if (AR_SREV_9280_20_OR_LATER(ah))
 		ar9002_hw_attach_phy_ops(ah);
 
 	ar9002_hw_attach_calib_ops(ah);
 	ar9002_hw_attach_mac_ops(ah);
+	return 0;
 }
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 846dd79..f400351 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -555,14 +555,73 @@
 	REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
 }
 
+static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
+				    struct ath_spec_scan *param)
+{
+	u8 count;
+
+	if (!param->enabled) {
+		REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+			    AR_PHY_SPECTRAL_SCAN_ENABLE);
+		return;
+	}
+	REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+	if (param->short_repeat)
+		REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+			    AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+	else
+		REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+			    AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+	/* on AR92xx, the highest bit of count will make the the chip send
+	 * spectral samples endlessly. Check if this really was intended,
+	 * and fix otherwise.
+	 */
+	count = param->count;
+	if (param->endless)
+		count = 0x80;
+	else if (count & 0x80)
+		count = 0x7f;
+
+	REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+		      AR_PHY_SPECTRAL_SCAN_COUNT, count);
+	REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+		      AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+	REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+		      AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+	return;
+}
+
+static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+	/* Activate spectral scan */
+	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+		    AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	/* Poll for spectral scan complete */
+	if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+			   AR_PHY_SPECTRAL_SCAN_ACTIVE,
+			   0, AH_WAIT_TIMEOUT)) {
+		ath_err(common, "spectral scan wait failed\n");
+		return;
+	}
+}
+
 void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
 	priv_ops->set_rf_regs = NULL;
-	priv_ops->rf_alloc_ext_banks = NULL;
-	priv_ops->rf_free_ext_banks = NULL;
 	priv_ops->rf_set_freq = ar9002_hw_set_channel;
 	priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
 	priv_ops->olc_init = ar9002_olc_init;
@@ -571,6 +630,9 @@
 
 	ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
 	ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+	ops->spectral_scan_config = ar9002_hw_spectral_scan_config;
+	ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
+	ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;
 
 	ar9002_hw_set_nf_limits(ah);
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 262e1e0..db5ffad 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -744,6 +744,186 @@
 	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
+static const u32 ar9300Modes_mixed_ob_db_tx_gain_table_2p2[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+	{0x0000a544, 0x52022470, 0x52022470, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x55022490, 0x55022490, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59022492, 0x59022492, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5d022692, 0x5d022692, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61022892, 0x61022892, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x65024890, 0x65024890, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x69024892, 0x69024892, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6e024c92, 0x6e024c92, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x52822470, 0x52822470, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x55822490, 0x55822490, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59822492, 0x59822492, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5d822692, 0x5d822692, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61822892, 0x61822892, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x65824890, 0x65824890, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x69824892, 0x69824892, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+	{0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+	{0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+	{0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_type5_tx_gain_table_2p2[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+	{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+	{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+	{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+	{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
 static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
 	/* Addr      allmodes  */
 	{0x0000a000, 0x00010000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 56317b0..4cc1394 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -32,7 +32,6 @@
 
 enum ar9003_cal_types {
 	IQ_MISMATCH_CAL = BIT(0),
-	TEMP_COMP_CAL = BIT(1),
 };
 
 static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@@ -49,7 +48,7 @@
 		 */
 		REG_RMW_FIELD(ah, AR_PHY_TIMING4,
 			      AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
-		currCal->calData->calCountMax);
+			      currCal->calData->calCountMax);
 		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
 
 		ath_dbg(common, CALIBRATE,
@@ -58,14 +57,8 @@
 		/* Kick-off cal */
 		REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
 		break;
-	case TEMP_COMP_CAL:
-		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
-			      AR_PHY_65NM_CH0_THERM_LOCAL, 1);
-		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
-			      AR_PHY_65NM_CH0_THERM_START, 1);
-
-		ath_dbg(common, CALIBRATE,
-			"starting Temperature Compensation Calibration\n");
+	default:
+		ath_err(common, "Invalid calibration type\n");
 		break;
 	}
 }
@@ -323,6 +316,14 @@
 static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
 {
 	ah->iq_caldata.calData = &iq_cal_single_sample;
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		ah->enabled_cals |= TX_IQ_CAL;
+		if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
+			ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
+	}
+
+	ah->supp_cals = IQ_MISMATCH_CAL;
 }
 
 /*
@@ -959,22 +960,68 @@
 		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
 }
 
+static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
+					 struct ath9k_channel *chan)
+{
+	int i;
+
+	if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
+		return;
+
+	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+		if (!(ah->rxchainmask & (1 << i)))
+			continue;
+		ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
+	}
+}
+
+static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
+{
+	u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
+					  AR_PHY_CL_TAB_1,
+					  AR_PHY_CL_TAB_2 };
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+	bool txclcal_done = false;
+	int i, j;
+
+	if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
+		return;
+
+	txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
+			  AR_PHY_AGC_CONTROL_CLC_SUCCESS);
+
+	if (caldata->done_txclcal_once) {
+		for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+			if (!(ah->txchainmask & (1 << i)))
+				continue;
+			for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+				REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
+					  caldata->tx_clcal[i][j]);
+		}
+	} else if (is_reusable && txclcal_done) {
+		for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+			if (!(ah->txchainmask & (1 << i)))
+				continue;
+			for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+				caldata->tx_clcal[i][j] =
+					REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
+		}
+		caldata->done_txclcal_once = true;
+	}
+}
+
 static bool ar9003_hw_init_cal(struct ath_hw *ah,
 			       struct ath9k_channel *chan)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_hw_cal_data *caldata = ah->caldata;
-	bool txiqcal_done = false, txclcal_done = false;
+	bool txiqcal_done = false;
 	bool is_reusable = true, status = true;
-	bool run_rtt_cal = false, run_agc_cal;
+	bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
 	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
 	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
 					  AR_PHY_AGC_CONTROL_FLTR_CAL   |
 					  AR_PHY_AGC_CONTROL_PKDET_CAL;
-	int i, j;
-	u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
-					  AR_PHY_CL_TAB_1,
-					  AR_PHY_CL_TAB_2 };
 
 	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
 
@@ -1014,7 +1061,8 @@
 		}
 	}
 
-	if (!(ah->enabled_cals & TX_IQ_CAL))
+	if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
+	    !(ah->enabled_cals & TX_IQ_CAL))
 		goto skip_tx_iqcal;
 
 	/* Do Tx IQ Calibration */
@@ -1034,21 +1082,22 @@
 			REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
 				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
 		txiqcal_done = run_agc_cal = true;
-		goto skip_tx_iqcal;
-	} else if (caldata && !caldata->done_txiqcal_once)
+	} else if (caldata && !caldata->done_txiqcal_once) {
 		run_agc_cal = true;
+		sep_iq_cal = true;
+	}
 
+skip_tx_iqcal:
 	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
 		ar9003_mci_init_cal_req(ah, &is_reusable);
 
-	if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
+	if (sep_iq_cal) {
 		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
 		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
 		udelay(5);
 		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
 	}
 
-skip_tx_iqcal:
 	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
 		/* Calibrate the AGC */
 		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
@@ -1059,14 +1108,8 @@
 		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
 				       AR_PHY_AGC_CONTROL_CAL,
 				       0, AH_WAIT_TIMEOUT);
-		if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
-			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-				if (!(ah->rxchainmask & (1 << i)))
-					continue;
-				ar9003_hw_manual_peak_cal(ah, i,
-							  IS_CHAN_2GHZ(chan));
-			}
-		}
+
+		ar9003_hw_do_manual_peak_cal(ah, chan);
 	}
 
 	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
@@ -1091,31 +1134,7 @@
 	else if (caldata && caldata->done_txiqcal_once)
 		ar9003_hw_tx_iq_cal_reload(ah);
 
-#define CL_TAB_ENTRY(reg_base)	(reg_base + (4 * j))
-	if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
-		txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
-					   AR_PHY_AGC_CONTROL_CLC_SUCCESS);
-		if (caldata->done_txclcal_once) {
-			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-				if (!(ah->txchainmask & (1 << i)))
-					continue;
-				for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
-					REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
-						  caldata->tx_clcal[i][j]);
-			}
-		} else if (is_reusable && txclcal_done) {
-			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-				if (!(ah->txchainmask & (1 << i)))
-					continue;
-				for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
-					caldata->tx_clcal[i][j] =
-						REG_READ(ah,
-						  CL_TAB_ENTRY(cl_idx[i]));
-			}
-			caldata->done_txclcal_once = true;
-		}
-	}
-#undef CL_TAB_ENTRY
+	ar9003_hw_cl_cal_post_proc(ah, is_reusable);
 
 	if (run_rtt_cal && caldata) {
 		if (is_reusable) {
@@ -1133,20 +1152,10 @@
 
 	/* Initialize list pointers */
 	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
-	ah->supp_cals = IQ_MISMATCH_CAL;
 
-	if (ah->supp_cals & IQ_MISMATCH_CAL) {
-		INIT_CAL(&ah->iq_caldata);
-		INSERT_CAL(ah, &ah->iq_caldata);
-		ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
-	}
-
-	if (ah->supp_cals & TEMP_COMP_CAL) {
-		INIT_CAL(&ah->tempCompCalData);
-		INSERT_CAL(ah, &ah->tempCompCalData);
-		ath_dbg(common, CALIBRATE,
-			"enabling Temperature Compensation Calibration\n");
-	}
+	INIT_CAL(&ah->iq_caldata);
+	INSERT_CAL(ah, &ah->iq_caldata);
+	ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
 
 	/* Initialize current pointer to first element in list */
 	ah->cal_list_curr = ah->cal_list;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 562186c..881e989 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -4586,14 +4586,14 @@
 	return 0;
 }
 
-static int ar9003_hw_power_control_override(struct ath_hw *ah,
-					    int frequency,
-					    int *correction,
-					    int *voltage, int *temperature)
+static void ar9003_hw_power_control_override(struct ath_hw *ah,
+					     int frequency,
+					     int *correction,
+					     int *voltage, int *temperature)
 {
-	int tempSlope = 0;
+	int temp_slope = 0, temp_slope1 = 0, temp_slope2 = 0;
 	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
-	int f[8], t[8], i;
+	int f[8], t[8], t1[3], t2[3], i;
 
 	REG_RMW(ah, AR_PHY_TPC_11_B0,
 		(correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
@@ -4624,38 +4624,108 @@
 	 * enable temperature compensation
 	 * Need to use register names
 	 */
-	if (frequency < 4000)
-		tempSlope = eep->modalHeader2G.tempSlope;
-	else if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
-		for (i = 0; i < 8; i++) {
-			t[i] = eep->base_ext1.tempslopextension[i];
-			f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
-		}
-		tempSlope = ar9003_hw_power_interpolate((s32) frequency,
-							f, t, 8);
-	} else if (eep->base_ext2.tempSlopeLow != 0) {
-		t[0] = eep->base_ext2.tempSlopeLow;
-		f[0] = 5180;
-		t[1] = eep->modalHeader5G.tempSlope;
-		f[1] = 5500;
-		t[2] = eep->base_ext2.tempSlopeHigh;
-		f[2] = 5785;
-		tempSlope = ar9003_hw_power_interpolate((s32) frequency,
-							f, t, 3);
-	} else
-		tempSlope = eep->modalHeader5G.tempSlope;
+	if (frequency < 4000) {
+		temp_slope = eep->modalHeader2G.tempSlope;
+	} else {
+		if (AR_SREV_9550(ah)) {
+			t[0] = eep->base_ext1.tempslopextension[2];
+			t1[0] = eep->base_ext1.tempslopextension[3];
+			t2[0] = eep->base_ext1.tempslopextension[4];
+			f[0] = 5180;
 
-	REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
+			t[1] = eep->modalHeader5G.tempSlope;
+			t1[1] = eep->base_ext1.tempslopextension[0];
+			t2[1] = eep->base_ext1.tempslopextension[1];
+			f[1] = 5500;
+
+			t[2] = eep->base_ext1.tempslopextension[5];
+			t1[2] = eep->base_ext1.tempslopextension[6];
+			t2[2] = eep->base_ext1.tempslopextension[7];
+			f[2] = 5785;
+
+			temp_slope = ar9003_hw_power_interpolate(frequency,
+								 f, t, 3);
+			temp_slope1 = ar9003_hw_power_interpolate(frequency,
+								   f, t1, 3);
+			temp_slope2 = ar9003_hw_power_interpolate(frequency,
+								   f, t2, 3);
+
+			goto tempslope;
+		}
+
+		if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
+			for (i = 0; i < 8; i++) {
+				t[i] = eep->base_ext1.tempslopextension[i];
+				f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
+			}
+			temp_slope = ar9003_hw_power_interpolate((s32) frequency,
+								 f, t, 8);
+		} else if (eep->base_ext2.tempSlopeLow != 0) {
+			t[0] = eep->base_ext2.tempSlopeLow;
+			f[0] = 5180;
+			t[1] = eep->modalHeader5G.tempSlope;
+			f[1] = 5500;
+			t[2] = eep->base_ext2.tempSlopeHigh;
+			f[2] = 5785;
+			temp_slope = ar9003_hw_power_interpolate((s32) frequency,
+								 f, t, 3);
+		} else {
+			temp_slope = eep->modalHeader5G.tempSlope;
+		}
+	}
+
+tempslope:
+	if (AR_SREV_9550(ah)) {
+		/*
+		 * AR955x has tempSlope register for each chain.
+		 * Check whether temp_compensation feature is enabled or not.
+		 */
+		if (eep->baseEepHeader.featureEnable & 0x1) {
+			if (frequency < 4000) {
+				REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+					      AR_PHY_TPC_19_ALPHA_THERM,
+					      eep->base_ext2.tempSlopeLow);
+				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+					      AR_PHY_TPC_19_ALPHA_THERM,
+					      temp_slope);
+				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+					      AR_PHY_TPC_19_ALPHA_THERM,
+					      eep->base_ext2.tempSlopeHigh);
+			} else {
+				REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+					      AR_PHY_TPC_19_ALPHA_THERM,
+					      temp_slope);
+				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+					      AR_PHY_TPC_19_ALPHA_THERM,
+					      temp_slope1);
+				REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+					      AR_PHY_TPC_19_ALPHA_THERM,
+					      temp_slope2);
+			}
+		} else {
+			/*
+			 * If temp compensation is not enabled,
+			 * set all registers to 0.
+			 */
+			REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+				      AR_PHY_TPC_19_ALPHA_THERM, 0);
+			REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+				      AR_PHY_TPC_19_ALPHA_THERM, 0);
+			REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+				      AR_PHY_TPC_19_ALPHA_THERM, 0);
+		}
+	} else {
+		REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+			      AR_PHY_TPC_19_ALPHA_THERM, temp_slope);
+	}
 
 	if (AR_SREV_9462_20(ah))
 		REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
-			      AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope);
+			      AR_PHY_TPC_19_B1_ALPHA_THERM, temp_slope);
 
 
 	REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
 		      temperature[0]);
-
-	return 0;
 }
 
 /* Apply the recorded correction values. */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 59bf5f3..a3523c9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -507,28 +507,59 @@
 	else if (AR_SREV_9580(ah))
 		INIT_INI_ARRAY(&ah->iniModesTxGain,
 			ar9580_1p0_mixed_ob_db_tx_gain_table);
+	else
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
 }
 
+static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
+{
+	if (AR_SREV_9485_11(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9485Modes_green_ob_db_tx_gain_1_1);
+	else if (AR_SREV_9340(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9340Modes_ub124_tx_gain_table_1p0);
+	else if (AR_SREV_9580(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9580_1p0_type5_tx_gain_table);
+	else if (AR_SREV_9300_22(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9300Modes_type5_tx_gain_table_2p2);
+}
+
+static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
+{
+	if (AR_SREV_9340(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0);
+	else if (AR_SREV_9485_11(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9485Modes_green_spur_ob_db_tx_gain_1_1);
+	else if (AR_SREV_9580(ah))
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9580_1p0_type6_tx_gain_table);
+}
+
+typedef void (*ath_txgain_tab)(struct ath_hw *ah);
+
 static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
 {
-	switch (ar9003_hw_get_tx_gain_idx(ah)) {
-	case 0:
-	default:
-		ar9003_tx_gain_table_mode0(ah);
-		break;
-	case 1:
-		ar9003_tx_gain_table_mode1(ah);
-		break;
-	case 2:
-		ar9003_tx_gain_table_mode2(ah);
-		break;
-	case 3:
-		ar9003_tx_gain_table_mode3(ah);
-		break;
-	case 4:
-		ar9003_tx_gain_table_mode4(ah);
-		break;
-	}
+	static const ath_txgain_tab modes[] = {
+		ar9003_tx_gain_table_mode0,
+		ar9003_tx_gain_table_mode1,
+		ar9003_tx_gain_table_mode2,
+		ar9003_tx_gain_table_mode3,
+		ar9003_tx_gain_table_mode4,
+		ar9003_tx_gain_table_mode5,
+		ar9003_tx_gain_table_mode6,
+	};
+	int idx = ar9003_hw_get_tx_gain_idx(ah);
+
+	if (idx >= ARRAY_SIZE(modes))
+		idx = 0;
+
+	modes[idx](ah);
 }
 
 static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
@@ -673,7 +704,7 @@
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
-	priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
+	ar9003_hw_init_mode_regs(ah);
 	priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
 
 	ops->config_pci_powersave = ar9003_hw_configpcipowersave;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 3afc24b..2bf6548 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -68,7 +68,7 @@
 static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	u16 bMode, fracMode = 0, aModeRefSel = 0;
-	u32 freq, channelSel = 0, reg32 = 0;
+	u32 freq, chan_frac, div, channelSel = 0, reg32 = 0;
 	struct chan_centers centers;
 	int loadSynthChannel;
 
@@ -77,9 +77,6 @@
 
 	if (freq < 4800) {     /* 2 GHz, fractional mode */
 		if (AR_SREV_9330(ah)) {
-			u32 chan_frac;
-			u32 div;
-
 			if (ah->is_clk_25mhz)
 				div = 75;
 			else
@@ -89,34 +86,40 @@
 			chan_frac = (((freq * 4) % div) * 0x20000) / div;
 			channelSel = (channelSel << 17) | chan_frac;
 		} else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
-			u32 chan_frac;
-
 			/*
-			 * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+			 * freq_ref = 40 / (refdiva >> amoderefsel);
+			 * where refdiva=1 and amoderefsel=0
 			 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
 			 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
 			 */
 			channelSel = (freq * 4) / 120;
 			chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
 			channelSel = (channelSel << 17) | chan_frac;
-		} else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
+		} else if (AR_SREV_9340(ah)) {
 			if (ah->is_clk_25mhz) {
-				u32 chan_frac;
-
 				channelSel = (freq * 2) / 75;
 				chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
 				channelSel = (channelSel << 17) | chan_frac;
-			} else
+			} else {
 				channelSel = CHANSEL_2G(freq) >> 1;
-		} else
+			}
+		} else if (AR_SREV_9550(ah)) {
+			if (ah->is_clk_25mhz)
+				div = 75;
+			else
+				div = 120;
+
+			channelSel = (freq * 4) / div;
+			chan_frac = (((freq * 4) % div) * 0x20000) / div;
+			channelSel = (channelSel << 17) | chan_frac;
+		} else {
 			channelSel = CHANSEL_2G(freq);
+		}
 		/* Set to 2G mode */
 		bMode = 1;
 	} else {
 		if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
 		    ah->is_clk_25mhz) {
-			u32 chan_frac;
-
 			channelSel = freq / 75;
 			chan_frac = ((freq % 75) * 0x20000) / 75;
 			channelSel = (channelSel << 17) | chan_frac;
@@ -1437,6 +1440,67 @@
 	return 0;
 }
 
+static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
+					   struct ath_spec_scan *param)
+{
+	u8 count;
+
+	if (!param->enabled) {
+		REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+			    AR_PHY_SPECTRAL_SCAN_ENABLE);
+		return;
+	}
+
+	REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+	/* on AR93xx and newer, count = 0 will make the the chip send
+	 * spectral samples endlessly. Check if this really was intended,
+	 * and fix otherwise.
+	 */
+	count = param->count;
+	if (param->endless)
+		count = 0;
+	else if (param->count == 0)
+		count = 1;
+
+	if (param->short_repeat)
+		REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+			    AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+	else
+		REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+			    AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+	REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+		      AR_PHY_SPECTRAL_SCAN_COUNT, count);
+	REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+		      AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+	REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+		      AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+	return;
+}
+
+static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+	/* Activate spectral scan */
+	REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+		    AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	/* Poll for spectral scan complete */
+	if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+			   AR_PHY_SPECTRAL_SCAN_ACTIVE,
+			   0, AH_WAIT_TIMEOUT)) {
+		ath_err(common, "spectral scan wait failed\n");
+		return;
+	}
+}
+
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1470,6 +1534,9 @@
 	ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
 	ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
 	ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
+	ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+	ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
+	ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
 
 	ar9003_hw_set_nf_limits(ah);
 	ar9003_hw_set_radar_conf(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 1079562..e717741 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1028,7 +1028,7 @@
 #define AR_PHY_TPC_5_B2          (AR_SM2_BASE + 0x208)
 #define AR_PHY_TPC_6_B2          (AR_SM2_BASE + 0x20c)
 #define AR_PHY_TPC_11_B2         (AR_SM2_BASE + 0x220)
-#define AR_PHY_PDADC_TAB_2       (AR_SM2_BASE + 0x240)
+#define AR_PHY_TPC_19_B2         (AR_SM2_BASE + 0x240)
 #define AR_PHY_TX_IQCAL_STATUS_B2   (AR_SM2_BASE + 0x48c)
 #define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i)    (AR_SM2_BASE + 0x450 + ((_i) << 2))
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
index f69d292..25db921 100644
--- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
@@ -1172,6 +1172,106 @@
 	{0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
 };
 
+static const u32 ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
+	{0x0000a394, 0x00000444, 0x00000444, 0x00000404, 0x00000404},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x02000001, 0x02000001},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x05000003, 0x05000003},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0a000005, 0x0a000005},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0e000201, 0x0e000201},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x11000203, 0x11000203},
+	{0x0000a518, 0x21002220, 0x21002220, 0x14000401, 0x14000401},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x18000403, 0x18000403},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1b000602, 0x1b000602},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x1f000802, 0x1f000802},
+	{0x0000a528, 0x34022225, 0x34022225, 0x21000620, 0x21000620},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x25000820, 0x25000820},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x29000822, 0x29000822},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x2d000824, 0x2d000824},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x30000828, 0x30000828},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x3400082a, 0x3400082a},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38000849, 0x38000849},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3b000a2c, 0x3b000a2c},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x3e000e2b, 0x3e000e2b},
+	{0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42000e2d, 0x42000e2d},
+	{0x0000a550, 0x61024a6c, 0x61024a6c, 0x4500124a, 0x4500124a},
+	{0x0000a554, 0x66026a6c, 0x66026a6c, 0x4900124c, 0x4900124c},
+	{0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c00126c, 0x4c00126c},
+	{0x0000a55c, 0x7002708c, 0x7002708c, 0x4f00128c, 0x4f00128c},
+	{0x0000a560, 0x7302b08a, 0x7302b08a, 0x52001290, 0x52001290},
+	{0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x02800001, 0x02800001},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x05800003, 0x05800003},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0a800005, 0x0a800005},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0e800201, 0x0e800201},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x11800203, 0x11800203},
+	{0x0000a598, 0x21820220, 0x21820220, 0x14800401, 0x14800401},
+	{0x0000a59c, 0x27820223, 0x27820223, 0x18800403, 0x18800403},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800602, 0x1b800602},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800802, 0x1f800802},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x21800620, 0x21800620},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x25800820, 0x25800820},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x29800822, 0x29800822},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2d800824, 0x2d800824},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x30800828, 0x30800828},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x3480082a, 0x3480082a},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38800849, 0x38800849},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b800a2c, 0x3b800a2c},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e800e2b, 0x3e800e2b},
+	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42800e2d, 0x42800e2d},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4580124a, 0x4580124a},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4980124c, 0x4980124c},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c80126c, 0x4c80126c},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x4f80128c, 0x4f80128c},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x52801290, 0x52801290},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01404000, 0x01404000, 0x01404501, 0x01404501},
+	{0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02008802, 0x02008802, 0x01404501, 0x01404501},
+	{0x0000a620, 0x0300cc03, 0x0300cc03, 0x03c0cf02, 0x03c0cf02},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03c0cf03, 0x03c0cf03},
+	{0x0000a628, 0x0300cc03, 0x0300cc03, 0x04011004, 0x04011004},
+	{0x0000a62c, 0x03810c03, 0x03810c03, 0x05419405, 0x05419405},
+	{0x0000a630, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+	{0x0000a634, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+	{0x0000a638, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+	{0x0000a63c, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
+	{0x00016044, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
+	{0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+	{0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
+	{0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000},
+	{0x00016444, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
+	{0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+};
+
 static const u32 ar9340_1p0_mac_core[][2] = {
 	/* Addr      allmodes  */
 	{0x00000008, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index a3710f3..712f415 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -260,6 +260,79 @@
 	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
 };
 
+static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+	{0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+	{0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+	{0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+	{0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
 static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
@@ -450,6 +523,79 @@
 
 #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
 
+static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+	{0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x07000203, 0x07000203},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x14000406, 0x14000406},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1800040a, 0x1800040a},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000460, 0x1c000460},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x22000463, 0x22000463},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x26000465, 0x26000465},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2e0006e0, 0x2e0006e0},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+	{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+	{0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+	{0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+	{0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
 static const u32 ar9485_1_1[][2] = {
 	/* Addr      allmodes  */
 	{0x0000a580, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
index df97f21..ccc5b6c 100644
--- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
@@ -23,16 +23,16 @@
 static const u32 ar955x_1p0_radio_postamble[][5] = {
 	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
 	{0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330},
-	{0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a},
-	{0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800},
-	{0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a},
-	{0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+	{0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a},
+	{0x000160ac, 0xa4647c00, 0xa4647c00, 0x24647c00, 0x24647c00},
+	{0x000160b0, 0x01885f52, 0x01885f52, 0x01885f52, 0x01885f52},
+	{0x00016104, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
 	{0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
 	{0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
-	{0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+	{0x00016504, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
 	{0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
 	{0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
-	{0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+	{0x00016904, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
 	{0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
 	{0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
 };
@@ -69,15 +69,15 @@
 	{0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
 	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
 	{0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
-	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+	{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
 	{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
 	{0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
 	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
 	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
 	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
-	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
 	{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
-	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
 	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
 	{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
 	{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
@@ -125,7 +125,7 @@
 	{0x00016094, 0x00000000},
 	{0x000160a0, 0x0a108ffe},
 	{0x000160a4, 0x812fc370},
-	{0x000160a8, 0x423c8000},
+	{0x000160a8, 0x423c8100},
 	{0x000160b4, 0x92480080},
 	{0x000160c0, 0x006db6d0},
 	{0x000160c4, 0x6db6db60},
@@ -134,7 +134,7 @@
 	{0x00016100, 0x11999601},
 	{0x00016108, 0x00080010},
 	{0x00016144, 0x02084080},
-	{0x00016148, 0x000080c0},
+	{0x00016148, 0x00008040},
 	{0x00016280, 0x01800804},
 	{0x00016284, 0x00038dc5},
 	{0x00016288, 0x00000000},
@@ -178,7 +178,7 @@
 	{0x00016500, 0x11999601},
 	{0x00016508, 0x00080010},
 	{0x00016544, 0x02084080},
-	{0x00016548, 0x000080c0},
+	{0x00016548, 0x00008040},
 	{0x00016780, 0x00000000},
 	{0x00016784, 0x00000000},
 	{0x00016788, 0x00400705},
@@ -218,7 +218,7 @@
 	{0x00016900, 0x11999601},
 	{0x00016908, 0x00080010},
 	{0x00016944, 0x02084080},
-	{0x00016948, 0x000080c0},
+	{0x00016948, 0x00008040},
 	{0x00016b80, 0x00000000},
 	{0x00016b84, 0x00000000},
 	{0x00016b88, 0x00400705},
@@ -245,9 +245,9 @@
 
 static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
 	/* Addr      5G_HT20_L   5G_HT40_L   5G_HT20_M   5G_HT40_M   5G_HT20_H   5G_HT40_H   2G_HT40     2G_HT20  */
-	{0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
-	{0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
-	{0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+	{0x0000a2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+	{0x0000a2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+	{0x0000a2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
 	{0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
 	{0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da},
 	{0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000},
@@ -256,63 +256,63 @@
 	{0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006},
 	{0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a},
 	{0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c},
-	{0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e},
-	{0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064},
-	{0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242},
-	{0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229},
-	{0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2},
-	{0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203},
-	{0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803},
-	{0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881},
-	{0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809},
-	{0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814},
-	{0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c},
-	{0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e},
-	{0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812},
-	{0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884},
-	{0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84},
-	{0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69},
-	{0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4},
-	{0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3},
-	{0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5},
-	{0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced},
-	{0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4},
-	{0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4},
-	{0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4},
-	{0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4},
-	{0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
-	{0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
+	{0x0000a518, 0x1700002b, 0x1700002b, 0x1700002b, 0x1700002b, 0x1600002b, 0x1600002b, 0x1700000e, 0x1700000e},
+	{0x0000a51c, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1a00002d, 0x1a00002d, 0x1b000064, 0x1b000064},
+	{0x0000a520, 0x20000031, 0x20000031, 0x1f000031, 0x1f000031, 0x1e000031, 0x1e000031, 0x1f000242, 0x1f000242},
+	{0x0000a524, 0x24000051, 0x24000051, 0x23000051, 0x23000051, 0x23000051, 0x23000051, 0x23000229, 0x23000229},
+	{0x0000a528, 0x27000071, 0x27000071, 0x27000071, 0x27000071, 0x26000071, 0x26000071, 0x270002a2, 0x270002a2},
+	{0x0000a52c, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2c001203, 0x2c001203},
+	{0x0000a530, 0x3000028c, 0x3000028c, 0x2f00028c, 0x2f00028c, 0x2e00028c, 0x2e00028c, 0x30001803, 0x30001803},
+	{0x0000a534, 0x34000290, 0x34000290, 0x33000290, 0x33000290, 0x32000290, 0x32000290, 0x33000881, 0x33000881},
+	{0x0000a538, 0x37000292, 0x37000292, 0x36000292, 0x36000292, 0x35000292, 0x35000292, 0x38001809, 0x38001809},
+	{0x0000a53c, 0x3b02028d, 0x3b02028d, 0x3a02028d, 0x3a02028d, 0x3902028d, 0x3902028d, 0x3a000814, 0x3a000814},
+	{0x0000a540, 0x3f020291, 0x3f020291, 0x3e020291, 0x3e020291, 0x3d020291, 0x3d020291, 0x3f001a0c, 0x3f001a0c},
+	{0x0000a544, 0x44020490, 0x44020490, 0x43020490, 0x43020490, 0x42020490, 0x42020490, 0x43001a0e, 0x43001a0e},
+	{0x0000a548, 0x48020492, 0x48020492, 0x47020492, 0x47020492, 0x46020492, 0x46020492, 0x46001812, 0x46001812},
+	{0x0000a54c, 0x4c020692, 0x4c020692, 0x4b020692, 0x4b020692, 0x4a020692, 0x4a020692, 0x49001884, 0x49001884},
+	{0x0000a550, 0x50020892, 0x50020892, 0x4f020892, 0x4f020892, 0x4e020892, 0x4e020892, 0x4d001e84, 0x4d001e84},
+	{0x0000a554, 0x53040891, 0x53040891, 0x53040891, 0x53040891, 0x52040891, 0x52040891, 0x50001e69, 0x50001e69},
+	{0x0000a558, 0x58040893, 0x58040893, 0x57040893, 0x57040893, 0x56040893, 0x56040893, 0x550006f4, 0x550006f4},
+	{0x0000a55c, 0x5c0408b4, 0x5c0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x59000ad3, 0x59000ad3},
+	{0x0000a560, 0x610408b6, 0x610408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e000ad5, 0x5e000ad5},
+	{0x0000a564, 0x670408f6, 0x670408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x61001ced, 0x61001ced},
+	{0x0000a568, 0x6a040cf6, 0x6a040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x660018d4, 0x660018d4},
+	{0x0000a56c, 0x6d040d76, 0x6d040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x660018d4, 0x660018d4},
+	{0x0000a570, 0x70060db6, 0x70060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x660018d4, 0x660018d4},
+	{0x0000a574, 0x730a0df6, 0x730a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x660018d4, 0x660018d4},
+	{0x0000a578, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
+	{0x0000a57c, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
 	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000},
-	{0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02},
-	{0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04},
-	{0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000},
-	{0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000},
-	{0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000},
-	{0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000},
-	{0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05},
-	{0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06},
-	{0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07},
-	{0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07},
-	{0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07},
-	{0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07},
-	{0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
-	{0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
-	{0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+	{0x0000a60c, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x03804000, 0x03804000},
+	{0x0000a610, 0x04008b01, 0x04008b01, 0x04008b01, 0x04008b01, 0x03c08b01, 0x03c08b01, 0x0300ca02, 0x0300ca02},
+	{0x0000a614, 0x05811403, 0x05811403, 0x05411303, 0x05411303, 0x05411303, 0x05411303, 0x00000e04, 0x00000e04},
+	{0x0000a618, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
+	{0x0000a61c, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
+	{0x0000a620, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
+	{0x0000a624, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
+	{0x0000a628, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03804c05, 0x03804c05},
+	{0x0000a62c, 0x06815604, 0x06815604, 0x06415504, 0x06415504, 0x06015504, 0x06015504, 0x0701de06, 0x0701de06},
+	{0x0000a630, 0x07819a05, 0x07819a05, 0x07419905, 0x07419905, 0x07019805, 0x07019805, 0x07819c07, 0x07819c07},
+	{0x0000a634, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+	{0x0000a638, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+	{0x0000a63c, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+	{0x0000b2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+	{0x0000b2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+	{0x0000b2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
 	{0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
-	{0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
-	{0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
-	{0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+	{0x0000c2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+	{0x0000c2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+	{0x0000c2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
 	{0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
 	{0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
-	{0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+	{0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
 	{0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84},
 	{0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
-	{0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+	{0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
 	{0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
-	{0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+	{0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
 };
 
 static const u32 ar955x_1p0_mac_core[][2] = {
@@ -846,7 +846,7 @@
 	{0x0000a44c, 0x00000001},
 	{0x0000a450, 0x00010000},
 	{0x0000a458, 0x00000000},
-	{0x0000a644, 0x3fad9d74},
+	{0x0000a644, 0xbfad9d74},
 	{0x0000a648, 0x0048060a},
 	{0x0000a64c, 0x00003c37},
 	{0x0000a670, 0x03020100},
@@ -1277,7 +1277,7 @@
 	{0x0000801c, 0x148ec02b, 0x148ec057},
 	{0x00008318, 0x000044c0, 0x00008980},
 	{0x00009e00, 0x0372131c, 0x0372131c},
-	{0x0000a230, 0x0000000b, 0x00000016},
+	{0x0000a230, 0x0000400b, 0x00004016},
 	{0x0000a254, 0x00000898, 0x00001130},
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
index 6e1915a..28fd992 100644
--- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
@@ -685,6 +685,82 @@
 
 #define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
 
+#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
+
+static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+	{0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+	{0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+	{0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+	{0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+	{0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
 static const u32 ar9580_1p0_soc_preamble[][2] = {
 	/* Addr      allmodes  */
 	{0x000040a4, 0x00a0c1c9},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 42794c5..a56b241 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -109,14 +109,11 @@
 	void *dd_desc;
 	dma_addr_t dd_desc_paddr;
 	u32 dd_desc_len;
-	struct ath_buf *dd_bufptr;
 };
 
 int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 		      struct list_head *head, const char *name,
 		      int nbuf, int ndesc, bool is_tx);
-void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
-			 struct list_head *head);
 
 /***********/
 /* RX / TX */
@@ -319,10 +316,11 @@
 	unsigned int rxfilter;
 	struct list_head rxbuf;
 	struct ath_descdma rxdma;
-	struct ath_buf *rx_bufptr;
 	struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
 
 	struct sk_buff *frag;
+
+	u32 ampdu_ref;
 };
 
 int ath_startrecv(struct ath_softc *sc);
@@ -336,14 +334,12 @@
 void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
 void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
-void ath_draintxq(struct ath_softc *sc,
-		     struct ath_txq *txq, bool retry_tx);
+bool ath_drain_all_txq(struct ath_softc *sc);
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
-void ath_tx_cleanup(struct ath_softc *sc);
 int ath_txq_update(struct ath_softc *sc, int qnum,
 		   struct ath9k_tx_queue_info *q);
 void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
@@ -393,6 +389,7 @@
 	u16 bmiss_timeout;
 	u8 dtim_count;
 	bool enable_beacon;
+	bool ibss_creator;
 };
 
 struct ath_beacon {
@@ -672,6 +669,23 @@
 	int nadhocs;   /* number of adhoc vifs */
 };
 
+/* enum spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ *	something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ *	is performed manually.
+ * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
+ *	during a channel scan.
+ */
+enum spectral_mode {
+	SPECTRAL_DISABLED = 0,
+	SPECTRAL_BACKGROUND,
+	SPECTRAL_MANUAL,
+	SPECTRAL_CHANSCAN,
+};
+
 struct ath_softc {
 	struct ieee80211_hw *hw;
 	struct device *dev;
@@ -740,6 +754,11 @@
 	u8 ant_tx, ant_rx;
 	struct dfs_pattern_detector *dfs_detector;
 	u32 wow_enabled;
+	/* relay(fs) channel for spectral scan */
+	struct rchan *rfs_chan_spec_scan;
+	enum spectral_mode spectral_mode;
+	struct ath_spec_scan spec_config;
+	int scanning;
 
 #ifdef CONFIG_PM_SLEEP
 	atomic_t wow_got_bmiss_intr;
@@ -748,6 +767,133 @@
 #endif
 };
 
+#define SPECTRAL_SCAN_BITMASK		0x10
+/* Radar info packet format, used for DFS and spectral formats. */
+struct ath_radar_info {
+	u8 pulse_length_pri;
+	u8 pulse_length_ext;
+	u8 pulse_bw_info;
+} __packed;
+
+/* The HT20 spectral data has 4 bytes of additional information at it's end.
+ *
+ * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: all bins  max_magnitude[9:2]
+ * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_mag_info {
+	u8 all_bins[3];
+	u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_NUM_BINS		56
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data by -1/+2. This struct is for reference only.
+ */
+struct ath_ht20_fft_packet {
+	u8 data[SPECTRAL_HT20_NUM_BINS];
+	struct ath_ht20_mag_info mag_info;
+	struct ath_radar_info radar_info;
+} __packed;
+
+#define SPECTRAL_HT20_TOTAL_DATA_LEN	(sizeof(struct ath_ht20_fft_packet))
+
+/* Dynamic 20/40 mode:
+ *
+ * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: lower bins  max_magnitude[9:2]
+ * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
+ * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: upper bins  max_magnitude[9:2]
+ * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_40_mag_info {
+	u8 lower_bins[3];
+	u8 upper_bins[3];
+	u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_40_NUM_BINS		128
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data. This struct is for reference only.
+ */
+struct ath_ht20_40_fft_packet {
+	u8 data[SPECTRAL_HT20_40_NUM_BINS];
+	struct ath_ht20_40_mag_info mag_info;
+	struct ath_radar_info radar_info;
+} __packed;
+
+
+#define SPECTRAL_HT20_40_TOTAL_DATA_LEN	(sizeof(struct ath_ht20_40_fft_packet))
+
+/* grabs the max magnitude from the all/upper/lower bins */
+static inline u16 spectral_max_magnitude(u8 *bins)
+{
+	return (bins[0] & 0xc0) >> 6 |
+	       (bins[1] & 0xff) << 2 |
+	       (bins[2] & 0x03) << 10;
+}
+
+/* return the max magnitude from the all/upper/lower bins */
+static inline u8 spectral_max_index(u8 *bins)
+{
+	s8 m = (bins[2] & 0xfc) >> 2;
+
+	/* TODO: this still doesn't always report the right values ... */
+	if (m > 32)
+		m |= 0xe0;
+	else
+		m &= ~0xe0;
+
+	return m + 29;
+}
+
+/* return the bitmap weight from the all/upper/lower bins */
+static inline u8 spectral_bitmap_weight(u8 *bins)
+{
+	return bins[0] & 0x3f;
+}
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+	ATH_FFT_SAMPLE_HT20 = 1,
+};
+
+struct fft_sample_tlv {
+	u8 type;	/* see ath_fft_sample */
+	__be16 length;
+	/* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+	struct fft_sample_tlv tlv;
+
+	u8 max_exp;
+
+	__be16 freq;
+	s8 rssi;
+	s8 noise;
+
+	__be16 max_magnitude;
+	u8 max_index;
+	u8 bitmap_weight;
+
+	__be64 tsf;
+
+	u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
 void ath9k_tasklet(unsigned long data);
 int ath_cabq_update(struct ath_softc *);
 
@@ -770,6 +916,10 @@
 void ath9k_reload_chainmask_settings(struct ath_softc *sc);
 
 bool ath9k_uses_beacons(int type);
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+			       enum spectral_mode spectral_mode);
+
 
 #ifdef CONFIG_ATH9K_PCI
 int ath_pci_init(void);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 2ca355e..5f05c26 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -199,7 +199,7 @@
 		if (sc->nvifs > 1) {
 			ath_dbg(common, BEACON,
 				"Flushing previous cabq traffic\n");
-			ath_draintxq(sc, cabq, false);
+			ath_draintxq(sc, cabq);
 		}
 	}
 
@@ -407,12 +407,17 @@
 	}
 }
 
-static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
+/*
+ * Both nexttbtt and intval have to be in usecs.
+ */
+static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
+			      u32 intval, bool reset_tsf)
 {
 	struct ath_hw *ah = sc->sc_ah;
 
 	ath9k_hw_disable_interrupts(ah);
-	ath9k_hw_reset_tsf(ah);
+	if (reset_tsf)
+		ath9k_hw_reset_tsf(ah);
 	ath9k_beaconq_config(sc);
 	ath9k_hw_beaconinit(ah, nexttbtt, intval);
 	sc->beacon.bmisscnt = 0;
@@ -442,10 +447,12 @@
 	else
 		ah->imask &= ~ATH9K_INT_SWBA;
 
-	ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
+	ath_dbg(common, BEACON,
+		"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+		(conf->enable_beacon) ? "Enable" : "Disable",
 		nexttbtt, intval, conf->beacon_interval);
 
-	ath9k_beacon_init(sc, nexttbtt, intval);
+	ath9k_beacon_init(sc, nexttbtt, intval, true);
 }
 
 /*
@@ -586,17 +593,45 @@
 	ath9k_reset_beacon_status(sc);
 
 	intval = TU_TO_USEC(conf->beacon_interval);
-	nexttbtt = intval;
+
+	if (conf->ibss_creator) {
+		nexttbtt = intval;
+	} else {
+		u32 tbtt, offset, tsftu;
+		u64 tsf;
+
+		/*
+		 * Pull nexttbtt forward to reflect the current
+		 * sync'd TSF.
+		 */
+		tsf = ath9k_hw_gettsf64(ah);
+		tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
+		offset = tsftu % conf->beacon_interval;
+		tbtt = tsftu - offset;
+		if (offset)
+			tbtt += conf->beacon_interval;
+
+		nexttbtt = TU_TO_USEC(tbtt);
+	}
 
 	if (conf->enable_beacon)
 		ah->imask |= ATH9K_INT_SWBA;
 	else
 		ah->imask &= ~ATH9K_INT_SWBA;
 
-	ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
+	ath_dbg(common, BEACON,
+		"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+		(conf->enable_beacon) ? "Enable" : "Disable",
 		nexttbtt, intval, conf->beacon_interval);
 
-	ath9k_beacon_init(sc, nexttbtt, intval);
+	ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator);
+
+	/*
+	 * Set the global 'beacon has been configured' flag for the
+	 * joiner case in IBSS mode.
+	 */
+	if (!conf->ibss_creator && conf->enable_beacon)
+		set_bit(SC_OP_BEACONS, &sc->sc_flags);
 }
 
 bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
@@ -639,6 +674,7 @@
 	cur_conf->dtim_period = bss_conf->dtim_period;
 	cur_conf->listen_interval = 1;
 	cur_conf->dtim_count = 1;
+	cur_conf->ibss_creator = bss_conf->ibss_creator;
 	cur_conf->bmiss_timeout =
 		ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
 
@@ -666,34 +702,59 @@
 {
 	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+	unsigned long flags;
+	bool skip_beacon = false;
 
 	if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
 		ath9k_cache_beacon_config(sc, bss_conf);
 		ath9k_set_beacon(sc);
 		set_bit(SC_OP_BEACONS, &sc->sc_flags);
-	} else {
+		return;
+
+	}
+
+	/*
+	 * Take care of multiple interfaces when
+	 * enabling/disabling SWBA.
+	 */
+	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+		if (!bss_conf->enable_beacon &&
+		    (sc->nbcnvifs <= 1)) {
+			cur_conf->enable_beacon = false;
+		} else if (bss_conf->enable_beacon) {
+			cur_conf->enable_beacon = true;
+			ath9k_cache_beacon_config(sc, bss_conf);
+		}
+	}
+
+	/*
+	 * Configure the HW beacon registers only when we have a valid
+	 * beacon interval.
+	 */
+	if (cur_conf->beacon_interval) {
 		/*
-		 * Take care of multiple interfaces when
-		 * enabling/disabling SWBA.
+		 * If we are joining an existing IBSS network, start beaconing
+		 * only after a TSF-sync has taken place. Ensure that this
+		 * happens by setting the appropriate flags.
 		 */
-		if (changed & BSS_CHANGED_BEACON_ENABLED) {
-			if (!bss_conf->enable_beacon &&
-			    (sc->nbcnvifs <= 1)) {
-				cur_conf->enable_beacon = false;
-			} else if (bss_conf->enable_beacon) {
-				cur_conf->enable_beacon = true;
-				ath9k_cache_beacon_config(sc, bss_conf);
-			}
-		}
-
-		if (cur_conf->beacon_interval) {
+		if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
+		    bss_conf->enable_beacon) {
+			spin_lock_irqsave(&sc->sc_pm_lock, flags);
+			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+			spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+			skip_beacon = true;
+		} else {
 			ath9k_set_beacon(sc);
-
-			if (cur_conf->enable_beacon)
-				set_bit(SC_OP_BEACONS, &sc->sc_flags);
-			else
-				clear_bit(SC_OP_BEACONS, &sc->sc_flags);
 		}
+
+		/*
+		 * Do not set the SC_OP_BEACONS flag for IBSS joiner mode
+		 * here, it is done in ath9k_beacon_config_adhoc().
+		 */
+		if (cur_conf->enable_beacon && !skip_beacon)
+			set_bit(SC_OP_BEACONS, &sc->sc_flags);
+		else
+			clear_bit(SC_OP_BEACONS, &sc->sc_flags);
 	}
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index e585fc8..3714b97 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
+#include <linux/relay.h>
 #include <asm/unaligned.h>
 
 #include "ath9k.h"
@@ -894,6 +895,7 @@
 	RXS_ERR("RX-Bytes-All", rx_bytes_all);
 	RXS_ERR("RX-Beacons", rx_beacons);
 	RXS_ERR("RX-Frags", rx_frags);
+	RXS_ERR("RX-Spectral", rx_spectral);
 
 	if (len > size)
 		len = size;
@@ -965,6 +967,290 @@
 	.llseek = default_llseek,
 };
 
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char *mode = "";
+	unsigned int len;
+
+	switch (sc->spectral_mode) {
+	case SPECTRAL_DISABLED:
+		mode = "disable";
+		break;
+	case SPECTRAL_BACKGROUND:
+		mode = "background";
+		break;
+	case SPECTRAL_CHANSCAN:
+		mode = "chanscan";
+		break;
+	case SPECTRAL_MANUAL:
+		mode = "manual";
+		break;
+	}
+	len = strlen(mode);
+	return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	if (strncmp("trigger", buf, 7) == 0) {
+		ath9k_spectral_scan_trigger(sc->hw);
+	} else if (strncmp("background", buf, 9) == 0) {
+		ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
+		ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
+	} else if (strncmp("chanscan", buf, 8) == 0) {
+		ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
+		ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
+	} else if (strncmp("manual", buf, 6) == 0) {
+		ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
+		ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
+	} else if (strncmp("disable", buf, 7) == 0) {
+		ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
+		ath_dbg(common, CONFIG, "spectral scan: disabled\n");
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+	.read = read_file_spec_scan_ctl,
+	.write = write_file_spec_scan_ctl,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_short_repeat(struct file *file,
+					       char __user *user_buf,
+					       size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_short_repeat(struct file *file,
+						const char __user *user_buf,
+						size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	unsigned long val;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 0 || val > 1)
+		return -EINVAL;
+
+	sc->spec_config.short_repeat = val;
+	return count;
+}
+
+static const struct file_operations fops_spectral_short_repeat = {
+	.read = read_file_spectral_short_repeat,
+	.write = write_file_spectral_short_repeat,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_count(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "%d\n", sc->spec_config.count);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+					 const char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	unsigned long val;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	sc->spec_config.count = val;
+	return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+	.read = read_file_spectral_count,
+	.write = write_file_spectral_count,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_period(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "%d\n", sc->spec_config.period);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_period(struct file *file,
+					  const char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	unsigned long val;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	sc->spec_config.period = val;
+	return count;
+}
+
+static const struct file_operations fops_spectral_period = {
+	.read = read_file_spectral_period,
+	.write = write_file_spectral_period,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_fft_period(struct file *file,
+					     char __user *user_buf,
+					     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_fft_period(struct file *file,
+					      const char __user *user_buf,
+					      size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	unsigned long val;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 0 || val > 15)
+		return -EINVAL;
+
+	sc->spec_config.fft_period = val;
+	return count;
+}
+
+static const struct file_operations fops_spectral_fft_period = {
+	.read = read_file_spectral_fft_period,
+	.write = write_file_spectral_fft_period,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+					      struct dentry *parent,
+					      umode_t mode,
+					      struct rchan_buf *buf,
+					      int *is_global)
+{
+	struct dentry *buf_file;
+
+	buf_file = debugfs_create_file(filename, mode, parent, buf,
+				       &relay_file_operations);
+	*is_global = 1;
+	return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+	debugfs_remove(dentry);
+
+	return 0;
+}
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+			       struct fft_sample_tlv *fft_sample_tlv)
+{
+	int length;
+	if (!sc->rfs_chan_spec_scan)
+		return;
+
+	length = __be16_to_cpu(fft_sample_tlv->length) +
+		 sizeof(*fft_sample_tlv);
+	relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+	.create_buf_file = create_buf_file_handler,
+	.remove_buf_file = remove_buf_file_handler,
+};
+
+
 static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
@@ -1779,6 +2065,24 @@
 			    &fops_base_eeprom);
 	debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_modal_eeprom);
+	sc->rfs_chan_spec_scan = relay_open("spectral_scan",
+					    sc->debug.debugfs_phy,
+					    262144, 4, &rfs_spec_scan_cb,
+					    NULL);
+	debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc,
+			    &fops_spec_scan_ctl);
+	debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc,
+			    &fops_spectral_short_repeat);
+	debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc, &fops_spectral_count);
+	debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc, &fops_spectral_period);
+	debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR,
+			    sc->debug.debugfs_phy, sc,
+			    &fops_spectral_fft_period);
+
 #ifdef CONFIG_ATH9K_MAC_DEBUG
 	debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_samps);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 6df2ab6..410d6d8 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -23,6 +23,7 @@
 
 struct ath_txq;
 struct ath_buf;
+struct fft_sample_tlv;
 
 #ifdef CONFIG_ATH9K_DEBUGFS
 #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
@@ -218,6 +219,7 @@
  * @rx_too_many_frags_err:  Frames dropped due to too-many-frags received.
  * @rx_beacons:  No. of beacons received.
  * @rx_frags:  No. of rx-fragements received.
+ * @rx_spectral: No of spectral packets received.
  */
 struct ath_rx_stats {
 	u32 rx_pkts_all;
@@ -236,6 +238,7 @@
 	u32 rx_too_many_frags_err;
 	u32 rx_beacons;
 	u32 rx_frags;
+	u32 rx_spectral;
 };
 
 struct ath_stats {
@@ -321,6 +324,10 @@
 			      struct ieee80211_vif *vif,
 			      struct ieee80211_sta *sta,
 			      struct dentry *dir);
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+			       struct fft_sample_tlv *fft_sample);
+
 #else
 
 #define RX_STAT_INC(c) /* NOP */
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
index 24877b0..467b600 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
@@ -288,11 +288,11 @@
 dfs_pattern_detector_init(enum nl80211_dfs_regions region)
 {
 	struct dfs_pattern_detector *dpd;
+
 	dpd = kmalloc(sizeof(*dpd), GFP_KERNEL);
-	if (dpd == NULL) {
-		pr_err("allocation of dfs_pattern_detector failed\n");
+	if (dpd == NULL)
 		return NULL;
-	}
+
 	*dpd = default_dpd;
 	INIT_LIST_HEAD(&dpd->channel_detectors);
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 05d5ba6..716058b 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -280,14 +280,14 @@
 	return ret;
 }
 
-static int ath9k_reg_notifier(struct wiphy *wiphy,
-			      struct regulatory_request *request)
+static void ath9k_reg_notifier(struct wiphy *wiphy,
+			       struct regulatory_request *request)
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath9k_htc_priv *priv = hw->priv;
 
-	return ath_reg_notifier_apply(wiphy, request,
-				      ath9k_hw_regulatory(priv->ah));
+	ath_reg_notifier_apply(wiphy, request,
+			       ath9k_hw_regulatory(priv->ah));
 }
 
 static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
@@ -783,7 +783,7 @@
 	priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
 	priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
 
-	snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
+	snprintf(hw->wiphy->fw_version, sizeof(hw->wiphy->fw_version), "%d.%d",
 		 priv->fw_version_major,
 		 priv->fw_version_minor);
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9c07a8f..a8016d7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1628,7 +1628,9 @@
 		if (!ret)
 			ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index b6a5a08..3ad1fd0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -1196,20 +1196,17 @@
 
 int ath9k_rx_init(struct ath9k_htc_priv *priv)
 {
-	struct ath_hw *ah = priv->ah;
-	struct ath_common *common = ath9k_hw_common(ah);
-	struct ath9k_htc_rxbuf *rxbuf;
 	int i = 0;
 
 	INIT_LIST_HEAD(&priv->rx.rxbuf);
 	spin_lock_init(&priv->rx.rxbuflock);
 
 	for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
-		rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
-		if (rxbuf == NULL) {
-			ath_err(common, "Unable to allocate RX buffers\n");
+		struct ath9k_htc_rxbuf *rxbuf =
+			kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
+		if (rxbuf == NULL)
 			goto err;
-		}
+
 		list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
 	}
 
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 0f2b97f..14b7011 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -101,22 +101,6 @@
 	ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan);
 }
 
-static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
-{
-	if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks)
-		return 0;
-
-	return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah);
-}
-
-static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
-	if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks)
-		return;
-
-	ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah);
-}
-
 static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
 					struct ath9k_channel *chan,
 					u16 modesIndex)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 7cb7870..2a2ae40 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -54,11 +54,6 @@
 	ath9k_hw_private_ops(ah)->init_cal_settings(ah);
 }
 
-static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
-{
-	ath9k_hw_private_ops(ah)->init_mode_regs(ah);
-}
-
 static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
 					struct ath9k_channel *chan)
 {
@@ -208,7 +203,7 @@
 	udelay(hw_delay + BASE_ACTIVATE_DELAY);
 }
 
-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
 			  int column, unsigned int *writecnt)
 {
 	int r;
@@ -554,28 +549,19 @@
 		ah->eep_ops->get_eeprom_ver(ah),
 		ah->eep_ops->get_eeprom_rev(ah));
 
-	ecode = ath9k_hw_rf_alloc_ext_banks(ah);
-	if (ecode) {
-		ath_err(ath9k_hw_common(ah),
-			"Failed allocating banks for external radio\n");
-		ath9k_hw_rf_free_ext_banks(ah);
-		return ecode;
-	}
-
-	if (ah->config.enable_ani) {
-		ath9k_hw_ani_setup(ah);
+	if (ah->config.enable_ani)
 		ath9k_hw_ani_init(ah);
-	}
 
 	return 0;
 }
 
-static void ath9k_hw_attach_ops(struct ath_hw *ah)
+static int ath9k_hw_attach_ops(struct ath_hw *ah)
 {
-	if (AR_SREV_9300_20_OR_LATER(ah))
-		ar9003_hw_attach_ops(ah);
-	else
-		ar9002_hw_attach_ops(ah);
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		return ar9002_hw_attach_ops(ah);
+
+	ar9003_hw_attach_ops(ah);
+	return 0;
 }
 
 /* Called for all hardware families */
@@ -611,7 +597,9 @@
 	ath9k_hw_init_defaults(ah);
 	ath9k_hw_init_config(ah);
 
-	ath9k_hw_attach_ops(ah);
+	r = ath9k_hw_attach_ops(ah);
+	if (r)
+		return r;
 
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
 		ath_err(common, "Couldn't wakeup chip\n");
@@ -675,8 +663,6 @@
 	if (!AR_SREV_9300_20_OR_LATER(ah))
 		ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
 
-	ath9k_hw_init_mode_regs(ah);
-
 	if (!ah->is_pciexpress)
 		ath9k_hw_disablepcie(ah);
 
@@ -1153,12 +1139,9 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 
 	if (common->state < ATH_HW_INITIALIZED)
-		goto free_hw;
+		return;
 
 	ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
-
-free_hw:
-	ath9k_hw_rf_free_ext_banks(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_deinit);
 
@@ -2576,12 +2559,6 @@
 		rx_chainmask >>= 1;
 	}
 
-	if (AR_SREV_9300_20_OR_LATER(ah)) {
-		ah->enabled_cals |= TX_IQ_CAL;
-		if (AR_SREV_9485_OR_LATER(ah))
-			ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
-	}
-
 	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
 		if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE))
 			pCap->hw_caps |= ATH9K_HW_CAP_MCI;
@@ -2590,7 +2567,6 @@
 			pCap->hw_caps |= ATH9K_HW_CAP_RTT;
 	}
 
-
 	if (AR_SREV_9280_20_OR_LATER(ah)) {
 		pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE |
 				 ATH9K_HW_WOW_PATTERN_MATCH_EXACT;
@@ -3005,13 +2981,8 @@
 	struct ath_gen_timer *timer;
 
 	timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
-
-	if (timer == NULL) {
-		ath_err(ath9k_hw_common(ah),
-			"Failed to allocate memory for hw timer[%d]\n",
-			timer_index);
+	if (timer == NULL)
 		return NULL;
-	}
 
 	/* allocate a hardware generic timer slot */
 	timer_table->timers[timer_index] = timer;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 9d26fc5..784e81c 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -397,6 +397,7 @@
 #define MAX_RTT_TABLE_ENTRY     6
 #define MAX_IQCAL_MEASUREMENT	8
 #define MAX_CL_TAB_ENTRY	16
+#define CL_TAB_ENTRY(reg_base)	(reg_base + (4 * j))
 
 struct ath9k_hw_cal_data {
 	u16 channel;
@@ -599,13 +600,10 @@
  * @init_cal_settings: setup types of calibrations supported
  * @init_cal: starts actual calibration
  *
- * @init_mode_regs: Initializes mode registers
  * @init_mode_gain_regs: Initialize TX/RX gain registers
  *
  * @rf_set_freq: change frequency
  * @spur_mitigate_freq: spur mitigation
- * @rf_alloc_ext_banks:
- * @rf_free_ext_banks:
  * @set_rf_regs:
  * @compute_pll_control: compute the PLL control value to use for
  *	AR_RTC_PLL_CONTROL for a given channel
@@ -620,7 +618,6 @@
 	void (*init_cal_settings)(struct ath_hw *ah);
 	bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
 
-	void (*init_mode_regs)(struct ath_hw *ah);
 	void (*init_mode_gain_regs)(struct ath_hw *ah);
 	void (*setup_calibration)(struct ath_hw *ah,
 				  struct ath9k_cal_list *currCal);
@@ -630,8 +627,6 @@
 			   struct ath9k_channel *chan);
 	void (*spur_mitigate_freq)(struct ath_hw *ah,
 				   struct ath9k_channel *chan);
-	int (*rf_alloc_ext_banks)(struct ath_hw *ah);
-	void (*rf_free_ext_banks)(struct ath_hw *ah);
 	bool (*set_rf_regs)(struct ath_hw *ah,
 			    struct ath9k_channel *chan,
 			    u16 modesIndex);
@@ -661,6 +656,37 @@
 };
 
 /**
+ * struct ath_spec_scan - parameters for Atheros spectral scan
+ *
+ * @enabled: enable/disable spectral scan
+ * @short_repeat: controls whether the chip is in spectral scan mode
+ *		  for 4 usec (enabled) or 204 usec (disabled)
+ * @count: number of scan results requested. There are special meanings
+ *	   in some chip revisions:
+ *	   AR92xx: highest bit set (>=128) for endless mode
+ *		   (spectral scan won't stopped until explicitly disabled)
+ *	   AR9300 and newer: 0 for endless mode
+ * @endless: true if endless mode is intended. Otherwise, count value is
+ *           corrected to the next possible value.
+ * @period: time duration between successive spectral scan entry points
+ *	    (period*256*Tclk). Tclk = ath_common->clockrate
+ * @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS
+ *
+ * Note: Tclk = 40MHz or 44MHz depending upon operating mode.
+ *	 Typically it's 44MHz in 2/5GHz on later chips, but there's
+ *	 a "fast clock" check for this in 5GHz.
+ *
+ */
+struct ath_spec_scan {
+	bool enabled;
+	bool short_repeat;
+	bool endless;
+	u8 count;
+	u8 period;
+	u8 fft_period;
+};
+
+/**
  * struct ath_hw_ops - callbacks used by hardware code and driver code
  *
  * This structure contains callbacks designed to to be used internally by
@@ -668,6 +694,10 @@
  *
  * @config_pci_powersave:
  * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
+ * @spectral_scan_config: set parameters for spectral scan and enable/disable it
+ * @spectral_scan_trigger: trigger a spectral scan run
+ * @spectral_scan_wait: wait for a spectral scan run to finish
  */
 struct ath_hw_ops {
 	void (*config_pci_powersave)(struct ath_hw *ah,
@@ -688,6 +718,10 @@
 	void (*antdiv_comb_conf_set)(struct ath_hw *ah,
 			struct ath_hw_antcomb_conf *antconf);
 	void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
+	void (*spectral_scan_config)(struct ath_hw *ah,
+				     struct ath_spec_scan *param);
+	void (*spectral_scan_trigger)(struct ath_hw *ah);
+	void (*spectral_scan_wait)(struct ath_hw *ah);
 };
 
 struct ath_nf_limits {
@@ -710,6 +744,7 @@
 struct ath_hw {
 	struct ath_ops reg_ops;
 
+	struct device *dev;
 	struct ieee80211_hw *hw;
 	struct ath_common common;
 	struct ath9k_hw_version hw_version;
@@ -771,7 +806,6 @@
 	struct ath9k_cal_list iq_caldata;
 	struct ath9k_cal_list adcgain_caldata;
 	struct ath9k_cal_list adcdc_caldata;
-	struct ath9k_cal_list tempCompCalData;
 	struct ath9k_cal_list *cal_list;
 	struct ath9k_cal_list *cal_list_last;
 	struct ath9k_cal_list *cal_list_curr;
@@ -830,10 +864,6 @@
 	/* ANI */
 	u32 proc_phyerr;
 	u32 aniperiod;
-	int totalSizeDesired[5];
-	int coarse_high[5];
-	int coarse_low[5];
-	int firpwr[5];
 	enum ath9k_ani_cmd ani_function;
 	u32 ani_skip_count;
 
@@ -979,7 +1009,7 @@
 void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
 			  int hw_delay);
 bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
 			  int column, unsigned int *writecnt);
 u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
@@ -1069,14 +1099,14 @@
 void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
 
 /* Hardware family op attach helpers */
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
+int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
 void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
 
 void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
 void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
 
-void ar9002_hw_attach_ops(struct ath_hw *ah);
+int ar9002_hw_attach_ops(struct ath_hw *ah);
 void ar9003_hw_attach_ops(struct ath_hw *ah);
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index f69ef5d4..af932c9 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/ath9k_platform.h>
 #include <linux/module.h>
+#include <linux/relay.h>
 
 #include "ath9k.h"
 
@@ -302,16 +303,15 @@
 	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 }
 
-static int ath9k_reg_notifier(struct wiphy *wiphy,
-			      struct regulatory_request *request)
+static void ath9k_reg_notifier(struct wiphy *wiphy,
+			       struct regulatory_request *request)
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ath_softc *sc = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
-	int ret;
 
-	ret = ath_reg_notifier_apply(wiphy, request, reg);
+	ath_reg_notifier_apply(wiphy, request, reg);
 
 	/* Set tx power */
 	if (ah->curchan) {
@@ -321,8 +321,6 @@
 		sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
 		ath9k_ps_restore(sc);
 	}
-
-	return ret;
 }
 
 /*
@@ -337,7 +335,7 @@
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	u8 *ds;
 	struct ath_buf *bf;
-	int i, bsize, error, desc_len;
+	int i, bsize, desc_len;
 
 	ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n",
 		name, nbuf, ndesc);
@@ -353,8 +351,7 @@
 	if ((desc_len % 4) != 0) {
 		ath_err(common, "ath_desc not DWORD aligned\n");
 		BUG_ON((desc_len % 4) != 0);
-		error = -ENOMEM;
-		goto fail;
+		return -ENOMEM;
 	}
 
 	dd->dd_desc_len = desc_len * nbuf * ndesc;
@@ -378,12 +375,11 @@
 	}
 
 	/* allocate descriptors */
-	dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
-					 &dd->dd_desc_paddr, GFP_KERNEL);
-	if (dd->dd_desc == NULL) {
-		error = -ENOMEM;
-		goto fail;
-	}
+	dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
+					  &dd->dd_desc_paddr, GFP_KERNEL);
+	if (!dd->dd_desc)
+		return -ENOMEM;
+
 	ds = (u8 *) dd->dd_desc;
 	ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
 		name, ds, (u32) dd->dd_desc_len,
@@ -391,12 +387,9 @@
 
 	/* allocate buffers */
 	bsize = sizeof(struct ath_buf) * nbuf;
-	bf = kzalloc(bsize, GFP_KERNEL);
-	if (bf == NULL) {
-		error = -ENOMEM;
-		goto fail2;
-	}
-	dd->dd_bufptr = bf;
+	bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
+	if (!bf)
+		return -ENOMEM;
 
 	for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
 		bf->bf_desc = ds;
@@ -422,12 +415,6 @@
 		list_add_tail(&bf->list, head);
 	}
 	return 0;
-fail2:
-	dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-			  dd->dd_desc_paddr);
-fail:
-	memset(dd, 0, sizeof(*dd));
-	return error;
 }
 
 static int ath9k_init_queues(struct ath_softc *sc)
@@ -457,11 +444,13 @@
 		     ATH9K_NUM_CHANNELS);
 
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
-		channels = kmemdup(ath9k_2ghz_chantable,
+		channels = devm_kzalloc(sc->dev,
 			sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
 		if (!channels)
 		    return -ENOMEM;
 
+		memcpy(channels, ath9k_2ghz_chantable,
+		       sizeof(ath9k_2ghz_chantable));
 		sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
 		sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
 		sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
@@ -472,14 +461,13 @@
 	}
 
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
-		channels = kmemdup(ath9k_5ghz_chantable,
+		channels = devm_kzalloc(sc->dev,
 			sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
-		if (!channels) {
-			if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
-				kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+		if (!channels)
 			return -ENOMEM;
-		}
 
+		memcpy(channels, ath9k_5ghz_chantable,
+		       sizeof(ath9k_5ghz_chantable));
 		sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
 		sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
 		sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
@@ -509,6 +497,13 @@
 
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
 		sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
+
+	sc->spec_config.enabled = 0;
+	sc->spec_config.short_repeat = true;
+	sc->spec_config.count = 8;
+	sc->spec_config.endless = false;
+	sc->spec_config.period = 0xFF;
+	sc->spec_config.fft_period = 0xF;
 }
 
 static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob,
@@ -565,10 +560,11 @@
 	int ret = 0, i;
 	int csz = 0;
 
-	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+	ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL);
 	if (!ah)
 		return -ENOMEM;
 
+	ah->dev = sc->dev;
 	ah->hw = sc->hw;
 	ah->hw_version.devid = devid;
 	ah->reg_ops.read = ath9k_ioread32;
@@ -636,7 +632,7 @@
 	if (pdata && pdata->eeprom_name) {
 		ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
 		if (ret)
-			goto err_eeprom;
+			return ret;
 	}
 
 	/* Initializes the hardware for all supported chipsets */
@@ -676,10 +672,6 @@
 	ath9k_hw_deinit(ah);
 err_hw:
 	ath9k_eeprom_release(sc);
-err_eeprom:
-	kfree(ah);
-	sc->sc_ah = NULL;
-
 	return ret;
 }
 
@@ -844,8 +836,8 @@
 
 	/* Bring up device */
 	error = ath9k_init_softc(devid, sc, bus_ops);
-	if (error != 0)
-		goto error_init;
+	if (error)
+		return error;
 
 	ah = sc->sc_ah;
 	common = ath9k_hw_common(ah);
@@ -855,19 +847,19 @@
 	error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
 			      ath9k_reg_notifier);
 	if (error)
-		goto error_regd;
+		goto deinit;
 
 	reg = &common->regulatory;
 
 	/* Setup TX DMA */
 	error = ath_tx_init(sc, ATH_TXBUF);
 	if (error != 0)
-		goto error_tx;
+		goto deinit;
 
 	/* Setup RX DMA */
 	error = ath_rx_init(sc, ATH_RXBUF);
 	if (error != 0)
-		goto error_rx;
+		goto deinit;
 
 	ath9k_init_txpower_limits(sc);
 
@@ -881,19 +873,19 @@
 	/* Register with mac80211 */
 	error = ieee80211_register_hw(hw);
 	if (error)
-		goto error_register;
+		goto rx_cleanup;
 
 	error = ath9k_init_debug(ah);
 	if (error) {
 		ath_err(common, "Unable to create debugfs files\n");
-		goto error_world;
+		goto unregister;
 	}
 
 	/* Handle world regulatory */
 	if (!ath_is_world_regd(reg)) {
 		error = regulatory_hint(hw->wiphy, reg->alpha2);
 		if (error)
-			goto error_world;
+			goto unregister;
 	}
 
 	ath_init_leds(sc);
@@ -901,17 +893,12 @@
 
 	return 0;
 
-error_world:
+unregister:
 	ieee80211_unregister_hw(hw);
-error_register:
+rx_cleanup:
 	ath_rx_cleanup(sc);
-error_rx:
-	ath_tx_cleanup(sc);
-error_tx:
-	/* Nothing */
-error_regd:
+deinit:
 	ath9k_deinit_softc(sc);
-error_init:
 	return error;
 }
 
@@ -923,12 +910,6 @@
 {
 	int i = 0;
 
-	if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
-		kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
-
-	if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
-		kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
-
 	ath9k_deinit_btcoex(sc);
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
@@ -940,8 +921,11 @@
 		sc->dfs_detector->exit(sc->dfs_detector);
 
 	ath9k_eeprom_release(sc);
-	kfree(sc->sc_ah);
-	sc->sc_ah = NULL;
+
+	if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
+		relay_close(sc->rfs_chan_spec_scan);
+		sc->rfs_chan_spec_scan = NULL;
+	}
 }
 
 void ath9k_deinit_device(struct ath_softc *sc)
@@ -957,22 +941,9 @@
 
 	ieee80211_unregister_hw(hw);
 	ath_rx_cleanup(sc);
-	ath_tx_cleanup(sc);
 	ath9k_deinit_softc(sc);
 }
 
-void ath_descdma_cleanup(struct ath_softc *sc,
-			 struct ath_descdma *dd,
-			 struct list_head *head)
-{
-	dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-			  dd->dd_desc_paddr);
-
-	INIT_LIST_HEAD(head);
-	kfree(dd->dd_bufptr);
-	memset(dd, 0, sizeof(*dd));
-}
-
 /************************/
 /*     Module Hooks     */
 /************************/
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index b42be91..811007e 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -605,13 +605,13 @@
 		 * reported, then decryption and MIC errors are irrelevant,
 		 * the frame is going to be dropped either way
 		 */
-		if (ads.ds_rxstatus8 & AR_CRCErr)
-			rs->rs_status |= ATH9K_RXERR_CRC;
-		else if (ads.ds_rxstatus8 & AR_PHYErr) {
+		if (ads.ds_rxstatus8 & AR_PHYErr) {
 			rs->rs_status |= ATH9K_RXERR_PHY;
 			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
 			rs->rs_phyerr = phyerr;
-		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+		} else if (ads.ds_rxstatus8 & AR_CRCErr)
+			rs->rs_status |= ATH9K_RXERR_CRC;
+		else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
 			rs->rs_status |= ATH9K_RXERR_DECRYPT;
 		else if (ads.ds_rxstatus8 & AR_MichaelErr)
 			rs->rs_status |= ATH9K_RXERR_MIC;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 4a745e6..1ff8170 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -226,7 +226,8 @@
 	ATH9K_PHYERR_HT_LENGTH_ILLEGAL    = 35,
 	ATH9K_PHYERR_HT_RATE_ILLEGAL      = 36,
 
-	ATH9K_PHYERR_MAX                  = 37,
+	ATH9K_PHYERR_SPECTRAL		  = 38,
+	ATH9K_PHYERR_MAX                  = 39,
 };
 
 struct ath_desc {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index dd91f8f..6e66f9c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -182,7 +182,7 @@
 	ath_start_ani(sc);
 }
 
-static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
+static bool ath_prepare_reset(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	bool ret = true;
@@ -196,10 +196,10 @@
 	ath9k_debug_samp_bb_mac(sc);
 	ath9k_hw_disable_interrupts(ah);
 
-	if (!ath_stoprecv(sc))
+	if (!ath_drain_all_txq(sc))
 		ret = false;
 
-	if (!ath_drain_all_txq(sc, retry_tx))
+	if (!ath_stoprecv(sc))
 		ret = false;
 
 	return ret;
@@ -247,8 +247,7 @@
 	return true;
 }
 
-static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
-			      bool retry_tx)
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -271,7 +270,7 @@
 		hchan = ah->curchan;
 	}
 
-	if (!ath_prepare_reset(sc, retry_tx))
+	if (!ath_prepare_reset(sc))
 		fastcc = false;
 
 	ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
@@ -312,7 +311,7 @@
 	if (test_bit(SC_OP_INVALID, &sc->sc_flags))
 		return -EIO;
 
-	r = ath_reset_internal(sc, hchan, false);
+	r = ath_reset_internal(sc, hchan);
 
 	return r;
 }
@@ -321,28 +320,25 @@
 			    struct ieee80211_vif *vif)
 {
 	struct ath_node *an;
-	u8 density;
 	an = (struct ath_node *)sta->drv_priv;
 
 	an->sc = sc;
 	an->sta = sta;
 	an->vif = vif;
 
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
-		ath_tx_node_init(sc, an);
+	ath_tx_node_init(sc, an);
+
+	if (sta->ht_cap.ht_supported) {
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 				     sta->ht_cap.ampdu_factor);
-		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
-		an->mpdudensity = density;
+		an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
 	}
 }
 
 static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
 	struct ath_node *an = (struct ath_node *)sta->drv_priv;
-
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-		ath_tx_node_cleanup(sc, an);
+	ath_tx_node_cleanup(sc, an);
 }
 
 void ath9k_tasklet(unsigned long data)
@@ -542,23 +538,21 @@
 #undef SCHED_INTR
 }
 
-static int ath_reset(struct ath_softc *sc, bool retry_tx)
+static int ath_reset(struct ath_softc *sc)
 {
-	int r;
+	int i, r;
 
 	ath9k_ps_wakeup(sc);
 
-	r = ath_reset_internal(sc, NULL, retry_tx);
+	r = ath_reset_internal(sc, NULL);
 
-	if (retry_tx) {
-		int i;
-		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-			if (ATH_TXQ_SETUP(sc, i)) {
-				spin_lock_bh(&sc->tx.txq[i].axq_lock);
-				ath_txq_schedule(sc, &sc->tx.txq[i]);
-				spin_unlock_bh(&sc->tx.txq[i].axq_lock);
-			}
-		}
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+		if (!ATH_TXQ_SETUP(sc, i))
+			continue;
+
+		spin_lock_bh(&sc->tx.txq[i].axq_lock);
+		ath_txq_schedule(sc, &sc->tx.txq[i]);
+		spin_unlock_bh(&sc->tx.txq[i].axq_lock);
 	}
 
 	ath9k_ps_restore(sc);
@@ -579,7 +573,7 @@
 {
 	struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
 
-	ath_reset(sc, true);
+	ath_reset(sc);
 }
 
 /**********************/
@@ -797,7 +791,7 @@
 		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
 	}
 
-	ath_prepare_reset(sc, false);
+	ath_prepare_reset(sc);
 
 	if (sc->rx.frag) {
 		dev_kfree_skb_any(sc->rx.frag);
@@ -1068,6 +1062,75 @@
 	ath_dbg(common, PS, "PowerSave disabled\n");
 }
 
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	u32 rxfilter;
+
+	if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+		ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+		return;
+	}
+
+	ath9k_ps_wakeup(sc);
+	rxfilter = ath9k_hw_getrxfilter(ah);
+	ath9k_hw_setrxfilter(ah, rxfilter |
+				 ATH9K_RX_FILTER_PHYRADAR |
+				 ATH9K_RX_FILTER_PHYERR);
+
+	/* TODO: usually this should not be neccesary, but for some reason
+	 * (or in some mode?) the trigger must be called after the
+	 * configuration, otherwise the register will have its values reset
+	 * (on my ar9220 to value 0x01002310)
+	 */
+	ath9k_spectral_scan_config(hw, sc->spectral_mode);
+	ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
+	ath9k_ps_restore(sc);
+}
+
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+			       enum spectral_mode spectral_mode)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+		ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+		return -1;
+	}
+
+	switch (spectral_mode) {
+	case SPECTRAL_DISABLED:
+		sc->spec_config.enabled = 0;
+		break;
+	case SPECTRAL_BACKGROUND:
+		/* send endless samples.
+		 * TODO: is this really useful for "background"?
+		 */
+		sc->spec_config.endless = 1;
+		sc->spec_config.enabled = 1;
+		break;
+	case SPECTRAL_CHANSCAN:
+	case SPECTRAL_MANUAL:
+		sc->spec_config.endless = 0;
+		sc->spec_config.enabled = 1;
+		break;
+	default:
+		return -1;
+	}
+
+	ath9k_ps_wakeup(sc);
+	ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config);
+	ath9k_ps_restore(sc);
+
+	sc->spectral_mode = spectral_mode;
+
+	return 0;
+}
+
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct ath_softc *sc = hw->priv;
@@ -1181,6 +1244,11 @@
 		 */
 		if (old_pos >= 0)
 			ath_update_survey_nf(sc, old_pos);
+
+		/* perform spectral scan if requested. */
+		if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
+			ath9k_spectral_scan_trigger(hw);
+
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -1603,7 +1671,9 @@
 			ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		ath9k_ps_restore(sc);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		ath9k_ps_wakeup(sc);
 		ath_tx_aggr_stop(sc, sta, tid);
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -1722,11 +1792,11 @@
 	if (drop) {
 		ath9k_ps_wakeup(sc);
 		spin_lock_bh(&sc->sc_pcu_lock);
-		drain_txq = ath_drain_all_txq(sc, false);
+		drain_txq = ath_drain_all_txq(sc);
 		spin_unlock_bh(&sc->sc_pcu_lock);
 
 		if (!drain_txq)
-			ath_reset(sc, false);
+			ath_reset(sc);
 
 		ath9k_ps_restore(sc);
 		ieee80211_wake_queues(hw);
@@ -2234,6 +2304,19 @@
 }
 
 #endif
+static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+
+	sc->scanning = 1;
+}
+
+static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+	struct ath_softc *sc = hw->priv;
+
+	sc->scanning = 0;
+}
 
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
@@ -2280,4 +2363,6 @@
 	.sta_add_debugfs    = ath9k_sta_add_debugfs,
 	.sta_remove_debugfs = ath9k_sta_remove_debugfs,
 #endif
+	.sw_scan_start	    = ath9k_sw_scan_start,
+	.sw_scan_complete   = ath9k_sw_scan_complete,
 };
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 5c02702..815bee2 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -438,7 +438,7 @@
 	struct ath_mci_buf *buf = &mci->sched_buf;
 	int ret;
 
-	buf->bf_addr = dma_alloc_coherent(sc->dev,
+	buf->bf_addr = dmam_alloc_coherent(sc->dev,
 				  ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
 				  &buf->bf_paddr, GFP_KERNEL);
 
@@ -474,13 +474,6 @@
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_hw *ah = sc->sc_ah;
-	struct ath_mci_coex *mci = &sc->mci_coex;
-	struct ath_mci_buf *buf = &mci->sched_buf;
-
-	if (buf->bf_addr)
-		dma_free_coherent(sc->dev,
-				  ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
-				  buf->bf_addr, buf->bf_paddr);
 
 	ar9003_mci_cleanup(ah);
 
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 7ae73fb..0e0d395 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -147,7 +147,6 @@
 
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	void __iomem *mem;
 	struct ath_softc *sc;
 	struct ieee80211_hw *hw;
 	u8 csz;
@@ -155,19 +154,19 @@
 	int ret = 0;
 	char hw_name[64];
 
-	if (pci_enable_device(pdev))
+	if (pcim_enable_device(pdev))
 		return -EIO;
 
 	ret =  pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 	if (ret) {
 		pr_err("32-bit DMA not available\n");
-		goto err_dma;
+		return ret;
 	}
 
 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 	if (ret) {
 		pr_err("32-bit DMA consistent DMA enable failed\n");
-		goto err_dma;
+		return ret;
 	}
 
 	/*
@@ -203,25 +202,16 @@
 	if ((val & 0x0000ff00) != 0)
 		pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
-	ret = pci_request_region(pdev, 0, "ath9k");
+	ret = pcim_iomap_regions(pdev, BIT(0), "ath9k");
 	if (ret) {
 		dev_err(&pdev->dev, "PCI memory region reserve error\n");
-		ret = -ENODEV;
-		goto err_region;
-	}
-
-	mem = pci_iomap(pdev, 0, 0);
-	if (!mem) {
-		pr_err("PCI memory map error\n") ;
-		ret = -EIO;
-		goto err_iomap;
+		return -ENODEV;
 	}
 
 	hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
 	if (!hw) {
 		dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
-		ret = -ENOMEM;
-		goto err_alloc_hw;
+		return -ENOMEM;
 	}
 
 	SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -230,7 +220,7 @@
 	sc = hw->priv;
 	sc->hw = hw;
 	sc->dev = &pdev->dev;
-	sc->mem = mem;
+	sc->mem = pcim_iomap_table(pdev)[0];
 
 	/* Will be cleared in ath9k_start() */
 	set_bit(SC_OP_INVALID, &sc->sc_flags);
@@ -251,7 +241,7 @@
 
 	ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
 	wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
-		   hw_name, (unsigned long)mem, pdev->irq);
+		   hw_name, (unsigned long)sc->mem, pdev->irq);
 
 	return 0;
 
@@ -259,14 +249,6 @@
 	free_irq(sc->irq, sc);
 err_irq:
 	ieee80211_free_hw(hw);
-err_alloc_hw:
-	pci_iounmap(pdev, mem);
-err_iomap:
-	pci_release_region(pdev, 0);
-err_region:
-	/* Nothing */
-err_dma:
-	pci_disable_device(pdev);
 	return ret;
 }
 
@@ -274,17 +256,12 @@
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath_softc *sc = hw->priv;
-	void __iomem *mem = sc->mem;
 
 	if (!is_ath9k_unloaded)
 		sc->sc_ah->ah_flags |= AH_UNPLUGGED;
 	ath9k_deinit_device(sc);
 	free_irq(sc->irq, sc);
 	ieee80211_free_hw(sc->hw);
-
-	pci_iounmap(pdev, mem);
-	pci_disable_device(pdev);
-	pci_release_region(pdev, 0);
 }
 
 #ifdef CONFIG_PM_SLEEP
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 714558d..96ac433 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1204,7 +1204,7 @@
 			caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
 		else if (sta->ht_cap.mcs.rx_mask[1])
 			caps |= WLAN_RC_DS_FLAG;
-		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+		if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
 			caps |= WLAN_RC_40_FLAG;
 			if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
 				caps |= WLAN_RC_SGI_FLAG;
@@ -1452,17 +1452,7 @@
 
 static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
-	struct ath_softc *sc = priv;
-	struct ath_rate_priv *rate_priv;
-
-	rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
-	if (!rate_priv) {
-		ath_err(ath9k_hw_common(sc->sc_ah),
-			"Unable to allocate private rc structure\n");
-		return NULL;
-	}
-
-	return rate_priv;
+	return kzalloc(sizeof(struct ath_rate_priv), gfp);
 }
 
 static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 90752f2..ee156e5 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -15,6 +15,7 @@
  */
 
 #include <linux/dma-mapping.h>
+#include <linux/relay.h>
 #include "ath9k.h"
 #include "ar9003_mac.h"
 
@@ -180,11 +181,6 @@
 			bf->bf_mpdu = NULL;
 		}
 	}
-
-	INIT_LIST_HEAD(&sc->rx.rxbuf);
-
-	kfree(sc->rx.rx_bufptr);
-	sc->rx.rx_bufptr = NULL;
 }
 
 static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
@@ -211,12 +207,11 @@
 			       ah->caps.rx_hp_qdepth);
 
 	size = sizeof(struct ath_buf) * nbufs;
-	bf = kzalloc(size, GFP_KERNEL);
+	bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
 	if (!bf)
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&sc->rx.rxbuf);
-	sc->rx.rx_bufptr = bf;
 
 	for (i = 0; i < nbufs; i++, bf++) {
 		skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
@@ -357,9 +352,6 @@
 				bf->bf_mpdu = NULL;
 			}
 		}
-
-		if (sc->rx.rxdma.dd_desc_len != 0)
-			ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
 	}
 }
 
@@ -541,7 +533,7 @@
 	if (sc->ps_flags & PS_BEACON_SYNC) {
 		sc->ps_flags &= ~PS_BEACON_SYNC;
 		ath_dbg(common, PS,
-			"Reconfigure Beacon timers based on timestamp from the AP\n");
+			"Reconfigure beacon timers based on synchronized timestamp\n");
 		ath9k_set_beacon(sc);
 	}
 
@@ -1024,6 +1016,134 @@
 		rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 
+#ifdef CONFIG_ATH9K_DEBUGFS
+static s8 fix_rssi_inv_only(u8 rssi_val)
+{
+	if (rssi_val == 128)
+		rssi_val = 0;
+	return (s8) rssi_val;
+}
+#endif
+
+/* returns 1 if this was a spectral frame, even if not handled. */
+static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+			   struct ath_rx_status *rs, u64 tsf)
+{
+#ifdef CONFIG_ATH9K_DEBUGFS
+	struct ath_hw *ah = sc->sc_ah;
+	u8 bins[SPECTRAL_HT20_NUM_BINS];
+	u8 *vdata = (u8 *)hdr;
+	struct fft_sample_ht20 fft_sample;
+	struct ath_radar_info *radar_info;
+	struct ath_ht20_mag_info *mag_info;
+	int len = rs->rs_datalen;
+	int dc_pos;
+	u16 length, max_magnitude;
+
+	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
+	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
+	 * yet, but this is supposed to be possible as well.
+	 */
+	if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
+	    rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
+	    rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
+		return 0;
+
+	/* check if spectral scan bit is set. This does not have to be checked
+	 * if received through a SPECTRAL phy error, but shouldn't hurt.
+	 */
+	radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
+	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
+		return 0;
+
+	/* Variation in the data length is possible and will be fixed later.
+	 * Note that we only support HT20 for now.
+	 *
+	 * TODO: add HT20_40 support as well.
+	 */
+	if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
+	    (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
+		return 1;
+
+	fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
+	length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
+	fft_sample.tlv.length = __cpu_to_be16(length);
+
+	fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
+	fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
+	fft_sample.noise = ah->noise;
+
+	switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
+	case 0:
+		/* length correct, nothing to do. */
+		memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
+		break;
+	case -1:
+		/* first byte missing, duplicate it. */
+		memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
+		bins[0] = vdata[0];
+		break;
+	case 2:
+		/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
+		memcpy(bins, vdata, 30);
+		bins[30] = vdata[31];
+		memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
+		break;
+	case 1:
+		/* MAC added 2 extra bytes AND first byte is missing. */
+		bins[0] = vdata[0];
+		memcpy(&bins[0], vdata, 30);
+		bins[31] = vdata[31];
+		memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
+		break;
+	default:
+		return 1;
+	}
+
+	/* DC value (value in the middle) is the blind spot of the spectral
+	 * sample and invalid, interpolate it.
+	 */
+	dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+	bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
+
+	/* mag data is at the end of the frame, in front of radar_info */
+	mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
+
+	/* copy raw bins without scaling them */
+	memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
+	fft_sample.max_exp = mag_info->max_exp & 0xf;
+
+	max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+	fft_sample.max_magnitude = __cpu_to_be16(max_magnitude);
+	fft_sample.max_index = spectral_max_index(mag_info->all_bins);
+	fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
+	fft_sample.tsf = __cpu_to_be64(tsf);
+
+	ath_debug_send_fft_sample(sc, &fft_sample.tlv);
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static void ath9k_apply_ampdu_details(struct ath_softc *sc,
+	struct ath_rx_status *rs, struct ieee80211_rx_status *rxs)
+{
+	if (rs->rs_isaggr) {
+		rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN;
+
+		rxs->ampdu_reference = sc->rx.ampdu_ref;
+
+		if (!rs->rs_moreaggr) {
+			rxs->flag |= RX_FLAG_AMPDU_IS_LAST;
+			sc->rx.ampdu_ref++;
+		}
+
+		if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE)
+			rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR;
+	}
+}
+
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
 	struct ath_buf *bf;
@@ -1108,6 +1228,13 @@
 		    unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
 			rxs->mactime += 0x100000000ULL;
 
+		if (rs.rs_status & ATH9K_RXERR_PHY) {
+			if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {
+				RX_STAT_INC(rx_spectral);
+				goto requeue_drop_frag;
+			}
+		}
+
 		retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
 						 rxs, &decrypt_error);
 		if (retval)
@@ -1223,6 +1350,8 @@
 		if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
 			ath_ant_comb_scan(sc, &rs);
 
+		ath9k_apply_ampdu_details(sc, &rs, rxs);
+
 		ieee80211_rx(hw, skb);
 
 requeue_drop_frag:
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index ad3c82c..5929850 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -789,6 +789,7 @@
 #define AR_SREV_REVISION_9271_11	1
 #define AR_SREV_VERSION_9300		0x1c0
 #define AR_SREV_REVISION_9300_20	2 /* 2.0 and 2.1 */
+#define AR_SREV_REVISION_9300_22	3
 #define AR_SREV_VERSION_9330		0x200
 #define AR_SREV_REVISION_9330_10	0
 #define AR_SREV_REVISION_9330_11	1
@@ -869,6 +870,9 @@
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
 #define AR_SREV_9300_20_OR_LATER(_ah) \
 	((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
+#define AR_SREV_9300_22(_ah) \
+	(AR_SREV_9300(ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22))
 
 #define AR_SREV_9330(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330))
@@ -884,9 +888,6 @@
 
 #define AR_SREV_9485(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
-#define AR_SREV_9485_10(_ah) \
-	(AR_SREV_9485(_ah) && \
-	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10))
 #define AR_SREV_9485_11(_ah) \
 	(AR_SREV_9485(_ah) && \
 	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 90e48a0..89a6441 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -378,7 +378,7 @@
 
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 				 struct ath_buf *bf, struct list_head *bf_q,
-				 struct ath_tx_status *ts, int txok, bool retry)
+				 struct ath_tx_status *ts, int txok)
 {
 	struct ath_node *an = NULL;
 	struct sk_buff *skb;
@@ -490,7 +490,7 @@
 		} else if (!isaggr && txok) {
 			/* transmit completion */
 			acked_cnt++;
-		} else if ((tid->state & AGGR_CLEANUP) || !retry) {
+		} else if (tid->state & AGGR_CLEANUP) {
 			/*
 			 * cleanup in progress, just fail
 			 * the un-acked sub-frames
@@ -604,6 +604,37 @@
 		ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
 }
 
+static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
+{
+    struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
+    return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+}
+
+static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+				  struct ath_tx_status *ts, struct ath_buf *bf,
+				  struct list_head *bf_head)
+{
+	bool txok, flush;
+
+	txok = !(ts->ts_status & ATH9K_TXERR_MASK);
+	flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
+	txq->axq_tx_inprogress = false;
+
+	txq->axq_depth--;
+	if (bf_is_ampdu_not_probing(bf))
+		txq->axq_ampdu_depth--;
+
+	if (!bf_isampdu(bf)) {
+		if (!flush)
+			ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+		ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
+	} else
+		ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
+
+	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush)
+		ath_txq_schedule(sc, txq);
+}
+
 static bool ath_lookup_legacy(struct ath_buf *bf)
 {
 	struct sk_buff *skb;
@@ -1202,7 +1233,7 @@
 	 * in HT IBSS when a beacon with HT-info is received after the station
 	 * has already been added.
 	 */
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+	if (sta->ht_cap.ht_supported) {
 		an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
 				     sta->ht_cap.ampdu_factor);
 		density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
@@ -1331,23 +1362,6 @@
 /* Queue Management */
 /********************/
 
-static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
-					  struct ath_txq *txq)
-{
-	struct ath_atx_ac *ac, *ac_tmp;
-	struct ath_atx_tid *tid, *tid_tmp;
-
-	list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
-		list_del(&ac->list);
-		ac->sched = false;
-		list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
-			list_del(&tid->list);
-			tid->sched = false;
-			ath_tid_drain(sc, txq, tid);
-		}
-	}
-}
-
 struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
 {
 	struct ath_hw *ah = sc->sc_ah;
@@ -1470,14 +1484,8 @@
 	return 0;
 }
 
-static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
-{
-    struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
-    return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
-}
-
 static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
-			       struct list_head *list, bool retry_tx)
+			       struct list_head *list)
 {
 	struct ath_buf *bf, *lastbf;
 	struct list_head bf_head;
@@ -1499,16 +1507,7 @@
 
 		lastbf = bf->bf_lastbf;
 		list_cut_position(&bf_head, list, &lastbf->list);
-
-		txq->axq_depth--;
-		if (bf_is_ampdu_not_probing(bf))
-			txq->axq_ampdu_depth--;
-
-		if (bf_isampdu(bf))
-			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
-					     retry_tx);
-		else
-			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
+		ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
 	}
 }
 
@@ -1518,7 +1517,7 @@
  * This assumes output has been stopped and
  * we do not need to block ath_tx_tasklet.
  */
-void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
 {
 	ath_txq_lock(sc, txq);
 
@@ -1526,8 +1525,7 @@
 		int idx = txq->txq_tailidx;
 
 		while (!list_empty(&txq->txq_fifo[idx])) {
-			ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
-					   retry_tx);
+			ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]);
 
 			INCR(idx, ATH_TXFIFO_DEPTH);
 		}
@@ -1536,16 +1534,12 @@
 
 	txq->axq_link = NULL;
 	txq->axq_tx_inprogress = false;
-	ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
-
-	/* flush any pending frames if aggregation is enabled */
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx)
-		ath_txq_drain_pending_buffers(sc, txq);
+	ath_drain_txq_list(sc, txq, &txq->axq_q);
 
 	ath_txq_unlock_complete(sc, txq);
 }
 
-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
+bool ath_drain_all_txq(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1581,7 +1575,7 @@
 		 */
 		txq = &sc->tx.txq[i];
 		txq->stopped = false;
-		ath_draintxq(sc, txq, retry_tx);
+		ath_draintxq(sc, txq);
 	}
 
 	return !npend;
@@ -1910,8 +1904,7 @@
 	struct ath_buf *bf;
 	u8 tidno;
 
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an &&
-		ieee80211_is_data_qos(hdr->frame_control)) {
+	if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
 		tidno = ieee80211_get_qos_ctl(hdr)[0] &
 			IEEE80211_QOS_CTL_TID_MASK;
 		tid = ATH_AN_2_TID(txctl->an, tidno);
@@ -2175,28 +2168,6 @@
 	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
 }
 
-static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
-				  struct ath_tx_status *ts, struct ath_buf *bf,
-				  struct list_head *bf_head)
-{
-	int txok;
-
-	txq->axq_depth--;
-	txok = !(ts->ts_status & ATH9K_TXERR_MASK);
-	txq->axq_tx_inprogress = false;
-	if (bf_is_ampdu_not_probing(bf))
-		txq->axq_ampdu_depth--;
-
-	if (!bf_isampdu(bf)) {
-		ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
-		ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
-	} else
-		ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
-
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-		ath_txq_schedule(sc, txq);
-}
-
 static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
 	struct ath_hw *ah = sc->sc_ah;
@@ -2361,8 +2332,8 @@
 	u8 txs_len = sc->sc_ah->caps.txs_len;
 
 	dd->dd_desc_len = size * txs_len;
-	dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
-					 &dd->dd_desc_paddr, GFP_KERNEL);
+	dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
+					  &dd->dd_desc_paddr, GFP_KERNEL);
 	if (!dd->dd_desc)
 		return -ENOMEM;
 
@@ -2382,14 +2353,6 @@
 	return err;
 }
 
-static void ath_tx_edma_cleanup(struct ath_softc *sc)
-{
-	struct ath_descdma *dd = &sc->txsdma;
-
-	dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-			  dd->dd_desc_paddr);
-}
-
 int ath_tx_init(struct ath_softc *sc, int nbufs)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -2402,7 +2365,7 @@
 	if (error != 0) {
 		ath_err(common,
 			"Failed to allocate tx descriptors: %d\n", error);
-		goto err;
+		return error;
 	}
 
 	error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
@@ -2410,36 +2373,17 @@
 	if (error != 0) {
 		ath_err(common,
 			"Failed to allocate beacon descriptors: %d\n", error);
-		goto err;
+		return error;
 	}
 
 	INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
 
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 		error = ath_tx_edma_init(sc);
-		if (error)
-			goto err;
-	}
-
-err:
-	if (error != 0)
-		ath_tx_cleanup(sc);
 
 	return error;
 }
 
-void ath_tx_cleanup(struct ath_softc *sc)
-{
-	if (sc->beacon.bdma.dd_desc_len != 0)
-		ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
-
-	if (sc->tx.txdma.dd_desc_len != 0)
-		ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
-
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-		ath_tx_edma_cleanup(sc);
-}
-
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
 	struct ath_atx_tid *tid;
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 2df17f1..2559974 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -85,20 +85,14 @@
 	CARL9170_STARTED,
 };
 
-#define CARL9170_NUM_TID		16
 #define WME_BA_BMP_SIZE			64
 #define CARL9170_TX_USER_RATE_TRIES	3
 
-#define WME_AC_BE   2
-#define WME_AC_BK   3
-#define WME_AC_VI   1
-#define WME_AC_VO   0
-
 #define TID_TO_WME_AC(_tid)				\
-	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
-	 (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK :	\
-	 (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI :	\
-	 WME_AC_VO)
+	((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE :	\
+	 (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK :	\
+	 (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI :	\
+	 IEEE80211_AC_VO)
 
 #define SEQ_DIFF(_start, _seq) \
 	(((_start) - (_seq)) & 0x0fff)
@@ -290,6 +284,7 @@
 		unsigned int rx_size;
 		unsigned int tx_seq_table;
 		bool ba_filter;
+		bool disable_offload_fw;
 	} fw;
 
 	/* interface configuration combinations */
@@ -493,8 +488,8 @@
 	bool sleeping;
 	atomic_t pending_frames;
 	unsigned int ampdu_max_len;
-	struct carl9170_sta_tid __rcu *agg[CARL9170_NUM_TID];
-	struct carl9170_ba_stats stats[CARL9170_NUM_TID];
+	struct carl9170_sta_tid __rcu *agg[IEEE80211_NUM_TIDS];
+	struct carl9170_ba_stats stats[IEEE80211_NUM_TIDS];
 };
 
 struct carl9170_tx_info {
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 63fd9af..47d5c2e 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -215,6 +215,24 @@
 	return 0;
 }
 
+static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
+					    u16 if_comb_types)
+{
+	if (ar->fw.vif_num < 2)
+		return;
+
+	ar->if_comb_limits[0].max = ar->fw.vif_num;
+	ar->if_comb_limits[0].types = if_comb_types;
+
+	ar->if_combs[0].num_different_channels = 1;
+	ar->if_combs[0].max_interfaces = ar->fw.vif_num;
+	ar->if_combs[0].limits = ar->if_comb_limits;
+	ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+
+	ar->hw->wiphy->iface_combinations = ar->if_combs;
+	ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+}
+
 static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
 {
 	const struct carl9170fw_otus_desc *otus_desc;
@@ -264,7 +282,7 @@
 	if (!SUPP(CARL9170FW_COMMAND_CAM)) {
 		dev_info(&ar->udev->dev, "crypto offloading is disabled "
 			 "by firmware.\n");
-		ar->disable_offload = true;
+		ar->fw.disable_offload_fw = true;
 	}
 
 	if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
@@ -345,20 +363,15 @@
 		}
 	}
 
-	ar->if_comb_limits[0].max = ar->fw.vif_num;
-	ar->if_comb_limits[0].types = if_comb_types;
-
-	ar->if_combs[0].num_different_channels = 1;
-	ar->if_combs[0].max_interfaces = ar->fw.vif_num;
-	ar->if_combs[0].limits = ar->if_comb_limits;
-	ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
-
-	ar->hw->wiphy->iface_combinations = ar->if_combs;
-	ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+	carl9170_fw_set_if_combinations(ar, if_comb_types);
 
 	ar->hw->wiphy->interface_modes |= if_comb_types;
 
-	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+	ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+	/* As IBSS Encryption is software-based, IBSS RSN is supported. */
+	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+		 WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS;
 
 #undef SUPPORTED
 	return carl9170_fw_tx_sequence(ar);
diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h
index 9443c80..9111d4f 100644
--- a/drivers/net/wireless/ath/carl9170/fwcmd.h
+++ b/drivers/net/wireless/ath/carl9170/fwcmd.h
@@ -156,6 +156,14 @@
 } __packed;
 #define CARL9170_PSM_SIZE		4
 
+/*
+ * Note: If a bit in rx_filter is set, then it
+ * means that the particular frames which matches
+ * the condition are FILTERED/REMOVED/DISCARDED!
+ * (This is can be a bit confusing, especially
+ * because someone people think it's the exact
+ * opposite way, so watch out!)
+ */
 struct carl9170_rx_filter_cmd {
 	__le32		rx_filter;
 } __packed;
diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h
index fa834c14..0db874a 100644
--- a/drivers/net/wireless/ath/carl9170/hw.h
+++ b/drivers/net/wireless/ath/carl9170/hw.h
@@ -384,7 +384,7 @@
 
 #define	AR9170_MAC_REG_BCN_ADDR			(AR9170_MAC_REG_BASE + 0xd84)
 #define	AR9170_MAC_REG_BCN_LENGTH		(AR9170_MAC_REG_BASE + 0xd88)
-#define		AR9170_MAC_BCN_LENGTH_MAX		256
+#define		AR9170_MAC_BCN_LENGTH_MAX		(512 - 32)
 
 #define AR9170_MAC_REG_BCN_STATUS		(AR9170_MAC_REG_BASE + 0xd8c)
 
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 25a1e2f..f293b3f 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -358,8 +358,13 @@
 	ar->ps.last_action = jiffies;
 	ar->ps.last_slept = jiffies;
 	ar->erp_mode = CARL9170_ERP_AUTO;
-	ar->rx_software_decryption = false;
-	ar->disable_offload = false;
+
+	/* Set "disable hw crypto offload" whenever the module parameter
+	 * nohwcrypt is true or if the firmware does not support it.
+	 */
+	ar->disable_offload = modparam_nohwcrypt |
+		ar->fw.disable_offload_fw;
+	ar->rx_software_decryption = ar->disable_offload;
 
 	for (i = 0; i < ar->hw->queues; i++) {
 		ar->queue_stop_timeout[i] = jiffies;
@@ -565,12 +570,28 @@
 
 	memcpy(common->macaddr, vif->addr, ETH_ALEN);
 
-	if (modparam_nohwcrypt ||
-	    ((vif->type != NL80211_IFTYPE_STATION) &&
-	     (vif->type != NL80211_IFTYPE_AP))) {
-		ar->rx_software_decryption = true;
-		ar->disable_offload = true;
-	}
+	/* We have to fall back to software crypto, whenever
+	 * the user choose to participates in an IBSS. HW
+	 * offload for IBSS RSN is not supported by this driver.
+	 *
+	 * NOTE: If the previous main interface has already
+	 * disabled hw crypto offload, we have to keep this
+	 * previous disable_offload setting as it was.
+	 * Altough ideally, we should notify mac80211 and tell
+	 * it to forget about any HW crypto offload for now.
+	 */
+	ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
+	    (vif->type != NL80211_IFTYPE_AP));
+
+	/* While the driver supports HW offload in a single
+	 * P2P client configuration, it doesn't support HW
+	 * offload in the favourit, concurrent P2P GO+CLIENT
+	 * configuration. Hence, HW offload will always be
+	 * disabled for P2P.
+	 */
+	ar->disable_offload |= vif->p2p;
+
+	ar->rx_software_decryption = ar->disable_offload;
 
 	err = carl9170_set_operating_mode(ar);
 	return err;
@@ -580,7 +601,7 @@
 				     struct ieee80211_vif *vif)
 {
 	struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
-	struct ieee80211_vif *main_vif;
+	struct ieee80211_vif *main_vif, *old_main = NULL;
 	struct ar9170 *ar = hw->priv;
 	int vif_id = -1, err = 0;
 
@@ -602,6 +623,15 @@
 		goto init;
 	}
 
+	/* Because the AR9170 HW's MAC doesn't provide full support for
+	 * multiple, independent interfaces [of different operation modes].
+	 * We have to select ONE main interface [main mode of HW], but we
+	 * can have multiple slaves [AKA: entry in the ACK-table].
+	 *
+	 * The first (from HEAD/TOP) interface in the ar->vif_list is
+	 * always the main intf. All following intfs in this list
+	 * are considered to be slave intfs.
+	 */
 	main_vif = carl9170_get_main_vif(ar);
 
 	if (main_vif) {
@@ -610,6 +640,18 @@
 			if (vif->type == NL80211_IFTYPE_STATION)
 				break;
 
+			/* P2P GO [master] use-case
+			 * Because the P2P GO station is selected dynamically
+			 * by all participating peers of a WIFI Direct network,
+			 * the driver has be able to change the main interface
+			 * operating mode on the fly.
+			 */
+			if (main_vif->p2p && vif->p2p &&
+			    vif->type == NL80211_IFTYPE_AP) {
+				old_main = main_vif;
+				break;
+			}
+
 			err = -EBUSY;
 			rcu_read_unlock();
 
@@ -648,14 +690,41 @@
 	vif_priv->id = vif_id;
 	vif_priv->enable_beacon = false;
 	ar->vifs++;
-	list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+	if (old_main) {
+		/* We end up in here, if the main interface is being replaced.
+		 * Put the new main interface at the HEAD of the list and the
+		 * previous inteface will automatically become second in line.
+		 */
+		list_add_rcu(&vif_priv->list, &ar->vif_list);
+	} else {
+		/* Add new inteface. If the list is empty, it will become the
+		 * main inteface, otherwise it will be slave.
+		 */
+		list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+	}
 	rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif);
 
 init:
-	if (carl9170_get_main_vif(ar) == vif) {
+	main_vif = carl9170_get_main_vif(ar);
+
+	if (main_vif == vif) {
 		rcu_assign_pointer(ar->beacon_iter, vif_priv);
 		rcu_read_unlock();
 
+		if (old_main) {
+			struct carl9170_vif_info *old_main_priv =
+				(void *) old_main->drv_priv;
+			/* downgrade old main intf to slave intf.
+			 * NOTE: We are no longer under rcu_read_lock.
+			 * But we are still holding ar->mutex, so the
+			 * vif data [id, addr] is safe.
+			 */
+			err = carl9170_mod_virtual_mac(ar, old_main_priv->id,
+						       old_main->addr);
+			if (err)
+				goto unlock;
+		}
+
 		err = carl9170_init_interface(ar, vif);
 		if (err)
 			goto unlock;
@@ -1112,9 +1181,7 @@
 	if (ar->disable_offload || !vif)
 		return -EOPNOTSUPP;
 
-	/*
-	 * We have to fall back to software encryption, whenever
-	 * the user choose to participates in an IBSS or is connected
+	/* Fall back to software encryption whenever the driver is connected
 	 * to more than one network.
 	 *
 	 * This is very unfortunate, because some machines cannot handle
@@ -1263,7 +1330,7 @@
 			return 0;
 		}
 
-		for (i = 0; i < CARL9170_NUM_TID; i++)
+		for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++)
 			RCU_INIT_POINTER(sta_info->agg[i], NULL);
 
 		sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
@@ -1287,7 +1354,7 @@
 		sta_info->ht_sta = false;
 
 		rcu_read_lock();
-		for (i = 0; i < CARL9170_NUM_TID; i++) {
+		for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) {
 			struct carl9170_sta_tid *tid_info;
 
 			tid_info = rcu_dereference(sta_info->agg[i]);
@@ -1394,7 +1461,9 @@
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		rcu_read_lock();
 		tid_info = rcu_dereference(sta_info->agg[tid]);
 		if (tid_info) {
@@ -1784,7 +1853,7 @@
 		     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		     IEEE80211_HW_SUPPORTS_PS |
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
-		     IEEE80211_HW_NEED_DTIM_PERIOD |
+		     IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
 		     IEEE80211_HW_SIGNAL_DBM;
 
 	if (!modparam_noht) {
@@ -1805,10 +1874,6 @@
 	for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
 		ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
 
-	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-	/* As IBSS Encryption is software-based, IBSS RSN is supported. */
-	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 	return ar;
 
 err_nomem:
@@ -1916,13 +1981,13 @@
 	return 0;
 }
 
-static int carl9170_reg_notifier(struct wiphy *wiphy,
-				 struct regulatory_request *request)
+static void carl9170_reg_notifier(struct wiphy *wiphy,
+				  struct regulatory_request *request)
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct ar9170 *ar = hw->priv;
 
-	return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
+	ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
 }
 
 int carl9170_register(struct ar9170 *ar)
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index ef4ec0d..9c0b150 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1520,36 +1520,93 @@
 		carl9170_tx(ar);
 }
 
+/* caller has to take rcu_read_lock */
+static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
+{
+	struct carl9170_vif_info *cvif;
+	int i = 1;
+
+	/* The AR9170 hardware has no fancy beacon queue or some
+	 * other scheduling mechanism. So, the driver has to make
+	 * due by setting the two beacon timers (pretbtt and tbtt)
+	 * once and then swapping the beacon address in the HW's
+	 * register file each time the pretbtt fires.
+	 */
+
+	cvif = rcu_dereference(ar->beacon_iter);
+	if (ar->vifs > 0 && cvif) {
+		do {
+			list_for_each_entry_continue_rcu(cvif, &ar->vif_list,
+							 list) {
+				if (cvif->active && cvif->enable_beacon)
+					goto out;
+			}
+		} while (ar->beacon_enabled && i--);
+	}
+
+out:
+	rcu_assign_pointer(ar->beacon_iter, cvif);
+	return cvif;
+}
+
+static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb,
+				      u32 *ht1, u32 *plcp)
+{
+	struct ieee80211_tx_info *txinfo;
+	struct ieee80211_tx_rate *rate;
+	unsigned int power, chains;
+	bool ht_rate;
+
+	txinfo = IEEE80211_SKB_CB(skb);
+	rate = &txinfo->control.rates[0];
+	ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS);
+	carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains);
+
+	*ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
+	if (chains == AR9170_TX_PHY_TXCHAIN_2)
+		*ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
+	SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7);
+	SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power);
+	SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains);
+
+	if (ht_rate) {
+		*ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
+		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+			*plcp |= AR9170_MAC_BCN_HT2_SGI;
+
+		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+			*ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
+			*plcp |= AR9170_MAC_BCN_HT2_BW40;
+		} else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
+			*ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
+			*plcp |= AR9170_MAC_BCN_HT2_BW40;
+		}
+
+		SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN);
+	} else {
+		if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M)
+			*plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
+		else
+			*plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
+	}
+
+	return ht_rate;
+}
+
 int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
 {
 	struct sk_buff *skb = NULL;
 	struct carl9170_vif_info *cvif;
-	struct ieee80211_tx_info *txinfo;
-	struct ieee80211_tx_rate *rate;
 	__le32 *data, *old = NULL;
-	unsigned int plcp, power, chains;
-	u32 word, ht1, off, addr, len;
+	u32 word, ht1, plcp, off, addr, len;
 	int i = 0, err = 0;
+	bool ht_rate;
 
 	rcu_read_lock();
-	cvif = rcu_dereference(ar->beacon_iter);
-retry:
-	if (ar->vifs == 0 || !cvif)
+	cvif = carl9170_pick_beaconing_vif(ar);
+	if (!cvif)
 		goto out_unlock;
 
-	list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
-		if (cvif->active && cvif->enable_beacon)
-			goto found;
-	}
-
-	if (!ar->beacon_enabled || i++)
-		goto out_unlock;
-
-	goto retry;
-
-found:
-	rcu_assign_pointer(ar->beacon_iter, cvif);
-
 	skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
 		NULL, NULL);
 
@@ -1558,7 +1615,6 @@
 		goto err_free;
 	}
 
-	txinfo = IEEE80211_SKB_CB(skb);
 	spin_lock_bh(&ar->beacon_lock);
 	data = (__le32 *)skb->data;
 	if (cvif->beacon)
@@ -1588,43 +1644,14 @@
 		goto err_unlock;
 	}
 
-	ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
-	rate = &txinfo->control.rates[0];
-	carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains);
-	if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
-		if (plcp <= AR9170_TX_PHY_RATE_CCK_11M)
-			plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
-		else
-			plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
-	} else {
-		ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
-		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-			plcp |= AR9170_MAC_BCN_HT2_SGI;
-
-		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
-			ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
-			plcp |= AR9170_MAC_BCN_HT2_BW40;
-		}
-		if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
-			ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
-			plcp |= AR9170_MAC_BCN_HT2_BW40;
-		}
-
-		SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN);
-	}
-
-	SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7);
-	SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power);
-	SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains);
-	if (chains == AR9170_TX_PHY_TXCHAIN_2)
-		ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
+	ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp);
 
 	carl9170_async_regwrite_begin(ar);
 	carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1);
-	if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS))
-		carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
-	else
+	if (ht_rate)
 		carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp);
+	else
+		carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
 
 	for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
 		/*
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h
index 2ec3e91..2282847 100644
--- a/drivers/net/wireless/ath/carl9170/version.h
+++ b/drivers/net/wireless/ath/carl9170/version.h
@@ -1,7 +1,7 @@
 #ifndef __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
 #define CARL9170FW_VERSION_YEAR 12
-#define CARL9170FW_VERSION_MONTH 7
-#define CARL9170FW_VERSION_DAY 7
-#define CARL9170FW_VERSION_GIT "1.9.6"
+#define CARL9170FW_VERSION_MONTH 12
+#define CARL9170FW_VERSION_DAY 15
+#define CARL9170FW_VERSION_GIT "1.9.7"
 #endif /* __CARL9170_SHARED_VERSION_H */
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index d816980..ccc4c71 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -195,8 +195,6 @@
 	const struct ieee80211_reg_rule *reg_rule;
 	struct ieee80211_channel *ch;
 	unsigned int i;
-	u32 bandwidth = 0;
-	int r;
 
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
@@ -214,11 +212,8 @@
 				continue;
 
 			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-				r = freq_reg_info(wiphy,
-						  ch->center_freq,
-						  bandwidth,
-						  &reg_rule);
-				if (r)
+				reg_rule = freq_reg_info(wiphy, ch->center_freq);
+				if (IS_ERR(reg_rule))
 					continue;
 				/*
 				 * If 11d had a rule for this channel ensure
@@ -254,8 +249,6 @@
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *ch;
 	const struct ieee80211_reg_rule *reg_rule;
-	u32 bandwidth = 0;
-	int r;
 
 	sband = wiphy->bands[IEEE80211_BAND_2GHZ];
 	if (!sband)
@@ -283,16 +276,16 @@
 	 */
 
 	ch = &sband->channels[11]; /* CH 12 */
-	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-	if (!r) {
+	reg_rule = freq_reg_info(wiphy, ch->center_freq);
+	if (!IS_ERR(reg_rule)) {
 		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
 			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
 				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
 	}
 
 	ch = &sband->channels[12]; /* CH 13 */
-	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-	if (!r) {
+	reg_rule = freq_reg_info(wiphy, ch->center_freq);
+	if (!IS_ERR(reg_rule)) {
 		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
 			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
 				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -363,9 +356,9 @@
 	return -1;
 }
 
-int ath_reg_notifier_apply(struct wiphy *wiphy,
-			   struct regulatory_request *request,
-			   struct ath_regulatory *reg)
+void ath_reg_notifier_apply(struct wiphy *wiphy,
+			    struct regulatory_request *request,
+			    struct ath_regulatory *reg)
 {
 	struct ath_common *common = container_of(reg, struct ath_common,
 						 regulatory);
@@ -380,7 +373,7 @@
 	 * any pending requests in the queue.
 	 */
 	if (!request)
-		return 0;
+		return;
 
 	switch (request->initiator) {
 	case NL80211_REGDOM_SET_BY_CORE:
@@ -416,8 +409,6 @@
 
 		break;
 	}
-
-	return 0;
 }
 EXPORT_SYMBOL(ath_reg_notifier_apply);
 
@@ -507,8 +498,8 @@
 static int
 ath_regd_init_wiphy(struct ath_regulatory *reg,
 		    struct wiphy *wiphy,
-		    int (*reg_notifier)(struct wiphy *wiphy,
-					struct regulatory_request *request))
+		    void (*reg_notifier)(struct wiphy *wiphy,
+					 struct regulatory_request *request))
 {
 	const struct ieee80211_regdomain *regd;
 
@@ -628,8 +619,8 @@
 int
 ath_regd_init(struct ath_regulatory *reg,
 	      struct wiphy *wiphy,
-	      int (*reg_notifier)(struct wiphy *wiphy,
-				  struct regulatory_request *request))
+	      void (*reg_notifier)(struct wiphy *wiphy,
+				   struct regulatory_request *request))
 {
 	struct ath_common *common = container_of(reg, struct ath_common,
 						 regulatory);
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 03a8268..37f53bd 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -252,12 +252,12 @@
 bool ath_is_world_regd(struct ath_regulatory *reg);
 bool ath_is_49ghz_allowed(u16 redomain);
 int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
-		  int (*reg_notifier)(struct wiphy *wiphy,
-		  struct regulatory_request *request));
+		  void (*reg_notifier)(struct wiphy *wiphy,
+				       struct regulatory_request *request));
 u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
 			  enum ieee80211_band band);
-int ath_reg_notifier_apply(struct wiphy *wiphy,
-			   struct regulatory_request *request,
-			   struct ath_regulatory *reg);
+void ath_reg_notifier_apply(struct wiphy *wiphy,
+			    struct regulatory_request *request,
+			    struct ath_regulatory *reg);
 
 #endif
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 116f4e8..9ecc196 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -204,7 +204,6 @@
 		break;
 	default:
 		return -EOPNOTSUPP;
-
 	}
 
 	/* FW don't support scan after connection attempt */
@@ -228,8 +227,8 @@
 		}
 		/* 0-based channel indexes */
 		cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
-		wil_dbg(wil, "Scan for ch %d  : %d MHz\n", ch,
-			request->channels[i]->center_freq);
+		wil_dbg_misc(wil, "Scan for ch %d  : %d MHz\n", ch,
+			     request->channels[i]->center_freq);
 	}
 
 	return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
@@ -342,7 +341,7 @@
 	}
 
  out:
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(wiphy, bss);
 
 	return rc;
 }
@@ -425,8 +424,8 @@
 		return -EINVAL;
 	}
 
-	wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
-		channel->center_freq, info->privacy ? "secure" : "open");
+	wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
+		     channel->center_freq, info->privacy ? "secure" : "open");
 	print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
 			     info->ssid, info->ssid_len);
 
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 38049da..dc97e7b 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -38,7 +38,9 @@
 #define WIL6210_IMC_RX		BIT_DMA_EP_RX_ICR_RX_DONE
 #define WIL6210_IMC_TX		(BIT_DMA_EP_TX_ICR_TX_DONE | \
 				BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
-#define WIL6210_IMC_MISC	(ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT)
+#define WIL6210_IMC_MISC	(ISR_MISC_FW_READY | \
+				 ISR_MISC_MBOX_EVT | \
+				 ISR_MISC_FW_ERROR)
 
 #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
 					BIT_DMA_PSEUDO_CAUSE_TX | \
@@ -50,7 +52,6 @@
 
 static inline void wil_icr_clear(u32 x, void __iomem *addr)
 {
-
 }
 #else /* defined(CONFIG_WIL6210_ISR_COR) */
 /* configure to Write-1-to-Clear mode */
@@ -94,7 +95,7 @@
 
 static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
 {
-	wil_dbg_IRQ(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "%s()\n", __func__);
 
 	iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
 		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
@@ -125,7 +126,7 @@
 
 static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
 {
-	wil_dbg_IRQ(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "%s()\n", __func__);
 
 	set_bit(wil_status_irqen, &wil->status);
 
@@ -135,7 +136,7 @@
 
 void wil6210_disable_irq(struct wil6210_priv *wil)
 {
-	wil_dbg_IRQ(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "%s()\n", __func__);
 
 	wil6210_mask_irq_tx(wil);
 	wil6210_mask_irq_rx(wil);
@@ -145,7 +146,7 @@
 
 void wil6210_enable_irq(struct wil6210_priv *wil)
 {
-	wil_dbg_IRQ(wil, "%s()\n", __func__);
+	wil_dbg_irq(wil, "%s()\n", __func__);
 
 	iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
 		  offsetof(struct RGF_ICR, ICC));
@@ -167,7 +168,7 @@
 					 HOSTADDR(RGF_DMA_EP_RX_ICR) +
 					 offsetof(struct RGF_ICR, ICR));
 
-	wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr);
+	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
 
 	if (!isr) {
 		wil_err(wil, "spurious IRQ: RX\n");
@@ -177,7 +178,7 @@
 	wil6210_mask_irq_rx(wil);
 
 	if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
-		wil_dbg_IRQ(wil, "RX done\n");
+		wil_dbg_irq(wil, "RX done\n");
 		isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
 		wil_rx_handle(wil);
 	}
@@ -197,7 +198,7 @@
 					 HOSTADDR(RGF_DMA_EP_TX_ICR) +
 					 offsetof(struct RGF_ICR, ICR));
 
-	wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr);
+	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
 
 	if (!isr) {
 		wil_err(wil, "spurious IRQ: TX\n");
@@ -208,13 +209,13 @@
 
 	if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
 		uint i;
-		wil_dbg_IRQ(wil, "TX done\n");
+		wil_dbg_irq(wil, "TX done\n");
 		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
 		for (i = 0; i < 24; i++) {
 			u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i);
 			if (isr & mask) {
 				isr &= ~mask;
-				wil_dbg_IRQ(wil, "TX done(%i)\n", i);
+				wil_dbg_irq(wil, "TX done(%i)\n", i);
 				wil_tx_complete(wil, i);
 			}
 		}
@@ -228,6 +229,17 @@
 	return IRQ_HANDLED;
 }
 
+static void wil_notify_fw_error(struct wil6210_priv *wil)
+{
+	struct device *dev = &wil_to_ndev(wil)->dev;
+	char *envp[3] = {
+		[0] = "SOURCE=wil6210",
+		[1] = "EVENT=FW_ERROR",
+		[2] = NULL,
+	};
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+}
+
 static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
 {
 	struct wil6210_priv *wil = cookie;
@@ -235,7 +247,7 @@
 					 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
 					 offsetof(struct RGF_ICR, ICR));
 
-	wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr);
+	wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
 
 	if (!isr) {
 		wil_err(wil, "spurious IRQ: MISC\n");
@@ -244,8 +256,15 @@
 
 	wil6210_mask_irq_misc(wil);
 
+	if (isr & ISR_MISC_FW_ERROR) {
+		wil_dbg_irq(wil, "IRQ: Firmware error\n");
+		clear_bit(wil_status_fwready, &wil->status);
+		wil_notify_fw_error(wil);
+		isr &= ~ISR_MISC_FW_ERROR;
+	}
+
 	if (isr & ISR_MISC_FW_READY) {
-		wil_dbg_IRQ(wil, "IRQ: FW ready\n");
+		wil_dbg_irq(wil, "IRQ: FW ready\n");
 		/**
 		 * Actual FW ready indicated by the
 		 * WMI_FW_READY_EVENTID
@@ -268,10 +287,10 @@
 	struct wil6210_priv *wil = cookie;
 	u32 isr = wil->isr_misc;
 
-	wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr);
+	wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
 
 	if (isr & ISR_MISC_MBOX_EVT) {
-		wil_dbg_IRQ(wil, "MBOX event\n");
+		wil_dbg_irq(wil, "MBOX event\n");
 		wmi_recv_cmd(wil);
 		isr &= ~ISR_MISC_MBOX_EVT;
 	}
@@ -293,7 +312,7 @@
 {
 	struct wil6210_priv *wil = cookie;
 
-	wil_dbg_IRQ(wil, "Thread IRQ\n");
+	wil_dbg_irq(wil, "Thread IRQ\n");
 	/* Discover real IRQ cause */
 	if (wil->isr_misc)
 		wil6210_irq_misc_thread(irq, cookie);
@@ -370,6 +389,8 @@
 	if (wil6210_debug_irq_mask(wil, pseudo_cause))
 		return IRQ_NONE;
 
+	wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
+
 	wil6210_mask_irq_pseudo(wil);
 
 	/* Discover real IRQ cause
@@ -401,8 +422,6 @@
 	if (rc != IRQ_WAKE_THREAD)
 		wil6210_unmask_irq_pseudo(wil);
 
-	wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause);
-
 	return rc;
 }
 
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 95fcd36..761c389 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -64,7 +64,7 @@
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *wdev = wil->wdev;
 
-	wil_dbg(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	wil_link_off(wil);
 	clear_bit(wil_status_fwconnected, &wil->status);
@@ -80,11 +80,13 @@
 					GFP_KERNEL);
 		break;
 	default:
-		;
+		break;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
 		wil_vring_fini_tx(wil, i);
+
+	clear_bit(wil_status_dontscan, &wil->status);
 }
 
 static void wil_disconnect_worker(struct work_struct *work)
@@ -99,7 +101,7 @@
 {
 	struct wil6210_priv *wil = (void *)x;
 
-	wil_dbg(wil, "Connect timeout\n");
+	wil_dbg_misc(wil, "Connect timeout\n");
 
 	/* reschedule to thread context - disconnect won't
 	 * run from atomic context
@@ -107,9 +109,18 @@
 	schedule_work(&wil->disconnect_worker);
 }
 
+static void wil_cache_mbox_regs(struct wil6210_priv *wil)
+{
+	/* make shadow copy of registers that should not change on run time */
+	wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
+			     sizeof(struct wil6210_mbox_ctl));
+	wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
+	wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+}
+
 int wil_priv_init(struct wil6210_priv *wil)
 {
-	wil_dbg(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	mutex_init(&wil->mutex);
 	mutex_init(&wil->wmi_mutex);
@@ -136,11 +147,7 @@
 		return -EAGAIN;
 	}
 
-	/* make shadow copy of registers that should not change on run time */
-	wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
-			     sizeof(struct wil6210_mbox_ctl));
-	wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
-	wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+	wil_cache_mbox_regs(wil);
 
 	return 0;
 }
@@ -162,7 +169,7 @@
 
 static void wil_target_reset(struct wil6210_priv *wil)
 {
-	wil_dbg(wil, "Resetting...\n");
+	wil_dbg_misc(wil, "Resetting...\n");
 
 	/* register write */
 #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
@@ -202,7 +209,7 @@
 
 	msleep(2000);
 
-	wil_dbg(wil, "Reset completed\n");
+	wil_dbg_misc(wil, "Reset completed\n");
 
 #undef W
 #undef S
@@ -225,8 +232,8 @@
 		wil_err(wil, "Firmware not ready\n");
 		return -ETIME;
 	} else {
-		wil_dbg(wil, "FW ready after %d ms\n",
-			jiffies_to_msecs(to-left));
+		wil_dbg_misc(wil, "FW ready after %d ms\n",
+			     jiffies_to_msecs(to-left));
 	}
 	return 0;
 }
@@ -243,14 +250,14 @@
 	cancel_work_sync(&wil->disconnect_worker);
 	wil6210_disconnect(wil, NULL);
 
-	wmi_event_flush(wil);
-
-	flush_workqueue(wil->wmi_wq);
-	flush_workqueue(wil->wmi_wq_conn);
-
 	wil6210_disable_irq(wil);
 	wil->status = 0;
 
+	wmi_event_flush(wil);
+
+	flush_workqueue(wil->wmi_wq_conn);
+	flush_workqueue(wil->wmi_wq);
+
 	/* TODO: put MAC in reset */
 	wil_target_reset(wil);
 
@@ -258,11 +265,7 @@
 	wil->pending_connect_cid = -1;
 	INIT_COMPLETION(wil->wmi_ready);
 
-	/* make shadow copy of registers that should not change on run time */
-	wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
-			     sizeof(struct wil6210_mbox_ctl));
-	wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
-	wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+	wil_cache_mbox_regs(wil);
 
 	/* TODO: release MAC reset */
 	wil6210_enable_irq(wil);
@@ -278,7 +281,7 @@
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 
-	wil_dbg(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	netif_carrier_on(ndev);
 	netif_tx_wake_all_queues(ndev);
@@ -288,7 +291,7 @@
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 
-	wil_dbg(wil, "%s()\n", __func__);
+	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	netif_tx_stop_all_queues(ndev);
 	netif_carrier_off(ndev);
@@ -311,27 +314,27 @@
 	wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC);
 	switch (wdev->iftype) {
 	case NL80211_IFTYPE_STATION:
-		wil_dbg(wil, "type: STATION\n");
+		wil_dbg_misc(wil, "type: STATION\n");
 		bi = 0;
 		ndev->type = ARPHRD_ETHER;
 		break;
 	case NL80211_IFTYPE_AP:
-		wil_dbg(wil, "type: AP\n");
+		wil_dbg_misc(wil, "type: AP\n");
 		bi = 100;
 		ndev->type = ARPHRD_ETHER;
 		break;
 	case NL80211_IFTYPE_P2P_CLIENT:
-		wil_dbg(wil, "type: P2P_CLIENT\n");
+		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
 		bi = 0;
 		ndev->type = ARPHRD_ETHER;
 		break;
 	case NL80211_IFTYPE_P2P_GO:
-		wil_dbg(wil, "type: P2P_GO\n");
+		wil_dbg_misc(wil, "type: P2P_GO\n");
 		bi = 100;
 		ndev->type = ARPHRD_ETHER;
 		break;
 	case NL80211_IFTYPE_MONITOR:
-		wil_dbg(wil, "type: Monitor\n");
+		wil_dbg_misc(wil, "type: Monitor\n");
 		bi = 0;
 		ndev->type = ARPHRD_IEEE80211_RADIOTAP;
 		/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
@@ -354,7 +357,7 @@
 			wmi_set_channel(wil, channel->hw_value);
 		break;
 	default:
-		;
+		break;
 	}
 
 	/* MAC address - pre-requisite for other commands */
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 3068b5c..8ce2e33 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -35,37 +35,12 @@
 	return wil_down(wil);
 }
 
-/*
- * AC to queue mapping
- *
- * AC_VO -> queue 3
- * AC_VI -> queue 2
- * AC_BE -> queue 1
- * AC_BK -> queue 0
- */
-static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb)
-{
-	static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
-	struct wil6210_priv *wil = ndev_to_wil(ndev);
-	u16 rc;
-
-	skb->priority = cfg80211_classify8021d(skb);
-
-	rc = wil_1d_to_queue[skb->priority];
-
-	wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority,
-		     (int)rc);
-
-	return rc;
-}
-
 static const struct net_device_ops wil_netdev_ops = {
 	.ndo_open		= wil_open,
 	.ndo_stop		= wil_stop,
 	.ndo_start_xmit		= wil_start_xmit,
-	.ndo_select_queue	= wil_select_queue,
-	.ndo_set_mac_address    = eth_mac_addr,
-	.ndo_validate_addr      = eth_validate_addr,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
 };
 
 void *wil_if_alloc(struct device *dev, void __iomem *csr)
@@ -97,7 +72,7 @@
 	ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
 	cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
 
-	ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1);
+	ndev = alloc_netdev(0, "wlan%d", ether_setup);
 	if (!ndev) {
 		dev_err(dev, "alloc_netdev_mqs failed\n");
 		rc = -ENOMEM;
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 0fc83ed..81c35c6 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -53,7 +53,7 @@
 	}
 	wil->n_msi = use_msi;
 	if (wil->n_msi) {
-		wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi);
+		wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
 		rc = pci_enable_msi_block(pdev, wil->n_msi);
 		if (rc && (wil->n_msi == 3)) {
 			wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
@@ -65,7 +65,7 @@
 			wil->n_msi = 0;
 		}
 	} else {
-		wil_dbg(wil, "MSI interrupts disabled, use INTx\n");
+		wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
 	}
 
 	rc = wil6210_init_irq(wil, pdev->irq);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index f29c294..d1315b4 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -74,8 +74,6 @@
 	vring->swtail = 0;
 	vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL);
 	if (!vring->ctx) {
-		wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n",
-			vring->size);
 		vring->va = NULL;
 		return -ENOMEM;
 	}
@@ -100,8 +98,8 @@
 		d->dma.status = TX_DMA_STATUS_DU;
 	}
 
-	wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
-		vring->va, (unsigned long long)vring->pa, vring->ctx);
+	wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
+		     vring->va, (unsigned long long)vring->pa, vring->ctx);
 
 	return 0;
 }
@@ -353,8 +351,8 @@
 	if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
 		wil_rx_add_radiotap_header(wil, skb, d);
 
-	wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
-	wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4,
+	wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
+	wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
 			  (const void *)d, sizeof(*d), false);
 
 	wil_vring_advance_head(vring, 1);
@@ -369,7 +367,7 @@
 	 */
 	ftype = wil_rxdesc_ftype(d) << 2;
 	if (ftype != IEEE80211_FTYPE_DATA) {
-		wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype);
+		wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
 		/* TODO: process it */
 		kfree_skb(skb);
 		return NULL;
@@ -430,6 +428,8 @@
 	int rc;
 	unsigned int len = skb->len;
 
+	skb_orphan(skb);
+
 	if (in_interrupt())
 		rc = netif_rx(skb);
 	else
@@ -459,13 +459,11 @@
 		wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
 		return;
 	}
-	wil_dbg_TXRX(wil, "%s()\n", __func__);
+	wil_dbg_txrx(wil, "%s()\n", __func__);
 	while (NULL != (skb = wil_vring_reap_rx(wil, v))) {
-		wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
+		wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
 				  skb->data, skb_headlen(skb), false);
 
-		skb_orphan(skb);
-
 		if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 			skb->dev = ndev;
 			skb_reset_mac_header(skb);
@@ -484,53 +482,18 @@
 
 int wil_rx_init(struct wil6210_priv *wil)
 {
-	struct net_device *ndev = wil_to_ndev(wil);
-	struct wireless_dev *wdev = wil->wdev;
 	struct vring *vring = &wil->vring_rx;
 	int rc;
-	struct wmi_cfg_rx_chain_cmd cmd = {
-		.action = WMI_RX_CHAIN_ADD,
-		.rx_sw_ring = {
-			.max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
-		},
-		.mid = 0, /* TODO - what is it? */
-		.decap_trans_type = WMI_DECAP_TYPE_802_3,
-	};
-	struct {
-		struct wil6210_mbox_hdr_wmi wmi;
-		struct wmi_cfg_rx_chain_done_event evt;
-	} __packed evt;
 
 	vring->size = WIL6210_RX_RING_SIZE;
 	rc = wil_vring_alloc(wil, vring);
 	if (rc)
 		return rc;
 
-	cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
-	cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size);
-	if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
-		struct ieee80211_channel *ch = wdev->preset_chandef.chan;
-
-		cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
-		if (ch)
-			cmd.sniffer_cfg.channel = ch->hw_value - 1;
-		cmd.sniffer_cfg.phy_info_mode =
-			cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
-		cmd.sniffer_cfg.phy_support =
-			cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
-				    ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
-	}
-	/* typical time for secure PCP is 840ms */
-	rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
-		      WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
+	rc = wmi_rx_chain_add(wil, vring);
 	if (rc)
 		goto err_free;
 
-	vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
-
-	wil_dbg(wil, "Rx init: status %d tail 0x%08x\n",
-		le32_to_cpu(evt.evt.status), vring->hwtail);
-
 	rc = wil_rx_refill(wil, vring->size);
 	if (rc)
 		goto err_free;
@@ -546,25 +509,8 @@
 {
 	struct vring *vring = &wil->vring_rx;
 
-	if (vring->va) {
-		int rc;
-		struct wmi_cfg_rx_chain_cmd cmd = {
-			.action = cpu_to_le32(WMI_RX_CHAIN_DEL),
-			.rx_sw_ring = {
-				.max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
-			},
-		};
-		struct {
-			struct wil6210_mbox_hdr_wmi wmi;
-			struct wmi_cfg_rx_chain_done_event cfg;
-		} __packed wmi_rx_cfg_reply;
-
-		rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
-			      WMI_CFG_RX_CHAIN_DONE_EVENTID,
-			      &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply),
-			      100);
+	if (vring->va)
 		wil_vring_free(wil, vring, 0);
-	}
 }
 
 int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
@@ -617,6 +563,7 @@
 	if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
 		wil_err(wil, "Tx config failed, status 0x%02x\n",
 			reply.cmd.status);
+		rc = -EINVAL;
 		goto out_free;
 	}
 	vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
@@ -689,7 +636,7 @@
 	uint i = swhead;
 	dma_addr_t pa;
 
-	wil_dbg_TXRX(wil, "%s()\n", __func__);
+	wil_dbg_txrx(wil, "%s()\n", __func__);
 
 	if (avail < vring->size/8)
 		netif_tx_stop_all_queues(wil_to_ndev(wil));
@@ -706,9 +653,9 @@
 	pa = dma_map_single(dev, skb->data,
 			skb_headlen(skb), DMA_TO_DEVICE);
 
-	wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
+	wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
 		     skb->data, (unsigned long long)pa);
-	wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
+	wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
 			  skb->data, skb_headlen(skb), false);
 
 	if (unlikely(dma_mapping_error(dev, pa)))
@@ -737,12 +684,12 @@
 	d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
 	d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
 
-	wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4,
+	wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
 			  (const void *)d, sizeof(*d), false);
 
 	/* advance swhead */
 	wil_vring_advance_head(vring, nr_frags + 1);
-	wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
+	wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
 	iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
 	/* hold reference to skb
 	 * to prevent skb release before accounting
@@ -775,7 +722,7 @@
 	struct vring *vring;
 	int rc;
 
-	wil_dbg_TXRX(wil, "%s()\n", __func__);
+	wil_dbg_txrx(wil, "%s()\n", __func__);
 	if (!test_bit(wil_status_fwready, &wil->status)) {
 		wil_err(wil, "FW not ready\n");
 		goto drop;
@@ -802,15 +749,13 @@
 	}
 	switch (rc) {
 	case 0:
-		ndev->stats.tx_packets++;
-		ndev->stats.tx_bytes += skb->len;
+		/* statistics will be updated on the tx_complete */
 		dev_kfree_skb_any(skb);
 		return NETDEV_TX_OK;
 	case -ENOMEM:
 		return NETDEV_TX_BUSY;
 	default:
-		; /* goto drop; */
-		break;
+		break; /* goto drop; */
 	}
  drop:
 	netif_tx_stop_all_queues(ndev);
@@ -827,6 +772,7 @@
  */
 void wil_tx_complete(struct wil6210_priv *wil, int ringid)
 {
+	struct net_device *ndev = wil_to_ndev(wil);
 	struct device *dev = wil_to_dev(wil);
 	struct vring *vring = &wil->vring_tx[ringid];
 
@@ -835,7 +781,7 @@
 		return;
 	}
 
-	wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid);
+	wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
 
 	while (!wil_vring_is_empty(vring)) {
 		volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx;
@@ -844,16 +790,23 @@
 		if (!(d->dma.status & TX_DMA_STATUS_DU))
 			break;
 
-		wil_dbg_TXRX(wil,
+		wil_dbg_txrx(wil,
 			     "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
 			     vring->swtail, d->dma.length, d->dma.status,
 			     d->dma.error);
-		wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4,
+		wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
 				  (const void *)d, sizeof(*d), false);
 
 		pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
 		skb = vring->ctx[vring->swtail];
 		if (skb) {
+			if (d->dma.error == 0) {
+				ndev->stats.tx_packets++;
+				ndev->stats.tx_bytes += skb->len;
+			} else {
+				ndev->stats.tx_errors++;
+			}
+
 			dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
 			dev_kfree_skb_any(skb);
 			vring->ctx[vring->swtail] = NULL;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9bcfffa..aea961f 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -36,8 +36,6 @@
 
 #define WIL6210_MEM_SIZE (2*1024*1024UL)
 
-#define WIL6210_TX_QUEUES (4)
-
 #define WIL6210_RX_RING_SIZE (128)
 #define WIL6210_TX_RING_SIZE (128)
 #define WIL6210_MAX_TX_RINGS (24)
@@ -101,8 +99,7 @@
 #define RGF_DMA_EP_MISC_ICR		(0x881bec) /* struct RGF_ICR */
 	#define BIT_DMA_EP_MISC_ICR_RX_HTRSH	BIT(0)
 	#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT	BIT(1)
-	#define BIT_DMA_EP_MISC_ICR_FW_INT0	BIT(28)
-	#define BIT_DMA_EP_MISC_ICR_FW_INT1	BIT(29)
+	#define BIT_DMA_EP_MISC_ICR_FW_INT(n)	BIT(28+n) /* n = [0..3] */
 
 /* Interrupt moderation control */
 #define RGF_DMA_ITR_CNT_TRSH		(0x881c5c)
@@ -121,8 +118,9 @@
 #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2
 
 /* ISR register bits */
-#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0
-#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1
+#define ISR_MISC_FW_READY	BIT_DMA_EP_MISC_ICR_FW_INT(0)
+#define ISR_MISC_MBOX_EVT	BIT_DMA_EP_MISC_ICR_FW_INT(1)
+#define ISR_MISC_FW_ERROR	BIT_DMA_EP_MISC_ICR_FW_INT(3)
 
 /* Hardware definitions end */
 
@@ -272,17 +270,18 @@
 #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg)
 #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg)
 
-#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
-#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
-#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
+#define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
+#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
+#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
+#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
 
-#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize,	\
+#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize,	\
 			  groupsize, buf, len, ascii)		\
 			  wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
 					 prefix_type, rowsize,	\
 					 groupsize, buf, len, ascii)
 
-#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize,	\
+#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize,	\
 			 groupsize, buf, len, ascii)		\
 			 wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
 					prefix_type, rowsize,	\
@@ -328,6 +327,7 @@
 		       const void *mac_addr, int key_len, const void *key);
 int wmi_echo(struct wil6210_priv *wil);
 int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
+int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
 
 int wil6210_init_irq(struct wil6210_priv *wil, int irq);
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 12915f6..0bb3b76 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -18,8 +18,10 @@
 #include <linux/io.h>
 #include <linux/list.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 
 #include "wil6210.h"
+#include "txrx.h"
 #include "wmi.h"
 
 /**
@@ -186,7 +188,6 @@
 		wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
 			(int)(sizeof(cmd) + len), r->entry_size);
 		return -ERANGE;
-
 	}
 
 	might_sleep();
@@ -213,7 +214,7 @@
 	}
 	/* next head */
 	next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
-	wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
+	wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
 	/* wait till FW finish with previous command */
 	for (retry = 5; retry > 0; retry--) {
 		r->tail = ioread32(wil->csr + HOST_MBOX +
@@ -234,10 +235,10 @@
 	}
 	cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
 	/* set command */
-	wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
-	wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
+	wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
+	wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
 			 sizeof(cmd), true);
-	wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
+	wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
 			 len, true);
 	wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
 	wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
@@ -273,7 +274,7 @@
 	struct wmi_ready_event *evt = d;
 	u32 ver = le32_to_cpu(evt->sw_version);
 
-	wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
+	wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
 
 	if (!is_valid_ether_addr(ndev->dev_addr)) {
 		memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
@@ -286,7 +287,7 @@
 static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
 			     int len)
 {
-	wil_dbg_WMI(wil, "WMI: FW ready\n");
+	wil_dbg_wmi(wil, "WMI: FW ready\n");
 
 	set_bit(wil_status_fwready, &wil->status);
 	/* reuse wmi_ready for the firmware ready indication */
@@ -309,11 +310,11 @@
 	u32 d_len = le32_to_cpu(data->info.len);
 	u16 d_status = le16_to_cpu(data->info.status);
 
-	wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n",
+	wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
 		    data->info.channel, data->info.mcs, data->info.snr);
-	wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
+	wil_dbg_wmi(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
 		    le16_to_cpu(data->info.stype));
-	wil_dbg_WMI(wil, "qid %d mid %d cid %d\n",
+	wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
 		    data->info.qid, data->info.mid, data->info.cid);
 
 	if (!channel) {
@@ -329,15 +330,15 @@
 		const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
 		size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
 						 u.beacon.variable);
-		wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap);
+		wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
 
 		bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
 					  tsf, cap, bi, ie_buf, ie_len,
 					  signal, GFP_KERNEL);
 		if (bss) {
-			wil_dbg_WMI(wil, "Added BSS %pM\n",
+			wil_dbg_wmi(wil, "Added BSS %pM\n",
 				    rx_mgmt_frame->bssid);
-			cfg80211_put_bss(bss);
+			cfg80211_put_bss(wiphy, bss);
 		} else {
 			wil_err(wil, "cfg80211_inform_bss() failed\n");
 		}
@@ -351,7 +352,7 @@
 		struct wmi_scan_complete_event *data = d;
 		bool aborted = (data->status != 0);
 
-		wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
+		wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
 		cfg80211_scan_done(wil->scan_request, aborted);
 		wil->scan_request = NULL;
 	} else {
@@ -386,9 +387,9 @@
 		return;
 	}
 	ch = evt->channel + 1;
-	wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n",
+	wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
 		    evt->bssid, ch, evt->cid);
-	wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
+	wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
 			 evt->assoc_info, len - sizeof(*evt), true);
 
 	/* figure out IE's */
@@ -450,14 +451,13 @@
 {
 	struct wmi_disconnect_event *evt = d;
 
-	wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n",
+	wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n",
 		    evt->bssid,
 		    evt->protocol_reason_status, evt->disconnect_reason);
 
 	wil->sinfo_gen++;
 
 	wil6210_disconnect(wil, evt->bssid);
-	clear_bit(wil_status_dontscan, &wil->status);
 }
 
 static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
@@ -476,7 +476,7 @@
 	wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
 	wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
 	wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
-	wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n"
+	wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
 		    "BF status 0x%08x SNR 0x%08x\n"
 		    "Tx Tpt %d goodput %d Rx goodput %d\n"
 		    "Sectors(rx:tx) my %d:%d peer %d:%d\n",
@@ -501,7 +501,7 @@
 	struct sk_buff *skb;
 	struct ethhdr *eth;
 
-	wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len,
+	wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
 		    evt->src_mac);
 
 	if (eapol_len > 196) { /* TODO: revisit size limit */
@@ -587,11 +587,9 @@
 		evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
 					     event.wmi) + len, 4),
 			      GFP_KERNEL);
-		if (!evt) {
-			wil_err(wil, "kmalloc for WMI event (%d) failed\n",
-				len);
+		if (!evt)
 			return;
-		}
+
 		evt->event.hdr = hdr;
 		cmd = (void *)&evt->event.wmi;
 		wil_memcpy_fromio_32(cmd, src, len);
@@ -599,15 +597,15 @@
 		iowrite32(0, wil->csr + HOSTADDR(r->tail) +
 			  offsetof(struct wil6210_mbox_ring_desc, sync));
 		/* indicate */
-		wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n",
+		wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
 			    le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
 			    hdr.flags);
 		if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
 		    (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
-			wil_dbg_WMI(wil, "WMI event 0x%04x\n",
+			wil_dbg_wmi(wil, "WMI event 0x%04x\n",
 				    evt->event.wmi.id);
 		}
-		wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1,
+		wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
 				 &evt->event.hdr, sizeof(hdr) + len, true);
 
 		/* advance tail */
@@ -623,7 +621,7 @@
 		{
 			int q =	queue_work(wil->wmi_wq,
 					   &wil->wmi_event_worker);
-			wil_dbg_WMI(wil, "queue_work -> %d\n", q);
+			wil_dbg_wmi(wil, "queue_work -> %d\n", q);
 		}
 	}
 }
@@ -650,7 +648,7 @@
 			cmdid, reply_id, to_msec);
 		rc = -ETIME;
 	} else {
-		wil_dbg_WMI(wil,
+		wil_dbg_wmi(wil,
 			    "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
 			    cmdid, reply_id,
 			    to_msec - jiffies_to_msecs(remain));
@@ -680,7 +678,7 @@
 
 	memcpy(cmd.mac, addr, ETH_ALEN);
 
-	wil_dbg_WMI(wil, "Set MAC %pM\n", addr);
+	wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
 
 	return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
 }
@@ -778,7 +776,7 @@
 
 	skb_set_mac_header(skb, 0);
 	eth = eth_hdr(skb);
-	wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
+	wil_dbg_wmi(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
 	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
 		if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0)
 			goto found_dest;
@@ -838,10 +836,8 @@
 	int rc;
 	u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
 	struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
-	if (!cmd) {
-		wil_err(wil, "kmalloc(%d) failed\n", len);
+	if (!cmd)
 		return -ENOMEM;
-	}
 
 	cmd->mgmt_frm_type = type;
 	/* BUG: FW API define ieLen as u8. Will fix FW */
@@ -853,11 +849,60 @@
 	return rc;
 }
 
+int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
+{
+	struct wireless_dev *wdev = wil->wdev;
+	struct net_device *ndev = wil_to_ndev(wil);
+	struct wmi_cfg_rx_chain_cmd cmd = {
+		.action = WMI_RX_CHAIN_ADD,
+		.rx_sw_ring = {
+			.max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
+			.ring_mem_base = cpu_to_le64(vring->pa),
+			.ring_size = cpu_to_le16(vring->size),
+		},
+		.mid = 0, /* TODO - what is it? */
+		.decap_trans_type = WMI_DECAP_TYPE_802_3,
+	};
+	struct {
+		struct wil6210_mbox_hdr_wmi wmi;
+		struct wmi_cfg_rx_chain_done_event evt;
+	} __packed evt;
+	int rc;
+
+	if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
+		struct ieee80211_channel *ch = wdev->preset_chandef.chan;
+
+		cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
+		if (ch)
+			cmd.sniffer_cfg.channel = ch->hw_value - 1;
+		cmd.sniffer_cfg.phy_info_mode =
+			cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
+		cmd.sniffer_cfg.phy_support =
+			cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
+				    ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
+	}
+	/* typical time for secure PCP is 840ms */
+	rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
+		      WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
+	if (rc)
+		return rc;
+
+	vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
+
+	wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
+		     le32_to_cpu(evt.evt.status), vring->hwtail);
+
+	if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
+		rc = -EINVAL;
+
+	return rc;
+}
+
 void wmi_event_flush(struct wil6210_priv *wil)
 {
 	struct pending_wmi_event *evt, *t;
 
-	wil_dbg_WMI(wil, "%s()\n", __func__);
+	wil_dbg_wmi(wil, "%s()\n", __func__);
 
 	list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
 		list_del(&evt->list);
@@ -899,7 +944,7 @@
 				wmi_evt_call_handler(wil, id, evt_data,
 						     len - sizeof(*wmi));
 			}
-			wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id);
+			wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
 			complete(&wil->wmi_ready);
 			return;
 		}
@@ -964,7 +1009,7 @@
 		return;
 	}
 
-	wil_dbg_WMI(wil, "Configure for connection CID %d\n",
+	wil_dbg_wmi(wil, "Configure for connection CID %d\n",
 		    wil->pending_connect_cid);
 
 	rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index ded03d2..b42930f 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -79,10 +79,9 @@
 
 	/* Allocate space for private device-specific data */
 	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
-	if (!local) {
-		printk(KERN_ERR "atmel_cs: no memory for new device\n");
+	if (!local)
 		return -ENOMEM;
-	}
+
 	p_dev->priv = local;
 
 	return atmel_config(p_dev);
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index 315b96e..9fdd198 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -169,7 +169,7 @@
 
 /* DMA engine tuning knobs */
 #define B43_TXRING_SLOTS		256
-#define B43_RXRING_SLOTS		64
+#define B43_RXRING_SLOTS		256
 #define B43_DMA0_RX_FW598_BUFSIZE	(B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN)
 #define B43_DMA0_RX_FW351_BUFSIZE	(B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN)
 
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 97d4e27..aaca60c 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -3226,8 +3226,6 @@
 {
 	struct nphy_gain_ctl_workaround_entry *e;
 	u8 phy_idx;
-	u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso :
-			   dev->dev->bus_sprom->fem.ghz2.tr_iso;
 
 	if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11)
 		return &nphy_gain_ctl_wa_phy6_radio11_ghz2;
@@ -3249,6 +3247,10 @@
 		    !b43_channel_type_is_40mhz(dev->phy.channel_type))
 			e->cliplo_gain = 0x2d;
 	} else if (!ghz5 && dev->phy.rev >= 5) {
+		static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
+						0x106c, 0x1074, 0x107c, 0x207c};
+		u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
+
 		if (ext_lna) {
 			e->rfseq_init[0] &= ~0x4000;
 			e->rfseq_init[1] &= ~0x4000;
@@ -3256,26 +3258,10 @@
 			e->rfseq_init[3] &= ~0x4000;
 			e->init_gain &= ~0x4000;
 		}
-		switch (tr_iso) {
-		case 0:
-			e->cliplo_gain = 0x0062;
-		case 1:
-			e->cliplo_gain = 0x0064;
-		case 2:
-			e->cliplo_gain = 0x006a;
-		case 3:
-			e->cliplo_gain = 0x106a;
-		case 4:
-			e->cliplo_gain = 0x106c;
-		case 5:
-			e->cliplo_gain = 0x1074;
-		case 6:
-			e->cliplo_gain = 0x107c;
-		case 7:
-			e->cliplo_gain = 0x207c;
-		default:
-			e->cliplo_gain = 0x106a;
-		}
+		if (tr_iso > 7)
+			tr_iso = 3;
+		e->cliplo_gain = gain_data[tr_iso];
+
 	} else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
 		e->rfseq_init[0] &= ~0x4000;
 		e->rfseq_init[1] &= ~0x4000;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 1a6661a..756e19f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -26,6 +26,7 @@
 		wl_cfg80211.o \
 		fwil.o \
 		fweh.o \
+		p2p.o \
 		dhd_cdc.o \
 		dhd_common.o \
 		dhd_linux.o
@@ -37,4 +38,4 @@
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
 		usb.o
 brcmfmac-$(CONFIG_BRCMDBG) += \
-		dhd_dbg.o
\ No newline at end of file
+		dhd_dbg.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index be35a2f..11fd1c7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -15,8 +15,6 @@
  */
 /* ****************** SDIO CARD Interface Functions **************************/
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/export.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index d33e559..d92d373 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/mmc/sdio.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index fd672bf..ef6f23b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -39,6 +39,7 @@
 #define BRCMF_C_GET_BSSID			23
 #define BRCMF_C_GET_SSID			25
 #define BRCMF_C_SET_SSID			26
+#define BRCMF_C_TERMINATED			28
 #define BRCMF_C_GET_CHANNEL			29
 #define BRCMF_C_SET_CHANNEL			30
 #define BRCMF_C_GET_SRL				31
@@ -71,6 +72,7 @@
 #define BRCMF_C_SET_WSEC			134
 #define BRCMF_C_GET_PHY_NOISE			135
 #define BRCMF_C_GET_BSS_INFO			136
+#define BRCMF_C_SET_SCB_TIMEOUT			158
 #define BRCMF_C_GET_PHYLIST			180
 #define BRCMF_C_SET_SCAN_CHANNEL_TIME		185
 #define BRCMF_C_SET_SCAN_UNASSOC_TIME		187
@@ -148,6 +150,7 @@
 #define BRCMF_E_REASON_MINTXRATE		9
 #define BRCMF_E_REASON_TXFAIL			10
 
+#define BRCMF_E_REASON_LINK_BSSCFG_DIS		4
 #define BRCMF_E_REASON_FAST_ROAM_FAILED		5
 #define BRCMF_E_REASON_DIRECTED_ROAM		6
 #define BRCMF_E_REASON_TSPEC_REJECTED		7
@@ -374,6 +377,28 @@
 	struct brcmf_assoc_params_le params_le;
 };
 
+/* scan params for extended join */
+struct brcmf_join_scan_params_le {
+	u8 scan_type;		/* 0 use default, active or passive scan */
+	__le32 nprobes;		/* -1 use default, nr of probes per channel */
+	__le32 active_time;	/* -1 use default, dwell time per channel for
+				 * active scanning
+				 */
+	__le32 passive_time;	/* -1 use default, dwell time per channel
+				 * for passive scanning
+				 */
+	__le32 home_time;	/* -1 use default, dwell time for the home
+				 * channel between channel scans
+				 */
+};
+
+/* extended join params */
+struct brcmf_ext_join_params_le {
+	struct brcmf_ssid_le ssid_le;	/* {0, ""}: wildcard scan */
+	struct brcmf_join_scan_params_le scan_le;
+	struct brcmf_assoc_params_le assoc_le;
+};
+
 struct brcmf_wsec_key {
 	u32 index;		/* key index */
 	u32 len;		/* key length */
@@ -450,6 +475,19 @@
 	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */
 };
 
+/*
+ * WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
+struct brcmf_rx_mgmt_data {
+	__be16	version;
+	__be16	chanspec;
+	__be32	rssi;
+	__be32	mactime;
+	__be32	rate;
+};
+
 /* Bus independent dongle command */
 struct brcmf_dcmd {
 	uint cmd;		/* common dongle cmd definition */
@@ -480,50 +518,20 @@
 	unsigned long drv_version;	/* Version of dongle-resident driver */
 	u8 mac[ETH_ALEN];		/* MAC address obtained from dongle */
 
-	/* Additional stats for the bus level */
-
 	/* Multicast data packets sent to dongle */
 	unsigned long tx_multicast;
-	/* Packets flushed due to unscheduled sendup thread */
-	unsigned long rx_flushed;
-	/* Number of times dpc scheduled by watchdog timer */
-	unsigned long wd_dpc_sched;
-
-	/* Number of flow control pkts recvd */
-	unsigned long fc_packets;
-
-	/* Last error return */
-	int bcmerror;
-
-	/* Last error from dongle */
-	int dongle_error;
-
-	/* Suspend disable flag  flag */
-	int suspend_disable_flag;	/* "1" to disable all extra powersaving
-					 during suspend */
-	int in_suspend;		/* flag set to 1 when early suspend called */
-	int dtim_skip;		/* dtim skip , default 0 means wake each dtim */
 
 	struct brcmf_if *iflist[BRCMF_MAX_IFS];
 
 	struct mutex proto_block;
 	unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
-	u8 macvalue[ETH_ALEN];
-	atomic_t pend_8021x_cnt;
-	wait_queue_head_t pend_8021x_wait;
-
 	struct brcmf_fweh_info fweh;
 #ifdef DEBUG
 	struct dentry *dbgfs_dir;
 #endif
 };
 
-struct bcmevent_name {
-	uint event;
-	const char *name;
-};
-
 struct brcmf_if_event {
 	u8 ifidx;
 	u8 action;
@@ -541,9 +549,11 @@
  * @vif: points to cfg80211 specific interface information.
  * @ndev: associated network device.
  * @stats: interface specific network statistics.
- * @idx: interface index in device firmware.
+ * @ifidx: interface index in device firmware.
  * @bssidx: index of bss associated with this interface.
  * @mac_addr: assigned mac address.
+ * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
+ * @pend_8021x_wait: used for signalling change in count.
  */
 struct brcmf_if {
 	struct brcmf_pub *drvr;
@@ -552,18 +562,13 @@
 	struct net_device_stats stats;
 	struct work_struct setmacaddr_work;
 	struct work_struct multicast_work;
-	int idx;
+	int ifidx;
 	s32 bssidx;
 	u8 mac_addr[ETH_ALEN];
+	atomic_t pend_8021x_cnt;
+	wait_queue_head_t pend_8021x_wait;
 };
 
-static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
-{
-	struct brcmf_if *ifp = netdev_priv(ndev);
-	return ifp->bssidx;
-}
-
-extern const struct bcmevent_name bcmevent_names[];
 
 extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 
@@ -576,9 +581,14 @@
 extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
 				    void *buf, uint len);
 
-extern int brcmf_net_attach(struct brcmf_if *ifp);
-extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
-				     s32 bssidx, char *name, u8 *mac_addr);
-extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
+/* Remove any protocol-specific data header. */
+extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+			       struct sk_buff *rxp);
+
+extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx,
+				     s32 ifidx, char *name, u8 *mac_addr);
+extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
+extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
 
 #endif				/* _BRCMF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index dd38b78..ad25c34 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -24,18 +24,6 @@
 	BRCMF_BUS_DATA		/* Ready for frame transfers */
 };
 
-struct dngl_stats {
-	unsigned long rx_packets;	/* total packets received */
-	unsigned long tx_packets;	/* total packets transmitted */
-	unsigned long rx_bytes;	/* total bytes received */
-	unsigned long tx_bytes;	/* total bytes transmitted */
-	unsigned long rx_errors;	/* bad packets received */
-	unsigned long tx_errors;	/* packet transmit problems */
-	unsigned long rx_dropped;	/* packets dropped by dongle */
-	unsigned long tx_dropped;	/* packets dropped by dongle */
-	unsigned long multicast;	/* multicast packets received */
-};
-
 struct brcmf_bus_dcmd {
 	char *name;
 	char *param;
@@ -72,11 +60,12 @@
  * @drvr: public driver information.
  * @state: operational state of the bus interface.
  * @maxctl: maximum size for rxctl request message.
- * @drvr_up: indicates driver up/down status.
  * @tx_realloc: number of tx packets realloced for headroom.
  * @dstats: dongle-based statistical data.
  * @align: alignment requirement for the bus.
  * @dcmd_list: bus/device specific dongle initialization commands.
+ * @chip: device identifier of the dongle chip.
+ * @chiprev: revision of the dongle chip.
  */
 struct brcmf_bus {
 	union {
@@ -87,10 +76,10 @@
 	struct brcmf_pub *drvr;
 	enum brcmf_bus_state state;
 	uint maxctl;
-	bool drvr_up;
 	unsigned long tx_realloc;
-	struct dngl_stats dstats;
 	u8 align;
+	u32 chip;
+	u32 chiprev;
 	struct list_head dcmd_list;
 
 	struct brcmf_bus_ops *ops;
@@ -130,31 +119,18 @@
  * interface functions from common layer
  */
 
-/* Remove any protocol-specific data header. */
-extern int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
-			       struct sk_buff *rxp);
-
 extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
 			 struct sk_buff *pkt, int prec);
 
 /* Receive frame for delivery to OS.  Callee disposes of rxp. */
-extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
-			   struct sk_buff_head *rxlist);
-static inline void brcmf_rx_packet(struct device *dev, int ifidx,
-				   struct sk_buff *pkt)
-{
-	struct sk_buff_head q;
-
-	skb_queue_head_init(&q);
-	skb_queue_tail(&q, pkt);
-	brcmf_rx_frame(dev, ifidx, &q);
-}
+extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
 extern int brcmf_attach(uint bus_hdrlen, struct device *dev);
 /* Indication from bus module regarding removal/absence of dongle */
 extern void brcmf_detach(struct device *dev);
-
+/* Indication from bus module that dongle should be reset */
+extern void brcmf_dev_reset(struct device *dev);
 /* Indication from bus module to change flow-control state */
 extern void brcmf_txflowblock(struct device *dev, bool state);
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
index 8392355..a2354d9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
@@ -19,8 +19,6 @@
  * For certain dcmd codes, the dongle interprets string data from the host.
  ******************************************************************************/
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 
@@ -94,8 +92,6 @@
 
 struct brcmf_proto {
 	u16 reqid;
-	u8 pending;
-	u32 lastcmd;
 	u8 bus_header[BUS_HEADER_LEN];
 	struct brcmf_proto_cdc_dcmd msg;
 	unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
@@ -107,7 +103,7 @@
 	int len = le32_to_cpu(prot->msg.len) +
 			sizeof(struct brcmf_proto_cdc_dcmd);
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(CDC, "Enter\n");
 
 	/* NOTE : cdc->msg.len holds the desired length of the buffer to be
 	 *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
@@ -125,7 +121,7 @@
 	int ret;
 	struct brcmf_proto *prot = drvr->prot;
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(CDC, "Enter\n");
 	len += sizeof(struct brcmf_proto_cdc_dcmd);
 	do {
 		ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,
@@ -147,20 +143,7 @@
 	int ret = 0, retries = 0;
 	u32 id, flags;
 
-	brcmf_dbg(TRACE, "Enter\n");
-	brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
-
-	/* Respond "bcmerror" and "bcmerrorstr" with local cache */
-	if (cmd == BRCMF_C_GET_VAR && buf) {
-		if (!strcmp((char *)buf, "bcmerrorstr")) {
-			strncpy((char *)buf, "bcm_error",
-				BCME_STRLEN);
-			goto done;
-		} else if (!strcmp((char *)buf, "bcmerror")) {
-			*(int *)buf = drvr->dongle_error;
-			goto done;
-		}
-	}
+	brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
 
 	memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
 
@@ -210,11 +193,8 @@
 	}
 
 	/* Check the ERROR flag */
-	if (flags & CDC_DCMD_ERROR) {
+	if (flags & CDC_DCMD_ERROR)
 		ret = le32_to_cpu(msg->status);
-		/* Cache error from dongle */
-		drvr->dongle_error = ret;
-	}
 
 done:
 	return ret;
@@ -228,8 +208,7 @@
 	int ret = 0;
 	u32 flags, id;
 
-	brcmf_dbg(TRACE, "Enter\n");
-	brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
+	brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
 
 	memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
 
@@ -262,11 +241,8 @@
 	}
 
 	/* Check the ERROR flag */
-	if (flags & CDC_DCMD_ERROR) {
+	if (flags & CDC_DCMD_ERROR)
 		ret = le32_to_cpu(msg->status);
-		/* Cache error from dongle */
-		drvr->dongle_error = ret;
-	}
 
 done:
 	return ret;
@@ -287,7 +263,7 @@
 {
 	struct brcmf_proto_bdc_header *h;
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(CDC, "Enter\n");
 
 	/* Push BDC header used to convey priority for buses that don't */
 
@@ -305,14 +281,12 @@
 	BDC_SET_IF_IDX(h, ifidx);
 }
 
-int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
+int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
 			struct sk_buff *pktbuf)
 {
 	struct brcmf_proto_bdc_header *h;
-	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-	struct brcmf_pub *drvr = bus_if->drvr;
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(CDC, "Enter\n");
 
 	/* Pop BDC header used to convey priority for buses that don't */
 
@@ -329,6 +303,14 @@
 		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
 		return -EBADE;
 	}
+	/* The ifidx is the idx to map to matching netdev/ifp. When receiving
+	 * events this is easy because it contains the bssidx which maps
+	 * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+	 * bssidx 1 is used for p2p0 and no data can be received or
+	 * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+	 */
+	if (*ifidx)
+		(*ifidx)++;
 
 	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
 	    BDC_PROTO_VER) {
@@ -338,7 +320,7 @@
 	}
 
 	if (h->flags & BDC_FLAG_SUM_GOOD) {
-		brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n",
+		brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
 			  brcmf_ifname(drvr, *ifidx), h->flags);
 		pkt_set_sum_good(pktbuf, true);
 	}
@@ -348,6 +330,8 @@
 	skb_pull(pktbuf, BDC_HEADER_LEN);
 	skb_pull(pktbuf, h->data_offset << 2);
 
+	if (pktbuf->len == 0)
+		return -ENODATA;
 	return 0;
 }
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
index f8b52e5..4544342 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index f2ab01c..bc013cb 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -18,21 +18,26 @@
 #define _BRCMF_DBG_H_
 
 /* message levels */
-#define BRCMF_TRACE_VAL	0x0002
-#define BRCMF_INFO_VAL	0x0004
-#define BRCMF_DATA_VAL	0x0008
-#define BRCMF_CTL_VAL	0x0010
-#define BRCMF_TIMER_VAL	0x0020
-#define BRCMF_HDRS_VAL	0x0040
-#define BRCMF_BYTES_VAL	0x0080
-#define BRCMF_INTR_VAL	0x0100
-#define BRCMF_GLOM_VAL	0x0200
-#define BRCMF_EVENT_VAL	0x0400
-#define BRCMF_BTA_VAL	0x0800
-#define BRCMF_FIL_VAL	0x1000
-#define BRCMF_USB_VAL	0x2000
-#define BRCMF_SCAN_VAL	0x4000
-#define BRCMF_CONN_VAL	0x8000
+#define BRCMF_TRACE_VAL	0x00000002
+#define BRCMF_INFO_VAL	0x00000004
+#define BRCMF_DATA_VAL	0x00000008
+#define BRCMF_CTL_VAL	0x00000010
+#define BRCMF_TIMER_VAL	0x00000020
+#define BRCMF_HDRS_VAL	0x00000040
+#define BRCMF_BYTES_VAL	0x00000080
+#define BRCMF_INTR_VAL	0x00000100
+#define BRCMF_GLOM_VAL	0x00000200
+#define BRCMF_EVENT_VAL	0x00000400
+#define BRCMF_BTA_VAL	0x00000800
+#define BRCMF_FIL_VAL	0x00001000
+#define BRCMF_USB_VAL	0x00002000
+#define BRCMF_SCAN_VAL	0x00004000
+#define BRCMF_CONN_VAL	0x00008000
+#define BRCMF_CDC_VAL	0x00010000
+
+/* set default print format */
+#undef pr_fmt
+#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
 
 /* Macro for error messages. net_ratelimit() is used when driver
  * debugging is not selected. When debugging the driver error
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 74a616b..c06cea8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <linux/module.h>
@@ -28,6 +26,8 @@
 #include "dhd_bus.h"
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
+#include "fwil_types.h"
+#include "p2p.h"
 #include "wl_cfg80211.h"
 #include "fwil.h"
 
@@ -42,6 +42,12 @@
 int brcmf_msg_level;
 module_param(brcmf_msg_level, int, 0);
 
+/* P2P0 enable */
+static int brcmf_p2p_enable;
+#ifdef CONFIG_BRCMDBG
+module_param_named(p2pon, brcmf_p2p_enable, int, 0);
+MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
+#endif
 
 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
 {
@@ -72,9 +78,10 @@
 	u32 buflen;
 	s32 err;
 
-	brcmf_dbg(TRACE, "enter\n");
-
 	ifp = container_of(work, struct brcmf_if, multicast_work);
+
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
 	ndev = ifp->ndev;
 
 	/* Determine initial value of allmulti flag */
@@ -131,9 +138,10 @@
 	struct brcmf_if *ifp;
 	s32 err;
 
-	brcmf_dbg(TRACE, "enter\n");
-
 	ifp = container_of(work, struct brcmf_if, setmacaddr_work);
+
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
 	err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
 				       ETH_ALEN);
 	if (err < 0) {
@@ -162,28 +170,31 @@
 	schedule_work(&ifp->multicast_work);
 }
 
-static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
+					   struct net_device *ndev)
 {
 	int ret;
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
+	struct ethhdr *eh;
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
-	/* Reject if down */
-	if (!drvr->bus_if->drvr_up ||
-	    (drvr->bus_if->state != BRCMF_BUS_DATA)) {
-		brcmf_err("xmit rejected drvup=%d state=%d\n",
-			  drvr->bus_if->drvr_up,
-			  drvr->bus_if->state);
+	/* Can the device send data? */
+	if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+		brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
 		netif_stop_queue(ndev);
-		return -ENODEV;
+		dev_kfree_skb(skb);
+		ret = -ENODEV;
+		goto done;
 	}
 
-	if (!drvr->iflist[ifp->idx]) {
-		brcmf_err("bad ifidx %d\n", ifp->idx);
+	if (!drvr->iflist[ifp->bssidx]) {
+		brcmf_err("bad ifidx %d\n", ifp->bssidx);
 		netif_stop_queue(ndev);
-		return -ENODEV;
+		dev_kfree_skb(skb);
+		ret = -ENODEV;
+		goto done;
 	}
 
 	/* Make sure there's enough room for any header */
@@ -191,44 +202,49 @@
 		struct sk_buff *skb2;
 
 		brcmf_dbg(INFO, "%s: insufficient headroom\n",
-			  brcmf_ifname(drvr, ifp->idx));
+			  brcmf_ifname(drvr, ifp->bssidx));
 		drvr->bus_if->tx_realloc++;
 		skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
 		dev_kfree_skb(skb);
 		skb = skb2;
 		if (skb == NULL) {
 			brcmf_err("%s: skb_realloc_headroom failed\n",
-				  brcmf_ifname(drvr, ifp->idx));
+				  brcmf_ifname(drvr, ifp->bssidx));
 			ret = -ENOMEM;
 			goto done;
 		}
 	}
 
-	/* Update multicast statistic */
-	if (skb->len >= ETH_ALEN) {
-		u8 *pktdata = (u8 *)(skb->data);
-		struct ethhdr *eh = (struct ethhdr *)pktdata;
-
-		if (is_multicast_ether_addr(eh->h_dest))
-			drvr->tx_multicast++;
-		if (ntohs(eh->h_proto) == ETH_P_PAE)
-			atomic_inc(&drvr->pend_8021x_cnt);
+	/* validate length for ether packet */
+	if (skb->len < sizeof(*eh)) {
+		ret = -EINVAL;
+		dev_kfree_skb(skb);
+		goto done;
 	}
 
+	/* handle ethernet header */
+	eh = (struct ethhdr *)(skb->data);
+	if (is_multicast_ether_addr(eh->h_dest))
+		drvr->tx_multicast++;
+	if (ntohs(eh->h_proto) == ETH_P_PAE)
+		atomic_inc(&ifp->pend_8021x_cnt);
+
 	/* If the protocol uses a data header, apply it */
-	brcmf_proto_hdrpush(drvr, ifp->idx, skb);
+	brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
 
 	/* Use bus module to send data frame */
 	ret =  brcmf_bus_txdata(drvr->bus_if, skb);
 
 done:
-	if (ret)
-		drvr->bus_if->dstats.tx_dropped++;
-	else
-		drvr->bus_if->dstats.tx_packets++;
+	if (ret) {
+		ifp->stats.tx_dropped++;
+	} else {
+		ifp->stats.tx_packets++;
+		ifp->stats.tx_bytes += skb->len;
+	}
 
 	/* Return ok: we always eat the packet */
-	return 0;
+	return NETDEV_TX_OK;
 }
 
 void brcmf_txflowblock(struct device *dev, bool state)
@@ -250,8 +266,7 @@
 		}
 }
 
-void brcmf_rx_frame(struct device *dev, u8 ifidx,
-		    struct sk_buff_head *skb_list)
+void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
 {
 	unsigned char *eth;
 	uint len;
@@ -259,12 +274,25 @@
 	struct brcmf_if *ifp;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
+	u8 ifidx;
+	int ret;
 
 	brcmf_dbg(TRACE, "Enter\n");
 
 	skb_queue_walk_safe(skb_list, skb, pnext) {
 		skb_unlink(skb, skb_list);
 
+		/* process and remove protocol-specific header */
+		ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
+		ifp = drvr->iflist[ifidx];
+
+		if (ret || !ifp || !ifp->ndev) {
+			if ((ret != -ENODATA) && ifp)
+				ifp->stats.rx_errors++;
+			brcmu_pkt_buf_free_skb(skb);
+			continue;
+		}
+
 		/* Get the protocol, maintain skb around eth_type_trans()
 		 * The main reason for this hack is for the limitation of
 		 * Linux 2.4 where 'eth_type_trans' uses the
@@ -280,21 +308,11 @@
 		eth = skb->data;
 		len = skb->len;
 
-		ifp = drvr->iflist[ifidx];
-		if (ifp == NULL)
-			ifp = drvr->iflist[0];
-
-		if (!ifp || !ifp->ndev ||
-		    ifp->ndev->reg_state != NETREG_REGISTERED) {
-			brcmu_pkt_buf_free_skb(skb);
-			continue;
-		}
-
 		skb->dev = ifp->ndev;
 		skb->protocol = eth_type_trans(skb, skb->dev);
 
 		if (skb->pkt_type == PACKET_MULTICAST)
-			bus_if->dstats.multicast++;
+			ifp->stats.multicast++;
 
 		skb->data = eth;
 		skb->len = len;
@@ -310,8 +328,13 @@
 			ifp->ndev->last_rx = jiffies;
 		}
 
-		bus_if->dstats.rx_bytes += skb->len;
-		bus_if->dstats.rx_packets++;	/* Local count */
+		if (!(ifp->ndev->flags & IFF_UP)) {
+			brcmu_pkt_buf_free_skb(skb);
+			continue;
+		}
+
+		ifp->stats.rx_bytes += skb->len;
+		ifp->stats.rx_packets++;
 
 		if (in_interrupt())
 			netif_rx(skb);
@@ -328,41 +351,36 @@
 
 void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
 {
-	uint ifidx;
+	u8 ifidx;
 	struct ethhdr *eh;
 	u16 type;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
+	struct brcmf_if *ifp;
 
-	brcmf_proto_hdrpull(dev, &ifidx, txp);
+	brcmf_proto_hdrpull(drvr, &ifidx, txp);
+
+	ifp = drvr->iflist[ifidx];
+	if (!ifp)
+		return;
 
 	eh = (struct ethhdr *)(txp->data);
 	type = ntohs(eh->h_proto);
 
 	if (type == ETH_P_PAE) {
-		atomic_dec(&drvr->pend_8021x_cnt);
-		if (waitqueue_active(&drvr->pend_8021x_wait))
-			wake_up(&drvr->pend_8021x_wait);
+		atomic_dec(&ifp->pend_8021x_cnt);
+		if (waitqueue_active(&ifp->pend_8021x_wait))
+			wake_up(&ifp->pend_8021x_wait);
 	}
+	if (!success)
+		ifp->stats.tx_errors++;
 }
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_bus *bus_if = ifp->drvr->bus_if;
 
-	brcmf_dbg(TRACE, "Enter\n");
-
-	/* Copy dongle stats to net device stats */
-	ifp->stats.rx_packets = bus_if->dstats.rx_packets;
-	ifp->stats.tx_packets = bus_if->dstats.tx_packets;
-	ifp->stats.rx_bytes = bus_if->dstats.rx_bytes;
-	ifp->stats.tx_bytes = bus_if->dstats.tx_bytes;
-	ifp->stats.rx_errors = bus_if->dstats.rx_errors;
-	ifp->stats.tx_errors = bus_if->dstats.tx_errors;
-	ifp->stats.rx_dropped = bus_if->dstats.rx_dropped;
-	ifp->stats.tx_dropped = bus_if->dstats.tx_dropped;
-	ifp->stats.multicast = bus_if->dstats.multicast;
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 	return &ifp->stats;
 }
@@ -395,9 +413,11 @@
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
 
-	sprintf(info->driver, KBUILD_MODNAME);
-	sprintf(info->version, "%lu", drvr->drv_version);
-	sprintf(info->bus_info, "%s", dev_name(drvr->bus_if->dev));
+	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+	snprintf(info->version, sizeof(info->version), "%lu",
+		 drvr->drv_version);
+	strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
+		sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops brcmf_ethtool_ops = {
@@ -414,7 +434,7 @@
 	u32 toe_cmpnt, csum_dir;
 	int ret;
 
-	brcmf_dbg(TRACE, "Enter\n");
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 	/* all ethtool calls start with a cmd word */
 	if (copy_from_user(&cmd, uaddr, sizeof(u32)))
@@ -437,20 +457,14 @@
 			sprintf(info.driver, "dhd");
 			strcpy(info.version, BRCMF_VERSION_STR);
 		}
-
-		/* otherwise, require dongle to be up */
-		else if (!drvr->bus_if->drvr_up) {
-			brcmf_err("dongle is not up\n");
-			return -ENODEV;
-		}
-		/* finally, report dongle driver type */
+		/* report dongle driver type */
 		else
 			sprintf(info.driver, "wl");
 
 		sprintf(info.version, "%lu", drvr->drv_version);
 		if (copy_to_user(uaddr, &info, sizeof(info)))
 			return -EFAULT;
-		brcmf_dbg(CTL, "given %*s, returning %s\n",
+		brcmf_dbg(TRACE, "given %*s, returning %s\n",
 			  (int)sizeof(drvname), drvname, info.driver);
 		break;
 
@@ -517,9 +531,9 @@
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_pub *drvr = ifp->drvr;
 
-	brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
+	brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
 
-	if (!drvr->iflist[ifp->idx])
+	if (!drvr->iflist[ifp->bssidx])
 		return -1;
 
 	if (cmd == SIOCETHTOOL)
@@ -531,17 +545,12 @@
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_pub *drvr = ifp->drvr;
 
-	brcmf_dbg(TRACE, "Enter\n");
-
-	if (drvr->bus_if->drvr_up == 0)
-		return 0;
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 	brcmf_cfg80211_down(ndev);
 
 	/* Set state and stop OS transmissions */
-	drvr->bus_if->drvr_up = false;
 	netif_stop_queue(ndev);
 
 	return 0;
@@ -555,7 +564,7 @@
 	u32 toe_ol;
 	s32 ret = 0;
 
-	brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
+	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
 	/* If bus is not ready, can't continue */
 	if (bus_if->state != BRCMF_BUS_DATA) {
@@ -563,25 +572,17 @@
 		return -EAGAIN;
 	}
 
-	atomic_set(&drvr->pend_8021x_cnt, 0);
-
-	memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
+	atomic_set(&ifp->pend_8021x_cnt, 0);
 
 	/* Get current TOE mode from dongle */
 	if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
 	    && (toe_ol & TOE_TX_CSUM_OL) != 0)
-		drvr->iflist[ifp->idx]->ndev->features |=
-			NETIF_F_IP_CSUM;
+		ndev->features |= NETIF_F_IP_CSUM;
 	else
-		drvr->iflist[ifp->idx]->ndev->features &=
-			~NETIF_F_IP_CSUM;
-
-	/* make sure RF is ready for work */
-	brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+		ndev->features &= ~NETIF_F_IP_CSUM;
 
 	/* Allow transmit calls */
 	netif_start_queue(ndev);
-	drvr->bus_if->drvr_up = true;
 	if (brcmf_cfg80211_up(ndev)) {
 		brcmf_err("failed to bring up cfg80211\n");
 		return -1;
@@ -600,29 +601,18 @@
 	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
 };
 
-static const struct net_device_ops brcmf_netdev_ops_virt = {
-	.ndo_open = brcmf_cfg80211_up,
-	.ndo_stop = brcmf_cfg80211_down,
-	.ndo_get_stats = brcmf_netdev_get_stats,
-	.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
-	.ndo_start_xmit = brcmf_netdev_start_xmit,
-	.ndo_set_mac_address = brcmf_netdev_set_mac_address,
-	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
-int brcmf_net_attach(struct brcmf_if *ifp)
+int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 {
 	struct brcmf_pub *drvr = ifp->drvr;
 	struct net_device *ndev;
+	s32 err;
 
-	brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
+	brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+		  ifp->mac_addr);
 	ndev = ifp->ndev;
 
 	/* set appropriate operations */
-	if (!ifp->idx)
-		ndev->netdev_ops = &brcmf_netdev_ops_pri;
-	else
-		ndev->netdev_ops = &brcmf_netdev_ops_virt;
+	ndev->netdev_ops = &brcmf_netdev_ops_pri;
 
 	ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
 	ndev->ethtool_ops = &brcmf_ethtool_ops;
@@ -633,7 +623,14 @@
 	/* set the mac address */
 	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
 
-	if (register_netdev(ndev) != 0) {
+	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
+	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+
+	if (rtnl_locked)
+		err = register_netdevice(ndev);
+	else
+		err = register_netdev(ndev);
+	if (err != 0) {
 		brcmf_err("couldn't register the net device\n");
 		goto fail;
 	}
@@ -647,16 +644,78 @@
 	return -EBADE;
 }
 
-struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
-			      char *name, u8 *addr_mask)
+static int brcmf_net_p2p_open(struct net_device *ndev)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+
+	return brcmf_cfg80211_up(ndev);
+}
+
+static int brcmf_net_p2p_stop(struct net_device *ndev)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+
+	return brcmf_cfg80211_down(ndev);
+}
+
+static int brcmf_net_p2p_do_ioctl(struct net_device *ndev,
+				  struct ifreq *ifr, int cmd)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+	return 0;
+}
+
+static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
+					    struct net_device *ndev)
+{
+	if (skb)
+		dev_kfree_skb_any(skb);
+
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops brcmf_netdev_ops_p2p = {
+	.ndo_open = brcmf_net_p2p_open,
+	.ndo_stop = brcmf_net_p2p_stop,
+	.ndo_do_ioctl = brcmf_net_p2p_do_ioctl,
+	.ndo_start_xmit = brcmf_net_p2p_start_xmit
+};
+
+static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
+{
+	struct net_device *ndev;
+
+	brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+		  ifp->mac_addr);
+	ndev = ifp->ndev;
+
+	ndev->netdev_ops = &brcmf_netdev_ops_p2p;
+
+	/* set the mac address */
+	memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+
+	if (register_netdev(ndev) != 0) {
+		brcmf_err("couldn't register the p2p net device\n");
+		goto fail;
+	}
+
+	brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+
+	return 0;
+
+fail:
+	return -EBADE;
+}
+
+struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+			      char *name, u8 *mac_addr)
 {
 	struct brcmf_if *ifp;
 	struct net_device *ndev;
-	int i;
 
-	brcmf_dbg(TRACE, "idx %d\n", ifidx);
+	brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
 
-	ifp = drvr->iflist[ifidx];
+	ifp = drvr->iflist[bssidx];
 	/*
 	 * Delete the existing interface before overwriting it
 	 * in case we missed the BRCMF_E_IF_DEL event.
@@ -668,7 +727,7 @@
 			netif_stop_queue(ifp->ndev);
 			unregister_netdev(ifp->ndev);
 			free_netdev(ifp->ndev);
-			drvr->iflist[ifidx] = NULL;
+			drvr->iflist[bssidx] = NULL;
 		} else {
 			brcmf_err("ignore IF event\n");
 			return ERR_PTR(-EINVAL);
@@ -685,16 +744,15 @@
 	ifp = netdev_priv(ndev);
 	ifp->ndev = ndev;
 	ifp->drvr = drvr;
-	drvr->iflist[ifidx] = ifp;
-	ifp->idx = ifidx;
+	drvr->iflist[bssidx] = ifp;
+	ifp->ifidx = ifidx;
 	ifp->bssidx = bssidx;
 
-	INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
-	INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
 
-	if (addr_mask != NULL)
-		for (i = 0; i < ETH_ALEN; i++)
-			ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
+	init_waitqueue_head(&ifp->pend_8021x_wait);
+
+	if (mac_addr != NULL)
+		memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
 
 	brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
 		  current->pid, ifp->ndev->name, ifp->mac_addr);
@@ -702,19 +760,18 @@
 	return ifp;
 }
 
-void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
+void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
 {
 	struct brcmf_if *ifp;
 
-	brcmf_dbg(TRACE, "idx %d\n", ifidx);
-
-	ifp = drvr->iflist[ifidx];
+	ifp = drvr->iflist[bssidx];
 	if (!ifp) {
-		brcmf_err("Null interface\n");
+		brcmf_err("Null interface, idx=%d\n", bssidx);
 		return;
 	}
+	brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
 	if (ifp->ndev) {
-		if (ifidx == 0) {
+		if (bssidx == 0) {
 			if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
 				rtnl_lock();
 				brcmf_netdev_stop(ifp->ndev);
@@ -724,12 +781,14 @@
 			netif_stop_queue(ifp->ndev);
 		}
 
-		cancel_work_sync(&ifp->setmacaddr_work);
-		cancel_work_sync(&ifp->multicast_work);
+		if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+			cancel_work_sync(&ifp->setmacaddr_work);
+			cancel_work_sync(&ifp->multicast_work);
+		}
 
 		unregister_netdev(ifp->ndev);
-		drvr->iflist[ifidx] = NULL;
-		if (ifidx == 0)
+		drvr->iflist[bssidx] = NULL;
+		if (bssidx == 0)
 			brcmf_cfg80211_detach(drvr->config);
 		free_netdev(ifp->ndev);
 	}
@@ -769,8 +828,6 @@
 
 	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
 
-	init_waitqueue_head(&drvr->pend_8021x_wait);
-
 	return ret;
 
 fail:
@@ -785,6 +842,7 @@
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
 	struct brcmf_if *ifp;
+	struct brcmf_if *p2p_ifp;
 
 	brcmf_dbg(TRACE, "\n");
 
@@ -800,6 +858,13 @@
 	if (IS_ERR(ifp))
 		return PTR_ERR(ifp);
 
+	if (brcmf_p2p_enable)
+		p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
+	else
+		p2p_ifp = NULL;
+	if (IS_ERR(p2p_ifp))
+		p2p_ifp = NULL;
+
 	/* signal bus ready */
 	bus_if->state = BRCMF_BUS_DATA;
 
@@ -818,16 +883,22 @@
 	if (ret < 0)
 		goto fail;
 
-	ret = brcmf_net_attach(ifp);
+	ret = brcmf_net_attach(ifp, false);
 fail:
 	if (ret < 0) {
 		brcmf_err("failed: %d\n", ret);
 		if (drvr->config)
 			brcmf_cfg80211_detach(drvr->config);
-		free_netdev(drvr->iflist[0]->ndev);
+		free_netdev(ifp->ndev);
 		drvr->iflist[0] = NULL;
+		if (p2p_ifp) {
+			free_netdev(p2p_ifp->ndev);
+			drvr->iflist[1] = NULL;
+		}
 		return ret;
 	}
+	if ((brcmf_p2p_enable) && (p2p_ifp))
+		brcmf_net_p2p_attach(p2p_ifp);
 
 	return 0;
 }
@@ -845,9 +916,21 @@
 	}
 }
 
+void brcmf_dev_reset(struct device *dev)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pub *drvr = bus_if->drvr;
+
+	if (drvr == NULL)
+		return;
+
+	if (drvr->iflist[0])
+		brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
+}
+
 void brcmf_detach(struct device *dev)
 {
-	int i;
+	s32 i;
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
 	struct brcmf_pub *drvr = bus_if->drvr;
 
@@ -866,28 +949,26 @@
 
 	brcmf_bus_detach(drvr);
 
-	if (drvr->prot) {
+	if (drvr->prot)
 		brcmf_proto_detach(drvr);
-	}
 
 	brcmf_debugfs_detach(drvr);
 	bus_if->drvr = NULL;
 	kfree(drvr);
 }
 
-static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
+static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
 {
-	return atomic_read(&drvr->pend_8021x_cnt);
+	return atomic_read(&ifp->pend_8021x_cnt);
 }
 
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcmf_pub *drvr = ifp->drvr;
 	int err;
 
-	err = wait_event_timeout(drvr->pend_8021x_wait,
-				 !brcmf_get_pend_8021x_cnt(drvr),
+	err = wait_event_timeout(ifp->pend_8021x_wait,
+				 !brcmf_get_pend_8021x_cnt(ifp),
 				 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
 
 	WARN_ON(!err);
@@ -895,6 +976,16 @@
 	return !err;
 }
 
+/*
+ * return chip id and rev of the device encoded in u32.
+ */
+u32 brcmf_get_chip_info(struct brcmf_if *ifp)
+{
+	struct brcmf_bus *bus = ifp->drvr->bus_if;
+
+	return bus->chip << 4 | bus->chiprev;
+}
+
 static void brcmf_driver_init(struct work_struct *work)
 {
 	brcmf_debugfs_init();
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index cf857f1..4469321 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -14,8 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
@@ -1098,7 +1096,6 @@
 	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
 	    type != BRCMF_SDIO_FT_SUPER) {
 		brcmf_err("HW header length too long\n");
-		bus->sdiodev->bus_if->dstats.rx_errors++;
 		bus->sdcnt.rx_toolong++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		rd->len = 0;
@@ -1169,7 +1166,6 @@
 	int errcode;
 	u8 doff, sfdoff;
 
-	int ifidx = 0;
 	bool usechain = bus->use_rxchain;
 
 	struct brcmf_sdio_read rd_new;
@@ -1301,7 +1297,6 @@
 		if (errcode < 0) {
 			brcmf_err("glom read of %d bytes failed: %d\n",
 				  dlen, errcode);
-			bus->sdiodev->bus_if->dstats.rx_errors++;
 
 			sdio_claim_host(bus->sdiodev->func[1]);
 			if (bus->glomerr++ < 3) {
@@ -1388,13 +1383,6 @@
 				skb_unlink(pfirst, &bus->glom);
 				brcmu_pkt_buf_free_skb(pfirst);
 				continue;
-			} else if (brcmf_proto_hdrpull(bus->sdiodev->dev,
-						       &ifidx, pfirst) != 0) {
-				brcmf_err("rx protocol error\n");
-				bus->sdiodev->bus_if->dstats.rx_errors++;
-				skb_unlink(pfirst, &bus->glom);
-				brcmu_pkt_buf_free_skb(pfirst);
-				continue;
 			}
 
 			brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
@@ -1407,7 +1395,7 @@
 		}
 		/* sent any remaining packets up */
 		if (bus->glom.qlen)
-			brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
+			brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);
 
 		bus->sdcnt.rxglomframes++;
 		bus->sdcnt.rxglompkts += bus->glom.qlen;
@@ -1455,10 +1443,9 @@
 
 	if (bus->rxblen)
 		buf = vzalloc(bus->rxblen);
-	if (!buf) {
-		brcmf_err("no memory for control frame\n");
+	if (!buf)
 		goto done;
-	}
+
 	rbuf = bus->rxbuf;
 	pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
 	if (pad)
@@ -1488,7 +1475,6 @@
 	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
 		brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
 			  rdlen, bus->sdiodev->bus_if->maxctl);
-		bus->sdiodev->bus_if->dstats.rx_errors++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto done;
 	}
@@ -1496,7 +1482,6 @@
 	if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
 		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
 			  len, len - doff, bus->sdiodev->bus_if->maxctl);
-		bus->sdiodev->bus_if->dstats.rx_errors++;
 		bus->sdcnt.rx_toolong++;
 		brcmf_sdbrcm_rxfail(bus, false, false);
 		goto done;
@@ -1558,10 +1543,10 @@
 static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 {
 	struct sk_buff *pkt;		/* Packet for event or data frames */
+	struct sk_buff_head pktlist;	/* needed for bus interface */
 	u16 pad;		/* Number of pad bytes to read */
 	uint rxleft = 0;	/* Remaining number of frames allowed */
 	int sdret;		/* Return code from calls */
-	int ifidx = 0;
 	uint rxcount = 0;	/* Total frames read */
 	struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
 	u8 head_read = 0;
@@ -1644,7 +1629,6 @@
 		if (!pkt) {
 			/* Give up on data, request rtx of events */
 			brcmf_err("brcmu_pkt_buf_get_skb failed\n");
-			bus->sdiodev->bus_if->dstats.rx_dropped++;
 			brcmf_sdbrcm_rxfail(bus, false,
 					    RETRYCHAN(rd->channel));
 			sdio_release_host(bus->sdiodev->func[1]);
@@ -1662,7 +1646,6 @@
 			brcmf_err("read %d bytes from channel %d failed: %d\n",
 				  rd->len, rd->channel, sdret);
 			brcmu_pkt_buf_free_skb(pkt);
-			bus->sdiodev->bus_if->dstats.rx_errors++;
 			sdio_claim_host(bus->sdiodev->func[1]);
 			brcmf_sdbrcm_rxfail(bus, true,
 					    RETRYCHAN(rd->channel));
@@ -1760,15 +1743,11 @@
 		if (pkt->len == 0) {
 			brcmu_pkt_buf_free_skb(pkt);
 			continue;
-		} else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx,
-			   pkt) != 0) {
-			brcmf_err("rx protocol error\n");
-			brcmu_pkt_buf_free_skb(pkt);
-			bus->sdiodev->bus_if->dstats.rx_errors++;
-			continue;
 		}
 
-		brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
+		skb_queue_head_init(&pktlist);
+		skb_queue_tail(&pktlist, pkt);
+		brcmf_rx_frames(bus->sdiodev->dev, &pktlist);
 	}
 
 	rxcount = maxframes - rxleft;
@@ -1954,10 +1933,6 @@
 		datalen = pkt->len - SDPCM_HDRLEN;
 
 		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
-		if (ret)
-			bus->sdiodev->bus_if->dstats.tx_errors++;
-		else
-			bus->sdiodev->bus_if->dstats.tx_bytes += datalen;
 
 		/* In poll mode, need to check for other events */
 		if (!bus->intr && cnt) {
@@ -1976,8 +1951,7 @@
 	}
 
 	/* Deflow-control stack if needed */
-	if (bus->sdiodev->bus_if->drvr_up &&
-	    (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+	if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
 	    bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
 		bus->txoff = false;
 		brcmf_txflowblock(bus->sdiodev->dev, false);
@@ -2724,9 +2698,10 @@
 	 * address of sdpcm_shared structure
 	 */
 	sdio_claim_host(bus->sdiodev->func[1]);
+	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
 	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
 				   (u8 *)&addr_le, 4);
-	sdio_claim_host(bus->sdiodev->func[1]);
+	sdio_release_host(bus->sdiodev->func[1]);
 	if (rv < 0)
 		return rv;
 
@@ -2745,10 +2720,8 @@
 	}
 
 	/* Read hndrte_shared structure */
-	sdio_claim_host(bus->sdiodev->func[1]);
 	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
 				   sizeof(struct sdpcm_shared_le));
-	sdio_release_host(bus->sdiodev->func[1]);
 	if (rv < 0)
 		return rv;
 
@@ -2850,14 +2823,12 @@
 	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
 		return 0;
 
-	sdio_claim_host(bus->sdiodev->func[1]);
 	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
 				      sizeof(struct brcmf_trap_info));
 	if (error < 0)
 		return error;
 
 	nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
-	sdio_release_host(bus->sdiodev->func[1]);
 	if (nbytes < 0)
 		return nbytes;
 
@@ -3322,9 +3293,6 @@
 {
 	int ret;
 
-	if (bus->sdiodev->bus_if->drvr_up)
-		return -EISCONN;
-
 	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
 			       &bus->sdiodev->func[2]->dev);
 	if (ret) {
@@ -3955,6 +3923,8 @@
 	/* Assign bus interface call back */
 	bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
 	bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
+	bus->sdiodev->bus_if->chip = bus->ci->chip;
+	bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
 
 	/* Attach to the brcmf/OS/network interface */
 	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index ba0b225..e9d6f91 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -189,24 +189,24 @@
 		return;
 	}
 
-	ifp = drvr->iflist[ifevent->ifidx];
+	ifp = drvr->iflist[ifevent->bssidx];
 
 	if (ifevent->action == BRCMF_E_IF_ADD) {
 		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
 			  emsg->addr);
-		ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx,
+		ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
 				   emsg->ifname, emsg->addr);
 		if (IS_ERR(ifp))
 			return;
 
 		if (!drvr->fweh.evt_handler[BRCMF_E_IF])
-			err = brcmf_net_attach(ifp);
+			err = brcmf_net_attach(ifp, false);
 	}
 
 	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
 
 	if (ifevent->action == BRCMF_E_IF_DEL)
-		brcmf_del_if(drvr, ifevent->ifidx);
+		brcmf_del_if(drvr, ifevent->bssidx);
 }
 
 /**
@@ -250,8 +250,6 @@
 	drvr = container_of(fweh, struct brcmf_pub, fweh);
 
 	while ((event = brcmf_fweh_dequeue_event(fweh))) {
-		ifp = drvr->iflist[event->ifidx];
-
 		brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
 			  brcmf_fweh_event_name(event->code), event->code,
 			  event->emsg.ifidx, event->emsg.bsscfgidx,
@@ -283,6 +281,7 @@
 			goto event_free;
 		}
 
+		ifp = drvr->iflist[emsg.bsscfgidx];
 		err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
 						    event->data);
 		if (err) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
index 36901f7..8c39b51 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -83,6 +83,7 @@
 	BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
 	BRCMF_ENUM_DEF(TRACE, 52) \
 	BRCMF_ENUM_DEF(IF, 54) \
+	BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
 	BRCMF_ENUM_DEF(RSSI, 56) \
 	BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
 	BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
@@ -96,8 +97,11 @@
 	BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
 	BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
 	BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
+	BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \
+	BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
 	BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
-	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74)
+	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
+	BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)
 
 #define BRCMF_ENUM_DEF(id, val) \
 	BRCMF_E_##id = (val),
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index d8d8b65..8d1def9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -45,9 +45,10 @@
 	if (data != NULL)
 		len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
 	if (set)
-		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len);
+		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
+					       len);
 	else
-		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data,
+		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
 						 len);
 
 	if (err >= 0)
@@ -100,6 +101,7 @@
 	__le32 data_le = cpu_to_le32(data);
 
 	mutex_lock(&ifp->drvr->proto_block);
+	brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
 	mutex_unlock(&ifp->drvr->proto_block);
 
@@ -116,6 +118,7 @@
 	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
 	mutex_unlock(&ifp->drvr->proto_block);
 	*data = le32_to_cpu(data_le);
+	brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
 
 	return err;
 }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
new file mode 100644
index 0000000..0f2c83b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef FWIL_TYPES_H_
+#define FWIL_TYPES_H_
+
+#include <linux/if_ether.h>
+
+
+#define BRCMF_FIL_ACTION_FRAME_SIZE	1800
+
+
+enum brcmf_fil_p2p_if_types {
+	BRCMF_FIL_P2P_IF_CLIENT,
+	BRCMF_FIL_P2P_IF_GO,
+	BRCMF_FIL_P2P_IF_DYNBCN_GO,
+	BRCMF_FIL_P2P_IF_DEV,
+};
+
+struct brcmf_fil_p2p_if_le {
+	u8 addr[ETH_ALEN];
+	__le16 type;
+	__le16 chspec;
+};
+
+struct brcmf_fil_chan_info_le {
+	__le32 hw_channel;
+	__le32 target_channel;
+	__le32 scan_channel;
+};
+
+struct brcmf_fil_action_frame_le {
+	u8	da[ETH_ALEN];
+	__le16	len;
+	__le32	packet_id;
+	u8	data[BRCMF_FIL_ACTION_FRAME_SIZE];
+};
+
+struct brcmf_fil_af_params_le {
+	__le32					channel;
+	__le32					dwell_time;
+	u8					bssid[ETH_ALEN];
+	u8					pad[2];
+	struct brcmf_fil_action_frame_le	action_frame;
+};
+
+struct brcmf_fil_bss_enable_le {
+	__le32 bsscfg_idx;
+	__le32 enable;
+};
+
+#endif /* FWIL_TYPES_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
new file mode 100644
index 0000000..4166e64
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -0,0 +1,2277 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <defs.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include "fwil.h"
+#include "fwil_types.h"
+#include "p2p.h"
+#include "wl_cfg80211.h"
+
+/* parameters used for p2p escan */
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 80
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_HOME_TIME_MS 60
+#define P2PAPI_SCAN_NPROBS_TIME_MS 30
+#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
+#define WL_SCAN_CONNECT_DWELL_TIME_MS 200
+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
+
+#define BRCMF_P2P_WILDCARD_SSID		"DIRECT-"
+#define BRCMF_P2P_WILDCARD_SSID_LEN	(sizeof(BRCMF_P2P_WILDCARD_SSID) - 1)
+
+#define SOCIAL_CHAN_1		1
+#define SOCIAL_CHAN_2		6
+#define SOCIAL_CHAN_3		11
+#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
+					 (channel == SOCIAL_CHAN_2) || \
+					 (channel == SOCIAL_CHAN_3))
+#define SOCIAL_CHAN_CNT		3
+#define AF_PEER_SEARCH_CNT	2
+
+#define BRCMF_SCB_TIMEOUT_VALUE	20
+
+#define P2P_VER			9	/* P2P version: 9=WiFi P2P v1.0 */
+#define P2P_PUB_AF_CATEGORY	0x04
+#define P2P_PUB_AF_ACTION	0x09
+#define P2P_AF_CATEGORY		0x7f
+#define P2P_OUI			"\x50\x6F\x9A"	/* P2P OUI */
+#define P2P_OUI_LEN		3		/* P2P OUI length */
+
+/* Action Frame Constants */
+#define DOT11_ACTION_HDR_LEN	2	/* action frame category + action */
+#define DOT11_ACTION_CAT_OFF	0	/* category offset */
+#define DOT11_ACTION_ACT_OFF	1	/* action offset */
+
+#define P2P_AF_DWELL_TIME		200
+#define P2P_AF_MIN_DWELL_TIME		100
+#define P2P_AF_MED_DWELL_TIME		400
+#define P2P_AF_LONG_DWELL_TIME		1000
+#define P2P_AF_TX_MAX_RETRY		1
+#define P2P_AF_MAX_WAIT_TIME		2000
+#define P2P_INVALID_CHANNEL		-1
+#define P2P_CHANNEL_SYNC_RETRY		5
+#define P2P_AF_FRM_SCAN_MAX_WAIT	1500
+#define P2P_DEFAULT_SLEEP_TIME_VSDB	200
+
+/* WiFi P2P Public Action Frame OUI Subtypes */
+#define P2P_PAF_GON_REQ		0	/* Group Owner Negotiation Req */
+#define P2P_PAF_GON_RSP		1	/* Group Owner Negotiation Rsp */
+#define P2P_PAF_GON_CONF	2	/* Group Owner Negotiation Confirm */
+#define P2P_PAF_INVITE_REQ	3	/* P2P Invitation Request */
+#define P2P_PAF_INVITE_RSP	4	/* P2P Invitation Response */
+#define P2P_PAF_DEVDIS_REQ	5	/* Device Discoverability Request */
+#define P2P_PAF_DEVDIS_RSP	6	/* Device Discoverability Response */
+#define P2P_PAF_PROVDIS_REQ	7	/* Provision Discovery Request */
+#define P2P_PAF_PROVDIS_RSP	8	/* Provision Discovery Response */
+#define P2P_PAF_SUBTYPE_INVALID	255	/* Invalid Subtype */
+
+/* WiFi P2P Action Frame OUI Subtypes */
+#define P2P_AF_NOTICE_OF_ABSENCE	0	/* Notice of Absence */
+#define P2P_AF_PRESENCE_REQ		1	/* P2P Presence Request */
+#define P2P_AF_PRESENCE_RSP		2	/* P2P Presence Response */
+#define P2P_AF_GO_DISC_REQ		3	/* GO Discoverability Request */
+
+/* P2P Service Discovery related */
+#define P2PSD_ACTION_CATEGORY		0x04	/* Public action frame */
+#define P2PSD_ACTION_ID_GAS_IREQ	0x0a	/* GAS Initial Request AF */
+#define P2PSD_ACTION_ID_GAS_IRESP	0x0b	/* GAS Initial Response AF */
+#define P2PSD_ACTION_ID_GAS_CREQ	0x0c	/* GAS Comback Request AF */
+#define P2PSD_ACTION_ID_GAS_CRESP	0x0d	/* GAS Comback Response AF */
+
+/**
+ * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
+ *
+ * @state: requested discovery state (see enum brcmf_p2p_disc_state).
+ * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state.
+ * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.
+ */
+struct brcmf_p2p_disc_st_le {
+	u8 state;
+	__le16 chspec;
+	__le16 dwell;
+};
+
+/**
+ * enum brcmf_p2p_disc_state - P2P discovery state values
+ *
+ * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE.
+ * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time.
+ * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.
+ */
+enum brcmf_p2p_disc_state {
+	WL_P2P_DISC_ST_SCAN,
+	WL_P2P_DISC_ST_LISTEN,
+	WL_P2P_DISC_ST_SEARCH
+};
+
+/**
+ * struct brcmf_p2p_scan_le - P2P specific scan request.
+ *
+ * @type: type of scan method requested (values: 'E' or 'S').
+ * @reserved: reserved (ignored).
+ * @eparams: parameters used for type 'E'.
+ * @sparams: parameters used for type 'S'.
+ */
+struct brcmf_p2p_scan_le {
+	u8 type;
+	u8 reserved[3];
+	union {
+		struct brcmf_escan_params_le eparams;
+		struct brcmf_scan_params_le sparams;
+	};
+};
+
+/**
+ * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame
+ *
+ * @category: P2P_PUB_AF_CATEGORY
+ * @action: P2P_PUB_AF_ACTION
+ * @oui[3]: P2P_OUI
+ * @oui_type: OUI type - P2P_VER
+ * @subtype: OUI subtype - P2P_TYPE_*
+ * @dialog_token: nonzero, identifies req/rsp transaction
+ * @elts[1]: Variable length information elements.
+ */
+struct brcmf_p2p_pub_act_frame {
+	u8	category;
+	u8	action;
+	u8	oui[3];
+	u8	oui_type;
+	u8	subtype;
+	u8	dialog_token;
+	u8	elts[1];
+};
+
+/**
+ * struct brcmf_p2p_action_frame - WiFi P2P Action Frame
+ *
+ * @category: P2P_AF_CATEGORY
+ * @OUI[3]: OUI - P2P_OUI
+ * @type: OUI Type - P2P_VER
+ * @subtype: OUI Subtype - P2P_AF_*
+ * @dialog_token: nonzero, identifies req/resp tranaction
+ * @elts[1]: Variable length information elements.
+ */
+struct brcmf_p2p_action_frame {
+	u8	category;
+	u8	oui[3];
+	u8	type;
+	u8	subtype;
+	u8	dialog_token;
+	u8	elts[1];
+};
+
+/**
+ * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame
+ *
+ * @category: 0x04 Public Action Frame
+ * @action: 0x6c Advertisement Protocol
+ * @dialog_token: nonzero, identifies req/rsp transaction
+ * @query_data[1]: Query Data. SD gas ireq SD gas iresp
+ */
+struct brcmf_p2psd_gas_pub_act_frame {
+	u8	category;
+	u8	action;
+	u8	dialog_token;
+	u8	query_data[1];
+};
+
+/**
+ * struct brcmf_config_af_params - Action Frame Parameters for tx.
+ *
+ * @mpc_onoff: To make sure to send successfully action frame, we have to
+ *             turn off mpc  0: off, 1: on,  (-1): do nothing
+ * @search_channel: 1: search peer's channel to send af
+ * extra_listen: keep the dwell time to get af response frame.
+ */
+struct brcmf_config_af_params {
+	s32 mpc_onoff;
+	bool search_channel;
+	bool extra_listen;
+};
+
+/**
+ * brcmf_p2p_is_pub_action() - true if p2p public type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p public action type
+ */
+static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
+{
+	struct brcmf_p2p_pub_act_frame *pact_frm;
+
+	if (frame == NULL)
+		return false;
+
+	pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+	if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
+		return false;
+
+	if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+	    pact_frm->action == P2P_PUB_AF_ACTION &&
+	    pact_frm->oui_type == P2P_VER &&
+	    memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
+		return true;
+
+	return false;
+}
+
+/**
+ * brcmf_p2p_is_p2p_action() - true if p2p action type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p action type
+ */
+static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
+{
+	struct brcmf_p2p_action_frame *act_frm;
+
+	if (frame == NULL)
+		return false;
+
+	act_frm = (struct brcmf_p2p_action_frame *)frame;
+	if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1)
+		return false;
+
+	if (act_frm->category == P2P_AF_CATEGORY &&
+	    act_frm->type  == P2P_VER &&
+	    memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
+		return true;
+
+	return false;
+}
+
+/**
+ * brcmf_p2p_is_gas_action() - true if p2p gas action type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p gas action type
+ */
+static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)
+{
+	struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+
+	if (frame == NULL)
+		return false;
+
+	sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+	if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1)
+		return false;
+
+	if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+		return false;
+
+	if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+	    sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+	    sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+	    sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+		return true;
+
+	return false;
+}
+
+/**
+ * brcmf_p2p_print_actframe() - debug print routine.
+ *
+ * @tx: Received or to be transmitted
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Print information about the p2p action frame
+ */
+
+#ifdef DEBUG
+
+static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+	struct brcmf_p2p_pub_act_frame *pact_frm;
+	struct brcmf_p2p_action_frame *act_frm;
+	struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+
+	if (!frame || frame_len <= 2)
+		return;
+
+	if (brcmf_p2p_is_pub_action(frame, frame_len)) {
+		pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+		switch (pact_frm->subtype) {
+		case P2P_PAF_GON_REQ:
+			brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_GON_RSP:
+			brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_GON_CONF:
+			brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_INVITE_REQ:
+			brcmf_dbg(TRACE, "%s P2P Invitation Request  Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_INVITE_RSP:
+			brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_DEVDIS_REQ:
+			brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_DEVDIS_RSP:
+			brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_PROVDIS_REQ:
+			brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_PAF_PROVDIS_RSP:
+			brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		default:
+			brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		}
+	} else if (brcmf_p2p_is_p2p_action(frame, frame_len)) {
+		act_frm = (struct brcmf_p2p_action_frame *)frame;
+		switch (act_frm->subtype) {
+		case P2P_AF_NOTICE_OF_ABSENCE:
+			brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_AF_PRESENCE_REQ:
+			brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_AF_PRESENCE_RSP:
+			brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2P_AF_GO_DISC_REQ:
+			brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		default:
+			brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n",
+				  (tx) ? "TX" : "RX");
+		}
+
+	} else if (brcmf_p2p_is_gas_action(frame, frame_len)) {
+		sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+		switch (sd_act_frm->action) {
+		case P2PSD_ACTION_ID_GAS_IREQ:
+			brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2PSD_ACTION_ID_GAS_IRESP:
+			brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2PSD_ACTION_ID_GAS_CREQ:
+			brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		case P2PSD_ACTION_ID_GAS_CRESP:
+			brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		default:
+			brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n",
+				  (tx) ? "TX" : "RX");
+			break;
+		}
+	}
+}
+
+#else
+
+static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+}
+
+#endif
+
+
+/**
+ * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec.
+ *
+ * @channel: channel number
+ */
+static u16 brcmf_p2p_chnr_to_chspec(u16 channel)
+{
+	u16 chanspec;
+
+	chanspec = channel & WL_CHANSPEC_CHAN_MASK;
+
+	if (channel <= CH_MAX_2G_CHANNEL)
+		chanspec |= WL_CHANSPEC_BAND_2G;
+	else
+		chanspec |= WL_CHANSPEC_BAND_5G;
+
+	chanspec |= WL_CHANSPEC_BW_20;
+	chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+	return chanspec;
+}
+
+
+/**
+ * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
+ *
+ * @ifp: ifp to use for iovars (primary).
+ * @p2p_mac: mac address to configure for p2p_da_override
+ */
+static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
+{
+	s32 ret = 0;
+
+	brcmf_fil_iovar_int_set(ifp, "apsta", 1);
+
+	/* In case of COB type, firmware has default mac address
+	 * After Initializing firmware, we have to set current mac address to
+	 * firmware for P2P device address
+	 */
+	ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,
+				       ETH_ALEN);
+	if (ret)
+		brcmf_err("failed to update device address ret %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
+ *
+ * @p2p: P2P specific data.
+ *
+ * P2P needs mac addresses for P2P device and interface. These are
+ * derived from the primary net device, ie. the permanent ethernet
+ * address of the device.
+ */
+static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+	struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+
+	/* Generate the P2P Device Address.  This consists of the device's
+	 * primary MAC address with the locally administered bit set.
+	 */
+	memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN);
+	p2p->dev_addr[0] |= 0x02;
+	memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+
+	/* Generate the P2P Interface Address.  If the discovery and connection
+	 * BSSCFGs need to simultaneously co-exist, then this address must be
+	 * different from the P2P Device Address, but also locally administered.
+	 */
+	memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
+	p2p->int_addr[4] ^= 0x80;
+}
+
+/**
+ * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan.
+ *
+ * @request: the scan request as received from cfg80211.
+ *
+ * returns true if one of the ssids in the request matches the
+ * P2P wildcard ssid; otherwise returns false.
+ */
+static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)
+{
+	struct cfg80211_ssid *ssids = request->ssids;
+	int i;
+
+	for (i = 0; i < request->n_ssids; i++) {
+		if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN)
+			continue;
+
+		brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid);
+		if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid,
+			    BRCMF_P2P_WILDCARD_SSID_LEN))
+			return true;
+	}
+	return false;
+}
+
+/**
+ * brcmf_p2p_set_discover_state - set discover state in firmware.
+ *
+ * @ifp: low-level interface object.
+ * @state: discover state to set.
+ * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only).
+ * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only).
+ */
+static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state,
+					u16 chanspec, u16 listen_ms)
+{
+	struct brcmf_p2p_disc_st_le discover_state;
+	s32 ret = 0;
+	brcmf_dbg(TRACE, "enter\n");
+
+	discover_state.state = state;
+	discover_state.chspec = cpu_to_le16(chanspec);
+	discover_state.dwell = cpu_to_le16(listen_ms);
+	ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state,
+					sizeof(discover_state));
+	return ret;
+}
+
+/**
+ * brcmf_p2p_deinit_discovery() - disable P2P device discovery.
+ *
+ * @p2p: P2P specific data.
+ *
+ * Resets the discovery state and disables it in firmware.
+ */
+static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_cfg80211_vif *vif;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	/* Set the discovery state to SCAN */
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	(void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+
+	/* Disable P2P discovery in the firmware */
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+	(void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0);
+
+	return 0;
+}
+
+/**
+ * brcmf_p2p_enable_discovery() - initialize and configure discovery.
+ *
+ * @p2p: P2P specific data.
+ *
+ * Initializes the discovery device and configure the virtual interface.
+ */
+static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_cfg80211_vif *vif;
+	s32 ret = 0;
+
+	brcmf_dbg(TRACE, "enter\n");
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (!vif) {
+		brcmf_err("P2P config device not available\n");
+		ret = -EPERM;
+		goto exit;
+	}
+
+	if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) {
+		brcmf_dbg(INFO, "P2P config device already configured\n");
+		goto exit;
+	}
+
+	/* Re-initialize P2P Discovery in the firmware */
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+	ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1);
+	if (ret < 0) {
+		brcmf_err("set p2p_disc error\n");
+		goto exit;
+	}
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+	if (ret < 0) {
+		brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n");
+		goto exit;
+	}
+
+	/*
+	 * Set wsec to any non-zero value in the discovery bsscfg
+	 * to ensure our P2P probe responses have the privacy bit
+	 * set in the 802.11 WPA IE. Some peer devices may not
+	 * initiate WPS with us if this bit is not set.
+	 */
+	ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED);
+	if (ret < 0) {
+		brcmf_err("wsec error %d\n", ret);
+		goto exit;
+	}
+
+	set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status);
+exit:
+	return ret;
+}
+
+/**
+ * brcmf_p2p_escan() - initiate a P2P scan.
+ *
+ * @p2p: P2P specific data.
+ * @num_chans: number of channels to scan.
+ * @chanspecs: channel parameters for @num_chans channels.
+ * @search_state: P2P discover state to use.
+ * @action: scan action to pass to firmware.
+ * @bss_type: type of P2P bss.
+ */
+static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
+			   u16 chanspecs[], s32 search_state, u16 action,
+			   enum p2p_bss_type bss_type)
+{
+	s32 ret = 0;
+	s32 memsize = offsetof(struct brcmf_p2p_scan_le,
+			       eparams.params_le.channel_list);
+	s32 nprobes;
+	s32 active;
+	u32 i;
+	u8 *memblk;
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_p2p_scan_le *p2p_params;
+	struct brcmf_scan_params_le *sparams;
+	struct brcmf_ssid ssid;
+
+	memsize += num_chans * sizeof(__le16);
+	memblk = kzalloc(memsize, GFP_KERNEL);
+	if (!memblk)
+		return -ENOMEM;
+
+	vif = p2p->bss_idx[bss_type].vif;
+	if (vif == NULL) {
+		brcmf_err("no vif for bss type %d\n", bss_type);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	switch (search_state) {
+	case WL_P2P_DISC_ST_SEARCH:
+		/*
+		 * If we in SEARCH STATE, we don't need to set SSID explictly
+		 * because dongle use P2P WILDCARD internally by default
+		 */
+		/* use null ssid */
+		ssid.SSID_len = 0;
+		memset(ssid.SSID, 0, sizeof(ssid.SSID));
+		break;
+	case WL_P2P_DISC_ST_SCAN:
+		/*
+		 * wpa_supplicant has p2p_find command with type social or
+		 * progressive. For progressive, we need to set the ssid to
+		 * P2P WILDCARD because we just do broadcast scan unless
+		 * setting SSID.
+		 */
+		ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN;
+		memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len);
+		break;
+	default:
+		brcmf_err(" invalid search state %d\n", search_state);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0);
+
+	/*
+	 * set p2p scan parameters.
+	 */
+	p2p_params = (struct brcmf_p2p_scan_le *)memblk;
+	p2p_params->type = 'E';
+
+	/* determine the scan engine parameters */
+	sparams = &p2p_params->eparams.params_le;
+	sparams->bss_type = DOT11_BSSTYPE_ANY;
+	if (p2p->cfg->active_scan)
+		sparams->scan_type = 0;
+	else
+		sparams->scan_type = 1;
+
+	memset(&sparams->bssid, 0xFF, ETH_ALEN);
+	if (ssid.SSID_len)
+		memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len);
+	sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
+	sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);
+
+	/*
+	 * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan
+	 * supported by the supplicant.
+	 */
+	if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))
+		active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
+	else if (num_chans == AF_PEER_SEARCH_CNT)
+		active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;
+	else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
+		active = -1;
+	else
+		active = P2PAPI_SCAN_DWELL_TIME_MS;
+
+	/* Override scan params to find a peer for a connection */
+	if (num_chans == 1) {
+		active = WL_SCAN_CONNECT_DWELL_TIME_MS;
+		/* WAR to sync with presence period of VSDB GO.
+		 * send probe request more frequently
+		 */
+		nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
+	} else {
+		nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
+	}
+
+	if (nprobes <= 0)
+		nprobes = 1;
+
+	brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active);
+	sparams->active_time = cpu_to_le32(active);
+	sparams->nprobes = cpu_to_le32(nprobes);
+	sparams->passive_time = cpu_to_le32(-1);
+	sparams->channel_num = cpu_to_le32(num_chans &
+					   BRCMF_SCAN_PARAMS_COUNT_MASK);
+	for (i = 0; i < num_chans; i++)
+		sparams->channel_list[i] = cpu_to_le16(chanspecs[i]);
+
+	/* set the escan specific parameters */
+	p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+	p2p_params->eparams.action =  cpu_to_le16(action);
+	p2p_params->eparams.sync_id = cpu_to_le16(0x1234);
+	/* perform p2p scan on primary device */
+	ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize);
+	if (!ret)
+		set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status);
+exit:
+	kfree(memblk);
+	return ret;
+}
+
+/**
+ * brcmf_p2p_run_escan() - escan callback for peer-to-peer.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @ndev: net device for which scan is requested.
+ * @request: scan request from cfg80211.
+ * @action: scan action.
+ *
+ * Determines the P2P discovery state based to scan request parameters and
+ * validates the channels in the request.
+ */
+static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
+			       struct net_device *ndev,
+			       struct cfg80211_scan_request *request,
+			       u16 action)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	s32 err = 0;
+	s32 search_state = WL_P2P_DISC_ST_SCAN;
+	struct brcmf_cfg80211_vif *vif;
+	struct net_device *dev = NULL;
+	int i, num_nodfs = 0;
+	u16 *chanspecs;
+
+	brcmf_dbg(TRACE, "enter\n");
+
+	if (!request) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	if (request->n_channels) {
+		chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs),
+				    GFP_KERNEL);
+		if (!chanspecs) {
+			err = -ENOMEM;
+			goto exit;
+		}
+		vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+		if (vif)
+			dev = vif->wdev.netdev;
+		if (request->n_channels == 3 &&
+		    request->channels[0]->hw_value == SOCIAL_CHAN_1 &&
+		    request->channels[1]->hw_value == SOCIAL_CHAN_2 &&
+		    request->channels[2]->hw_value == SOCIAL_CHAN_3) {
+			/* SOCIAL CHANNELS 1, 6, 11 */
+			search_state = WL_P2P_DISC_ST_SEARCH;
+			brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");
+		} else if (dev != NULL && vif->mode == WL_MODE_AP) {
+			/* If you are already a GO, then do SEARCH only */
+			brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");
+			search_state = WL_P2P_DISC_ST_SEARCH;
+		} else {
+			brcmf_dbg(INFO, "P2P SCAN STATE START\n");
+		}
+
+		/*
+		 * no P2P scanning on passive or DFS channels.
+		 */
+		for (i = 0; i < request->n_channels; i++) {
+			struct ieee80211_channel *chan = request->channels[i];
+
+			if (chan->flags & (IEEE80211_CHAN_RADAR |
+					   IEEE80211_CHAN_PASSIVE_SCAN))
+				continue;
+
+			chanspecs[i] = channel_to_chanspec(chan);
+			brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",
+				  num_nodfs, chan->hw_value, chanspecs[i]);
+			num_nodfs++;
+		}
+		err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,
+				      action, P2PAPI_BSSCFG_DEVICE);
+	}
+exit:
+	if (err)
+		brcmf_err("error (%d)\n", err);
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_find_listen_channel() - find listen channel in ie string.
+ *
+ * @ie: string of information elements.
+ * @ie_len: length of string.
+ *
+ * Scan ie for p2p ie and look for attribute 6 channel. If available determine
+ * channel and return it.
+ */
+static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len)
+{
+	u8 channel_ie[5];
+	s32 listen_channel;
+	s32 err;
+
+	err = cfg80211_get_p2p_attr(ie, ie_len,
+				    IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
+				    channel_ie, sizeof(channel_ie));
+	if (err < 0)
+		return err;
+
+	/* listen channel subel length format:     */
+	/* 3(country) + 1(op. class) + 1(chan num) */
+	listen_channel = (s32)channel_ie[3 + 1];
+
+	if (listen_channel == SOCIAL_CHAN_1 ||
+	    listen_channel == SOCIAL_CHAN_2 ||
+	    listen_channel == SOCIAL_CHAN_3) {
+		brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel);
+		return listen_channel;
+	}
+
+	return -EPERM;
+}
+
+
+/**
+ * brcmf_p2p_scan_prep() - prepare scan based on request.
+ *
+ * @wiphy: wiphy device.
+ * @request: scan request from cfg80211.
+ * @vif: vif on which scan request is to be executed.
+ *
+ * Prepare the scan appropriately for type of scan requested. Overrides the
+ * escan .run() callback for peer-to-peer scanning.
+ */
+int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+			struct cfg80211_scan_request *request,
+			struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	int err = 0;
+
+	if (brcmf_p2p_scan_is_p2p_request(request)) {
+		/* find my listen channel */
+		err = brcmf_p2p_find_listen_channel(request->ie,
+						    request->ie_len);
+		if (err < 0)
+			return err;
+
+		p2p->afx_hdl.my_listen_chan = err;
+
+		clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
+
+		err = brcmf_p2p_enable_discovery(p2p);
+		if (err)
+			return err;
+
+		vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+
+		/* override .run_escan() callback. */
+		cfg->escan_info.run = brcmf_p2p_run_escan;
+	}
+	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
+				    request->ie, request->ie_len);
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_discover_listen() - set firmware to discover listen state.
+ *
+ * @p2p: p2p device.
+ * @channel: channel nr for discover listen.
+ * @duration: time in ms to stay on channel.
+ *
+ */
+static s32
+brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
+{
+	struct brcmf_cfg80211_vif *vif;
+	s32 err = 0;
+	u16 chanspec;
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (!vif) {
+		brcmf_err("Discovery is not set, so we have nothing to do\n");
+		err = -EPERM;
+		goto exit;
+	}
+
+	if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) {
+		brcmf_err("Previous LISTEN is not completed yet\n");
+		/* WAR: prevent cookie mismatch in wpa_supplicant return OK */
+		goto exit;
+	}
+
+	chanspec = brcmf_p2p_chnr_to_chspec(channel);
+	err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
+					   chanspec, (u16)duration);
+	if (!err) {
+		set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);
+		p2p->remain_on_channel_cookie++;
+	}
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_remain_on_channel() - put device on channel and stay there.
+ *
+ * @wiphy: wiphy device.
+ * @channel: channel to stay on.
+ * @duration: time in ms to remain on channel.
+ *
+ */
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+				struct ieee80211_channel *channel,
+				unsigned int duration, u64 *cookie)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	s32 err;
+	u16 channel_nr;
+
+	channel_nr = ieee80211_frequency_to_channel(channel->center_freq);
+	brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr,
+		  duration);
+
+	err = brcmf_p2p_enable_discovery(p2p);
+	if (err)
+		goto exit;
+	err = brcmf_p2p_discover_listen(p2p, channel_nr, duration);
+	if (err)
+		goto exit;
+
+	memcpy(&p2p->remain_on_channel, channel, sizeof(*channel));
+	*cookie = p2p->remain_on_channel_cookie;
+	cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
+
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_notify_listen_complete() - p2p listen has completed.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message. Not used.
+ *
+ */
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+	brcmf_dbg(TRACE, "Enter\n");
+	if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN,
+			       &p2p->status)) {
+		if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+				       &p2p->status)) {
+			clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+				  &p2p->status);
+			brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n");
+			complete(&p2p->wait_next_af);
+		}
+
+		cfg80211_remain_on_channel_expired(&ifp->vif->wdev,
+						   p2p->remain_on_channel_cookie,
+						   &p2p->remain_on_channel,
+						   GFP_KERNEL);
+	}
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
+ *
+ * @ifp: interfac control.
+ *
+ */
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
+{
+	if (!ifp)
+		return;
+	brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+	brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
+}
+
+
+/**
+ * brcmf_p2p_act_frm_search() - search function for action frame.
+ *
+ * @p2p: p2p device.
+ * channel: channel on which action frame is to be trasmitted.
+ *
+ * search function to reach at common channel to send action frame. When
+ * channel is 0 then all social channels will be used to send af
+ */
+static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)
+{
+	s32 err;
+	u32 channel_cnt;
+	u16 *default_chan_list;
+	u32 i;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	if (channel)
+		channel_cnt = AF_PEER_SEARCH_CNT;
+	else
+		channel_cnt = SOCIAL_CHAN_CNT;
+	default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list),
+				    GFP_KERNEL);
+	if (default_chan_list == NULL) {
+		brcmf_err("channel list allocation failed\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+	if (channel) {
+		/* insert same channel to the chan_list */
+		for (i = 0; i < channel_cnt; i++)
+			default_chan_list[i] =
+					brcmf_p2p_chnr_to_chspec(channel);
+	} else {
+		default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1);
+		default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2);
+		default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3);
+	}
+	err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,
+			      WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START,
+			      P2PAPI_BSSCFG_DEVICE);
+	kfree(default_chan_list);
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_afx_handler() - afx worker thread.
+ *
+ * @work:
+ *
+ */
+static void brcmf_p2p_afx_handler(struct work_struct *work)
+{
+	struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work);
+	struct brcmf_p2p_info *p2p = container_of(afx_hdl,
+						  struct brcmf_p2p_info,
+						  afx_hdl);
+	s32 err;
+
+	if (!afx_hdl->is_active)
+		return;
+
+	if (afx_hdl->is_listen && afx_hdl->my_listen_chan)
+		/* 100ms ~ 300ms */
+		err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,
+						100 * (1 + (random32() % 3)));
+	else
+		err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);
+
+	if (err) {
+		brcmf_err("ERROR occurred! value is (%d)\n", err);
+		if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+			     &p2p->status))
+			complete(&afx_hdl->act_frm_scan);
+	}
+}
+
+
+/**
+ * brcmf_p2p_af_searching_channel() - search channel.
+ *
+ * @p2p: p2p device info struct.
+ *
+ */
+static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
+{
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	struct brcmf_cfg80211_vif *pri_vif;
+	unsigned long duration;
+	s32 retry;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+
+	INIT_COMPLETION(afx_hdl->act_frm_scan);
+	set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
+	afx_hdl->is_active = true;
+	afx_hdl->peer_chan = P2P_INVALID_CHANNEL;
+
+	/* Loop to wait until we find a peer's channel or the
+	 * pending action frame tx is cancelled.
+	 */
+	retry = 0;
+	duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT);
+	while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
+	       (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
+		afx_hdl->is_listen = false;
+		brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n",
+			  retry);
+		/* search peer on peer's listen channel */
+		schedule_work(&afx_hdl->afx_work);
+		wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration);
+		if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
+		    (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+			       &p2p->status)))
+			break;
+
+		if (afx_hdl->my_listen_chan) {
+			brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n",
+				  afx_hdl->my_listen_chan);
+			/* listen on my listen channel */
+			afx_hdl->is_listen = true;
+			schedule_work(&afx_hdl->afx_work);
+			wait_for_completion_timeout(&afx_hdl->act_frm_scan,
+						    duration);
+		}
+		if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
+		    (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+			       &p2p->status)))
+			break;
+		retry++;
+
+		/* if sta is connected or connecting, sleep for a while before
+		 * retry af tx or finding a peer
+		 */
+		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) ||
+		    test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state))
+			msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);
+	}
+
+	brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n",
+		  afx_hdl->peer_chan);
+	afx_hdl->is_active = false;
+
+	clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
+
+	return afx_hdl->peer_chan;
+}
+
+
+/**
+ * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel
+ *
+ * @cfg: common configuration struct.
+ * @bi: bss info struct, result from scan.
+ *
+ */
+bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
+					   struct brcmf_bss_info_le *bi)
+
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	u8 *ie;
+	s32 err;
+	u8 p2p_dev_addr[ETH_ALEN];
+
+	if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status))
+		return false;
+
+	if (bi == NULL) {
+		brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n");
+		if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)
+			complete(&afx_hdl->act_frm_scan);
+		return true;
+	}
+
+	ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
+	memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr));
+	err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
+				    IEEE80211_P2P_ATTR_DEVICE_INFO,
+				    p2p_dev_addr, sizeof(p2p_dev_addr));
+	if (err < 0)
+		err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
+					    IEEE80211_P2P_ATTR_DEVICE_ID,
+					    p2p_dev_addr, sizeof(p2p_dev_addr));
+	if ((err >= 0) &&
+	    (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) {
+		afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch :
+				      CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+		brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n",
+			  afx_hdl->tx_dst_addr, afx_hdl->peer_chan);
+		complete(&afx_hdl->act_frm_scan);
+	}
+	return true;
+}
+
+/**
+ * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete.
+ *
+ * @cfg: common configuration struct.
+ *
+ */
+static void
+brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct net_device *ndev = cfg->escan_info.ndev;
+
+	if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
+	    (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
+	     test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) {
+		brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n");
+		/* if channel is not zero, "actfame" uses off channel scan.
+		 * So abort scan for off channel completion.
+		 */
+		if (p2p->af_sent_channel)
+			brcmf_notify_escan_complete(cfg, ndev, true, true);
+	} else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+			    &p2p->status)) {
+		brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");
+		/* So abort scan to cancel listen */
+		brcmf_notify_escan_complete(cfg, ndev, true, true);
+	}
+}
+
+
+/**
+ * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission
+ *
+ * @p2p: p2p device info struct.
+ *
+ * return true if recevied action frame is to be dropped.
+ */
+static bool
+brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
+{
+	struct brcmf_cfg80211_info *cfg = p2p->cfg;
+	struct brcmf_if *ifp;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) ||
+	    !p2p->gon_req_action)
+		return false;
+
+	brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n");
+	/* if sa(peer) addr is less than da(my) addr, then this device
+	 * process peer's gon request and block to send gon req.
+	 * if not (sa addr > da addr),
+	 * this device will process gon request and drop gon req of peer.
+	 */
+	ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+	if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
+		brcmf_dbg(INFO, "Block transmit gon req !!!\n");
+		p2p->block_gon_req_tx = true;
+		/* if we are finding a common channel for sending af,
+		 * do not scan more to block to send current gon req
+		 */
+		if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+				       &p2p->status))
+			complete(&p2p->afx_hdl.act_frm_scan);
+		if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+				       &p2p->status))
+			brcmf_p2p_stop_wait_next_action_frame(cfg);
+		return false;
+	}
+
+	/* drop gon request of peer to process gon request by this device. */
+	brcmf_dbg(INFO, "Drop received gon req !!!\n");
+
+	return true;
+}
+
+
+/**
+ * brcmf_p2p_notify_action_frame_rx() - received action frame.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message, containing action frame data.
+ *
+ */
+int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	struct wireless_dev *wdev;
+	u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
+	struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+	u8 *frame = (u8 *)(rxframe + 1);
+	struct brcmf_p2p_pub_act_frame *act_frm;
+	struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+	u16 chanspec = be16_to_cpu(rxframe->chanspec);
+	struct ieee80211_mgmt *mgmt_frame;
+	s32 freq;
+	u16 mgmt_type;
+	u8 action;
+
+	/* Check if wpa_supplicant has registered for this frame */
+	brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);
+	mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;
+	if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+		return 0;
+
+	brcmf_p2p_print_actframe(false, frame, mgmt_frame_len);
+
+	action = P2P_PAF_SUBTYPE_INVALID;
+	if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) {
+		act_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+		action = act_frm->subtype;
+		if ((action == P2P_PAF_GON_REQ) &&
+		    (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {
+			if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+				     &p2p->status) &&
+			    (memcmp(afx_hdl->tx_dst_addr, e->addr,
+				    ETH_ALEN) == 0)) {
+				afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+				brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
+					  afx_hdl->peer_chan);
+				complete(&afx_hdl->act_frm_scan);
+			}
+			return 0;
+		}
+		/* After complete GO Negotiation, roll back to mpc mode */
+		if ((action == P2P_PAF_GON_CONF) ||
+		    (action == P2P_PAF_PROVDIS_RSP))
+			brcmf_set_mpc(ifp->ndev, 1);
+		if (action == P2P_PAF_GON_CONF) {
+			brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
+			clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		}
+	} else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) {
+		sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+		action = sd_act_frm->action;
+	}
+
+	if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
+	    (p2p->next_af_subtype == action)) {
+		brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action);
+		clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+			  &p2p->status);
+		/* Stop waiting for next AF. */
+		brcmf_p2p_stop_wait_next_action_frame(cfg);
+	}
+
+	mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) +
+			     mgmt_frame_len, GFP_KERNEL);
+	if (!mgmt_frame) {
+		brcmf_err("No memory available for action frame\n");
+		return -ENOMEM;
+	}
+	memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
+	brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
+			       ETH_ALEN);
+	memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
+	mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
+	memcpy(&mgmt_frame->u, frame, mgmt_frame_len);
+	mgmt_frame_len += offsetof(struct ieee80211_mgmt, u);
+
+	freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+					      CHSPEC_IS2G(chanspec) ?
+					      IEEE80211_BAND_2GHZ :
+					      IEEE80211_BAND_5GHZ);
+	wdev = ifp->ndev->ieee80211_ptr;
+	cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
+			 GFP_ATOMIC);
+
+	kfree(mgmt_frame);
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: not used.
+ *
+ */
+int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
+					const struct brcmf_event_msg *e,
+					void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+	brcmf_dbg(INFO, "Enter: event %s, status=%d\n",
+		  e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ?
+		  "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE",
+		  e->status);
+
+	if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status))
+		return 0;
+
+	if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
+		if (e->status == BRCMF_E_STATUS_SUCCESS)
+			set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
+				&p2p->status);
+		else {
+			set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+			/* If there is no ack, we don't need to wait for
+			 * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
+			 */
+			brcmf_p2p_stop_wait_next_action_frame(cfg);
+		}
+
+	} else {
+		complete(&p2p->send_af_done);
+	}
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_tx_action_frame() - send action frame over fil.
+ *
+ * @p2p: p2p info struct for vif.
+ * @af_params: action frame data/info.
+ *
+ * Send an action frame immediately without doing channel synchronization.
+ *
+ * This function waits for a completion event before returning.
+ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
+ * frame is transmitted.
+ */
+static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
+				     struct brcmf_fil_af_params_le *af_params)
+{
+	struct brcmf_cfg80211_vif *vif;
+	s32 err = 0;
+	s32 timeout = 0;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	INIT_COMPLETION(p2p->send_af_done);
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
+					sizeof(*af_params));
+	if (err) {
+		brcmf_err(" sending action frame has failed\n");
+		goto exit;
+	}
+
+	p2p->af_sent_channel = le32_to_cpu(af_params->channel);
+	p2p->af_tx_sent_jiffies = jiffies;
+
+	timeout = wait_for_completion_timeout(&p2p->send_af_done,
+					msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME));
+
+	if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) {
+		brcmf_dbg(TRACE, "TX action frame operation is success\n");
+	} else {
+		err = -EIO;
+		brcmf_dbg(TRACE, "TX action frame operation has failed\n");
+	}
+	/* clear status bit for action tx */
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
+	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_pub_af_tx() - public action frame tx routine.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @af_params: action frame data/info.
+ * @config_af_params: configuration data for action frame.
+ *
+ * routine which transmits ation frame public type.
+ */
+static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg,
+			       struct brcmf_fil_af_params_le *af_params,
+			       struct brcmf_config_af_params *config_af_params)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_fil_action_frame_le *action_frame;
+	struct brcmf_p2p_pub_act_frame *act_frm;
+	s32 err = 0;
+	u16 ie_len;
+
+	action_frame = &af_params->action_frame;
+	act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data);
+
+	config_af_params->extra_listen = true;
+
+	switch (act_frm->subtype) {
+	case P2P_PAF_GON_REQ:
+		brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n");
+		set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		config_af_params->mpc_onoff = 0;
+		config_af_params->search_channel = true;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		p2p->gon_req_action = true;
+		/* increase dwell time to wait for RESP frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_GON_RSP:
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* increase dwell time to wait for CONF frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_GON_CONF:
+		/* If we reached till GO Neg confirmation reset the filter */
+		brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
+		clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+		/* turn on mpc again if go nego is done */
+		config_af_params->mpc_onoff = 1;
+		/* minimize dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	case P2P_PAF_INVITE_REQ:
+		config_af_params->search_channel = true;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* increase dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_INVITE_RSP:
+		/* minimize dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	case P2P_PAF_DEVDIS_REQ:
+		config_af_params->search_channel = true;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* maximize dwell time to wait for RESP frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME);
+		break;
+	case P2P_PAF_DEVDIS_RSP:
+		/* minimize dwell time */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	case P2P_PAF_PROVDIS_REQ:
+		ie_len = le16_to_cpu(action_frame->len) -
+			 offsetof(struct brcmf_p2p_pub_act_frame, elts);
+		if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len,
+					  IEEE80211_P2P_ATTR_GROUP_ID,
+					  NULL, 0) < 0)
+			config_af_params->search_channel = true;
+		config_af_params->mpc_onoff = 0;
+		p2p->next_af_subtype = act_frm->subtype + 1;
+		/* increase dwell time to wait for RESP frame */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		break;
+	case P2P_PAF_PROVDIS_RSP:
+		/* wpa_supplicant send go nego req right after prov disc */
+		p2p->next_af_subtype = P2P_PAF_GON_REQ;
+		/* increase dwell time to MED level */
+		af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		config_af_params->extra_listen = false;
+		break;
+	default:
+		brcmf_err("Unknown p2p pub act frame subtype: %d\n",
+			  act_frm->subtype);
+		err = -EINVAL;
+	}
+	return err;
+}
+
+/**
+ * brcmf_p2p_send_action_frame() - send action frame .
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @ndev: net device to transmit on.
+ * @af_params: configuration data for action frame.
+ */
+bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
+				 struct net_device *ndev,
+				 struct brcmf_fil_af_params_le *af_params)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_fil_action_frame_le *action_frame;
+	struct brcmf_config_af_params config_af_params;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	u16 action_frame_len;
+	bool ack = false;
+	u8 category;
+	u8 action;
+	s32 tx_retry;
+	s32 extra_listen_time;
+	uint delta_ms;
+
+	action_frame = &af_params->action_frame;
+	action_frame_len = le16_to_cpu(action_frame->len);
+
+	brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len);
+
+	/* Add the default dwell time. Dwell time to stay off-channel */
+	/* to wait for a response action frame after transmitting an  */
+	/* GO Negotiation action frame                                */
+	af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME);
+
+	category = action_frame->data[DOT11_ACTION_CAT_OFF];
+	action = action_frame->data[DOT11_ACTION_ACT_OFF];
+
+	/* initialize variables */
+	p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+	p2p->gon_req_action = false;
+
+	/* config parameters */
+	config_af_params.mpc_onoff = -1;
+	config_af_params.search_channel = false;
+	config_af_params.extra_listen = false;
+
+	if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) {
+		/* p2p public action frame process */
+		if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) {
+			/* Just send unknown subtype frame with */
+			/* default parameters.                  */
+			brcmf_err("P2P Public action frame, unknown subtype.\n");
+		}
+	} else if (brcmf_p2p_is_gas_action(action_frame->data,
+					   action_frame_len)) {
+		/* service discovery process */
+		if (action == P2PSD_ACTION_ID_GAS_IREQ ||
+		    action == P2PSD_ACTION_ID_GAS_CREQ) {
+			/* configure service discovery query frame */
+			config_af_params.search_channel = true;
+
+			/* save next af suptype to cancel */
+			/* remaining dwell time           */
+			p2p->next_af_subtype = action + 1;
+
+			af_params->dwell_time =
+				cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+		} else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
+			   action == P2PSD_ACTION_ID_GAS_CRESP) {
+			/* configure service discovery response frame */
+			af_params->dwell_time =
+				cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+		} else {
+			brcmf_err("Unknown action type: %d\n", action);
+			goto exit;
+		}
+	} else if (brcmf_p2p_is_p2p_action(action_frame->data,
+					   action_frame_len)) {
+		/* do not configure anything. it will be */
+		/* sent with a default configuration     */
+	} else {
+		brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n",
+			  category, action);
+		return false;
+	}
+
+	/* if connecting on primary iface, sleep for a while before sending
+	 * af tx for VSDB
+	 */
+	if (test_bit(BRCMF_VIF_STATUS_CONNECTING,
+		     &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state))
+		msleep(50);
+
+	/* if scan is ongoing, abort current scan. */
+	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+		brcmf_abort_scanning(cfg);
+
+	memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN);
+
+	/* To make sure to send successfully action frame, turn off mpc */
+	if (config_af_params.mpc_onoff == 0)
+		brcmf_set_mpc(ndev, 0);
+
+	/* set status and destination address before sending af */
+	if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+		/* set status to cancel the remained dwell time in rx process */
+		set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
+	}
+
+	p2p->af_sent_channel = 0;
+	set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
+	/* validate channel and p2p ies */
+	if (config_af_params.search_channel &&
+	    IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&
+	    p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {
+		afx_hdl = &p2p->afx_hdl;
+		afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);
+
+		if (brcmf_p2p_af_searching_channel(p2p) ==
+							P2P_INVALID_CHANNEL) {
+			brcmf_err("Couldn't find peer's channel.\n");
+			goto exit;
+		}
+
+		/* Abort scan even for VSDB scenarios. Scan gets aborted in
+		 * firmware but after the check of piggyback algorithm. To take
+		 * care of current piggback algo, lets abort the scan here
+		 * itself.
+		 */
+		brcmf_notify_escan_complete(cfg, ndev, true, true);
+
+		/* update channel */
+		af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
+	}
+
+	tx_retry = 0;
+	while (!p2p->block_gon_req_tx &&
+	       (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) {
+		ack = !brcmf_p2p_tx_action_frame(p2p, af_params);
+		tx_retry++;
+	}
+	if (ack == false) {
+		brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry);
+		clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+	}
+
+exit:
+	clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
+
+	/* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
+	 * if we coundn't get the next action response frame and dongle does
+	 * not keep the dwell time, go to listen state again to get next action
+	 * response frame.
+	 */
+	if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx &&
+	    test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
+	    p2p->af_sent_channel == afx_hdl->my_listen_chan) {
+		delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies);
+		if (le32_to_cpu(af_params->dwell_time) > delta_ms)
+			extra_listen_time = le32_to_cpu(af_params->dwell_time) -
+					    delta_ms;
+		else
+			extra_listen_time = 0;
+		if (extra_listen_time > 50) {
+			set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+				&p2p->status);
+			brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n",
+				  le32_to_cpu(af_params->dwell_time),
+				  extra_listen_time);
+			extra_listen_time += 100;
+			if (!brcmf_p2p_discover_listen(p2p,
+						       p2p->af_sent_channel,
+						       extra_listen_time)) {
+				unsigned long duration;
+
+				extra_listen_time += 100;
+				duration = msecs_to_jiffies(extra_listen_time);
+				wait_for_completion_timeout(&p2p->wait_next_af,
+							    duration);
+			}
+			clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+				  &p2p->status);
+		}
+	}
+
+	if (p2p->block_gon_req_tx) {
+		/* if ack is true, supplicant will wait more time(100ms).
+		 * so we will return it as a success to get more time .
+		 */
+		p2p->block_gon_req_tx = false;
+		ack = true;
+	}
+
+	clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
+	/* if all done, turn mpc on again */
+	if (config_af_params.mpc_onoff == 1)
+		brcmf_set_mpc(ndev, 1);
+
+	return ack;
+}
+
+/**
+ * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req.
+ *
+ * @ifp: interface pointer for which event was received.
+ * @e: even message.
+ * @data: payload of event message (probe request).
+ */
+s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+					  const struct brcmf_event_msg *e,
+					  void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+	struct wireless_dev *wdev;
+	struct brcmf_cfg80211_vif *vif = ifp->vif;
+	struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+	u16 chanspec = be16_to_cpu(rxframe->chanspec);
+	u8 *mgmt_frame;
+	u32 mgmt_frame_len;
+	s32 freq;
+	u16 mgmt_type;
+
+	brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
+		  e->reason);
+
+	if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&
+	    (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) {
+		afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+		brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",
+			  afx_hdl->peer_chan);
+		complete(&afx_hdl->act_frm_scan);
+	}
+
+	/* Firmware sends us two proberesponses for each idx one. At the */
+	/* moment anything but bsscfgidx 0 is passed up to supplicant    */
+	if (e->bsscfgidx == 0)
+		return 0;
+
+	/* Filter any P2P probe reqs arriving during the GO-NEG Phase */
+	if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) {
+		brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n");
+		return 0;
+	}
+
+	/* Check if wpa_supplicant has registered for this frame */
+	brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
+	mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
+	if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+		return 0;
+
+	mgmt_frame = (u8 *)(rxframe + 1);
+	mgmt_frame_len = e->datalen - sizeof(*rxframe);
+	freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+					      CHSPEC_IS2G(chanspec) ?
+					      IEEE80211_BAND_2GHZ :
+					      IEEE80211_BAND_5GHZ);
+	wdev = ifp->ndev->ieee80211_ptr;
+	cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+
+	brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
+		  mgmt_frame_len, e->datalen, chanspec, freq);
+
+	return 0;
+}
+
+
+/**
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_if *pri_ifp;
+	struct brcmf_if *p2p_ifp;
+	struct brcmf_cfg80211_vif *p2p_vif;
+	struct brcmf_p2p_info *p2p;
+	struct brcmf_pub *drvr;
+	s32 bssidx;
+	s32 err = 0;
+
+	p2p = &cfg->p2p;
+	p2p->cfg = cfg;
+
+	drvr = cfg->pub;
+
+	pri_ifp = drvr->iflist[0];
+	p2p_ifp = drvr->iflist[1];
+
+	p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+	if (p2p_ifp) {
+		p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+					  false);
+		if (IS_ERR(p2p_vif)) {
+			brcmf_err("could not create discovery vif\n");
+			err = -ENOMEM;
+			goto exit;
+		}
+
+		p2p_vif->ifp = p2p_ifp;
+		p2p_ifp->vif = p2p_vif;
+		p2p_vif->wdev.netdev = p2p_ifp->ndev;
+		p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+		SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+
+		p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+
+		brcmf_p2p_generate_bss_mac(p2p);
+		brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+		/* Initialize P2P Discovery in the firmware */
+		err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+		if (err < 0) {
+			brcmf_err("set p2p_disc error\n");
+			brcmf_free_vif(p2p_vif);
+			goto exit;
+		}
+		/* obtain bsscfg index for P2P discovery */
+		err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+		if (err < 0) {
+			brcmf_err("retrieving discover bsscfg index failed\n");
+			brcmf_free_vif(p2p_vif);
+			goto exit;
+		}
+		/* Verify that firmware uses same bssidx as driver !! */
+		if (p2p_ifp->bssidx != bssidx) {
+			brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+				  bssidx, p2p_ifp->bssidx);
+			brcmf_free_vif(p2p_vif);
+			goto exit;
+		}
+
+		init_completion(&p2p->send_af_done);
+		INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+		init_completion(&p2p->afx_hdl.act_frm_scan);
+		init_completion(&p2p->wait_next_af);
+	}
+exit:
+	return err;
+}
+
+
+/**
+ * brcmf_p2p_detach() - detach P2P.
+ *
+ * @p2p: P2P specific data.
+ */
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+{
+	struct brcmf_cfg80211_vif *vif;
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (vif != NULL) {
+		brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+		brcmf_p2p_deinit_discovery(p2p);
+		/* remove discovery interface */
+		brcmf_free_vif(vif);
+		p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+	}
+	/* just set it all to zero */
+	memset(p2p, 0, sizeof(*p2p));
+}
+
+/**
+ * brcmf_p2p_get_current_chanspec() - Get current operation channel.
+ *
+ * @p2p: P2P specific data.
+ * @chanspec: chanspec to be returned.
+ */
+static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
+					   u16 *chanspec)
+{
+	struct brcmf_if *ifp;
+	struct brcmf_fil_chan_info_le ci;
+	s32 err;
+
+	ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+
+	*chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
+
+	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
+	if (!err) {
+		*chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
+		if (*chanspec < CH_MAX_2G_CHANNEL)
+			*chanspec |= WL_CHANSPEC_BAND_2G;
+		else
+			*chanspec |= WL_CHANSPEC_BAND_5G;
+	}
+	*chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
+}
+
+/**
+ * Change a P2P Role.
+ * Parameters:
+ * @mac: MAC address of the BSS to change a role
+ * Returns 0 if success.
+ */
+int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+		       enum brcmf_fil_p2p_if_types if_type)
+{
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_fil_p2p_if_le if_request;
+	s32 err;
+	u16 chanspec;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+	if (!vif) {
+		brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
+		return -EPERM;
+	}
+	brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true);
+	vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+	if (!vif) {
+		brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
+		return -EPERM;
+	}
+	brcmf_set_mpc(vif->ifp->ndev, 0);
+
+	/* In concurrency case, STA may be already associated in a particular */
+	/* channel. so retrieve the current channel of primary interface and  */
+	/* then start the virtual interface on that.                          */
+	brcmf_p2p_get_current_chanspec(p2p, &chanspec);
+
+	if_request.type = cpu_to_le16((u16)if_type);
+	if_request.chspec = cpu_to_le16(chanspec);
+	memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr));
+
+	brcmf_cfg80211_arm_vif_event(cfg, vif);
+	err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,
+				       sizeof(if_request));
+	if (err) {
+		brcmf_err("p2p_ifupd FAILED, err=%d\n", err);
+		brcmf_cfg80211_arm_vif_event(cfg, NULL);
+		return err;
+	}
+	err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
+						    msecs_to_jiffies(1500));
+	brcmf_cfg80211_arm_vif_event(cfg, NULL);
+	if (!err)  {
+		brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
+		return -EIO;
+	}
+
+	err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT,
+				    BRCMF_SCB_TIMEOUT_VALUE);
+
+	return err;
+}
+
+static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p,
+				    struct brcmf_if *ifp, u8 ea[ETH_ALEN],
+				    enum brcmf_fil_p2p_if_types iftype)
+{
+	struct brcmf_fil_p2p_if_le if_request;
+	int err;
+	u16 chanspec;
+
+	/* we need a default channel */
+	brcmf_p2p_get_current_chanspec(p2p, &chanspec);
+
+	/* fill the firmware request */
+	memcpy(if_request.addr, ea, ETH_ALEN);
+	if_request.type = cpu_to_le16((u16)iftype);
+	if_request.chspec = cpu_to_le16(chanspec);
+
+	err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,
+				       sizeof(if_request));
+	if (err)
+		return err;
+
+	return err;
+}
+
+static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
+	struct net_device *pri_ndev = cfg_to_ndev(cfg);
+	struct brcmf_if *ifp = netdev_priv(pri_ndev);
+	u8 *addr = vif->wdev.netdev->dev_addr;
+
+	return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);
+}
+
+static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
+	struct net_device *pri_ndev = cfg_to_ndev(cfg);
+	struct brcmf_if *ifp = netdev_priv(pri_ndev);
+	u8 *addr = vif->wdev.netdev->dev_addr;
+
+	return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);
+}
+
+/**
+ * brcmf_p2p_add_vif() - create a new P2P virtual interface.
+ *
+ * @wiphy: wiphy device of new interface.
+ * @name: name of the new interface.
+ * @type: nl80211 interface type.
+ * @flags: TBD
+ * @params: TBD
+ */
+struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+				       enum nl80211_iftype type, u32 *flags,
+				       struct vif_params *params)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+	struct brcmf_cfg80211_vif *vif;
+	enum brcmf_fil_p2p_if_types iftype;
+	enum wl_mode mode;
+	int err;
+
+	if (brcmf_cfg80211_vif_event_armed(cfg))
+		return ERR_PTR(-EBUSY);
+
+	brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type);
+
+	switch (type) {
+	case NL80211_IFTYPE_P2P_CLIENT:
+		iftype = BRCMF_FIL_P2P_IF_CLIENT;
+		mode = WL_MODE_BSS;
+		break;
+	case NL80211_IFTYPE_P2P_GO:
+		iftype = BRCMF_FIL_P2P_IF_GO;
+		mode = WL_MODE_AP;
+		break;
+	default:
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+
+	vif = brcmf_alloc_vif(cfg, type, false);
+	if (IS_ERR(vif))
+		return (struct wireless_dev *)vif;
+	brcmf_cfg80211_arm_vif_event(cfg, vif);
+
+	err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr,
+				       iftype);
+	if (err) {
+		brcmf_cfg80211_arm_vif_event(cfg, NULL);
+		goto fail;
+	}
+
+	/* wait for firmware event */
+	err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
+						    msecs_to_jiffies(1500));
+	brcmf_cfg80211_arm_vif_event(cfg, NULL);
+	if (!err) {
+		brcmf_err("timeout occurred\n");
+		err = -EIO;
+		goto fail;
+	}
+
+	/* interface created in firmware */
+	ifp = vif->ifp;
+	if (!ifp) {
+		brcmf_err("no if pointer provided\n");
+		err = -ENOENT;
+		goto fail;
+	}
+
+	strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+	err = brcmf_net_attach(ifp, true);
+	if (err) {
+		brcmf_err("Registering netdevice failed\n");
+		goto fail;
+	}
+	cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
+	/* Disable firmware roaming for P2P interface  */
+	brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
+	if (iftype == BRCMF_FIL_P2P_IF_GO) {
+		/* set station timeout for p2p */
+		brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT,
+				      BRCMF_SCB_TIMEOUT_VALUE);
+	}
+	return &ifp->vif->wdev;
+
+fail:
+	brcmf_free_vif(vif);
+	return ERR_PTR(err);
+}
+
+/**
+ * brcmf_p2p_del_vif() - delete a P2P virtual interface.
+ *
+ * @wiphy: wiphy device of interface.
+ * @wdev: wireless device of interface.
+ *
+ * TODO: not yet supported.
+ */
+int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+	struct brcmf_p2p_info *p2p = &cfg->p2p;
+	struct brcmf_cfg80211_vif *vif;
+	unsigned long jiffie_timeout = msecs_to_jiffies(1500);
+	bool wait_for_disable = false;
+	int err;
+
+	brcmf_dbg(TRACE, "delete P2P vif\n");
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+	switch (vif->wdev.iftype) {
+	case NL80211_IFTYPE_P2P_CLIENT:
+		if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
+			wait_for_disable = true;
+		break;
+
+	case NL80211_IFTYPE_P2P_GO:
+		if (!brcmf_p2p_disable_p2p_if(vif))
+			wait_for_disable = true;
+		break;
+
+	case NL80211_IFTYPE_P2P_DEVICE:
+	default:
+		return -ENOTSUPP;
+		break;
+	}
+
+	clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+	brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
+
+	if (wait_for_disable)
+		wait_for_completion_timeout(&cfg->vif_disabled,
+					    msecs_to_jiffies(500));
+
+	brcmf_vif_clear_mgmt_ies(vif);
+
+	brcmf_cfg80211_arm_vif_event(cfg, vif);
+	err = brcmf_p2p_release_p2p_if(vif);
+	if (!err) {
+		/* wait for firmware event */
+		err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
+							    jiffie_timeout);
+		if (!err)
+			err = -EIO;
+		else
+			err = 0;
+	}
+	brcmf_cfg80211_arm_vif_event(cfg, NULL);
+	brcmf_free_vif(vif);
+	p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
+
+	return err;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
new file mode 100644
index 0000000..6821b26
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef WL_CFGP2P_H_
+#define WL_CFGP2P_H_
+
+#include <net/cfg80211.h>
+
+struct brcmf_cfg80211_info;
+
+/**
+ * enum p2p_bss_type - different type of BSS configurations.
+ *
+ * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg.
+ * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg.
+ * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg.
+ * @P2PAPI_BSSCFG_MAX: used for range checking.
+ */
+enum p2p_bss_type {
+	P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
+	P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
+	P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
+	P2PAPI_BSSCFG_MAX
+};
+
+/**
+ * struct p2p_bss - peer-to-peer bss related information.
+ *
+ * @vif: virtual interface of this P2P bss.
+ * @private_data: TBD
+ */
+struct p2p_bss {
+	struct brcmf_cfg80211_vif *vif;
+	void *private_data;
+};
+
+/**
+ * enum brcmf_p2p_status - P2P specific dongle status.
+ *
+ * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED?
+ * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle.
+ * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed.
+ * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
+ * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
+ * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel.
+ * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame.
+ * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx.
+ * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response.
+ * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active.
+ */
+enum brcmf_p2p_status {
+	BRCMF_P2P_STATUS_ENABLED,
+	BRCMF_P2P_STATUS_IF_ADD,
+	BRCMF_P2P_STATUS_IF_DEL,
+	BRCMF_P2P_STATUS_IF_DELETING,
+	BRCMF_P2P_STATUS_IF_CHANGING,
+	BRCMF_P2P_STATUS_IF_CHANGED,
+	BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
+	BRCMF_P2P_STATUS_ACTION_TX_NOACK,
+	BRCMF_P2P_STATUS_GO_NEG_PHASE,
+	BRCMF_P2P_STATUS_DISCOVER_LISTEN,
+	BRCMF_P2P_STATUS_SENDING_ACT_FRAME,
+	BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+	BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+	BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL
+};
+
+/**
+ * struct afx_hdl - action frame off channel storage.
+ *
+ * @afx_work: worker thread for searching channel
+ * @act_frm_scan: thread synchronizing struct.
+ * @is_active: channel searching active.
+ * @peer_chan: current channel.
+ * @is_listen: sets mode for afx worker.
+ * @my_listen_chan: this peers listen channel.
+ * @peer_listen_chan: remote peers listen channel.
+ * @tx_dst_addr: mac address where tx af should be sent to.
+ */
+struct afx_hdl {
+	struct work_struct afx_work;
+	struct completion act_frm_scan;
+	bool is_active;
+	s32 peer_chan;
+	bool is_listen;
+	u16 my_listen_chan;
+	u16 peer_listen_chan;
+	u8 tx_dst_addr[ETH_ALEN];
+};
+
+/**
+ * struct brcmf_p2p_info - p2p specific driver information.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @status: status of P2P (see enum brcmf_p2p_status).
+ * @dev_addr: P2P device address.
+ * @int_addr: P2P interface address.
+ * @bss_idx: informate for P2P bss types.
+ * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @ssid: ssid for P2P GO.
+ * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @remain_on_channel: contains copy of struct used by cfg80211.
+ * @remain_on_channel_cookie: cookie counter for remain on channel cmd
+ * @next_af_subtype: expected action frame subtype.
+ * @send_af_done: indication that action frame tx is complete.
+ * @afx_hdl: action frame search handler info.
+ * @af_sent_channel: channel action frame is sent.
+ * @af_tx_sent_jiffies: jiffies time when af tx was transmitted.
+ * @wait_next_af: thread synchronizing struct.
+ * @gon_req_action: about to send go negotiation requets frame.
+ * @block_gon_req_tx: drop tx go negotiation requets frame.
+ */
+struct brcmf_p2p_info {
+	struct brcmf_cfg80211_info *cfg;
+	unsigned long status;
+	u8 dev_addr[ETH_ALEN];
+	u8 int_addr[ETH_ALEN];
+	struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
+	struct timer_list listen_timer;
+	struct brcmf_ssid ssid;
+	u8 listen_channel;
+	struct ieee80211_channel remain_on_channel;
+	u32 remain_on_channel_cookie;
+	u8 next_af_subtype;
+	struct completion send_af_done;
+	struct afx_hdl afx_hdl;
+	u32 af_sent_channel;
+	unsigned long af_tx_sent_jiffies;
+	struct completion wait_next_af;
+	bool gon_req_action;
+	bool block_gon_req_tx;
+};
+
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
+struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+				       enum nl80211_iftype type, u32 *flags,
+				       struct vif_params *params);
+int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
+int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+		       enum brcmf_fil_p2p_if_types if_type);
+int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+			struct cfg80211_scan_request *request,
+			struct brcmf_cfg80211_vif *vif);
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+				struct ieee80211_channel *channel,
+				unsigned int duration, u64 *cookie);
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data);
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);
+int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data);
+int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
+					const struct brcmf_event_msg *e,
+					void *data);
+bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
+				 struct net_device *ndev,
+				 struct brcmf_fil_af_params_le *af_params);
+bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
+					   struct brcmf_bss_info_le *bi);
+s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+					  const struct brcmf_event_msg *e,
+					  void *data);
+#endif /* WL_CFGP2P_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
index b1bb46c..14be2d5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
@@ -15,8 +15,6 @@
  */
 /* ***** SDIO interface chip backplane handle functions ***** */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/mmc/card.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 914c56f..42289e9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -354,11 +354,10 @@
 	int i;
 	struct brcmf_usbreq *req, *reqs;
 
-	reqs = kzalloc(sizeof(struct brcmf_usbreq) * qsize, GFP_ATOMIC);
-	if (reqs == NULL) {
-		brcmf_err("fail to allocate memory!\n");
+	reqs = kcalloc(qsize, sizeof(struct brcmf_usbreq), GFP_ATOMIC);
+	if (reqs == NULL)
 		return NULL;
-	}
+
 	req = reqs;
 
 	for (i = 0; i < qsize; i++) {
@@ -421,10 +420,6 @@
 	brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
 		  req->skb);
 	brcmf_usb_del_fromq(devinfo, req);
-	if (urb->status == 0)
-		devinfo->bus_pub.bus->dstats.tx_packets++;
-	else
-		devinfo->bus_pub.bus->dstats.tx_errors++;
 
 	brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
 
@@ -443,30 +438,25 @@
 	struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;
 	struct brcmf_usbdev_info *devinfo = req->devinfo;
 	struct sk_buff *skb;
-	int ifidx = 0;
+	struct sk_buff_head skbq;
 
 	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
 	brcmf_usb_del_fromq(devinfo, req);
 	skb = req->skb;
 	req->skb = NULL;
 
-	if (urb->status == 0) {
-		devinfo->bus_pub.bus->dstats.rx_packets++;
-	} else {
-		devinfo->bus_pub.bus->dstats.rx_errors++;
+	/* zero lenght packets indicate usb "failure". Do not refill */
+	if (urb->status != 0 || !urb->actual_length) {
 		brcmu_pkt_buf_free_skb(skb);
 		brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
 		return;
 	}
 
 	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
+		skb_queue_head_init(&skbq);
+		skb_queue_tail(&skbq, skb);
 		skb_put(skb, urb->actual_length);
-		if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
-			brcmf_err("rx protocol error\n");
-			brcmu_pkt_buf_free_skb(skb);
-			devinfo->bus_pub.bus->dstats.rx_errors++;
-		} else
-			brcmf_rx_packet(devinfo->dev, ifidx, skb);
+		brcmf_rx_frames(devinfo->dev, &skbq);
 		brcmf_usb_rx_refill(devinfo, req);
 	} else {
 		brcmu_pkt_buf_free_skb(skb);
@@ -1259,6 +1249,8 @@
 	bus->bus_priv.usb = bus_pub;
 	dev_set_drvdata(dev, bus);
 	bus->ops = &brcmf_usb_bus_ops;
+	bus->chip = bus_pub->devid;
+	bus->chiprev = bus_pub->chiprev;
 
 	/* Attach to the common driver interface */
 	ret = brcmf_attach(0, dev);
@@ -1520,10 +1512,23 @@
 	}
 }
 
+static int brcmf_usb_reset_device(struct device *dev, void *notused)
+{
+	/* device past is the usb interface so we
+	 * need to use parent here.
+	 */
+	brcmf_dev_reset(dev->parent);
+	return 0;
+}
 
 void brcmf_usb_exit(void)
 {
+	struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+	int ret;
+
 	brcmf_dbg(USB, "Enter\n");
+	ret = driver_for_each_device(drv, NULL, NULL,
+				     brcmf_usb_reset_device);
 	usb_deregister(&brcmf_usbdrvr);
 	brcmf_release_fw(&fw_image_list);
 }
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 75464ad..cecc3ef 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -16,8 +16,6 @@
 
 /* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <net/cfg80211.h>
@@ -28,6 +26,8 @@
 #include <brcmu_wifi.h>
 #include "dhd.h"
 #include "dhd_dbg.h"
+#include "fwil_types.h"
+#include "p2p.h"
 #include "wl_cfg80211.h"
 #include "fwil.h"
 
@@ -43,16 +43,13 @@
 #define BRCMF_PNO_SCAN_COMPLETE		1
 #define BRCMF_PNO_SCAN_INCOMPLETE	0
 
-#define BRCMF_IFACE_MAX_CNT		2
+#define BRCMF_IFACE_MAX_CNT		3
 
-#define TLV_LEN_OFF			1	/* length offset */
-#define TLV_HDR_LEN			2	/* header length */
-#define TLV_BODY_OFF			2	/* body offset */
-#define TLV_OUI_LEN			3	/* oui id length */
 #define WPA_OUI				"\x00\x50\xF2"	/* WPA OUI */
 #define WPA_OUI_TYPE			1
 #define RSN_OUI				"\x00\x0F\xAC"	/* RSN OUI */
 #define	WME_OUI_TYPE			2
+#define WPS_OUI_TYPE			4
 
 #define VS_IE_FIXED_HDR_LEN		6
 #define WPA_IE_VERSION_LEN		2
@@ -78,13 +75,15 @@
 #define VNDR_IE_PKTFLAG_OFFSET		8
 #define VNDR_IE_VSIE_OFFSET		12
 #define VNDR_IE_HDR_SIZE		12
-#define VNDR_IE_BEACON_FLAG		0x1
-#define VNDR_IE_PRBRSP_FLAG		0x2
-#define MAX_VNDR_IE_NUMBER		5
+#define VNDR_IE_PARSE_LIMIT		5
 
 #define	DOT11_MGMT_HDR_LEN		24	/* d11 management header len */
 #define	DOT11_BCN_PRB_FIXED_LEN		12	/* beacon/probe fixed length */
 
+#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS	320
+#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS	400
+#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS	20
+
 #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
 	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
 
@@ -273,13 +272,6 @@
 	WLAN_CIPHER_SUITE_AES_CMAC,
 };
 
-/* tag_ID/length/value_buffer tuple */
-struct brcmf_tlv {
-	u8 id;
-	u8 len;
-	u8 data[1];
-};
-
 /* Vendor specific ie. id = 221, oui and type defines exact ie */
 struct brcmf_vs_tlv {
 	u8 id;
@@ -296,7 +288,7 @@
 
 struct parsed_vndr_ies {
 	u32 count;
-	struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
+	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 };
 
 /* Quarter dBm units to mW
@@ -383,7 +375,7 @@
 	return qdbm;
 }
 
-static u16 channel_to_chanspec(struct ieee80211_channel *ch)
+u16 channel_to_chanspec(struct ieee80211_channel *ch)
 {
 	u16 chanspec;
 
@@ -395,19 +387,92 @@
 	else
 		chanspec |= WL_CHANSPEC_BAND_5G;
 
-	if (ch->flags & IEEE80211_CHAN_NO_HT40) {
-		chanspec |= WL_CHANSPEC_BW_20;
-		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-	} else {
-		chanspec |= WL_CHANSPEC_BW_40;
-		if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
-			chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
-		else
-			chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
-	}
+	chanspec |= WL_CHANSPEC_BW_20;
+	chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
 	return chanspec;
 }
 
+/* Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+{
+	struct brcmf_tlv *elt;
+	int totlen;
+
+	elt = (struct brcmf_tlv *)buf;
+	totlen = buflen;
+
+	/* find tagged parameter */
+	while (totlen >= TLV_HDR_LEN) {
+		int len = elt->len;
+
+		/* validate remaining totlen */
+		if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
+			return elt;
+
+		elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
+		totlen -= (len + TLV_HDR_LEN);
+	}
+
+	return NULL;
+}
+
+/* Is any of the tlvs the expected entry? If
+ * not update the tlvs buffer pointer/length.
+ */
+static bool
+brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
+		 u8 *oui, u32 oui_len, u8 type)
+{
+	/* If the contents match the OUI and the type */
+	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+	    !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+	    type == ie[TLV_BODY_OFF + oui_len]) {
+		return true;
+	}
+
+	if (tlvs == NULL)
+		return false;
+	/* point to the next ie */
+	ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+	/* calculate the length of the rest of the buffer */
+	*tlvs_len -= (int)(ie - *tlvs);
+	/* update the pointer to the start of the buffer */
+	*tlvs = ie;
+
+	return false;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpaie(u8 *parse, u32 len)
+{
+	struct brcmf_tlv *ie;
+
+	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
+			return (struct brcmf_vs_tlv *)ie;
+	}
+	return NULL;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpsie(u8 *parse, u32 len)
+{
+	struct brcmf_tlv *ie;
+
+	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+				     WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
+			return (struct brcmf_vs_tlv *)ie;
+	}
+	return NULL;
+}
+
+
 static void convert_key_from_CPU(struct brcmf_wsec_key *key,
 				 struct brcmf_wsec_key_le *key_le)
 {
@@ -440,11 +505,153 @@
 	return err;
 }
 
+static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+						     const char *name,
+						     enum nl80211_iftype type,
+						     u32 *flags,
+						     struct vif_params *params)
+{
+	brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
+	switch (type) {
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+		return ERR_PTR(-EOPNOTSUPP);
+	case NL80211_IFTYPE_P2P_CLIENT:
+	case NL80211_IFTYPE_P2P_GO:
+		return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_P2P_DEVICE:
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+void brcmf_set_mpc(struct net_device *ndev, int mpc)
+{
+	struct brcmf_if *ifp = netdev_priv(ndev);
+	s32 err = 0;
+
+	if (check_vif_up(ifp->vif)) {
+		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
+		if (err) {
+			brcmf_err("fail to set mpc\n");
+			return;
+		}
+		brcmf_dbg(INFO, "MPC : %d\n", mpc);
+	}
+}
+
+s32
+brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+			    struct net_device *ndev,
+			    bool aborted, bool fw_abort)
+{
+	struct brcmf_scan_params_le params_le;
+	struct cfg80211_scan_request *scan_request;
+	s32 err = 0;
+
+	brcmf_dbg(SCAN, "Enter\n");
+
+	/* clear scan request, because the FW abort can cause a second call */
+	/* to this functon and might cause a double cfg80211_scan_done      */
+	scan_request = cfg->scan_request;
+	cfg->scan_request = NULL;
+
+	if (timer_pending(&cfg->escan_timeout))
+		del_timer_sync(&cfg->escan_timeout);
+
+	if (fw_abort) {
+		/* Do a scan abort to stop the driver's scan engine */
+		brcmf_dbg(SCAN, "ABORT scan in firmware\n");
+		memset(&params_le, 0, sizeof(params_le));
+		memset(params_le.bssid, 0xFF, ETH_ALEN);
+		params_le.bss_type = DOT11_BSSTYPE_ANY;
+		params_le.scan_type = 0;
+		params_le.channel_num = cpu_to_le32(1);
+		params_le.nprobes = cpu_to_le32(1);
+		params_le.active_time = cpu_to_le32(-1);
+		params_le.passive_time = cpu_to_le32(-1);
+		params_le.home_time = cpu_to_le32(-1);
+		/* Scan is aborted by setting channel_list[0] to -1 */
+		params_le.channel_list[0] = cpu_to_le16(-1);
+		/* E-Scan (or anyother type) can be aborted by SCAN */
+		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
+					     &params_le, sizeof(params_le));
+		if (err)
+			brcmf_err("Scan abort  failed\n");
+	}
+	/*
+	 * e-scan can be initiated by scheduled scan
+	 * which takes precedence.
+	 */
+	if (cfg->sched_escan) {
+		brcmf_dbg(SCAN, "scheduled scan completed\n");
+		cfg->sched_escan = false;
+		if (!aborted)
+			cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
+		brcmf_set_mpc(ndev, 1);
+	} else if (scan_request) {
+		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
+			  aborted ? "Aborted" : "Done");
+		cfg80211_scan_done(scan_request, aborted);
+		brcmf_set_mpc(ndev, 1);
+	}
+	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+		brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
+
+	return err;
+}
+
+static
+int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+	struct net_device *ndev = wdev->netdev;
+
+	/* vif event pending in firmware */
+	if (brcmf_cfg80211_vif_event_armed(cfg))
+		return -EBUSY;
+
+	if (ndev) {
+		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
+		    cfg->escan_info.ndev == ndev)
+			brcmf_notify_escan_complete(cfg, ndev, true,
+						    true);
+
+		brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
+	}
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+		return -EOPNOTSUPP;
+	case NL80211_IFTYPE_P2P_CLIENT:
+	case NL80211_IFTYPE_P2P_GO:
+		return brcmf_p2p_del_vif(wiphy, wdev);
+	case NL80211_IFTYPE_UNSPECIFIED:
+	case NL80211_IFTYPE_P2P_DEVICE:
+	default:
+		return -EINVAL;
+	}
+	return -EOPNOTSUPP;
+}
+
 static s32
 brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
 			 enum nl80211_iftype type, u32 *flags,
 			 struct vif_params *params)
 {
+	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_cfg80211_vif *vif = ifp->vif;
 	s32 infra = 0;
@@ -464,10 +671,23 @@
 		infra = 0;
 		break;
 	case NL80211_IFTYPE_STATION:
+		/* Ignore change for p2p IF. Unclear why supplicant does this */
+		if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
+		    (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
+			brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
+			/* WAR: It is unexpected to get a change of VIF for P2P
+			 * IF, but it happens. The request can not be handled
+			 * but returning EPERM causes a crash. Returning 0
+			 * without setting ieee80211_ptr->iftype causes trace
+			 * (WARN_ON) but it works with wpa_supplicant
+			 */
+			return 0;
+		}
 		vif->mode = WL_MODE_BSS;
 		infra = 1;
 		break;
 	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
 		vif->mode = WL_MODE_AP;
 		ap = 1;
 		break;
@@ -477,8 +697,14 @@
 	}
 
 	if (ap) {
-		set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
-		brcmf_dbg(INFO, "IF Type = AP\n");
+		if (type == NL80211_IFTYPE_P2P_GO) {
+			brcmf_dbg(INFO, "IF Type = P2P GO\n");
+			err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
+		}
+		if (!err) {
+			set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
+			brcmf_dbg(INFO, "IF Type = AP\n");
+		}
 	} else {
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
 		if (err) {
@@ -497,21 +723,6 @@
 	return err;
 }
 
-static void brcmf_set_mpc(struct net_device *ndev, int mpc)
-{
-	struct brcmf_if *ifp = netdev_priv(ndev);
-	s32 err = 0;
-
-	if (check_vif_up(ifp->vif)) {
-		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
-		if (err) {
-			brcmf_err("fail to set mpc\n");
-			return;
-		}
-		brcmf_dbg(INFO, "MPC : %d\n", mpc);
-	}
-}
-
 static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
 			     struct cfg80211_scan_request *request)
 {
@@ -592,69 +803,6 @@
 }
 
 static s32
-brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
-			    struct net_device *ndev,
-			    bool aborted, bool fw_abort)
-{
-	struct brcmf_scan_params_le params_le;
-	struct cfg80211_scan_request *scan_request;
-	s32 err = 0;
-
-	brcmf_dbg(SCAN, "Enter\n");
-
-	/* clear scan request, because the FW abort can cause a second call */
-	/* to this functon and might cause a double cfg80211_scan_done      */
-	scan_request = cfg->scan_request;
-	cfg->scan_request = NULL;
-
-	if (timer_pending(&cfg->escan_timeout))
-		del_timer_sync(&cfg->escan_timeout);
-
-	if (fw_abort) {
-		/* Do a scan abort to stop the driver's scan engine */
-		brcmf_dbg(SCAN, "ABORT scan in firmware\n");
-		memset(&params_le, 0, sizeof(params_le));
-		memset(params_le.bssid, 0xFF, ETH_ALEN);
-		params_le.bss_type = DOT11_BSSTYPE_ANY;
-		params_le.scan_type = 0;
-		params_le.channel_num = cpu_to_le32(1);
-		params_le.nprobes = cpu_to_le32(1);
-		params_le.active_time = cpu_to_le32(-1);
-		params_le.passive_time = cpu_to_le32(-1);
-		params_le.home_time = cpu_to_le32(-1);
-		/* Scan is aborted by setting channel_list[0] to -1 */
-		params_le.channel_list[0] = cpu_to_le16(-1);
-		/* E-Scan (or anyother type) can be aborted by SCAN */
-		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
-					     &params_le, sizeof(params_le));
-		if (err)
-			brcmf_err("Scan abort  failed\n");
-	}
-	/*
-	 * e-scan can be initiated by scheduled scan
-	 * which takes precedence.
-	 */
-	if (cfg->sched_escan) {
-		brcmf_dbg(SCAN, "scheduled scan completed\n");
-		cfg->sched_escan = false;
-		if (!aborted)
-			cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
-		brcmf_set_mpc(ndev, 1);
-	} else if (scan_request) {
-		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
-			  aborted ? "Aborted" : "Done");
-		cfg80211_scan_done(scan_request, aborted);
-		brcmf_set_mpc(ndev, 1);
-	}
-	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-		brcmf_err("Scan complete while device not scanning\n");
-		return -EPERM;
-	}
-
-	return err;
-}
-
-static s32
 brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
 		struct cfg80211_scan_request *request, u16 action)
 {
@@ -705,11 +853,12 @@
 	s32 err;
 	u32 passive_scan;
 	struct brcmf_scan_results *results;
+	struct escan_info *escan = &cfg->escan_info;
 
 	brcmf_dbg(SCAN, "Enter\n");
-	cfg->escan_info.ndev = ndev;
-	cfg->escan_info.wiphy = wiphy;
-	cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
+	escan->ndev = ndev;
+	escan->wiphy = wiphy;
+	escan->escan_state = WL_ESCAN_STATE_SCANNING;
 	passive_scan = cfg->active_scan ? 0 : 1;
 	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
 				    passive_scan);
@@ -723,7 +872,7 @@
 	results->count = 0;
 	results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
 
-	err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
+	err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
 	if (err)
 		brcmf_set_mpc(ndev, 1);
 	return err;
@@ -760,6 +909,12 @@
 		return -EAGAIN;
 	}
 
+	/* If scan req comes for p2p0, send it over primary I/F */
+	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
+		ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+		ndev = ifp->ndev;
+	}
+
 	/* Arm scan timeout timer */
 	mod_timer(&cfg->escan_timeout, jiffies +
 			WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
@@ -778,6 +933,11 @@
 	cfg->scan_request = request;
 	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
 	if (escan_req) {
+		cfg->escan_info.run = brcmf_run_escan;
+		err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
+		if (err)
+			goto scan_out;
+
 		err = brcmf_do_escan(cfg, wiphy, ndev, request);
 		if (err)
 			goto scan_out;
@@ -935,31 +1095,6 @@
 	memset(prof, 0, sizeof(*prof));
 }
 
-static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
-	size_t *join_params_size)
-{
-	u16 chanspec = 0;
-
-	if (ch != 0) {
-		if (ch <= CH_MAX_2G_CHANNEL)
-			chanspec |= WL_CHANSPEC_BAND_2G;
-		else
-			chanspec |= WL_CHANSPEC_BAND_5G;
-
-		chanspec |= WL_CHANSPEC_BW_20;
-		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-
-		*join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
-				     sizeof(u16);
-
-		chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
-		join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
-		join_params->params_le.chanspec_num = cpu_to_le32(1);
-
-		brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec);
-	}
-}
-
 static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
 {
 	s32 err = 0;
@@ -990,6 +1125,7 @@
 	s32 err = 0;
 	s32 wsec = 0;
 	s32 bcnprd;
+	u16 chanspec;
 
 	brcmf_dbg(TRACE, "Enter\n");
 	if (!check_vif_up(ifp->vif))
@@ -1093,8 +1229,11 @@
 				params->chandef.chan->center_freq);
 		if (params->channel_fixed) {
 			/* adding chanspec */
-			brcmf_ch_to_chanspec(cfg->channel,
-				&join_params, &join_params_size);
+			chanspec = channel_to_chanspec(params->chandef.chan);
+			join_params.params_le.chanspec_list[0] =
+				cpu_to_le16(chanspec);
+			join_params.params_le.chanspec_num = cpu_to_le32(1);
+			join_params_size += sizeof(join_params.params_le);
 		}
 
 		/* set channel for starter */
@@ -1157,7 +1296,7 @@
 	else
 		val = WPA_AUTH_DISABLED;
 	brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
-	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
+	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
 	if (err) {
 		brcmf_err("set wpa_auth failed (%d)\n", err);
 		return err;
@@ -1196,7 +1335,7 @@
 		break;
 	}
 
-	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
+	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
 	if (err) {
 		brcmf_err("set auth failed (%d)\n", err);
 		return err;
@@ -1260,7 +1399,12 @@
 	}
 
 	brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
-	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
+	/* In case of privacy, but no security and WPS then simulate */
+	/* setting AES. WPS-2.0 allows no security                   */
+	if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
+	    sme->privacy)
+		pval = AES_ENABLED;
+	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
 	if (err) {
 		brcmf_err("error (%d)\n", err);
 		return err;
@@ -1282,8 +1426,8 @@
 	s32 err = 0;
 
 	if (sme->crypto.n_akm_suites) {
-		err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
-					      "wpa_auth", &val);
+		err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
+					       "wpa_auth", &val);
 		if (err) {
 			brcmf_err("could not get wpa_auth (%d)\n", err);
 			return err;
@@ -1317,8 +1461,8 @@
 		}
 
 		brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
-		err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
-					      "wpa_auth", val);
+		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
+					       "wpa_auth", val);
 		if (err) {
 			brcmf_err("could not set wpa_auth (%d)\n", err);
 			return err;
@@ -1395,9 +1539,28 @@
 	return err;
 }
 
+static
+enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
+					   enum nl80211_auth_type type)
+{
+	u32 ci;
+	if (type == NL80211_AUTHTYPE_AUTOMATIC) {
+		/* shift to ignore chip revision */
+		ci = brcmf_get_chip_info(ifp) >> 4;
+		switch (ci) {
+		case 43236:
+			brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
+			return NL80211_AUTHTYPE_OPEN_SYSTEM;
+		default:
+			break;
+		}
+	}
+	return type;
+}
+
 static s32
 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
-		    struct cfg80211_connect_params *sme)
+		       struct cfg80211_connect_params *sme)
 {
 	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 	struct brcmf_if *ifp = netdev_priv(ndev);
@@ -1405,7 +1568,12 @@
 	struct ieee80211_channel *chan = sme->channel;
 	struct brcmf_join_params join_params;
 	size_t join_params_size;
-	struct brcmf_ssid ssid;
+	struct brcmf_tlv *rsn_ie;
+	struct brcmf_vs_tlv *wpa_ie;
+	void *ie;
+	u32 ie_len;
+	struct brcmf_ext_join_params_le *ext_join_params;
+	u16 chanspec;
 
 	s32 err = 0;
 
@@ -1418,15 +1586,46 @@
 		return -EOPNOTSUPP;
 	}
 
+	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
+		/* A normal (non P2P) connection request setup. */
+		ie = NULL;
+		ie_len = 0;
+		/* find the WPA_IE */
+		wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
+		if (wpa_ie) {
+			ie = wpa_ie;
+			ie_len = wpa_ie->len + TLV_HDR_LEN;
+		} else {
+			/* find the RSN_IE */
+			rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+						  WLAN_EID_RSN);
+			if (rsn_ie) {
+				ie = rsn_ie;
+				ie_len = rsn_ie->len + TLV_HDR_LEN;
+			}
+		}
+		brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
+	}
+
+	err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
+				    sme->ie, sme->ie_len);
+	if (err)
+		brcmf_err("Set Assoc REQ IE Failed\n");
+	else
+		brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
+
 	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
 
 	if (chan) {
 		cfg->channel =
 			ieee80211_frequency_to_channel(chan->center_freq);
-		brcmf_dbg(CONN, "channel (%d), center_req (%d)\n",
-			  cfg->channel, chan->center_freq);
-	} else
+		chanspec = channel_to_chanspec(chan);
+		brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
+			  cfg->channel, chan->center_freq, chanspec);
+	} else {
 		cfg->channel = 0;
+		chanspec = 0;
+	}
 
 	brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
 
@@ -1436,6 +1635,7 @@
 		goto done;
 	}
 
+	sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
 	err = brcmf_set_auth_type(ndev, sme);
 	if (err) {
 		brcmf_err("wl_set_auth_type failed (%d)\n", err);
@@ -1460,27 +1660,88 @@
 		goto done;
 	}
 
+	profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
+				       (u32)sme->ssid_len);
+	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
+	if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+		profile->ssid.SSID[profile->ssid.SSID_len] = 0;
+		brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
+			  profile->ssid.SSID_len);
+	}
+
+	/* Join with specific BSSID and cached SSID
+	 * If SSID is zero join based on BSSID only
+	 */
+	join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
+		offsetof(struct brcmf_assoc_params_le, chanspec_list);
+	if (cfg->channel)
+		join_params_size += sizeof(u16);
+	ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
+	if (ext_join_params == NULL) {
+		err = -ENOMEM;
+		goto done;
+	}
+	ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
+	memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
+	       profile->ssid.SSID_len);
+	/*increase dwell time to receive probe response or detect Beacon
+	 * from target AP at a noisy air only during connect command
+	 */
+	ext_join_params->scan_le.active_time =
+		cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
+	ext_join_params->scan_le.passive_time =
+		cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
+	/* Set up join scan parameters */
+	ext_join_params->scan_le.scan_type = -1;
+	/* to sync with presence period of VSDB GO.
+	 * Send probe request more frequently. Probe request will be stopped
+	 * when it gets probe response from target AP/GO.
+	 */
+	ext_join_params->scan_le.nprobes =
+		cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
+			    BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
+	ext_join_params->scan_le.home_time = cpu_to_le32(-1);
+
+	if (sme->bssid)
+		memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
+	else
+		memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
+
+	if (cfg->channel) {
+		ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
+
+		ext_join_params->assoc_le.chanspec_list[0] =
+			cpu_to_le16(chanspec);
+	}
+
+	err  = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
+					 join_params_size);
+	kfree(ext_join_params);
+	if (!err)
+		/* This is it. join command worked, we are done */
+		goto done;
+
+	/* join command failed, fallback to set ssid */
 	memset(&join_params, 0, sizeof(join_params));
 	join_params_size = sizeof(join_params.ssid_le);
 
-	profile->ssid.SSID_len = min_t(u32,
-				       sizeof(ssid.SSID), (u32)sme->ssid_len);
 	memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
-	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
 	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
 
-	memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
+	if (sme->bssid)
+		memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
+	else
+		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
 
-	if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
-		brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
-			  ssid.SSID, ssid.SSID_len);
-
-	brcmf_ch_to_chanspec(cfg->channel,
-			     &join_params, &join_params_size);
+	if (cfg->channel) {
+		join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
+		join_params.params_le.chanspec_num = cpu_to_le32(1);
+		join_params_size += sizeof(join_params.params_le);
+	}
 	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
 				     &join_params, join_params_size);
 	if (err)
-		brcmf_err("WLC_SET_SSID failed (%d)\n", err);
+		brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
 
 done:
 	if (err)
@@ -1939,7 +2200,7 @@
 			goto done;
 		}
 		/* Report the current tx rate */
-	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
+		err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
 		if (err) {
 			brcmf_err("Could not get rate (%d)\n", err);
 			goto done;
@@ -2011,67 +2272,6 @@
 	return err;
 }
 
-static s32
-brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
-			     const u8 *addr,
-			     const struct cfg80211_bitrate_mask *mask)
-{
-	struct brcmf_if *ifp = netdev_priv(ndev);
-	struct brcm_rateset_le rateset_le;
-	s32 rate;
-	s32 val;
-	s32 err_bg;
-	s32 err_a;
-	u32 legacy;
-	s32 err = 0;
-
-	brcmf_dbg(TRACE, "Enter\n");
-	if (!check_vif_up(ifp->vif))
-		return -EIO;
-
-	/* addr param is always NULL. ignore it */
-	/* Get current rateset */
-	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET,
-				     &rateset_le, sizeof(rateset_le));
-	if (err) {
-		brcmf_err("could not get current rateset (%d)\n", err);
-		goto done;
-	}
-
-	legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
-	if (!legacy)
-		legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
-			     0xFFFF);
-
-	val = wl_g_rates[legacy - 1].bitrate * 100000;
-
-	if (val < le32_to_cpu(rateset_le.count))
-		/* Select rate by rateset index */
-		rate = rateset_le.rates[val] & 0x7f;
-	else
-		/* Specified rate in bps */
-		rate = val / 500000;
-
-	brcmf_dbg(CONN, "rate %d mbps\n", rate / 2);
-
-	/*
-	 *
-	 *      Set rate override,
-	 *      Since the is a/b/g-blind, both a/bg_rate are enforced.
-	 */
-	err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
-	err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
-	if (err_bg && err_a) {
-		brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg,
-			  err_a);
-		err = err_bg | err_a;
-	}
-
-done:
-	brcmf_dbg(TRACE, "Exit\n");
-	return err;
-}
-
 static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
 				   struct brcmf_bss_info_le *bi)
 {
@@ -2123,7 +2323,7 @@
 	if (!bss)
 		return -ENOMEM;
 
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(wiphy, bss);
 
 	return err;
 }
@@ -2229,7 +2429,7 @@
 		goto CleanUp;
 	}
 
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(wiphy, bss);
 
 CleanUp:
 
@@ -2245,78 +2445,10 @@
 	return vif->mode == WL_MODE_IBSS;
 }
 
-/*
- * Traverse a string of 1-byte tag/1-byte length/variable-length value
- * triples, returning a pointer to the substring whose first element
- * matches tag
- */
-static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
+				 struct brcmf_if *ifp)
 {
-	struct brcmf_tlv *elt;
-	int totlen;
-
-	elt = (struct brcmf_tlv *) buf;
-	totlen = buflen;
-
-	/* find tagged parameter */
-	while (totlen >= TLV_HDR_LEN) {
-		int len = elt->len;
-
-		/* validate remaining totlen */
-		if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
-			return elt;
-
-		elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
-		totlen -= (len + TLV_HDR_LEN);
-	}
-
-	return NULL;
-}
-
-/* Is any of the tlvs the expected entry? If
- * not update the tlvs buffer pointer/length.
- */
-static bool
-brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
-		 u8 *oui, u32 oui_len, u8 type)
-{
-	/* If the contents match the OUI and the type */
-	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
-	    !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
-	    type == ie[TLV_BODY_OFF + oui_len]) {
-		return true;
-	}
-
-	if (tlvs == NULL)
-		return false;
-	/* point to the next ie */
-	ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
-	/* calculate the length of the rest of the buffer */
-	*tlvs_len -= (int)(ie - *tlvs);
-	/* update the pointer to the start of the buffer */
-	*tlvs = ie;
-
-	return false;
-}
-
-static struct brcmf_vs_tlv *
-brcmf_find_wpaie(u8 *parse, u32 len)
-{
-	struct brcmf_tlv *ie;
-
-	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
-		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
-				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
-			return (struct brcmf_vs_tlv *)ie;
-	}
-	return NULL;
-}
-
-static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
-{
-	struct net_device *ndev = cfg_to_ndev(cfg);
-	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
-	struct brcmf_if *ifp = netdev_priv(ndev);
+	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
 	struct brcmf_bss_info_le *bi;
 	struct brcmf_ssid *ssid;
 	struct brcmf_tlv *tim;
@@ -2372,7 +2504,7 @@
 	return err;
 }
 
-static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
 {
 	struct escan_info *escan = &cfg->escan_info;
 
@@ -2391,8 +2523,7 @@
 			container_of(work, struct brcmf_cfg80211_info,
 				     escan_timeout_work);
 
-	brcmf_notify_escan_complete(cfg,
-		cfg->escan_info.ndev, true, true);
+	brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
 }
 
 static void brcmf_escan_timeout(unsigned long data)
@@ -2469,11 +2600,6 @@
 			brcmf_err("Invalid escan result (NULL pointer)\n");
 			goto exit;
 		}
-		if (!cfg->scan_request) {
-			brcmf_dbg(SCAN, "result without cfg80211 request\n");
-			goto exit;
-		}
-
 		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
 			brcmf_err("Invalid bss_count %d: ignoring\n",
 				  escan_result_le->bss_count);
@@ -2481,6 +2607,14 @@
 		}
 		bss_info_le = &escan_result_le->bss_info_le;
 
+		if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
+			goto exit;
+
+		if (!cfg->scan_request) {
+			brcmf_dbg(SCAN, "result without cfg80211 request\n");
+			goto exit;
+		}
+
 		bi_length = le32_to_cpu(bss_info_le->length);
 		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
 					WL_ESCAN_RESULTS_FIXED_SIZE)) {
@@ -2519,6 +2653,8 @@
 		list->count++;
 	} else {
 		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+		if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
+			goto exit;
 		if (cfg->scan_request) {
 			cfg->bss_list = (struct brcmf_scan_results *)
 				cfg->escan_info.escan_buf;
@@ -2527,7 +2663,8 @@
 			brcmf_notify_escan_complete(cfg, ndev, aborted,
 						    false);
 		} else
-			brcmf_err("Unexpected scan result 0x%x\n", status);
+			brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
+				  status);
 	}
 exit:
 	return err;
@@ -3031,9 +3168,8 @@
 }
 #endif
 
-static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
+static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
 {
-	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err;
 
 	/* set auth */
@@ -3292,7 +3428,7 @@
 			  parsed_info->vndrie.oui[2],
 			  parsed_info->vndrie.oui_type);
 
-		if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
+		if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
 			break;
 next:
 		remaining_len -= (ie->len + TLV_HDR_LEN);
@@ -3326,7 +3462,6 @@
 	return ie_len + VNDR_IE_HDR_SIZE;
 }
 
-static
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
 			  const u8 *vndr_ie_buf, u32 vndr_ie_len)
 {
@@ -3358,24 +3493,28 @@
 	if (!iovar_ie_buf)
 		return -ENOMEM;
 	curr_ie_buf = iovar_ie_buf;
-	if (ifp->vif->mode == WL_MODE_AP) {
-		switch (pktflag) {
-		case VNDR_IE_PRBRSP_FLAG:
-			mgmt_ie_buf = saved_ie->probe_res_ie;
-			mgmt_ie_len = &saved_ie->probe_res_ie_len;
-			mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
-			break;
-		case VNDR_IE_BEACON_FLAG:
-			mgmt_ie_buf = saved_ie->beacon_ie;
-			mgmt_ie_len = &saved_ie->beacon_ie_len;
-			mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
-			break;
-		default:
-			err = -EPERM;
-			brcmf_err("not suitable type\n");
-			goto exit;
-		}
-	} else {
+	switch (pktflag) {
+	case BRCMF_VNDR_IE_PRBREQ_FLAG:
+		mgmt_ie_buf = saved_ie->probe_req_ie;
+		mgmt_ie_len = &saved_ie->probe_req_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
+		break;
+	case BRCMF_VNDR_IE_PRBRSP_FLAG:
+		mgmt_ie_buf = saved_ie->probe_res_ie;
+		mgmt_ie_len = &saved_ie->probe_res_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
+		break;
+	case BRCMF_VNDR_IE_BEACON_FLAG:
+		mgmt_ie_buf = saved_ie->beacon_ie;
+		mgmt_ie_len = &saved_ie->beacon_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
+		break;
+	case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
+		mgmt_ie_buf = saved_ie->assoc_req_ie;
+		mgmt_ie_len = &saved_ie->assoc_req_ie_len;
+		mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
+		break;
+	default:
 		err = -EPERM;
 		brcmf_err("not suitable type\n");
 		goto exit;
@@ -3484,6 +3623,49 @@
 	return err;
 }
 
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
+{
+	s32 pktflags[] = {
+		BRCMF_VNDR_IE_PRBREQ_FLAG,
+		BRCMF_VNDR_IE_PRBRSP_FLAG,
+		BRCMF_VNDR_IE_BEACON_FLAG
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pktflags); i++)
+		brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
+
+	memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
+	return 0;
+}
+
+static s32
+brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
+			struct cfg80211_beacon_data *beacon)
+{
+	s32 err;
+
+	/* Set Beacon IEs to FW */
+	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
+				    beacon->tail, beacon->tail_len);
+	if (err) {
+		brcmf_err("Set Beacon IE Failed\n");
+		return err;
+	}
+	brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
+
+	/* Set Probe Response IEs to FW */
+	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
+				    beacon->proberesp_ies,
+				    beacon->proberesp_ies_len);
+	if (err)
+		brcmf_err("Set Probe Resp IE Failed\n");
+	else
+		brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+
+	return err;
+}
+
 static s32
 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 			struct cfg80211_ap_settings *settings)
@@ -3496,7 +3678,8 @@
 	struct brcmf_tlv *rsn_ie;
 	struct brcmf_vs_tlv *wpa_ie;
 	struct brcmf_join_params join_params;
-	s32 bssidx = 0;
+	enum nl80211_iftype dev_role;
+	struct brcmf_fil_bss_enable_le bss_enable;
 
 	brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
 		  cfg80211_get_chandef_type(&settings->chandef),
@@ -3506,10 +3689,7 @@
 		  settings->ssid, settings->ssid_len, settings->auth_type,
 		  settings->inactivity_timeout);
 
-	if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
-		brcmf_err("Not in AP creation mode\n");
-		return -EPERM;
-	}
+	dev_role = ifp->vif->wdev.iftype;
 
 	memset(&ssid_le, 0, sizeof(ssid_le));
 	if (settings->ssid == NULL || settings->ssid_len == 0) {
@@ -3530,21 +3710,6 @@
 	}
 
 	brcmf_set_mpc(ndev, 0);
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
-	if (err < 0) {
-		brcmf_err("BRCMF_C_DOWN error %d\n", err);
-		goto exit;
-	}
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
-	if (err < 0) {
-		brcmf_err("SET INFRA error %d\n", err);
-		goto exit;
-	}
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
-	if (err < 0) {
-		brcmf_err("setting AP mode failed %d\n", err);
-		goto exit;
-	}
 
 	/* find the RSN_IE */
 	rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@@ -3570,27 +3735,10 @@
 		}
 	} else {
 		brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
-		brcmf_configure_opensecurity(ndev, bssidx);
+		brcmf_configure_opensecurity(ifp);
 	}
-	/* Set Beacon IEs to FW */
-	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
-				    VNDR_IE_BEACON_FLAG,
-				    settings->beacon.tail,
-				    settings->beacon.tail_len);
-	if (err)
-		brcmf_err("Set Beacon IE Failed\n");
-	else
-		brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
 
-	/* Set Probe Response IEs to FW */
-	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
-				    VNDR_IE_PRBRSP_FLAG,
-				    settings->beacon.proberesp_ies,
-				    settings->beacon.proberesp_ies_len);
-	if (err)
-		brcmf_err("Set Probe Resp IE Failed\n");
-	else
-		brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+	brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
 
 	if (settings->beacon_interval) {
 		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
@@ -3608,22 +3756,62 @@
 			goto exit;
 		}
 	}
-	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
-	if (err < 0) {
-		brcmf_err("BRCMF_C_UP error (%d)\n", err);
-		goto exit;
+
+	if (dev_role == NL80211_IFTYPE_AP) {
+		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
+		if (err < 0) {
+			brcmf_err("BRCMF_C_DOWN error %d\n", err);
+			goto exit;
+		}
+		brcmf_fil_iovar_int_set(ifp, "apsta", 0);
 	}
 
-	memset(&join_params, 0, sizeof(join_params));
-	/* join parameters starts with ssid */
-	memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
-	/* create softap */
-	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
-				     &join_params, sizeof(join_params));
+	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
 	if (err < 0) {
-		brcmf_err("SET SSID error (%d)\n", err);
+		brcmf_err("SET INFRA error %d\n", err);
 		goto exit;
 	}
+	if (dev_role == NL80211_IFTYPE_AP) {
+		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
+		if (err < 0) {
+			brcmf_err("setting AP mode failed %d\n", err);
+			goto exit;
+		}
+		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
+		if (err < 0) {
+			brcmf_err("BRCMF_C_UP error (%d)\n", err);
+			goto exit;
+		}
+
+		memset(&join_params, 0, sizeof(join_params));
+		/* join parameters starts with ssid */
+		memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
+		/* create softap */
+		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+					     &join_params, sizeof(join_params));
+		if (err < 0) {
+			brcmf_err("SET SSID error (%d)\n", err);
+			goto exit;
+		}
+		brcmf_dbg(TRACE, "AP mode configuration complete\n");
+	} else {
+		err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
+						sizeof(ssid_le));
+		if (err < 0) {
+			brcmf_err("setting ssid failed %d\n", err);
+			goto exit;
+		}
+		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+		bss_enable.enable = cpu_to_le32(1);
+		err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+					       sizeof(bss_enable));
+		if (err < 0) {
+			brcmf_err("bss_enable config failed %d\n", err);
+			goto exit;
+		}
+
+		brcmf_dbg(TRACE, "GO mode configuration complete\n");
+	}
 	clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
 	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
 
@@ -3637,10 +3825,11 @@
 {
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err = -EPERM;
+	struct brcmf_fil_bss_enable_le bss_enable;
 
 	brcmf_dbg(TRACE, "Enter\n");
 
-	if (ifp->vif->mode == WL_MODE_AP) {
+	if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
 		/* Due to most likely deauths outstanding we sleep */
 		/* first to make sure they get processed by fw. */
 		msleep(400);
@@ -3654,18 +3843,41 @@
 			brcmf_err("BRCMF_C_UP error %d\n", err);
 			goto exit;
 		}
-		brcmf_set_mpc(ndev, 1);
-		clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
-		clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+	} else {
+		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+		bss_enable.enable = cpu_to_le32(0);
+		err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+					       sizeof(bss_enable));
+		if (err < 0)
+			brcmf_err("bss_enable config failed %d\n", err);
 	}
+	brcmf_set_mpc(ndev, 1);
+	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
 exit:
 	return err;
 }
 
+static s32
+brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
+			     struct cfg80211_beacon_data *info)
+{
+	struct brcmf_if *ifp = netdev_priv(ndev);
+	s32 err;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
+
+	return err;
+}
+
 static int
 brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
 			   u8 *mac)
 {
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 	struct brcmf_scb_val_le scbval;
 	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err;
@@ -3675,6 +3887,8 @@
 
 	brcmf_dbg(TRACE, "Enter %pM\n", mac);
 
+	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+		ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
 	if (!check_vif_up(ifp->vif))
 		return -EIO;
 
@@ -3689,7 +3903,147 @@
 	return err;
 }
 
+
+static void
+brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+				   struct wireless_dev *wdev,
+				   u16 frame_type, bool reg)
+{
+	struct brcmf_if *ifp = netdev_priv(wdev->netdev);
+	struct brcmf_cfg80211_vif *vif = ifp->vif;
+	u16 mgmt_type;
+
+	brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
+
+	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+	if (reg)
+		vif->mgmt_rx_reg |= BIT(mgmt_type);
+	else
+		vif->mgmt_rx_reg &= ~BIT(mgmt_type);
+}
+
+
+static int
+brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+		       struct ieee80211_channel *chan, bool offchan,
+		       unsigned int wait, const u8 *buf, size_t len,
+		       bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	const struct ieee80211_mgmt *mgmt;
+	struct brcmf_if *ifp;
+	struct brcmf_cfg80211_vif *vif;
+	s32 err = 0;
+	s32 ie_offset;
+	s32 ie_len;
+	struct brcmf_fil_action_frame_le *action_frame;
+	struct brcmf_fil_af_params_le *af_params;
+	bool ack;
+	s32 chan_nr;
+
+	brcmf_dbg(TRACE, "Enter\n");
+
+	*cookie = 0;
+
+	mgmt = (const struct ieee80211_mgmt *)buf;
+
+	if (!ieee80211_is_mgmt(mgmt->frame_control)) {
+		brcmf_err("Driver only allows MGMT packet type\n");
+		return -EPERM;
+	}
+
+	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+		/* Right now the only reason to get a probe response */
+		/* is for p2p listen response or for p2p GO from     */
+		/* wpa_supplicant. Unfortunately the probe is send   */
+		/* on primary ndev, while dongle wants it on the p2p */
+		/* vif. Since this is only reason for a probe        */
+		/* response to be sent, the vif is taken from cfg.   */
+		/* If ever desired to send proberesp for non p2p     */
+		/* response then data should be checked for          */
+		/* "DIRECT-". Note in future supplicant will take    */
+		/* dedicated p2p wdev to do this and then this 'hack'*/
+		/* is not needed anymore.                            */
+		ie_offset =  DOT11_MGMT_HDR_LEN +
+			     DOT11_BCN_PRB_FIXED_LEN;
+		ie_len = len - ie_offset;
+		ifp = netdev_priv(wdev->netdev);
+		vif = ifp->vif;
+		if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
+			vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+		err = brcmf_vif_set_mgmt_ie(vif,
+					    BRCMF_VNDR_IE_PRBRSP_FLAG,
+					    &buf[ie_offset],
+					    ie_len);
+		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
+					GFP_KERNEL);
+	} else if (ieee80211_is_action(mgmt->frame_control)) {
+		af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
+		if (af_params == NULL) {
+			brcmf_err("unable to allocate frame\n");
+			err = -ENOMEM;
+			goto exit;
+		}
+		action_frame = &af_params->action_frame;
+		/* Add the packet Id */
+		action_frame->packet_id = cpu_to_le32(*cookie);
+		/* Add BSSID */
+		memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
+		memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
+		/* Add the length exepted for 802.11 header  */
+		action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
+		/* Add the channel */
+		chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
+		af_params->channel = cpu_to_le32(chan_nr);
+
+		memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
+		       le16_to_cpu(action_frame->len));
+
+		brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
+			  *cookie, le16_to_cpu(action_frame->len),
+			  chan->center_freq);
+
+		ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
+						  af_params);
+
+		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
+					GFP_KERNEL);
+		kfree(af_params);
+	} else {
+		brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
+		brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
+	}
+
+exit:
+	return err;
+}
+
+
+static int
+brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					u64 cookie)
+{
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct brcmf_cfg80211_vif *vif;
+	int err = 0;
+
+	brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
+
+	vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+	if (vif == NULL) {
+		brcmf_err("No p2p device available for probe response\n");
+		err = -ENODEV;
+		goto exit;
+	}
+	brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+exit:
+	return err;
+}
+
 static struct cfg80211_ops wl_cfg80211_ops = {
+	.add_virtual_intf = brcmf_cfg80211_add_iface,
+	.del_virtual_intf = brcmf_cfg80211_del_iface,
 	.change_virtual_intf = brcmf_cfg80211_change_iface,
 	.scan = brcmf_cfg80211_scan,
 	.set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
@@ -3704,7 +4058,6 @@
 	.set_default_key = brcmf_cfg80211_config_default_key,
 	.set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
 	.set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
-	.set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
 	.connect = brcmf_cfg80211_connect,
 	.disconnect = brcmf_cfg80211_disconnect,
 	.suspend = brcmf_cfg80211_suspend,
@@ -3714,28 +4067,43 @@
 	.flush_pmksa = brcmf_cfg80211_flush_pmksa,
 	.start_ap = brcmf_cfg80211_start_ap,
 	.stop_ap = brcmf_cfg80211_stop_ap,
+	.change_beacon = brcmf_cfg80211_change_beacon,
 	.del_station = brcmf_cfg80211_del_station,
 	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
 	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
+	.mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+	.mgmt_tx = brcmf_cfg80211_mgmt_tx,
+	.remain_on_channel = brcmf_p2p_remain_on_channel,
+	.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
 #ifdef CONFIG_NL80211_TESTMODE
 	.testmode_cmd = brcmf_cfg80211_testmode
 #endif
 };
 
-static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
+static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
 {
-	s32 err = 0;
-
-	switch (mode) {
-	case WL_MODE_BSS:
-		return NL80211_IFTYPE_STATION;
-	case WL_MODE_IBSS:
-		return NL80211_IFTYPE_ADHOC;
+	switch (type) {
+	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_WDS:
+	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_MESH_POINT:
+		return -ENOTSUPP;
+	case NL80211_IFTYPE_ADHOC:
+		return WL_MODE_IBSS;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		return WL_MODE_BSS;
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		return WL_MODE_AP;
+	case NL80211_IFTYPE_P2P_DEVICE:
+		return WL_MODE_P2P;
+	case NL80211_IFTYPE_UNSPECIFIED:
 	default:
-		return NL80211_IFTYPE_UNSPECIFIED;
+		break;
 	}
 
-	return err;
+	return -EINVAL;
 }
 
 static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
@@ -3747,6 +4115,56 @@
 	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 }
 
+static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_STATION) |
+			 BIT(NL80211_IFTYPE_ADHOC) |
+			 BIT(NL80211_IFTYPE_AP)
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			 BIT(NL80211_IFTYPE_P2P_GO)
+	},
+};
+static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
+	{
+		 .max_interfaces = BRCMF_IFACE_MAX_CNT,
+		 .num_different_channels = 1, /* no multi-channel for now */
+		 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
+		 .limits = brcmf_iface_limits
+	}
+};
+
+static const struct ieee80211_txrx_stypes
+brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+	[NL80211_IFTYPE_STATION] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+	},
+	[NL80211_IFTYPE_P2P_CLIENT] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+	},
+	[NL80211_IFTYPE_P2P_GO] = {
+		.tx = 0xffff,
+		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+		      BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+		      BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+		      BIT(IEEE80211_STYPE_AUTH >> 4) |
+		      BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+		      BIT(IEEE80211_STYPE_ACTION >> 4)
+	}
+};
+
 static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
 {
 	struct wiphy *wiphy;
@@ -3759,10 +4177,16 @@
 	}
 	set_wiphy_dev(wiphy, phydev);
 	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+	wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
 	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 				 BIT(NL80211_IFTYPE_ADHOC) |
-				 BIT(NL80211_IFTYPE_AP);
+				 BIT(NL80211_IFTYPE_AP) |
+				 BIT(NL80211_IFTYPE_P2P_CLIENT) |
+				 BIT(NL80211_IFTYPE_P2P_GO) |
+				 BIT(NL80211_IFTYPE_P2P_DEVICE);
+	wiphy->iface_combinations = brcmf_iface_combos;
+	wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
 	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
 	wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set
 						* it as 11a by default.
@@ -3774,10 +4198,11 @@
 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 	wiphy->cipher_suites = __wl_cipher_suites;
 	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;	/* enable power
-								 * save mode
-								 * by default
-								 */
+	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+			WIPHY_FLAG_OFFCHAN_TX |
+			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+	wiphy->mgmt_stypes = brcmf_txrx_stypes;
+	wiphy->max_remain_on_channel_duration = 5000;
 	brcmf_wiphy_pno_params(wiphy);
 	err = wiphy_register(wiphy);
 	if (err < 0) {
@@ -3788,31 +4213,25 @@
 	return wiphy;
 }
 
-static
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
-					   struct net_device *netdev,
-					   s32 mode, bool pm_block)
+					   enum nl80211_iftype type,
+					   bool pm_block)
 {
 	struct brcmf_cfg80211_vif *vif;
 
 	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
 		return ERR_PTR(-ENOSPC);
 
+	brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
+		  sizeof(*vif));
 	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
 	if (!vif)
 		return ERR_PTR(-ENOMEM);
 
 	vif->wdev.wiphy = cfg->wiphy;
-	vif->wdev.netdev = netdev;
-	vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
+	vif->wdev.iftype = type;
 
-	if (netdev) {
-		vif->ifp = netdev_priv(netdev);
-		netdev->ieee80211_ptr = &vif->wdev;
-		SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
-	}
-
-	vif->mode = mode;
+	vif->mode = brcmf_nl80211_iftype_to_mode(type);
 	vif->pm_block = pm_block;
 	vif->roam_off = -1;
 
@@ -3823,7 +4242,7 @@
 	return vif;
 }
 
-static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 {
 	struct brcmf_cfg80211_info *cfg;
 	struct wiphy *wiphy;
@@ -3897,9 +4316,9 @@
 	conn_info->resp_ie_len = 0;
 }
 
-static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
+static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
+			       struct brcmf_if *ifp)
 {
-	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
 	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
 	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
 	u32 req_len;
@@ -3975,9 +4394,9 @@
 
 	brcmf_dbg(TRACE, "Enter\n");
 
-	brcmf_get_assoc_ies(cfg);
+	brcmf_get_assoc_ies(cfg, ifp);
 	memcpy(profile->bssid, e->addr, ETH_ALEN);
-	brcmf_update_bss_info(cfg);
+	brcmf_update_bss_info(cfg, ifp);
 
 	buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
 	if (buf == NULL) {
@@ -4032,9 +4451,11 @@
 	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
 			       &ifp->vif->sme_state)) {
 		if (completed) {
-			brcmf_get_assoc_ies(cfg);
+			brcmf_get_assoc_ies(cfg, ifp);
 			memcpy(profile->bssid, e->addr, ETH_ALEN);
-			brcmf_update_bss_info(cfg);
+			brcmf_update_bss_info(cfg, ifp);
+			set_bit(BRCMF_VIF_STATUS_CONNECTED,
+				&ifp->vif->sme_state);
 		}
 		cfg80211_connect_result(ndev,
 					(u8 *)profile->bssid,
@@ -4045,9 +4466,6 @@
 					completed ? WLAN_STATUS_SUCCESS :
 						    WLAN_STATUS_AUTH_TIMEOUT,
 					GFP_KERNEL);
-		if (completed)
-			set_bit(BRCMF_VIF_STATUS_CONNECTED,
-				&ifp->vif->sme_state);
 		brcmf_dbg(CONN, "Report connect result - connection %s\n",
 			  completed ? "succeeded" : "failed");
 	}
@@ -4060,38 +4478,38 @@
 			       struct net_device *ndev,
 			       const struct brcmf_event_msg *e, void *data)
 {
-	s32 err = 0;
+	static int generation;
 	u32 event = e->event_code;
 	u32 reason = e->reason;
-	u32 len = e->datalen;
-	static int generation;
-
 	struct station_info sinfo;
 
 	brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
-	memset(&sinfo, 0, sizeof(sinfo));
+	if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
+	    ndev != cfg_to_ndev(cfg)) {
+		brcmf_dbg(CONN, "AP mode link down\n");
+		complete(&cfg->vif_disabled);
+		return 0;
+	}
 
-	sinfo.filled = 0;
 	if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
-	    reason == BRCMF_E_STATUS_SUCCESS) {
+	    (reason == BRCMF_E_STATUS_SUCCESS)) {
+		memset(&sinfo, 0, sizeof(sinfo));
 		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
 		if (!data) {
 			brcmf_err("No IEs present in ASSOC/REASSOC_IND");
 			return -EINVAL;
 		}
 		sinfo.assoc_req_ies = data;
-		sinfo.assoc_req_ies_len = len;
+		sinfo.assoc_req_ies_len = e->datalen;
 		generation++;
 		sinfo.generation = generation;
-		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
+		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
 	} else if ((event == BRCMF_E_DISASSOC_IND) ||
 		   (event == BRCMF_E_DEAUTH_IND) ||
 		   (event == BRCMF_E_DEAUTH)) {
-		generation++;
-		sinfo.generation = generation;
-		cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
+		cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
 	}
-	return err;
+	return 0;
 }
 
 static s32
@@ -4128,6 +4546,8 @@
 		}
 		brcmf_link_down(ifp->vif);
 		brcmf_init_prof(ndev_to_prof(ndev));
+		if (ndev != cfg_to_ndev(cfg))
+			complete(&cfg->vif_disabled);
 	} else if (brcmf_is_nonetwork(cfg, e)) {
 		if (brcmf_is_ibssmode(ifp->vif))
 			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
@@ -4176,6 +4596,57 @@
 	return 0;
 }
 
+static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
+				  const struct brcmf_event_msg *e, void *data)
+{
+	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+	struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+	struct brcmf_cfg80211_vif *vif;
+
+	brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
+		  ifevent->action, ifevent->flags, ifevent->ifidx,
+		  ifevent->bssidx);
+
+	mutex_lock(&event->vif_event_lock);
+	event->action = ifevent->action;
+	vif = event->vif;
+
+	switch (ifevent->action) {
+	case BRCMF_E_IF_ADD:
+		/* waiting process may have timed out */
+		if (!cfg->vif_event.vif)
+			return -EBADF;
+
+		ifp->vif = vif;
+		vif->ifp = ifp;
+		vif->wdev.netdev = ifp->ndev;
+		ifp->ndev->ieee80211_ptr = &vif->wdev;
+		SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+		mutex_unlock(&event->vif_event_lock);
+		wake_up(&event->vif_wq);
+		return 0;
+
+	case BRCMF_E_IF_DEL:
+		ifp->vif = NULL;
+		mutex_unlock(&event->vif_event_lock);
+		/* event may not be upon user request */
+		if (brcmf_cfg80211_vif_event_armed(cfg))
+			wake_up(&event->vif_wq);
+		return 0;
+
+	case BRCMF_E_IF_CHANGE:
+		mutex_unlock(&event->vif_event_lock);
+		wake_up(&event->vif_wq);
+		return 0;
+
+	default:
+		mutex_unlock(&event->vif_event_lock);
+		break;
+	}
+	return -EINVAL;
+}
+
 static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
 {
 	conf->frag_threshold = (u32)-1;
@@ -4207,6 +4678,18 @@
 			    brcmf_notify_connect_status);
 	brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
 			    brcmf_notify_sched_scan_results);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
+			    brcmf_notify_vif_event);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
+			    brcmf_p2p_notify_rx_mgmt_p2p_probereq);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
+			    brcmf_p2p_notify_listen_complete);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
+			    brcmf_p2p_notify_action_frame_rx);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
+			    brcmf_p2p_notify_action_tx_complete);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
+			    brcmf_p2p_notify_action_tx_complete);
 }
 
 static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -4262,7 +4745,7 @@
 	mutex_init(&cfg->usr_sync);
 	brcmf_init_escan(cfg);
 	brcmf_init_conf(cfg->conf);
-
+	init_completion(&cfg->vif_disabled);
 	return err;
 }
 
@@ -4273,6 +4756,12 @@
 	brcmf_deinit_priv_mem(cfg);
 }
 
+static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
+{
+	init_waitqueue_head(&event->vif_wq);
+	mutex_init(&event->vif_event_lock);
+}
+
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
 						  struct device *busdev)
 {
@@ -4296,25 +4785,41 @@
 	cfg = wiphy_priv(wiphy);
 	cfg->wiphy = wiphy;
 	cfg->pub = drvr;
+	init_vif_event(&cfg->vif_event);
 	INIT_LIST_HEAD(&cfg->vif_list);
 
-	vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
+	vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
 	if (IS_ERR(vif)) {
 		wiphy_free(wiphy);
 		return NULL;
 	}
 
+	vif->ifp = ifp;
+	vif->wdev.netdev = ndev;
+	ndev->ieee80211_ptr = &vif->wdev;
+	SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
+
 	err = wl_init_priv(cfg);
 	if (err) {
 		brcmf_err("Failed to init iwm_priv (%d)\n", err);
 		goto cfg80211_attach_out;
 	}
-
 	ifp->vif = vif;
+
+	err = brcmf_p2p_attach(cfg);
+	if (err) {
+		brcmf_err("P2P initilisation failed (%d)\n", err);
+		goto cfg80211_p2p_attach_out;
+	}
+
 	return cfg;
 
+cfg80211_p2p_attach_out:
+	wl_deinit_priv(cfg);
+
 cfg80211_attach_out:
 	brcmf_free_vif(vif);
+	wiphy_free(wiphy);
 	return NULL;
 }
 
@@ -4330,9 +4835,8 @@
 }
 
 static s32
-brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
 {
-	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err = 0;
 	__le32 roamtrigger[2];
 	__le32 roam_delta[2];
@@ -4383,10 +4887,9 @@
 }
 
 static s32
-brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
 		      s32 scan_unassoc_time, s32 scan_passive_time)
 {
-	struct brcmf_if *ifp = netdev_priv(ndev);
 	s32 err = 0;
 
 	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
@@ -4456,6 +4959,7 @@
 {
 	struct net_device *ndev;
 	struct wireless_dev *wdev;
+	struct brcmf_if *ifp;
 	s32 power_mode;
 	s32 err = 0;
 
@@ -4464,35 +4968,34 @@
 
 	ndev = cfg_to_ndev(cfg);
 	wdev = ndev->ieee80211_ptr;
+	ifp = netdev_priv(ndev);
 
-	brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
-			WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
+	/* make sure RF is ready for work */
+	brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+
+	brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
+			      WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
 
 	power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
-	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
-				    power_mode);
+	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
 	if (err)
 		goto default_conf_out;
 	brcmf_dbg(INFO, "power save set to %s\n",
 		  (power_mode ? "enabled" : "disabled"));
 
-	err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
-				WL_BEACON_TIMEOUT);
+	err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
 	if (err)
 		goto default_conf_out;
 	err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
 					  NULL, NULL);
-	if (err && err != -EINPROGRESS)
+	if (err)
 		goto default_conf_out;
 	err = brcmf_dongle_probecap(cfg);
 	if (err)
 		goto default_conf_out;
 
-	/* -EINPROGRESS: Call commit handler */
-
-default_conf_out:
-
 	cfg->dongle_up = true;
+default_conf_out:
 
 	return err;
 
@@ -4501,8 +5004,6 @@
 static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
 {
 	set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
-	if (ifp->idx)
-		return 0;
 
 	return brcmf_config_dongle(ifp->drvr->config);
 }
@@ -4557,3 +5058,57 @@
 	return err;
 }
 
+u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
+{
+	struct brcmf_cfg80211_vif *vif;
+	bool result = 0;
+
+	list_for_each_entry(vif, &cfg->vif_list, list) {
+		if (test_bit(state, &vif->sme_state))
+			result++;
+	}
+	return result;
+}
+
+static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
+				    u8 action)
+{
+	u8 evt_action;
+
+	mutex_lock(&event->vif_event_lock);
+	evt_action = event->action;
+	mutex_unlock(&event->vif_event_lock);
+	return evt_action == action;
+}
+
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+				  struct brcmf_cfg80211_vif *vif)
+{
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+	mutex_lock(&event->vif_event_lock);
+	event->vif = vif;
+	event->action = 0;
+	mutex_unlock(&event->vif_event_lock);
+}
+
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
+{
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+	bool armed;
+
+	mutex_lock(&event->vif_event_lock);
+	armed = event->vif != NULL;
+	mutex_unlock(&event->vif_event_lock);
+
+	return armed;
+}
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+					  u8 action, ulong timeout)
+{
+	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+	return wait_event_timeout(event->vif_wq,
+				  vif_event_equals(event, action), timeout);
+}
+
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index e4d9cc7..8b5d498 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -41,6 +41,38 @@
 #define WL_AUTH_SHARED_KEY		1	/* d11 shared authentication */
 #define IE_MAX_LEN			512
 
+/* IE TLV processing */
+#define TLV_LEN_OFF			1	/* length offset */
+#define TLV_HDR_LEN			2	/* header length */
+#define TLV_BODY_OFF			2	/* body offset */
+#define TLV_OUI_LEN			3	/* oui id length */
+
+/* 802.11 Mgmt Packet flags */
+#define BRCMF_VNDR_IE_BEACON_FLAG	0x1
+#define BRCMF_VNDR_IE_PRBRSP_FLAG	0x2
+#define BRCMF_VNDR_IE_ASSOCRSP_FLAG	0x4
+#define BRCMF_VNDR_IE_AUTHRSP_FLAG	0x8
+#define BRCMF_VNDR_IE_PRBREQ_FLAG	0x10
+#define BRCMF_VNDR_IE_ASSOCREQ_FLAG	0x20
+/* vendor IE in IW advertisement protocol ID field */
+#define BRCMF_VNDR_IE_IWAPID_FLAG	0x40
+/* allow custom IE id */
+#define BRCMF_VNDR_IE_CUSTOM_FLAG	0x100
+
+/* P2P Action Frames flags (spec ordered) */
+#define BRCMF_VNDR_IE_GONREQ_FLAG     0x001000
+#define BRCMF_VNDR_IE_GONRSP_FLAG     0x002000
+#define BRCMF_VNDR_IE_GONCFM_FLAG     0x004000
+#define BRCMF_VNDR_IE_INVREQ_FLAG     0x008000
+#define BRCMF_VNDR_IE_INVRSP_FLAG     0x010000
+#define BRCMF_VNDR_IE_DISREQ_FLAG     0x020000
+#define BRCMF_VNDR_IE_DISRSP_FLAG     0x040000
+#define BRCMF_VNDR_IE_PRDREQ_FLAG     0x080000
+#define BRCMF_VNDR_IE_PRDRSP_FLAG     0x100000
+
+#define BRCMF_VNDR_IE_P2PAF_SHIFT	12
+
+
 /**
  * enum brcmf_scan_status - dongle scan status
  *
@@ -52,11 +84,19 @@
 	BRCMF_SCAN_STATUS_ABORT,
 };
 
-/* wi-fi mode */
+/**
+ * enum wl_mode - driver mode of virtual interface.
+ *
+ * @WL_MODE_BSS: connects to BSS.
+ * @WL_MODE_IBSS: operate as ad-hoc.
+ * @WL_MODE_AP: operate as access-point.
+ * @WL_MODE_P2P: provide P2P discovery.
+ */
 enum wl_mode {
 	WL_MODE_BSS,
 	WL_MODE_IBSS,
-	WL_MODE_AP
+	WL_MODE_AP,
+	WL_MODE_P2P
 };
 
 /* dongle configuration */
@@ -108,6 +148,7 @@
  * @BRCMF_VIF_STATUS_READY: ready for operation.
  * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
  * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
  * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
  * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
  */
@@ -115,6 +156,7 @@
 	BRCMF_VIF_STATUS_READY,
 	BRCMF_VIF_STATUS_CONNECTING,
 	BRCMF_VIF_STATUS_CONNECTED,
+	BRCMF_VIF_STATUS_DISCONNECTING,
 	BRCMF_VIF_STATUS_AP_CREATING,
 	BRCMF_VIF_STATUS_AP_CREATED
 };
@@ -122,16 +164,22 @@
 /**
  * struct vif_saved_ie - holds saved IEs for a virtual interface.
  *
+ * @probe_req_ie: IE info for probe request.
  * @probe_res_ie: IE info for probe response.
  * @beacon_ie: IE info for beacon frame.
+ * @probe_req_ie_len: IE info length for probe request.
  * @probe_res_ie_len: IE info length for probe response.
  * @beacon_ie_len: IE info length for beacon frame.
  */
 struct vif_saved_ie {
+	u8  probe_req_ie[IE_MAX_LEN];
 	u8  probe_res_ie[IE_MAX_LEN];
 	u8  beacon_ie[IE_MAX_LEN];
+	u8  assoc_req_ie[IE_MAX_LEN];
+	u32 probe_req_ie_len;
 	u32 probe_res_ie_len;
 	u32 beacon_ie_len;
+	u32 assoc_req_ie_len;
 };
 
 /**
@@ -145,6 +193,7 @@
  * @sme_state: SME state using enum brcmf_vif_status bits.
  * @pm_block: power-management blocked.
  * @list: linked list.
+ * @mgmt_rx_reg: registered rx mgmt frame types.
  */
 struct brcmf_cfg80211_vif {
 	struct brcmf_if *ifp;
@@ -156,6 +205,7 @@
 	bool pm_block;
 	struct vif_saved_ie saved_ie;
 	struct list_head list;
+	u16 mgmt_rx_reg;
 };
 
 /* association inform */
@@ -189,6 +239,9 @@
 	u8 escan_buf[WL_ESCAN_BUF_SIZE];
 	struct wiphy *wiphy;
 	struct net_device *ndev;
+	s32 (*run)(struct brcmf_cfg80211_info *cfg,
+		   struct net_device *ndev,
+		   struct cfg80211_scan_request *request, u16 action);
 };
 
 /**
@@ -273,10 +326,27 @@
 };
 
 /**
+ * struct brcmf_cfg80211_vif_event - virtual interface event information.
+ *
+ * @vif_wq: waitqueue awaiting interface event from firmware.
+ * @vif_event_lock: protects other members in this structure.
+ * @vif_complete: completion for net attach.
+ * @action: either add, change, or delete.
+ * @vif: virtual interface object related to the event.
+ */
+struct brcmf_cfg80211_vif_event {
+	wait_queue_head_t vif_wq;
+	struct mutex vif_event_lock;
+	u8 action;
+	struct brcmf_cfg80211_vif *vif;
+};
+
+/**
  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
  *
  * @wiphy: wiphy object for cfg80211 interface.
  * @conf: dongle configuration.
+ * @p2p: peer-to-peer specific information.
  * @scan_request: cfg80211 scan request object.
  * @usr_sync: mainly for dongle up/down synchronization.
  * @bss_list: bss_list holding scanned ap information.
@@ -304,10 +374,12 @@
  * @escan_ioctl_buf: dongle command buffer for escan commands.
  * @vif_list: linked list of vif instances.
  * @vif_cnt: number of vif instances.
+ * @vif_event: vif event signalling.
  */
 struct brcmf_cfg80211_info {
 	struct wiphy *wiphy;
 	struct brcmf_cfg80211_conf *conf;
+	struct brcmf_p2p_info p2p;
 	struct cfg80211_scan_request *scan_request;
 	struct mutex usr_sync;
 	struct brcmf_scan_results *bss_list;
@@ -335,6 +407,21 @@
 	u8 *escan_ioctl_buf;
 	struct list_head vif_list;
 	u8 vif_cnt;
+	struct brcmf_cfg80211_vif_event vif_event;
+	struct completion vif_disabled;
+};
+
+/**
+ * struct brcmf_tlv - tag_ID/length/value_buffer tuple.
+ *
+ * @id: tag identifier.
+ * @len: number of bytes in value buffer.
+ * @data: value buffer.
+ */
+struct brcmf_tlv {
+	u8 id;
+	u8 len;
+	u8 data[1];
 };
 
 static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
@@ -389,4 +476,26 @@
 s32 brcmf_cfg80211_up(struct net_device *ndev);
 s32 brcmf_cfg80211_down(struct net_device *ndev);
 
+struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
+					   enum nl80211_iftype type,
+					   bool pm_block);
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
+
+s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
+			  const u8 *vndr_ie_buf, u32 vndr_ie_len);
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
+struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
+u16 channel_to_chanspec(struct ieee80211_channel *ch);
+u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+				  struct brcmf_cfg80211_vif *vif);
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+					  u8 action, ulong timeout);
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+				struct net_device *ndev,
+				bool aborted, bool fw_abort);
+void brcmf_set_mpc(struct net_device *ndev, int mpc);
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
+
 #endif				/* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
index 1de94f3..1585cc5 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -961,7 +961,6 @@
 			/* if acked then clear bit and free packet */
 			if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
 			    && isset(bitmap, bindex)) {
-				ini->tx_in_transit--;
 				ini->txretry[index] = 0;
 
 				/*
@@ -990,7 +989,6 @@
 			if (retry && (ini->txretry[index] < (int)retry_limit)) {
 				int ret;
 				ini->txretry[index]++;
-				ini->tx_in_transit--;
 				ret = brcms_c_txfifo(wlc, queue, p);
 				/*
 				 * We shouldn't be out of space in the DMA
@@ -1000,7 +998,6 @@
 				WARN_ONCE(ret, "queue %d out of txds\n", queue);
 			} else {
 				/* Retry timeout */
-				ini->tx_in_transit--;
 				ieee80211_tx_info_clear_status(tx_info);
 				tx_info->status.ampdu_ack_len = 0;
 				tx_info->status.ampdu_len = 1;
@@ -1009,8 +1006,8 @@
 				skb_pull(p, D11_PHY_HDR_LEN);
 				skb_pull(p, D11_TXH_LEN);
 				brcms_dbg_ht(wlc->hw->d11core,
-					     "BA Timeout, seq %d, in_transit %d\n",
-					     seq, ini->tx_in_transit);
+					     "BA Timeout, seq %d\n",
+					     seq);
 				ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
 							    p);
 			}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index a90b722..10ee314 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -183,8 +183,7 @@
 	 * chars.
 	 */
 	if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
-	      (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A &&
-	      ccode[2] == '\0'))
+	      (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A))
 		return false;
 
 	/*
@@ -670,7 +669,7 @@
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *ch;
 	const struct ieee80211_reg_rule *rule;
-	int band, i, ret;
+	int band, i;
 
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 		sband = wiphy->bands[band];
@@ -685,9 +684,8 @@
 				continue;
 
 			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-				ret = freq_reg_info(wiphy, ch->center_freq,
-						    0, &rule);
-				if (ret)
+				rule = freq_reg_info(wiphy, ch->center_freq);
+				if (IS_ERR(rule))
 					continue;
 
 				if (!(rule->flags & NL80211_RRF_NO_IBSS))
@@ -703,8 +701,8 @@
 	}
 }
 
-static int brcms_reg_notifier(struct wiphy *wiphy,
-			      struct regulatory_request *request)
+static void brcms_reg_notifier(struct wiphy *wiphy,
+			       struct regulatory_request *request)
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct brcms_info *wl = hw->priv;
@@ -745,8 +743,6 @@
 	if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
 		wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
 					brcms_c_japan_ccode(request->alpha2));
-
-	return 0;
 }
 
 void brcms_c_regd_init(struct brcms_c_info *wlc)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index e5fd209..c6451c6 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -363,8 +363,11 @@
 		return -EOPNOTSUPP;
 	}
 
+	spin_lock_bh(&wl->lock);
+	memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
 	wl->mute_tx = false;
 	brcms_c_mute(wl->wlc, false);
+	spin_unlock_bh(&wl->lock);
 
 	return 0;
 }
@@ -540,9 +543,8 @@
 
 	if (changed & BSS_CHANGED_ARP_FILTER) {
 		/* Hardware ARP filter address list or state changed */
-		brcms_err(core, "%s: arp filtering: enabled %s, count %d"
-			  " (implement)\n", __func__, info->arp_filter_enabled ?
-			  "true" : "false", info->arp_addr_cnt);
+		brcms_err(core, "%s: arp filtering: %d addresses"
+			  " (implement)\n", __func__, info->arp_addr_cnt);
 	}
 
 	if (changed & BSS_CHANGED_QOS) {
@@ -669,7 +671,9 @@
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		spin_lock_bh(&wl->lock);
 		brcms_c_ampdu_flush(wl->wlc, sta, tid);
 		spin_unlock_bh(&wl->lock);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 8b58390..8ef02dc 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -101,8 +101,6 @@
 #define DOT11_RTS_LEN			16
 #define DOT11_CTS_LEN			10
 #define DOT11_BA_BITMAP_LEN		128
-#define DOT11_MIN_BEACON_PERIOD		1
-#define DOT11_MAX_BEACON_PERIOD		0xFFFF
 #define DOT11_MAXNUMFRAGS		16
 #define DOT11_MAX_FRAG_LEN		2346
 
@@ -2466,6 +2464,7 @@
 static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
 {
 	static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+	u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr;
 
 	if (mute_tx) {
 		/* suspend tx fifos */
@@ -2475,8 +2474,7 @@
 		brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
 
 		/* zero the address match register so we do not send ACKs */
-		brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
-				       null_ether_addr);
+		brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr);
 	} else {
 		/* resume tx fifos */
 		brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
@@ -2485,8 +2483,7 @@
 		brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
 
 		/* Restore address */
-		brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
-				       wlc_hw->etheraddr);
+		brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr);
 	}
 
 	wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
@@ -3141,8 +3138,7 @@
 	brcms_c_statsupd(wlc);
 
 	/* reset our snapshot of macstat counters */
-	memset((char *)wlc->core->macstat_snapshot, 0,
-		sizeof(struct macstat));
+	memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat));
 
 	brcms_b_reset(wlc->hw);
 }
@@ -4055,7 +4051,7 @@
 		return;
 	}
 
-	memset((char *)&acp_shm, 0, sizeof(struct shm_acparams));
+	memset(&acp_shm, 0, sizeof(struct shm_acparams));
 	/* fill in shm ac params struct */
 	acp_shm.txop = params->txop;
 	/* convert from units of 32us to us for ucode */
@@ -4771,7 +4767,7 @@
 	struct brcms_bss_info *bi = wlc->default_bss;
 
 	/* init default and target BSS with some sane initial values */
-	memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
+	memset(bi, 0, sizeof(*bi));
 	bi->beacon_period = BEACON_INTERVAL_DEFAULT;
 
 	/* fill the default channel as the first valid channel
@@ -5300,7 +5296,7 @@
 		brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
 
 	/* Clear rateset override */
-	memset(&rs, 0, sizeof(struct brcms_c_rateset));
+	memset(&rs, 0, sizeof(rs));
 
 	switch (gmode) {
 	case GMODE_LEGACY_B:
@@ -5523,7 +5519,7 @@
 	if (rs->count > BRCMS_NUMRATES)
 		return -ENOBUFS;
 
-	memset(&internal_rs, 0, sizeof(struct brcms_c_rateset));
+	memset(&internal_rs, 0, sizeof(internal_rs));
 
 	/* Copy only legacy rateset section */
 	internal_rs.count = rs->count;
@@ -5549,8 +5545,7 @@
 
 int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
 {
-	if (period < DOT11_MIN_BEACON_PERIOD ||
-	    period > DOT11_MAX_BEACON_PERIOD)
+	if (period == 0)
 		return -EINVAL;
 
 	wlc->default_bss->beacon_period = period;
@@ -5627,7 +5622,7 @@
 	for (i = 0; i < BRCMS_MAXMODULES; i++) {
 		if (!strcmp(wlc->modulecb[i].name, name) &&
 		    (wlc->modulecb[i].hdl == hdl)) {
-			memset(&wlc->modulecb[i], 0, sizeof(struct modulecb));
+			memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i]));
 			return 0;
 		}
 	}
@@ -6447,10 +6442,9 @@
 
 			if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
 			    && (!is_mcs_rate(rspec[k]))) {
-				brcms_err(wlc->hw->d11core,
-					  "wl%d: %s: IEEE80211_TX_"
-					  "RC_MCS != is_mcs_rate(rspec)\n",
-					  wlc->pub->unit, __func__);
+				brcms_warn(wlc->hw->d11core,
+					   "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n",
+					   wlc->pub->unit, __func__);
 			}
 
 			if (is_mcs_rate(rspec[k])) {
@@ -6683,11 +6677,9 @@
 					(struct ofdm_phy_hdr *) rts_plcp) :
 				rts_plcp[0]) << 8;
 	} else {
-		memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
-		memset((char *)&txh->rts_frame, 0,
-			sizeof(struct ieee80211_rts));
-		memset((char *)txh->RTSPLCPFallback, 0,
-		      sizeof(txh->RTSPLCPFallback));
+		memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
+		memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts));
+		memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback));
 		txh->RTSDurFallback = 0;
 	}
 
@@ -6842,21 +6834,19 @@
 					wlc->fragthresh[queue] =
 					    (u16) newfragthresh;
 			} else {
-				brcms_err(wlc->hw->d11core,
-					  "wl%d: %s txop invalid "
-					  "for rate %d\n",
-					  wlc->pub->unit, fifo_names[queue],
-					  rspec2rate(rspec[0]));
+				brcms_warn(wlc->hw->d11core,
+					   "wl%d: %s txop invalid for rate %d\n",
+					   wlc->pub->unit, fifo_names[queue],
+					   rspec2rate(rspec[0]));
 			}
 
 			if (dur > wlc->edcf_txop[ac])
-				brcms_err(wlc->hw->d11core,
-					  "wl%d: %s: %s txop "
-					  "exceeded phylen %d/%d dur %d/%d\n",
-					  wlc->pub->unit, __func__,
-					  fifo_names[queue],
-					  phylen, wlc->fragthresh[queue],
-					  dur, wlc->edcf_txop[ac]);
+				brcms_warn(wlc->hw->d11core,
+					   "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n",
+					   wlc->pub->unit, __func__,
+					   fifo_names[queue],
+					   phylen, wlc->fragthresh[queue],
+					   dur, wlc->edcf_txop[ac]);
 		}
 	}
 
@@ -7331,7 +7321,7 @@
 	*len = hdr_len + body_len;
 
 	/* format PHY and MAC headers */
-	memset((char *)buf, 0, hdr_len);
+	memset(buf, 0, hdr_len);
 
 	plcp = (struct cck_phy_hdr *) buf;
 
@@ -7402,9 +7392,13 @@
 			      struct brcms_bss_cfg *cfg,
 			      bool suspend)
 {
-	u16 prb_resp[BCN_TMPL_LEN / 2];
+	u16 *prb_resp;
 	int len = BCN_TMPL_LEN;
 
+	prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
+	if (!prb_resp)
+		return;
+
 	/*
 	 * write the probe response to hardware, or save in
 	 * the config structure
@@ -7438,6 +7432,8 @@
 
 	if (suspend)
 		brcms_c_enable_mac(wlc);
+
+	kfree(prb_resp);
 }
 
 void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
@@ -7617,7 +7613,7 @@
 
 	uint n = 0;
 	uint bound_limit = bound ? RXBND : -1;
-	bool morepending;
+	bool morepending = false;
 
 	skb_queue_head_init(&recv_frames);
 
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/scb.h b/drivers/net/wireless/brcm80211/brcmsmac/scb.h
index 51c79c7..3a3d736 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/scb.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/scb.h
@@ -36,7 +36,6 @@
 
 /* structure to store per-tid state for the ampdu initiator */
 struct scb_ampdu_tid_ini {
-	u8 tx_in_transit; /* number of pending mpdus in transit in driver */
 	u8 tid;		  /* initiator tid for easy lookup */
 	/* tx retry count; indexed by seq modulo */
 	u8 txretry[AMPDU_TX_BA_MAX_WSIZE];
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index c6ea995..dd9a18f 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -376,7 +376,7 @@
 
 	entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
 	if (entry == NULL)
-		return -1;
+		return -ENOMEM;
 
 	memcpy(entry->addr, mac, ETH_ALEN);
 
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index d92b21a..cb066f6 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -2181,9 +2181,10 @@
 	mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
 }
 
-static void send_scan_event(void *data)
+static void ipw2100_scan_event(struct work_struct *work)
 {
-	struct ipw2100_priv *priv = data;
+	struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv,
+						 scan_event.work);
 	union iwreq_data wrqu;
 
 	wrqu.data.length = 0;
@@ -2191,18 +2192,6 @@
 	wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
 }
 
-static void ipw2100_scan_event_later(struct work_struct *work)
-{
-	send_scan_event(container_of(work, struct ipw2100_priv,
-					scan_event_later.work));
-}
-
-static void ipw2100_scan_event_now(struct work_struct *work)
-{
-	send_scan_event(container_of(work, struct ipw2100_priv,
-					scan_event_now));
-}
-
 static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
 {
 	IPW_DEBUG_SCAN("scan complete\n");
@@ -2212,13 +2201,11 @@
 
 	/* Only userspace-requested scan completion events go out immediately */
 	if (!priv->user_requested_scan) {
-		if (!delayed_work_pending(&priv->scan_event_later))
-			schedule_delayed_work(&priv->scan_event_later,
-					      round_jiffies_relative(msecs_to_jiffies(4000)));
+		schedule_delayed_work(&priv->scan_event,
+				      round_jiffies_relative(msecs_to_jiffies(4000)));
 	} else {
 		priv->user_requested_scan = 0;
-		cancel_delayed_work(&priv->scan_event_later);
-		schedule_work(&priv->scan_event_now);
+		mod_delayed_work(system_wq, &priv->scan_event, 0);
 	}
 }
 
@@ -4459,8 +4446,7 @@
 	cancel_delayed_work_sync(&priv->wx_event_work);
 	cancel_delayed_work_sync(&priv->hang_check);
 	cancel_delayed_work_sync(&priv->rf_kill);
-	cancel_work_sync(&priv->scan_event_now);
-	cancel_delayed_work_sync(&priv->scan_event_later);
+	cancel_delayed_work_sync(&priv->scan_event);
 }
 
 static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
@@ -4478,13 +4464,10 @@
 		return err;
 	}
 
-	priv->tx_buffers =
-	    kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
-		    GFP_ATOMIC);
+	priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH,
+					 sizeof(struct ipw2100_tx_packet),
+					 GFP_ATOMIC);
 	if (!priv->tx_buffers) {
-		printk(KERN_ERR DRV_NAME
-		       ": %s: alloc failed form tx buffers.\n",
-		       priv->net_dev->name);
 		bd_queue_free(priv, &priv->tx_queue);
 		return -ENOMEM;
 	}
@@ -6195,8 +6178,7 @@
 	INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
 	INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
 	INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
-	INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
-	INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
+	INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
 
 	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
 		     ipw2100_irq_tasklet, (unsigned long)priv);
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index 5fe17cb..c6d7879 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
@@ -577,8 +577,7 @@
 	struct delayed_work wx_event_work;
 	struct delayed_work hang_check;
 	struct delayed_work rf_kill;
-	struct work_struct scan_event_now;
-	struct delayed_work scan_event_later;
+	struct delayed_work scan_event;
 
 	int user_requested_scan;
 
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 844f201..d96257b 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -4480,18 +4480,11 @@
 {
 	/* Only userspace-requested scan completion events go out immediately */
 	if (!priv->user_requested_scan) {
-		if (!delayed_work_pending(&priv->scan_event))
-			schedule_delayed_work(&priv->scan_event,
-					      round_jiffies_relative(msecs_to_jiffies(4000)));
+		schedule_delayed_work(&priv->scan_event,
+				      round_jiffies_relative(msecs_to_jiffies(4000)));
 	} else {
-		union iwreq_data wrqu;
-
 		priv->user_requested_scan = 0;
-		cancel_delayed_work(&priv->scan_event);
-
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+		mod_delayed_work(system_wq, &priv->scan_event, 0);
 	}
 }
 
@@ -11327,7 +11320,6 @@
 		if (!(priv->config & CFG_CUSTOM_MAC))
 			eeprom_parse_mac(priv, priv->mac_addr);
 		memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
-		memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN);
 
 		ipw_set_geo(priv);
 
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 3726cd6..3630a41 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -572,26 +572,11 @@
 	il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id);
 
 	/* Total # bytes to be transmitted */
-	len = (u16) skb->len;
-	tx_cmd->len = cpu_to_le16(len);
+	tx_cmd->len = cpu_to_le16((u16) skb->len);
 
-	il_update_stats(il, true, fc, len);
 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
 	tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
 
-	if (!ieee80211_has_morefrags(hdr->frame_control)) {
-		txq->need_update = 1;
-	} else {
-		wait_write_ptr = 1;
-		txq->need_update = 0;
-	}
-
-	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
-	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-	il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd));
-	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr,
-			  ieee80211_hdrlen(fc));
-
 	/*
 	 * Use the first empty entry in this queue's command buffer array
 	 * to contain the Tx command and MAC header concatenated together
@@ -610,14 +595,8 @@
 	 * within command buffer array. */
 	txcmd_phys =
 	    pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE);
-	/* we do not map meta data ... so we can safely access address to
-	 * provide to unmap command*/
-	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-	dma_unmap_len_set(out_meta, len, len);
-
-	/* Add buffer containing Tx command and MAC(!) header to TFD's
-	 * first entry */
-	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
+		goto drop_unlock;
 
 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 	 * if any (802.11 null frames have no payload). */
@@ -626,10 +605,34 @@
 		phys_addr =
 		    pci_map_single(il->pci_dev, skb->data + hdr_len, len,
 				   PCI_DMA_TODEVICE);
+		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
+			goto drop_unlock;
+	}
+
+	/* Add buffer containing Tx command and MAC(!) header to TFD's
+	 * first entry */
+	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	dma_unmap_len_set(out_meta, len, len);
+	if (len)
 		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
 					       U32_PAD(len));
+
+	if (!ieee80211_has_morefrags(hdr->frame_control)) {
+		txq->need_update = 1;
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
 	}
 
+	il_update_stats(il, true, fc, skb->len);
+
+	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
+	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+	il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd));
+	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr,
+			  ieee80211_hdrlen(fc));
+
 	/* Tell device the write idx *just past* this latest filled TFD */
 	q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd);
 	il_txq_update_write_ptr(il, txq);
@@ -1001,12 +1004,12 @@
 	struct list_head *element;
 	struct il_rx_buf *rxb;
 	struct page *page;
+	dma_addr_t page_dma;
 	unsigned long flags;
 	gfp_t gfp_mask = priority;
 
 	while (1) {
 		spin_lock_irqsave(&rxq->lock, flags);
-
 		if (list_empty(&rxq->rx_used)) {
 			spin_unlock_irqrestore(&rxq->lock, flags);
 			return;
@@ -1035,26 +1038,34 @@
 			break;
 		}
 
-		spin_lock_irqsave(&rxq->lock, flags);
-		if (list_empty(&rxq->rx_used)) {
-			spin_unlock_irqrestore(&rxq->lock, flags);
-			__free_pages(page, il->hw_params.rx_page_order);
-			return;
-		}
-		element = rxq->rx_used.next;
-		rxb = list_entry(element, struct il_rx_buf, list);
-		list_del(element);
-		spin_unlock_irqrestore(&rxq->lock, flags);
-
-		rxb->page = page;
 		/* Get physical address of RB/SKB */
-		rxb->page_dma =
+		page_dma =
 		    pci_map_page(il->pci_dev, page, 0,
 				 PAGE_SIZE << il->hw_params.rx_page_order,
 				 PCI_DMA_FROMDEVICE);
 
+		if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) {
+			__free_pages(page, il->hw_params.rx_page_order);
+			break;
+		}
+
 		spin_lock_irqsave(&rxq->lock, flags);
 
+		if (list_empty(&rxq->rx_used)) {
+			spin_unlock_irqrestore(&rxq->lock, flags);
+			pci_unmap_page(il->pci_dev, page_dma,
+				       PAGE_SIZE << il->hw_params.rx_page_order,
+				       PCI_DMA_FROMDEVICE);
+			__free_pages(page, il->hw_params.rx_page_order);
+			return;
+		}
+
+		element = rxq->rx_used.next;
+		rxb = list_entry(element, struct il_rx_buf, list);
+		list_del(element);
+
+		rxb->page = page;
+		rxb->page_dma = page_dma;
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
 		il->alloc_rxb_page++;
@@ -1284,8 +1295,15 @@
 			    pci_map_page(il->pci_dev, rxb->page, 0,
 					 PAGE_SIZE << il->hw_params.
 					 rx_page_order, PCI_DMA_FROMDEVICE);
-			list_add_tail(&rxb->list, &rxq->rx_free);
-			rxq->free_count++;
+			if (unlikely(pci_dma_mapping_error(il->pci_dev,
+							   rxb->page_dma))) {
+				__il_free_pages(il, rxb->page);
+				rxb->page = NULL;
+				list_add_tail(&rxb->list, &rxq->rx_used);
+			} else {
+				list_add_tail(&rxb->list, &rxq->rx_free);
+				rxq->free_count++;
+			}
 		} else
 			list_add_tail(&rxb->list, &rxq->rx_used);
 
@@ -3474,6 +3492,7 @@
 	.sta_add = il3945_mac_sta_add,
 	.sta_remove = il_mac_sta_remove,
 	.tx_last_beacon = il_mac_tx_last_beacon,
+	.flush = il_mac_flush,
 };
 
 static int
@@ -3548,7 +3567,8 @@
 	hw->vif_data_size = sizeof(struct il_vif_priv);
 
 	/* Tell mac80211 our characteristics */
-	hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT;
+	hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
+		    IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
 	hw->wiphy->interface_modes =
 	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
@@ -3557,6 +3577,8 @@
 	    WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
 	    WIPHY_FLAG_IBSS_RSN;
 
+	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
 	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
 	/* we create the 802.11 header and a zero-length SSID element */
 	hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2;
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index c3fbf67..7941eb3 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -319,6 +319,7 @@
 	struct list_head *element;
 	struct il_rx_buf *rxb;
 	struct page *page;
+	dma_addr_t page_dma;
 	unsigned long flags;
 	gfp_t gfp_mask = priority;
 
@@ -356,33 +357,35 @@
 			return;
 		}
 
+		/* Get physical address of the RB */
+		page_dma =
+		    pci_map_page(il->pci_dev, page, 0,
+				 PAGE_SIZE << il->hw_params.rx_page_order,
+				 PCI_DMA_FROMDEVICE);
+		if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) {
+			__free_pages(page, il->hw_params.rx_page_order);
+			break;
+		}
+
 		spin_lock_irqsave(&rxq->lock, flags);
 
 		if (list_empty(&rxq->rx_used)) {
 			spin_unlock_irqrestore(&rxq->lock, flags);
+			pci_unmap_page(il->pci_dev, page_dma,
+				       PAGE_SIZE << il->hw_params.rx_page_order,
+				       PCI_DMA_FROMDEVICE);
 			__free_pages(page, il->hw_params.rx_page_order);
 			return;
 		}
+
 		element = rxq->rx_used.next;
 		rxb = list_entry(element, struct il_rx_buf, list);
 		list_del(element);
 
-		spin_unlock_irqrestore(&rxq->lock, flags);
-
 		BUG_ON(rxb->page);
+
 		rxb->page = page;
-		/* Get physical address of the RB */
-		rxb->page_dma =
-		    pci_map_page(il->pci_dev, page, 0,
-				 PAGE_SIZE << il->hw_params.rx_page_order,
-				 PCI_DMA_FROMDEVICE);
-		/* dma address must be no more than 36 bits */
-		BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-		/* and also 256 byte aligned! */
-		BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-		spin_lock_irqsave(&rxq->lock, flags);
-
+		rxb->page_dma = page_dma;
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
 		il->alloc_rxb_page++;
@@ -725,6 +728,16 @@
 	if (rate_n_flags & RATE_MCS_SGI_MSK)
 		rx_status.flag |= RX_FLAG_SHORT_GI;
 
+	if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) {
+		/* We know which subframes of an A-MPDU belong
+		 * together since we get a single PHY response
+		 * from the firmware for all of them.
+		 */
+
+		rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
+		rx_status.ampdu_reference = il->_4965.ampdu_ref;
+	}
+
 	il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb,
 				       &rx_status);
 }
@@ -736,6 +749,7 @@
 {
 	struct il_rx_pkt *pkt = rxb_addr(rxb);
 	il->_4965.last_phy_res_valid = true;
+	il->_4965.ampdu_ref++;
 	memcpy(&il->_4965.last_phy_res, pkt->u.raw,
 	       sizeof(struct il_rx_phy_res));
 }
@@ -1779,8 +1793,7 @@
 	memcpy(tx_cmd->hdr, hdr, hdr_len);
 
 	/* Total # bytes to be transmitted */
-	len = (u16) skb->len;
-	tx_cmd->len = cpu_to_le16(len);
+	tx_cmd->len = cpu_to_le16((u16) skb->len);
 
 	if (info->control.hw_key)
 		il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id);
@@ -1790,7 +1803,6 @@
 
 	il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc);
 
-	il_update_stats(il, true, fc, len);
 	/*
 	 * Use the first empty entry in this queue's command buffer array
 	 * to contain the Tx command and MAC header concatenated together
@@ -1812,18 +1824,8 @@
 	txcmd_phys =
 	    pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen,
 			   PCI_DMA_BIDIRECTIONAL);
-	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-	dma_unmap_len_set(out_meta, len, firstlen);
-	/* Add buffer containing Tx command and MAC(!) header to TFD's
-	 * first entry */
-	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
-
-	if (!ieee80211_has_morefrags(hdr->frame_control)) {
-		txq->need_update = 1;
-	} else {
-		wait_write_ptr = 1;
-		txq->need_update = 0;
-	}
+	if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
+		goto drop_unlock;
 
 	/* Set up TFD's 2nd entry to point directly to remainder of skb,
 	 * if any (802.11 null frames have no payload). */
@@ -1832,8 +1834,24 @@
 		phys_addr =
 		    pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
 				   PCI_DMA_TODEVICE);
+		if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
+			goto drop_unlock;
+	}
+
+	/* Add buffer containing Tx command and MAC(!) header to TFD's
+	 * first entry */
+	il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
+	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+	dma_unmap_len_set(out_meta, len, firstlen);
+	if (secondlen)
 		il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen,
 					       0, 0);
+
+	if (!ieee80211_has_morefrags(hdr->frame_control)) {
+		txq->need_update = 1;
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
 	}
 
 	scratch_phys =
@@ -1846,6 +1864,8 @@
 	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
 	tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys);
 
+	il_update_stats(il, true, fc, skb->len);
+
 	D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
 	D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
 	il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd));
@@ -4281,8 +4301,16 @@
 			    pci_map_page(il->pci_dev, rxb->page, 0,
 					 PAGE_SIZE << il->hw_params.
 					 rx_page_order, PCI_DMA_FROMDEVICE);
-			list_add_tail(&rxb->list, &rxq->rx_free);
-			rxq->free_count++;
+
+			if (unlikely(pci_dma_mapping_error(il->pci_dev,
+							   rxb->page_dma))) {
+				__il_free_pages(il, rxb->page);
+				rxb->page = NULL;
+				list_add_tail(&rxb->list, &rxq->rx_used);
+			} else {
+				list_add_tail(&rxb->list, &rxq->rx_free);
+				rxq->free_count++;
+			}
 		} else
 			list_add_tail(&rxb->list, &rxq->rx_used);
 
@@ -5711,9 +5739,9 @@
 	/* Tell mac80211 our characteristics */
 	hw->flags =
 	    IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
-	    IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
-	    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
-
+	    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
+	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
+	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 	if (il->cfg->sku & IL_SKU_N)
 		hw->flags |=
 		    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
@@ -5968,7 +5996,9 @@
 		D_HT("start Tx\n");
 		ret = il4965_tx_agg_start(il, vif, sta, tid, ssn);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		D_HT("stop Tx\n");
 		ret = il4965_tx_agg_stop(il, vif, sta, tid);
 		if (test_bit(S_EXIT_PENDING, &il->status))
@@ -6306,6 +6336,7 @@
 	.sta_remove = il_mac_sta_remove,
 	.channel_switch = il4965_mac_channel_switch,
 	.tx_last_beacon = il_mac_tx_last_beacon,
+	.flush = il_mac_flush,
 };
 
 static int
@@ -6553,6 +6584,7 @@
 	il4965_prepare_card_hw(il);
 	if (!il->hw_ready) {
 		IL_WARN("Failed, HW not ready\n");
+		err = -EIO;
 		goto out_iounmap;
 	}
 
@@ -6569,9 +6601,6 @@
 	if (err)
 		goto out_free_eeprom;
 
-	if (err)
-		goto out_free_eeprom;
-
 	/* extract MAC Address */
 	il4965_eeprom_get_mac(il, il->addresses[0].addr);
 	D_INFO("MAC address: %pM\n", il->addresses[0].addr);
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c
index f3b8e91..e8324b5 100644
--- a/drivers/net/wireless/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/4965-rs.c
@@ -1183,8 +1183,7 @@
 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
 		return -1;
 
-	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) ==
-	    WLAN_HT_CAP_SM_PS_STATIC)
+	if (sta->smps_mode == IEEE80211_SMPS_STATIC)
 		return -1;
 
 	/* Need both Tx chains/antennas to support MIMO */
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c
index 5db1171..91eb2d0 100644
--- a/drivers/net/wireless/iwlegacy/4965.c
+++ b/drivers/net/wireless/iwlegacy/4965.c
@@ -1748,7 +1748,6 @@
 il4965_post_associate(struct il_priv *il)
 {
 	struct ieee80211_vif *vif = il->vif;
-	struct ieee80211_conf *conf = NULL;
 	int ret = 0;
 
 	if (!vif || !il->is_open)
@@ -1759,8 +1758,6 @@
 
 	il_scan_cancel_timeout(il, 200);
 
-	conf = &il->hw->conf;
-
 	il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	il_commit_rxon(il);
 
diff --git a/drivers/net/wireless/iwlegacy/commands.h b/drivers/net/wireless/iwlegacy/commands.h
index 25dd7d2..3b6c994 100644
--- a/drivers/net/wireless/iwlegacy/commands.h
+++ b/drivers/net/wireless/iwlegacy/commands.h
@@ -1134,8 +1134,9 @@
 #define RX_RES_PHY_FLAGS_MOD_CCK_MSK		cpu_to_le16(1 << 1)
 #define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	cpu_to_le16(1 << 2)
 #define RX_RES_PHY_FLAGS_NARROW_BAND_MSK	cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK		0xf0
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK		0x70
 #define RX_RES_PHY_FLAGS_ANTENNA_POS		4
+#define RX_RES_PHY_FLAGS_AGG_MSK	cpu_to_le16(1 << 7)
 
 #define RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
 #define RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 90b8970..e006ea8 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -1830,32 +1830,30 @@
 {
 	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
 	__le32 sta_flags;
-	u8 mimo_ps_mode;
 
 	if (!sta || !sta_ht_inf->ht_supported)
 		goto done;
 
-	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
 	D_ASSOC("spatial multiplexing power save mode: %s\n",
-		(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" :
-		(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? "dynamic" :
+		(sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" :
+		(sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" :
 		"disabled");
 
 	sta_flags = il->stations[idx].sta.station_flags;
 
 	sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
 
-	switch (mimo_ps_mode) {
-	case WLAN_HT_CAP_SM_PS_STATIC:
+	switch (sta->smps_mode) {
+	case IEEE80211_SMPS_STATIC:
 		sta_flags |= STA_FLG_MIMO_DIS_MSK;
 		break;
-	case WLAN_HT_CAP_SM_PS_DYNAMIC:
+	case IEEE80211_SMPS_DYNAMIC:
 		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
 		break;
-	case WLAN_HT_CAP_SM_PS_DISABLED:
+	case IEEE80211_SMPS_OFF:
 		break;
 	default:
-		IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode);
+		IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode);
 		break;
 	}
 
@@ -3162,18 +3160,23 @@
 		     idx, il->cmd_queue);
 	}
 #endif
+
+	phys_addr =
+	    pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
+			   PCI_DMA_BIDIRECTIONAL);
+	if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr))) {
+		idx = -ENOMEM;
+		goto out;
+	}
+	dma_unmap_addr_set(out_meta, mapping, phys_addr);
+	dma_unmap_len_set(out_meta, len, fix_size);
+
 	txq->need_update = 1;
 
 	if (il->ops->txq_update_byte_cnt_tbl)
 		/* Set up entry in queue's byte count circular buffer */
 		il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
 
-	phys_addr =
-	    pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
-			   PCI_DMA_BIDIRECTIONAL);
-	dma_unmap_addr_set(out_meta, mapping, phys_addr);
-	dma_unmap_len_set(out_meta, len, fix_size);
-
 	il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
 					    U32_PAD(cmd->len));
 
@@ -3181,6 +3184,7 @@
 	q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd);
 	il_txq_update_write_ptr(il, txq);
 
+out:
 	spin_unlock_irqrestore(&il->hcmd_lock, flags);
 	return idx;
 }
@@ -4700,6 +4704,42 @@
 }
 EXPORT_SYMBOL(il_mac_change_interface);
 
+void
+il_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+	struct il_priv *il = hw->priv;
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	int i;
+
+	mutex_lock(&il->mutex);
+	D_MAC80211("enter\n");
+
+	if (il->txq == NULL)
+		goto out;
+
+	for (i = 0; i < il->hw_params.max_txq_num; i++) {
+		struct il_queue *q;
+
+		if (i == il->cmd_queue)
+			continue;
+
+		q = &il->txq[i].q;
+		if (q->read_ptr == q->write_ptr)
+			continue;
+
+		if (time_after(jiffies, timeout)) {
+			IL_ERR("Failed to flush queue %d\n", q->id);
+			break;
+		}
+
+		msleep(20);
+	}
+out:
+	D_MAC80211("leave\n");
+	mutex_unlock(&il->mutex);
+}
+EXPORT_SYMBOL(il_mac_flush);
+
 /*
  * On every watchdog tick we check (latest) time stamp. If it does not
  * change during timeout period and queue is not empty we reset firmware.
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index a9a569f..96f2025 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1356,6 +1356,7 @@
 		struct {
 			struct il_rx_phy_res last_phy_res;
 			bool last_phy_res_valid;
+			u32 ampdu_ref;
 
 			struct completion firmware_loading_complete;
 
@@ -1723,6 +1724,7 @@
 			     struct ieee80211_vif *vif);
 int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			    enum nl80211_iftype newtype, bool newp2p);
+void il_mac_flush(struct ieee80211_hw *hw, bool drop);
 int il_alloc_txq_mem(struct il_priv *il);
 void il_free_txq_mem(struct il_priv *il);
 
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 5cf4323..ba319cb 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -43,8 +43,20 @@
 	  module will be called iwlwifi.
 
 config IWLDVM
-	tristate "Intel Wireless WiFi"
+	tristate "Intel Wireless WiFi DVM Firmware support"
 	depends on IWLWIFI
+	help
+	  This is the driver supporting the DVM firmware which is
+	  currently the only firmware available for existing devices.
+
+config IWLMVM
+	tristate "Intel Wireless WiFi MVM Firmware support"
+	depends on IWLWIFI
+	help
+	  This is the driver supporting the MVM firmware which is
+	  currently only available for 7000 series devices.
+
+	  Say yes if you have such a device.
 
 menu "Debugging Options"
 	depends on IWLWIFI
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 170ec33..6c78000 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -5,8 +5,10 @@
 iwlwifi-objs		+= iwl-debug.o
 iwlwifi-objs		+= iwl-notif-wait.o
 iwlwifi-objs		+= iwl-eeprom-read.o iwl-eeprom-parse.o
+iwlwifi-objs		+= iwl-phy-db.o iwl-nvm-parse.o
 iwlwifi-objs		+= pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
 iwlwifi-objs		+= pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
+iwlwifi-objs		+= pcie/7000.o
 
 iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
 iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o
@@ -15,5 +17,6 @@
 
 
 obj-$(CONFIG_IWLDVM)	+= dvm/
+obj-$(CONFIG_IWLMVM)	+= mvm/
 
 CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
index 33b3ad2..41ec27c 100644
--- a/drivers/net/wireless/iwlwifi/dvm/agn.h
+++ b/drivers/net/wireless/iwlwifi/dvm/agn.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -338,7 +338,7 @@
 
 bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 			    struct iwl_rxon_context *ctx,
-			    struct ieee80211_sta_ht_cap *ht_cap);
+			    struct ieee80211_sta *sta);
 
 static inline int iwl_sta_id(struct ieee80211_sta *sta)
 {
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c
index de54713..6468de8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/calib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h
index 2349f39..65e920c 100644
--- a/drivers/net/wireless/iwlwifi/dvm/calib.h
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h
index 71ab76b..84e2c0f 100644
--- a/drivers/net/wireless/iwlwifi/dvm/commands.h
+++ b/drivers/net/wireless/iwlwifi/dvm/commands.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1403,6 +1403,7 @@
 
 #define AGG_TX_STATUS_MSK	0x00000fff	/* bits 0:11 */
 #define AGG_TX_TRY_MSK		0x0000f000	/* bits 12:15 */
+#define AGG_TX_TRY_POS		12
 
 #define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
 				     AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
@@ -3695,7 +3696,7 @@
 	u8 frame5;
 	u8 frame6;
 	u8 frame7;
-} __attribute__((packed));
+} __packed;
 
 struct iwl_bt_coex_profile_notif {
 	struct iwl_bt_uart_msg last_bt_uart_msg;
@@ -3703,7 +3704,7 @@
 	u8 bt_traffic_load; /* 0 .. 3? */
 	u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
 	u8 reserved;
-} __attribute__((packed));
+} __packed;
 
 #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS	0
 #define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK	0x1
@@ -3752,7 +3753,7 @@
 
 struct iwl_bt_coex_prio_table_cmd {
 	u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
-} __attribute__((packed));
+} __packed;
 
 #define IWL_BT_COEX_ENV_CLOSE	0
 #define IWL_BT_COEX_ENV_OPEN	1
@@ -3764,7 +3765,7 @@
 	u8 action; /* 0 = closed, 1 = open */
 	u8 type; /* 0 .. 15 */
 	u8 reserved[2];
-} __attribute__((packed));
+} __packed;
 
 /*
  * REPLY_D3_CONFIG
@@ -3897,6 +3898,24 @@
 	__le64	replay_ctr;
 } __packed;
 
+#define RF_KILL_INDICATOR_FOR_WOWLAN	0x87
+
+/*
+ * REPLY_WOWLAN_GET_STATUS = 0xe5
+ */
+struct iwlagn_wowlan_status {
+	__le64 replay_ctr;
+	__le32 rekey_status;
+	__le32 wakeup_reason;
+	u8 pattern_number;
+	u8 reserved1;
+	__le16 qos_seq_ctr[8];
+	__le16 non_qos_seq_ctr;
+	__le16 reserved2;
+	union iwlagn_all_tsc_rsc tsc_rsc;
+	__le16 reserved3;
+} __packed;
+
 /*
  * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
  */
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
index 5b9533e..20806ca 100644
--- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -157,7 +157,7 @@
 	sram = priv->dbgfs_sram_offset & ~0x3;
 
 	/* read the first u32 from sram */
-	val = iwl_read_targ_mem(priv->trans, sram);
+	val = iwl_trans_read_mem32(priv->trans, sram);
 
 	for (; len; len--) {
 		/* put the address at the start of every line */
@@ -176,7 +176,7 @@
 		if (++offset == 4) {
 			sram += 4;
 			offset = 0;
-			val = iwl_read_targ_mem(priv->trans, sram);
+			val = iwl_trans_read_mem32(priv->trans, sram);
 		}
 
 		/* put in extra spaces and split lines for human readability */
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h
index 2653a89..71ea775 100644
--- a/drivers/net/wireless/iwlwifi/dvm/dev.h
+++ b/drivers/net/wireless/iwlwifi/dvm/dev.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
index 8c72be3..15cca2e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c
index bf479f7..33c7e15 100644
--- a/drivers/net/wireless/iwlwifi/dvm/led.c
+++ b/drivers/net/wireless/iwlwifi/dvm/led.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -69,7 +69,7 @@
 /* Set led register off */
 void iwlagn_led_enable(struct iwl_priv *priv)
 {
-	iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+	iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
 }
 
 /*
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h
index b02a853..8749dcf 100644
--- a/drivers/net/wireless/iwlwifi/dvm/led.h
+++ b/drivers/net/wireless/iwlwifi/dvm/led.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c
index 6ff4660..86ea5f4 100644
--- a/drivers/net/wireless/iwlwifi/dvm/lib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/lib.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 3163e0f..323e4a3 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -145,14 +145,13 @@
 	/* Tell mac80211 our characteristics */
 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
 		    IEEE80211_HW_AMPDU_AGGREGATION |
-		    IEEE80211_HW_NEED_DTIM_PERIOD |
+		    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
 		    IEEE80211_HW_SPECTRUM_MGMT |
 		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 		    IEEE80211_HW_QUEUE_CONTROL |
 		    IEEE80211_HW_SUPPORTS_PS |
 		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
-		    IEEE80211_HW_WANT_MONITOR_VIF |
-		    IEEE80211_HW_SCAN_WHILE_IDLE;
+		    IEEE80211_HW_WANT_MONITOR_VIF;
 
 	hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
 	hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
@@ -206,7 +205,8 @@
 
 #ifdef CONFIG_PM_SLEEP
 	if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
-	    priv->trans->ops->wowlan_suspend &&
+	    priv->trans->ops->d3_suspend &&
+	    priv->trans->ops->d3_resume &&
 	    device_can_wakeup(priv->trans->dev)) {
 		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
 					  WIPHY_WOWLAN_DISCONNECT |
@@ -426,7 +426,7 @@
 	if (ret)
 		goto error;
 
-	iwl_trans_wowlan_suspend(priv->trans);
+	iwl_trans_d3_suspend(priv->trans);
 
 	goto out;
 
@@ -441,55 +441,155 @@
 	return ret;
 }
 
+struct iwl_resume_data {
+	struct iwl_priv *priv;
+	struct iwlagn_wowlan_status *cmd;
+	bool valid;
+};
+
+static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait,
+				 struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_resume_data *resume_data = data;
+	struct iwl_priv *priv = resume_data->priv;
+	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+	if (len - 4 != sizeof(*resume_data->cmd)) {
+		IWL_ERR(priv, "rx wrong size data\n");
+		return true;
+	}
+	memcpy(resume_data->cmd, pkt->data, sizeof(*resume_data->cmd));
+	resume_data->valid = true;
+
+	return true;
+}
+
 static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 	struct ieee80211_vif *vif;
-	unsigned long flags;
-	u32 base, status = 0xffffffff;
-	int ret = -EIO;
+	u32 base;
+	int ret;
+	enum iwl_d3_status d3_status;
+	struct error_table_start {
+		/* cf. struct iwl_error_event_table */
+		u32 valid;
+		u32 error_id;
+	} err_info;
+	struct iwl_notification_wait status_wait;
+	static const u8 status_cmd[] = {
+		REPLY_WOWLAN_GET_STATUS,
+	};
+	struct iwlagn_wowlan_status status_data = {};
+	struct iwl_resume_data resume_data = {
+		.priv = priv,
+		.cmd = &status_data,
+		.valid = false,
+	};
+	struct cfg80211_wowlan_wakeup wakeup = {
+		.pattern_idx = -1,
+	};
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	const struct fw_img *img;
+#endif
 
 	IWL_DEBUG_MAC80211(priv, "enter\n");
 	mutex_lock(&priv->mutex);
 
-	iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-			  CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-	base = priv->device_pointers.error_event_table;
-	if (iwlagn_hw_valid_rtc_data_addr(base)) {
-		spin_lock_irqsave(&priv->trans->reg_lock, flags);
-		ret = iwl_grab_nic_access_silent(priv->trans);
-		if (likely(ret == 0)) {
-			iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
-			status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-			iwl_release_nic_access(priv->trans);
-		}
-		spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-		if (ret == 0) {
-			const struct fw_img *img;
-
-			img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
-			if (!priv->wowlan_sram) {
-				priv->wowlan_sram =
-				   kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
-						GFP_KERNEL);
-			}
-
-			if (priv->wowlan_sram)
-				_iwl_read_targ_mem_dwords(
-				      priv->trans, 0x800000,
-				      priv->wowlan_sram,
-				      img->sec[IWL_UCODE_SECTION_DATA].len / 4);
-		}
-#endif
-	}
-
 	/* we'll clear ctx->vif during iwlagn_prepare_restart() */
 	vif = ctx->vif;
 
+	ret = iwl_trans_d3_resume(priv->trans, &d3_status);
+	if (ret)
+		goto out_unlock;
+
+	if (d3_status != IWL_D3_STATUS_ALIVE) {
+		IWL_INFO(priv, "Device was reset during suspend\n");
+		goto out_unlock;
+	}
+
+	base = priv->device_pointers.error_event_table;
+	if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+		IWL_WARN(priv, "Invalid error table during resume!\n");
+		goto out_unlock;
+	}
+
+	iwl_trans_read_mem_bytes(priv->trans, base,
+				 &err_info, sizeof(err_info));
+
+	if (err_info.valid) {
+		IWL_INFO(priv, "error table is valid (%d, 0x%x)\n",
+			 err_info.valid, err_info.error_id);
+		if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+			wakeup.rfkill_release = true;
+			ieee80211_report_wowlan_wakeup(vif, &wakeup,
+						       GFP_KERNEL);
+		}
+		goto out_unlock;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	img = &priv->fw->img[IWL_UCODE_WOWLAN];
+	if (!priv->wowlan_sram)
+		priv->wowlan_sram =
+			kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
+				GFP_KERNEL);
+
+	if (priv->wowlan_sram)
+		iwl_trans_read_mem(priv->trans, 0x800000,
+				   priv->wowlan_sram,
+				   img->sec[IWL_UCODE_SECTION_DATA].len / 4);
+#endif
+
+	/*
+	 * This is very strange. The GET_STATUS command is sent but the device
+	 * doesn't reply properly, it seems it doesn't close the RBD so one is
+	 * always left open ... As a result, we need to send another command
+	 * and have to reset the driver afterwards. As we need to switch to
+	 * runtime firmware again that'll happen.
+	 */
+
+	iwl_init_notification_wait(&priv->notif_wait, &status_wait, status_cmd,
+				   ARRAY_SIZE(status_cmd), iwl_resume_status_fn,
+				   &resume_data);
+
+	iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL);
+	iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL);
+	/* an RBD is left open in the firmware now! */
+
+	ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5);
+	if (ret)
+		goto out_unlock;
+
+	if (resume_data.valid && priv->contexts[IWL_RXON_CTX_BSS].vif) {
+		u32 reasons = le32_to_cpu(status_data.wakeup_reason);
+		struct cfg80211_wowlan_wakeup *wakeup_report;
+
+		IWL_INFO(priv, "WoWLAN wakeup reason(s): 0x%.8x\n", reasons);
+
+		if (reasons) {
+			if (reasons & IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET)
+				wakeup.magic_pkt = true;
+			if (reasons & IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH)
+				wakeup.pattern_idx = status_data.pattern_number;
+			if (reasons & (IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+				       IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE))
+				wakeup.disconnect = true;
+			if (reasons & IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL)
+				wakeup.gtk_rekey_failure = true;
+			if (reasons & IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ)
+				wakeup.eap_identity_req = true;
+			if (reasons & IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE)
+				wakeup.four_way_handshake = true;
+			wakeup_report = &wakeup;
+		} else {
+			wakeup_report = NULL;
+		}
+
+		ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
+	}
+
 	priv->wowlan = false;
 
 	iwlagn_prepare_restart(priv);
@@ -498,6 +598,7 @@
 	iwl_connection_init_rx_config(priv, ctx);
 	iwlagn_set_rxon_chain(priv, ctx);
 
+ out_unlock:
 	mutex_unlock(&priv->mutex);
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 
@@ -520,9 +621,6 @@
 {
 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
-	IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-		     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
 	if (iwlagn_tx_skb(priv, control->sta, skb))
 		ieee80211_free_txskb(hw, skb);
 }
@@ -679,7 +777,9 @@
 		IWL_DEBUG_HT(priv, "start Tx\n");
 		ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		IWL_DEBUG_HT(priv, "stop Tx\n");
 		ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
 		if ((ret == 0) && (priv->agg_tids_count > 0)) {
@@ -1154,6 +1254,7 @@
 }
 
 static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
 				     enum ieee80211_rssi_event rssi_event)
 {
 	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index faa0593..b9e3517 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -353,11 +353,8 @@
 		ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
 
 	/* Make sure device is powered up for SRAM reads */
-	spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
-	if (unlikely(!iwl_grab_nic_access(priv->trans))) {
-		spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+	if (!iwl_trans_grab_nic_access(priv->trans, false, &reg_flags))
 		return;
-	}
 
 	/* Set starting address; reads will auto-increment */
 	iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
@@ -388,8 +385,7 @@
 		}
 	}
 	/* Allow device to power down */
-	iwl_release_nic_access(priv->trans);
-	spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+	iwl_trans_release_nic_access(priv->trans, &reg_flags);
 }
 
 static void iwl_continuous_event_trace(struct iwl_priv *priv)
@@ -408,7 +404,8 @@
 
 	base = priv->device_pointers.log_event_table;
 	if (iwlagn_hw_valid_rtc_data_addr(base)) {
-		iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
+		iwl_trans_read_mem_bytes(priv->trans, base,
+					 &read, sizeof(read));
 		capacity = read.capacity;
 		mode = read.mode;
 		num_wraps = read.wrap_counter;
@@ -1627,7 +1624,7 @@
 	}
 
 	/*TODO: Update dbgfs with ISR error stats obtained below */
-	iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
+	iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
 
 	if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
 		IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -1716,9 +1713,8 @@
 	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
 
 	/* Make sure device is powered up for SRAM reads */
-	spin_lock_irqsave(&trans->reg_lock, reg_flags);
-	if (unlikely(!iwl_grab_nic_access(trans)))
-		goto out_unlock;
+	if (!iwl_trans_grab_nic_access(trans, false, &reg_flags))
+		return pos;
 
 	/* Set starting address; reads will auto-increment */
 	iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
@@ -1756,9 +1752,7 @@
 	}
 
 	/* Allow device to power down */
-	iwl_release_nic_access(trans);
-out_unlock:
-	spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
+	iwl_trans_release_nic_access(trans, &reg_flags);
 	return pos;
 }
 
@@ -1835,10 +1829,10 @@
 	}
 
 	/* event log header */
-	capacity = iwl_read_targ_mem(trans, base);
-	mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
-	num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
-	next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+	capacity = iwl_trans_read_mem32(trans, base);
+	mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32)));
+	num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32)));
+	next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32)));
 
 	if (capacity > logsize) {
 		IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
@@ -1990,13 +1984,13 @@
 	struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
 
 	/* SKU Control */
-	iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
-			  CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
-			  CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
-			  (CSR_HW_REV_STEP(priv->trans->hw_rev) <<
-				CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
-			  (CSR_HW_REV_DASH(priv->trans->hw_rev) <<
-				CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
+	iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+				CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+				CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
+				(CSR_HW_REV_STEP(priv->trans->hw_rev) <<
+					CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
+				(CSR_HW_REV_DASH(priv->trans->hw_rev) <<
+					CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
 
 	/* write radio config values to register */
 	if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) {
@@ -2008,10 +2002,11 @@
 			priv->nvm_data->radio_cfg_dash <<
 				CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
 
-		iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
-				  CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
-				  CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
-				  CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val);
+		iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+					CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
+					CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
+					CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH,
+					reg_val);
 
 		IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
 			 priv->nvm_data->radio_cfg_type,
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
index 518cf37..bd69018 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.c
+++ b/drivers/net/wireless/iwlwifi/dvm/power.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.h b/drivers/net/wireless/iwlwifi/dvm/power.h
index a2cee7f..7b03e13 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.h
+++ b/drivers/net/wireless/iwlwifi/dvm/power.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c
index f3dd0da..abe3042 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -411,8 +411,9 @@
 	 * BT traffic, as they would just be disrupted by BT.
 	 */
 	if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
-		IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
-			priv->bt_traffic_load);
+		IWL_DEBUG_COEX(priv,
+			       "BT traffic (%d), no aggregation allowed\n",
+			       priv->bt_traffic_load);
 		return ret;
 	}
 
@@ -1288,8 +1289,7 @@
 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
 		return -1;
 
-	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
-						== WLAN_HT_CAP_SM_PS_STATIC)
+	if (sta->smps_mode == IEEE80211_SMPS_STATIC)
 		return -1;
 
 	/* Need both Tx chains/antennas to support MIMO */
@@ -1304,7 +1304,7 @@
 	tbl->max_search = IWL_MAX_SEARCH;
 	rate_mask = lq_sta->active_mimo2_rate;
 
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+	if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 		tbl->is_ht40 = 1;
 	else
 		tbl->is_ht40 = 0;
@@ -1344,8 +1344,7 @@
 	if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
 		return -1;
 
-	if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
-						== WLAN_HT_CAP_SM_PS_STATIC)
+	if (sta->smps_mode == IEEE80211_SMPS_STATIC)
 		return -1;
 
 	/* Need both Tx chains/antennas to support MIMO */
@@ -1360,7 +1359,7 @@
 	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
 	rate_mask = lq_sta->active_mimo3_rate;
 
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+	if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 		tbl->is_ht40 = 1;
 	else
 		tbl->is_ht40 = 0;
@@ -1409,7 +1408,7 @@
 	tbl->max_search = IWL_MAX_SEARCH;
 	rate_mask = lq_sta->active_siso_rate;
 
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+	if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 		tbl->is_ht40 = 1;
 	else
 		tbl->is_ht40 = 0;
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h
index ad3aea8..5d83cab 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c
index cac4f37..a4eed20 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rx.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portionhelp of the ieee80211 subsystem header files.
@@ -790,7 +790,7 @@
 
 	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
-	ieee80211_rx(priv->hw, skb);
+	ieee80211_rx_ni(priv->hw, skb);
 }
 
 static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 9a891e6..23be948 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -1545,10 +1545,9 @@
 				bss_conf->bssid);
 	}
 
-	if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
-	    priv->beacon_ctx) {
+	if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) {
 		if (iwlagn_update_beacon(priv, vif))
-			IWL_ERR(priv, "Error sending IBSS beacon\n");
+			IWL_ERR(priv, "Error updating beacon\n");
 	}
 
 	mutex_unlock(&priv->mutex);
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c
index 610ed220..3a4aa52 100644
--- a/drivers/net/wireless/iwlwifi/dvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/dvm/scan.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
index bdba954..94ef338 100644
--- a/drivers/net/wireless/iwlwifi/dvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/dvm/sta.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -77,7 +77,7 @@
 	IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
 		       sta_id);
 
-	spin_lock(&priv->sta_lock);
+	spin_lock_bh(&priv->sta_lock);
 
 	switch (add_sta_resp->status) {
 	case ADD_STA_SUCCESS_MSK:
@@ -119,7 +119,7 @@
 		       priv->stations[sta_id].sta.mode ==
 		       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
 		       addsta->sta.addr);
-	spin_unlock(&priv->sta_lock);
+	spin_unlock_bh(&priv->sta_lock);
 
 	return ret;
 }
@@ -173,7 +173,7 @@
 
 bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 			    struct iwl_rxon_context *ctx,
-			    struct ieee80211_sta_ht_cap *ht_cap)
+			    struct ieee80211_sta *sta)
 {
 	if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
 		return false;
@@ -183,20 +183,11 @@
 		return false;
 #endif
 
-	/*
-	 * Remainder of this function checks ht_cap, but if it's
-	 * NULL then we can do HT40 (special case for RXON)
-	 */
-	if (!ht_cap)
+	/* special case for RXON */
+	if (!sta)
 		return true;
 
-	if (!ht_cap->ht_supported)
-		return false;
-
-	if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
-		return false;
-
-	return true;
+	return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 }
 
 static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
@@ -205,7 +196,6 @@
 				  __le32 *flags, __le32 *mask)
 {
 	struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
-	u8 mimo_ps_mode;
 
 	*mask = STA_FLG_RTS_MIMO_PROT_MSK |
 		STA_FLG_MIMO_DIS_MSK |
@@ -217,26 +207,24 @@
 	if (!sta || !sta_ht_inf->ht_supported)
 		return;
 
-	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
-
 	IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
 			sta->addr,
-			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
+			(sta->smps_mode == IEEE80211_SMPS_STATIC) ?
 			"static" :
-			(mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
+			(sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ?
 			"dynamic" : "disabled");
 
-	switch (mimo_ps_mode) {
-	case WLAN_HT_CAP_SM_PS_STATIC:
+	switch (sta->smps_mode) {
+	case IEEE80211_SMPS_STATIC:
 		*flags |= STA_FLG_MIMO_DIS_MSK;
 		break;
-	case WLAN_HT_CAP_SM_PS_DYNAMIC:
+	case IEEE80211_SMPS_DYNAMIC:
 		*flags |= STA_FLG_RTS_MIMO_PROT_MSK;
 		break;
-	case WLAN_HT_CAP_SM_PS_DISABLED:
+	case IEEE80211_SMPS_OFF:
 		break;
 	default:
-		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
+		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", sta->smps_mode);
 		break;
 	}
 
@@ -246,7 +234,7 @@
 	*flags |= cpu_to_le32(
 		(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 
-	if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+	if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
 		*flags |= STA_FLG_HT40_EN_MSK;
 }
 
diff --git a/drivers/net/wireless/iwlwifi/dvm/testmode.c b/drivers/net/wireless/iwlwifi/dvm/testmode.c
index 57b918c..dc6f965 100644
--- a/drivers/net/wireless/iwlwifi/dvm/testmode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/testmode.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
index eb86443..03f9bc0 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -185,10 +185,8 @@
 			priv->thermal_throttle.ct_kill_toggle = true;
 		}
 		iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
-		spin_lock_irqsave(&priv->trans->reg_lock, flags);
-		if (likely(iwl_grab_nic_access(priv->trans)))
-			iwl_release_nic_access(priv->trans);
-		spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+		if (iwl_trans_grab_nic_access(priv->trans, false, &flags))
+			iwl_trans_release_nic_access(priv->trans, &flags);
 
 		/* Reschedule the ct_kill timer to occur in
 		 * CT_KILL_EXIT_DURATION seconds to ensure we get a
@@ -473,8 +471,8 @@
 					set_bit(STATUS_CT_KILL, &priv->status);
 					iwl_perform_ct_kill_task(priv, true);
 				} else {
-					iwl_prepare_ct_kill_task(priv);
 					tt->state = old_state;
+					iwl_prepare_ct_kill_task(priv);
 				}
 			} else if (old_state == IWL_TI_CT_KILL &&
 				  tt->state != IWL_TI_CT_KILL) {
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.h b/drivers/net/wireless/iwlwifi/dvm/tt.h
index 44c7c8f..9356c4b 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.h
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index 2797964..6aec2df 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -231,13 +231,11 @@
 		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
 		if (info->flags & IEEE80211_TX_CTL_AMPDU)
 			tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-		IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
 		break;
 
 	case WLAN_CIPHER_SUITE_TKIP:
 		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
 		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
-		IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
 		break;
 
 	case WLAN_CIPHER_SUITE_WEP104:
@@ -355,8 +353,6 @@
 		}
 	}
 
-	IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
 	if (sta)
 		sta_priv = (void *)sta->drv_priv;
 
@@ -472,6 +468,9 @@
 	WARN_ON_ONCE(is_agg &&
 		     priv->queue_to_mac80211[txq_id] != info->hw_queue);
 
+	IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid,
+		     txq_id, seq_number);
+
 	if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
 		goto drop_unlock_sta;
 
@@ -541,9 +540,9 @@
 	spin_lock_bh(&priv->sta_lock);
 
 	tid_data = &priv->tid_data[sta_id][tid];
-	txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+	txq_id = tid_data->agg.txq_id;
 
-	switch (priv->tid_data[sta_id][tid].agg.state) {
+	switch (tid_data->agg.state) {
 	case IWL_EMPTYING_HW_QUEUE_ADDBA:
 		/*
 		* This can happen if the peer stops aggregation
@@ -563,9 +562,9 @@
 	case IWL_AGG_ON:
 		break;
 	default:
-		IWL_WARN(priv, "Stopping AGG while state not ON "
-			 "or starting for %d on %d (%d)\n", sta_id, tid,
-			 priv->tid_data[sta_id][tid].agg.state);
+		IWL_WARN(priv,
+			 "Stopping AGG while state not ON or starting for %d on %d (%d)\n",
+			 sta_id, tid, tid_data->agg.state);
 		spin_unlock_bh(&priv->sta_lock);
 		return 0;
 	}
@@ -578,12 +577,11 @@
 			"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
 			sta_id, tid, txq_id);
 	} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
-		IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
-				    "next_recl = %d\n",
+		IWL_DEBUG_TX_QUEUES(priv,
+				    "Can't proceed: ssn %d, next_recl = %d\n",
 				    tid_data->agg.ssn,
 				    tid_data->next_reclaimed);
-		priv->tid_data[sta_id][tid].agg.state =
-			IWL_EMPTYING_HW_QUEUE_DELBA;
+		tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA;
 		spin_unlock_bh(&priv->sta_lock);
 		return 0;
 	}
@@ -591,8 +589,8 @@
 	IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
 			    tid_data->agg.ssn);
 turn_off:
-	agg_state = priv->tid_data[sta_id][tid].agg.state;
-	priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+	agg_state = tid_data->agg.state;
+	tid_data->agg.state = IWL_AGG_OFF;
 
 	spin_unlock_bh(&priv->sta_lock);
 
@@ -910,6 +908,12 @@
 	}
 }
 
+static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
+{
+	return le32_to_cpup((__le32 *)&tx_resp->status +
+			    tx_resp->frame_count) & MAX_SN;
+}
+
 static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
 				struct iwlagn_tx_resp *tx_resp)
 {
@@ -944,9 +948,15 @@
 	if (tx_resp->frame_count == 1)
 		return;
 
+	IWL_DEBUG_TX_REPLY(priv, "TXQ %d initial_rate 0x%x ssn %d frm_cnt %d\n",
+			   agg->txq_id,
+			   le32_to_cpu(tx_resp->rate_n_flags),
+			   iwlagn_get_scd_ssn(tx_resp), tx_resp->frame_count);
+
 	/* Construct bit-map of pending frames within Tx window */
 	for (i = 0; i < tx_resp->frame_count; i++) {
 		u16 fstatus = le16_to_cpu(frame_status[i].status);
+		u8 retry_cnt = (fstatus & AGG_TX_TRY_MSK) >> AGG_TX_TRY_POS;
 
 		if (status & AGG_TX_STATUS_MSK)
 			iwlagn_count_agg_tx_err_status(priv, fstatus);
@@ -955,11 +965,13 @@
 			      AGG_TX_STATE_ABORT_MSK))
 			continue;
 
-		IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
-				   "try-count (0x%08x)\n",
-				   iwl_get_agg_tx_fail_reason(fstatus),
-				   fstatus & AGG_TX_STATUS_MSK,
-				   fstatus & AGG_TX_TRY_MSK);
+		if (status & AGG_TX_STATUS_MSK || retry_cnt > 1)
+			IWL_DEBUG_TX_REPLY(priv,
+					   "%d: status %s (0x%04x), try-count (0x%01x)\n",
+					   i,
+					   iwl_get_agg_tx_fail_reason(fstatus),
+					   fstatus & AGG_TX_STATUS_MSK,
+					   retry_cnt);
 	}
 }
 
@@ -990,12 +1002,6 @@
 }
 #endif /* CONFIG_IWLWIFI_DEBUG */
 
-static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
-{
-	return le32_to_cpup((__le32 *)&tx_resp->status +
-			    tx_resp->frame_count) & MAX_SN;
-}
-
 static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
 {
 	status &= TX_STATUS_MSK;
@@ -1125,10 +1131,16 @@
 	sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
 		IWLAGN_TX_RES_RA_POS;
 
-	spin_lock(&priv->sta_lock);
+	spin_lock_bh(&priv->sta_lock);
 
-	if (is_agg)
+	if (is_agg) {
+		WARN_ON_ONCE(sta_id >= IWLAGN_STATION_COUNT ||
+			     tid >= IWL_MAX_TID_COUNT);
+		if (txq_id != priv->tid_data[sta_id][tid].agg.txq_id)
+			IWL_ERR(priv, "txq_id mismatch: %d %d\n", txq_id,
+				priv->tid_data[sta_id][tid].agg.txq_id);
 		iwl_rx_reply_tx_agg(priv, tx_resp);
+	}
 
 	__skb_queue_head_init(&skbs);
 
@@ -1215,22 +1227,41 @@
 			freed++;
 		}
 
-		WARN_ON(!is_agg && freed != 1);
+		if (tid != IWL_TID_NON_QOS) {
+			priv->tid_data[sta_id][tid].next_reclaimed =
+				next_reclaimed;
+			IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
+					   next_reclaimed);
+		}
+
+		if (!is_agg && freed != 1)
+			IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed);
 
 		/*
 		 * An offchannel frame can be send only on the AUX queue, where
 		 * there is no aggregation (and reordering) so it only is single
 		 * skb is expected to be processed.
 		 */
-		WARN_ON(is_offchannel_skb && freed != 1);
+		if (is_offchannel_skb && freed != 1)
+			IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed);
+
+		IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
+				   iwl_get_tx_fail_reason(status), status);
+
+		IWL_DEBUG_TX_REPLY(priv,
+				   "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
+				   le32_to_cpu(tx_resp->rate_n_flags),
+				   tx_resp->failure_frame,
+				   SEQ_TO_INDEX(sequence), ssn,
+				   le16_to_cpu(tx_resp->seq_ctl));
 	}
 
 	iwl_check_abort_status(priv, tx_resp->frame_count, status);
-	spin_unlock(&priv->sta_lock);
+	spin_unlock_bh(&priv->sta_lock);
 
 	while (!skb_queue_empty(&skbs)) {
 		skb = __skb_dequeue(&skbs);
-		ieee80211_tx_status(priv->hw, skb);
+		ieee80211_tx_status_ni(priv->hw, skb);
 	}
 
 	if (is_offchannel_skb)
@@ -1277,12 +1308,12 @@
 	tid = ba_resp->tid;
 	agg = &priv->tid_data[sta_id][tid].agg;
 
-	spin_lock(&priv->sta_lock);
+	spin_lock_bh(&priv->sta_lock);
 
 	if (unlikely(!agg->wait_for_ba)) {
 		if (unlikely(ba_resp->bitmap))
 			IWL_ERR(priv, "Received BA when not expected\n");
-		spin_unlock(&priv->sta_lock);
+		spin_unlock_bh(&priv->sta_lock);
 		return 0;
 	}
 
@@ -1296,7 +1327,7 @@
 		IWL_DEBUG_TX_QUEUES(priv,
 				    "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
 				    scd_flow, sta_id, tid, agg->txq_id);
-		spin_unlock(&priv->sta_lock);
+		spin_unlock_bh(&priv->sta_lock);
 		return 0;
 	}
 
@@ -1365,11 +1396,11 @@
 		}
 	}
 
-	spin_unlock(&priv->sta_lock);
+	spin_unlock_bh(&priv->sta_lock);
 
 	while (!skb_queue_empty(&reclaimed_skbs)) {
 		skb = __skb_dequeue(&reclaimed_skbs);
-		ieee80211_tx_status(priv->hw, skb);
+		ieee80211_tx_status_ni(priv->hw, skb);
 	}
 
 	return 0;
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index c6467e5..736fe9b 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -286,89 +286,6 @@
 	return iwl_send_calib_results(priv);
 }
 
-
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- *   using sample data 100 bytes apart.  If these sample points are good,
- *   it's a pretty good bet that everything between them is good, too.
- */
-static int iwl_verify_sec_sparse(struct iwl_priv *priv,
-				  const struct fw_desc *fw_desc)
-{
-	__le32 *image = (__le32 *)fw_desc->data;
-	u32 len = fw_desc->len;
-	u32 val;
-	u32 i;
-
-	IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-	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
-		 * if IWL_DL_IO is set */
-		iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-			i + fw_desc->offset);
-		val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image))
-			return -EIO;
-	}
-
-	return 0;
-}
-
-static void iwl_print_mismatch_sec(struct iwl_priv *priv,
-				    const struct fw_desc *fw_desc)
-{
-	__le32 *image = (__le32 *)fw_desc->data;
-	u32 len = fw_desc->len;
-	u32 val;
-	u32 offs;
-	int errors = 0;
-
-	IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-	iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-				fw_desc->offset);
-
-	for (offs = 0;
-	     offs < len && errors < 20;
-	     offs += sizeof(u32), image++) {
-		/* read data comes through single port, auto-incr addr */
-		val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-		if (val != le32_to_cpu(*image)) {
-			IWL_ERR(priv, "uCode INST section at "
-				"offset 0x%x, is 0x%x, s/b 0x%x\n",
-				offs, val, le32_to_cpu(*image));
-			errors++;
-		}
-	}
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv,
-			    enum iwl_ucode_type ucode_type)
-{
-	const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
-
-	if (!img) {
-		IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
-		return -EINVAL;
-	}
-
-	if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
-		IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
-
-	iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
-	return -EIO;
-}
-
 struct iwl_alive_data {
 	bool valid;
 	u8 subtype;
@@ -426,7 +343,7 @@
 				   alive_cmd, ARRAY_SIZE(alive_cmd),
 				   iwl_alive_fn, &alive_data);
 
-	ret = iwl_trans_start_fw(priv->trans, fw);
+	ret = iwl_trans_start_fw(priv->trans, fw, false);
 	if (ret) {
 		priv->cur_ucode = old_type;
 		iwl_remove_notification(&priv->notif_wait, &alive_wait);
@@ -450,18 +367,7 @@
 		return -EIO;
 	}
 
-	/*
-	 * This step takes a long time (60-80ms!!) and
-	 * WoWLAN image should be loaded quickly, so
-	 * skip it for WoWLAN.
-	 */
 	if (ucode_type != IWL_UCODE_WOWLAN) {
-		ret = iwl_verify_ucode(priv, ucode_type);
-		if (ret) {
-			priv->cur_ucode = old_type;
-			return ret;
-		}
-
 		/* delay a bit to give rfkill time to run */
 		msleep(5);
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index 7960a52..e9975c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 864219d..743b483 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -83,6 +83,7 @@
 	IWL_DEVICE_FAMILY_6030,
 	IWL_DEVICE_FAMILY_6050,
 	IWL_DEVICE_FAMILY_6150,
+	IWL_DEVICE_FAMILY_7000,
 };
 
 /*
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 34a5287..df3463a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -381,8 +381,8 @@
 
 /* LED */
 #define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
-#define CSR_LED_REG_TRUN_ON (0x78)
-#define CSR_LED_REG_TRUN_OFF (0x38)
+#define CSR_LED_REG_TURN_ON (0x60)
+#define CSR_LED_REG_TURN_OFF (0x20)
 
 /* ANA_PLL */
 #define CSR50_ANA_PLL_CFG_VAL        (0x00880300)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 42b20b0..8cf5db7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
@@ -116,6 +116,7 @@
 #define IWL_DL_HCMD		0x00000004
 #define IWL_DL_STATE		0x00000008
 /* 0x000000F0 - 0x00000010 */
+#define IWL_DL_TE		0x00000020
 #define IWL_DL_EEPROM		0x00000040
 #define IWL_DL_RADIO		0x00000080
 /* 0x00000F00 - 0x00000100 */
@@ -156,6 +157,7 @@
 #define IWL_DEBUG_LED(p, f, a...)	IWL_DEBUG(p, IWL_DL_LED, f, ## a)
 #define IWL_DEBUG_WEP(p, f, a...)	IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
 #define IWL_DEBUG_HC(p, f, a...)	IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
+#define IWL_DEBUG_TE(p, f, a...)	IWL_DEBUG(p, IWL_DL_TE, f, ## a)
 #define IWL_DEBUG_EEPROM(d, f, a...)	IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
 #define IWL_DEBUG_CALIB(p, f, a...)	IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
 #define IWL_DEBUG_FW(p, f, a...)	IWL_DEBUG(p, IWL_DL_FW, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 70191dd..8f61c71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index dc7e26b..9a0f45e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index d3549f4..6f228bb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,8 +139,10 @@
 #endif
 };
 
-#define DVM_OP_MODE	0
-#define MVM_OP_MODE	1
+enum {
+	DVM_OP_MODE =	0,
+	MVM_OP_MODE =	1,
+};
 
 /* Protects the table contents, i.e. the ops pointer & drv list */
 static struct mutex iwlwifi_opmode_table_mtx;
@@ -149,8 +151,8 @@
 	const struct iwl_op_mode_ops *ops;	/* pointer to op_mode ops */
 	struct list_head drv;		/* list of devices using this op_mode */
 } iwlwifi_opmode_table[] = {		/* ops set when driver is initialized */
-	{ .name = "iwldvm", .ops = NULL },
-	{ .name = "iwlmvm", .ops = NULL },
+	[DVM_OP_MODE] = { .name = "iwldvm", .ops = NULL },
+	[MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL },
 };
 
 /*
@@ -268,7 +270,7 @@
  */
 struct iwl_tlv_calib_data {
 	__le32 ucode_type;
-	__le64 calib;
+	struct iwl_tlv_calib_ctrl calib;
 } __packed;
 
 struct iwl_firmware_pieces {
@@ -358,7 +360,11 @@
 			ucode_type);
 		return -EINVAL;
 	}
-	drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib);
+	drv->fw.default_calib[ucode_type].flow_trigger =
+		def_calib->calib.flow_trigger;
+	drv->fw.default_calib[ucode_type].event_trigger =
+		def_calib->calib.event_trigger;
+
 	return 0;
 }
 
@@ -959,7 +965,10 @@
 	release_firmware(ucode_raw);
 
 	mutex_lock(&iwlwifi_opmode_table_mtx);
-	op = &iwlwifi_opmode_table[DVM_OP_MODE];
+	if (fw->mvm_fw)
+		op = &iwlwifi_opmode_table[MVM_OP_MODE];
+	else
+		op = &iwlwifi_opmode_table[DVM_OP_MODE];
 
 	/* add this device to the list of devices using this op_mode */
 	list_add_tail(&drv->list, &op->drv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index 285de5f..594a5c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
 #define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2012 Intel Corporation"
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2013 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index 4719866..034f2ff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -703,9 +703,9 @@
 	return n_channels;
 }
 
-static int iwl_init_sband_channels(struct iwl_nvm_data *data,
-				   struct ieee80211_supported_band *sband,
-				   int n_channels, enum ieee80211_band band)
+int iwl_init_sband_channels(struct iwl_nvm_data *data,
+			    struct ieee80211_supported_band *sband,
+			    int n_channels, enum ieee80211_band band)
 {
 	struct ieee80211_channel *chan = &data->channels[0];
 	int n = 0, idx = 0;
@@ -728,10 +728,10 @@
 #define MAX_BIT_RATE_40_MHZ	150 /* Mbps */
 #define MAX_BIT_RATE_20_MHZ	72 /* Mbps */
 
-static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
-				 struct iwl_nvm_data *data,
-				 struct ieee80211_sta_ht_cap *ht_info,
-				 enum ieee80211_band band)
+void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
+			  struct iwl_nvm_data *data,
+			  struct ieee80211_sta_ht_cap *ht_info,
+			  enum ieee80211_band band)
 {
 	int max_bit_rate = 0;
 	u8 rx_chains;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
index 555f0eb..683fe6a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -126,4 +126,13 @@
 int iwl_nvm_check_version(struct iwl_nvm_data *data,
 			  struct iwl_trans *trans);
 
+int iwl_init_sband_channels(struct iwl_nvm_data *data,
+			    struct ieee80211_supported_band *sband,
+			    int n_channels, enum ieee80211_band band);
+
+void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
+			  struct iwl_nvm_data *data,
+			  struct ieee80211_sta_ht_cap *ht_info,
+			  enum ieee80211_band band);
+
 #endif /* __iwl_eeprom_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
index 27c7da3..ef4806f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
index 1337c9d..b2588c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index ec48563..f5592fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -225,6 +225,8 @@
 #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG	(FH_MEM_RSCSR_CHNL0 + 0x008)
 #define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
 
+#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG	(FH_MEM_RSCSR_CHNL0 + 0x00c)
+#define FH_RSCSR_CHNL0_RDPTR		FW_RSCSR_CHNL0_RXDCB_RDPTR_REG
 
 /**
  * Rx Config/Status Registers (RCSR)
@@ -257,6 +259,8 @@
 #define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
 
 #define FH_MEM_RCSR_CHNL0_CONFIG_REG	(FH_MEM_RCSR_CHNL0)
+#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR	(FH_MEM_RCSR_CHNL0 + 0x8)
+#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ	(FH_MEM_RCSR_CHNL0 + 0x10)
 
 #define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
 #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK   (0x00001000) /* bits 12 */
@@ -410,6 +414,7 @@
  *	uCode/driver must write "1" in order to clear this flag
  */
 #define FH_TSSR_TX_ERROR_REG		(FH_TSSR_LOWER_BOUND + 0x018)
+#define FH_TSSR_TX_MSG_CONFIG_REG	(FH_TSSR_LOWER_BOUND + 0x008)
 
 #define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16)
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index e715640..90873ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index d1a86b6..b545178 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,6 +139,19 @@
 #define IWL_UCODE_API(ver)	(((ver) & 0x0000FF00) >> 8)
 #define IWL_UCODE_SERIAL(ver)	((ver) & 0x000000FF)
 
+/*
+ * Calibration control struct.
+ * Sent as part of the phy configuration command.
+ * @flow_trigger: bitmap for which calibrations to perform according to
+ *		flow triggers.
+ * @event_trigger: bitmap for which calibrations to perform according to
+ *		event triggers.
+ */
+struct iwl_tlv_calib_ctrl {
+	__le32 flow_trigger;
+	__le32 event_trigger;
+} __packed;
+
 /**
  * struct iwl_fw - variables associated with the firmware
  *
@@ -153,11 +166,12 @@
  * @inst_evtlog_ptr: event log offset for runtime ucode.
  * @inst_evtlog_size: event log size for runtime ucode.
  * @inst_errlog_ptr: error log offfset for runtime ucode.
+ * @mvm_fw: indicates this is MVM firmware
  */
 struct iwl_fw {
 	u32 ucode_ver;
 
-	char fw_version[ETHTOOL_BUSINFO_LEN];
+	char fw_version[ETHTOOL_FWVERS_LEN];
 
 	/* ucode images */
 	struct fw_img img[IWL_UCODE_TYPE_MAX];
@@ -168,7 +182,7 @@
 	u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
 	u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
 
-	u64 default_calib[IWL_UCODE_TYPE_MAX];
+	struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
 	u32 phy_config;
 
 	bool mvm_fw;
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index cdaff95..276410d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
@@ -35,54 +35,6 @@
 
 #define IWL_POLL_INTERVAL 10	/* microseconds */
 
-static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
-	iwl_write32(trans, reg, iwl_read32(trans, reg) | mask);
-}
-
-static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
-	iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask);
-}
-
-void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	__iwl_set_bit(trans, reg, mask);
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_set_bit);
-
-void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	__iwl_clear_bit(trans, reg, mask);
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_clear_bit);
-
-void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
-{
-	unsigned long flags;
-	u32 v;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	WARN_ON_ONCE(value & ~mask);
-#endif
-
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	v = iwl_read32(trans, reg);
-	v &= ~mask;
-	v |= value;
-	iwl_write32(trans, reg, v);
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_set_bits_mask);
-
 int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 		 u32 bits, u32 mask, int timeout)
 {
@@ -99,87 +51,14 @@
 }
 EXPORT_SYMBOL_GPL(iwl_poll_bit);
 
-int iwl_grab_nic_access_silent(struct iwl_trans *trans)
-{
-	int ret;
-
-	lockdep_assert_held(&trans->reg_lock);
-
-	/* this bit wakes up the NIC */
-	__iwl_set_bit(trans, CSR_GP_CNTRL,
-		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	/*
-	 * These bits say the device is running, and should keep running for
-	 * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
-	 * but they do not indicate that embedded SRAM is restored yet;
-	 * 3945 and 4965 have volatile SRAM, and must save/restore contents
-	 * to/from host DRAM when sleeping/waking for power-saving.
-	 * Each direction takes approximately 1/4 millisecond; with this
-	 * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
-	 * series of register accesses are expected (e.g. reading Event Log),
-	 * to keep device from sleeping.
-	 *
-	 * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
-	 * SRAM is okay/restored.  We don't check that here because this call
-	 * is just for hardware register access; but GP1 MAC_SLEEP check is a
-	 * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
-	 *
-	 * 5000 series and later (including 1000 series) have non-volatile SRAM,
-	 * and do not save/restore SRAM when power cycling.
-	 */
-	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
-			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
-			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
-			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
-	if (ret < 0) {
-		iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
-		return -EIO;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
-
-bool iwl_grab_nic_access(struct iwl_trans *trans)
-{
-	int ret = iwl_grab_nic_access_silent(trans);
-	if (unlikely(ret)) {
-		u32 val = iwl_read32(trans, CSR_GP_CNTRL);
-		WARN_ONCE(1, "Timeout waiting for hardware access "
-			     "(CSR_GP_CNTRL 0x%08x)\n", val);
-		return false;
-	}
-
-	return true;
-}
-EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
-
-void iwl_release_nic_access(struct iwl_trans *trans)
-{
-	lockdep_assert_held(&trans->reg_lock);
-	__iwl_clear_bit(trans, CSR_GP_CNTRL,
-			CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-	/*
-	 * Above we read the CSR_GP_CNTRL register, which will flush
-	 * any previous writes, but we need the write that clears the
-	 * MAC_ACCESS_REQ bit to be performed before any other writes
-	 * scheduled on different CPUs (after we drop reg_lock).
-	 */
-	mmiowb();
-}
-EXPORT_SYMBOL_GPL(iwl_release_nic_access);
-
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 {
-	u32 value;
+	u32 value = 0x5a5a5a5a;
 	unsigned long flags;
-
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	iwl_grab_nic_access(trans);
-	value = iwl_read32(trans, reg);
-	iwl_release_nic_access(trans);
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+		value = iwl_read32(trans, reg);
+		iwl_trans_release_nic_access(trans, &flags);
+	}
 
 	return value;
 }
@@ -189,12 +68,10 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
 		iwl_write32(trans, reg, value);
-		iwl_release_nic_access(trans);
+		iwl_trans_release_nic_access(trans, &flags);
 	}
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 EXPORT_SYMBOL_GPL(iwl_write_direct32);
 
@@ -230,13 +107,12 @@
 u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
 {
 	unsigned long flags;
-	u32 val;
+	u32 val = 0x5a5a5a5a;
 
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	iwl_grab_nic_access(trans);
-	val = __iwl_read_prph(trans, ofs);
-	iwl_release_nic_access(trans);
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+		val = __iwl_read_prph(trans, ofs);
+		iwl_trans_release_nic_access(trans, &flags);
+	}
 	return val;
 }
 EXPORT_SYMBOL_GPL(iwl_read_prph);
@@ -245,12 +121,10 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
 		__iwl_write_prph(trans, ofs, val);
-		iwl_release_nic_access(trans);
+		iwl_trans_release_nic_access(trans, &flags);
 	}
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 EXPORT_SYMBOL_GPL(iwl_write_prph);
 
@@ -258,13 +132,11 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
 		__iwl_write_prph(trans, ofs,
 				 __iwl_read_prph(trans, ofs) | mask);
-		iwl_release_nic_access(trans);
+		iwl_trans_release_nic_access(trans, &flags);
 	}
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
 
@@ -273,13 +145,11 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
 		__iwl_write_prph(trans, ofs,
 				 (__iwl_read_prph(trans, ofs) & mask) | bits);
-		iwl_release_nic_access(trans);
+		iwl_trans_release_nic_access(trans, &flags);
 	}
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
 
@@ -288,67 +158,10 @@
 	unsigned long flags;
 	u32 val;
 
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
 		val = __iwl_read_prph(trans, ofs);
 		__iwl_write_prph(trans, ofs, (val & ~mask));
-		iwl_release_nic_access(trans);
+		iwl_trans_release_nic_access(trans, &flags);
 	}
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
 EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
-
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-			       void *buf, int dwords)
-{
-	unsigned long flags;
-	int offs;
-	u32 *vals = buf;
-
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
-		iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
-		for (offs = 0; offs < dwords; offs++)
-			vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-		iwl_release_nic_access(trans);
-	}
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
-{
-	u32 value;
-
-	_iwl_read_targ_mem_dwords(trans, addr, &value, 1);
-
-	return value;
-}
-EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-			       const void *buf, int dwords)
-{
-	unsigned long flags;
-	int offs, result = 0;
-	const u32 *vals = buf;
-
-	spin_lock_irqsave(&trans->reg_lock, flags);
-	if (likely(iwl_grab_nic_access(trans))) {
-		iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
-		for (offs = 0; offs < dwords; offs++)
-			iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
-		iwl_release_nic_access(trans);
-	} else
-		result = -EBUSY;
-	spin_unlock_irqrestore(&trans->reg_lock, flags);
-
-	return result;
-}
-EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
-
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
-{
-	return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
-}
-EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 48dc753..fd9f5b9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
@@ -51,20 +51,21 @@
 	return val;
 }
 
-void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
-void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
+static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
+{
+	iwl_trans_set_bits_mask(trans, reg, mask, mask);
+}
 
-void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
+static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
+{
+	iwl_trans_set_bits_mask(trans, reg, mask, 0);
+}
 
 int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 		 u32 bits, u32 mask, int timeout);
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
 			int timeout);
 
-int iwl_grab_nic_access_silent(struct iwl_trans *trans);
-bool iwl_grab_nic_access(struct iwl_trans *trans);
-void iwl_release_nic_access(struct iwl_trans *trans);
-
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
 
@@ -76,19 +77,4 @@
 			    u32 bits, u32 mask);
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
 
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-			       void *buf, int dwords);
-
-#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize)	\
-	do {							\
-		BUILD_BUG_ON((bufsize) % sizeof(u32));		\
-		_iwl_read_targ_mem_dwords(trans, addr, buf,	\
-					  (bufsize) / sizeof(u32));\
-	} while (0)
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
-			       const void *buf, int dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index d9a86d6..e5e3a79 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
index c61f207..c3affbc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
index 82152310..c2ce764 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
new file mode 100644
index 0000000..a70213b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -0,0 +1,346 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "iwl-modparams.h"
+#include "iwl-nvm-parse.h"
+
+/* NVM offsets (in words) definitions */
+enum wkp_nvm_offsets {
+	/* NVM HW-Section offset (in words) definitions */
+	HW_ADDR = 0x15,
+
+/* NVM SW-Section offset (in words) definitions */
+	NVM_SW_SECTION = 0x1C0,
+	NVM_VERSION = 0,
+	RADIO_CFG = 1,
+	SKU = 2,
+	N_HW_ADDRS = 3,
+	NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
+
+/* NVM calibration section offset (in words) definitions */
+	NVM_CALIB_SECTION = 0x2B8,
+	XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
+};
+
+/* SKU Capabilities (actual values from NVM definition) */
+enum nvm_sku_bits {
+	NVM_SKU_CAP_BAND_24GHZ	= BIT(0),
+	NVM_SKU_CAP_BAND_52GHZ	= BIT(1),
+	NVM_SKU_CAP_11N_ENABLE	= BIT(2),
+};
+
+/* radio config bits (actual values from NVM definition) */
+#define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
+#define NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
+#define NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
+#define NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
+#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
+#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+/*
+ * These are the channel numbers in the order that they are stored in the NVM
+ */
+static const u8 iwl_nvm_channels[] = {
+	/* 2.4 GHz */
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+	/* 5 GHz */
+	36, 40, 44 , 48, 52, 56, 60, 64,
+	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+	149, 153, 157, 161, 165
+};
+
+#define IWL_NUM_CHANNELS	ARRAY_SIZE(iwl_nvm_channels)
+#define NUM_2GHZ_CHANNELS	14
+#define FIRST_2GHZ_HT_MINUS	5
+#define LAST_2GHZ_HT_PLUS	9
+#define LAST_5GHZ_HT		161
+
+
+/* rate data (static) */
+static struct ieee80211_rate iwl_cfg80211_rates[] = {
+	{ .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
+	{ .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+	{ .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+	{ .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
+	  .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+	{ .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
+	{ .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
+	{ .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
+	{ .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
+	{ .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
+	{ .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
+	{ .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
+	{ .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
+};
+#define RATES_24_OFFS	0
+#define N_RATES_24	ARRAY_SIZE(iwl_cfg80211_rates)
+#define RATES_52_OFFS	4
+#define N_RATES_52	(N_RATES_24 - RATES_52_OFFS)
+
+/**
+ * enum iwl_nvm_channel_flags - channel flags in NVM
+ * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
+ * @NVM_CHANNEL_IBSS: usable as an IBSS channel
+ * @NVM_CHANNEL_ACTIVE: active scanning allowed
+ * @NVM_CHANNEL_RADAR: radar detection required
+ * @NVM_CHANNEL_DFS: dynamic freq selection candidate
+ * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
+ * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
+ */
+enum iwl_nvm_channel_flags {
+	NVM_CHANNEL_VALID = BIT(0),
+	NVM_CHANNEL_IBSS = BIT(1),
+	NVM_CHANNEL_ACTIVE = BIT(3),
+	NVM_CHANNEL_RADAR = BIT(4),
+	NVM_CHANNEL_DFS = BIT(7),
+	NVM_CHANNEL_WIDE = BIT(8),
+	NVM_CHANNEL_40MHZ = BIT(9),
+};
+
+#define CHECK_AND_PRINT_I(x)	\
+	((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
+
+static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
+				struct iwl_nvm_data *data,
+				const __le16 * const nvm_ch_flags)
+{
+	int ch_idx;
+	int n_channels = 0;
+	struct ieee80211_channel *channel;
+	u16 ch_flags;
+	bool is_5ghz;
+
+	for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
+		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
+		if (!(ch_flags & NVM_CHANNEL_VALID)) {
+			IWL_DEBUG_EEPROM(dev,
+					 "Ch. %d Flags %x [%sGHz] - No traffic\n",
+					 iwl_nvm_channels[ch_idx],
+					 ch_flags,
+					 (ch_idx >= NUM_2GHZ_CHANNELS) ?
+					 "5.2" : "2.4");
+			continue;
+		}
+
+		channel = &data->channels[n_channels];
+		n_channels++;
+
+		channel->hw_value = iwl_nvm_channels[ch_idx];
+		channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
+				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+		channel->center_freq =
+			ieee80211_channel_to_frequency(
+				channel->hw_value, channel->band);
+
+		/* TODO: Need to be dependent to the NVM */
+		channel->flags = IEEE80211_CHAN_NO_HT40;
+		if (ch_idx < NUM_2GHZ_CHANNELS &&
+		    (ch_flags & NVM_CHANNEL_40MHZ)) {
+			if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
+				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
+			if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
+				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
+		} else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
+			   (ch_flags & NVM_CHANNEL_40MHZ)) {
+			if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
+				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
+			else
+				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
+		}
+
+		if (!(ch_flags & NVM_CHANNEL_IBSS))
+			channel->flags |= IEEE80211_CHAN_NO_IBSS;
+
+		if (!(ch_flags & NVM_CHANNEL_ACTIVE))
+			channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+		if (ch_flags & NVM_CHANNEL_RADAR)
+			channel->flags |= IEEE80211_CHAN_RADAR;
+
+		/* Initialize regulatory-based run-time data */
+
+		/* TODO: read the real value from the NVM */
+		channel->max_power = 0;
+		is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
+		IWL_DEBUG_EEPROM(dev,
+				 "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+				 channel->hw_value,
+				 is_5ghz ? "5.2" : "2.4",
+				 CHECK_AND_PRINT_I(VALID),
+				 CHECK_AND_PRINT_I(IBSS),
+				 CHECK_AND_PRINT_I(ACTIVE),
+				 CHECK_AND_PRINT_I(RADAR),
+				 CHECK_AND_PRINT_I(WIDE),
+				 CHECK_AND_PRINT_I(DFS),
+				 ch_flags,
+				 channel->max_power,
+				 ((ch_flags & NVM_CHANNEL_IBSS) &&
+				  !(ch_flags & NVM_CHANNEL_RADAR))
+					? "" : "not ");
+	}
+
+	return n_channels;
+}
+
+static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
+			    struct iwl_nvm_data *data, const __le16 *nvm_sw)
+{
+	int n_channels = iwl_init_channel_map(dev, cfg, data,
+			&nvm_sw[NVM_CHANNELS]);
+	int n_used = 0;
+	struct ieee80211_supported_band *sband;
+
+	sband = &data->bands[IEEE80211_BAND_2GHZ];
+	sband->band = IEEE80211_BAND_2GHZ;
+	sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
+	sband->n_bitrates = N_RATES_24;
+	n_used += iwl_init_sband_channels(data, sband, n_channels,
+					  IEEE80211_BAND_2GHZ);
+	iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
+
+	sband = &data->bands[IEEE80211_BAND_5GHZ];
+	sband->band = IEEE80211_BAND_5GHZ;
+	sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
+	sband->n_bitrates = N_RATES_52;
+	n_used += iwl_init_sband_channels(data, sband, n_channels,
+					  IEEE80211_BAND_5GHZ);
+	iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
+
+	if (n_channels != n_used)
+		IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
+			    n_used, n_channels);
+}
+
+struct iwl_nvm_data *
+iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
+		   const __le16 *nvm_hw, const __le16 *nvm_sw,
+		   const __le16 *nvm_calib)
+{
+	struct iwl_nvm_data *data;
+	u8 hw_addr[ETH_ALEN];
+	u16 radio_cfg, sku;
+
+	data = kzalloc(sizeof(*data) +
+		       sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
+		       GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
+
+	radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
+	data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
+	data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
+	data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
+	data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
+	data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
+	data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
+
+	sku = le16_to_cpup(nvm_sw + SKU);
+	data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
+	data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
+	data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
+	if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
+		data->sku_cap_11n_enable = false;
+
+	/* check overrides (some devices have wrong NVM) */
+	if (cfg->valid_tx_ant)
+		data->valid_tx_ant = cfg->valid_tx_ant;
+	if (cfg->valid_rx_ant)
+		data->valid_rx_ant = cfg->valid_rx_ant;
+
+	if (!data->valid_tx_ant || !data->valid_rx_ant) {
+		IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
+			    data->valid_tx_ant, data->valid_rx_ant);
+		kfree(data);
+		return NULL;
+	}
+
+	data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
+
+	data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
+	data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
+
+	/* The byte order is little endian 16 bit, meaning 214365 */
+	memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
+	data->hw_addr[0] = hw_addr[1];
+	data->hw_addr[1] = hw_addr[0];
+	data->hw_addr[2] = hw_addr[3];
+	data->hw_addr[3] = hw_addr[2];
+	data->hw_addr[4] = hw_addr[5];
+	data->hw_addr[5] = hw_addr[4];
+
+	iwl_init_sbands(dev, cfg, data, nvm_sw);
+
+	data->calib_version = 255;   /* TODO:
+					this value will prevent some checks from
+					failing, we need to check if this
+					field is still needed, and if it does,
+					where is it in the NVM*/
+
+	return data;
+}
+EXPORT_SYMBOL_GPL(iwl_parse_nvm_data);
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
new file mode 100644
index 0000000..b2692bd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+#ifndef __iwl_nvm_parse_h__
+#define __iwl_nvm_parse_h__
+
+#include "iwl-eeprom-parse.h"
+
+/**
+ * iwl_parse_nvm_data - parse NVM data and return values
+ *
+ * This function parses all NVM values we need and then
+ * returns a (newly allocated) struct containing all the
+ * relevant values for driver use. The struct must be freed
+ * later with iwl_free_nvm_data().
+ */
+struct iwl_nvm_data *
+iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
+		   const __le16 *nvm_hw, const __le16 *nvm_sw,
+		   const __le16 *nvm_calib);
+
+#endif /* __iwl_nvm_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index c8d9b95..4a68001 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,6 +63,8 @@
 #ifndef __iwl_op_mode_h__
 #define __iwl_op_mode_h__
 
+#include <linux/debugfs.h>
+
 struct iwl_op_mode;
 struct iwl_trans;
 struct sk_buff;
@@ -111,13 +113,13 @@
  *	May sleep
  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
  *	HCMD the this Rx responds to.
- *	Must be atomic and called with BH disabled.
+ *	This callback may sleep, it is called from a threaded IRQ handler.
  * @queue_full: notifies that a HW queue is full.
  *	Must be atomic and called with BH disabled.
  * @queue_not_full: notifies that a HW queue is not full any more.
  *	Must be atomic and called with BH disabled.
  * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
- *	the radio is killed. Must be atomic.
+ *	the radio is killed. May sleep.
  * @free_skb: allows the transport layer to free skbs that haven't been
  *	reclaimed by the op_mode. This can happen when the driver is freed and
  *	there are Tx packets pending in the transport layer.
@@ -128,8 +130,7 @@
  *	called with BH disabled.
  * @nic_config: configure NIC, called before firmware is started.
  *	May sleep
- * @wimax_active: invoked when WiMax becomes active.  Must be atomic and called
- *	with BH disabled.
+ * @wimax_active: invoked when WiMax becomes active. May sleep
  */
 struct iwl_op_mode_ops {
 	struct iwl_op_mode *(*start)(struct iwl_trans *trans,
@@ -176,6 +177,7 @@
 				  struct iwl_rx_cmd_buffer *rxb,
 				  struct iwl_device_cmd *cmd)
 {
+	might_sleep();
 	return op_mode->ops->rx(op_mode, rxb, cmd);
 }
 
@@ -194,6 +196,7 @@
 static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
 					  bool state)
 {
+	might_sleep();
 	op_mode->ops->hw_rf_kill(op_mode, state);
 }
 
@@ -221,6 +224,7 @@
 
 static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
 {
+	might_sleep();
 	op_mode->ops->wimax_active(op_mode);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
new file mode 100644
index 0000000..14fc8d3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
@@ -0,0 +1,514 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/export.h>
+
+#include "iwl-phy-db.h"
+#include "iwl-debug.h"
+#include "iwl-op-mode.h"
+#include "iwl-trans.h"
+
+#define CHANNEL_NUM_SIZE	4	/* num of channels in calib_ch size */
+#define IWL_NUM_PAPD_CH_GROUPS	4
+#define IWL_NUM_TXP_CH_GROUPS	9
+
+struct iwl_phy_db_entry {
+	u16	size;
+	u8	*data;
+};
+
+/**
+ * struct iwl_phy_db - stores phy configuration and calibration data.
+ *
+ * @cfg: phy configuration.
+ * @calib_nch: non channel specific calibration data.
+ * @calib_ch: channel specific calibration data.
+ * @calib_ch_group_papd: calibration data related to papd channel group.
+ * @calib_ch_group_txp: calibration data related to tx power chanel group.
+ */
+struct iwl_phy_db {
+	struct iwl_phy_db_entry	cfg;
+	struct iwl_phy_db_entry	calib_nch;
+	struct iwl_phy_db_entry	calib_ch;
+	struct iwl_phy_db_entry	calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS];
+	struct iwl_phy_db_entry	calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS];
+
+	u32 channel_num;
+	u32 channel_size;
+
+	struct iwl_trans *trans;
+};
+
+enum iwl_phy_db_section_type {
+	IWL_PHY_DB_CFG = 1,
+	IWL_PHY_DB_CALIB_NCH,
+	IWL_PHY_DB_CALIB_CH,
+	IWL_PHY_DB_CALIB_CHG_PAPD,
+	IWL_PHY_DB_CALIB_CHG_TXP,
+	IWL_PHY_DB_MAX
+};
+
+#define PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */
+
+/*
+ * phy db - configure operational ucode
+ */
+struct iwl_phy_db_cmd {
+	__le16 type;
+	__le16 length;
+	u8 data[];
+} __packed;
+
+/* for parsing of tx power channel group data that comes from the firmware*/
+struct iwl_phy_db_chg_txp {
+	__le32 space;
+	__le16 max_channel_idx;
+} __packed;
+
+/*
+ * phy db - Receieve phy db chunk after calibrations
+ */
+struct iwl_calib_res_notif_phy_db {
+	__le16 type;
+	__le16 length;
+	u8 data[];
+} __packed;
+
+#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587)
+static inline void iwl_phy_db_test_pic(__le32 pic)
+{
+	WARN_ON(IWL_PHY_DB_STATIC_PIC != pic);
+}
+
+struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
+{
+	struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db),
+					    GFP_KERNEL);
+
+	if (!phy_db)
+		return phy_db;
+
+	phy_db->trans = trans;
+
+	/* TODO: add default values of the phy db. */
+	return phy_db;
+}
+EXPORT_SYMBOL(iwl_phy_db_init);
+
+/*
+ * get phy db section: returns a pointer to a phy db section specified by
+ * type and channel group id.
+ */
+static struct iwl_phy_db_entry *
+iwl_phy_db_get_section(struct iwl_phy_db *phy_db,
+		       enum iwl_phy_db_section_type type,
+		       u16 chg_id)
+{
+	if (!phy_db || type >= IWL_PHY_DB_MAX)
+		return NULL;
+
+	switch (type) {
+	case IWL_PHY_DB_CFG:
+		return &phy_db->cfg;
+	case IWL_PHY_DB_CALIB_NCH:
+		return &phy_db->calib_nch;
+	case IWL_PHY_DB_CALIB_CH:
+		return &phy_db->calib_ch;
+	case IWL_PHY_DB_CALIB_CHG_PAPD:
+		if (chg_id >= IWL_NUM_PAPD_CH_GROUPS)
+			return NULL;
+		return &phy_db->calib_ch_group_papd[chg_id];
+	case IWL_PHY_DB_CALIB_CHG_TXP:
+		if (chg_id >= IWL_NUM_TXP_CH_GROUPS)
+			return NULL;
+		return &phy_db->calib_ch_group_txp[chg_id];
+	default:
+		return NULL;
+	}
+	return NULL;
+}
+
+static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db,
+				    enum iwl_phy_db_section_type type,
+				    u16 chg_id)
+{
+	struct iwl_phy_db_entry *entry =
+				iwl_phy_db_get_section(phy_db, type, chg_id);
+	if (!entry)
+		return;
+
+	kfree(entry->data);
+	entry->data = NULL;
+	entry->size = 0;
+}
+
+void iwl_phy_db_free(struct iwl_phy_db *phy_db)
+{
+	int i;
+
+	if (!phy_db)
+		return;
+
+	iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0);
+	iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0);
+	iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CH, 0);
+	for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++)
+		iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i);
+	for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++)
+		iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i);
+
+	kfree(phy_db);
+}
+EXPORT_SYMBOL(iwl_phy_db_free);
+
+int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
+			   gfp_t alloc_ctx)
+{
+	struct iwl_calib_res_notif_phy_db *phy_db_notif =
+			(struct iwl_calib_res_notif_phy_db *)pkt->data;
+	enum iwl_phy_db_section_type type = le16_to_cpu(phy_db_notif->type);
+	u16 size  = le16_to_cpu(phy_db_notif->length);
+	struct iwl_phy_db_entry *entry;
+	u16 chg_id = 0;
+
+	if (!phy_db)
+		return -EINVAL;
+
+	if (type == IWL_PHY_DB_CALIB_CHG_PAPD ||
+	    type == IWL_PHY_DB_CALIB_CHG_TXP)
+		chg_id = le16_to_cpup((__le16 *)phy_db_notif->data);
+
+	entry = iwl_phy_db_get_section(phy_db, type, chg_id);
+	if (!entry)
+		return -EINVAL;
+
+	kfree(entry->data);
+	entry->data = kmemdup(phy_db_notif->data, size, alloc_ctx);
+	if (!entry->data) {
+		entry->size = 0;
+		return -ENOMEM;
+	}
+
+	entry->size = size;
+
+	if (type == IWL_PHY_DB_CALIB_CH) {
+		phy_db->channel_num =
+			le32_to_cpup((__le32 *)phy_db_notif->data);
+		phy_db->channel_size =
+			(size - CHANNEL_NUM_SIZE) / phy_db->channel_num;
+	}
+
+	/* Test PIC */
+	if (type != IWL_PHY_DB_CFG)
+		iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) +
+				      (size / sizeof(__le32)) - 1));
+
+	IWL_DEBUG_INFO(phy_db->trans,
+		       "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",
+		       __func__, __LINE__, type, size);
+
+	return 0;
+}
+EXPORT_SYMBOL(iwl_phy_db_set_section);
+
+static int is_valid_channel(u16 ch_id)
+{
+	if (ch_id <= 14 ||
+	    (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) ||
+	    (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) ||
+	    (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1))
+		return 1;
+	return 0;
+}
+
+static u8 ch_id_to_ch_index(u16 ch_id)
+{
+	if (WARN_ON(!is_valid_channel(ch_id)))
+		return 0xff;
+
+	if (ch_id <= 14)
+		return ch_id - 1;
+	if (ch_id <= 64)
+		return (ch_id + 20) / 4;
+	if (ch_id <= 140)
+		return (ch_id - 12) / 4;
+	return (ch_id - 13) / 4;
+}
+
+
+static u16 channel_id_to_papd(u16 ch_id)
+{
+	if (WARN_ON(!is_valid_channel(ch_id)))
+		return 0xff;
+
+	if (1 <= ch_id && ch_id <= 14)
+		return 0;
+	if (36 <= ch_id && ch_id <= 64)
+		return 1;
+	if (100 <= ch_id && ch_id <= 140)
+		return 2;
+	return 3;
+}
+
+static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id)
+{
+	struct iwl_phy_db_chg_txp *txp_chg;
+	int i;
+	u8 ch_index = ch_id_to_ch_index(ch_id);
+	if (ch_index == 0xff)
+		return 0xff;
+
+	for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) {
+		txp_chg = (void *)phy_db->calib_ch_group_txp[i].data;
+		if (!txp_chg)
+			return 0xff;
+		/*
+		 * Looking for the first channel group that its max channel is
+		 * higher then wanted channel.
+		 */
+		if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index)
+			return i;
+	}
+	return 0xff;
+}
+static
+int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,
+				u32 type, u8 **data, u16 *size, u16 ch_id)
+{
+	struct iwl_phy_db_entry *entry;
+	u32 channel_num;
+	u32 channel_size;
+	u16 ch_group_id = 0;
+	u16 index;
+
+	if (!phy_db)
+		return -EINVAL;
+
+	/* find wanted channel group */
+	if (type == IWL_PHY_DB_CALIB_CHG_PAPD)
+		ch_group_id = channel_id_to_papd(ch_id);
+	else if (type == IWL_PHY_DB_CALIB_CHG_TXP)
+		ch_group_id = channel_id_to_txp(phy_db, ch_id);
+
+	entry = iwl_phy_db_get_section(phy_db, type, ch_group_id);
+	if (!entry)
+		return -EINVAL;
+
+	if (type == IWL_PHY_DB_CALIB_CH) {
+		index = ch_id_to_ch_index(ch_id);
+		channel_num = phy_db->channel_num;
+		channel_size = phy_db->channel_size;
+		if (index >= channel_num) {
+			IWL_ERR(phy_db->trans, "Wrong channel number %d\n",
+				ch_id);
+			return -EINVAL;
+		}
+		*data = entry->data + CHANNEL_NUM_SIZE + index * channel_size;
+		*size = channel_size;
+	} else {
+		*data = entry->data;
+		*size = entry->size;
+	}
+
+	/* Test PIC */
+	if (type != IWL_PHY_DB_CFG)
+		iwl_phy_db_test_pic(*(((__le32 *)*data) +
+				      (*size / sizeof(__le32)) - 1));
+
+	IWL_DEBUG_INFO(phy_db->trans,
+		       "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
+		       __func__, __LINE__, type, *size);
+
+	return 0;
+}
+
+static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type,
+			       u16 length, void *data)
+{
+	struct iwl_phy_db_cmd phy_db_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = PHY_DB_CMD,
+		.flags = CMD_SYNC,
+	};
+
+	IWL_DEBUG_INFO(phy_db->trans,
+		       "Sending PHY-DB hcmd of type %d, of length %d\n",
+		       type, length);
+
+	/* Set phy db cmd variables */
+	phy_db_cmd.type = cpu_to_le16(type);
+	phy_db_cmd.length = cpu_to_le16(length);
+
+	/* Set hcmd variables */
+	cmd.data[0] = &phy_db_cmd;
+	cmd.len[0] = sizeof(struct iwl_phy_db_cmd);
+	cmd.data[1] = data;
+	cmd.len[1] = length;
+	cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
+
+	return iwl_trans_send_cmd(phy_db->trans, &cmd);
+}
+
+static int iwl_phy_db_send_all_channel_groups(
+					struct iwl_phy_db *phy_db,
+					enum iwl_phy_db_section_type type,
+					u8 max_ch_groups)
+{
+	u16 i;
+	int err;
+	struct iwl_phy_db_entry *entry;
+
+	/* Send all the  channel specific groups to operational fw */
+	for (i = 0; i < max_ch_groups; i++) {
+		entry = iwl_phy_db_get_section(phy_db,
+					       type,
+					       i);
+		if (!entry)
+			return -EINVAL;
+
+		/* Send the requested PHY DB section */
+		err = iwl_send_phy_db_cmd(phy_db,
+					  type,
+					  entry->size,
+					  entry->data);
+		if (err) {
+			IWL_ERR(phy_db->trans,
+				"Can't SEND phy_db section %d (%d), err %d",
+				type, i, err);
+			return err;
+		}
+
+		IWL_DEBUG_INFO(phy_db->trans,
+			       "Sent PHY_DB HCMD, type = %d num = %d",
+			       type, i);
+	}
+
+	return 0;
+}
+
+int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
+{
+	u8 *data = NULL;
+	u16 size = 0;
+	int err;
+
+	IWL_DEBUG_INFO(phy_db->trans,
+		       "Sending phy db data and configuration to runtime image\n");
+
+	/* Send PHY DB CFG section */
+	err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG,
+					  &data, &size, 0);
+	if (err) {
+		IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n");
+		return err;
+	}
+
+	err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data);
+	if (err) {
+		IWL_ERR(phy_db->trans,
+			"Cannot send HCMD of  Phy DB cfg section\n");
+		return err;
+	}
+
+	err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH,
+					  &data, &size, 0);
+	if (err) {
+		IWL_ERR(phy_db->trans,
+			"Cannot get Phy DB non specific channel section\n");
+		return err;
+	}
+
+	err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data);
+	if (err) {
+		IWL_ERR(phy_db->trans,
+			"Cannot send HCMD of Phy DB non specific channel section\n");
+		return err;
+	}
+
+	/* Send all the TXP channel specific data */
+	err = iwl_phy_db_send_all_channel_groups(phy_db,
+						 IWL_PHY_DB_CALIB_CHG_PAPD,
+						 IWL_NUM_PAPD_CH_GROUPS);
+	if (err) {
+		IWL_ERR(phy_db->trans,
+			"Cannot send channel specific PAPD groups");
+		return err;
+	}
+
+	/* Send all the TXP channel specific data */
+	err = iwl_phy_db_send_all_channel_groups(phy_db,
+						 IWL_PHY_DB_CALIB_CHG_TXP,
+						 IWL_NUM_TXP_CH_GROUPS);
+	if (err) {
+		IWL_ERR(phy_db->trans,
+			"Cannot send channel specific TX power groups");
+		return err;
+	}
+
+	IWL_DEBUG_INFO(phy_db->trans,
+		       "Finished sending phy db non channel data\n");
+	return 0;
+}
+EXPORT_SYMBOL(iwl_send_phy_db_data);
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/iwlwifi/iwl-phy-db.h
new file mode 100644
index 0000000..d0e43d9
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __IWL_PHYDB_H__
+#define __IWL_PHYDB_H__
+
+#include <linux/types.h>
+
+#include "iwl-op-mode.h"
+#include "iwl-trans.h"
+
+struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans);
+
+void iwl_phy_db_free(struct iwl_phy_db *phy_db);
+
+int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
+			   gfp_t alloc_ctx);
+
+
+int iwl_send_phy_db_data(struct iwl_phy_db *phy_db);
+
+#endif /* __IWL_PHYDB_H__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index c3a4bb4..f76e9ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,6 +97,9 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS		(0x00000800)
 
+/* Device system time */
+#define DEVICE_SYSTEM_TIME_REG 0xA0206C
+
 /**
  * Tx Scheduler
  *
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index 81e8c71..ce0c67b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -466,19 +466,18 @@
 	/* Hard-coded periphery absolute address */
 	if (IWL_ABS_PRPH_START <= addr &&
 	    addr < IWL_ABS_PRPH_START + PRPH_END) {
-			spin_lock_irqsave(&trans->reg_lock, flags);
-			iwl_grab_nic_access(trans);
+			if (!iwl_trans_grab_nic_access(trans, false, &flags)) {
+				return -EIO;
+			}
 			iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
 				    addr | (3 << 24));
 			for (i = 0; i < size; i += 4)
 				*(u32 *)(tst->mem.addr + i) =
 					iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
-			iwl_release_nic_access(trans);
-			spin_unlock_irqrestore(&trans->reg_lock, flags);
+			iwl_trans_release_nic_access(trans, &flags);
 	} else { /* target memory (SRAM) */
-		_iwl_read_targ_mem_dwords(trans, addr,
-					  tst->mem.addr,
-					  tst->mem.size / 4);
+		iwl_trans_read_mem(trans, addr, tst->mem.addr,
+				   tst->mem.size / 4);
 	}
 
 	tst->mem.nchunks =
@@ -501,28 +500,25 @@
 
 	if (IWL_ABS_PRPH_START <= addr &&
 	    addr < IWL_ABS_PRPH_START + PRPH_END) {
-			/* Periphery writes can be 1-3 bytes long, or DWORDs */
-			if (size < 4) {
-				memcpy(&val, buf, size);
-				spin_lock_irqsave(&trans->reg_lock, flags);
-				iwl_grab_nic_access(trans);
-				iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
-					    (addr & 0x0000FFFF) |
-					    ((size - 1) << 24));
-				iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
-				iwl_release_nic_access(trans);
-				/* needed after consecutive writes w/o read */
-				mmiowb();
-				spin_unlock_irqrestore(&trans->reg_lock, flags);
-			} else {
-				if (size % 4)
-					return -EINVAL;
-				for (i = 0; i < size; i += 4)
-					iwl_write_prph(trans, addr+i,
-						       *(u32 *)(buf+i));
-			}
+		/* Periphery writes can be 1-3 bytes long, or DWORDs */
+		if (size < 4) {
+			memcpy(&val, buf, size);
+			if (!iwl_trans_grab_nic_access(trans, false, &flags))
+					return -EIO;
+			iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+				    (addr & 0x0000FFFF) |
+				    ((size - 1) << 24));
+			iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+			iwl_trans_release_nic_access(trans, &flags);
+		} else {
+			if (size % 4)
+				return -EINVAL;
+			for (i = 0; i < size; i += 4)
+				iwl_write_prph(trans, addr+i,
+					       *(u32 *)(buf+i));
+		}
 	} else if (iwl_test_valid_hw_addr(tst, addr)) {
-		_iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
+		iwl_trans_write_mem(trans, addr, buf, size / 4);
 	} else {
 		return -EINVAL;
 	}
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.h b/drivers/net/wireless/iwlwifi/iwl-test.h
index e13ffa8..7fbf4d7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.h
+++ b/drivers/net/wireless/iwlwifi/iwl-test.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
index 6ba211b..a963f45 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index b76532e..8c7bec6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -65,6 +65,7 @@
 
 #include <linux/ieee80211.h>
 #include <linux/mm.h> /* for page_address */
+#include <linux/lockdep.h>
 
 #include "iwl-debug.h"
 #include "iwl-config.h"
@@ -193,11 +194,11 @@
  * @CMD_ON_DEMAND: This command is sent by the test mode pipe.
  */
 enum CMD_MODE {
-	CMD_SYNC = 0,
-	CMD_ASYNC = BIT(0),
-	CMD_WANT_SKB = BIT(1),
-	CMD_WANT_HCMD = BIT(2),
-	CMD_ON_DEMAND = BIT(3),
+	CMD_SYNC		= 0,
+	CMD_ASYNC		= BIT(0),
+	CMD_WANT_SKB		= BIT(1),
+	CMD_WANT_HCMD		= BIT(2),
+	CMD_ON_DEMAND		= BIT(3),
 };
 
 #define DEF_CMD_PAYLOAD_SIZE 320
@@ -274,6 +275,7 @@
 	struct page *_page;
 	int _offset;
 	bool _page_stolen;
+	u32 _rx_page_order;
 	unsigned int truesize;
 };
 
@@ -294,6 +296,11 @@
 	return r->_page;
 }
 
+static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
+{
+	__free_pages(r->_page, r->_rx_page_order);
+}
+
 #define MAX_NO_RECLAIM_CMDS	6
 
 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
@@ -308,6 +315,16 @@
 #define IWL_FRAME_LIMIT	64
 
 /**
+ * enum iwl_wowlan_status - WoWLAN image/device status
+ * @IWL_D3_STATUS_ALIVE: firmware is still running after resume
+ * @IWL_D3_STATUS_RESET: device was reset while suspended
+ */
+enum iwl_d3_status {
+	IWL_D3_STATUS_ALIVE,
+	IWL_D3_STATUS_RESET,
+};
+
+/**
  * struct iwl_trans_config - transport configuration
  *
  * @op_mode: pointer to the upper layer.
@@ -321,6 +338,8 @@
  * @n_no_reclaim_cmds: # of commands in list
  * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
  *	if unset 4k will be the RX buffer size
+ * @bc_table_dword: set to true if the BC table expects the byte count to be
+ *	in DWORD (as opposed to bytes)
  * @queue_watchdog_timeout: time (in ms) after which queues
  *	are considered stuck and will trigger device restart
  * @command_names: array of command names, must be 256 entries
@@ -335,6 +354,7 @@
 	int n_no_reclaim_cmds;
 
 	bool rx_buf_size_8k;
+	bool bc_table_dword;
 	unsigned int queue_watchdog_timeout;
 	const char **command_names;
 };
@@ -360,9 +380,12 @@
  *	May sleep
  * @stop_device:stops the whole device (embedded CPU put to reset)
  *	May sleep
- * @wowlan_suspend: put the device into the correct mode for WoWLAN during
+ * @d3_suspend: put the device into the correct mode for WoWLAN during
  *	suspend. This is optional, if not implemented WoWLAN will not be
  *	supported. This callback may sleep.
+ * @d3_resume: resume the device after WoWLAN, enabling the opmode to
+ *	talk to the WoWLAN image to get its status. This is optional, if not
+ *	implemented WoWLAN will not be supported. This callback may sleep.
  * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
  *	If RFkill is asserted in the middle of a SYNC host command, it must
  *	return -ERFKILL straight away.
@@ -387,20 +410,31 @@
  * @read32: read a u32 register at offset ofs from the BAR
  * @read_prph: read a DWORD from a periphery register
  * @write_prph: write a DWORD to a periphery register
+ * @read_mem: read device's SRAM in DWORD
+ * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory
+ *	will be zeroed.
  * @configure: configure parameters required by the transport layer from
  *	the op_mode. May be called several times before start_fw, can't be
  *	called after that.
  * @set_pmi: set the power pmi state
+ * @grab_nic_access: wake the NIC to be able to access non-HBUS regs.
+ *	Sleeping is not allowed between grab_nic_access and
+ *	release_nic_access.
+ * @release_nic_access: let the NIC go to sleep. The "flags" parameter
+ *	must be the same one that was sent before to the grab_nic_access.
+ * @set_bits_mask - set SRAM register according to value and mask.
  */
 struct iwl_trans_ops {
 
 	int (*start_hw)(struct iwl_trans *iwl_trans);
 	void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
-	int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
+	int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
+			bool run_in_rfkill);
 	void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
 	void (*stop_device)(struct iwl_trans *trans);
 
-	void (*wowlan_suspend)(struct iwl_trans *trans);
+	void (*d3_suspend)(struct iwl_trans *trans);
+	int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
 
 	int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -424,9 +458,19 @@
 	u32 (*read32)(struct iwl_trans *trans, u32 ofs);
 	u32 (*read_prph)(struct iwl_trans *trans, u32 ofs);
 	void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val);
+	int (*read_mem)(struct iwl_trans *trans, u32 addr,
+			void *buf, int dwords);
+	int (*write_mem)(struct iwl_trans *trans, u32 addr,
+			 void *buf, int dwords);
 	void (*configure)(struct iwl_trans *trans,
 			  const struct iwl_trans_config *trans_cfg);
 	void (*set_pmi)(struct iwl_trans *trans, bool state);
+	bool (*grab_nic_access)(struct iwl_trans *trans, bool silent,
+				unsigned long *flags);
+	void (*release_nic_access)(struct iwl_trans *trans,
+				   unsigned long *flags);
+	void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
+			      u32 value);
 };
 
 /**
@@ -446,7 +490,6 @@
  * @ops - pointer to iwl_trans_ops
  * @op_mode - pointer to the op_mode
  * @cfg - pointer to the configuration
- * @reg_lock - protect hw register access
  * @dev - pointer to struct device * that represents the device
  * @hw_id: a u32 with the ID of the device / subdevice.
  *	Set during transport allocation.
@@ -467,7 +510,6 @@
 	struct iwl_op_mode *op_mode;
 	const struct iwl_cfg *cfg;
 	enum iwl_trans_state state;
-	spinlock_t reg_lock;
 
 	struct device *dev;
 	u32 hw_rev;
@@ -485,6 +527,10 @@
 
 	struct dentry *dbgfs_dir;
 
+#ifdef CONFIG_LOCKDEP
+	struct lockdep_map sync_cmd_lockdep_map;
+#endif
+
 	/* pointer to trans specific struct */
 	/*Ensure that this pointer will always be aligned to sizeof pointer */
 	char trans_specific[0] __aligned(sizeof(void *));
@@ -528,13 +574,14 @@
 }
 
 static inline int iwl_trans_start_fw(struct iwl_trans *trans,
-				     const struct fw_img *fw)
+				     const struct fw_img *fw,
+				     bool run_in_rfkill)
 {
 	might_sleep();
 
 	WARN_ON_ONCE(!trans->rx_mpdu_cmd);
 
-	return trans->ops->start_fw(trans, fw);
+	return trans->ops->start_fw(trans, fw, run_in_rfkill);
 }
 
 static inline void iwl_trans_stop_device(struct iwl_trans *trans)
@@ -546,19 +593,36 @@
 	trans->state = IWL_TRANS_NO_FW;
 }
 
-static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
+static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
 {
 	might_sleep();
-	trans->ops->wowlan_suspend(trans);
+	trans->ops->d3_suspend(trans);
+}
+
+static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
+				      enum iwl_d3_status *status)
+{
+	might_sleep();
+	return trans->ops->d3_resume(trans, status);
 }
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
-				struct iwl_host_cmd *cmd)
+				     struct iwl_host_cmd *cmd)
 {
+	int ret;
+
 	WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
 		  "%s bad state = %d", __func__, trans->state);
 
-	return trans->ops->send_cmd(trans, cmd);
+	if (!(cmd->flags & CMD_ASYNC))
+		lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
+
+	ret = trans->ops->send_cmd(trans, cmd);
+
+	if (!(cmd->flags & CMD_ASYNC))
+		lock_map_release(&trans->sync_cmd_lockdep_map);
+
+	return ret;
 }
 
 static inline struct iwl_device_cmd *
@@ -636,7 +700,7 @@
 }
 
 static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
-					    struct dentry *dir)
+					   struct dentry *dir)
 {
 	return trans->ops->dbgfs_register(trans, dir);
 }
@@ -679,15 +743,77 @@
 	return trans->ops->write_prph(trans, ofs, val);
 }
 
+static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
+				     void *buf, int dwords)
+{
+	return trans->ops->read_mem(trans, addr, buf, dwords);
+}
+
+#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize)		      \
+	do {								      \
+		if (__builtin_constant_p(bufsize))			      \
+			BUILD_BUG_ON((bufsize) % sizeof(u32));		      \
+		iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
+	} while (0)
+
+static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
+{
+	u32 value;
+
+	if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1)))
+		return 0xa5a5a5a5;
+
+	return value;
+}
+
+static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
+				      void *buf, int dwords)
+{
+	return trans->ops->write_mem(trans, addr, buf, dwords);
+}
+
+static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
+					u32 val)
+{
+	return iwl_trans_write_mem(trans, addr, &val, 1);
+}
+
 static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
 {
 	trans->ops->set_pmi(trans, state);
 }
 
+static inline void
+iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
+{
+	trans->ops->set_bits_mask(trans, reg, mask, value);
+}
+
+#define iwl_trans_grab_nic_access(trans, silent, flags)	\
+	__cond_lock(nic_access,				\
+		    likely((trans)->ops->grab_nic_access(trans, silent, flags)))
+
+static inline void __releases(nic_access)
+iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
+{
+	trans->ops->release_nic_access(trans, flags);
+	__release(nic_access);
+}
+
 /*****************************************************
 * driver (transport) register/unregister functions
 ******************************************************/
 int __must_check iwl_pci_register_driver(void);
 void iwl_pci_unregister_driver(void);
 
+static inline void trans_lockdep_init(struct iwl_trans *trans)
+{
+#ifdef CONFIG_LOCKDEP
+	static struct lock_class_key __key;
+
+	lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
+			 &__key, 0);
+#endif
+}
+
 #endif /* __iwl_trans_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
new file mode 100644
index 0000000..807b250
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_IWLMVM)   += iwlmvm.o
+iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
+iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
+iwlmvm-y += scan.o time-event.o rs.o
+iwlmvm-y += power.o
+iwlmvm-y += led.o
+iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
+iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
+
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c
new file mode 100644
index 0000000..73d24aa
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/binding.c
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+#include "fw-api.h"
+#include "mvm.h"
+
+struct iwl_mvm_iface_iterator_data {
+	struct ieee80211_vif *ignore_vif;
+	int idx;
+
+	struct iwl_mvm_phy_ctxt *phyctxt;
+
+	u16 ids[MAX_MACS_IN_BINDING];
+	u16 colors[MAX_MACS_IN_BINDING];
+};
+
+static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
+			       struct iwl_mvm_iface_iterator_data *data)
+{
+	struct iwl_binding_cmd cmd;
+	struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
+	int i, ret;
+	u32 status;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
+							   phyctxt->color));
+	cmd.action = cpu_to_le32(action);
+	cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
+						  phyctxt->color));
+
+	for (i = 0; i < MAX_MACS_IN_BINDING; i++)
+		cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
+	for (i = 0; i < data->idx; i++)
+		cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
+							      data->colors[i]));
+
+	status = 0;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
+					  sizeof(cmd), &cmd, &status);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
+			action, ret);
+		return ret;
+	}
+
+	if (status) {
+		IWL_ERR(mvm, "Binding command failed: %u\n", status);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
+				   struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_iface_iterator_data *data = _data;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (vif == data->ignore_vif)
+		return;
+
+	if (mvmvif->phy_ctxt != data->phyctxt)
+		return;
+
+	if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
+		return;
+
+	data->ids[data->idx] = mvmvif->id;
+	data->colors[data->idx] = mvmvif->color;
+	data->idx++;
+}
+
+static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
+				  struct ieee80211_vif *vif,
+				  struct iwl_mvm_phy_ctxt *phyctxt,
+				  bool add)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_iface_iterator_data data = {
+		.ignore_vif = vif,
+		.phyctxt = phyctxt,
+	};
+	u32 action = FW_CTXT_ACTION_MODIFY;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+						   IEEE80211_IFACE_ITER_NORMAL,
+						   iwl_mvm_iface_iterator,
+						   &data);
+
+	/*
+	 * If there are no other interfaces yet we
+	 * need to create a new binding.
+	 */
+	if (data.idx == 0) {
+		if (add)
+			action = FW_CTXT_ACTION_ADD;
+		else
+			action = FW_CTXT_ACTION_REMOVE;
+	}
+
+	if (add) {
+		if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
+			return -EINVAL;
+
+		data.ids[data.idx] = mvmvif->id;
+		data.colors[data.idx] = mvmvif->color;
+		data.idx++;
+	}
+
+	return iwl_mvm_binding_cmd(mvm, action, &data);
+}
+
+int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
+		return -EINVAL;
+
+	return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
+}
+
+int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
+		return -EINVAL;
+
+	return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
new file mode 100644
index 0000000..c64d864
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -0,0 +1,955 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <net/cfg80211.h>
+#include <net/ipv6.h>
+#include "iwl-modparams.h"
+#include "fw-api.h"
+#include "mvm.h"
+
+void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif,
+			    struct cfg80211_gtk_rekey_data *data)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (iwlwifi_mod_params.sw_crypto)
+		return;
+
+	mutex_lock(&mvm->mutex);
+
+	memcpy(mvmvif->rekey_data.kek, data->kek, NL80211_KEK_LEN);
+	memcpy(mvmvif->rekey_data.kck, data->kck, NL80211_KCK_LEN);
+	mvmvif->rekey_data.replay_ctr =
+		cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+	mvmvif->rekey_data.valid = true;
+
+	mutex_unlock(&mvm->mutex);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct inet6_dev *idev)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct inet6_ifaddr *ifa;
+	int idx = 0;
+
+	read_lock_bh(&idev->lock);
+	list_for_each_entry(ifa, &idev->addr_list, if_list) {
+		mvmvif->target_ipv6_addrs[idx] = ifa->addr;
+		idx++;
+		if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS)
+			break;
+	}
+	read_unlock_bh(&idev->lock);
+
+	mvmvif->num_target_ipv6_addrs = idx;
+}
+#endif
+
+void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif, int idx)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	mvmvif->tx_key_idx = idx;
+}
+
+static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out)
+{
+	int i;
+
+	for (i = 0; i < IWL_P1K_SIZE; i++)
+		out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+	struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+	struct iwl_wowlan_tkip_params_cmd *tkip;
+	bool error, use_rsc_tsc, use_tkip;
+	int gtk_key_idx;
+};
+
+static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
+					struct ieee80211_sta *sta,
+					struct ieee80211_key_conf *key,
+					void *_data)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct wowlan_key_data *data = _data;
+	struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+	struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+	struct iwl_p1k_cache *rx_p1ks;
+	u8 *rx_mic_key;
+	struct ieee80211_key_seq seq;
+	u32 cur_rx_iv32 = 0;
+	u16 p1k[IWL_P1K_SIZE];
+	int ret, i;
+
+	mutex_lock(&mvm->mutex);
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */
+		struct {
+			struct iwl_mvm_wep_key_cmd wep_key_cmd;
+			struct iwl_mvm_wep_key wep_key;
+		} __packed wkc = {
+			.wep_key_cmd.mac_id_n_color =
+				cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+								mvmvif->color)),
+			.wep_key_cmd.num_keys = 1,
+			/* firmware sets STA_KEY_FLG_WEP_13BYTES */
+			.wep_key_cmd.decryption_type = STA_KEY_FLG_WEP,
+			.wep_key.key_index = key->keyidx,
+			.wep_key.key_size = key->keylen,
+		};
+
+		/*
+		 * This will fail -- the key functions don't set support
+		 * pairwise WEP keys. However, that's better than silently
+		 * failing WoWLAN. Or maybe not?
+		 */
+		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+			break;
+
+		memcpy(&wkc.wep_key.key[3], key->key, key->keylen);
+		if (key->keyidx == mvmvif->tx_key_idx) {
+			/* TX key must be at offset 0 */
+			wkc.wep_key.key_offset = 0;
+		} else {
+			/* others start at 1 */
+			data->gtk_key_idx++;
+			wkc.wep_key.key_offset = data->gtk_key_idx;
+		}
+
+		ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
+					   sizeof(wkc), &wkc);
+		data->error = ret != 0;
+
+		/* don't upload key again */
+		goto out_unlock;
+	}
+	default:
+		data->error = true;
+		goto out_unlock;
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+		/*
+		 * Ignore CMAC keys -- the WoWLAN firmware doesn't support them
+		 * but we also shouldn't abort suspend due to that. It does have
+		 * support for the IGTK key renewal, but doesn't really use the
+		 * IGTK for anything. This means we could spuriously wake up or
+		 * be deauthenticated, but that was considered acceptable.
+		 */
+		goto out_unlock;
+	case WLAN_CIPHER_SUITE_TKIP:
+		if (sta) {
+			tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+			tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+			rx_p1ks = data->tkip->rx_uni;
+
+			ieee80211_get_key_tx_seq(key, &seq);
+			tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+			tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+			ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+			iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k);
+
+			memcpy(data->tkip->mic_keys.tx,
+			       &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+			       IWL_MIC_KEY_SIZE);
+
+			rx_mic_key = data->tkip->mic_keys.rx_unicast;
+		} else {
+			tkip_sc =
+				data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+			rx_p1ks = data->tkip->rx_multi;
+			rx_mic_key = data->tkip->mic_keys.rx_mcast;
+		}
+
+		/*
+		 * For non-QoS this relies on the fact that both the uCode and
+		 * mac80211 use TID 0 (as they need to to avoid replay attacks)
+		 * for checking the IV in the frames.
+		 */
+		for (i = 0; i < IWL_NUM_RSC; i++) {
+			ieee80211_get_key_rx_seq(key, i, &seq);
+			tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+			tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+			/* wrapping isn't allowed, AP must rekey */
+			if (seq.tkip.iv32 > cur_rx_iv32)
+				cur_rx_iv32 = seq.tkip.iv32;
+		}
+
+		ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,
+					  cur_rx_iv32, p1k);
+		iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k);
+		ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,
+					  cur_rx_iv32 + 1, p1k);
+		iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+		memcpy(rx_mic_key,
+		       &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+		       IWL_MIC_KEY_SIZE);
+
+		data->use_tkip = true;
+		data->use_rsc_tsc = true;
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		if (sta) {
+			u8 *pn = seq.ccmp.pn;
+
+			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+			aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+			ieee80211_get_key_tx_seq(key, &seq);
+			aes_tx_sc->pn = cpu_to_le64((u64)pn[5] |
+						    ((u64)pn[4] << 8) |
+						    ((u64)pn[3] << 16) |
+						    ((u64)pn[2] << 24) |
+						    ((u64)pn[1] << 32) |
+						    ((u64)pn[0] << 40));
+		} else {
+			aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+		}
+
+		/*
+		 * For non-QoS this relies on the fact that both the uCode and
+		 * mac80211 use TID 0 for checking the IV in the frames.
+		 */
+		for (i = 0; i < IWL_NUM_RSC; i++) {
+			u8 *pn = seq.ccmp.pn;
+
+			ieee80211_get_key_rx_seq(key, i, &seq);
+			aes_sc->pn = cpu_to_le64((u64)pn[5] |
+						 ((u64)pn[4] << 8) |
+						 ((u64)pn[3] << 16) |
+						 ((u64)pn[2] << 24) |
+						 ((u64)pn[1] << 32) |
+						 ((u64)pn[0] << 40));
+		}
+		data->use_rsc_tsc = true;
+		break;
+	}
+
+	/*
+	 * The D3 firmware hardcodes the key offset 0 as the key it uses
+	 * to transmit packets to the AP, i.e. the PTK.
+	 */
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
+		key->hw_key_idx = 0;
+	} else {
+		data->gtk_key_idx++;
+		key->hw_key_idx = data->gtk_key_idx;
+	}
+
+	ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
+	data->error = ret != 0;
+out_unlock:
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
+				 struct cfg80211_wowlan *wowlan)
+{
+	struct iwl_wowlan_patterns_cmd *pattern_cmd;
+	struct iwl_host_cmd cmd = {
+		.id = WOWLAN_PATTERNS,
+		.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+		.flags = CMD_SYNC,
+	};
+	int i, err;
+
+	if (!wowlan->n_patterns)
+		return 0;
+
+	cmd.len[0] = sizeof(*pattern_cmd) +
+		wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern);
+
+	pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+	if (!pattern_cmd)
+		return -ENOMEM;
+
+	pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+	for (i = 0; i < wowlan->n_patterns; i++) {
+		int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+		memcpy(&pattern_cmd->patterns[i].mask,
+		       wowlan->patterns[i].mask, mask_len);
+		memcpy(&pattern_cmd->patterns[i].pattern,
+		       wowlan->patterns[i].pattern,
+		       wowlan->patterns[i].pattern_len);
+		pattern_cmd->patterns[i].mask_size = mask_len;
+		pattern_cmd->patterns[i].pattern_size =
+			wowlan->patterns[i].pattern_len;
+	}
+
+	cmd.data[0] = pattern_cmd;
+	err = iwl_mvm_send_cmd(mvm, &cmd);
+	kfree(pattern_cmd);
+	return err;
+}
+
+static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
+				      struct ieee80211_vif *vif)
+{
+	struct iwl_proto_offload_cmd cmd = {};
+#if IS_ENABLED(CONFIG_IPV6)
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int i;
+
+	if (mvmvif->num_target_ipv6_addrs) {
+		cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS);
+		memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN);
+	}
+
+	BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) !=
+		     sizeof(mvmvif->target_ipv6_addrs[i]));
+
+	for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++)
+		memcpy(cmd.target_ipv6_addr[i],
+		       &mvmvif->target_ipv6_addrs[i],
+		       sizeof(cmd.target_ipv6_addr[i]));
+#endif
+
+	if (vif->bss_conf.arp_addr_cnt) {
+		cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP);
+		cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
+		memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN);
+	}
+
+	if (!cmd.enabled)
+		return 0;
+
+	return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC,
+				    sizeof(cmd), &cmd);
+}
+
+struct iwl_d3_iter_data {
+	struct iwl_mvm *mvm;
+	struct ieee80211_vif *vif;
+	bool error;
+};
+
+static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
+				      struct ieee80211_vif *vif)
+{
+	struct iwl_d3_iter_data *data = _data;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+		return;
+
+	if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
+		return;
+
+	if (data->vif) {
+		IWL_ERR(data->mvm, "More than one managed interface active!\n");
+		data->error = true;
+		return;
+	}
+
+	data->vif = vif;
+}
+
+static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+				struct ieee80211_sta *ap_sta)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct ieee80211_chanctx_conf *ctx;
+	u8 chains_static, chains_dynamic;
+	struct cfg80211_chan_def chandef;
+	int ret, i;
+	struct iwl_binding_cmd binding_cmd = {};
+	struct iwl_time_quota_cmd quota_cmd = {};
+	u32 status;
+
+	/* add back the PHY */
+	if (WARN_ON(!mvmvif->phy_ctxt))
+		return -EINVAL;
+
+	rcu_read_lock();
+	ctx = rcu_dereference(vif->chanctx_conf);
+	if (WARN_ON(!ctx)) {
+		rcu_read_unlock();
+		return -EINVAL;
+	}
+	chandef = ctx->def;
+	chains_static = ctx->rx_chains_static;
+	chains_dynamic = ctx->rx_chains_dynamic;
+	rcu_read_unlock();
+
+	ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, &chandef,
+				   chains_static, chains_dynamic);
+	if (ret)
+		return ret;
+
+	/* add back the MAC */
+	mvmvif->uploaded = false;
+
+	if (WARN_ON(!vif->bss_conf.assoc))
+		return -EINVAL;
+	/* hack */
+	vif->bss_conf.assoc = false;
+	ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+	vif->bss_conf.assoc = true;
+	if (ret)
+		return ret;
+
+	/* add back binding - XXX refactor? */
+	binding_cmd.id_and_color =
+		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
+						mvmvif->phy_ctxt->color));
+	binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
+	binding_cmd.phy =
+		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
+						mvmvif->phy_ctxt->color));
+	binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+							      mvmvif->color));
+	for (i = 1; i < MAX_MACS_IN_BINDING; i++)
+		binding_cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
+
+	status = 0;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
+					  sizeof(binding_cmd), &binding_cmd,
+					  &status);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to add binding: %d\n", ret);
+		return ret;
+	}
+
+	if (status) {
+		IWL_ERR(mvm, "Binding command failed: %u\n", status);
+		return -EIO;
+	}
+
+	ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false);
+	if (ret)
+		return ret;
+	rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
+
+	ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
+	if (ret)
+		return ret;
+
+	/* and some quota */
+	quota_cmd.quotas[0].id_and_color =
+		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
+						mvmvif->phy_ctxt->color));
+	quota_cmd.quotas[0].quota = cpu_to_le32(100);
+	quota_cmd.quotas[0].max_duration = cpu_to_le32(1000);
+
+	for (i = 1; i < MAX_BINDINGS; i++)
+		quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
+				   sizeof(quota_cmd), &quota_cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
+
+	return 0;
+}
+
+int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_d3_iter_data suspend_iter_data = {
+		.mvm = mvm,
+	};
+	struct ieee80211_vif *vif;
+	struct iwl_mvm_vif *mvmvif;
+	struct ieee80211_sta *ap_sta;
+	struct iwl_mvm_sta *mvm_ap_sta;
+	struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
+	struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
+	struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
+	struct iwl_d3_manager_config d3_cfg_cmd = {};
+	struct wowlan_key_data key_data = {
+		.use_rsc_tsc = false,
+		.tkip = &tkip_cmd,
+		.use_tkip = false,
+	};
+	int ret, i;
+	u16 seq;
+	u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
+
+	if (WARN_ON(!wowlan))
+		return -EINVAL;
+
+	key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+	if (!key_data.rsc_tsc)
+		return -ENOMEM;
+
+	mutex_lock(&mvm->mutex);
+
+	old_aux_sta_id = mvm->aux_sta.sta_id;
+
+	/* see if there's only a single BSS vif and it's associated */
+	ieee80211_iterate_active_interfaces_atomic(
+		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+		iwl_mvm_d3_iface_iterator, &suspend_iter_data);
+
+	if (suspend_iter_data.error || !suspend_iter_data.vif) {
+		ret = 1;
+		goto out_noreset;
+	}
+
+	vif = suspend_iter_data.vif;
+	mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	ap_sta = rcu_dereference_protected(
+			mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
+			lockdep_is_held(&mvm->mutex));
+	if (IS_ERR_OR_NULL(ap_sta)) {
+		ret = -EINVAL;
+		goto out_noreset;
+	}
+
+	mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+
+	/*
+	 * The D3 firmware still hardcodes the AP station ID for the
+	 * BSS we're associated with as 0. Store the real STA ID here
+	 * and assign 0. When we leave this function, we'll restore
+	 * the original value for the resume code.
+	 */
+	old_ap_sta_id = mvm_ap_sta->sta_id;
+	mvm_ap_sta->sta_id = 0;
+	mvmvif->ap_sta_id = 0;
+
+	/* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
+
+	wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
+
+	/*
+	 * We know the last used seqno, and the uCode expects to know that
+	 * one, it will increment before TX.
+	 */
+	seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ;
+	wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq);
+
+	/*
+	 * For QoS counters, we store the one to use next, so subtract 0x10
+	 * since the uCode will add 0x10 *before* using the value while we
+	 * increment after using the value (i.e. store the next value to use).
+	 */
+	for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+		seq = mvm_ap_sta->tid_data[i].seq_number;
+		seq -= 0x10;
+		wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
+	}
+
+	if (wowlan->disconnect)
+		wowlan_config_cmd.wakeup_filter |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
+				    IWL_WOWLAN_WAKEUP_LINK_CHANGE);
+	if (wowlan->magic_pkt)
+		wowlan_config_cmd.wakeup_filter |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
+	if (wowlan->gtk_rekey_failure)
+		wowlan_config_cmd.wakeup_filter |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+	if (wowlan->eap_identity_req)
+		wowlan_config_cmd.wakeup_filter |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+	if (wowlan->four_way_handshake)
+		wowlan_config_cmd.wakeup_filter |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+	if (wowlan->n_patterns)
+		wowlan_config_cmd.wakeup_filter |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+	if (wowlan->rfkill_release)
+		d3_cfg_cmd.wakeup_flags |=
+			cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
+
+	iwl_mvm_cancel_scan(mvm);
+
+	iwl_trans_stop_device(mvm->trans);
+
+	/*
+	 * Set the HW restart bit -- this is mostly true as we're
+	 * going to load new firmware and reprogram that, though
+	 * the reprogramming is going to be manual to avoid adding
+	 * all the MACs that aren't support.
+	 * We don't have to clear up everything though because the
+	 * reprogramming is manual. When we resume, we'll actually
+	 * go through a proper restart sequence again to switch
+	 * back to the runtime firmware image.
+	 */
+	set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+	/* We reprogram keys and shouldn't allocate new key indices */
+	memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+
+	/*
+	 * The D3 firmware still hardcodes the AP station ID for the
+	 * BSS we're associated with as 0. As a result, we have to move
+	 * the auxiliary station to ID 1 so the ID 0 remains free for
+	 * the AP station for later.
+	 * We set the sta_id to 1 here, and reset it to its previous
+	 * value (that we stored above) later.
+	 */
+	mvm->aux_sta.sta_id = 1;
+
+	ret = iwl_mvm_load_d3_fw(mvm);
+	if (ret)
+		goto out;
+
+	ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
+	if (ret)
+		goto out;
+
+	if (!iwlwifi_mod_params.sw_crypto) {
+		/*
+		 * This needs to be unlocked due to lock ordering
+		 * constraints. Since we're in the suspend path
+		 * that isn't really a problem though.
+		 */
+		mutex_unlock(&mvm->mutex);
+		ieee80211_iter_keys(mvm->hw, vif,
+				    iwl_mvm_wowlan_program_keys,
+				    &key_data);
+		mutex_lock(&mvm->mutex);
+		if (key_data.error) {
+			ret = -EIO;
+			goto out;
+		}
+
+		if (key_data.use_rsc_tsc) {
+			struct iwl_host_cmd rsc_tsc_cmd = {
+				.id = WOWLAN_TSC_RSC_PARAM,
+				.flags = CMD_SYNC,
+				.data[0] = key_data.rsc_tsc,
+				.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+				.len[0] = sizeof(*key_data.rsc_tsc),
+			};
+
+			ret = iwl_mvm_send_cmd(mvm, &rsc_tsc_cmd);
+			if (ret)
+				goto out;
+		}
+
+		if (key_data.use_tkip) {
+			ret = iwl_mvm_send_cmd_pdu(mvm,
+						   WOWLAN_TKIP_PARAM,
+						   CMD_SYNC, sizeof(tkip_cmd),
+						   &tkip_cmd);
+			if (ret)
+				goto out;
+		}
+
+		if (mvmvif->rekey_data.valid) {
+			memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+			memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
+			       NL80211_KCK_LEN);
+			kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+			memcpy(kek_kck_cmd.kek, mvmvif->rekey_data.kek,
+			       NL80211_KEK_LEN);
+			kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+			kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
+
+			ret = iwl_mvm_send_cmd_pdu(mvm,
+						   WOWLAN_KEK_KCK_MATERIAL,
+						   CMD_SYNC,
+						   sizeof(kek_kck_cmd),
+						   &kek_kck_cmd);
+			if (ret)
+				goto out;
+		}
+	}
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION,
+				   CMD_SYNC, sizeof(wowlan_config_cmd),
+				   &wowlan_config_cmd);
+	if (ret)
+		goto out;
+
+	ret = iwl_mvm_send_patterns(mvm, wowlan);
+	if (ret)
+		goto out;
+
+	ret = iwl_mvm_send_proto_offload(mvm, vif);
+	if (ret)
+		goto out;
+
+	/* must be last -- this switches firmware state */
+	ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
+				   sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+	if (ret)
+		goto out;
+
+	clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+	iwl_trans_d3_suspend(mvm->trans);
+ out:
+	mvm->aux_sta.sta_id = old_aux_sta_id;
+	mvm_ap_sta->sta_id = old_ap_sta_id;
+	mvmvif->ap_sta_id = old_ap_sta_id;
+ out_noreset:
+	kfree(key_data.rsc_tsc);
+	if (ret < 0)
+		ieee80211_restart_hw(mvm->hw);
+
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
+					 struct ieee80211_vif *vif)
+{
+	u32 base = mvm->error_event_table;
+	struct error_table_start {
+		/* cf. struct iwl_error_event_table */
+		u32 valid;
+		u32 error_id;
+	} err_info;
+	struct cfg80211_wowlan_wakeup wakeup = {
+		.pattern_idx = -1,
+	};
+	struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
+	struct iwl_host_cmd cmd = {
+		.id = WOWLAN_GET_STATUSES,
+		.flags = CMD_SYNC | CMD_WANT_SKB,
+	};
+	struct iwl_wowlan_status *status;
+	u32 reasons;
+	int ret, len;
+	bool pkt8023 = false;
+	struct sk_buff *pkt = NULL;
+
+	iwl_trans_read_mem_bytes(mvm->trans, base,
+				 &err_info, sizeof(err_info));
+
+	if (err_info.valid) {
+		IWL_INFO(mvm, "error table is valid (%d)\n",
+			 err_info.valid);
+		if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+			wakeup.rfkill_release = true;
+			ieee80211_report_wowlan_wakeup(vif, &wakeup,
+						       GFP_KERNEL);
+		}
+		return;
+	}
+
+	/* only for tracing for now */
+	ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
+	if (ret)
+		IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
+
+	ret = iwl_mvm_send_cmd(mvm, &cmd);
+	if (ret) {
+		IWL_ERR(mvm, "failed to query status (%d)\n", ret);
+		return;
+	}
+
+	/* RF-kill already asserted again... */
+	if (!cmd.resp_pkt)
+		return;
+
+	len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) {
+		IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+		goto out;
+	}
+
+	status = (void *)cmd.resp_pkt->data;
+
+	if (len - sizeof(struct iwl_cmd_header) !=
+	    sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) {
+		IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+		goto out;
+	}
+
+	reasons = le32_to_cpu(status->wakeup_reasons);
+
+	if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
+		wakeup_report = NULL;
+		goto report;
+	}
+
+	if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) {
+		wakeup.magic_pkt = true;
+		pkt8023 = true;
+	}
+
+	if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) {
+		wakeup.pattern_idx =
+			le16_to_cpu(status->pattern_number);
+		pkt8023 = true;
+	}
+
+	if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
+		       IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
+		wakeup.disconnect = true;
+
+	if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) {
+		wakeup.gtk_rekey_failure = true;
+		pkt8023 = true;
+	}
+
+	if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) {
+		wakeup.rfkill_release = true;
+		pkt8023 = true;
+	}
+
+	if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) {
+		wakeup.eap_identity_req = true;
+		pkt8023 = true;
+	}
+
+	if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) {
+		wakeup.four_way_handshake = true;
+		pkt8023 = true;
+	}
+
+	if (status->wake_packet_bufsize) {
+		u32 pktsize = le32_to_cpu(status->wake_packet_bufsize);
+		u32 pktlen = le32_to_cpu(status->wake_packet_length);
+
+		if (pkt8023) {
+			pkt = alloc_skb(pktsize, GFP_KERNEL);
+			if (!pkt)
+				goto report;
+			memcpy(skb_put(pkt, pktsize), status->wake_packet,
+			       pktsize);
+			if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
+				goto report;
+			wakeup.packet = pkt->data;
+			wakeup.packet_present_len = pkt->len;
+			wakeup.packet_len = pkt->len - (pktlen - pktsize);
+			wakeup.packet_80211 = false;
+		} else {
+			wakeup.packet = status->wake_packet;
+			wakeup.packet_present_len = pktsize;
+			wakeup.packet_len = pktlen;
+			wakeup.packet_80211 = true;
+		}
+	}
+
+ report:
+	ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
+	kfree_skb(pkt);
+
+ out:
+	iwl_free_resp(&cmd);
+}
+
+int iwl_mvm_resume(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_d3_iter_data resume_iter_data = {
+		.mvm = mvm,
+	};
+	struct ieee80211_vif *vif = NULL;
+	int ret;
+	enum iwl_d3_status d3_status;
+
+	mutex_lock(&mvm->mutex);
+
+	/* get the BSS vif pointer again */
+	ieee80211_iterate_active_interfaces_atomic(
+		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+		iwl_mvm_d3_iface_iterator, &resume_iter_data);
+
+	if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
+		goto out_unlock;
+
+	vif = resume_iter_data.vif;
+
+	ret = iwl_trans_d3_resume(mvm->trans, &d3_status);
+	if (ret)
+		goto out_unlock;
+
+	if (d3_status != IWL_D3_STATUS_ALIVE) {
+		IWL_INFO(mvm, "Device was reset during suspend\n");
+		goto out_unlock;
+	}
+
+	iwl_mvm_query_wakeup_reasons(mvm, vif);
+
+ out_unlock:
+	mutex_unlock(&mvm->mutex);
+
+	if (vif)
+		ieee80211_resume_disconnect(vif);
+
+	/* return 1 to reconfigure the device */
+	set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+	return 1;
+}
+
+void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	device_set_wakeup_enable(mvm->trans->dev, enabled);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
new file mode 100644
index 0000000..c1bdb55
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -0,0 +1,378 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include "mvm.h"
+#include "sta.h"
+#include "iwl-io.h"
+
+struct iwl_dbgfs_mvm_ctx {
+	struct iwl_mvm *mvm;
+	struct ieee80211_vif *vif;
+};
+
+static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+
+	char buf[16];
+	int buf_size, ret;
+	u32 scd_q_msk;
+
+	if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%x", &scd_q_msk) != 1)
+		return -EINVAL;
+
+	IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
+
+	mutex_lock(&mvm->mutex);
+	ret =  iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_sta_drain_write(struct file *file,
+					 const char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	struct ieee80211_sta *sta;
+
+	char buf[8];
+	int buf_size, sta_id, drain, ret;
+
+	if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
+		return -EIO;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
+		return -EINVAL;
+
+	mutex_lock(&mvm->mutex);
+
+	sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+					lockdep_is_held(&mvm->mutex));
+	if (IS_ERR_OR_NULL(sta))
+		ret = -ENOENT;
+	else
+		ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? :
+			count;
+
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	const struct fw_img *img;
+	int ofs, len, pos = 0;
+	size_t bufsz, ret;
+	char *buf;
+	u8 *ptr;
+
+	/* default is to dump the entire data segment */
+	if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
+		mvm->dbgfs_sram_offset = 0x800000;
+		if (!mvm->ucode_loaded)
+			return -EINVAL;
+		img = &mvm->fw->img[mvm->cur_ucode];
+		mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+	}
+	len = mvm->dbgfs_sram_len;
+
+	bufsz = len * 4 + 256;
+	buf = kzalloc(bufsz, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ptr = kzalloc(len, GFP_KERNEL);
+	if (!ptr) {
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
+	pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
+			 mvm->dbgfs_sram_offset);
+
+	iwl_trans_read_mem_bytes(mvm->trans,
+				 mvm->dbgfs_sram_offset,
+				 ptr, len);
+	for (ofs = 0; ofs < len; ofs += 16) {
+		pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
+		hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
+				   bufsz - pos, false);
+		pos += strlen(buf + pos);
+		if (bufsz - pos > 0)
+			buf[pos++] = '\n';
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+
+	kfree(buf);
+	kfree(ptr);
+
+	return ret;
+}
+
+static ssize_t iwl_dbgfs_sram_write(struct file *file,
+				    const char __user *user_buf, size_t count,
+				    loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	char buf[64];
+	int buf_size;
+	u32 offset, len;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
+		if ((offset & 0x3) || (len & 0x3))
+			return -EINVAL;
+		mvm->dbgfs_sram_offset = offset;
+		mvm->dbgfs_sram_len = len;
+	} else {
+		mvm->dbgfs_sram_offset = 0;
+		mvm->dbgfs_sram_len = 0;
+	}
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	struct ieee80211_sta *sta;
+	char buf[400];
+	int i, pos = 0, bufsz = sizeof(buf);
+
+	mutex_lock(&mvm->mutex);
+
+	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+		pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
+		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+						lockdep_is_held(&mvm->mutex));
+		if (!sta)
+			pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
+		else if (IS_ERR(sta))
+			pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
+					 PTR_ERR(sta));
+		else
+			pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
+					 sta->addr);
+	}
+
+	mutex_unlock(&mvm->mutex);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file,
+						const char __user *user_buf,
+						size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	char buf[8] = {};
+	int allow;
+
+	if (!mvm->ucode_loaded)
+		return -EIO;
+
+	if (copy_from_user(buf, user_buf, sizeof(buf)))
+		return -EFAULT;
+
+	if (sscanf(buf, "%d", &allow) != 1)
+		return -EINVAL;
+
+	IWL_DEBUG_POWER(mvm, "%s device power down\n",
+			allow ? "allow" : "prevent");
+
+	/*
+	 * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
+	 */
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
+						   const char __user *user_buf,
+						   size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	char buf[8] = {};
+	int allow;
+
+	if (copy_from_user(buf, user_buf, sizeof(buf)))
+		return -EFAULT;
+
+	if (sscanf(buf, "%d", &allow) != 1)
+		return -EINVAL;
+
+	IWL_DEBUG_POWER(mvm, "%s device power down in d3\n",
+			allow ? "allow" : "prevent");
+
+	/*
+	 * TODO: When WoWLAN FW alive notification happens, driver will send
+	 * REPLY_DEBUG_CMD setting power_down_allow flag according to
+	 * mvm->prevent_power_down_d3
+	 */
+	mvm->prevent_power_down_d3 = !allow;
+
+	return count;
+}
+
+#define MVM_DEBUGFS_READ_FILE_OPS(name)					\
+static const struct file_operations iwl_dbgfs_##name##_ops = {	\
+	.read = iwl_dbgfs_##name##_read,				\
+	.open = iwl_dbgfs_open_file_generic,				\
+	.llseek = generic_file_llseek,					\
+}
+
+#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name)				\
+static const struct file_operations iwl_dbgfs_##name##_ops = {	\
+	.write = iwl_dbgfs_##name##_write,				\
+	.read = iwl_dbgfs_##name##_read,				\
+	.open = iwl_dbgfs_open_file_generic,				\
+	.llseek = generic_file_llseek,					\
+};
+
+#define MVM_DEBUGFS_WRITE_FILE_OPS(name)				\
+static const struct file_operations iwl_dbgfs_##name##_ops = {	\
+	.write = iwl_dbgfs_##name##_write,				\
+	.open = iwl_dbgfs_open_file_generic,				\
+	.llseek = generic_file_llseek,					\
+};
+
+#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do {			\
+		if (!debugfs_create_file(#name, mode, parent, mvm,	\
+					 &iwl_dbgfs_##name##_ops))	\
+			goto err;					\
+	} while (0)
+
+#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {		\
+		if (!debugfs_create_file(#name, mode, parent, vif,	\
+					 &iwl_dbgfs_##name##_ops))	\
+			goto err;					\
+	} while (0)
+
+/* Device wide debugfs entries */
+MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
+MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
+MVM_DEBUGFS_READ_FILE_OPS(stations);
+MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
+MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
+
+int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
+{
+	char buf[100];
+
+	mvm->debugfs_dir = dbgfs_dir;
+
+	MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
+	MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
+	MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
+	MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
+	MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
+	MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
+
+	/*
+	 * Create a symlink with mac80211. It will be removed when mac80211
+	 * exists (before the opmode exists which removes the target.)
+	 */
+	snprintf(buf, 100, "../../%s/%s",
+		 dbgfs_dir->d_parent->d_parent->d_name.name,
+		 dbgfs_dir->d_parent->d_name.name);
+	if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
+		goto err;
+
+	return 0;
+err:
+	IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
+	return -ENOMEM;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
new file mode 100644
index 0000000..cf6f9a0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -0,0 +1,282 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+
+#ifndef __fw_api_d3_h__
+#define __fw_api_d3_h__
+
+/**
+ * enum iwl_d3_wakeup_flags - D3 manager wakeup flags
+ * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert
+ */
+enum iwl_d3_wakeup_flags {
+	IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0),
+}; /* D3_MANAGER_WAKEUP_CONFIG_API_E_VER_3 */
+
+/**
+ * struct iwl_d3_manager_config - D3 manager configuration command
+ * @min_sleep_time: minimum sleep time (in usec)
+ * @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags
+ *
+ * The structure is used for the D3_CONFIG_CMD command.
+ */
+struct iwl_d3_manager_config {
+	__le32 min_sleep_time;
+	__le32 wakeup_flags;
+} __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_3 */
+
+
+/* TODO: OFFLOADS_QUERY_API_S_VER_1 */
+
+/**
+ * enum iwl_d3_proto_offloads - enabled protocol offloads
+ * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled
+ * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled
+ */
+enum iwl_proto_offloads {
+	IWL_D3_PROTO_OFFLOAD_ARP = BIT(0),
+	IWL_D3_PROTO_OFFLOAD_NS = BIT(1),
+};
+
+#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS	2
+
+/**
+ * struct iwl_proto_offload_cmd - ARP/NS offload configuration
+ * @enabled: enable flags
+ * @remote_ipv4_addr: remote address to answer to (or zero if all)
+ * @host_ipv4_addr: our IPv4 address to respond to queries for
+ * @arp_mac_addr: our MAC address for ARP responses
+ * @remote_ipv6_addr: remote address to answer to (or zero if all)
+ * @solicited_node_ipv6_addr: broken -- solicited node address exists
+ *	for each target address
+ * @target_ipv6_addr: our target addresses
+ * @ndp_mac_addr: neighbor soliciation response MAC address
+ */
+struct iwl_proto_offload_cmd {
+	__le32 enabled;
+	__be32 remote_ipv4_addr;
+	__be32 host_ipv4_addr;
+	u8 arp_mac_addr[ETH_ALEN];
+	__le16 reserved1;
+
+	u8 remote_ipv6_addr[16];
+	u8 solicited_node_ipv6_addr[16];
+	u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16];
+	u8 ndp_mac_addr[ETH_ALEN];
+	__le16 reserved2;
+} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */
+
+
+/*
+ * WOWLAN_PATTERNS
+ */
+#define IWL_WOWLAN_MIN_PATTERN_LEN	16
+#define IWL_WOWLAN_MAX_PATTERN_LEN	128
+
+struct iwl_wowlan_pattern {
+	u8 mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
+	u8 pattern[IWL_WOWLAN_MAX_PATTERN_LEN];
+	u8 mask_size;
+	u8 pattern_size;
+	__le16 reserved;
+} __packed; /* WOWLAN_PATTERN_API_S_VER_1 */
+
+#define IWL_WOWLAN_MAX_PATTERNS	20
+
+struct iwl_wowlan_patterns_cmd {
+	__le32 n_patterns;
+	struct iwl_wowlan_pattern patterns[];
+} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_1 */
+
+enum iwl_wowlan_wakeup_filters {
+	IWL_WOWLAN_WAKEUP_MAGIC_PACKET			= BIT(0),
+	IWL_WOWLAN_WAKEUP_PATTERN_MATCH			= BIT(1),
+	IWL_WOWLAN_WAKEUP_BEACON_MISS			= BIT(2),
+	IWL_WOWLAN_WAKEUP_LINK_CHANGE			= BIT(3),
+	IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL		= BIT(4),
+	IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ			= BIT(5),
+	IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE		= BIT(6),
+	IWL_WOWLAN_WAKEUP_ENABLE_NET_DETECT		= BIT(7),
+	IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT		= BIT(8),
+	IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS		= BIT(9),
+	IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE	= BIT(10),
+	/* BIT(11) reserved */
+	IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET		= BIT(12),
+}; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */
+
+struct iwl_wowlan_config_cmd {
+	__le32 wakeup_filter;
+	__le16 non_qos_seq;
+	__le16 qos_seq[8];
+	u8 wowlan_ba_teardown_tids;
+	u8 is_11n_connection;
+} __packed; /* WOWLAN_CONFIG_API_S_VER_2 */
+
+/*
+ * WOWLAN_TSC_RSC_PARAMS
+ */
+#define IWL_NUM_RSC	16
+
+struct tkip_sc {
+	__le16 iv16;
+	__le16 pad;
+	__le32 iv32;
+} __packed; /* TKIP_SC_API_U_VER_1 */
+
+struct iwl_tkip_rsc_tsc {
+	struct tkip_sc unicast_rsc[IWL_NUM_RSC];
+	struct tkip_sc multicast_rsc[IWL_NUM_RSC];
+	struct tkip_sc tsc;
+} __packed; /* TKIP_TSC_RSC_API_S_VER_1 */
+
+struct aes_sc {
+	__le64 pn;
+} __packed; /* TKIP_AES_SC_API_U_VER_1 */
+
+struct iwl_aes_rsc_tsc {
+	struct aes_sc unicast_rsc[IWL_NUM_RSC];
+	struct aes_sc multicast_rsc[IWL_NUM_RSC];
+	struct aes_sc tsc;
+} __packed; /* AES_TSC_RSC_API_S_VER_1 */
+
+union iwl_all_tsc_rsc {
+	struct iwl_tkip_rsc_tsc tkip;
+	struct iwl_aes_rsc_tsc aes;
+}; /* ALL_TSC_RSC_API_S_VER_2 */
+
+struct iwl_wowlan_rsc_tsc_params_cmd {
+	union iwl_all_tsc_rsc all_tsc_rsc;
+} __packed; /* ALL_TSC_RSC_API_S_VER_2 */
+
+#define IWL_MIC_KEY_SIZE	8
+struct iwl_mic_keys {
+	u8 tx[IWL_MIC_KEY_SIZE];
+	u8 rx_unicast[IWL_MIC_KEY_SIZE];
+	u8 rx_mcast[IWL_MIC_KEY_SIZE];
+} __packed; /* MIC_KEYS_API_S_VER_1 */
+
+#define IWL_P1K_SIZE		5
+struct iwl_p1k_cache {
+	__le16 p1k[IWL_P1K_SIZE];
+} __packed;
+
+#define IWL_NUM_RX_P1K_CACHE	2
+
+struct iwl_wowlan_tkip_params_cmd {
+	struct iwl_mic_keys mic_keys;
+	struct iwl_p1k_cache tx;
+	struct iwl_p1k_cache rx_uni[IWL_NUM_RX_P1K_CACHE];
+	struct iwl_p1k_cache rx_multi[IWL_NUM_RX_P1K_CACHE];
+} __packed; /* WOWLAN_TKIP_SETTING_API_S_VER_1 */
+
+#define IWL_KCK_MAX_SIZE	32
+#define IWL_KEK_MAX_SIZE	32
+
+struct iwl_wowlan_kek_kck_material_cmd {
+	u8	kck[IWL_KCK_MAX_SIZE];
+	u8	kek[IWL_KEK_MAX_SIZE];
+	__le16	kck_len;
+	__le16	kek_len;
+	__le64	replay_ctr;
+} __packed; /* KEK_KCK_MATERIAL_API_S_VER_2 */
+
+#define RF_KILL_INDICATOR_FOR_WOWLAN	0x87
+
+enum iwl_wowlan_rekey_status {
+	IWL_WOWLAN_REKEY_POST_REKEY = 0,
+	IWL_WOWLAN_REKEY_WHILE_REKEY = 1,
+}; /* WOWLAN_REKEY_STATUS_API_E_VER_1 */
+
+enum iwl_wowlan_wakeup_reason {
+	IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS			= 0,
+	IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET			= BIT(0),
+	IWL_WOWLAN_WAKEUP_BY_PATTERN				= BIT(1),
+	IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON	= BIT(2),
+	IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH		= BIT(3),
+	IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE			= BIT(4),
+	IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED			= BIT(5),
+	IWL_WOWLAN_WAKEUP_BY_UCODE_ERROR			= BIT(6),
+	IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST			= BIT(7),
+	IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE			= BIT(8),
+	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS			= BIT(9),
+	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE		= BIT(10),
+	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL		= BIT(11),
+	IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET		= BIT(12),
+}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
+
+struct iwl_wowlan_status {
+	__le64 replay_ctr;
+	__le16 pattern_number;
+	__le16 non_qos_seq_ctr;
+	__le16 qos_seq_ctr[8];
+	__le32 wakeup_reasons;
+	__le32 rekey_status;
+	__le32 num_of_gtk_rekeys;
+	__le32 transmitted_ndps;
+	__le32 received_beacons;
+	__le32 wake_packet_length;
+	__le32 wake_packet_bufsize;
+	u8 wake_packet[]; /* can be truncated from _length to _bufsize */
+} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
+
+/* TODO: NetDetect API */
+
+#endif /* __fw_api_d3_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
new file mode 100644
index 0000000..ae39b7d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+
+#ifndef __fw_api_mac_h__
+#define __fw_api_mac_h__
+
+/*
+ * The first MAC indices (starting from 0)
+ * are available to the driver, AUX follows
+ */
+#define MAC_INDEX_AUX		4
+#define MAC_INDEX_MIN_DRIVER	0
+#define NUM_MAC_INDEX_DRIVER	MAC_INDEX_AUX
+
+#define AC_NUM	4 /* Number of access categories */
+
+/**
+ * enum iwl_mac_protection_flags - MAC context flags
+ * @MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames,
+ *	this will require CCK RTS/CTS2self.
+ *	RTS/CTS will protect full burst time.
+ * @MAC_PROT_FLG_HT_PROT: enable HT protection
+ * @MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions
+ * @MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self
+ */
+enum iwl_mac_protection_flags {
+	MAC_PROT_FLG_TGG_PROTECT	= BIT(3),
+	MAC_PROT_FLG_HT_PROT		= BIT(23),
+	MAC_PROT_FLG_FAT_PROT		= BIT(24),
+	MAC_PROT_FLG_SELF_CTS_EN	= BIT(30),
+};
+
+#define MAC_FLG_SHORT_SLOT		BIT(4)
+#define MAC_FLG_SHORT_PREAMBLE		BIT(5)
+
+/**
+ * enum iwl_mac_types - Supported MAC types
+ * @FW_MAC_TYPE_FIRST: lowest supported MAC type
+ * @FW_MAC_TYPE_AUX: Auxiliary MAC (internal)
+ * @FW_MAC_TYPE_LISTENER: monitor MAC type (?)
+ * @FW_MAC_TYPE_PIBSS: Pseudo-IBSS
+ * @FW_MAC_TYPE_IBSS: IBSS
+ * @FW_MAC_TYPE_BSS_STA: BSS (managed) station
+ * @FW_MAC_TYPE_P2P_DEVICE: P2P Device
+ * @FW_MAC_TYPE_P2P_STA: P2P client
+ * @FW_MAC_TYPE_GO: P2P GO
+ * @FW_MAC_TYPE_TEST: ?
+ * @FW_MAC_TYPE_MAX: highest support MAC type
+ */
+enum iwl_mac_types {
+	FW_MAC_TYPE_FIRST = 1,
+	FW_MAC_TYPE_AUX = FW_MAC_TYPE_FIRST,
+	FW_MAC_TYPE_LISTENER,
+	FW_MAC_TYPE_PIBSS,
+	FW_MAC_TYPE_IBSS,
+	FW_MAC_TYPE_BSS_STA,
+	FW_MAC_TYPE_P2P_DEVICE,
+	FW_MAC_TYPE_P2P_STA,
+	FW_MAC_TYPE_GO,
+	FW_MAC_TYPE_TEST,
+	FW_MAC_TYPE_MAX = FW_MAC_TYPE_TEST
+}; /* MAC_CONTEXT_TYPE_API_E_VER_1 */
+
+/**
+ * enum iwl_tsf_id - TSF hw timer ID
+ * @TSF_ID_A: use TSF A
+ * @TSF_ID_B: use TSF B
+ * @TSF_ID_C: use TSF C
+ * @TSF_ID_D: use TSF D
+ * @NUM_TSF_IDS: number of TSF timers available
+ */
+enum iwl_tsf_id {
+	TSF_ID_A = 0,
+	TSF_ID_B = 1,
+	TSF_ID_C = 2,
+	TSF_ID_D = 3,
+	NUM_TSF_IDS = 4,
+}; /* TSF_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_mac_data_ap - configuration data for AP MAC context
+ * @beacon_time: beacon transmit time in system time
+ * @beacon_tsf: beacon transmit time in TSF
+ * @bi: beacon interval in TU
+ * @bi_reciprocal: 2^32 / bi
+ * @dtim_interval: dtim transmit time in TU
+ * @dtim_reciprocal: 2^32 / dtim_interval
+ * @mcast_qid: queue ID for multicast traffic
+ * @beacon_template: beacon template ID
+ */
+struct iwl_mac_data_ap {
+	__le32 beacon_time;
+	__le64 beacon_tsf;
+	__le32 bi;
+	__le32 bi_reciprocal;
+	__le32 dtim_interval;
+	__le32 dtim_reciprocal;
+	__le32 mcast_qid;
+	__le32 beacon_template;
+} __packed; /* AP_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_ibss - configuration data for IBSS MAC context
+ * @beacon_time: beacon transmit time in system time
+ * @beacon_tsf: beacon transmit time in TSF
+ * @bi: beacon interval in TU
+ * @bi_reciprocal: 2^32 / bi
+ */
+struct iwl_mac_data_ibss {
+	__le32 beacon_time;
+	__le64 beacon_tsf;
+	__le32 bi;
+	__le32 bi_reciprocal;
+} __packed; /* IBSS_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_sta - configuration data for station MAC context
+ * @is_assoc: 1 for associated state, 0 otherwise
+ * @dtim_time: DTIM arrival time in system time
+ * @dtim_tsf: DTIM arrival time in TSF
+ * @bi: beacon interval in TU, applicable only when associated
+ * @bi_reciprocal: 2^32 / bi , applicable only when associated
+ * @dtim_interval: DTIM interval in TU, applicable only when associated
+ * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated
+ * @listen_interval: in beacon intervals, applicable only when associated
+ * @assoc_id: unique ID assigned by the AP during association
+ */
+struct iwl_mac_data_sta {
+	__le32 is_assoc;
+	__le32 dtim_time;
+	__le64 dtim_tsf;
+	__le32 bi;
+	__le32 bi_reciprocal;
+	__le32 dtim_interval;
+	__le32 dtim_reciprocal;
+	__le32 listen_interval;
+	__le32 assoc_id;
+	__le32 assoc_beacon_arrive_time;
+} __packed; /* STA_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_go - configuration data for P2P GO MAC context
+ * @ap: iwl_mac_data_ap struct with most config data
+ * @ctwin: client traffic window in TU (period after TBTT when GO is present).
+ *	0 indicates that there is no CT window.
+ * @opp_ps_enabled: indicate that opportunistic PS allowed
+ */
+struct iwl_mac_data_go {
+	struct iwl_mac_data_ap ap;
+	__le32 ctwin;
+	__le32 opp_ps_enabled;
+} __packed; /* GO_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_p2p_sta - configuration data for P2P client MAC context
+ * @sta: iwl_mac_data_sta struct with most config data
+ * @ctwin: client traffic window in TU (period after TBTT when GO is present).
+ *	0 indicates that there is no CT window.
+ */
+struct iwl_mac_data_p2p_sta {
+	struct iwl_mac_data_sta sta;
+	__le32 ctwin;
+} __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_pibss - Pseudo IBSS config data
+ * @stats_interval: interval in TU between statistics notifications to host.
+ */
+struct iwl_mac_data_pibss {
+	__le32 stats_interval;
+} __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */
+
+/*
+ * struct iwl_mac_data_p2p_dev - configuration data for the P2P Device MAC
+ * context.
+ * @is_disc_extended: if set to true, P2P Device discoverability is enabled on
+ *	other channels as well. This should be to true only in case that the
+ *	device is discoverable and there is an active GO. Note that setting this
+ *	field when not needed, will increase the number of interrupts and have
+ *	effect on the platform power, as this setting opens the Rx filters on
+ *	all macs.
+ */
+struct iwl_mac_data_p2p_dev {
+	__le32 is_disc_extended;
+} __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */
+
+/**
+ * enum iwl_mac_filter_flags - MAC context filter flags
+ * @MAC_FILTER_IN_PROMISC: accept all data frames
+ * @MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and
+ *	control frames to the host
+ * @MAC_FILTER_ACCEPT_GRP: accept multicast frames
+ * @MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames
+ * @MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames
+ * @MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host
+ *	(in station mode when associated)
+ * @MAC_FILTER_OUT_BCAST: filter out all broadcast frames
+ * @MAC_FILTER_IN_CRC32: extract FCS and append it to frames
+ * @MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host
+ */
+enum iwl_mac_filter_flags {
+	MAC_FILTER_IN_PROMISC		= BIT(0),
+	MAC_FILTER_IN_CONTROL_AND_MGMT	= BIT(1),
+	MAC_FILTER_ACCEPT_GRP		= BIT(2),
+	MAC_FILTER_DIS_DECRYPT		= BIT(3),
+	MAC_FILTER_DIS_GRP_DECRYPT	= BIT(4),
+	MAC_FILTER_IN_BEACON		= BIT(6),
+	MAC_FILTER_OUT_BCAST		= BIT(8),
+	MAC_FILTER_IN_CRC32		= BIT(11),
+	MAC_FILTER_IN_PROBE_REQUEST	= BIT(12),
+};
+
+/**
+ * enum iwl_mac_qos_flags - QoS flags
+ * @MAC_QOS_FLG_UPDATE_EDCA: ?
+ * @MAC_QOS_FLG_TGN: HT is enabled
+ * @MAC_QOS_FLG_TXOP_TYPE: ?
+ *
+ */
+enum iwl_mac_qos_flags {
+	MAC_QOS_FLG_UPDATE_EDCA	= BIT(0),
+	MAC_QOS_FLG_TGN		= BIT(1),
+	MAC_QOS_FLG_TXOP_TYPE	= BIT(4),
+};
+
+/**
+ * struct iwl_ac_qos - QOS timing params for MAC_CONTEXT_CMD
+ * @cw_min: Contention window, start value in numbers of slots.
+ *	Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *	Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *	performing random backoff timing prior to Tx).  Device default 1.
+ * @fifos_mask: FIFOs used by this MAC for this AC
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * One instance of this config struct for each of 4 EDCA access categories
+ * in struct iwl_qosparam_cmd.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 fifos_mask;
+	__le16 edca_txop;
+} __packed; /* AC_QOS_API_S_VER_2 */
+
+/**
+ * struct iwl_mac_ctx_cmd - command structure to configure MAC contexts
+ * ( MAC_CONTEXT_CMD = 0x28 )
+ * @id_and_color: ID and color of the MAC
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @mac_type: one of FW_MAC_TYPE_*
+ * @tsd_id: TSF HW timer, one of TSF_ID_*
+ * @node_addr: MAC address
+ * @bssid_addr: BSSID
+ * @cck_rates: basic rates available for CCK
+ * @ofdm_rates: basic rates available for OFDM
+ * @protection_flags: combination of MAC_PROT_FLG_FLAG_*
+ * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise
+ * @short_slot: 0x10 for enabling short slots, 0 otherwise
+ * @filter_flags: combination of MAC_FILTER_*
+ * @qos_flags: from MAC_QOS_FLG_*
+ * @ac: one iwl_mac_qos configuration for each AC
+ * @mac_specific: one of struct iwl_mac_data_*, according to mac_type
+ */
+struct iwl_mac_ctx_cmd {
+	/* COMMON_INDEX_HDR_API_S_VER_1 */
+	__le32 id_and_color;
+	__le32 action;
+	/* MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */
+	__le32 mac_type;
+	__le32 tsf_id;
+	u8 node_addr[6];
+	__le16 reserved_for_node_addr;
+	u8 bssid_addr[6];
+	__le16 reserved_for_bssid_addr;
+	__le32 cck_rates;
+	__le32 ofdm_rates;
+	__le32 protection_flags;
+	__le32 cck_short_preamble;
+	__le32 short_slot;
+	__le32 filter_flags;
+	/* MAC_QOS_PARAM_API_S_VER_1 */
+	__le32 qos_flags;
+	struct iwl_ac_qos ac[AC_NUM+1];
+	/* MAC_CONTEXT_COMMON_DATA_API_S */
+	union {
+		struct iwl_mac_data_ap ap;
+		struct iwl_mac_data_go go;
+		struct iwl_mac_data_sta sta;
+		struct iwl_mac_data_p2p_sta p2p_sta;
+		struct iwl_mac_data_p2p_dev p2p_dev;
+		struct iwl_mac_data_pibss pibss;
+		struct iwl_mac_data_ibss ibss;
+	};
+} __packed; /* MAC_CONTEXT_CMD_API_S_VER_1 */
+
+static inline u32 iwl_mvm_reciprocal(u32 v)
+{
+	if (!v)
+		return 0;
+	return 0xFFFFFFFF / v;
+}
+
+#endif /* __fw_api_mac_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
new file mode 100644
index 0000000..be36b76
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __fw_api_power_h__
+#define __fw_api_power_h__
+
+/* Power Management Commands, Responses, Notifications */
+
+/**
+ * enum iwl_scan_flags - masks for power table command flags
+ * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
+ *		'1' Driver enables PM (use rest of parameters)
+ * @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM,
+ *		'1' PM could sleep over DTIM till listen Interval.
+ * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
+ * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all
+ *		access categories are both delivery and trigger enabled.
+ * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and
+ *		PBW Snoozing enabled
+ * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
+*/
+enum iwl_power_flags {
+	POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK	= BIT(0),
+	POWER_FLAGS_SLEEP_OVER_DTIM_MSK		= BIT(1),
+	POWER_FLAGS_LPRX_ENA_MSK		= BIT(2),
+	POWER_FLAGS_SNOOZE_ENA_MSK		= BIT(3),
+	POWER_FLAGS_BT_SCO_ENA			= BIT(4),
+	POWER_FLAGS_ADVANCE_PM_ENA_MSK		= BIT(5)
+};
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * @id_and_color:	MAC contex identifier
+ * @action:		Action on context - no action, add new,
+ *			modify existent, remove
+ * @flags:		Power table command flags from POWER_FLAGS_*
+ * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec.
+ *			Minimum allowed:- 3 * DTIM
+ * @rx_data_timeout:    Minimum time (usec) from last Rx packet for AM to
+ *			PSM transition - legacy PM
+ * @tx_data_timeout:    Minimum time (usec) from last Tx packet for AM to
+ *			PSM transition - legacy PM
+ * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to
+ *			PSM transition - uAPSD
+ * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to
+ *			PSM transition - uAPSD
+ * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled.
+ *			Default: 80dbm
+ * @num_skip_dtim:      Number of DTIMs to skip if Skip over DTIM flag is set
+ * @snooze_interval:    TBD
+ * @snooze_window:      TBD
+ * @snooze_step:        TBD
+ * @qndp_tid:           TBD
+ * @uapsd_ac_flags:     TBD
+ * @uapsd_max_sp:       TBD
+ */
+struct iwl_powertable_cmd {
+	/* COMMON_INDEX_HDR_API_S_VER_1 */
+	__le32 id_and_color;
+	__le32 action;
+	__le16 flags;
+	u8 reserved;
+	__le16 keep_alive_seconds;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 rx_data_timeout_uapsd;
+	__le32 tx_data_timeout_uapsd;
+	u8 lprx_rssi_threshold;
+	u8 num_skip_dtim;
+	__le16 snooze_interval;
+	__le16 snooze_window;
+	u8 snooze_step;
+	u8 qndp_tid;
+	u8 uapsd_ac_flags;
+	u8 uapsd_max_sp;
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
new file mode 100644
index 0000000..aa3474d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
@@ -0,0 +1,312 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+
+#ifndef __fw_api_rs_h__
+#define __fw_api_rs_h__
+
+#include "fw-api-mac.h"
+
+/*
+ * These serve as indexes into
+ * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT];
+ */
+enum {
+	IWL_RATE_1M_INDEX = 0,
+	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+	IWL_RATE_2M_INDEX,
+	IWL_RATE_5M_INDEX,
+	IWL_RATE_11M_INDEX,
+	IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+	IWL_RATE_6M_INDEX,
+	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+	IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX,
+	IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX,
+	IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX,
+	IWL_RATE_54M_INDEX,
+	IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX,
+	IWL_RATE_60M_INDEX,
+	IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+	IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1,
+	IWL_RATE_COUNT,
+};
+
+#define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX)
+
+/* fw API values for legacy bit rates, both OFDM and CCK */
+enum {
+	IWL_RATE_6M_PLCP  = 13,
+	IWL_RATE_9M_PLCP  = 15,
+	IWL_RATE_12M_PLCP = 5,
+	IWL_RATE_18M_PLCP = 7,
+	IWL_RATE_24M_PLCP = 9,
+	IWL_RATE_36M_PLCP = 11,
+	IWL_RATE_48M_PLCP = 1,
+	IWL_RATE_54M_PLCP = 3,
+	IWL_RATE_1M_PLCP  = 10,
+	IWL_RATE_2M_PLCP  = 20,
+	IWL_RATE_5M_PLCP  = 55,
+	IWL_RATE_11M_PLCP = 110,
+};
+
+/*
+ * rate_n_flags bit fields
+ *
+ * The 32-bit value has different layouts in the low 8 bites depending on the
+ * format. There are three formats, HT, VHT and legacy (11abg, with subformats
+ * for CCK and OFDM).
+ *
+ * High-throughput (HT) rate format
+ *	bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM)
+ * Very High-throughput (VHT) rate format
+ *	bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM)
+ * Legacy OFDM rate format for bits 7:0
+ *	bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM)
+ * Legacy CCK rate format for bits 7:0:
+ *	bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK)
+ */
+
+/* Bit 8: (1) HT format, (0) legacy or VHT format */
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK (1 << RATE_MCS_HT_POS)
+
+/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK (1 << RATE_MCS_CCK_POS)
+
+/* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */
+#define RATE_MCS_VHT_POS 26
+#define RATE_MCS_VHT_MSK (1 << RATE_MCS_VHT_POS)
+
+
+/*
+ * High-throughput (HT) rate format for bits 7:0
+ *
+ *  2-0:  MCS rate base
+ *        0)   6 Mbps
+ *        1)  12 Mbps
+ *        2)  18 Mbps
+ *        3)  24 Mbps
+ *        4)  36 Mbps
+ *        5)  48 Mbps
+ *        6)  54 Mbps
+ *        7)  60 Mbps
+ *  4-3:  0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *        2)  Triple stream (MIMO)
+ *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
+ *  (bits 7-6 are zero)
+ *
+ * Together the low 5 bits work out to the MCS index because we don't
+ * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two
+ * streams and 16-23 have three streams. We could also support MCS 32
+ * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.)
+ */
+#define RATE_HT_MCS_RATE_CODE_MSK	0x7
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_HT_MCS_GF_POS		10
+#define RATE_HT_MCS_GF_MSK		(1 << RATE_HT_MCS_GF_POS)
+
+#define RATE_HT_MCS_INDEX_MSK		0x3f
+
+/*
+ * Very High-throughput (VHT) rate format for bits 7:0
+ *
+ *  3-0:  VHT MCS (0-9)
+ *  5-4:  number of streams - 1:
+ *        0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *        2)  Triple stream (MIMO)
+ */
+
+/* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */
+#define RATE_VHT_MCS_RATE_CODE_MSK	0xf
+#define RATE_VHT_MCS_NSS_POS		4
+#define RATE_VHT_MCS_NSS_MSK		(3 << RATE_VHT_MCS_NSS_POS)
+
+/*
+ * Legacy OFDM rate format for bits 7:0
+ *
+ *  3-0:  0xD)   6 Mbps
+ *        0xF)   9 Mbps
+ *        0x5)  12 Mbps
+ *        0x7)  18 Mbps
+ *        0x9)  24 Mbps
+ *        0xB)  36 Mbps
+ *        0x1)  48 Mbps
+ *        0x3)  54 Mbps
+ * (bits 7-4 are 0)
+ *
+ * Legacy CCK rate format for bits 7:0:
+ * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK):
+ *
+ *  6-0:   10)  1 Mbps
+ *         20)  2 Mbps
+ *         55)  5.5 Mbps
+ *        110)  11 Mbps
+ * (bit 7 is 0)
+ */
+#define RATE_LEGACY_RATE_MSK 0xff
+
+
+/*
+ * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz
+ * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT
+ */
+#define RATE_MCS_CHAN_WIDTH_POS		11
+#define RATE_MCS_CHAN_WIDTH_MSK		(3 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_20		(0 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_40		(1 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_80		(2 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_160		(3 << RATE_MCS_CHAN_WIDTH_POS)
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS		13
+#define RATE_MCS_SGI_MSK		(1 << RATE_MCS_SGI_POS)
+
+/* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */
+#define RATE_MCS_ANT_POS		14
+#define RATE_MCS_ANT_A_MSK		(1 << RATE_MCS_ANT_POS)
+#define RATE_MCS_ANT_B_MSK		(2 << RATE_MCS_ANT_POS)
+#define RATE_MCS_ANT_C_MSK		(4 << RATE_MCS_ANT_POS)
+#define RATE_MCS_ANT_AB_MSK		(RATE_MCS_ANT_A_MSK | \
+					 RATE_MCS_ANT_B_MSK)
+#define RATE_MCS_ANT_ABC_MSK		(RATE_MCS_ANT_AB_MSK | \
+					 RATE_MCS_ANT_C_MSK)
+#define RATE_MCS_ANT_MSK		RATE_MCS_ANT_ABC_MSK
+#define RATE_MCS_ANT_NUM 3
+
+/* Bit 17-18: (0) SS, (1) SS*2 */
+#define RATE_MCS_STBC_POS		17
+#define RATE_MCS_STBC_MSK		(1 << RATE_MCS_STBC_POS)
+
+/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
+#define RATE_MCS_BF_POS			19
+#define RATE_MCS_BF_MSK			(1 << RATE_MCS_BF_POS)
+
+/* Bit 20: (0) ZLF is off, (1) ZLF is on */
+#define RATE_MCS_ZLF_POS		20
+#define RATE_MCS_ZLF_MSK		(1 << RATE_MCS_ZLF_POS)
+
+/* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */
+#define RATE_MCS_DUP_POS		24
+#define RATE_MCS_DUP_MSK		(3 << RATE_MCS_DUP_POS)
+
+/* Bit 27: (1) LDPC enabled, (0) LDPC disabled */
+#define RATE_MCS_LDPC_POS		27
+#define RATE_MCS_LDPC_MSK		(1 << RATE_MCS_LDPC_POS)
+
+
+/* Link Quality definitions */
+
+/* # entries in rate scale table to support Tx retries */
+#define  LQ_MAX_RETRY_NUM 16
+
+/* Link quality command flags, only this one is available */
+#define  LQ_FLAG_SET_STA_TLC_RTS_MSK	BIT(0)
+
+/**
+ * struct iwl_lq_cmd - link quality command
+ * @sta_id: station to update
+ * @control: not used
+ * @flags: combination of LQ_FLAG_*
+ * @mimo_delim: the first SISO index in rs_table, which separates MIMO
+ *	and SISO rates
+ * @single_stream_ant_msk: best antenna for SISO (can be dual in CDD).
+ *	Should be ANT_[ABC]
+ * @dual_stream_ant_msk: best antennas for MIMO, combination of ANT_[ABC]
+ * @initial_rate_index: first index from rs_table per AC category
+ * @agg_time_limit: aggregation max time threshold in usec/100, meaning
+ *	value of 100 is one usec. Range is 100 to 8000
+ * @agg_disable_start_th: try-count threshold for starting aggregation.
+ *	If a frame has higher try-count, it should not be selected for
+ *	starting an aggregation sequence.
+ * @agg_frame_cnt_limit: max frame count in an aggregation.
+ *	0: no limit
+ *	1: no aggregation (one frame per aggregation)
+ *	2 - 0x3f: maximal number of frames (up to 3f == 63)
+ * @rs_table: array of rates for each TX try, each is rate_n_flags,
+ *	meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP
+ * @bf_params: beam forming params, currently not used
+ */
+struct iwl_lq_cmd {
+	u8 sta_id;
+	u8 reserved1;
+	u16 control;
+	/* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */
+	u8 flags;
+	u8 mimo_delim;
+	u8 single_stream_ant_msk;
+	u8 dual_stream_ant_msk;
+	u8 initial_rate_index[AC_NUM];
+	/* LINK_QUAL_AGG_PARAMS_API_S_VER_1 */
+	__le16 agg_time_limit;
+	u8 agg_disable_start_th;
+	u8 agg_frame_cnt_limit;
+	__le32 reserved2;
+	__le32 rs_table[LQ_MAX_RETRY_NUM];
+	__le32 bf_params;
+}; /* LINK_QUALITY_CMD_API_S_VER_1 */
+#endif /* __fw_api_rs_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
new file mode 100644
index 0000000..670ac8f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -0,0 +1,561 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __fw_api_scan_h__
+#define __fw_api_scan_h__
+
+#include "fw-api.h"
+
+/* Scan Commands, Responses, Notifications */
+
+/* Masks for iwl_scan_channel.type flags */
+#define SCAN_CHANNEL_TYPE_PASSIVE	0
+#define SCAN_CHANNEL_TYPE_ACTIVE	BIT(0)
+#define SCAN_CHANNEL_NARROW_BAND	BIT(22)
+
+/* Max number of IEs for direct SSID scans in a command */
+#define PROBE_OPTION_MAX		20
+
+/**
+ * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
+ * @channel: band is selected by iwl_scan_cmd "flags" field
+ * @tx_gain: gain for analog radio
+ * @dsp_atten: gain for DSP
+ * @active_dwell: dwell time for active scan in TU, typically 5-50
+ * @passive_dwell: dwell time for passive scan in TU, typically 20-500
+ * @type: type is broken down to these bits:
+ *	bit 0: 0 = passive, 1 = active
+ *	bits 1-20: SSID direct bit map. If any of these bits is set then
+ *		the corresponding SSID IE is transmitted in probe request
+ *		(bit i adds IE in position i to the probe request)
+ *	bit 22: channel width, 0 = regular, 1 = TGj narrow channel
+ *
+ * @iteration_count:
+ * @iteration_interval:
+ * This struct is used once for each channel in the scan list.
+ * Each channel can independently select:
+ * 1)  SSID for directed active scans
+ * 2)  Txpower setting (for rate specified within Tx command)
+ * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
+ *     quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl_scan_cmd about max_out_time and quiet_time):
+ * 1)  If using passive_dwell (i.e. passive_dwell != 0):
+ *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2)  quiet_time <= active_dwell
+ * 3)  If restricting off-channel time (i.e. max_out_time !=0):
+ *     passive_dwell < max_out_time
+ *     active_dwell < max_out_time
+ */
+struct iwl_scan_channel {
+	__le32 type;
+	__le16 channel;
+	__le16 iteration_count;
+	__le32 iteration_interval;
+	__le16 active_dwell;
+	__le16 passive_dwell;
+} __packed; /* SCAN_CHANNEL_CONTROL_API_S_VER_1 */
+
+/**
+ * struct iwl_ssid_ie - directed scan network information element
+ *
+ * Up to 20 of these may appear in REPLY_SCAN_CMD,
+ * selected by "type" bit field in struct iwl_scan_channel;
+ * each channel may select different ssids from among the 20 entries.
+ * SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl_ssid_ie {
+	u8 id;
+	u8 len;
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+} __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */
+
+/**
+ * iwl_scan_flags - masks for scan command flags
+ *@SCAN_FLAGS_PERIODIC_SCAN:
+ *@SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX:
+ *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND:
+ *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND:
+ *@SCAN_FLAGS_FRAGMENTED_SCAN:
+ */
+enum iwl_scan_flags {
+	SCAN_FLAGS_PERIODIC_SCAN		= BIT(0),
+	SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX	= BIT(1),
+	SCAN_FLAGS_DELAYED_SCAN_LOWBAND		= BIT(2),
+	SCAN_FLAGS_DELAYED_SCAN_HIGHBAND	= BIT(3),
+	SCAN_FLAGS_FRAGMENTED_SCAN		= BIT(4),
+};
+
+/**
+ * enum iwl_scan_type - Scan types for scan command
+ * @SCAN_TYPE_FORCED:
+ * @SCAN_TYPE_BACKGROUND:
+ * @SCAN_TYPE_OS:
+ * @SCAN_TYPE_ROAMING:
+ * @SCAN_TYPE_ACTION:
+ * @SCAN_TYPE_DISCOVERY:
+ * @SCAN_TYPE_DISCOVERY_FORCED:
+ */
+enum iwl_scan_type {
+	SCAN_TYPE_FORCED		= 0,
+	SCAN_TYPE_BACKGROUND		= 1,
+	SCAN_TYPE_OS			= 2,
+	SCAN_TYPE_ROAMING		= 3,
+	SCAN_TYPE_ACTION		= 4,
+	SCAN_TYPE_DISCOVERY		= 5,
+	SCAN_TYPE_DISCOVERY_FORCED	= 6,
+}; /* SCAN_ACTIVITY_TYPE_E_VER_1 */
+
+/* Maximal number of channels to scan */
+#define MAX_NUM_SCAN_CHANNELS 0x24
+
+/**
+ * struct iwl_scan_cmd - scan request command
+ * ( SCAN_REQUEST_CMD = 0x80 )
+ * @len: command length in bytes
+ * @scan_flags: scan flags from SCAN_FLAGS_*
+ * @channel_count: num of channels in channel list (1 - MAX_NUM_SCAN_CHANNELS)
+ * @quiet_time: in msecs, dwell this time for active scan on quiet channels
+ * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than
+ *	this number of packets were received (typically 1)
+ * @passive2active: is auto switching from passive to active allowed (0 or 1)
+ * @rxchain_sel_flags: RXON_RX_CHAIN_*
+ * @max_out_time: in usecs, max out of serving channel time
+ * @suspend_time: how long to pause scan when returning to service channel:
+ *	bits 0-19: beacon interal in usecs (suspend before executing)
+ *	bits 20-23: reserved
+ *	bits 24-31: number of beacons (suspend between channels)
+ * @rxon_flags: RXON_FLG_*
+ * @filter_flags: RXON_FILTER_*
+ * @tx_cmd: for active scans (zero for passive), w/o payload,
+ *	no RS so specify TX rate
+ * @direct_scan: direct scan SSIDs
+ * @type: one of SCAN_TYPE_*
+ * @repeats: how many time to repeat the scan
+ */
+struct iwl_scan_cmd {
+	__le16 len;
+	u8 scan_flags;
+	u8 channel_count;
+	__le16 quiet_time;
+	__le16 quiet_plcp_th;
+	__le16 passive2active;
+	__le16 rxchain_sel_flags;
+	__le32 max_out_time;
+	__le32 suspend_time;
+	/* RX_ON_FLAGS_API_S_VER_1 */
+	__le32 rxon_flags;
+	__le32 filter_flags;
+	struct iwl_tx_cmd tx_cmd;
+	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+	__le32 type;
+	__le32 repeats;
+
+	/*
+	 * Probe request frame, followed by channel list.
+	 *
+	 * Size of probe request frame is specified by byte count in tx_cmd.
+	 * Channel list follows immediately after probe request frame.
+	 * Number of channels in list is specified by channel_count.
+	 * Each channel in list is of type:
+	 *
+	 * struct iwl_scan_channel channels[0];
+	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
+	 * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
+	 * before requesting another scan.
+	 */
+	u8 data[0];
+} __packed; /* SCAN_REQUEST_FIXED_PART_API_S_VER_5 */
+
+/* Response to scan request contains only status with one of these values */
+#define SCAN_RESPONSE_OK	0x1
+#define SCAN_RESPONSE_ERROR	0x2
+
+/*
+ * SCAN_ABORT_CMD = 0x81
+ * When scan abort is requested, the command has no fields except the common
+ * header. The response contains only a status with one of these values.
+ */
+#define SCAN_ABORT_POSSIBLE	0x1
+#define SCAN_ABORT_IGNORED	0x2 /* no pending scans */
+
+/* TODO: complete documentation */
+#define  SCAN_OWNER_STATUS 0x1
+#define  MEASURE_OWNER_STATUS 0x2
+
+/**
+ * struct iwl_scan_start_notif - notifies start of scan in the device
+ * ( SCAN_START_NOTIFICATION = 0x82 )
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @beacon_timer: structured as follows:
+ *	bits 0:19 - beacon interval in usecs
+ *	bits 20:23 - reserved (0)
+ *	bits 24:31 - number of beacons
+ * @channel: which channel is scanned
+ * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
+ * @status: one of *_OWNER_STATUS
+ */
+struct iwl_scan_start_notif {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
+} __packed; /* SCAN_START_NTF_API_S_VER_1 */
+
+/* scan results probe_status first bit indicates success */
+#define SCAN_PROBE_STATUS_OK		0
+#define SCAN_PROBE_STATUS_TX_FAILED	BIT(0)
+/* error statuses combined with TX_FAILED */
+#define SCAN_PROBE_STATUS_FAIL_TTL	BIT(1)
+#define SCAN_PROBE_STATUS_FAIL_BT	BIT(2)
+
+/* How many statistics are gathered for each channel */
+#define SCAN_RESULTS_STATISTICS 1
+
+/**
+ * enum iwl_scan_complete_status - status codes for scan complete notifications
+ * @SCAN_COMP_STATUS_OK:  scan completed successfully
+ * @SCAN_COMP_STATUS_ABORT: scan was aborted by user
+ * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed
+ * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready
+ * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed
+ * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed
+ * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command
+ * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort
+ * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax
+ * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful
+ *	(not an error!)
+ * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver
+ *	asked for
+ * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events
+*/
+enum iwl_scan_complete_status {
+	SCAN_COMP_STATUS_OK = 0x1,
+	SCAN_COMP_STATUS_ABORT = 0x2,
+	SCAN_COMP_STATUS_ERR_SLEEP = 0x3,
+	SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4,
+	SCAN_COMP_STATUS_ERR_PROBE = 0x5,
+	SCAN_COMP_STATUS_ERR_WAKEUP = 0x6,
+	SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7,
+	SCAN_COMP_STATUS_ERR_INTERNAL = 0x8,
+	SCAN_COMP_STATUS_ERR_COEX = 0x9,
+	SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA,
+	SCAN_COMP_STATUS_ITERATION_END = 0x0B,
+	SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C,
+};
+
+/**
+ * struct iwl_scan_results_notif - scan results for one channel
+ * ( SCAN_RESULTS_NOTIFICATION = 0x83 )
+ * @channel: which channel the results are from
+ * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
+ * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request
+ * @num_probe_not_sent: # of request that weren't sent due to not enough time
+ * @duration: duration spent in channel, in usecs
+ * @statistics: statistics gathered for this channel
+ */
+struct iwl_scan_results_notif {
+	u8 channel;
+	u8 band;
+	u8 probe_status;
+	u8 num_probe_not_sent;
+	__le32 duration;
+	__le32 statistics[SCAN_RESULTS_STATISTICS];
+} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */
+
+/**
+ * struct iwl_scan_complete_notif - notifies end of scanning (all channels)
+ * ( SCAN_COMPLETE_NOTIFICATION = 0x84 )
+ * @scanned_channels: number of channels scanned (and number of valid results)
+ * @status: one of SCAN_COMP_STATUS_*
+ * @bt_status: BT on/off status
+ * @last_channel: last channel that was scanned
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @results: all scan results, only "scanned_channels" of them are valid
+ */
+struct iwl_scan_complete_notif {
+	u8 scanned_channels;
+	u8 status;
+	u8 bt_status;
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
+	struct iwl_scan_results_notif results[MAX_NUM_SCAN_CHANNELS];
+} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */
+
+/* scan offload */
+#define IWL_MAX_SCAN_CHANNELS		40
+#define IWL_SCAN_MAX_BLACKLIST_LEN	64
+#define IWL_SCAN_MAX_PROFILES		11
+#define SCAN_OFFLOAD_PROBE_REQ_SIZE	512
+
+/* Default watchdog (in MS) for scheduled scan iteration */
+#define IWL_SCHED_SCAN_WATCHDOG cpu_to_le16(15000)
+
+#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
+#define CAN_ABORT_STATUS 1
+
+#define IWL_FULL_SCAN_MULTIPLIER 5
+#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
+
+/**
+ * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6
+ * @scan_flags:		see enum iwl_scan_flags
+ * @channel_count:	channels in channel list
+ * @quiet_time:		dwell time, in milisiconds, on quiet channel
+ * @quiet_plcp_th:	quiet channel num of packets threshold
+ * @good_CRC_th:	passive to active promotion threshold
+ * @rx_chain:		RXON rx chain.
+ * @max_out_time:	max uSec to be out of assoceated channel
+ * @suspend_time:	pause scan this long when returning to service channel
+ * @flags:		RXON flags
+ * @filter_flags:	RXONfilter
+ * @tx_cmd:		tx command for active scan; for 2GHz and for 5GHz.
+ * @direct_scan:	list of SSIDs for directed active scan
+ * @scan_type:		see enum iwl_scan_type.
+ * @rep_count:		repetition count for each scheduled scan iteration.
+ */
+struct iwl_scan_offload_cmd {
+	__le16 len;
+	u8 scan_flags;
+	u8 channel_count;
+	__le16 quiet_time;
+	__le16 quiet_plcp_th;
+	__le16 good_CRC_th;
+	__le16 rx_chain;
+	__le32 max_out_time;
+	__le32 suspend_time;
+	/* RX_ON_FLAGS_API_S_VER_1 */
+	__le32 flags;
+	__le32 filter_flags;
+	struct iwl_tx_cmd tx_cmd[2];
+	/* SCAN_DIRECT_SSID_IE_API_S_VER_1 */
+	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+	__le32 scan_type;
+	__le32 rep_count;
+} __packed;
+
+enum iwl_scan_offload_channel_flags {
+	IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE		= BIT(0),
+	IWL_SCAN_OFFLOAD_CHANNEL_NARROW		= BIT(22),
+	IWL_SCAN_OFFLOAD_CHANNEL_FULL		= BIT(24),
+	IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL	= BIT(25),
+};
+
+/**
+ * iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S
+ * @type:		bitmap - see enum iwl_scan_offload_channel_flags.
+ *			0:	passive (0) or active (1) scan.
+ *			1-20:	directed scan to i'th ssid.
+ *			22:	channel width configuation - 1 for narrow.
+ *			24:	full scan.
+ *			25:	partial scan.
+ * @channel_number:	channel number 1-13 etc.
+ * @iter_count:		repetition count for the channel.
+ * @iter_interval:	interval between two innteration on one channel.
+ * @dwell_time:	entry 0 - active scan, entry 1 - passive scan.
+ */
+struct iwl_scan_channel_cfg {
+	__le32 type[IWL_MAX_SCAN_CHANNELS];
+	__le16 channel_number[IWL_MAX_SCAN_CHANNELS];
+	__le16 iter_count[IWL_MAX_SCAN_CHANNELS];
+	__le32 iter_interval[IWL_MAX_SCAN_CHANNELS];
+	u8 dwell_time[IWL_MAX_SCAN_CHANNELS][2];
+} __packed;
+
+/**
+ * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S
+ * @scan_cmd:		scan command fixed part
+ * @channel_cfg:	scan channel configuration
+ * @data:		probe request frames (one per band)
+ */
+struct iwl_scan_offload_cfg {
+	struct iwl_scan_offload_cmd scan_cmd;
+	struct iwl_scan_channel_cfg channel_cfg;
+	u8 data[0];
+} __packed;
+
+/**
+ * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
+ * @ssid:		MAC address to filter out
+ * @reported_rssi:	AP rssi reported to the host
+ */
+struct iwl_scan_offload_blacklist {
+	u8 ssid[ETH_ALEN];
+	u8 reported_rssi;
+	u8 reserved;
+} __packed;
+
+enum iwl_scan_offload_network_type {
+	IWL_NETWORK_TYPE_BSS	= 1,
+	IWL_NETWORK_TYPE_IBSS	= 2,
+	IWL_NETWORK_TYPE_ANY	= 3,
+};
+
+enum iwl_scan_offload_band_selection {
+	IWL_SCAN_OFFLOAD_SELECT_2_4	= 0x4,
+	IWL_SCAN_OFFLOAD_SELECT_5_2	= 0x8,
+	IWL_SCAN_OFFLOAD_SELECT_ANY	= 0xc,
+};
+
+/**
+ * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S
+ * @ssid_index:		index to ssid list in fixed part
+ * @unicast_cipher:	encryption olgorithm to match - bitmap
+ * @aut_alg:		authentication olgorithm to match - bitmap
+ * @network_type:	enum iwl_scan_offload_network_type
+ * @band_selection:	enum iwl_scan_offload_band_selection
+ */
+struct iwl_scan_offload_profile {
+	u8 ssid_index;
+	u8 unicast_cipher;
+	u8 auth_alg;
+	u8 network_type;
+	u8 band_selection;
+	u8 reserved[3];
+} __packed;
+
+/**
+ * iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1
+ * @blaclist:		AP list to filter off from scan results
+ * @profiles:		profiles to search for match
+ * @blacklist_len:	length of blacklist
+ * @num_profiles:	num of profiles in the list
+ */
+struct iwl_scan_offload_profile_cfg {
+	struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN];
+	struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
+	u8 blacklist_len;
+	u8 num_profiles;
+	u8 reserved[2];
+} __packed;
+
+/**
+ * iwl_scan_offload_schedule - schedule of scan offload
+ * @delay:		delay between iterations, in seconds.
+ * @iterations:		num of scan iterations
+ * @full_scan_mul:	number of partial scans before each full scan
+ */
+struct iwl_scan_offload_schedule {
+	u16 delay;
+	u8 iterations;
+	u8 full_scan_mul;
+} __packed;
+
+/*
+ * iwl_scan_offload_flags
+ *
+ * IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match
+ *	ssid list.
+ * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
+ * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan
+ *	on A band.
+ */
+enum iwl_scan_offload_flags {
+	IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID	= BIT(0),
+	IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL	= BIT(2),
+	IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN	= BIT(3),
+};
+
+/**
+ * iwl_scan_offload_req - scan offload request command
+ * @flags:		bitmap - enum iwl_scan_offload_flags.
+ * @watchdog:		maximum scan duration in TU.
+ * @delay:		delay in seconds before first iteration.
+ * @schedule_line:	scan offload schedule, for fast and regular scan.
+ */
+struct iwl_scan_offload_req {
+	__le16 flags;
+	__le16 watchdog;
+	__le16 delay;
+	__le16 reserved;
+	struct iwl_scan_offload_schedule schedule_line[2];
+} __packed;
+
+enum iwl_scan_offload_compleate_status {
+	IWL_SCAN_OFFLOAD_COMPLETED	= 1,
+	IWL_SCAN_OFFLOAD_ABORTED	= 2,
+};
+
+/**
+ * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1
+ * @last_schedule_line:		last schedule line executed (fast or regular)
+ * @last_schedule_iteration:	last scan iteration executed before scan abort
+ * @status:			enum iwl_scan_offload_compleate_status
+ */
+struct iwl_scan_offload_complete {
+	u8 last_schedule_line;
+	u8 last_schedule_iteration;
+	u8 status;
+	u8 reserved;
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
new file mode 100644
index 0000000..0acb53d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+
+#ifndef __fw_api_sta_h__
+#define __fw_api_sta_h__
+
+/**
+ * enum iwl_sta_flags - flags for the ADD_STA host command
+ * @STA_FLG_REDUCED_TX_PWR_CTRL:
+ * @STA_FLG_REDUCED_TX_PWR_DATA:
+ * @STA_FLG_FLG_ANT_MSK: Antenna selection
+ * @STA_FLG_PS: set if STA is in Power Save
+ * @STA_FLG_INVALID: set if STA is invalid
+ * @STA_FLG_DLP_EN: Direct Link Protocol is enabled
+ * @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs
+ * @STA_FLG_DRAIN_FLOW: drain flow
+ * @STA_FLG_PAN: STA is for PAN interface
+ * @STA_FLG_CLASS_AUTH:
+ * @STA_FLG_CLASS_ASSOC:
+ * @STA_FLG_CLASS_MIMO_PROT:
+ * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU
+ * @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation
+ * @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is
+ *	initialised by driver and can be updated by fw upon reception of
+ *	action frames that can change the channel width. When cleared the fw
+ *	will send all the frames in 20MHz even when FAT channel is requested.
+ * @STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the
+ *	driver and can be updated by fw upon reception of action frames.
+ * @STA_FLG_MFP_EN: Management Frame Protection
+ */
+enum iwl_sta_flags {
+	STA_FLG_REDUCED_TX_PWR_CTRL	= BIT(3),
+	STA_FLG_REDUCED_TX_PWR_DATA	= BIT(6),
+
+	STA_FLG_FLG_ANT_A		= (1 << 4),
+	STA_FLG_FLG_ANT_B		= (2 << 4),
+	STA_FLG_FLG_ANT_MSK		= (STA_FLG_FLG_ANT_A |
+					   STA_FLG_FLG_ANT_B),
+
+	STA_FLG_PS			= BIT(8),
+	STA_FLG_INVALID			= BIT(9),
+	STA_FLG_DLP_EN			= BIT(10),
+	STA_FLG_SET_ALL_KEYS		= BIT(11),
+	STA_FLG_DRAIN_FLOW		= BIT(12),
+	STA_FLG_PAN			= BIT(13),
+	STA_FLG_CLASS_AUTH		= BIT(14),
+	STA_FLG_CLASS_ASSOC		= BIT(15),
+	STA_FLG_RTS_MIMO_PROT		= BIT(17),
+
+	STA_FLG_MAX_AGG_SIZE_SHIFT	= 19,
+	STA_FLG_MAX_AGG_SIZE_8K		= (0 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_16K	= (1 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_32K	= (2 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_64K	= (3 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_128K	= (4 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_256K	= (5 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_512K	= (6 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_1024K	= (7 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+	STA_FLG_MAX_AGG_SIZE_MSK	= (7 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+
+	STA_FLG_AGG_MPDU_DENS_SHIFT	= 23,
+	STA_FLG_AGG_MPDU_DENS_2US	= (4 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+	STA_FLG_AGG_MPDU_DENS_4US	= (5 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+	STA_FLG_AGG_MPDU_DENS_8US	= (6 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+	STA_FLG_AGG_MPDU_DENS_16US	= (7 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+	STA_FLG_AGG_MPDU_DENS_MSK	= (7 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+
+	STA_FLG_FAT_EN_20MHZ		= (0 << 26),
+	STA_FLG_FAT_EN_40MHZ		= (1 << 26),
+	STA_FLG_FAT_EN_80MHZ		= (2 << 26),
+	STA_FLG_FAT_EN_160MHZ		= (3 << 26),
+	STA_FLG_FAT_EN_MSK		= (3 << 26),
+
+	STA_FLG_MIMO_EN_SISO		= (0 << 28),
+	STA_FLG_MIMO_EN_MIMO2		= (1 << 28),
+	STA_FLG_MIMO_EN_MIMO3		= (2 << 28),
+	STA_FLG_MIMO_EN_MSK		= (3 << 28),
+};
+
+/**
+ * enum iwl_sta_key_flag - key flags for the ADD_STA host command
+ * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm
+ * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
+ *	station info array (1 - n 1X mode)
+ * @STA_KEY_FLG_KEYID_MSK: the index of the key
+ * @STA_KEY_NOT_VALID: key is invalid
+ * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key
+ * @STA_KEY_MULTICAST: set for multical key
+ * @STA_KEY_MFP: key is used for Management Frame Protection
+ */
+enum iwl_sta_key_flag {
+	STA_KEY_FLG_NO_ENC		= (0 << 0),
+	STA_KEY_FLG_WEP			= (1 << 0),
+	STA_KEY_FLG_CCM			= (2 << 0),
+	STA_KEY_FLG_TKIP		= (3 << 0),
+	STA_KEY_FLG_CMAC		= (6 << 0),
+	STA_KEY_FLG_ENC_UNKNOWN		= (7 << 0),
+	STA_KEY_FLG_EN_MSK		= (7 << 0),
+
+	STA_KEY_FLG_WEP_KEY_MAP		= BIT(3),
+	STA_KEY_FLG_KEYID_POS		 = 8,
+	STA_KEY_FLG_KEYID_MSK		= (3 << STA_KEY_FLG_KEYID_POS),
+	STA_KEY_NOT_VALID		= BIT(11),
+	STA_KEY_FLG_WEP_13BYTES		= BIT(12),
+	STA_KEY_MULTICAST		= BIT(14),
+	STA_KEY_MFP			= BIT(15),
+};
+
+/**
+ * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed
+ * @STA_MODIFY_KEY: this command modifies %key
+ * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx
+ * @STA_MODIFY_TX_RATE: unused
+ * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid
+ * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid
+ * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count
+ * @STA_MODIFY_PROT_TH:
+ * @STA_MODIFY_QUEUES: modify the queues used by this station
+ */
+enum iwl_sta_modify_flag {
+	STA_MODIFY_KEY				= BIT(0),
+	STA_MODIFY_TID_DISABLE_TX		= BIT(1),
+	STA_MODIFY_TX_RATE			= BIT(2),
+	STA_MODIFY_ADD_BA_TID			= BIT(3),
+	STA_MODIFY_REMOVE_BA_TID		= BIT(4),
+	STA_MODIFY_SLEEPING_STA_TX_COUNT	= BIT(5),
+	STA_MODIFY_PROT_TH			= BIT(6),
+	STA_MODIFY_QUEUES			= BIT(7),
+};
+
+#define STA_MODE_MODIFY	1
+
+/**
+ * enum iwl_sta_sleep_flag - type of sleep of the station
+ * @STA_SLEEP_STATE_AWAKE:
+ * @STA_SLEEP_STATE_PS_POLL:
+ * @STA_SLEEP_STATE_UAPSD:
+ */
+enum iwl_sta_sleep_flag {
+	STA_SLEEP_STATE_AWAKE	= 0,
+	STA_SLEEP_STATE_PS_POLL	= BIT(0),
+	STA_SLEEP_STATE_UAPSD	= BIT(1),
+};
+
+/* STA ID and color bits definitions */
+#define STA_ID_SEED		(0x0f)
+#define STA_ID_POS		(0)
+#define STA_ID_MSK		(STA_ID_SEED << STA_ID_POS)
+
+#define STA_COLOR_SEED		(0x7)
+#define STA_COLOR_POS		(4)
+#define STA_COLOR_MSK		(STA_COLOR_SEED << STA_COLOR_POS)
+
+#define STA_ID_N_COLOR_GET_COLOR(id_n_color) \
+	(((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS)
+#define STA_ID_N_COLOR_GET_ID(id_n_color)    \
+	(((id_n_color) & STA_ID_MSK) >> STA_ID_POS)
+
+#define STA_KEY_MAX_NUM (16)
+#define STA_KEY_IDX_INVALID (0xff)
+#define STA_KEY_MAX_DATA_KEY_NUM (4)
+#define IWL_MAX_GLOBAL_KEYS (4)
+#define STA_KEY_LEN_WEP40 (5)
+#define STA_KEY_LEN_WEP104 (13)
+
+/**
+ * struct iwl_mvm_keyinfo - key information
+ * @key_flags: type %iwl_sta_key_flag
+ * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
+ * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
+ * @key_offset: key offset in the fw's key table
+ * @key: 16-byte unicast decryption key
+ * @tx_secur_seq_cnt: initial RSC / PN needed for replay check
+ * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only
+ * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only
+ */
+struct iwl_mvm_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];
+	u8 key_offset;
+	u8 reserved2;
+	u8 key[16];
+	__le64 tx_secur_seq_cnt;
+	__le64 hw_tkip_mic_rx_key;
+	__le64 hw_tkip_mic_tx_key;
+} __packed;
+
+/**
+ * struct iwl_mvm_add_sta_cmd - Add / modify a station in the fw's station table
+ * ( REPLY_ADD_STA = 0x18 )
+ * @add_modify: 1: modify existing, 0: add new station
+ * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent
+ * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key
+ *	sent
+ * @mac_id_n_color: the Mac context this station belongs to
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
+ *	alone. 1 - modify, 0 - don't change.
+ * @key: look at %iwl_mvm_keyinfo
+ * @station_flags: look at %iwl_sta_flags
+ * @station_flags_msk: what of %station_flags have changed
+ * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
+ *	AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
+ * @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
+ *	Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
+ *	add_immediate_ba_ssn.
+ * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx)
+ *	Set %STA_MODIFY_REMOVE_BA_TID to use this field
+ * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with
+ *	add_immediate_ba_tid.
+ * @sleep_tx_count: number of packets to transmit to station even though it is
+ *	asleep. Used to synchronise PS-poll and u-APSD responses while ucode
+ *	keeps track of STA sleep state.
+ * @sleep_state_flags: Look at %iwl_sta_sleep_flag.
+ * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP
+ *	mac-addr.
+ * @beamform_flags: beam forming controls
+ * @tfd_queue_msk: tfd queues used by this station
+ *
+ * The device contains an internal table of per-station information, with info
+ * on security keys, aggregation parameters, and Tx rates for initial Tx
+ * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD).
+ *
+ * ADD_STA sets up the table entry for one station, either creating a new
+ * entry, or modifying a pre-existing one.
+ */
+struct iwl_mvm_add_sta_cmd {
+	u8 add_modify;
+	u8 unicast_tx_key_id;
+	u8 multicast_tx_key_id;
+	u8 reserved1;
+	__le32 mac_id_n_color;
+	u8 addr[ETH_ALEN];
+	__le16 reserved2;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved3;
+	struct iwl_mvm_keyinfo key;
+	__le32 station_flags;
+	__le32 station_flags_msk;
+	__le16 tid_disable_tx;
+	__le16 reserved4;
+	u8 add_immediate_ba_tid;
+	u8 remove_immediate_ba_tid;
+	__le16 add_immediate_ba_ssn;
+	__le16 sleep_tx_count;
+	__le16 sleep_state_flags;
+	__le16 assoc_id;
+	__le16 beamform_flags;
+	__le32 tfd_queue_msk;
+} __packed; /* ADD_STA_CMD_API_S_VER_5 */
+
+/**
+ * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command
+ * @ADD_STA_SUCCESS: operation was executed successfully
+ * @ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table
+ * @ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session
+ * @ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station that
+ *	doesn't exist.
+ */
+enum iwl_mvm_add_sta_rsp_status {
+	ADD_STA_SUCCESS			= 0x1,
+	ADD_STA_STATIONS_OVERLOAD	= 0x2,
+	ADD_STA_IMMEDIATE_BA_FAILURE	= 0x4,
+	ADD_STA_MODIFY_NON_EXISTING_STA	= 0x8,
+};
+
+/**
+ * struct iwl_mvm_rm_sta_cmd - Add / modify a station in the fw's station table
+ * ( REMOVE_STA = 0x19 )
+ * @sta_id: the station id of the station to be removed
+ */
+struct iwl_mvm_rm_sta_cmd {
+	u8 sta_id;
+	u8 reserved[3];
+} __packed; /* REMOVE_STA_CMD_API_S_VER_2 */
+
+/**
+ * struct iwl_mvm_mgmt_mcast_key_cmd
+ * ( MGMT_MCAST_KEY = 0x1f )
+ * @ctrl_flags: %iwl_sta_key_flag
+ * @IGTK:
+ * @K1: IGTK master key
+ * @K2: IGTK sub key
+ * @sta_id: station ID that support IGTK
+ * @key_id:
+ * @receive_seq_cnt: initial RSC/PN needed for replay check
+ */
+struct iwl_mvm_mgmt_mcast_key_cmd {
+	__le32 ctrl_flags;
+	u8 IGTK[16];
+	u8 K1[16];
+	u8 K2[16];
+	__le32 key_id;
+	__le32 sta_id;
+	__le64 receive_seq_cnt;
+} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */
+
+struct iwl_mvm_wep_key {
+	u8 key_index;
+	u8 key_offset;
+	__le16 reserved1;
+	u8 key_size;
+	u8 reserved2[3];
+	u8 key[16];
+} __packed;
+
+struct iwl_mvm_wep_key_cmd {
+	__le32 mac_id_n_color;
+	u8 num_keys;
+	u8 decryption_type;
+	u8 flags;
+	u8 reserved;
+	struct iwl_mvm_wep_key wep_key[0];
+} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
+
+
+#endif /* __fw_api_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
new file mode 100644
index 0000000..2677914
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -0,0 +1,580 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+
+#ifndef __fw_api_tx_h__
+#define __fw_api_tx_h__
+
+/**
+ * enum iwl_tx_flags - bitmasks for tx_flags in TX command
+ * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame
+ * @TX_CMD_FLG_ACK: expect ACK from receiving station
+ * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command.
+ *	Otherwise, use rate_n_flags from the TX command
+ * @TX_CMD_FLG_BA: this frame is a block ack
+ * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected
+ *	Must set TX_CMD_FLG_ACK with this flag.
+ * @TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection
+ * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence
+ * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence
+ * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC)
+ * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame
+ * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control.
+ *	Should be set for mgmt, non-QOS data, mcast, bcast and in scan command
+ * @TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU
+ * @TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame
+ * @TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame
+ *	Should be set for beacons and probe responses
+ * @TX_CMD_FLG_CALIB: activate PA TX power calibrations
+ * @TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count
+ * @TX_CMD_FLG_AGG_START: allow this frame to start aggregation
+ * @TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header.
+ *	Should be set for 26/30 length MAC headers
+ * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW
+ * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration
+ * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation
+ * @TX_CMD_FLG_CTS_ONLY: send CTS only, no data after that
+ * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id
+ * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped
+ * @TX_CMD_FLG_EXEC_PAPD: execute PAPD
+ * @TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power
+ * @TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk
+ */
+enum iwl_tx_flags {
+	TX_CMD_FLG_PROT_REQUIRE		= BIT(0),
+	TX_CMD_FLG_ACK			= BIT(3),
+	TX_CMD_FLG_STA_RATE		= BIT(4),
+	TX_CMD_FLG_BA			= BIT(5),
+	TX_CMD_FLG_BAR			= BIT(6),
+	TX_CMD_FLG_TXOP_PROT		= BIT(7),
+	TX_CMD_FLG_VHT_NDPA		= BIT(8),
+	TX_CMD_FLG_HT_NDPA		= BIT(9),
+	TX_CMD_FLG_CSI_FDBK2HOST	= BIT(10),
+	TX_CMD_FLG_BT_DIS		= BIT(12),
+	TX_CMD_FLG_SEQ_CTL		= BIT(13),
+	TX_CMD_FLG_MORE_FRAG		= BIT(14),
+	TX_CMD_FLG_NEXT_FRAME		= BIT(15),
+	TX_CMD_FLG_TSF			= BIT(16),
+	TX_CMD_FLG_CALIB		= BIT(17),
+	TX_CMD_FLG_KEEP_SEQ_CTL		= BIT(18),
+	TX_CMD_FLG_AGG_START		= BIT(19),
+	TX_CMD_FLG_MH_PAD		= BIT(20),
+	TX_CMD_FLG_RESP_TO_DRV		= BIT(21),
+	TX_CMD_FLG_CCMP_AGG		= BIT(22),
+	TX_CMD_FLG_TKIP_MIC_DONE	= BIT(23),
+	TX_CMD_FLG_CTS_ONLY		= BIT(24),
+	TX_CMD_FLG_DUR			= BIT(25),
+	TX_CMD_FLG_FW_DROP		= BIT(26),
+	TX_CMD_FLG_EXEC_PAPD		= BIT(27),
+	TX_CMD_FLG_PAPD_TYPE		= BIT(28),
+	TX_CMD_FLG_HCCA_CHUNK		= BIT(31)
+}; /* TX_FLAGS_BITS_API_S_VER_1 */
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP			0x01
+#define TX_CMD_SEC_CCM			0x02
+#define TX_CMD_SEC_TKIP			0x03
+#define TX_CMD_SEC_WEP_KEY_IDX_POS	6
+#define TX_CMD_SEC_WEP_KEY_IDX_MSK	0xc0
+#define TX_CMD_SEC_KEY128		0x08
+
+/* TODO: how does these values are OK with only 16 bit variable??? */
+/*
+ * TX command next frame info
+ *
+ * bits 0:2 - security control (TX_CMD_SEC_*)
+ * bit 3 - immediate ACK required
+ * bit 4 - rate is taken from STA table
+ * bit 5 - frame belongs to BA stream
+ * bit 6 - immediate BA response expected
+ * bit 7 - unused
+ * bits 8:15 - Station ID
+ * bits 16:31 - rate
+ */
+#define TX_CMD_NEXT_FRAME_ACK_MSK		(0x8)
+#define TX_CMD_NEXT_FRAME_STA_RATE_MSK		(0x10)
+#define TX_CMD_NEXT_FRAME_BA_MSK		(0x20)
+#define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK	(0x40)
+#define TX_CMD_NEXT_FRAME_FLAGS_MSK		(0xf8)
+#define TX_CMD_NEXT_FRAME_STA_ID_MSK		(0xff00)
+#define TX_CMD_NEXT_FRAME_STA_ID_POS		(8)
+#define TX_CMD_NEXT_FRAME_RATE_MSK		(0xffff0000)
+#define TX_CMD_NEXT_FRAME_RATE_POS		(16)
+
+/*
+ * TX command Frame life time in us - to be written in pm_frame_timeout
+ */
+#define TX_CMD_LIFE_TIME_INFINITE	0xFFFFFFFF
+#define TX_CMD_LIFE_TIME_DEFAULT	2000000 /* 2000 ms*/
+#define TX_CMD_LIFE_TIME_PROBE_RESP	40000 /* 40 ms */
+#define TX_CMD_LIFE_TIME_EXPIRED_FRAME	0
+
+/*
+ * TID for non QoS frames - to be written in tid_tspec
+ */
+#define IWL_TID_NON_QOS	IWL_MAX_TID_COUNT
+
+/*
+ * Limits on the retransmissions - to be written in {data,rts}_retry_limit
+ */
+#define IWL_DEFAULT_TX_RETRY			15
+#define IWL_MGMT_DFAULT_RETRY_LIMIT		3
+#define IWL_RTS_DFAULT_RETRY_LIMIT		60
+#define IWL_BAR_DFAULT_RETRY_LIMIT		60
+#define IWL_LOW_RETRY_LIMIT			7
+
+/* TODO: complete documentation for try_cnt and btkill_cnt */
+/**
+ * struct iwl_tx_cmd - TX command struct to FW
+ * ( TX_CMD = 0x1c )
+ * @len: in bytes of the payload, see below for details
+ * @next_frame_len: same as len, but for next frame (0 if not applicable)
+ *	Used for fragmentation and bursting, but not in 11n aggregation.
+ * @tx_flags: combination of TX_CMD_FLG_*
+ * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
+ *	cleared. Combination of RATE_MCS_*
+ * @sta_id: index of destination station in FW station table
+ * @sec_ctl: security control, TX_CMD_SEC_*
+ * @initial_rate_index: index into the the rate table for initial TX attempt.
+ *	Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames.
+ * @key: security key
+ * @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_*
+ * @life_time: frame life time (usecs??)
+ * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt +
+ *	btkill_cnd + reserved), first 32 bits. "0" disables usage.
+ * @dram_msb_ptr: upper bits of the scratch physical address
+ * @rts_retry_limit: max attempts for RTS
+ * @data_retry_limit: max attempts to send the data packet
+ * @tid_spec: TID/tspec
+ * @pm_frame_timeout: PM TX frame timeout
+ * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not
+ *	specified by HCCA protocol
+ *
+ * The byte count (both len and next_frame_len) includes MAC header
+ * (24/26/30/32 bytes)
+ * + 2 bytes pad if 26/30 header size
+ * + 8 byte IV for CCM or TKIP (not used for WEP)
+ * + Data payload
+ * + 8-byte MIC (not used for CCM/WEP)
+ * It does not include post-MAC padding, i.e.,
+ * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.
+ * Range of len: 14-2342 bytes.
+ *
+ * After the struct fields the MAC header is placed, plus any padding,
+ * and then the actial payload.
+ */
+struct iwl_tx_cmd {
+	__le16 len;
+	__le16 next_frame_len;
+	__le32 tx_flags;
+	/* DRAM_SCRATCH_API_U_VER_1 */
+	u8 try_cnt;
+	u8 btkill_cnt;
+	__le16 reserved;
+	__le32 rate_n_flags;
+	u8 sta_id;
+	u8 sec_ctl;
+	u8 initial_rate_index;
+	u8 reserved2;
+	u8 key[16];
+	__le16 next_frame_flags;
+	__le16 reserved3;
+	__le32 life_time;
+	__le32 dram_lsb_ptr;
+	u8 dram_msb_ptr;
+	u8 rts_retry_limit;
+	u8 data_retry_limit;
+	u8 tid_tspec;
+	__le16 pm_frame_timeout;
+	__le16 driver_txop;
+	u8 payload[0];
+	struct ieee80211_hdr hdr[0];
+} __packed; /* TX_CMD_API_S_VER_3 */
+
+/*
+ * TX response related data
+ */
+
+/*
+ * enum iwl_tx_status - status that is returned by the fw after attempts to Tx
+ * @TX_STATUS_SUCCESS:
+ * @TX_STATUS_DIRECT_DONE:
+ * @TX_STATUS_POSTPONE_DELAY:
+ * @TX_STATUS_POSTPONE_FEW_BYTES:
+ * @TX_STATUS_POSTPONE_BT_PRIO:
+ * @TX_STATUS_POSTPONE_QUIET_PERIOD:
+ * @TX_STATUS_POSTPONE_CALC_TTAK:
+ * @TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
+ * @TX_STATUS_FAIL_SHORT_LIMIT:
+ * @TX_STATUS_FAIL_LONG_LIMIT:
+ * @TX_STATUS_FAIL_UNDERRUN:
+ * @TX_STATUS_FAIL_DRAIN_FLOW:
+ * @TX_STATUS_FAIL_RFKILL_FLUSH:
+ * @TX_STATUS_FAIL_LIFE_EXPIRE:
+ * @TX_STATUS_FAIL_DEST_PS:
+ * @TX_STATUS_FAIL_HOST_ABORTED:
+ * @TX_STATUS_FAIL_BT_RETRY:
+ * @TX_STATUS_FAIL_STA_INVALID:
+ * @TX_TATUS_FAIL_FRAG_DROPPED:
+ * @TX_STATUS_FAIL_TID_DISABLE:
+ * @TX_STATUS_FAIL_FIFO_FLUSHED:
+ * @TX_STATUS_FAIL_SMALL_CF_POLL:
+ * @TX_STATUS_FAIL_FW_DROP:
+ * @TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and
+ *	STA table
+ * @TX_FRAME_STATUS_INTERNAL_ABORT:
+ * @TX_MODE_MSK:
+ * @TX_MODE_NO_BURST:
+ * @TX_MODE_IN_BURST_SEQ:
+ * @TX_MODE_FIRST_IN_BURST:
+ * @TX_QUEUE_NUM_MSK:
+ *
+ * Valid only if frame_count =1
+ * TODO: complete documentation
+ */
+enum iwl_tx_status {
+	TX_STATUS_MSK = 0x000000ff,
+	TX_STATUS_SUCCESS = 0x01,
+	TX_STATUS_DIRECT_DONE = 0x02,
+	/* postpone TX */
+	TX_STATUS_POSTPONE_DELAY = 0x40,
+	TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
+	TX_STATUS_POSTPONE_BT_PRIO = 0x42,
+	TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
+	TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
+	/* abort TX */
+	TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
+	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+	TX_STATUS_FAIL_UNDERRUN = 0x84,
+	TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
+	TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
+	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+	TX_STATUS_FAIL_DEST_PS = 0x88,
+	TX_STATUS_FAIL_HOST_ABORTED = 0x89,
+	TX_STATUS_FAIL_BT_RETRY = 0x8a,
+	TX_STATUS_FAIL_STA_INVALID = 0x8b,
+	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+	TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
+	TX_STATUS_FAIL_SMALL_CF_POLL = 0x8f,
+	TX_STATUS_FAIL_FW_DROP = 0x90,
+	TX_STATUS_FAIL_STA_COLOR_MISMATCH = 0x91,
+	TX_STATUS_INTERNAL_ABORT = 0x92,
+	TX_MODE_MSK = 0x00000f00,
+	TX_MODE_NO_BURST = 0x00000000,
+	TX_MODE_IN_BURST_SEQ = 0x00000100,
+	TX_MODE_FIRST_IN_BURST = 0x00000200,
+	TX_QUEUE_NUM_MSK = 0x0001f000,
+	TX_NARROW_BW_MSK = 0x00060000,
+	TX_NARROW_BW_1DIV2 = 0x00020000,
+	TX_NARROW_BW_1DIV4 = 0x00040000,
+	TX_NARROW_BW_1DIV8 = 0x00060000,
+};
+
+/*
+ * enum iwl_tx_agg_status - TX aggregation status
+ * @AGG_TX_STATE_STATUS_MSK:
+ * @AGG_TX_STATE_TRANSMITTED:
+ * @AGG_TX_STATE_UNDERRUN:
+ * @AGG_TX_STATE_BT_PRIO:
+ * @AGG_TX_STATE_FEW_BYTES:
+ * @AGG_TX_STATE_ABORT:
+ * @AGG_TX_STATE_LAST_SENT_TTL:
+ * @AGG_TX_STATE_LAST_SENT_TRY_CNT:
+ * @AGG_TX_STATE_LAST_SENT_BT_KILL:
+ * @AGG_TX_STATE_SCD_QUERY:
+ * @AGG_TX_STATE_TEST_BAD_CRC32:
+ * @AGG_TX_STATE_RESPONSE:
+ * @AGG_TX_STATE_DUMP_TX:
+ * @AGG_TX_STATE_DELAY_TX:
+ * @AGG_TX_STATE_TRY_CNT_MSK: Retry count for 1st frame in aggregation (retries
+ *	occur if tx failed for this frame when it was a member of a previous
+ *	aggregation block). If rate scaling is used, retry count indicates the
+ *	rate table entry used for all frames in the new agg.
+ *@ AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for
+ *	this frame
+ *
+ * TODO: complete documentation
+ */
+enum iwl_tx_agg_status {
+	AGG_TX_STATE_STATUS_MSK = 0x00fff,
+	AGG_TX_STATE_TRANSMITTED = 0x000,
+	AGG_TX_STATE_UNDERRUN = 0x001,
+	AGG_TX_STATE_BT_PRIO = 0x002,
+	AGG_TX_STATE_FEW_BYTES = 0x004,
+	AGG_TX_STATE_ABORT = 0x008,
+	AGG_TX_STATE_LAST_SENT_TTL = 0x010,
+	AGG_TX_STATE_LAST_SENT_TRY_CNT = 0x020,
+	AGG_TX_STATE_LAST_SENT_BT_KILL = 0x040,
+	AGG_TX_STATE_SCD_QUERY = 0x080,
+	AGG_TX_STATE_TEST_BAD_CRC32 = 0x0100,
+	AGG_TX_STATE_RESPONSE = 0x1ff,
+	AGG_TX_STATE_DUMP_TX = 0x200,
+	AGG_TX_STATE_DELAY_TX = 0x400,
+	AGG_TX_STATE_TRY_CNT_POS = 12,
+	AGG_TX_STATE_TRY_CNT_MSK = 0xf << AGG_TX_STATE_TRY_CNT_POS,
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL| \
+				     AGG_TX_STATE_LAST_SENT_TRY_CNT| \
+				     AGG_TX_STATE_LAST_SENT_BT_KILL)
+
+/*
+ * The mask below describes a status where we are absolutely sure that the MPDU
+ * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've
+ * written the bytes to the TXE, but we know nothing about what the DSP did.
+ */
+#define AGG_TX_STAT_FRAME_NOT_SENT (AGG_TX_STATE_FEW_BYTES | \
+				    AGG_TX_STATE_ABORT | \
+				    AGG_TX_STATE_SCD_QUERY)
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1)	No aggregation (frame_count == 1).  This reports Tx results for a single
+ *	frame. Multiple attempts, at various bit rates, may have been made for
+ *	this frame.
+ *
+ * 2)	Aggregation (frame_count > 1).  This reports Tx results for two or more
+ *	frames that used block-acknowledge.  All frames were transmitted at
+ *	same rate. Rate scaling may have been used if first frame in this new
+ *	agg block failed in previous agg block(s).
+ *
+ *	Note that, for aggregation, ACK (block-ack) status is not delivered
+ *	here; block-ack has not been received by the time the device records
+ *	this status.
+ *	This status relates to reasons the tx might have been blocked or aborted
+ *	within the device, rather than whether it was received successfully by
+ *	the destination station.
+ */
+
+/**
+ * struct agg_tx_status - per packet TX aggregation status
+ * @status: enum iwl_tx_agg_status
+ * @sequence: Sequence # for this frame's Tx cmd (not SSN!)
+ */
+struct agg_tx_status {
+	__le16 status;
+	__le16 sequence;
+} __packed;
+
+/*
+ * definitions for initial rate index field
+ * bits [3:0] initial rate index
+ * bits [6:4] rate table color, used for the initial rate
+ * bit-7 invalid rate indication
+ */
+#define TX_RES_INIT_RATE_INDEX_MSK 0x0f
+#define TX_RES_RATE_TABLE_COLOR_MSK 0x70
+#define TX_RES_INV_RATE_INDEX_MSK 0x80
+
+#define IWL_MVM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f)
+#define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4)
+
+/**
+ * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet
+ * ( REPLY_TX = 0x1c )
+ * @frame_count: 1 no aggregation, >1 aggregation
+ * @bt_kill_count: num of times blocked by bluetooth (unused for agg)
+ * @failure_rts: num of failures due to unsuccessful RTS
+ * @failure_frame: num failures due to no ACK (unused for agg)
+ * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the
+ *	Tx of all the batch. RATE_MCS_*
+ * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK.
+ *	for agg: RTS + CTS + aggregation tx time + block-ack time.
+ *	in usec.
+ * @pa_status: tx power info
+ * @pa_integ_res_a: tx power info
+ * @pa_integ_res_b: tx power info
+ * @pa_integ_res_c: tx power info
+ * @measurement_req_id: tx power info
+ * @tfd_info: TFD information set by the FH
+ * @seq_ctl: sequence control from the Tx cmd
+ * @byte_cnt: byte count from the Tx cmd
+ * @tlc_info: TLC rate info
+ * @ra_tid: bits [3:0] = ra, bits [7:4] = tid
+ * @frame_ctrl: frame control
+ * @status: for non-agg:  frame status TX_STATUS_*
+ *	for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields
+ *	follow this one, up to frame_count.
+ *
+ * After the array of statuses comes the SSN of the SCD. Look at
+ * %iwl_mvm_get_scd_ssn for more details.
+ */
+struct iwl_mvm_tx_resp {
+	u8 frame_count;
+	u8 bt_kill_count;
+	u8 failure_rts;
+	u8 failure_frame;
+	__le32 initial_rate;
+	__le16 wireless_media_time;
+
+	u8 pa_status;
+	u8 pa_integ_res_a[3];
+	u8 pa_integ_res_b[3];
+	u8 pa_integ_res_c[3];
+	__le16 measurement_req_id;
+	__le16 reserved;
+
+	__le32 tfd_info;
+	__le16 seq_ctl;
+	__le16 byte_cnt;
+	u8 tlc_info;
+	u8 ra_tid;
+	__le16 frame_ctrl;
+
+	struct agg_tx_status status;
+} __packed; /* TX_RSP_API_S_VER_3 */
+
+/**
+ * struct iwl_mvm_ba_notif - notifies about reception of BA
+ * ( BA_NOTIF = 0xc5 )
+ * @sta_addr_lo32: lower 32 bits of the MAC address
+ * @sta_addr_hi16: upper 16 bits of the MAC address
+ * @sta_id: Index of recipient (BA-sending) station in fw's station table
+ * @tid: tid of the session
+ * @seq_ctl:
+ * @bitmap: the bitmap of the BA notification as seen in the air
+ * @scd_flow: the tx queue this BA relates to
+ * @scd_ssn: the index of the last contiguously sent packet
+ * @txed: number of Txed frames in this batch
+ * @txed_2_done: number of Acked frames in this batch
+ */
+struct iwl_mvm_ba_notif {
+	__le32 sta_addr_lo32;
+	__le16 sta_addr_hi16;
+	__le16 reserved;
+
+	u8 sta_id;
+	u8 tid;
+	__le16 seq_ctl;
+	__le64 bitmap;
+	__le16 scd_flow;
+	__le16 scd_ssn;
+	u8 txed;
+	u8 txed_2_done;
+	__le16 reserved1;
+} __packed;
+
+/*
+ * struct iwl_mac_beacon_cmd - beacon template command
+ * @tx: the tx commands associated with the beacon frame
+ * @template_id: currently equal to the mac context id of the coresponding
+ *  mac.
+ * @tim_idx: the offset of the tim IE in the beacon
+ * @tim_size: the length of the tim IE
+ * @frame: the template of the beacon frame
+ */
+struct iwl_mac_beacon_cmd {
+	struct iwl_tx_cmd tx;
+	__le32 template_id;
+	__le32 tim_idx;
+	__le32 tim_size;
+	struct ieee80211_hdr frame[0];
+} __packed;
+
+/**
+ * enum iwl_dump_control - dump (flush) control flags
+ * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty
+ *	and the TFD queues are empty.
+ */
+enum iwl_dump_control {
+	DUMP_TX_FIFO_FLUSH	= BIT(1),
+};
+
+/**
+ * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command
+ * @queues_ctl: bitmap of queues to flush
+ * @flush_ctl: control flags
+ * @reserved: reserved
+ */
+struct iwl_tx_path_flush_cmd {
+	__le32 queues_ctl;
+	__le16 flush_ctl;
+	__le16 reserved;
+} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */
+
+/**
+ * iwl_mvm_get_scd_ssn - returns the SSN of the SCD
+ * @tx_resp: the Tx response from the fw (agg or non-agg)
+ *
+ * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since
+ * it can't know that everything will go well until the end of the AMPDU, it
+ * can't know in advance the number of MPDUs that will be sent in the current
+ * batch. This is why it writes the agg Tx response while it fetches the MPDUs.
+ * Hence, it can't know in advance what the SSN of the SCD will be at the end
+ * of the batch. This is why the SSN of the SCD is written at the end of the
+ * whole struct at a variable offset. This function knows how to cope with the
+ * variable offset and returns the SSN of the SCD.
+ */
+static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp)
+{
+	return le32_to_cpup((__le32 *)&tx_resp->status +
+			    tx_resp->frame_count) & 0xfff;
+}
+
+#endif /* __fw_api_tx_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
new file mode 100644
index 0000000..23eebda
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -0,0 +1,952 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __fw_api_h__
+#define __fw_api_h__
+
+#include "fw-api-rs.h"
+#include "fw-api-tx.h"
+#include "fw-api-sta.h"
+#include "fw-api-mac.h"
+#include "fw-api-power.h"
+#include "fw-api-d3.h"
+
+/* queue and FIFO numbers by usage */
+enum {
+	IWL_MVM_OFFCHANNEL_QUEUE = 8,
+	IWL_MVM_CMD_QUEUE = 9,
+	IWL_MVM_AUX_QUEUE = 15,
+	IWL_MVM_FIRST_AGG_QUEUE = 16,
+	IWL_MVM_NUM_QUEUES = 20,
+	IWL_MVM_LAST_AGG_QUEUE = IWL_MVM_NUM_QUEUES - 1,
+	IWL_MVM_CMD_FIFO = 7
+};
+
+#define IWL_MVM_STATION_COUNT	16
+
+/* commands */
+enum {
+	MVM_ALIVE = 0x1,
+	REPLY_ERROR = 0x2,
+
+	INIT_COMPLETE_NOTIF = 0x4,
+
+	/* PHY context commands */
+	PHY_CONTEXT_CMD = 0x8,
+	DBG_CFG = 0x9,
+
+	/* station table */
+	ADD_STA = 0x18,
+	REMOVE_STA = 0x19,
+
+	/* TX */
+	TX_CMD = 0x1c,
+	TXPATH_FLUSH = 0x1e,
+	MGMT_MCAST_KEY = 0x1f,
+
+	/* global key */
+	WEP_KEY = 0x20,
+
+	/* MAC and Binding commands */
+	MAC_CONTEXT_CMD = 0x28,
+	TIME_EVENT_CMD = 0x29, /* both CMD and response */
+	TIME_EVENT_NOTIFICATION = 0x2a,
+	BINDING_CONTEXT_CMD = 0x2b,
+	TIME_QUOTA_CMD = 0x2c,
+
+	LQ_CMD = 0x4e,
+
+	/* Calibration */
+	TEMPERATURE_NOTIFICATION = 0x62,
+	CALIBRATION_CFG_CMD = 0x65,
+	CALIBRATION_RES_NOTIFICATION = 0x66,
+	CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
+	RADIO_VERSION_NOTIFICATION = 0x68,
+
+	/* Scan offload */
+	SCAN_OFFLOAD_REQUEST_CMD = 0x51,
+	SCAN_OFFLOAD_ABORT_CMD = 0x52,
+	SCAN_OFFLOAD_COMPLETE = 0x6D,
+	SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
+	SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
+
+	/* Phy */
+	PHY_CONFIGURATION_CMD = 0x6a,
+	CALIB_RES_NOTIF_PHY_DB = 0x6b,
+	/* PHY_DB_CMD = 0x6c, */
+
+	/* Power */
+	POWER_TABLE_CMD = 0x77,
+
+	/* Scanning */
+	SCAN_REQUEST_CMD = 0x80,
+	SCAN_ABORT_CMD = 0x81,
+	SCAN_START_NOTIFICATION = 0x82,
+	SCAN_RESULTS_NOTIFICATION = 0x83,
+	SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+	/* NVM */
+	NVM_ACCESS_CMD = 0x88,
+
+	SET_CALIB_DEFAULT_CMD = 0x8e,
+
+	BEACON_TEMPLATE_CMD = 0x91,
+	TX_ANT_CONFIGURATION_CMD = 0x98,
+	STATISTICS_NOTIFICATION = 0x9d,
+
+	/* RF-KILL commands and notifications */
+	CARD_STATE_CMD = 0xa0,
+	CARD_STATE_NOTIFICATION = 0xa1,
+
+	REPLY_RX_PHY_CMD = 0xc0,
+	REPLY_RX_MPDU_CMD = 0xc1,
+	BA_NOTIF = 0xc5,
+
+	REPLY_DEBUG_CMD = 0xf0,
+	DEBUG_LOG_MSG = 0xf7,
+
+	/* D3 commands/notifications */
+	D3_CONFIG_CMD = 0xd3,
+	PROT_OFFLOAD_CONFIG_CMD = 0xd4,
+	OFFLOADS_QUERY_CMD = 0xd5,
+	REMOTE_WAKE_CONFIG_CMD = 0xd6,
+
+	/* for WoWLAN in particular */
+	WOWLAN_PATTERNS = 0xe0,
+	WOWLAN_CONFIGURATION = 0xe1,
+	WOWLAN_TSC_RSC_PARAM = 0xe2,
+	WOWLAN_TKIP_PARAM = 0xe3,
+	WOWLAN_KEK_KCK_MATERIAL = 0xe4,
+	WOWLAN_GET_STATUSES = 0xe5,
+	WOWLAN_TX_POWER_PER_DB = 0xe6,
+
+	/* and for NetDetect */
+	NET_DETECT_CONFIG_CMD = 0x54,
+	NET_DETECT_PROFILES_QUERY_CMD = 0x56,
+	NET_DETECT_PROFILES_CMD = 0x57,
+	NET_DETECT_HOTSPOTS_CMD = 0x58,
+	NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59,
+
+	REPLY_MAX = 0xff,
+};
+
+/**
+ * struct iwl_cmd_response - generic response struct for most commands
+ * @status: status of the command asked, changes for each one
+ */
+struct iwl_cmd_response {
+	__le32 status;
+};
+
+/*
+ * struct iwl_tx_ant_cfg_cmd
+ * @valid: valid antenna configuration
+ */
+struct iwl_tx_ant_cfg_cmd {
+	__le32 valid;
+} __packed;
+
+/*
+ * Calibration control struct.
+ * Sent as part of the phy configuration command.
+ * @flow_trigger: bitmap for which calibrations to perform according to
+ *		flow triggers.
+ * @event_trigger: bitmap for which calibrations to perform according to
+ *		event triggers.
+ */
+struct iwl_calib_ctrl {
+	__le32 flow_trigger;
+	__le32 event_trigger;
+} __packed;
+
+/* This enum defines the bitmap of various calibrations to enable in both
+ * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
+ */
+enum iwl_calib_cfg {
+	IWL_CALIB_CFG_XTAL_IDX			= BIT(0),
+	IWL_CALIB_CFG_TEMPERATURE_IDX		= BIT(1),
+	IWL_CALIB_CFG_VOLTAGE_READ_IDX		= BIT(2),
+	IWL_CALIB_CFG_PAPD_IDX			= BIT(3),
+	IWL_CALIB_CFG_TX_PWR_IDX		= BIT(4),
+	IWL_CALIB_CFG_DC_IDX			= BIT(5),
+	IWL_CALIB_CFG_BB_FILTER_IDX		= BIT(6),
+	IWL_CALIB_CFG_LO_LEAKAGE_IDX		= BIT(7),
+	IWL_CALIB_CFG_TX_IQ_IDX			= BIT(8),
+	IWL_CALIB_CFG_TX_IQ_SKEW_IDX		= BIT(9),
+	IWL_CALIB_CFG_RX_IQ_IDX			= BIT(10),
+	IWL_CALIB_CFG_RX_IQ_SKEW_IDX		= BIT(11),
+	IWL_CALIB_CFG_SENSITIVITY_IDX		= BIT(12),
+	IWL_CALIB_CFG_CHAIN_NOISE_IDX		= BIT(13),
+	IWL_CALIB_CFG_DISCONNECTED_ANT_IDX	= BIT(14),
+	IWL_CALIB_CFG_ANT_COUPLING_IDX		= BIT(15),
+	IWL_CALIB_CFG_DAC_IDX			= BIT(16),
+	IWL_CALIB_CFG_ABS_IDX			= BIT(17),
+	IWL_CALIB_CFG_AGC_IDX			= BIT(18),
+};
+
+/*
+ * Phy configuration command.
+ */
+struct iwl_phy_cfg_cmd {
+	__le32	phy_cfg;
+	struct iwl_calib_ctrl calib_control;
+} __packed;
+
+#define PHY_CFG_RADIO_TYPE	(BIT(0) | BIT(1))
+#define PHY_CFG_RADIO_STEP	(BIT(2) | BIT(3))
+#define PHY_CFG_RADIO_DASH	(BIT(4) | BIT(5))
+#define PHY_CFG_PRODUCT_NUMBER	(BIT(6) | BIT(7))
+#define PHY_CFG_TX_CHAIN_A	BIT(8)
+#define PHY_CFG_TX_CHAIN_B	BIT(9)
+#define PHY_CFG_TX_CHAIN_C	BIT(10)
+#define PHY_CFG_RX_CHAIN_A	BIT(12)
+#define PHY_CFG_RX_CHAIN_B	BIT(13)
+#define PHY_CFG_RX_CHAIN_C	BIT(14)
+
+
+/* Target of the NVM_ACCESS_CMD */
+enum {
+	NVM_ACCESS_TARGET_CACHE = 0,
+	NVM_ACCESS_TARGET_OTP = 1,
+	NVM_ACCESS_TARGET_EEPROM = 2,
+};
+
+/**
+ * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM.
+ * @op_code: 0 - read, 1 - write.
+ * @target: NVM_ACCESS_TARGET_*. should be 0 for read.
+ * @cache_refresh: 0 - None, 1- NVM.
+ * @offset: offset in the nvm data.
+ * @length: of the chunk.
+ * @data: empty on read, the NVM chunk on write
+ */
+struct iwl_nvm_access_cmd_ver1 {
+	u8 op_code;
+	u8 target;
+	u8 cache_refresh;
+	u8 reserved;
+	__le16 offset;
+	__le16 length;
+	u8 data[];
+} __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD
+ * @offset: the offset in the nvm data
+ * @length: of the chunk
+ * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write
+ */
+struct iwl_nvm_access_resp_ver1 {
+	__le16 offset;
+	__le16 length;
+	u8 data[];
+} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */
+
+/* Section types for NVM_ACCESS_CMD version 2 */
+enum {
+	NVM_SECTION_TYPE_HW = 0,
+	NVM_SECTION_TYPE_SW,
+	NVM_SECTION_TYPE_PAPD,
+	NVM_SECTION_TYPE_BT,
+	NVM_SECTION_TYPE_CALIBRATION,
+	NVM_SECTION_TYPE_PRODUCTION,
+	NVM_SECTION_TYPE_POST_FCS_CALIB,
+	NVM_NUM_OF_SECTIONS,
+};
+
+/**
+ * struct iwl_nvm_access_cmd_ver2 - Request the device to send an NVM section
+ * @op_code: 0 - read, 1 - write
+ * @target: NVM_ACCESS_TARGET_*
+ * @type: NVM_SECTION_TYPE_*
+ * @offset: offset in bytes into the section
+ * @length: in bytes, to read/write
+ * @data: if write operation, the data to write. On read its empty
+ */
+struct iwl_nvm_access_cmd_ver2 {
+	u8 op_code;
+	u8 target;
+	__le16 type;
+	__le16 offset;
+	__le16 length;
+	u8 data[];
+} __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */
+
+/**
+ * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD
+ * @offset: offset in bytes into the section
+ * @length: in bytes, either how much was written or read
+ * @type: NVM_SECTION_TYPE_*
+ * @status: 0 for success, fail otherwise
+ * @data: if read operation, the data returned. Empty on write.
+ */
+struct iwl_nvm_access_resp_ver2 {
+	__le16 offset;
+	__le16 length;
+	__le16 type;
+	__le16 status;
+	u8 data[];
+} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_2 */
+
+/* MVM_ALIVE 0x1 */
+
+/* alive response is_valid values */
+#define ALIVE_RESP_UCODE_OK	BIT(0)
+#define ALIVE_RESP_RFKILL	BIT(1)
+
+/* alive response ver_type values */
+enum {
+	FW_TYPE_HW = 0,
+	FW_TYPE_PROT = 1,
+	FW_TYPE_AP = 2,
+	FW_TYPE_WOWLAN = 3,
+	FW_TYPE_TIMING = 4,
+	FW_TYPE_WIPAN = 5
+};
+
+/* alive response ver_subtype values */
+enum {
+	FW_SUBTYPE_FULL_FEATURE = 0,
+	FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */
+	FW_SUBTYPE_REDUCED = 2,
+	FW_SUBTYPE_ALIVE_ONLY = 3,
+	FW_SUBTYPE_WOWLAN = 4,
+	FW_SUBTYPE_AP_SUBTYPE = 5,
+	FW_SUBTYPE_WIPAN = 6,
+	FW_SUBTYPE_INITIALIZE = 9
+};
+
+#define IWL_ALIVE_STATUS_ERR 0xDEAD
+#define IWL_ALIVE_STATUS_OK 0xCAFE
+
+#define IWL_ALIVE_FLG_RFKILL	BIT(0)
+
+struct mvm_alive_resp {
+	__le16 status;
+	__le16 flags;
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 id;
+	u8 api_minor;
+	u8 api_major;
+	u8 ver_subtype;
+	u8 ver_type;
+	u8 mac;
+	u8 opt;
+	__le16 reserved2;
+	__le32 timestamp;
+	__le32 error_event_table_ptr;	/* SRAM address for error log */
+	__le32 log_event_table_ptr;	/* SRAM address for event log */
+	__le32 cpu_register_ptr;
+	__le32 dbgm_config_ptr;
+	__le32 alive_counter_ptr;
+	__le32 scd_base_ptr;		/* SRAM address for SCD */
+} __packed; /* ALIVE_RES_API_S_VER_1 */
+
+/* Error response/notification */
+enum {
+	FW_ERR_UNKNOWN_CMD = 0x0,
+	FW_ERR_INVALID_CMD_PARAM = 0x1,
+	FW_ERR_SERVICE = 0x2,
+	FW_ERR_ARC_MEMORY = 0x3,
+	FW_ERR_ARC_CODE = 0x4,
+	FW_ERR_WATCH_DOG = 0x5,
+	FW_ERR_WEP_GRP_KEY_INDX = 0x10,
+	FW_ERR_WEP_KEY_SIZE = 0x11,
+	FW_ERR_OBSOLETE_FUNC = 0x12,
+	FW_ERR_UNEXPECTED = 0xFE,
+	FW_ERR_FATAL = 0xFF
+};
+
+/**
+ * struct iwl_error_resp - FW error indication
+ * ( REPLY_ERROR = 0x2 )
+ * @error_type: one of FW_ERR_*
+ * @cmd_id: the command ID for which the error occured
+ * @bad_cmd_seq_num: sequence number of the erroneous command
+ * @error_service: which service created the error, applicable only if
+ *	error_type = 2, otherwise 0
+ * @timestamp: TSF in usecs.
+ */
+struct iwl_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+	__le32 error_service;
+	__le64 timestamp;
+} __packed;
+
+
+/* Common PHY, MAC and Bindings definitions */
+
+#define MAX_MACS_IN_BINDING	(3)
+#define MAX_BINDINGS		(4)
+#define AUX_BINDING_INDEX	(3)
+#define MAX_PHYS		(4)
+
+/* Used to extract ID and color from the context dword */
+#define FW_CTXT_ID_POS	  (0)
+#define FW_CTXT_ID_MSK	  (0xff << FW_CTXT_ID_POS)
+#define FW_CTXT_COLOR_POS (8)
+#define FW_CTXT_COLOR_MSK (0xff << FW_CTXT_COLOR_POS)
+#define FW_CTXT_INVALID	  (0xffffffff)
+
+#define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\
+					  (_color << FW_CTXT_COLOR_POS))
+
+/* Possible actions on PHYs, MACs and Bindings */
+enum {
+	FW_CTXT_ACTION_STUB = 0,
+	FW_CTXT_ACTION_ADD,
+	FW_CTXT_ACTION_MODIFY,
+	FW_CTXT_ACTION_REMOVE,
+	FW_CTXT_ACTION_NUM
+}; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */
+
+/* Time Events */
+
+/* Time Event types, according to MAC type */
+enum iwl_time_event_type {
+	/* BSS Station Events */
+	TE_BSS_STA_AGGRESSIVE_ASSOC,
+	TE_BSS_STA_ASSOC,
+	TE_BSS_EAP_DHCP_PROT,
+	TE_BSS_QUIET_PERIOD,
+
+	/* P2P Device Events */
+	TE_P2P_DEVICE_DISCOVERABLE,
+	TE_P2P_DEVICE_LISTEN,
+	TE_P2P_DEVICE_ACTION_SCAN,
+	TE_P2P_DEVICE_FULL_SCAN,
+
+	/* P2P Client Events */
+	TE_P2P_CLIENT_AGGRESSIVE_ASSOC,
+	TE_P2P_CLIENT_ASSOC,
+	TE_P2P_CLIENT_QUIET_PERIOD,
+
+	/* P2P GO Events */
+	TE_P2P_GO_ASSOC_PROT,
+	TE_P2P_GO_REPETITIVE_NOA,
+	TE_P2P_GO_CT_WINDOW,
+
+	/* WiDi Sync Events */
+	TE_WIDI_TX_SYNC,
+
+	TE_MAX
+}; /* MAC_EVENT_TYPE_API_E_VER_1 */
+
+/* Time Event dependencies: none, on another TE, or in a specific time */
+enum {
+	TE_INDEPENDENT		= 0,
+	TE_DEP_OTHER		= 1,
+	TE_DEP_TSF		= 2,
+	TE_EVENT_SOCIOPATHIC	= 4,
+}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */
+
+/* When to send Time Event notifications and to whom (internal = FW) */
+enum {
+	TE_NOTIF_NONE = 0,
+	TE_NOTIF_HOST_START = 0x1,
+	TE_NOTIF_HOST_END = 0x2,
+	TE_NOTIF_INTERNAL_START = 0x4,
+	TE_NOTIF_INTERNAL_END = 0x8
+}; /* MAC_EVENT_ACTION_API_E_VER_1 */
+
+/*
+ * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed.
+ * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only
+ *  the first fragment is scheduled.
+ * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only
+ *  the first 2 fragments are scheduled.
+ * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number
+ *  of fragments are valid.
+ *
+ * Other than the constant defined above, specifying a fragmentation value 'x'
+ * means that the event can be fragmented but only the first 'x' will be
+ * scheduled.
+ */
+enum {
+	TE_FRAG_NONE = 0,
+	TE_FRAG_SINGLE = 1,
+	TE_FRAG_DUAL = 2,
+	TE_FRAG_ENDLESS = 0xffffffff
+};
+
+/* Repeat the time event endlessly (until removed) */
+#define TE_REPEAT_ENDLESS	(0xffffffff)
+/* If a Time Event has bounded repetitions, this is the maximal value */
+#define TE_REPEAT_MAX_MSK	(0x0fffffff)
+/* If a Time Event can be fragmented, this is the max number of fragments */
+#define TE_FRAG_MAX_MSK		(0x0fffffff)
+
+/**
+ * struct iwl_time_event_cmd - configuring Time Events
+ * ( TIME_EVENT_CMD = 0x29 )
+ * @id_and_color: ID and color of the relevant MAC
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @id: this field has two meanings, depending on the action:
+ *	If the action is ADD, then it means the type of event to add.
+ *	For all other actions it is the unique event ID assigned when the
+ *	event was added by the FW.
+ * @apply_time: When to start the Time Event (in GP2)
+ * @max_delay: maximum delay to event's start (apply time), in TU
+ * @depends_on: the unique ID of the event we depend on (if any)
+ * @interval: interval between repetitions, in TU
+ * @interval_reciprocal: 2^32 / interval
+ * @duration: duration of event in TU
+ * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS
+ * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF
+ * @is_present: 0 or 1, are we present or absent during the Time Event
+ * @max_frags: maximal number of fragments the Time Event can be divided to
+ * @notify: notifications using TE_NOTIF_* (whom to notify when)
+ */
+struct iwl_time_event_cmd {
+	/* COMMON_INDEX_HDR_API_S_VER_1 */
+	__le32 id_and_color;
+	__le32 action;
+	__le32 id;
+	/* MAC_TIME_EVENT_DATA_API_S_VER_1 */
+	__le32 apply_time;
+	__le32 max_delay;
+	__le32 dep_policy;
+	__le32 depends_on;
+	__le32 is_present;
+	__le32 max_frags;
+	__le32 interval;
+	__le32 interval_reciprocal;
+	__le32 duration;
+	__le32 repeat;
+	__le32 notify;
+} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_time_event_resp - response structure to iwl_time_event_cmd
+ * @status: bit 0 indicates success, all others specify errors
+ * @id: the Time Event type
+ * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE
+ * @id_and_color: ID and color of the relevant MAC
+ */
+struct iwl_time_event_resp {
+	__le32 status;
+	__le32 id;
+	__le32 unique_id;
+	__le32 id_and_color;
+} __packed; /* MAC_TIME_EVENT_RSP_API_S_VER_1 */
+
+/**
+ * struct iwl_time_event_notif - notifications of time event start/stop
+ * ( TIME_EVENT_NOTIFICATION = 0x2a )
+ * @timestamp: action timestamp in GP2
+ * @session_id: session's unique id
+ * @unique_id: unique id of the Time Event itself
+ * @id_and_color: ID and color of the relevant MAC
+ * @action: one of TE_NOTIF_START or TE_NOTIF_END
+ * @status: true if scheduled, false otherwise (not executed)
+ */
+struct iwl_time_event_notif {
+	__le32 timestamp;
+	__le32 session_id;
+	__le32 unique_id;
+	__le32 id_and_color;
+	__le32 action;
+	__le32 status;
+} __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */
+
+
+/* Bindings and Time Quota */
+
+/**
+ * struct iwl_binding_cmd - configuring bindings
+ * ( BINDING_CONTEXT_CMD = 0x2b )
+ * @id_and_color: ID and color of the relevant Binding
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @macs: array of MAC id and colors which belong to the binding
+ * @phy: PHY id and color which belongs to the binding
+ */
+struct iwl_binding_cmd {
+	/* COMMON_INDEX_HDR_API_S_VER_1 */
+	__le32 id_and_color;
+	__le32 action;
+	/* BINDING_DATA_API_S_VER_1 */
+	__le32 macs[MAX_MACS_IN_BINDING];
+	__le32 phy;
+} __packed; /* BINDING_CMD_API_S_VER_1 */
+
+/* The maximal number of fragments in the FW's schedule session */
+#define IWL_MVM_MAX_QUOTA 128
+
+/**
+ * struct iwl_time_quota_data - configuration of time quota per binding
+ * @id_and_color: ID and color of the relevant Binding
+ * @quota: absolute time quota in TU. The scheduler will try to divide the
+ *	remainig quota (after Time Events) according to this quota.
+ * @max_duration: max uninterrupted context duration in TU
+ */
+struct iwl_time_quota_data {
+	__le32 id_and_color;
+	__le32 quota;
+	__le32 max_duration;
+} __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_time_quota_cmd - configuration of time quota between bindings
+ * ( TIME_QUOTA_CMD = 0x2c )
+ * @quotas: allocations per binding
+ */
+struct iwl_time_quota_cmd {
+	struct iwl_time_quota_data quotas[MAX_BINDINGS];
+} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */
+
+
+/* PHY context */
+
+/* Supported bands */
+#define PHY_BAND_5  (0)
+#define PHY_BAND_24 (1)
+
+/* Supported channel width, vary if there is VHT support */
+#define PHY_VHT_CHANNEL_MODE20	(0x0)
+#define PHY_VHT_CHANNEL_MODE40	(0x1)
+#define PHY_VHT_CHANNEL_MODE80	(0x2)
+#define PHY_VHT_CHANNEL_MODE160	(0x3)
+
+/*
+ * Control channel position:
+ * For legacy set bit means upper channel, otherwise lower.
+ * For VHT - bit-2 marks if the control is lower/upper relative to center-freq
+ *   bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0.
+ *                                   center_freq
+ *                                        |
+ * 40Mhz                          |_______|_______|
+ * 80Mhz                  |_______|_______|_______|_______|
+ * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______|
+ * code      011     010     001     000  |  100     101     110    111
+ */
+#define PHY_VHT_CTRL_POS_1_BELOW  (0x0)
+#define PHY_VHT_CTRL_POS_2_BELOW  (0x1)
+#define PHY_VHT_CTRL_POS_3_BELOW  (0x2)
+#define PHY_VHT_CTRL_POS_4_BELOW  (0x3)
+#define PHY_VHT_CTRL_POS_1_ABOVE  (0x4)
+#define PHY_VHT_CTRL_POS_2_ABOVE  (0x5)
+#define PHY_VHT_CTRL_POS_3_ABOVE  (0x6)
+#define PHY_VHT_CTRL_POS_4_ABOVE  (0x7)
+
+/*
+ * @band: PHY_BAND_*
+ * @channel: channel number
+ * @width: PHY_[VHT|LEGACY]_CHANNEL_*
+ * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_*
+ */
+struct iwl_fw_channel_info {
+	u8 band;
+	u8 channel;
+	u8 width;
+	u8 ctrl_pos;
+} __packed;
+
+#define PHY_RX_CHAIN_DRIVER_FORCE_POS	(0)
+#define PHY_RX_CHAIN_DRIVER_FORCE_MSK \
+	(0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS)
+#define PHY_RX_CHAIN_VALID_POS		(1)
+#define PHY_RX_CHAIN_VALID_MSK \
+	(0x7 << PHY_RX_CHAIN_VALID_POS)
+#define PHY_RX_CHAIN_FORCE_SEL_POS	(4)
+#define PHY_RX_CHAIN_FORCE_SEL_MSK \
+	(0x7 << PHY_RX_CHAIN_FORCE_SEL_POS)
+#define PHY_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
+#define PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \
+	(0x7 << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS)
+#define PHY_RX_CHAIN_CNT_POS		(10)
+#define PHY_RX_CHAIN_CNT_MSK \
+	(0x3 << PHY_RX_CHAIN_CNT_POS)
+#define PHY_RX_CHAIN_MIMO_CNT_POS	(12)
+#define PHY_RX_CHAIN_MIMO_CNT_MSK \
+	(0x3 << PHY_RX_CHAIN_MIMO_CNT_POS)
+#define PHY_RX_CHAIN_MIMO_FORCE_POS	(14)
+#define PHY_RX_CHAIN_MIMO_FORCE_MSK \
+	(0x1 << PHY_RX_CHAIN_MIMO_FORCE_POS)
+
+/* TODO: fix the value, make it depend on firmware at runtime? */
+#define NUM_PHY_CTX	3
+
+/* TODO: complete missing documentation */
+/**
+ * struct iwl_phy_context_cmd - config of the PHY context
+ * ( PHY_CONTEXT_CMD = 0x8 )
+ * @id_and_color: ID and color of the relevant Binding
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @apply_time: 0 means immediate apply and context switch.
+ *	other value means apply new params after X usecs
+ * @tx_param_color: ???
+ * @channel_info:
+ * @txchain_info: ???
+ * @rxchain_info: ???
+ * @acquisition_data: ???
+ * @dsp_cfg_flags: set to 0
+ */
+struct iwl_phy_context_cmd {
+	/* COMMON_INDEX_HDR_API_S_VER_1 */
+	__le32 id_and_color;
+	__le32 action;
+	/* PHY_CONTEXT_DATA_API_S_VER_1 */
+	__le32 apply_time;
+	__le32 tx_param_color;
+	struct iwl_fw_channel_info ci;
+	__le32 txchain_info;
+	__le32 rxchain_info;
+	__le32 acquisition_data;
+	__le32 dsp_cfg_flags;
+} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */
+
+#define IWL_RX_INFO_PHY_CNT 8
+#define IWL_RX_INFO_AGC_IDX 1
+#define IWL_RX_INFO_RSSI_AB_IDX 2
+#define IWL_RX_INFO_RSSI_C_IDX 3
+#define IWL_OFDM_AGC_DB_MSK 0xfe00
+#define IWL_OFDM_AGC_DB_POS 9
+#define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff
+#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00
+#define IWL_OFDM_RSSI_A_POS 0
+#define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000
+#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000
+#define IWL_OFDM_RSSI_B_POS 16
+#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff
+#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00
+#define IWL_OFDM_RSSI_C_POS 0
+
+/**
+ * struct iwl_rx_phy_info - phy info
+ * (REPLY_RX_PHY_CMD = 0xc0)
+ * @non_cfg_phy_cnt: non configurable DSP phy data byte count
+ * @cfg_phy_cnt: configurable DSP phy data byte count
+ * @stat_id: configurable DSP phy data set ID
+ * @reserved1:
+ * @system_timestamp: GP2  at on air rise
+ * @timestamp: TSF at on air rise
+ * @beacon_time_stamp: beacon at on-air rise
+ * @phy_flags: general phy flags: band, modulation, ...
+ * @channel: channel number
+ * @non_cfg_phy_buf: for various implementations of non_cfg_phy
+ * @rate_n_flags: RATE_MCS_*
+ * @byte_count: frame's byte-count
+ * @frame_time: frame's time on the air, based on byte count and frame rate
+ *	calculation
+ *
+ * Before each Rx, the device sends this data. It contains PHY information
+ * about the reception of the packet.
+ */
+struct iwl_rx_phy_info {
+	u8 non_cfg_phy_cnt;
+	u8 cfg_phy_cnt;
+	u8 stat_id;
+	u8 reserved1;
+	__le32 system_timestamp;
+	__le64 timestamp;
+	__le32 beacon_time_stamp;
+	__le16 phy_flags;
+	__le16 channel;
+	__le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT];
+	__le32 rate_n_flags;
+	__le32 byte_count;
+	__le16 reserved2;
+	__le16 frame_time;
+} __packed;
+
+struct iwl_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __packed;
+
+/**
+ * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags
+ * @RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band
+ * @RX_RES_PHY_FLAGS_MOD_CCK:
+ * @RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short
+ * @RX_RES_PHY_FLAGS_NARROW_BAND:
+ * @RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received
+ * @RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU
+ * @RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame
+ * @RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble
+ * @RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame
+ */
+enum iwl_rx_phy_flags {
+	RX_RES_PHY_FLAGS_BAND_24	= BIT(0),
+	RX_RES_PHY_FLAGS_MOD_CCK	= BIT(1),
+	RX_RES_PHY_FLAGS_SHORT_PREAMBLE	= BIT(2),
+	RX_RES_PHY_FLAGS_NARROW_BAND	= BIT(3),
+	RX_RES_PHY_FLAGS_ANTENNA	= (0x7 << 4),
+	RX_RES_PHY_FLAGS_ANTENNA_POS	= 4,
+	RX_RES_PHY_FLAGS_AGG		= BIT(7),
+	RX_RES_PHY_FLAGS_OFDM_HT	= BIT(8),
+	RX_RES_PHY_FLAGS_OFDM_GF	= BIT(9),
+	RX_RES_PHY_FLAGS_OFDM_VHT	= BIT(10),
+};
+
+/**
+ * enum iwl_mvm_rx_status - written by fw for each Rx packet
+ * @RX_MPDU_RES_STATUS_CRC_OK: CRC is fine
+ * @RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow
+ * @RX_MPDU_RES_STATUS_SRC_STA_FOUND:
+ * @RX_MPDU_RES_STATUS_KEY_VALID:
+ * @RX_MPDU_RES_STATUS_KEY_PARAM_OK:
+ * @RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed
+ * @RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked
+ *	in the driver.
+ * @RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine
+ * @RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR:  valid for alg = CCM_CMAC or
+ *	alg = CCM only. Checks replay attack for 11w frames. Relevant only if
+ *	%RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set.
+ * @RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted
+ * @RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP
+ * @RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM
+ * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP
+ * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC
+ * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted
+ * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm
+ * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted
+ * @RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP:
+ * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP:
+ * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT:
+ * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame
+ * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK:
+ * @RX_MPDU_RES_STATUS_STA_ID_MSK:
+ * @RX_MPDU_RES_STATUS_RRF_KILL:
+ * @RX_MPDU_RES_STATUS_FILTERING_MSK:
+ * @RX_MPDU_RES_STATUS2_FILTERING_MSK:
+ */
+enum iwl_mvm_rx_status {
+	RX_MPDU_RES_STATUS_CRC_OK			= BIT(0),
+	RX_MPDU_RES_STATUS_OVERRUN_OK			= BIT(1),
+	RX_MPDU_RES_STATUS_SRC_STA_FOUND		= BIT(2),
+	RX_MPDU_RES_STATUS_KEY_VALID			= BIT(3),
+	RX_MPDU_RES_STATUS_KEY_PARAM_OK			= BIT(4),
+	RX_MPDU_RES_STATUS_ICV_OK			= BIT(5),
+	RX_MPDU_RES_STATUS_MIC_OK			= BIT(6),
+	RX_MPDU_RES_STATUS_TTAK_OK			= BIT(7),
+	RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR		= BIT(7),
+	RX_MPDU_RES_STATUS_SEC_NO_ENC			= (0 << 8),
+	RX_MPDU_RES_STATUS_SEC_WEP_ENC			= (1 << 8),
+	RX_MPDU_RES_STATUS_SEC_CCM_ENC			= (2 << 8),
+	RX_MPDU_RES_STATUS_SEC_TKIP_ENC			= (3 << 8),
+	RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC		= (6 << 8),
+	RX_MPDU_RES_STATUS_SEC_ENC_ERR			= (7 << 8),
+	RX_MPDU_RES_STATUS_SEC_ENC_MSK			= (7 << 8),
+	RX_MPDU_RES_STATUS_DEC_DONE			= BIT(11),
+	RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP	= BIT(12),
+	RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP		= BIT(13),
+	RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT		= BIT(14),
+	RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME		= BIT(15),
+	RX_MPDU_RES_STATUS_HASH_INDEX_MSK		= (0x3F0000),
+	RX_MPDU_RES_STATUS_STA_ID_MSK			= (0x1f000000),
+	RX_MPDU_RES_STATUS_RRF_KILL			= BIT(29),
+	RX_MPDU_RES_STATUS_FILTERING_MSK		= (0xc00000),
+	RX_MPDU_RES_STATUS2_FILTERING_MSK		= (0xc0000000),
+};
+
+/**
+ * struct iwl_radio_version_notif - information on the radio version
+ * ( RADIO_VERSION_NOTIFICATION = 0x68 )
+ * @radio_flavor:
+ * @radio_step:
+ * @radio_dash:
+ */
+struct iwl_radio_version_notif {
+	__le32 radio_flavor;
+	__le32 radio_step;
+	__le32 radio_dash;
+} __packed; /* RADIO_VERSION_NOTOFICATION_S_VER_1 */
+
+enum iwl_card_state_flags {
+	CARD_ENABLED		= 0x00,
+	HW_CARD_DISABLED	= 0x01,
+	SW_CARD_DISABLED	= 0x02,
+	CT_KILL_CARD_DISABLED	= 0x04,
+	HALT_CARD_DISABLED	= 0x08,
+	CARD_DISABLED_MSK	= 0x0f,
+	CARD_IS_RX_ON		= 0x10,
+};
+
+/**
+ * struct iwl_radio_version_notif - information on the radio version
+ * ( CARD_STATE_NOTIFICATION = 0xa1 )
+ * @flags: %iwl_card_state_flags
+ */
+struct iwl_card_state_notif {
+	__le32 flags;
+} __packed; /* CARD_STATE_NTFY_API_S_VER_1 */
+
+/**
+ * struct iwl_set_calib_default_cmd - set default value for calibration.
+ * ( SET_CALIB_DEFAULT_CMD = 0x8e )
+ * @calib_index: the calibration to set value for
+ * @length: of data
+ * @data: the value to set for the calibration result
+ */
+struct iwl_set_calib_default_cmd {
+	__le16 calib_index;
+	__le16 length;
+	u8 data[0];
+} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
+
+#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
new file mode 100644
index 0000000..d3d959d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -0,0 +1,640 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include <net/mac80211.h>
+
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-fw.h"
+#include "iwl-debug.h"
+#include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-eeprom-parse.h"
+
+#include "mvm.h"
+#include "iwl-phy-db.h"
+
+#define MVM_UCODE_ALIVE_TIMEOUT	HZ
+#define MVM_UCODE_CALIB_TIMEOUT	(2*HZ)
+
+#define UCODE_VALID_OK	cpu_to_le32(0x1)
+
+/* Default calibration values for WkP - set to INIT image w/o running */
+static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f,
+						 0x00, 0x18, 0x00 };
+static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+					     0x7f, 0x7f, 0x7f };
+static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 };
+static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00,
+					     0x00 };
+static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 };
+static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 };
+static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 };
+static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 };
+
+struct iwl_calib_default_data {
+	u16 size;
+	void *data;
+};
+
+#define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}
+
+static const struct iwl_calib_default_data wkp_calib_default_data[12] = {
+	[5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc),
+	[6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter),
+	[7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo),
+	[8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq),
+	[9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew),
+	[10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq),
+	[11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew),
+};
+
+struct iwl_mvm_alive_data {
+	bool valid;
+	u32 scd_base_addr;
+};
+
+static inline const struct fw_img *
+iwl_get_ucode_image(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type)
+{
+	if (ucode_type >= IWL_UCODE_TYPE_MAX)
+		return NULL;
+
+	return &mvm->fw->img[ucode_type];
+}
+
+static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
+{
+	struct iwl_tx_ant_cfg_cmd tx_ant_cmd = {
+		.valid = cpu_to_le32(valid_tx_ant),
+	};
+
+	IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant);
+	return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC,
+				    sizeof(tx_ant_cmd), &tx_ant_cmd);
+}
+
+static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
+			 struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_mvm *mvm =
+		container_of(notif_wait, struct iwl_mvm, notif_wait);
+	struct iwl_mvm_alive_data *alive_data = data;
+	struct mvm_alive_resp *palive;
+
+	palive = (void *)pkt->data;
+
+	mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr);
+	mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
+	alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+
+	alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK;
+	IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n",
+		     le16_to_cpu(palive->status), palive->ver_type,
+		     palive->ver_subtype);
+
+	return true;
+}
+
+static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait,
+				  struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_phy_db *phy_db = data;
+
+	if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) {
+		WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF);
+		return true;
+	}
+
+	WARN_ON(iwl_phy_db_set_section(phy_db, pkt, GFP_ATOMIC));
+
+	return false;
+}
+
+static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
+					 enum iwl_ucode_type ucode_type)
+{
+	struct iwl_notification_wait alive_wait;
+	struct iwl_mvm_alive_data alive_data;
+	const struct fw_img *fw;
+	int ret, i;
+	enum iwl_ucode_type old_type = mvm->cur_ucode;
+	static const u8 alive_cmd[] = { MVM_ALIVE };
+
+	mvm->cur_ucode = ucode_type;
+	fw = iwl_get_ucode_image(mvm, ucode_type);
+
+	mvm->ucode_loaded = false;
+
+	if (!fw)
+		return -EINVAL;
+
+	iwl_init_notification_wait(&mvm->notif_wait, &alive_wait,
+				   alive_cmd, ARRAY_SIZE(alive_cmd),
+				   iwl_alive_fn, &alive_data);
+
+	ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT);
+	if (ret) {
+		mvm->cur_ucode = old_type;
+		iwl_remove_notification(&mvm->notif_wait, &alive_wait);
+		return ret;
+	}
+
+	/*
+	 * Some things may run in the background now, but we
+	 * just wait for the ALIVE notification here.
+	 */
+	ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait,
+				    MVM_UCODE_ALIVE_TIMEOUT);
+	if (ret) {
+		mvm->cur_ucode = old_type;
+		return ret;
+	}
+
+	if (!alive_data.valid) {
+		IWL_ERR(mvm, "Loaded ucode is not valid!\n");
+		mvm->cur_ucode = old_type;
+		return -EIO;
+	}
+
+	iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr);
+
+	/*
+	 * Note: all the queues are enabled as part of the interface
+	 * initialization, but in firmware restart scenarios they
+	 * could be stopped, so wake them up. In firmware restart,
+	 * mac80211 will have the queues stopped as well until the
+	 * reconfiguration completes. During normal startup, they
+	 * will be empty.
+	 */
+
+	for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
+		if (i < IWL_MVM_FIRST_AGG_QUEUE && i != IWL_MVM_CMD_QUEUE)
+			mvm->queue_to_mac80211[i] = i;
+		else
+			mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+		atomic_set(&mvm->queue_stop_count[i], 0);
+	}
+
+	mvm->transport_queue_stop = 0;
+
+	mvm->ucode_loaded = true;
+
+	return 0;
+}
+#define IWL_HW_REV_ID_RAINBOW	0x2
+#define IWL_PROJ_TYPE_LHP	0x5
+
+static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm)
+{
+	struct iwl_nvm_data *data = mvm->nvm_data;
+	/* Temp calls to static definitions, will be changed to CSR calls */
+	u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW;
+	u8 project_type = IWL_PROJ_TYPE_LHP;
+
+	return data->radio_cfg_dash | (data->radio_cfg_step << 2) |
+		(hw_rev_id << 4) | ((project_type & 0x7f) << 6) |
+		(data->valid_tx_ant << 16) | (data->valid_rx_ant << 20);
+}
+
+static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
+{
+	struct iwl_phy_cfg_cmd phy_cfg_cmd;
+	enum iwl_ucode_type ucode_type = mvm->cur_ucode;
+
+	/* Set parameters */
+	phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm));
+	phy_cfg_cmd.calib_control.event_trigger =
+		mvm->fw->default_calib[ucode_type].event_trigger;
+	phy_cfg_cmd.calib_control.flow_trigger =
+		mvm->fw->default_calib[ucode_type].flow_trigger;
+
+	IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n",
+		       phy_cfg_cmd.phy_cfg);
+
+	return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, CMD_SYNC,
+				    sizeof(phy_cfg_cmd), &phy_cfg_cmd);
+}
+
+/* Starting with the new PHY DB implementation - New calibs are enabled */
+/* Value - 0x405e7 */
+#define IWL_CALIB_DEFAULT_FLOW_INIT	(IWL_CALIB_CFG_XTAL_IDX		|\
+					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\
+					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\
+					 IWL_CALIB_CFG_DC_IDX		|\
+					 IWL_CALIB_CFG_BB_FILTER_IDX	|\
+					 IWL_CALIB_CFG_LO_LEAKAGE_IDX	|\
+					 IWL_CALIB_CFG_TX_IQ_IDX	|\
+					 IWL_CALIB_CFG_RX_IQ_IDX	|\
+					 IWL_CALIB_CFG_AGC_IDX)
+
+#define IWL_CALIB_DEFAULT_EVENT_INIT	0x0
+
+/* Value 0x41567 */
+#define IWL_CALIB_DEFAULT_FLOW_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\
+					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\
+					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\
+					 IWL_CALIB_CFG_BB_FILTER_IDX	|\
+					 IWL_CALIB_CFG_DC_IDX		|\
+					 IWL_CALIB_CFG_TX_IQ_IDX	|\
+					 IWL_CALIB_CFG_RX_IQ_IDX	|\
+					 IWL_CALIB_CFG_SENSITIVITY_IDX	|\
+					 IWL_CALIB_CFG_AGC_IDX)
+
+#define IWL_CALIB_DEFAULT_EVENT_RUN	(IWL_CALIB_CFG_XTAL_IDX		|\
+					 IWL_CALIB_CFG_TEMPERATURE_IDX	|\
+					 IWL_CALIB_CFG_VOLTAGE_READ_IDX	|\
+					 IWL_CALIB_CFG_TX_PWR_IDX	|\
+					 IWL_CALIB_CFG_DC_IDX		|\
+					 IWL_CALIB_CFG_TX_IQ_IDX	|\
+					 IWL_CALIB_CFG_SENSITIVITY_IDX)
+
+/*
+ * Sets the calibrations trigger values that will be sent to the FW for runtime
+ * and init calibrations.
+ * The ones given in the FW TLV are not correct.
+ */
+static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm)
+{
+	struct iwl_tlv_calib_ctrl default_calib;
+
+	/*
+	 * WkP FW TLV calib bits are wrong, overwrite them.
+	 * This defines the dynamic calibrations which are implemented in the
+	 * uCode both for init(flow) calculation and event driven calibs.
+	 */
+
+	/* Init Image */
+	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT);
+	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT);
+
+	if (default_calib.event_trigger !=
+	    mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger)
+		IWL_ERR(mvm,
+			"Updating the event calib for INIT image: 0x%x -> 0x%x\n",
+			mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger,
+			default_calib.event_trigger);
+	if (default_calib.flow_trigger !=
+	    mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger)
+		IWL_ERR(mvm,
+			"Updating the flow calib for INIT image: 0x%x -> 0x%x\n",
+			mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger,
+			default_calib.flow_trigger);
+
+	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT],
+	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl));
+	IWL_ERR(mvm,
+		"Setting uCode init calibrations event 0x%x, trigger 0x%x\n",
+		default_calib.event_trigger,
+		default_calib.flow_trigger);
+
+	/* Run time image */
+	default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN);
+	default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN);
+
+	if (default_calib.event_trigger !=
+	    mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger)
+		IWL_ERR(mvm,
+			"Updating the event calib for RT image: 0x%x -> 0x%x\n",
+			mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger,
+			default_calib.event_trigger);
+	if (default_calib.flow_trigger !=
+	    mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger)
+		IWL_ERR(mvm,
+			"Updating the flow calib for RT image: 0x%x -> 0x%x\n",
+			mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger,
+			default_calib.flow_trigger);
+
+	memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR],
+	       &default_calib, sizeof(struct iwl_tlv_calib_ctrl));
+	IWL_ERR(mvm,
+		"Setting uCode runtime calibs event 0x%x, trigger 0x%x\n",
+		default_calib.event_trigger,
+		default_calib.flow_trigger);
+}
+
+static int iwl_set_default_calibrations(struct iwl_mvm *mvm)
+{
+	u8 cmd_raw[16]; /* holds the variable size commands */
+	struct iwl_set_calib_default_cmd *cmd =
+		(struct iwl_set_calib_default_cmd *)cmd_raw;
+	int ret, i;
+
+	/* Setting default values for calibrations we don't run */
+	for (i = 0; i < ARRAY_SIZE(wkp_calib_default_data); i++) {
+		u16 cmd_len;
+
+		if (wkp_calib_default_data[i].size == 0)
+			continue;
+
+		memset(cmd_raw, 0, sizeof(cmd_raw));
+		cmd_len = wkp_calib_default_data[i].size + sizeof(cmd);
+		cmd->calib_index = cpu_to_le16(i);
+		cmd->length = cpu_to_le16(wkp_calib_default_data[i].size);
+		if (WARN_ONCE(cmd_len > sizeof(cmd_raw),
+			      "Need to enlarge cmd_raw to %d\n", cmd_len))
+			break;
+		memcpy(cmd->data, wkp_calib_default_data[i].data,
+		       wkp_calib_default_data[i].size);
+		ret = iwl_mvm_send_cmd_pdu(mvm, SET_CALIB_DEFAULT_CMD, 0,
+					   sizeof(*cmd) +
+					   wkp_calib_default_data[i].size,
+					   cmd);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
+{
+	struct iwl_notification_wait calib_wait;
+	static const u8 init_complete[] = {
+		INIT_COMPLETE_NOTIF,
+		CALIB_RES_NOTIF_PHY_DB
+	};
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	if (mvm->init_ucode_run)
+		return 0;
+
+	iwl_init_notification_wait(&mvm->notif_wait,
+				   &calib_wait,
+				   init_complete,
+				   ARRAY_SIZE(init_complete),
+				   iwl_wait_phy_db_entry,
+				   mvm->phy_db);
+
+	/* Will also start the device */
+	ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret);
+		goto error;
+	}
+
+	if (read_nvm) {
+		/* Read nvm */
+		ret = iwl_nvm_init(mvm);
+		if (ret) {
+			IWL_ERR(mvm, "Failed to read NVM: %d\n", ret);
+			goto error;
+		}
+	}
+
+	ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
+	WARN_ON(ret);
+
+	/* Override the calibrations from TLV and the const of fw */
+	iwl_set_default_calib_trigger(mvm);
+
+	/* WkP doesn't have all calibrations, need to set default values */
+	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		ret = iwl_set_default_calibrations(mvm);
+		if (ret)
+			goto error;
+	}
+
+	/*
+	 * Send phy configurations command to init uCode
+	 * to start the 16.0 uCode init image internal calibrations.
+	 */
+	ret = iwl_send_phy_cfg_cmd(mvm);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n",
+			ret);
+		goto error;
+	}
+
+	/*
+	 * Some things may run in the background now, but we
+	 * just wait for the calibration complete notification.
+	 */
+	ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
+			MVM_UCODE_CALIB_TIMEOUT);
+	if (!ret)
+		mvm->init_ucode_run = true;
+	goto out;
+
+error:
+	iwl_remove_notification(&mvm->notif_wait, &calib_wait);
+out:
+	if (!iwlmvm_mod_params.init_dbg) {
+		iwl_trans_stop_device(mvm->trans);
+	} else if (!mvm->nvm_data) {
+		/* we want to debug INIT and we have no NVM - fake */
+		mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
+					sizeof(struct ieee80211_channel) +
+					sizeof(struct ieee80211_rate),
+					GFP_KERNEL);
+		if (!mvm->nvm_data)
+			return -ENOMEM;
+		mvm->nvm_data->valid_rx_ant = 1;
+		mvm->nvm_data->valid_tx_ant = 1;
+		mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
+		mvm->nvm_data->bands[0].n_channels = 1;
+		mvm->nvm_data->bands[0].n_bitrates = 1;
+		mvm->nvm_data->bands[0].bitrates =
+			(void *)mvm->nvm_data->channels + 1;
+		mvm->nvm_data->bands[0].bitrates->hw_value = 10;
+	}
+
+	return ret;
+}
+
+#define UCODE_CALIB_TIMEOUT	(2*HZ)
+
+int iwl_mvm_up(struct iwl_mvm *mvm)
+{
+	int ret, i;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	ret = iwl_trans_start_hw(mvm->trans);
+	if (ret)
+		return ret;
+
+	/* If we were in RFKILL during module loading, load init ucode now */
+	if (!mvm->init_ucode_run) {
+		ret = iwl_run_init_mvm_ucode(mvm, false);
+		if (ret && !iwlmvm_mod_params.init_dbg) {
+			IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
+			goto error;
+		}
+	}
+
+	if (iwlmvm_mod_params.init_dbg)
+		return 0;
+
+	ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
+		goto error;
+	}
+
+	ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+	if (ret)
+		goto error;
+
+	/* Send phy db control command and then phy db calibration*/
+	ret = iwl_send_phy_db_data(mvm->phy_db);
+	if (ret)
+		goto error;
+
+	ret = iwl_send_phy_cfg_cmd(mvm);
+	if (ret)
+		goto error;
+
+	/* init the fw <-> mac80211 STA mapping */
+	for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
+		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+
+	/* Add auxiliary station for scanning */
+	ret = iwl_mvm_add_aux_sta(mvm);
+	if (ret)
+		goto error;
+
+	IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
+
+	return 0;
+ error:
+	iwl_trans_stop_device(mvm->trans);
+	return ret;
+}
+
+int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
+{
+	int ret, i;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	ret = iwl_trans_start_hw(mvm->trans);
+	if (ret)
+		return ret;
+
+	ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret);
+		goto error;
+	}
+
+	ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+	if (ret)
+		goto error;
+
+	/* Send phy db control command and then phy db calibration*/
+	ret = iwl_send_phy_db_data(mvm->phy_db);
+	if (ret)
+		goto error;
+
+	ret = iwl_send_phy_cfg_cmd(mvm);
+	if (ret)
+		goto error;
+
+	/* init the fw <-> mac80211 STA mapping */
+	for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
+		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+
+	/* Add auxiliary station for scanning */
+	ret = iwl_mvm_add_aux_sta(mvm);
+	if (ret)
+		goto error;
+
+	return 0;
+ error:
+	iwl_trans_stop_device(mvm->trans);
+	return ret;
+}
+
+int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
+				    struct iwl_rx_cmd_buffer *rxb,
+				    struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
+	u32 flags = le32_to_cpu(card_state_notif->flags);
+
+	IWL_DEBUG_RF_KILL(mvm, "Card state received: HW:%s SW:%s CT:%s\n",
+			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & CT_KILL_CARD_DISABLED) ?
+			  "Reached" : "Not reached");
+
+	return 0;
+}
+
+int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			 struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_radio_version_notif *radio_version = (void *)pkt->data;
+
+	/* TODO: what to do with that? */
+	IWL_DEBUG_INFO(mvm,
+		       "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n",
+		       le32_to_cpu(radio_version->radio_flavor),
+		       le32_to_cpu(radio_version->radio_step),
+		       le32_to_cpu(radio_version->radio_dash));
+	return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c
new file mode 100644
index 0000000..011906e
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/led.c
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <linux/leds.h>
+#include "iwl-io.h"
+#include "iwl-csr.h"
+#include "mvm.h"
+
+/* Set led register on */
+static void iwl_mvm_led_enable(struct iwl_mvm *mvm)
+{
+	iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
+}
+
+/* Set led register off */
+static void iwl_mvm_led_disable(struct iwl_mvm *mvm)
+{
+	iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_OFF);
+}
+
+static void iwl_led_brightness_set(struct led_classdev *led_cdev,
+				   enum led_brightness brightness)
+{
+	struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led);
+	if (brightness > 0)
+		iwl_mvm_led_enable(mvm);
+	else
+		iwl_mvm_led_disable(mvm);
+}
+
+int iwl_mvm_leds_init(struct iwl_mvm *mvm)
+{
+	int mode = iwlwifi_mod_params.led_mode;
+	int ret;
+
+	switch (mode) {
+	case IWL_LED_DEFAULT:
+	case IWL_LED_RF_STATE:
+		mode = IWL_LED_RF_STATE;
+		break;
+	case IWL_LED_DISABLE:
+		IWL_INFO(mvm, "Led disabled\n");
+		return 0;
+	default:
+		return -EINVAL;
+	};
+
+	mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
+				   wiphy_name(mvm->hw->wiphy));
+	mvm->led.brightness_set = iwl_led_brightness_set;
+	mvm->led.max_brightness = 1;
+
+	if (mode == IWL_LED_RF_STATE)
+		mvm->led.default_trigger =
+			ieee80211_get_radio_led_name(mvm->hw);
+
+	ret = led_classdev_register(mvm->trans->dev, &mvm->led);
+	if (ret) {
+		kfree(mvm->led.name);
+		IWL_INFO(mvm, "Failed to enable led\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
+{
+	if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE)
+		return;
+
+	led_classdev_unregister(&mvm->led);
+	kfree(mvm->led.name);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
new file mode 100644
index 0000000..341dbc0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -0,0 +1,992 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "fw-api.h"
+#include "mvm.h"
+
+const u8 iwl_mvm_ac_to_tx_fifo[] = {
+	IWL_MVM_TX_FIFO_BK,
+	IWL_MVM_TX_FIFO_BE,
+	IWL_MVM_TX_FIFO_VI,
+	IWL_MVM_TX_FIFO_VO,
+};
+
+struct iwl_mvm_mac_iface_iterator_data {
+	struct iwl_mvm *mvm;
+	struct ieee80211_vif *vif;
+	unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
+	unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
+	unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_FIRST_AGG_QUEUE)];
+	enum iwl_tsf_id preferred_tsf;
+	bool found_vif;
+};
+
+static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
+				       struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_mac_iface_iterator_data *data = _data;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	u32 ac;
+
+	/* Iterator may already find the interface being added -- skip it */
+	if (vif == data->vif) {
+		data->found_vif = true;
+		return;
+	}
+
+	/* Mark the queues used by the vif */
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+			__set_bit(vif->hw_queue[ac], data->used_hw_queues);
+
+	if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+		__set_bit(vif->cab_queue, data->used_hw_queues);
+
+	/*
+	 * Mark MAC IDs as used by clearing the available bit, and
+	 * (below) mark TSFs as used if their existing use is not
+	 * compatible with the new interface type.
+	 * No locking or atomic bit operations are needed since the
+	 * data is on the stack of the caller function.
+	 */
+	__clear_bit(mvmvif->id, data->available_mac_ids);
+
+	/*
+	 * The TSF is a hardware/firmware resource, there are 4 and
+	 * the driver should assign and free them as needed. However,
+	 * there are cases where 2 MACs should share the same TSF ID
+	 * for the purpose of clock sync, an optimization to avoid
+	 * clock drift causing overlapping TBTTs/DTIMs for a GO and
+	 * client in the system.
+	 *
+	 * The firmware will decide according to the MAC type which
+	 * will be the master and slave. Clients that need to sync
+	 * with a remote station will be the master, and an AP or GO
+	 * will be the slave.
+	 *
+	 * Depending on the new interface type it can be slaved to
+	 * or become the master of an existing interface.
+	 */
+	switch (data->vif->type) {
+	case NL80211_IFTYPE_STATION:
+		/*
+		 * The new interface is client, so if the existing one
+		 * we're iterating is an AP, the TSF should be used to
+		 * avoid drift between the new client and existing AP,
+		 * the existing AP will get drift updates from the new
+		 * client context in this case
+		 */
+		if (vif->type == NL80211_IFTYPE_AP) {
+			if (data->preferred_tsf == NUM_TSF_IDS &&
+			    test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+				data->preferred_tsf = mvmvif->tsf_id;
+			return;
+		}
+		break;
+	case NL80211_IFTYPE_AP:
+		/*
+		 * The new interface is AP/GO, so should get drift
+		 * updates from an existing client or use the same
+		 * TSF as an existing GO. There's no drift between
+		 * TSFs internally but if they used different TSFs
+		 * then a new client MAC could update one of them
+		 * and cause drift that way.
+		 */
+		if (vif->type == NL80211_IFTYPE_STATION ||
+		    vif->type == NL80211_IFTYPE_AP) {
+			if (data->preferred_tsf == NUM_TSF_IDS &&
+			    test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+				data->preferred_tsf = mvmvif->tsf_id;
+			return;
+		}
+		break;
+	default:
+		/*
+		 * For all other interface types there's no need to
+		 * take drift into account. Either they're exclusive
+		 * like IBSS and monitor, or we don't care much about
+		 * their TSF (like P2P Device), but we won't be able
+		 * to share the TSF resource.
+		 */
+		break;
+	}
+
+	/*
+	 * Unless we exited above, we can't share the TSF resource
+	 * that the virtual interface we're iterating over is using
+	 * with the new one, so clear the available bit and if this
+	 * was the preferred one, reset that as well.
+	 */
+	__clear_bit(mvmvif->tsf_id, data->available_tsf_ids);
+
+	if (data->preferred_tsf == mvmvif->tsf_id)
+		data->preferred_tsf = NUM_TSF_IDS;
+}
+
+/*
+ * Get the mask of the queus used by the vif
+ */
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+				struct ieee80211_vif *vif)
+{
+	u32 qmask, ac;
+
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+		return BIT(IWL_OFFCHANNEL_QUEUE);
+
+	qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ?
+		BIT(vif->cab_queue) : 0;
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+			qmask |= BIT(vif->hw_queue[ac]);
+
+	return qmask;
+}
+
+static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
+					       struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_mac_iface_iterator_data data = {
+		.mvm = mvm,
+		.vif = vif,
+		.available_mac_ids = { (1 << NUM_MAC_INDEX_DRIVER) - 1 },
+		.available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
+		/* no preference yet */
+		.preferred_tsf = NUM_TSF_IDS,
+		.used_hw_queues = {
+			BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
+			BIT(IWL_MVM_AUX_QUEUE) |
+			BIT(IWL_MVM_CMD_QUEUE)
+		},
+		.found_vif = false,
+	};
+	u32 ac;
+	int ret;
+
+	/*
+	 * Allocate a MAC ID and a TSF for this MAC, along with the queues
+	 * and other resources.
+	 */
+
+	/*
+	 * Before the iterator, we start with all MAC IDs and TSFs available.
+	 *
+	 * During iteration, all MAC IDs are cleared that are in use by other
+	 * virtual interfaces, and all TSF IDs are cleared that can't be used
+	 * by this new virtual interface because they're used by an interface
+	 * that can't share it with the new one.
+	 * At the same time, we check if there's a preferred TSF in the case
+	 * that we should share it with another interface.
+	 */
+
+	/* Currently, MAC ID 0 should be used only for the managed vif */
+	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+		__clear_bit(0, data.available_mac_ids);
+
+	ieee80211_iterate_active_interfaces_atomic(
+		mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+		iwl_mvm_mac_iface_iterator, &data);
+
+	/*
+	 * In the case we're getting here during resume, it's similar to
+	 * firmware restart, and with RESUME_ALL the iterator will find
+	 * the vif being added already.
+	 * We don't want to reassign any IDs in either case since doing
+	 * so would probably assign different IDs (as interfaces aren't
+	 * necessarily added in the same order), but the old IDs were
+	 * preserved anyway, so skip ID assignment for both resume and
+	 * recovery.
+	 */
+	if (data.found_vif)
+		return 0;
+
+	/* Therefore, in recovery, we can't get here */
+	WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
+
+	mvmvif->id = find_first_bit(data.available_mac_ids,
+				    NUM_MAC_INDEX_DRIVER);
+	if (mvmvif->id == NUM_MAC_INDEX_DRIVER) {
+		IWL_ERR(mvm, "Failed to init MAC context - no free ID!\n");
+		ret = -EIO;
+		goto exit_fail;
+	}
+
+	if (data.preferred_tsf != NUM_TSF_IDS)
+		mvmvif->tsf_id = data.preferred_tsf;
+	else
+		mvmvif->tsf_id = find_first_bit(data.available_tsf_ids,
+						NUM_TSF_IDS);
+	if (mvmvif->tsf_id == NUM_TSF_IDS) {
+		IWL_ERR(mvm, "Failed to init MAC context - no free TSF!\n");
+		ret = -EIO;
+		goto exit_fail;
+	}
+
+	mvmvif->color = 0;
+
+	INIT_LIST_HEAD(&mvmvif->time_event_data.list);
+	mvmvif->time_event_data.id = TE_MAX;
+
+	/* No need to allocate data queues to P2P Device MAC.*/
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+			vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
+
+		return 0;
+	}
+
+	/* Find available queues, and allocate them to the ACs */
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+		u8 queue = find_first_zero_bit(data.used_hw_queues,
+					       IWL_MVM_FIRST_AGG_QUEUE);
+
+		if (queue >= IWL_MVM_FIRST_AGG_QUEUE) {
+			IWL_ERR(mvm, "Failed to allocate queue\n");
+			ret = -EIO;
+			goto exit_fail;
+		}
+
+		__set_bit(queue, data.used_hw_queues);
+		vif->hw_queue[ac] = queue;
+	}
+
+	/* Allocate the CAB queue for softAP and GO interfaces */
+	if (vif->type == NL80211_IFTYPE_AP) {
+		u8 queue = find_first_zero_bit(data.used_hw_queues,
+					       IWL_MVM_FIRST_AGG_QUEUE);
+
+		if (queue >= IWL_MVM_FIRST_AGG_QUEUE) {
+			IWL_ERR(mvm, "Failed to allocate cab queue\n");
+			ret = -EIO;
+			goto exit_fail;
+		}
+
+		vif->cab_queue = queue;
+	} else {
+		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+	}
+
+	mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT;
+	mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+
+	return 0;
+
+exit_fail:
+	memset(mvmvif, 0, sizeof(struct iwl_mvm_vif));
+	memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue));
+	vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+	return ret;
+}
+
+int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	u32 ac;
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	ret = iwl_mvm_mac_ctxt_allocate_resources(mvm, vif);
+	if (ret)
+		return ret;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_P2P_DEVICE:
+		iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE,
+					IWL_MVM_TX_FIFO_VO);
+		break;
+	case NL80211_IFTYPE_AP:
+		iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue,
+					IWL_MVM_TX_FIFO_VO);
+		/* fall through */
+	default:
+		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+			iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac],
+						iwl_mvm_ac_to_tx_fifo[ac]);
+		break;
+	}
+
+	return 0;
+}
+
+void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	int ac;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_P2P_DEVICE:
+		iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE);
+		break;
+	case NL80211_IFTYPE_AP:
+		iwl_trans_txq_disable(mvm->trans, vif->cab_queue);
+		/* fall through */
+	default:
+		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+			iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]);
+	}
+}
+
+static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,
+			      struct ieee80211_vif *vif,
+			      enum ieee80211_band band,
+			      u8 *cck_rates, u8 *ofdm_rates)
+{
+	struct ieee80211_supported_band *sband;
+	unsigned long basic = vif->bss_conf.basic_rates;
+	int lowest_present_ofdm = 100;
+	int lowest_present_cck = 100;
+	u8 cck = 0;
+	u8 ofdm = 0;
+	int i;
+
+	sband = mvm->hw->wiphy->bands[band];
+
+	for_each_set_bit(i, &basic, BITS_PER_LONG) {
+		int hw = sband->bitrates[i].hw_value;
+		if (hw >= IWL_FIRST_OFDM_RATE) {
+			ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
+			if (lowest_present_ofdm > hw)
+				lowest_present_ofdm = hw;
+		} else {
+			BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
+
+			cck |= BIT(hw);
+			if (lowest_present_cck > hw)
+				lowest_present_cck = hw;
+		}
+	}
+
+	/*
+	 * Now we've got the basic rates as bitmaps in the ofdm and cck
+	 * variables. This isn't sufficient though, as there might not
+	 * be all the right rates in the bitmap. E.g. if the only basic
+	 * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
+	 * and 6 Mbps because the 802.11-2007 standard says in 9.6:
+	 *
+	 *    [...] a STA responding to a received frame shall transmit
+	 *    its Control Response frame [...] at the highest rate in the
+	 *    BSSBasicRateSet parameter that is less than or equal to the
+	 *    rate of the immediately previous frame in the frame exchange
+	 *    sequence ([...]) and that is of the same modulation class
+	 *    ([...]) as the received frame. If no rate contained in the
+	 *    BSSBasicRateSet parameter meets these conditions, then the
+	 *    control frame sent in response to a received frame shall be
+	 *    transmitted at the highest mandatory rate of the PHY that is
+	 *    less than or equal to the rate of the received frame, and
+	 *    that is of the same modulation class as the received frame.
+	 *
+	 * As a consequence, we need to add all mandatory rates that are
+	 * lower than all of the basic rates to these bitmaps.
+	 */
+
+	if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE;
+	if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
+		ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE;
+	/* 6M already there or needed so always add */
+	ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE;
+
+	/*
+	 * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
+	 * Note, however:
+	 *  - if no CCK rates are basic, it must be ERP since there must
+	 *    be some basic rates at all, so they're OFDM => ERP PHY
+	 *    (or we're in 5 GHz, and the cck bitmap will never be used)
+	 *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
+	 *  - if 5.5M is basic, 1M and 2M are mandatory
+	 *  - if 2M is basic, 1M is mandatory
+	 *  - if 1M is basic, that's the only valid ACK rate.
+	 * As a consequence, it's not as complicated as it sounds, just add
+	 * any lower rates to the ACK rate bitmap.
+	 */
+	if (IWL_RATE_11M_INDEX < lowest_present_cck)
+		cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE;
+	if (IWL_RATE_5M_INDEX < lowest_present_cck)
+		cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE;
+	if (IWL_RATE_2M_INDEX < lowest_present_cck)
+		cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE;
+	/* 1M already there or needed so always add */
+	cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE;
+
+	*cck_rates = cck;
+	*ofdm_rates = ofdm;
+}
+
+static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					struct iwl_mac_ctx_cmd *cmd,
+					u32 action)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct ieee80211_chanctx_conf *chanctx;
+	u8 cck_ack_rates, ofdm_ack_rates;
+	int i;
+
+	cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+							    mvmvif->color));
+	cmd->action = cpu_to_le32(action);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		if (vif->p2p)
+			cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_STA);
+		else
+			cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_BSS_STA);
+		break;
+	case NL80211_IFTYPE_AP:
+		cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_GO);
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_LISTENER);
+		break;
+	case NL80211_IFTYPE_P2P_DEVICE:
+		cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_DEVICE);
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_IBSS);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+	}
+
+	cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
+
+	memcpy(cmd->node_addr, vif->addr, ETH_ALEN);
+	if (vif->bss_conf.bssid)
+		memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
+	else
+		eth_broadcast_addr(cmd->bssid_addr);
+
+	rcu_read_lock();
+	chanctx = rcu_dereference(vif->chanctx_conf);
+	iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band
+					    : IEEE80211_BAND_2GHZ,
+			  &cck_ack_rates, &ofdm_ack_rates);
+	rcu_read_unlock();
+
+	cmd->cck_rates = cpu_to_le32((u32)cck_ack_rates);
+	cmd->ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates);
+
+	cmd->cck_short_preamble =
+		cpu_to_le32(vif->bss_conf.use_short_preamble ?
+			    MAC_FLG_SHORT_PREAMBLE : 0);
+	cmd->short_slot =
+		cpu_to_le32(vif->bss_conf.use_short_slot ?
+			    MAC_FLG_SHORT_SLOT : 0);
+
+	for (i = 0; i < AC_NUM; i++) {
+		cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min);
+		cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max);
+		cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs;
+		cmd->ac[i].edca_txop =
+			cpu_to_le16(mvmvif->queue_params[i].txop * 32);
+		cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);
+	}
+
+	if (vif->bss_conf.qos)
+		cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
+
+	if (vif->bss_conf.use_cts_prot)
+		cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT |
+						     MAC_PROT_FLG_SELF_CTS_EN);
+
+	/*
+	 * I think that we should enable these 2 flags regardless the HT PROT
+	 * fields in the HT IE, but I am not sure. Someone knows whom to ask?...
+	 */
+	if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
+		cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
+		cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT |
+						     MAC_PROT_FLG_FAT_PROT);
+	}
+
+	cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
+}
+
+static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
+				     struct iwl_mac_ctx_cmd *cmd)
+{
+	int ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC,
+				       sizeof(*cmd), cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send MAC context (action:%d): %d\n",
+			le32_to_cpu(cmd->action), ret);
+	return ret;
+}
+
+/*
+ * Fill the specific data for mac context of type station or p2p client
+ */
+static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
+					  struct ieee80211_vif *vif,
+					  struct iwl_mac_data_sta *ctxt_sta)
+{
+	/* We need the dtim_period to set the MAC as associated */
+	if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) {
+		u32 dtim_offs;
+
+		/*
+		 * The DTIM count counts down, so when it is N that means N
+		 * more beacon intervals happen until the DTIM TBTT. Therefore
+		 * add this to the current time. If that ends up being in the
+		 * future, the firmware will handle it.
+		 *
+		 * Also note that the system_timestamp (which we get here as
+		 * "sync_device_ts") and TSF timestamp aren't at exactly the
+		 * same offset in the frame -- the TSF is at the first symbol
+		 * of the TSF, the system timestamp is at signal acquisition
+		 * time. This means there's an offset between them of at most
+		 * a few hundred microseconds (24 * 8 bits + PLCP time gives
+		 * 384us in the longest case), this is currently not relevant
+		 * as the firmware wakes up around 2ms before the TBTT.
+		 */
+		dtim_offs = vif->bss_conf.sync_dtim_count *
+				vif->bss_conf.beacon_int;
+		/* convert TU to usecs */
+		dtim_offs *= 1024;
+
+		ctxt_sta->dtim_tsf =
+			cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs);
+		ctxt_sta->dtim_time =
+			cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs);
+
+		IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n",
+			       le64_to_cpu(ctxt_sta->dtim_tsf),
+			       le32_to_cpu(ctxt_sta->dtim_time),
+			       dtim_offs);
+
+		ctxt_sta->is_assoc = cpu_to_le32(1);
+	} else {
+		ctxt_sta->is_assoc = cpu_to_le32(0);
+	}
+
+	ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int);
+	ctxt_sta->bi_reciprocal =
+		cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int));
+	ctxt_sta->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
+					      vif->bss_conf.dtim_period);
+	ctxt_sta->dtim_reciprocal =
+		cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int *
+					       vif->bss_conf.dtim_period));
+
+	ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval);
+	ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					u32 action)
+{
+	struct iwl_mac_ctx_cmd cmd = {};
+
+	WARN_ON(vif->type != NL80211_IFTYPE_STATION || vif->p2p);
+
+	/* Fill the common data for all mac context types */
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+	/* Fill the data specific for station mode */
+	iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
+
+	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
+					   struct ieee80211_vif *vif,
+					   u32 action)
+{
+	struct iwl_mac_ctx_cmd cmd = {};
+
+	WARN_ON(vif->type != NL80211_IFTYPE_STATION || !vif->p2p);
+
+	/* Fill the common data for all mac context types */
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+	/* Fill the data specific for station mode */
+	iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta);
+
+	cmd.p2p_sta.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
+
+	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
+					 struct ieee80211_vif *vif,
+					 u32 action)
+{
+	struct iwl_mac_ctx_cmd cmd = {};
+
+	WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
+
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	/* No other data to be filled */
+	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+struct iwl_mvm_go_iterator_data {
+	bool go_active;
+};
+
+static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_go_iterator_data *data = _data;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (vif->type == NL80211_IFTYPE_AP && vif->p2p && mvmvif->ap_active)
+		data->go_active = true;
+}
+
+static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
+					   struct ieee80211_vif *vif,
+					   u32 action)
+{
+	struct iwl_mac_ctx_cmd cmd = {};
+	struct iwl_mvm_go_iterator_data data = {};
+
+	WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
+
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+	cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
+	cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC);
+
+	/*
+	 * This flag should be set to true when the P2P Device is
+	 * discoverable and there is at least another active P2P GO. Settings
+	 * this flag will allow the P2P Device to be discoverable on other
+	 * channels in addition to its listen channel.
+	 * Note that this flag should not be set in other cases as it opens the
+	 * Rx filters on all MAC and increases the number of interrupts.
+	 */
+	ieee80211_iterate_active_interfaces_atomic(
+		mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+		iwl_mvm_go_iterator, &data);
+
+	cmd.p2p_dev.is_disc_extended = cpu_to_le32(data.go_active ? 1 : 0);
+	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
+				     struct iwl_mac_beacon_cmd *beacon_cmd,
+				     u8 *beacon, u32 frame_size)
+{
+	u32 tim_idx;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
+
+	/* The index is relative to frame start but we start looking at the
+	 * variable-length part of the beacon. */
+	tim_idx = mgmt->u.beacon.variable - beacon;
+
+	/* Parse variable-length elements of beacon to find WLAN_EID_TIM */
+	while ((tim_idx < (frame_size - 2)) &&
+			(beacon[tim_idx] != WLAN_EID_TIM))
+		tim_idx += beacon[tim_idx+1] + 2;
+
+	/* If TIM field was found, set variables */
+	if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
+		beacon_cmd->tim_idx = cpu_to_le32(tim_idx);
+		beacon_cmd->tim_size = cpu_to_le32((u32)beacon[tim_idx+1]);
+	} else {
+		IWL_WARN(mvm, "Unable to find TIM Element in beacon\n");
+	}
+}
+
+static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					struct sk_buff *beacon)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_host_cmd cmd = {
+		.id = BEACON_TEMPLATE_CMD,
+		.flags = CMD_ASYNC,
+	};
+	struct iwl_mac_beacon_cmd beacon_cmd = {};
+	struct ieee80211_tx_info *info;
+	u32 beacon_skb_len;
+	u32 rate;
+
+	if (WARN_ON(!beacon))
+		return -EINVAL;
+
+	beacon_skb_len = beacon->len;
+
+	/* TODO: for now the beacon template id is set to be the mac context id.
+	 * Might be better to handle it as another resource ... */
+	beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+
+	/* Set up TX command fields */
+	beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
+	beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
+	beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+	beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
+					     TX_CMD_FLG_BT_DIS  |
+					     TX_CMD_FLG_TSF);
+
+	mvm->mgmt_last_antenna_idx =
+		iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+				     mvm->mgmt_last_antenna_idx);
+
+	beacon_cmd.tx.rate_n_flags =
+		cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
+			    RATE_MCS_ANT_POS);
+
+	info = IEEE80211_SKB_CB(beacon);
+
+	if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) {
+		rate = IWL_FIRST_OFDM_RATE;
+	} else {
+		rate = IWL_FIRST_CCK_RATE;
+		beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK);
+	}
+	beacon_cmd.tx.rate_n_flags |=
+		cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate));
+
+	/* Set up TX beacon command fields */
+	iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd,
+				 beacon->data,
+				 beacon_skb_len);
+
+	/* Submit command */
+	cmd.len[0] = sizeof(beacon_cmd);
+	cmd.data[0] = &beacon_cmd;
+	cmd.dataflags[0] = 0;
+	cmd.len[1] = beacon_skb_len;
+	cmd.data[1] = beacon->data;
+	cmd.dataflags[1] = IWL_HCMD_DFL_DUP;
+
+	return iwl_mvm_send_cmd(mvm, &cmd);
+}
+
+/* The beacon template for the AP/GO context has changed and needs update */
+int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
+				    struct ieee80211_vif *vif)
+{
+	struct sk_buff *beacon;
+	int ret;
+
+	WARN_ON(vif->type != NL80211_IFTYPE_AP);
+
+	beacon = ieee80211_beacon_get(mvm->hw, vif);
+	if (!beacon)
+		return -ENOMEM;
+
+	ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon);
+	dev_kfree_skb(beacon);
+	return ret;
+}
+
+/*
+ * Fill the specific data for mac context of type AP of P2P GO
+ */
+static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
+					 struct ieee80211_vif *vif,
+					 struct iwl_mac_data_ap *ctxt_ap)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	u32 curr_dev_time;
+
+	ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
+	ctxt_ap->bi_reciprocal =
+		cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int));
+	ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
+					     vif->bss_conf.dtim_period);
+	ctxt_ap->dtim_reciprocal =
+		cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int *
+					       vif->bss_conf.dtim_period));
+
+	ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);
+	curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
+	ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time);
+
+	ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time);
+
+	/* TODO: Assume that the beacon id == mac context id */
+	ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
+				   struct ieee80211_vif *vif,
+				   u32 action)
+{
+	struct iwl_mac_ctx_cmd cmd = {};
+
+	WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
+
+	/* Fill the common data for all mac context types */
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+	/* Fill the data specific for ap mode */
+	iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap);
+
+	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
+				   struct ieee80211_vif *vif,
+				   u32 action)
+{
+	struct iwl_mac_ctx_cmd cmd = {};
+
+	WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
+
+	/* Fill the common data for all mac context types */
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+	/* Fill the data specific for GO mode */
+	iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap);
+
+	cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
+	cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps);
+
+	return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+				u32 action)
+{
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		if (!vif->p2p)
+			return iwl_mvm_mac_ctxt_cmd_station(mvm, vif,
+							    action);
+		else
+			return iwl_mvm_mac_ctxt_cmd_p2p_client(mvm, vif,
+							       action);
+		break;
+	case NL80211_IFTYPE_AP:
+		if (!vif->p2p)
+			return iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, action);
+		else
+			return iwl_mvm_mac_ctxt_cmd_go(mvm, vif, action);
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action);
+	case NL80211_IFTYPE_P2P_DEVICE:
+		return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action);
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int ret;
+
+	if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
+		      vif->addr, ieee80211_vif_type_p2p(vif)))
+		return -EIO;
+
+	ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD);
+	if (ret)
+		return ret;
+
+	mvmvif->uploaded = true;
+	return 0;
+}
+
+int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
+		      vif->addr, ieee80211_vif_type_p2p(vif)))
+		return -EIO;
+
+	return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY);
+}
+
+int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mac_ctx_cmd cmd;
+	int ret;
+
+	if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
+		      vif->addr, ieee80211_vif_type_p2p(vif)))
+		return -EIO;
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+							   mvmvif->color));
+	cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC,
+				   sizeof(cmd), &cmd);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to remove MAC context: %d\n", ret);
+		return ret;
+	}
+
+	mvmvif->uploaded = false;
+	return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
new file mode 100644
index 0000000..e8264e1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -0,0 +1,1314 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "iwl-op-mode.h"
+#include "iwl-io.h"
+#include "mvm.h"
+#include "sta.h"
+#include "time-event.h"
+#include "iwl-eeprom-parse.h"
+#include "fw-api-scan.h"
+#include "iwl-phy-db.h"
+
+static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_STATION) |
+			BIT(NL80211_IFTYPE_AP),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			BIT(NL80211_IFTYPE_P2P_GO),
+	},
+	{
+		.max = 1,
+		.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+	},
+};
+
+static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
+	{
+		.num_different_channels = 1,
+		.max_interfaces = 3,
+		.limits = iwl_mvm_limits,
+		.n_limits = ARRAY_SIZE(iwl_mvm_limits),
+	},
+};
+
+int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
+{
+	struct ieee80211_hw *hw = mvm->hw;
+	int num_mac, ret;
+
+	/* Tell mac80211 our characteristics */
+	hw->flags = IEEE80211_HW_SIGNAL_DBM |
+		    IEEE80211_HW_SPECTRUM_MGMT |
+		    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+		    IEEE80211_HW_QUEUE_CONTROL |
+		    IEEE80211_HW_WANT_MONITOR_VIF |
+		    IEEE80211_HW_SUPPORTS_PS |
+		    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
+		    IEEE80211_HW_AMPDU_AGGREGATION |
+		    IEEE80211_HW_TIMING_BEACON_ONLY;
+
+	hw->queues = IWL_FIRST_AMPDU_QUEUE;
+	hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE;
+	hw->rate_control_algorithm = "iwl-mvm-rs";
+
+	/*
+	 * Enable 11w if advertised by firmware and software crypto
+	 * is not enabled (as the firmware will interpret some mgmt
+	 * packets, so enabling it with software crypto isn't safe)
+	 */
+	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
+	    !iwlwifi_mod_params.sw_crypto)
+		hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+	hw->sta_data_size = sizeof(struct iwl_mvm_sta);
+	hw->vif_data_size = sizeof(struct iwl_mvm_vif);
+	hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt);
+
+	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+		BIT(NL80211_IFTYPE_P2P_CLIENT) |
+		BIT(NL80211_IFTYPE_AP) |
+		BIT(NL80211_IFTYPE_P2P_GO) |
+		BIT(NL80211_IFTYPE_P2P_DEVICE);
+
+	hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+			    WIPHY_FLAG_DISABLE_BEACON_HINTS |
+			    WIPHY_FLAG_IBSS_RSN;
+
+	hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
+	hw->wiphy->n_iface_combinations =
+		ARRAY_SIZE(iwl_mvm_iface_combinations);
+
+	hw->wiphy->max_remain_on_channel_duration = 500;
+	hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+	/* Extract MAC address */
+	memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
+	hw->wiphy->addresses = mvm->addresses;
+	hw->wiphy->n_addresses = 1;
+	num_mac = mvm->nvm_data->n_hw_addrs;
+	if (num_mac > 1) {
+		memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr,
+		       ETH_ALEN);
+		mvm->addresses[1].addr[5]++;
+		hw->wiphy->n_addresses++;
+	}
+
+	/* we create the 802.11 header and a max-length SSID element */
+	hw->wiphy->max_scan_ie_len =
+		mvm->fw->ucode_capa.max_probe_length - 24 - 34;
+	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+
+	if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
+		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+			&mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
+	if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels)
+		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+			&mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
+
+	hw->wiphy->hw_version = mvm->trans->hw_id;
+
+	if (iwlwifi_mod_params.power_save)
+		hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+	else
+		hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+	hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
+			       NL80211_FEATURE_P2P_GO_OPPPS;
+
+	mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+
+#ifdef CONFIG_PM_SLEEP
+	if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+	    mvm->trans->ops->d3_suspend &&
+	    mvm->trans->ops->d3_resume &&
+	    device_can_wakeup(mvm->trans->dev)) {
+		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+					  WIPHY_WOWLAN_DISCONNECT |
+					  WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+					  WIPHY_WOWLAN_RFKILL_RELEASE;
+		if (!iwlwifi_mod_params.sw_crypto)
+			hw->wiphy->wowlan.flags |=
+				WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+				WIPHY_WOWLAN_GTK_REKEY_FAILURE |
+				WIPHY_WOWLAN_4WAY_HANDSHAKE;
+
+		hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
+		hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
+		hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
+	}
+#endif
+
+	ret = iwl_mvm_leds_init(mvm);
+	if (ret)
+		return ret;
+
+	return ieee80211_register_hw(mvm->hw);
+}
+
+static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
+			   struct ieee80211_tx_control *control,
+			   struct sk_buff *skb)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) {
+		IWL_DEBUG_DROP(mvm, "Dropping - RF KILL\n");
+		goto drop;
+	}
+
+	if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE &&
+	    !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+		goto drop;
+
+	if (control->sta) {
+		if (iwl_mvm_tx_skb(mvm, skb, control->sta))
+			goto drop;
+		return;
+	}
+
+	if (iwl_mvm_tx_skb_non_sta(mvm, skb))
+		goto drop;
+	return;
+ drop:
+	ieee80211_free_txskb(hw, skb);
+}
+
+static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    enum ieee80211_ampdu_mlme_action action,
+				    struct ieee80211_sta *sta, u16 tid,
+				    u16 *ssn, u8 buf_size)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	int ret;
+
+	IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
+		     sta->addr, tid, action);
+
+	if (!(mvm->nvm_data->sku_cap_11n_enable))
+		return -EACCES;
+
+	mutex_lock(&mvm->mutex);
+
+	switch (action) {
+	case IEEE80211_AMPDU_RX_START:
+		if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		ret = -EINVAL;
+		break;
+	}
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
+				     struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = data;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	mvmvif->uploaded = false;
+	mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+
+	/* does this make sense at all? */
+	mvmvif->color++;
+
+	spin_lock_bh(&mvm->time_event_lock);
+	iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
+	spin_unlock_bh(&mvm->time_event_lock);
+
+	if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+		mvmvif->phy_ctxt = NULL;
+}
+
+static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
+{
+	iwl_trans_stop_device(mvm->trans);
+	iwl_trans_stop_hw(mvm->trans, false);
+
+	mvm->scan_status = IWL_MVM_SCAN_NONE;
+
+	/* just in case one was running */
+	ieee80211_remain_on_channel_expired(mvm->hw);
+
+	ieee80211_iterate_active_interfaces_atomic(
+		mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+		iwl_mvm_cleanup_iterator, mvm);
+
+	memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+	memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
+
+	ieee80211_wake_queues(mvm->hw);
+
+	mvm->vif_count = 0;
+}
+
+static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	int ret;
+
+	mutex_lock(&mvm->mutex);
+
+	/* Clean up some internal and mac80211 state on restart */
+	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+		iwl_mvm_restart_cleanup(mvm);
+
+	ret = iwl_mvm_up(mvm);
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	int ret;
+
+	mutex_lock(&mvm->mutex);
+
+	clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+	ret = iwl_mvm_update_quotas(mvm, NULL);
+	if (ret)
+		IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
+			ret);
+
+	mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	flush_work(&mvm->async_handlers_wk);
+
+	mutex_lock(&mvm->mutex);
+	/* async_handlers_wk is now blocked */
+
+	/*
+	 * The work item could be running or queued if the
+	 * ROC time event stops just as we get here.
+	 */
+	cancel_work_sync(&mvm->roc_done_wk);
+
+	iwl_trans_stop_device(mvm->trans);
+	iwl_trans_stop_hw(mvm->trans, false);
+
+	iwl_mvm_async_handlers_purge(mvm);
+	/* async_handlers_list is empty and will stay empty: HW is stopped */
+
+	/* the fw is stopped, the aux sta is dead: clean up driver state */
+	iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+
+	mutex_unlock(&mvm->mutex);
+
+	/*
+	 * The worker might have been waiting for the mutex, let it run and
+	 * discover that its list is now empty.
+	 */
+	cancel_work_sync(&mvm->async_handlers_wk);
+}
+
+static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac,
+					struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = data;
+	int ret;
+
+	ret = iwl_mvm_power_disable(mvm, vif);
+	if (ret)
+		IWL_ERR(mvm, "failed to disable power management\n");
+}
+
+static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
+					  struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = data;
+
+	iwl_mvm_power_update_mode(mvm, vif);
+}
+
+static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int ret;
+
+	/*
+	 * Not much to do here. The stack will not allow interface
+	 * types or combinations that we didn't advertise, so we
+	 * don't really have to check the types.
+	 */
+
+	mutex_lock(&mvm->mutex);
+
+	/* Allocate resources for the MAC context, and add it the the fw  */
+	ret = iwl_mvm_mac_ctxt_init(mvm, vif);
+	if (ret)
+		goto out_unlock;
+
+	/*
+	 * The AP binding flow can be done only after the beacon
+	 * template is configured (which happens only in the mac80211
+	 * start_ap() flow), and adding the broadcast station can happen
+	 * only after the binding.
+	 * In addition, since modifying the MAC before adding a bcast
+	 * station is not allowed by the FW, delay the adding of MAC context to
+	 * the point where we can also add the bcast station.
+	 * In short: there's not much we can do at this point, other than
+	 * allocating resources :)
+	 */
+	if (vif->type == NL80211_IFTYPE_AP) {
+		u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+		ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
+					       qmask);
+		if (ret) {
+			IWL_ERR(mvm, "Failed to allocate bcast sta\n");
+			goto out_release;
+		}
+
+		goto out_unlock;
+	}
+
+	/*
+	 * TODO: remove this temporary code.
+	 * Currently MVM FW supports power management only on single MAC.
+	 * Iterate and disable PM on all active interfaces.
+	 * Note: the method below does not count the new interface being added
+	 * at this moment.
+	 */
+	mvm->vif_count++;
+	if (mvm->vif_count > 1) {
+		IWL_DEBUG_MAC80211(mvm,
+				   "Disable power on existing interfaces\n");
+		ieee80211_iterate_active_interfaces_atomic(
+					    mvm->hw,
+					    IEEE80211_IFACE_ITER_NORMAL,
+					    iwl_mvm_pm_disable_iterator, mvm);
+	}
+
+	ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+	if (ret)
+		goto out_release;
+
+	/*
+	 * Update power state on the new interface. Admittedly, based on
+	 * mac80211 logics this power update will disable power management
+	 */
+	iwl_mvm_power_update_mode(mvm, vif);
+
+	/*
+	 * P2P_DEVICE interface does not have a channel context assigned to it,
+	 * so a dedicated PHY context is allocated to it and the corresponding
+	 * MAC context is bound to it at this stage.
+	 */
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+		struct ieee80211_channel *chan;
+		struct cfg80211_chan_def chandef;
+
+		mvmvif->phy_ctxt = &mvm->phy_ctxt_roc;
+
+		/*
+		 * The channel used here isn't relevant as it's
+		 * going to be overwritten as part of the ROC flow.
+		 * For now use the first channel we have.
+		 */
+		chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
+		cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+		ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt,
+					   &chandef, 1, 1);
+		if (ret)
+			goto out_remove_mac;
+
+		ret = iwl_mvm_binding_add_vif(mvm, vif);
+		if (ret)
+			goto out_remove_phy;
+
+		ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+		if (ret)
+			goto out_unbind;
+
+		/* Save a pointer to p2p device vif, so it can later be used to
+		 * update the p2p device MAC when a GO is started/stopped */
+		mvm->p2p_device_vif = vif;
+	}
+
+	goto out_unlock;
+
+ out_unbind:
+	iwl_mvm_binding_remove_vif(mvm, vif);
+ out_remove_phy:
+	iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
+ out_remove_mac:
+	mvmvif->phy_ctxt = NULL;
+	iwl_mvm_mac_ctxt_remove(mvm, vif);
+ out_release:
+	/*
+	 * TODO: remove this temporary code.
+	 * Currently MVM FW supports power management only on single MAC.
+	 * Check if only one additional interface remains after rereasing
+	 * current one. Update power mode on the remaining interface.
+	 */
+	mvm->vif_count--;
+	IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
+			   mvm->vif_count);
+	if (mvm->vif_count == 1) {
+		ieee80211_iterate_active_interfaces(
+					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+					iwl_mvm_power_update_iterator, mvm);
+	}
+	iwl_mvm_mac_ctxt_release(mvm, vif);
+ out_unlock:
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
+					 struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	u32 tfd_msk = 0, ac;
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+			tfd_msk |= BIT(vif->hw_queue[ac]);
+
+	if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+		tfd_msk |= BIT(vif->cab_queue);
+
+	if (tfd_msk) {
+		mutex_lock(&mvm->mutex);
+		iwl_mvm_flush_tx_path(mvm, tfd_msk, true);
+		mutex_unlock(&mvm->mutex);
+	}
+
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+		/*
+		 * Flush the ROC worker which will flush the OFFCHANNEL queue.
+		 * We assume here that all the packets sent to the OFFCHANNEL
+		 * queue are sent in ROC session.
+		 */
+		flush_work(&mvm->roc_done_wk);
+	} else {
+		/*
+		 * By now, all the AC queues are empty. The AGG queues are
+		 * empty too. We already got all the Tx responses for all the
+		 * packets in the queues. The drain work can have been
+		 * triggered. Flush it. This work item takes the mutex, so kill
+		 * it before we take it.
+		 */
+		flush_work(&mvm->sta_drained_wk);
+	}
+
+	mutex_lock(&mvm->mutex);
+
+	/*
+	 * For AP/GO interface, the tear down of the resources allocated to the
+	 * interface should be handled as part of the bss_info_changed flow.
+	 */
+	if (vif->type == NL80211_IFTYPE_AP) {
+		iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+		goto out_release;
+	}
+
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+		mvm->p2p_device_vif = NULL;
+		iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+		iwl_mvm_binding_remove_vif(mvm, vif);
+		iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
+		mvmvif->phy_ctxt = NULL;
+	}
+
+	/*
+	 * TODO: remove this temporary code.
+	 * Currently MVM FW supports power management only on single MAC.
+	 * Check if only one additional interface remains after removing
+	 * current one. Update power mode on the remaining interface.
+	 */
+	if (mvm->vif_count)
+		mvm->vif_count--;
+	IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
+			   mvm->vif_count);
+	if (mvm->vif_count == 1) {
+		ieee80211_iterate_active_interfaces(
+					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+					iwl_mvm_power_update_iterator, mvm);
+	}
+
+	iwl_mvm_mac_ctxt_remove(mvm, vif);
+
+out_release:
+	iwl_mvm_mac_ctxt_release(mvm, vif);
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+	return 0;
+}
+
+static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
+				     unsigned int changed_flags,
+				     unsigned int *total_flags,
+				     u64 multicast)
+{
+	*total_flags = 0;
+}
+
+static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
+					     struct ieee80211_vif *vif,
+					     struct ieee80211_bss_conf *bss_conf,
+					     u32 changes)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int ret;
+
+	ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
+	if (ret)
+		IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
+
+	if (changes & BSS_CHANGED_ASSOC) {
+		if (bss_conf->assoc) {
+			/* add quota for this interface */
+			ret = iwl_mvm_update_quotas(mvm, vif);
+			if (ret) {
+				IWL_ERR(mvm, "failed to update quotas\n");
+				return;
+			}
+		} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+			/* remove AP station now that the MAC is unassoc */
+			ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
+			if (ret)
+				IWL_ERR(mvm, "failed to remove AP station\n");
+			mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+			/* remove quota for this interface */
+			ret = iwl_mvm_update_quotas(mvm, NULL);
+			if (ret)
+				IWL_ERR(mvm, "failed to update quotas\n");
+		}
+	} else if (changes & BSS_CHANGED_DTIM_PERIOD) {
+		/*
+		 * We received a beacon _after_ association so
+		 * remove the session protection.
+		 */
+		iwl_mvm_remove_time_event(mvm, mvmvif,
+					  &mvmvif->time_event_data);
+	} else if (changes & BSS_CHANGED_PS) {
+		/*
+		 * TODO: remove this temporary code.
+		 * Currently MVM FW supports power management only on single
+		 * MAC. Avoid power mode update if more than one interface
+		 * is active.
+		 */
+		IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
+				   mvm->vif_count);
+		if (mvm->vif_count == 1) {
+			ret = iwl_mvm_power_update_mode(mvm, vif);
+			if (ret)
+				IWL_ERR(mvm, "failed to update power mode\n");
+		}
+	}
+}
+
+static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int ret;
+
+	mutex_lock(&mvm->mutex);
+
+	/* Send the beacon template */
+	ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif);
+	if (ret)
+		goto out_unlock;
+
+	/* Add the mac context */
+	ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+	if (ret)
+		goto out_unlock;
+
+	/* Perform the binding */
+	ret = iwl_mvm_binding_add_vif(mvm, vif);
+	if (ret)
+		goto out_remove;
+
+	mvmvif->ap_active = true;
+
+	/* Send the bcast station. At this stage the TBTT and DTIM time events
+	 * are added and applied to the scheduler */
+	ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+	if (ret)
+		goto out_unbind;
+
+	ret = iwl_mvm_update_quotas(mvm, vif);
+	if (ret)
+		goto out_rm_bcast;
+
+	/* Need to update the P2P Device MAC */
+	if (vif->p2p && mvm->p2p_device_vif)
+		iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
+
+	mutex_unlock(&mvm->mutex);
+	return 0;
+
+out_rm_bcast:
+	iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+out_unbind:
+	iwl_mvm_binding_remove_vif(mvm, vif);
+out_remove:
+	iwl_mvm_mac_ctxt_remove(mvm, vif);
+out_unlock:
+	mutex_unlock(&mvm->mutex);
+	return ret;
+}
+
+static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	mutex_lock(&mvm->mutex);
+
+	mvmvif->ap_active = false;
+
+	/* Need to update the P2P Device MAC */
+	if (vif->p2p && mvm->p2p_device_vif)
+		iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
+
+	iwl_mvm_update_quotas(mvm, NULL);
+	iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+	iwl_mvm_binding_remove_vif(mvm, vif);
+	iwl_mvm_mac_ctxt_remove(mvm, vif);
+
+	mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					struct ieee80211_bss_conf *bss_conf,
+					u32 changes)
+{
+	/* Need to send a new beacon template to the FW */
+	if (changes & BSS_CHANGED_BEACON) {
+		if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
+			IWL_WARN(mvm, "Failed updating beacon data\n");
+	}
+}
+
+static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_bss_conf *bss_conf,
+				     u32 changes)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	mutex_lock(&mvm->mutex);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);
+		break;
+	case NL80211_IFTYPE_AP:
+		iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes);
+		break;
+	default:
+		/* shouldn't happen */
+		WARN_ON_ONCE(1);
+	}
+
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct cfg80211_scan_request *req)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	int ret;
+
+	if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS)
+		return -EINVAL;
+
+	mutex_lock(&mvm->mutex);
+
+	if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+		ret = iwl_mvm_scan_request(mvm, vif, req);
+	else
+		ret = -EBUSY;
+
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	mutex_lock(&mvm->mutex);
+
+	iwl_mvm_cancel_scan(mvm);
+
+	mutex_unlock(&mvm->mutex);
+}
+
+static void
+iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
+				  struct ieee80211_sta *sta, u16 tid,
+				  int num_frames,
+				  enum ieee80211_frame_release_type reason,
+				  bool more_data)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	/* TODO: how do we tell the fw to send frames for a specific TID */
+
+	/*
+	 * The fw will send EOSP notification when the last frame will be
+	 * transmitted.
+	 */
+	iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames);
+}
+
+static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   enum sta_notify_cmd cmd,
+				   struct ieee80211_sta *sta)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+
+	switch (cmd) {
+	case STA_NOTIFY_SLEEP:
+		if (atomic_read(&mvmsta->pending_frames) > 0)
+			ieee80211_sta_block_awake(hw, sta, true);
+		/*
+		 * The fw updates the STA to be asleep. Tx packets on the Tx
+		 * queues to this station will not be transmitted. The fw will
+		 * send a Tx response with TX_STATUS_FAIL_DEST_PS.
+		 */
+		break;
+	case STA_NOTIFY_AWAKE:
+		if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION))
+			break;
+		iwl_mvm_sta_modify_ps_wake(mvm, sta);
+		break;
+	default:
+		break;
+	}
+}
+
+static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta,
+				 enum ieee80211_sta_state old_state,
+				 enum ieee80211_sta_state new_state)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int ret;
+
+	IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n",
+			   sta->addr, old_state, new_state);
+
+	/* this would be a mac80211 bug ... but don't crash */
+	if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
+		return -EINVAL;
+
+	/* if a STA is being removed, reuse its ID */
+	flush_work(&mvm->sta_drained_wk);
+
+	mutex_lock(&mvm->mutex);
+	if (old_state == IEEE80211_STA_NOTEXIST &&
+	    new_state == IEEE80211_STA_NONE) {
+		ret = iwl_mvm_add_sta(mvm, vif, sta);
+	} else if (old_state == IEEE80211_STA_NONE &&
+		   new_state == IEEE80211_STA_AUTH) {
+		ret = 0;
+	} else if (old_state == IEEE80211_STA_AUTH &&
+		   new_state == IEEE80211_STA_ASSOC) {
+		ret = iwl_mvm_update_sta(mvm, vif, sta);
+		if (ret == 0)
+			iwl_mvm_rs_rate_init(mvm, sta,
+					     mvmvif->phy_ctxt->channel->band);
+	} else if (old_state == IEEE80211_STA_ASSOC &&
+		   new_state == IEEE80211_STA_AUTHORIZED) {
+		ret = 0;
+	} else if (old_state == IEEE80211_STA_AUTHORIZED &&
+		   new_state == IEEE80211_STA_ASSOC) {
+		ret = 0;
+	} else if (old_state == IEEE80211_STA_ASSOC &&
+		   new_state == IEEE80211_STA_AUTH) {
+		ret = 0;
+	} else if (old_state == IEEE80211_STA_AUTH &&
+		   new_state == IEEE80211_STA_NONE) {
+		ret = 0;
+	} else if (old_state == IEEE80211_STA_NONE &&
+		   new_state == IEEE80211_STA_NOTEXIST) {
+		ret = iwl_mvm_rm_sta(mvm, vif, sta);
+	} else {
+		ret = -EIO;
+	}
+	mutex_unlock(&mvm->mutex);
+
+	return ret;
+}
+
+static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	mvm->rts_threshold = value;
+
+	return 0;
+}
+
+static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif, u16 ac,
+			       const struct ieee80211_tx_queue_params *params)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	mvmvif->queue_params[ac] = *params;
+
+	/*
+	 * No need to update right away, we'll get BSS_CHANGED_QOS
+	 * The exception is P2P_DEVICE interface which needs immediate update.
+	 */
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+		int ret;
+
+		mutex_lock(&mvm->mutex);
+		ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
+		mutex_unlock(&mvm->mutex);
+		return ret;
+	}
+	return 0;
+}
+
+static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS,
+			   200 + vif->bss_conf.beacon_int);
+	u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS,
+			       100 + vif->bss_conf.beacon_int);
+
+	if (WARN_ON_ONCE(vif->bss_conf.assoc))
+		return;
+
+	mutex_lock(&mvm->mutex);
+	/* Try really hard to protect the session and hear a beacon */
+	iwl_mvm_protect_session(mvm, vif, duration, min_duration);
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
+			       enum set_key_cmd cmd,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_sta *sta,
+			       struct ieee80211_key_conf *key)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	int ret;
+
+	if (iwlwifi_mod_params.sw_crypto) {
+		IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+		/* fall-through */
+	case WLAN_CIPHER_SUITE_CCMP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		break;
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+		WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE));
+		break;
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		/*
+		 * Support for TX only, at least for now, so accept
+		 * the key and do nothing else. Then mac80211 will
+		 * pass it for TX but we don't have to use it for RX.
+		 */
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	mutex_lock(&mvm->mutex);
+
+	switch (cmd) {
+	case SET_KEY:
+		IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
+		ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
+		if (ret) {
+			IWL_WARN(mvm, "set key failed\n");
+			/*
+			 * can't add key for RX, but we don't need it
+			 * in the device for TX so still return 0
+			 */
+			ret = 0;
+		}
+
+		break;
+	case DISABLE_KEY:
+		IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
+		ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&mvm->mutex);
+	return ret;
+}
+
+static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
+					struct ieee80211_key_conf *keyconf,
+					struct ieee80211_sta *sta,
+					u32 iv32, u16 *phase1key)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key);
+}
+
+
+static int iwl_mvm_roc(struct ieee80211_hw *hw,
+		       struct ieee80211_vif *vif,
+		       struct ieee80211_channel *channel,
+		       int duration)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct cfg80211_chan_def chandef;
+	int ret;
+
+	if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
+		IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type);
+		return -EINVAL;
+	}
+
+	IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value,
+			   duration);
+
+	mutex_lock(&mvm->mutex);
+
+	cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
+	ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc,
+				       &chandef, 1, 1);
+
+	/* Schedule the time events */
+	ret = iwl_mvm_start_p2p_roc(mvm, vif, duration);
+
+	mutex_unlock(&mvm->mutex);
+	IWL_DEBUG_MAC80211(mvm, "leave\n");
+
+	return ret;
+}
+
+static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	IWL_DEBUG_MAC80211(mvm, "enter\n");
+
+	mutex_lock(&mvm->mutex);
+	iwl_mvm_stop_p2p_roc(mvm);
+	mutex_unlock(&mvm->mutex);
+
+	IWL_DEBUG_MAC80211(mvm, "leave\n");
+	return 0;
+}
+
+static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
+			       struct ieee80211_chanctx_conf *ctx)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+	int ret;
+
+	mutex_lock(&mvm->mutex);
+
+	IWL_DEBUG_MAC80211(mvm, "Add PHY context\n");
+	ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def,
+				   ctx->rx_chains_static,
+				   ctx->rx_chains_dynamic);
+	mutex_unlock(&mvm->mutex);
+	return ret;
+}
+
+static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw,
+				   struct ieee80211_chanctx_conf *ctx)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+
+	mutex_lock(&mvm->mutex);
+	iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt);
+	mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
+				   struct ieee80211_chanctx_conf *ctx,
+				   u32 changed)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+
+	mutex_lock(&mvm->mutex);
+	iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
+				 ctx->rx_chains_static,
+				 ctx->rx_chains_dynamic);
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      struct ieee80211_chanctx_conf *ctx)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	int ret;
+
+	mutex_lock(&mvm->mutex);
+
+	mvmvif->phy_ctxt = phyctx;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_AP:
+		/*
+		 * The AP binding flow is handled as part of the start_ap flow
+		 * (in bss_info_changed).
+		 */
+		ret = 0;
+		goto out_unlock;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MONITOR:
+		break;
+	default:
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	ret = iwl_mvm_binding_add_vif(mvm, vif);
+	if (ret)
+		goto out_unlock;
+
+	/*
+	 * Setting the quota at this stage is only required for monitor
+	 * interfaces. For the other types, the bss_info changed flow
+	 * will handle quota settings.
+	 */
+	if (vif->type == NL80211_IFTYPE_MONITOR) {
+		ret = iwl_mvm_update_quotas(mvm, vif);
+		if (ret)
+			goto out_remove_binding;
+	}
+
+	goto out_unlock;
+
+ out_remove_binding:
+	iwl_mvm_binding_remove_vif(mvm, vif);
+ out_unlock:
+	mutex_unlock(&mvm->mutex);
+	if (ret)
+		mvmvif->phy_ctxt = NULL;
+	return ret;
+}
+
+static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
+					 struct ieee80211_vif *vif,
+					 struct ieee80211_chanctx_conf *ctx)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	mutex_lock(&mvm->mutex);
+
+	iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
+
+	if (vif->type == NL80211_IFTYPE_AP)
+		goto out_unlock;
+
+	iwl_mvm_binding_remove_vif(mvm, vif);
+	switch (vif->type) {
+	case NL80211_IFTYPE_MONITOR:
+		iwl_mvm_update_quotas(mvm, vif);
+		break;
+	default:
+		break;
+	}
+
+out_unlock:
+	mvmvif->phy_ctxt = NULL;
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
+			   struct ieee80211_sta *sta,
+			   bool set)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+	if (!mvm_sta || !mvm_sta->vif) {
+		IWL_ERR(mvm, "Station is not associated to a vif\n");
+		return -EINVAL;
+	}
+
+	return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
+}
+
+struct ieee80211_ops iwl_mvm_hw_ops = {
+	.tx = iwl_mvm_mac_tx,
+	.ampdu_action = iwl_mvm_mac_ampdu_action,
+	.start = iwl_mvm_mac_start,
+	.restart_complete = iwl_mvm_mac_restart_complete,
+	.stop = iwl_mvm_mac_stop,
+	.add_interface = iwl_mvm_mac_add_interface,
+	.remove_interface = iwl_mvm_mac_remove_interface,
+	.config = iwl_mvm_mac_config,
+	.configure_filter = iwl_mvm_configure_filter,
+	.bss_info_changed = iwl_mvm_bss_info_changed,
+	.hw_scan = iwl_mvm_mac_hw_scan,
+	.cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
+	.sta_state = iwl_mvm_mac_sta_state,
+	.sta_notify = iwl_mvm_mac_sta_notify,
+	.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
+	.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
+	.conf_tx = iwl_mvm_mac_conf_tx,
+	.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
+	.set_key = iwl_mvm_mac_set_key,
+	.update_tkip_key = iwl_mvm_mac_update_tkip_key,
+	.remain_on_channel = iwl_mvm_roc,
+	.cancel_remain_on_channel = iwl_mvm_cancel_roc,
+
+	.add_chanctx = iwl_mvm_add_chanctx,
+	.remove_chanctx = iwl_mvm_remove_chanctx,
+	.change_chanctx = iwl_mvm_change_chanctx,
+	.assign_vif_chanctx = iwl_mvm_assign_vif_chanctx,
+	.unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx,
+
+	.start_ap = iwl_mvm_start_ap,
+	.stop_ap = iwl_mvm_stop_ap,
+
+	.set_tim = iwl_mvm_set_tim,
+
+#ifdef CONFIG_PM_SLEEP
+	/* look at d3.c */
+	.suspend = iwl_mvm_suspend,
+	.resume = iwl_mvm_resume,
+	.set_wakeup = iwl_mvm_set_wakeup,
+	.set_rekey_data = iwl_mvm_set_rekey_data,
+#if IS_ENABLED(CONFIG_IPV6)
+	.ipv6_addr_change = iwl_mvm_ipv6_addr_change,
+#endif
+	.set_default_unicast_key = iwl_mvm_set_default_unicast_key,
+#endif
+};
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
new file mode 100644
index 0000000..4e339cc
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __IWL_MVM_H__
+#define __IWL_MVM_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include <linux/in6.h>
+
+#include "iwl-op-mode.h"
+#include "iwl-trans.h"
+#include "iwl-notif-wait.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-test.h"
+#include "iwl-trans.h"
+#include "sta.h"
+#include "fw-api.h"
+
+#define IWL_INVALID_MAC80211_QUEUE	0xff
+#define IWL_MVM_MAX_ADDRESSES		2
+#define IWL_RSSI_OFFSET 44
+
+enum iwl_mvm_tx_fifo {
+	IWL_MVM_TX_FIFO_BK = 0,
+	IWL_MVM_TX_FIFO_BE,
+	IWL_MVM_TX_FIFO_VI,
+	IWL_MVM_TX_FIFO_VO,
+};
+
+/* Placeholder */
+#define IWL_OFFCHANNEL_QUEUE 8
+#define IWL_FIRST_AMPDU_QUEUE 11
+
+extern struct ieee80211_ops iwl_mvm_hw_ops;
+/**
+ * struct iwl_mvm_mod_params - module parameters for iwlmvm
+ * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted.
+ *	We will register to mac80211 to have testmode working. The NIC must not
+ *	be up'ed after the INIT fw asserted. This is useful to be able to use
+ *	proprietary tools over testmode to debug the INIT fw.
+ * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power
+ *	Save)-2(default), LP(Low Power)-3
+ */
+struct iwl_mvm_mod_params {
+	bool init_dbg;
+	int power_scheme;
+};
+extern struct iwl_mvm_mod_params iwlmvm_mod_params;
+
+struct iwl_mvm_phy_ctxt {
+	u16 id;
+	u16 color;
+
+	/*
+	 * TODO: This should probably be removed. Currently here only for rate
+	 * scaling algorithm
+	 */
+	struct ieee80211_channel *channel;
+};
+
+struct iwl_mvm_time_event_data {
+	struct ieee80211_vif *vif;
+	struct list_head list;
+	unsigned long end_jiffies;
+	u32 duration;
+	bool running;
+	u32 uid;
+
+	/*
+	 * The access to the 'id' field must be done when the
+	 * mvm->time_event_lock is held, as it value is used to indicate
+	 * if the te is in the time event list or not (when id == TE_MAX)
+	 */
+	u32 id;
+};
+
+ /* Power management */
+
+/**
+ * enum iwl_power_scheme
+ * @IWL_POWER_LEVEL_CAM - Continuously Active Mode
+ * @IWL_POWER_LEVEL_BPS - Balanced Power Save (default)
+ * @IWL_POWER_LEVEL_LP  - Low Power
+ */
+enum iwl_power_scheme {
+	IWL_POWER_SCHEME_CAM = 1,
+	IWL_POWER_SCHEME_BPS,
+	IWL_POWER_SCHEME_LP
+};
+
+#define IWL_CONN_MAX_LISTEN_INTERVAL	70
+
+/**
+ * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
+ * @id: between 0 and 3
+ * @color: to solve races upon MAC addition and removal
+ * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
+ * @uploaded: indicates the MAC context has been added to the device
+ * @ap_active: indicates that ap context is configured, and that the interface
+ *  should get quota etc.
+ * @queue_params: QoS params for this MAC
+ * @bcast_sta: station used for broadcast packets. Used by the following
+ *  vifs: P2P_DEVICE, GO and AP.
+ * @beacon_skb: the skb used to hold the AP/GO beacon template
+ */
+struct iwl_mvm_vif {
+	u16 id;
+	u16 color;
+	u8 ap_sta_id;
+
+	bool uploaded;
+	bool ap_active;
+
+	enum iwl_tsf_id tsf_id;
+
+	/*
+	 * QoS data from mac80211, need to store this here
+	 * as mac80211 has a separate callback but we need
+	 * to have the data for the MAC context
+	 */
+	struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+	struct iwl_mvm_time_event_data time_event_data;
+
+	struct iwl_mvm_int_sta bcast_sta;
+
+	/*
+	 * Assigned while mac80211 has the interface in a channel context,
+	 * or, for P2P Device, while it exists.
+	 */
+	struct iwl_mvm_phy_ctxt *phy_ctxt;
+
+#ifdef CONFIG_PM_SLEEP
+	/* WoWLAN GTK rekey data */
+	struct {
+		u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
+		__le64 replay_ctr;
+		bool valid;
+	} rekey_data;
+
+	int tx_key_idx;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	/* IPv6 addresses for WoWLAN */
+	struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS];
+	int num_target_ipv6_addrs;
+#endif
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	struct dentry *dbgfs_dir;
+	void *dbgfs_data;
+#endif
+};
+
+static inline struct iwl_mvm_vif *
+iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
+{
+	return (void *)vif->drv_priv;
+}
+
+enum iwl_mvm_status {
+	IWL_MVM_STATUS_HW_RFKILL,
+	IWL_MVM_STATUS_ROC_RUNNING,
+	IWL_MVM_STATUS_IN_HW_RESTART,
+};
+
+enum iwl_scan_status {
+	IWL_MVM_SCAN_NONE,
+	IWL_MVM_SCAN_OS,
+};
+
+/**
+ * struct iwl_nvm_section - describes an NVM section in memory.
+ *
+ * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD,
+ * and saved for later use by the driver. Not all NVM sections are saved
+ * this way, only the needed ones.
+ */
+struct iwl_nvm_section {
+	u16 length;
+	const u8 *data;
+};
+
+struct iwl_mvm {
+	/* for logger access */
+	struct device *dev;
+
+	struct iwl_trans *trans;
+	const struct iwl_fw *fw;
+	const struct iwl_cfg *cfg;
+	struct iwl_phy_db *phy_db;
+	struct ieee80211_hw *hw;
+
+	/* for protecting access to iwl_mvm */
+	struct mutex mutex;
+	struct list_head async_handlers_list;
+	spinlock_t async_handlers_lock;
+	struct work_struct async_handlers_wk;
+
+	struct work_struct roc_done_wk;
+
+	unsigned long status;
+
+	enum iwl_ucode_type cur_ucode;
+	bool ucode_loaded;
+	bool init_ucode_run;
+	u32 error_event_table;
+	u32 log_event_table;
+
+	u32 ampdu_ref;
+
+	struct iwl_notif_wait_data notif_wait;
+
+	unsigned long transport_queue_stop;
+	u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
+	atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+
+	struct iwl_nvm_data *nvm_data;
+	/* eeprom blob for debugfs/testmode */
+	u8 *eeprom_blob;
+	size_t eeprom_blob_size;
+	/* NVM sections for 7000 family */
+	struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS];
+
+	/* EEPROM MAC addresses */
+	struct mac_address addresses[IWL_MVM_MAX_ADDRESSES];
+
+	/* data related to data path */
+	struct iwl_rx_phy_info last_phy_info;
+	struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
+	struct work_struct sta_drained_wk;
+	unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
+
+	/* configured by mac80211 */
+	u32 rts_threshold;
+
+	/* Scan status, cmd (pre-allocated) and auxiliary station */
+	enum iwl_scan_status scan_status;
+	struct iwl_scan_cmd *scan_cmd;
+
+	/* Internal station */
+	struct iwl_mvm_int_sta aux_sta;
+
+	u8 scan_last_antenna_idx; /* to toggle TX between antennas */
+	u8 mgmt_last_antenna_idx;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+	struct dentry *debugfs_dir;
+	u32 dbgfs_sram_offset, dbgfs_sram_len;
+	bool prevent_power_down_d3;
+#endif
+
+	struct iwl_mvm_phy_ctxt phy_ctxt_roc;
+
+	struct list_head time_event_list;
+	spinlock_t time_event_lock;
+
+	/*
+	 * A bitmap indicating the index of the key in use. The firmware
+	 * can hold 16 keys at most. Reflect this fact.
+	 */
+	unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
+	u8 vif_count;
+
+	struct led_classdev led;
+
+	struct ieee80211_vif *p2p_device_vif;
+};
+
+/* Extract MVM priv from op_mode and _hw */
+#define IWL_OP_MODE_GET_MVM(_iwl_op_mode)		\
+	((struct iwl_mvm *)(_iwl_op_mode)->op_mode_specific)
+
+#define IWL_MAC80211_GET_MVM(_hw)			\
+	IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv))
+
+extern const u8 iwl_mvm_ac_to_tx_fifo[];
+
+struct iwl_rate_info {
+	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
+	u8 plcp_mimo2;	/* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
+	u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
+	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
+};
+
+/******************
+ * MVM Methods
+ ******************/
+/* uCode */
+int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm);
+
+/* Utils */
+int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
+					enum ieee80211_band band);
+u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
+void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
+u8 first_antenna(u8 mask);
+u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
+
+/* Tx / Host Commands */
+int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm,
+				  struct iwl_host_cmd *cmd);
+int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id,
+				      u32 flags, u16 len, const void *data);
+int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm,
+					 struct iwl_host_cmd *cmd,
+					 u32 *status);
+int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id,
+					     u16 len, const void *data,
+					     u32 *status);
+int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
+		   struct ieee80211_sta *sta);
+int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb);
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_mvm_get_tx_fail_reason(u32 status);
+#else
+static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
+#endif
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync);
+void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
+
+/* Statistics */
+int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
+				struct iwl_rx_cmd_buffer *rxb,
+				struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
+			  struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd);
+
+/* NVM */
+int iwl_nvm_init(struct iwl_mvm *mvm);
+
+int iwl_mvm_up(struct iwl_mvm *mvm);
+int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
+
+int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm);
+
+/*
+ * FW notifications / CMD responses handlers
+ * Convention: iwl_mvm_rx_<NAME OF THE CMD>
+ */
+int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+		       struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+		      struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			 struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
+				struct iwl_rx_cmd_buffer *rxb,
+				struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			 struct iwl_device_cmd *cmd);
+
+/* MVM PHY */
+int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+			 struct cfg80211_chan_def *chandef,
+			 u8 chains_static, u8 chains_dynamic);
+int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+			     struct cfg80211_chan_def *chandef,
+			     u8 chains_static, u8 chains_dynamic);
+void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm,
+			     struct iwl_mvm_phy_ctxt *ctxt);
+
+/* MAC (virtual interface) programming */
+int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+				struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
+				    struct ieee80211_vif *vif);
+
+/* Bindings */
+int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
+/* Quota management */
+int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif);
+
+/* Scanning */
+int iwl_mvm_scan_request(struct iwl_mvm *mvm,
+			 struct ieee80211_vif *vif,
+			 struct cfg80211_scan_request *req);
+int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			     struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			     struct iwl_device_cmd *cmd);
+void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
+
+/* MVM debugfs */
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
+int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			       struct dentry *dbgfs_dir);
+void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			  struct iwl_powertable_cmd *cmd);
+#else
+static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm,
+					 struct dentry *dbgfs_dir)
+{
+	return 0;
+}
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+
+/* rate scaling */
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
+			u8 flags, bool init);
+
+/* power managment */
+int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
+int iwl_mvm_leds_init(struct iwl_mvm *mvm);
+void iwl_mvm_leds_exit(struct iwl_mvm *mvm);
+
+/* D3 (WoWLAN, NetDetect) */
+int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
+int iwl_mvm_resume(struct ieee80211_hw *hw);
+void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled);
+void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif,
+			    struct cfg80211_gtk_rekey_data *data);
+void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
+			      struct ieee80211_vif *vif,
+			      struct inet6_dev *idev);
+void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif, int idx);
+
+#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
new file mode 100644
index 0000000..20016bc
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -0,0 +1,311 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include "iwl-trans.h"
+#include "mvm.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-eeprom-read.h"
+#include "iwl-nvm-parse.h"
+
+/* list of NVM sections we are allowed/need to read */
+static const int nvm_to_read[] = {
+	NVM_SECTION_TYPE_HW,
+	NVM_SECTION_TYPE_SW,
+	NVM_SECTION_TYPE_CALIBRATION,
+	NVM_SECTION_TYPE_PRODUCTION,
+};
+
+/* used to simplify the shared operations on NCM_ACCESS_CMD versions */
+union iwl_nvm_access_cmd {
+	struct iwl_nvm_access_cmd_ver1 ver1;
+	struct iwl_nvm_access_cmd_ver2 ver2;
+};
+union iwl_nvm_access_resp {
+	struct iwl_nvm_access_resp_ver1 ver1;
+	struct iwl_nvm_access_resp_ver2 ver2;
+};
+
+static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd,
+					  u16 offset, u16 length)
+{
+	cmd->offset = cpu_to_le16(offset);
+	cmd->length = cpu_to_le16(length);
+	cmd->cache_refresh = 1;
+}
+
+static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
+					  u16 offset, u16 length, u16 section)
+{
+	cmd->offset = cpu_to_le16(offset);
+	cmd->length = cpu_to_le16(length);
+	cmd->type = cpu_to_le16(section);
+}
+
+static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
+			      u16 offset, u16 length, u8 *data)
+{
+	union iwl_nvm_access_cmd nvm_access_cmd;
+	union iwl_nvm_access_resp *nvm_resp;
+	struct iwl_rx_packet *pkt;
+	struct iwl_host_cmd cmd = {
+		.id = NVM_ACCESS_CMD,
+		.flags = CMD_SYNC | CMD_WANT_SKB,
+		.data = { &nvm_access_cmd, },
+	};
+	int ret, bytes_read, offset_read;
+	u8 *resp_data;
+
+	memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd));
+
+	/* TODO: not sure family should be the decider, maybe FW version? */
+	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2),
+				       offset, length, section);
+		cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2);
+	} else {
+		iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1),
+				       offset, length);
+		cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1);
+	}
+
+	ret = iwl_mvm_send_cmd(mvm, &cmd);
+	if (ret)
+		return ret;
+
+	pkt = cmd.resp_pkt;
+	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n",
+			pkt->hdr.flags);
+		ret = -EIO;
+		goto exit;
+	}
+
+	/* Extract NVM response */
+	nvm_resp = (void *)pkt->data;
+	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		ret = le16_to_cpu(nvm_resp->ver2.status);
+		bytes_read = le16_to_cpu(nvm_resp->ver2.length);
+		offset_read = le16_to_cpu(nvm_resp->ver2.offset);
+		resp_data = nvm_resp->ver2.data;
+	} else {
+		ret = le16_to_cpu(nvm_resp->ver1.length) <= 0;
+		bytes_read = le16_to_cpu(nvm_resp->ver1.length);
+		offset_read = le16_to_cpu(nvm_resp->ver1.offset);
+		resp_data = nvm_resp->ver1.data;
+	}
+	if (ret) {
+		IWL_ERR(mvm,
+			"NVM access command failed with status %d (device: %s)\n",
+			ret, mvm->cfg->name);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (offset_read != offset) {
+		IWL_ERR(mvm, "NVM ACCESS response with invalid offset %d\n",
+			offset_read);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	/* Write data to NVM */
+	memcpy(data + offset, resp_data, bytes_read);
+	ret = bytes_read;
+
+exit:
+	iwl_free_resp(&cmd);
+	return ret;
+}
+
+/*
+ * Reads an NVM section completely.
+ * NICs prior to 7000 family doesn't have a real NVM, but just read
+ * section 0 which is the EEPROM. Because the EEPROM reading is unlimited
+ * by uCode, we need to manually check in this case that we don't
+ * overflow and try to read more than the EEPROM size.
+ * For 7000 family NICs, we supply the maximal size we can read, and
+ * the uCode fills the response with as much data as we can,
+ * without overflowing, so no check is needed.
+ */
+static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
+				u8 *data)
+{
+	u16 length, offset = 0;
+	int ret;
+	bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
+
+	length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024))
+		- sizeof(union iwl_nvm_access_cmd)
+		- sizeof(struct iwl_rx_packet);
+	/*
+	 * if length is greater than EEPROM size, truncate it because uCode
+	 * doesn't check it by itself, and exit the loop when reached.
+	 */
+	if (old_eeprom && length > mvm->cfg->base_params->eeprom_size)
+		length = mvm->cfg->base_params->eeprom_size;
+	ret = length;
+
+	/* Read the NVM until exhausted (reading less than requested) */
+	while (ret == length) {
+		ret = iwl_nvm_read_chunk(mvm, section, offset, length, data);
+		if (ret < 0) {
+			IWL_ERR(mvm,
+				"Cannot read NVM from section %d offset %d, length %d\n",
+				section, offset, length);
+			return ret;
+		}
+		offset += ret;
+		if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size)
+			break;
+	}
+
+	IWL_INFO(mvm, "NVM section %d read completed\n", section);
+	return offset;
+}
+
+static struct iwl_nvm_data *
+iwl_parse_nvm_sections(struct iwl_mvm *mvm)
+{
+	struct iwl_nvm_section *sections = mvm->nvm_sections;
+	const __le16 *hw, *sw, *calib;
+
+	/* Checking for required sections */
+	if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+	    !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) {
+		IWL_ERR(mvm, "Can't parse empty NVM sections\n");
+		return NULL;
+	}
+
+	if (WARN_ON(!mvm->cfg))
+		return NULL;
+
+	hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data;
+	sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
+	calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
+	return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib);
+}
+
+int iwl_nvm_init(struct iwl_mvm *mvm)
+{
+	int ret, i, section;
+	u8 *nvm_buffer, *temp;
+
+	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/* TODO: find correct NVM max size for a section */
+		nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
+				     GFP_KERNEL);
+		if (!nvm_buffer)
+			return -ENOMEM;
+		for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+			section = nvm_to_read[i];
+			/* we override the constness for initial read */
+			ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
+			if (ret < 0)
+				break;
+			temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
+			if (!temp) {
+				ret = -ENOMEM;
+				break;
+			}
+			mvm->nvm_sections[section].data = temp;
+			mvm->nvm_sections[section].length = ret;
+		}
+		kfree(nvm_buffer);
+		if (ret < 0)
+			return ret;
+	} else {
+		/* allocate eeprom */
+		mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size;
+		IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n",
+				 mvm->eeprom_blob_size);
+		mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL);
+		if (!mvm->eeprom_blob)
+			return -ENOMEM;
+
+		ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob);
+		if (ret != mvm->eeprom_blob_size) {
+			IWL_ERR(mvm, "Read partial NVM %d/%zd\n",
+				ret, mvm->eeprom_blob_size);
+			kfree(mvm->eeprom_blob);
+			mvm->eeprom_blob = NULL;
+			return -EINVAL;
+		}
+	}
+
+	ret = 0;
+	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+		mvm->nvm_data = iwl_parse_nvm_sections(mvm);
+	else
+		mvm->nvm_data =
+			iwl_parse_eeprom_data(mvm->trans->dev,
+					      mvm->cfg,
+					      mvm->eeprom_blob,
+					      mvm->eeprom_blob_size);
+
+	if (!mvm->nvm_data) {
+		kfree(mvm->eeprom_blob);
+		mvm->eeprom_blob = NULL;
+		ret = -ENOMEM;
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
new file mode 100644
index 0000000..aa59adf
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -0,0 +1,682 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <net/mac80211.h>
+
+#include "iwl-notif-wait.h"
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-fw.h"
+#include "iwl-debug.h"
+#include "iwl-drv.h"
+#include "iwl-modparams.h"
+#include "mvm.h"
+#include "iwl-phy-db.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-csr.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "rs.h"
+#include "fw-api-scan.h"
+#include "time-event.h"
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION	"The new Intel(R) wireless AGN driver for Linux"
+
+#define DRV_VERSION     IWLWIFI_VERSION
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct iwl_op_mode_ops iwl_mvm_ops;
+
+struct iwl_mvm_mod_params iwlmvm_mod_params = {
+	.power_scheme = IWL_POWER_SCHEME_BPS,
+	/* rest of fields are 0 by default */
+};
+
+module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, S_IRUGO);
+MODULE_PARM_DESC(init_dbg,
+		 "set to true to debug an ASSERT in INIT fw (default: false");
+module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO);
+MODULE_PARM_DESC(power_scheme,
+		 "power management scheme: 1-active, 2-balanced, 3-low power, default: 2");
+
+/*
+ * module init and exit functions
+ */
+static int __init iwl_mvm_init(void)
+{
+	int ret;
+
+	ret = iwl_mvm_rate_control_register();
+	if (ret) {
+		pr_err("Unable to register rate control algorithm: %d\n", ret);
+		return ret;
+	}
+
+	ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops);
+
+	if (ret) {
+		pr_err("Unable to register MVM op_mode: %d\n", ret);
+		iwl_mvm_rate_control_unregister();
+	}
+
+	return ret;
+}
+module_init(iwl_mvm_init);
+
+static void __exit iwl_mvm_exit(void)
+{
+	iwl_opmode_deregister("iwlmvm");
+	iwl_mvm_rate_control_unregister();
+}
+module_exit(iwl_mvm_exit);
+
+static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash;
+	u32 reg_val = 0;
+
+	/*
+	 * We can't upload the correct value to the INIT image
+	 * as we don't have nvm_data by that time.
+	 *
+	 * TODO: Figure out what we should do here
+	 */
+	if (mvm->nvm_data) {
+		radio_cfg_type = mvm->nvm_data->radio_cfg_type;
+		radio_cfg_step = mvm->nvm_data->radio_cfg_step;
+		radio_cfg_dash = mvm->nvm_data->radio_cfg_dash;
+	} else {
+		radio_cfg_type = 0;
+		radio_cfg_step = 0;
+		radio_cfg_dash = 0;
+	}
+
+	/* SKU control */
+	reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) <<
+				CSR_HW_IF_CONFIG_REG_POS_MAC_STEP;
+	reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) <<
+				CSR_HW_IF_CONFIG_REG_POS_MAC_DASH;
+
+	/* radio configuration */
+	reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE;
+	reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP;
+	reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
+
+	WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) &
+		 ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE);
+
+	/* silicon bits */
+	reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;
+	reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
+
+	iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG,
+				CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+				CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP |
+				CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
+				CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
+				CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH |
+				CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+				CSR_HW_IF_CONFIG_REG_BIT_MAC_SI,
+				reg_val);
+
+	IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
+		       radio_cfg_step, radio_cfg_dash);
+
+	/*
+	 * W/A : NIC is stuck in a reset state after Early PCIe power off
+	 * (PCIe power is lost before PERST# is asserted), causing ME FW
+	 * to lose ownership and not being able to obtain it back.
+	 */
+	iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,
+			       APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+			       ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+}
+
+struct iwl_rx_handlers {
+	u8 cmd_id;
+	bool async;
+	int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+		  struct iwl_device_cmd *cmd);
+};
+
+#define RX_HANDLER(_cmd_id, _fn, _async)	\
+	{ .cmd_id = _cmd_id , .fn = _fn , .async = _async }
+
+/*
+ * Handlers for fw notifications
+ * Convention: RX_HANDLER(CMD_NAME, iwl_mvm_rx_CMD_NAME
+ * This list should be in order of frequency for performance purposes.
+ *
+ * The handler can be SYNC - this means that it will be called in the Rx path
+ * which can't acquire mvm->mutex. If the handler needs to hold mvm->mutex (and
+ * only in this case!), it should be set as ASYNC. In that case, it will be
+ * called from a worker with mvm->mutex held.
+ */
+static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
+	RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false),
+	RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false),
+	RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),
+	RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false),
+	RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
+
+	RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
+	RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
+
+	RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
+	RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
+
+	RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
+};
+#undef RX_HANDLER
+#define CMD(x) [x] = #x
+
+static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
+	CMD(MVM_ALIVE),
+	CMD(REPLY_ERROR),
+	CMD(INIT_COMPLETE_NOTIF),
+	CMD(PHY_CONTEXT_CMD),
+	CMD(MGMT_MCAST_KEY),
+	CMD(TX_CMD),
+	CMD(TXPATH_FLUSH),
+	CMD(MAC_CONTEXT_CMD),
+	CMD(TIME_EVENT_CMD),
+	CMD(TIME_EVENT_NOTIFICATION),
+	CMD(BINDING_CONTEXT_CMD),
+	CMD(TIME_QUOTA_CMD),
+	CMD(RADIO_VERSION_NOTIFICATION),
+	CMD(SCAN_REQUEST_CMD),
+	CMD(SCAN_ABORT_CMD),
+	CMD(SCAN_START_NOTIFICATION),
+	CMD(SCAN_RESULTS_NOTIFICATION),
+	CMD(SCAN_COMPLETE_NOTIFICATION),
+	CMD(NVM_ACCESS_CMD),
+	CMD(PHY_CONFIGURATION_CMD),
+	CMD(CALIB_RES_NOTIF_PHY_DB),
+	CMD(SET_CALIB_DEFAULT_CMD),
+	CMD(CALIBRATION_COMPLETE_NOTIFICATION),
+	CMD(ADD_STA),
+	CMD(REMOVE_STA),
+	CMD(LQ_CMD),
+	CMD(SCAN_OFFLOAD_CONFIG_CMD),
+	CMD(SCAN_OFFLOAD_REQUEST_CMD),
+	CMD(SCAN_OFFLOAD_ABORT_CMD),
+	CMD(SCAN_OFFLOAD_COMPLETE),
+	CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
+	CMD(POWER_TABLE_CMD),
+	CMD(WEP_KEY),
+	CMD(REPLY_RX_PHY_CMD),
+	CMD(REPLY_RX_MPDU_CMD),
+	CMD(BEACON_TEMPLATE_CMD),
+	CMD(STATISTICS_NOTIFICATION),
+	CMD(TX_ANT_CONFIGURATION_CMD),
+	CMD(D3_CONFIG_CMD),
+	CMD(PROT_OFFLOAD_CONFIG_CMD),
+	CMD(OFFLOADS_QUERY_CMD),
+	CMD(REMOTE_WAKE_CONFIG_CMD),
+	CMD(WOWLAN_PATTERNS),
+	CMD(WOWLAN_CONFIGURATION),
+	CMD(WOWLAN_TSC_RSC_PARAM),
+	CMD(WOWLAN_TKIP_PARAM),
+	CMD(WOWLAN_KEK_KCK_MATERIAL),
+	CMD(WOWLAN_GET_STATUSES),
+	CMD(WOWLAN_TX_POWER_PER_DB),
+	CMD(NET_DETECT_CONFIG_CMD),
+	CMD(NET_DETECT_PROFILES_QUERY_CMD),
+	CMD(NET_DETECT_PROFILES_CMD),
+	CMD(NET_DETECT_HOTSPOTS_CMD),
+	CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
+};
+#undef CMD
+
+/* this forward declaration can avoid to export the function */
+static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
+
+static struct iwl_op_mode *
+iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
+		      const struct iwl_fw *fw, struct dentry *dbgfs_dir)
+{
+	struct ieee80211_hw *hw;
+	struct iwl_op_mode *op_mode;
+	struct iwl_mvm *mvm;
+	struct iwl_trans_config trans_cfg = {};
+	static const u8 no_reclaim_cmds[] = {
+		TX_CMD,
+	};
+	int err, scan_size;
+
+	switch (cfg->device_family) {
+	case IWL_DEVICE_FAMILY_6030:
+	case IWL_DEVICE_FAMILY_6005:
+	case IWL_DEVICE_FAMILY_7000:
+		break;
+	default:
+		IWL_ERR(trans, "Trying to load mvm on an unsupported device\n");
+		return NULL;
+	}
+
+	/********************************
+	 * 1. Allocating and configuring HW data
+	 ********************************/
+	hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) +
+				sizeof(struct iwl_mvm),
+				&iwl_mvm_hw_ops);
+	if (!hw)
+		return NULL;
+
+	op_mode = hw->priv;
+	op_mode->ops = &iwl_mvm_ops;
+	op_mode->trans = trans;
+
+	mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	mvm->dev = trans->dev;
+	mvm->trans = trans;
+	mvm->cfg = cfg;
+	mvm->fw = fw;
+	mvm->hw = hw;
+
+	mutex_init(&mvm->mutex);
+	spin_lock_init(&mvm->async_handlers_lock);
+	INIT_LIST_HEAD(&mvm->time_event_list);
+	INIT_LIST_HEAD(&mvm->async_handlers_list);
+	spin_lock_init(&mvm->time_event_lock);
+
+	INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
+	INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
+	INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
+
+	SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
+
+	/*
+	 * Populate the state variables that the transport layer needs
+	 * to know about.
+	 */
+	trans_cfg.op_mode = op_mode;
+	trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
+	trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
+	trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+
+	/* TODO: this should really be a TLV */
+	if (cfg->device_family == IWL_DEVICE_FAMILY_7000)
+		trans_cfg.bc_table_dword = true;
+
+	if (!iwlwifi_mod_params.wd_disable)
+		trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout;
+	else
+		trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
+
+	trans_cfg.command_names = iwl_mvm_cmd_strings;
+
+	trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
+	trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO;
+
+	snprintf(mvm->hw->wiphy->fw_version,
+		 sizeof(mvm->hw->wiphy->fw_version),
+		 "%s", fw->fw_version);
+
+	/* Configure transport layer */
+	iwl_trans_configure(mvm->trans, &trans_cfg);
+
+	trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
+	trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
+
+	/* set up notification wait support */
+	iwl_notification_wait_init(&mvm->notif_wait);
+
+	/* Init phy db */
+	mvm->phy_db = iwl_phy_db_init(trans);
+	if (!mvm->phy_db) {
+		IWL_ERR(mvm, "Cannot init phy_db\n");
+		goto out_free;
+	}
+
+	IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
+		 mvm->cfg->name, mvm->trans->hw_rev);
+
+	err = iwl_trans_start_hw(mvm->trans);
+	if (err)
+		goto out_free;
+
+	mutex_lock(&mvm->mutex);
+	err = iwl_run_init_mvm_ucode(mvm, true);
+	mutex_unlock(&mvm->mutex);
+	if (err && !iwlmvm_mod_params.init_dbg) {
+		IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
+		goto out_free;
+	}
+
+	/* Stop the hw after the ALIVE and NVM has been read */
+	if (!iwlmvm_mod_params.init_dbg)
+		iwl_trans_stop_hw(mvm->trans, false);
+
+	scan_size = sizeof(struct iwl_scan_cmd) +
+		mvm->fw->ucode_capa.max_probe_length +
+		(MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel));
+	mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
+	if (!mvm->scan_cmd)
+		goto out_free;
+
+	err = iwl_mvm_mac_setup_register(mvm);
+	if (err)
+		goto out_free;
+
+	err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir);
+	if (err)
+		goto out_unregister;
+
+	return op_mode;
+
+ out_unregister:
+	ieee80211_unregister_hw(mvm->hw);
+ out_free:
+	iwl_phy_db_free(mvm->phy_db);
+	kfree(mvm->scan_cmd);
+	kfree(mvm->eeprom_blob);
+	iwl_trans_stop_hw(trans, true);
+	ieee80211_free_hw(mvm->hw);
+	return NULL;
+}
+
+static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	int i;
+
+	iwl_mvm_leds_exit(mvm);
+
+	ieee80211_unregister_hw(mvm->hw);
+
+	kfree(mvm->scan_cmd);
+
+	iwl_trans_stop_hw(mvm->trans, true);
+
+	iwl_phy_db_free(mvm->phy_db);
+	mvm->phy_db = NULL;
+
+	kfree(mvm->eeprom_blob);
+	iwl_free_nvm_data(mvm->nvm_data);
+	for (i = 0; i < NVM_NUM_OF_SECTIONS; i++)
+		kfree(mvm->nvm_sections[i].data);
+
+	ieee80211_free_hw(mvm->hw);
+}
+
+struct iwl_async_handler_entry {
+	struct list_head list;
+	struct iwl_rx_cmd_buffer rxb;
+	int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+		  struct iwl_device_cmd *cmd);
+};
+
+void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm)
+{
+	struct iwl_async_handler_entry *entry, *tmp;
+
+	spin_lock_bh(&mvm->async_handlers_lock);
+	list_for_each_entry_safe(entry, tmp, &mvm->async_handlers_list, list) {
+		iwl_free_rxb(&entry->rxb);
+		list_del(&entry->list);
+		kfree(entry);
+	}
+	spin_unlock_bh(&mvm->async_handlers_lock);
+}
+
+static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
+{
+	struct iwl_mvm *mvm =
+		container_of(wk, struct iwl_mvm, async_handlers_wk);
+	struct iwl_async_handler_entry *entry, *tmp;
+	struct list_head local_list;
+
+	INIT_LIST_HEAD(&local_list);
+
+	/* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */
+	mutex_lock(&mvm->mutex);
+
+	/*
+	 * Sync with Rx path with a lock. Remove all the entries from this list,
+	 * add them to a local one (lock free), and then handle them.
+	 */
+	spin_lock_bh(&mvm->async_handlers_lock);
+	list_splice_init(&mvm->async_handlers_list, &local_list);
+	spin_unlock_bh(&mvm->async_handlers_lock);
+
+	list_for_each_entry_safe(entry, tmp, &local_list, list) {
+		if (entry->fn(mvm, &entry->rxb, NULL))
+			IWL_WARN(mvm,
+				 "returned value from ASYNC handlers are ignored\n");
+		iwl_free_rxb(&entry->rxb);
+		list_del(&entry->list);
+		kfree(entry);
+	}
+	mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,
+			       struct iwl_rx_cmd_buffer *rxb,
+			       struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	u8 i;
+
+	/*
+	 * Do the notification wait before RX handlers so
+	 * even if the RX handler consumes the RXB we have
+	 * access to it in the notification wait entry.
+	 */
+	iwl_notification_wait_notify(&mvm->notif_wait, pkt);
+
+	for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) {
+		const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i];
+		struct iwl_async_handler_entry *entry;
+
+		if (rx_h->cmd_id != pkt->hdr.cmd)
+			continue;
+
+		if (!rx_h->async)
+			return rx_h->fn(mvm, rxb, cmd);
+
+		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+		/* we can't do much... */
+		if (!entry)
+			return 0;
+
+		entry->rxb._page = rxb_steal_page(rxb);
+		entry->rxb._offset = rxb->_offset;
+		entry->rxb._rx_page_order = rxb->_rx_page_order;
+		entry->fn = rx_h->fn;
+		spin_lock(&mvm->async_handlers_lock);
+		list_add_tail(&entry->list, &mvm->async_handlers_list);
+		spin_unlock(&mvm->async_handlers_lock);
+		schedule_work(&mvm->async_handlers_wk);
+		break;
+	}
+
+	return 0;
+}
+
+static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	int mq = mvm->queue_to_mac80211[queue];
+
+	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+		return;
+
+	if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) {
+		IWL_DEBUG_TX_QUEUES(mvm,
+				    "queue %d (mac80211 %d) already stopped\n",
+				    queue, mq);
+		return;
+	}
+
+	set_bit(mq, &mvm->transport_queue_stop);
+	ieee80211_stop_queue(mvm->hw, mq);
+}
+
+static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	int mq = mvm->queue_to_mac80211[queue];
+
+	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+		return;
+
+	if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) {
+		IWL_DEBUG_TX_QUEUES(mvm,
+				    "queue %d (mac80211 %d) already awake\n",
+				    queue, mq);
+		return;
+	}
+
+	clear_bit(mq, &mvm->transport_queue_stop);
+
+	ieee80211_wake_queue(mvm->hw, mq);
+}
+
+static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+	if (state)
+		set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
+	else
+		clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
+
+	wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state);
+}
+
+static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	struct ieee80211_tx_info *info;
+
+	info = IEEE80211_SKB_CB(skb);
+	iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+	ieee80211_free_txskb(mvm->hw, skb);
+}
+
+static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
+{
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+	iwl_mvm_dump_nic_error_log(mvm);
+
+	iwl_abort_notification_waits(&mvm->notif_wait);
+
+	/*
+	 * If we're restarting already, don't cycle restarts.
+	 * If INIT fw asserted, it will likely fail again.
+	 * If WoWLAN fw asserted, don't restart either, mac80211
+	 * can't recover this since we're already half suspended.
+	 */
+	if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+		IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n");
+	} else if (mvm->cur_ucode == IWL_UCODE_REGULAR &&
+		   iwlwifi_mod_params.restart_fw) {
+		/*
+		 * This is a bit racy, but worst case we tell mac80211 about
+		 * a stopped/aborted (sched) scan when that was already done
+		 * which is not a problem. It is necessary to abort any scan
+		 * here because mac80211 requires having the scan cleared
+		 * before restarting.
+		 * We'll reset the scan_status to NONE in restart cleanup in
+		 * the next start() call from mac80211.
+		 */
+		switch (mvm->scan_status) {
+		case IWL_MVM_SCAN_NONE:
+			break;
+		case IWL_MVM_SCAN_OS:
+			ieee80211_scan_completed(mvm->hw, true);
+			break;
+		}
+
+		ieee80211_restart_hw(mvm->hw);
+	}
+}
+
+static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
+{
+	WARN_ON(1);
+}
+
+static const struct iwl_op_mode_ops iwl_mvm_ops = {
+	.start = iwl_op_mode_mvm_start,
+	.stop = iwl_op_mode_mvm_stop,
+	.rx = iwl_mvm_rx_dispatch,
+	.queue_full = iwl_mvm_stop_sw_queue,
+	.queue_not_full = iwl_mvm_wake_sw_queue,
+	.hw_rf_kill = iwl_mvm_set_hw_rfkill_state,
+	.free_skb = iwl_mvm_free_skb,
+	.nic_error = iwl_mvm_nic_error,
+	.cmd_queue_full = iwl_mvm_cmd_queue_full,
+	.nic_config = iwl_mvm_nic_config,
+};
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
new file mode 100644
index 0000000..b428448
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+#include "fw-api.h"
+#include "mvm.h"
+
+/* Maps the driver specific channel width definition to the the fw values */
+static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef)
+{
+	switch (chandef->width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+	case NL80211_CHAN_WIDTH_20:
+		return PHY_VHT_CHANNEL_MODE20;
+	case NL80211_CHAN_WIDTH_40:
+		return PHY_VHT_CHANNEL_MODE40;
+	case NL80211_CHAN_WIDTH_80:
+		return PHY_VHT_CHANNEL_MODE80;
+	case NL80211_CHAN_WIDTH_160:
+		return PHY_VHT_CHANNEL_MODE160;
+	default:
+		WARN(1, "Invalid channel width=%u", chandef->width);
+		return PHY_VHT_CHANNEL_MODE20;
+	}
+}
+
+/*
+ * Maps the driver specific control channel position (relative to the center
+ * freq) definitions to the the fw values
+ */
+static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef)
+{
+	switch (chandef->chan->center_freq - chandef->center_freq1) {
+	case -70:
+		return PHY_VHT_CTRL_POS_4_BELOW;
+	case -50:
+		return PHY_VHT_CTRL_POS_3_BELOW;
+	case -30:
+		return PHY_VHT_CTRL_POS_2_BELOW;
+	case -10:
+		return PHY_VHT_CTRL_POS_1_BELOW;
+	case  10:
+		return PHY_VHT_CTRL_POS_1_ABOVE;
+	case  30:
+		return PHY_VHT_CTRL_POS_2_ABOVE;
+	case  50:
+		return PHY_VHT_CTRL_POS_3_ABOVE;
+	case  70:
+		return PHY_VHT_CTRL_POS_4_ABOVE;
+	default:
+		WARN(1, "Invalid channel definition");
+	case 0:
+		/*
+		 * The FW is expected to check the control channel position only
+		 * when in HT/VHT and the channel width is not 20MHz. Return
+		 * this value as the default one.
+		 */
+		return PHY_VHT_CTRL_POS_1_BELOW;
+	}
+}
+
+/*
+ * Construct the generic fields of the PHY context command
+ */
+static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt,
+				     struct iwl_phy_context_cmd *cmd,
+				     u32 action, u32 apply_time)
+{
+	memset(cmd, 0, sizeof(struct iwl_phy_context_cmd));
+
+	cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(ctxt->id,
+							    ctxt->color));
+	cmd->action = cpu_to_le32(action);
+	cmd->apply_time = cpu_to_le32(apply_time);
+}
+
+/*
+ * Add the phy configuration to the PHY context command
+ */
+static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
+				      struct iwl_phy_context_cmd *cmd,
+				      struct cfg80211_chan_def *chandef,
+				      u8 chains_static, u8 chains_dynamic)
+{
+	u8 valid_rx_chains, active_cnt, idle_cnt;
+
+	/* Set the channel info data */
+	cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ?
+	      PHY_BAND_24 : PHY_BAND_5);
+
+	cmd->ci.channel = chandef->chan->hw_value;
+	cmd->ci.width = iwl_mvm_get_channel_width(chandef);
+	cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef);
+
+	/* Set rx the chains */
+
+	/* TODO:
+	 * Need to add on chain noise calibration limitations, and
+	 * BT coex considerations.
+	 */
+	valid_rx_chains = mvm->nvm_data->valid_rx_ant;
+	idle_cnt = chains_static;
+	active_cnt = chains_dynamic;
+
+	cmd->rxchain_info = cpu_to_le32(valid_rx_chains <<
+					PHY_RX_CHAIN_VALID_POS);
+	cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
+	cmd->rxchain_info |= cpu_to_le32(active_cnt <<
+					 PHY_RX_CHAIN_MIMO_CNT_POS);
+
+	cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant);
+}
+
+/*
+ * Send a command to apply the current phy configuration. The command is send
+ * only if something in the configuration changed: in case that this is the
+ * first time that the phy configuration is applied or in case that the phy
+ * configuration changed from the previous apply.
+ */
+static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
+				  struct iwl_mvm_phy_ctxt *ctxt,
+				  struct cfg80211_chan_def *chandef,
+				  u8 chains_static, u8 chains_dynamic,
+				  u32 action, u32 apply_time)
+{
+	struct iwl_phy_context_cmd cmd;
+	int ret;
+
+	/* Set the command header fields */
+	iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action, apply_time);
+
+	/* Set the command data */
+	iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef,
+				  chains_static, chains_dynamic);
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC,
+				   sizeof(struct iwl_phy_context_cmd),
+				   &cmd);
+	if (ret)
+		IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret);
+	return ret;
+}
+
+
+struct phy_ctx_used_data {
+	unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)];
+};
+
+static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw,
+				      struct ieee80211_chanctx_conf *ctx,
+				      void *_data)
+{
+	struct phy_ctx_used_data *data = _data;
+	struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+
+	__set_bit(phy_ctxt->id, data->used);
+}
+
+/*
+ * Send a command to add a PHY context based on the current HW configuration.
+ */
+int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+			 struct cfg80211_chan_def *chandef,
+			 u8 chains_static, u8 chains_dynamic)
+{
+	struct phy_ctx_used_data data = {
+		.used = { },
+	};
+
+	/*
+	 * If this is a regular PHY context (not the ROC one)
+	 * skip the ROC PHY context's ID.
+	 */
+	if (ctxt != &mvm->phy_ctxt_roc)
+		__set_bit(mvm->phy_ctxt_roc.id, data.used);
+
+	lockdep_assert_held(&mvm->mutex);
+	ctxt->color++;
+
+	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+		ieee80211_iter_chan_contexts_atomic(
+			mvm->hw, iwl_mvm_phy_ctx_used_iter, &data);
+
+		ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX);
+		if (WARN_ONCE(ctxt->id == NUM_PHY_CTX,
+			      "Failed to init PHY context - no free ID!\n"))
+			return -EIO;
+	}
+
+	ctxt->channel = chandef->chan;
+	return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
+				      chains_static, chains_dynamic,
+				      FW_CTXT_ACTION_ADD, 0);
+}
+
+/*
+ * Send a command to modify the PHY context based on the current HW
+ * configuration. Note that the function does not check that the configuration
+ * changed.
+ */
+int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+			     struct cfg80211_chan_def *chandef,
+			     u8 chains_static, u8 chains_dynamic)
+{
+	lockdep_assert_held(&mvm->mutex);
+
+	ctxt->channel = chandef->chan;
+	return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
+				      chains_static, chains_dynamic,
+				      FW_CTXT_ACTION_MODIFY, 0);
+}
+
+/*
+ * Send a command to the FW to remove the given phy context.
+ * Once the command is sent, regardless of success or failure, the context is
+ * marked as invalid
+ */
+void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
+{
+	struct iwl_phy_context_cmd cmd;
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0);
+	ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC,
+				   sizeof(struct iwl_phy_context_cmd),
+				   &cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n",
+			ctxt->id);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
new file mode 100644
index 0000000..5a92a49
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -0,0 +1,207 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-debug.h"
+#include "mvm.h"
+#include "iwl-modparams.h"
+#include "fw-api-power.h"
+
+#define POWER_KEEP_ALIVE_PERIOD_SEC    25
+
+static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+				struct iwl_powertable_cmd *cmd)
+{
+	struct ieee80211_hw *hw = mvm->hw;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_channel *chan;
+	int dtimper, dtimper_msec;
+	int keep_alive;
+	bool radar_detect = false;
+
+	cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+							    mvmvif->color));
+	cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);
+
+	if ((!vif->bss_conf.ps) ||
+	    (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM))
+		return;
+
+	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
+
+	dtimper = hw->conf.ps_dtim_period ?: 1;
+
+	/* Check if radar detection is required on current channel */
+	rcu_read_lock();
+	chanctx_conf = rcu_dereference(vif->chanctx_conf);
+	WARN_ON(!chanctx_conf);
+	if (chanctx_conf) {
+		chan = chanctx_conf->def.chan;
+		radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
+	}
+	rcu_read_unlock();
+
+	/* Check skip over DTIM conditions */
+	if (!radar_detect && (dtimper <= 10) &&
+	    (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) {
+		cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK);
+		cmd->num_skip_dtim = 2;
+	}
+
+	/* Check that keep alive period is at least 3 * DTIM */
+	dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+	keep_alive = max_t(int, 3 * dtimper_msec,
+			   MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC);
+	keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
+
+	cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
+
+	if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) {
+		/* TODO: Also for D3 (device sleep / WoWLAN) */
+		cmd->rx_data_timeout = cpu_to_le32(10);
+		cmd->tx_data_timeout = cpu_to_le32(10);
+	} else {
+		cmd->rx_data_timeout = cpu_to_le32(50);
+		cmd->tx_data_timeout = cpu_to_le32(50);
+	}
+}
+
+int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_powertable_cmd cmd = {};
+
+	if (!iwlwifi_mod_params.power_save) {
+		IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
+		return 0;
+	}
+
+	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+		return 0;
+
+	iwl_power_build_cmd(mvm, vif, &cmd);
+
+	IWL_DEBUG_POWER(mvm,
+			"Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
+			cmd.id_and_color, iwlmvm_mod_params.power_scheme,
+			le16_to_cpu(cmd.flags));
+
+	if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
+		IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",
+				le16_to_cpu(cmd.keep_alive_seconds));
+		IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
+				le32_to_cpu(cmd.rx_data_timeout));
+		IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
+				le32_to_cpu(cmd.tx_data_timeout));
+		IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",
+				le32_to_cpu(cmd.rx_data_timeout_uapsd));
+		IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
+				le32_to_cpu(cmd.tx_data_timeout_uapsd));
+		IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
+				cmd.lprx_rssi_threshold);
+		IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim);
+	}
+
+	return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
+				    sizeof(cmd), &cmd);
+}
+
+int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_powertable_cmd cmd = {};
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	if (!iwlwifi_mod_params.power_save) {
+		IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
+		return 0;
+	}
+
+	if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+		return 0;
+
+	cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+							    mvmvif->color));
+	cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);
+
+	IWL_DEBUG_POWER(mvm,
+			"Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
+			cmd.id_and_color, iwlmvm_mod_params.power_scheme,
+			le16_to_cpu(cmd.flags));
+
+	return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
+				    sizeof(cmd), &cmd);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			  struct iwl_powertable_cmd *cmd)
+{
+	iwl_power_build_cmd(mvm, vif, cmd);
+}
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
new file mode 100644
index 0000000..9256284
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+#include "fw-api.h"
+#include "mvm.h"
+
+struct iwl_mvm_quota_iterator_data {
+	int n_interfaces[MAX_BINDINGS];
+	int colors[MAX_BINDINGS];
+	struct ieee80211_vif *new_vif;
+};
+
+static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
+				   struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_quota_iterator_data *data = _data;
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	u16 id;
+
+	/*
+	 * We'll account for the new interface (if any) below,
+	 * skip it here in case we're not called from within
+	 * the add_interface callback (otherwise it won't show
+	 * up in iteration)
+	 */
+	if (vif == data->new_vif)
+		return;
+
+	if (!mvmvif->phy_ctxt)
+		return;
+
+	/* currently, PHY ID == binding ID */
+	id = mvmvif->phy_ctxt->id;
+
+	/* need at least one binding per PHY */
+	BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);
+
+	if (WARN_ON_ONCE(id >= MAX_BINDINGS))
+		return;
+
+	if (data->colors[id] < 0)
+		data->colors[id] = mvmvif->phy_ctxt->color;
+	else
+		WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		if (vif->bss_conf.assoc)
+			data->n_interfaces[id]++;
+		break;
+	case NL80211_IFTYPE_AP:
+		if (mvmvif->ap_active)
+			data->n_interfaces[id]++;
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		data->n_interfaces[id]++;
+		break;
+	case NL80211_IFTYPE_P2P_DEVICE:
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		if (vif->bss_conf.ibss_joined)
+			data->n_interfaces[id]++;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		break;
+	}
+}
+
+int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
+{
+	struct iwl_time_quota_cmd cmd;
+	int i, idx, ret, num_active_bindings, quota, quota_rem;
+	struct iwl_mvm_quota_iterator_data data = {
+		.n_interfaces = {},
+		.colors = { -1, -1, -1, -1 },
+		.new_vif = newvif,
+	};
+
+	/* update all upon completion */
+	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+		return 0;
+
+	BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1);
+
+	lockdep_assert_held(&mvm->mutex);
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ieee80211_iterate_active_interfaces_atomic(
+		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+		iwl_mvm_quota_iterator, &data);
+	if (newvif) {
+		data.new_vif = NULL;
+		iwl_mvm_quota_iterator(&data, newvif->addr, newvif);
+	}
+
+	/*
+	 * The FW's scheduling session consists of
+	 * IWL_MVM_MAX_QUOTA fragments. Divide these fragments
+	 * equally between all the bindings that require quota
+	 */
+	num_active_bindings = 0;
+	for (i = 0; i < MAX_BINDINGS; i++) {
+		cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
+		if (data.n_interfaces[i] > 0)
+			num_active_bindings++;
+	}
+
+	if (!num_active_bindings)
+		goto send_cmd;
+
+	quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
+	quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
+
+	for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
+		if (data.n_interfaces[i] <= 0)
+			continue;
+
+		cmd.quotas[idx].id_and_color =
+			cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
+		cmd.quotas[idx].quota = cpu_to_le32(quota);
+		cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
+		idx++;
+	}
+
+	/* Give the remainder of the session to the first binding */
+	le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
+
+send_cmd:
+	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
+				   sizeof(cmd), &cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
new file mode 100644
index 0000000..56b636d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -0,0 +1,3080 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+#include "rs.h"
+#include "fw-api.h"
+#include "sta.h"
+#include "iwl-op-mode.h"
+#include "mvm.h"
+
+#define RS_NAME "iwl-mvm-rs"
+
+#define NUM_TRY_BEFORE_ANT_TOGGLE 1
+#define IWL_NUMBER_TRY      1
+#define IWL_HT_NUMBER_TRY   3
+
+#define IWL_RATE_MAX_WINDOW		62	/* # tx in history window */
+#define IWL_RATE_MIN_FAILURE_TH		6	/* min failures to calc tpt */
+#define IWL_RATE_MIN_SUCCESS_TH		8	/* min successes to calc tpt */
+
+/* max allowed rate miss before sync LQ cmd */
+#define IWL_MISSED_RATE_MAX		15
+/* max time to accum history 2 seconds */
+#define IWL_RATE_SCALE_FLUSH_INTVL   (3*HZ)
+
+static u8 rs_ht_to_legacy[] = {
+	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+static const u8 ant_toggle_lookup[] = {
+	/*ANT_NONE -> */ ANT_NONE,
+	/*ANT_A    -> */ ANT_B,
+	/*ANT_B    -> */ ANT_C,
+	/*ANT_AB   -> */ ANT_BC,
+	/*ANT_C    -> */ ANT_A,
+	/*ANT_AC   -> */ ANT_AB,
+	/*ANT_BC   -> */ ANT_AC,
+	/*ANT_ABC  -> */ ANT_ABC,
+};
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
+	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
+				    IWL_RATE_SISO_##s##M_PLCP, \
+				    IWL_RATE_MIMO2_##s##M_PLCP,\
+				    IWL_RATE_MIMO3_##s##M_PLCP,\
+				    IWL_RATE_##r##M_IEEE,      \
+				    IWL_RATE_##ip##M_INDEX,    \
+				    IWL_RATE_##in##M_INDEX,    \
+				    IWL_RATE_##rp##M_INDEX,    \
+				    IWL_RATE_##rn##M_INDEX,    \
+				    IWL_RATE_##pp##M_INDEX,    \
+				    IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
+	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
+	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
+	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
+	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
+	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
+	IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
+	IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
+	IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+	/* FIXME:RS:          ^^    should be INV (legacy) */
+};
+
+static inline u8 rs_extract_rate(u32 rate_n_flags)
+{
+	/* also works for HT because bits 7:6 are zero there */
+	return (u8)(rate_n_flags & RATE_LEGACY_RATE_MSK);
+}
+
+static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
+{
+	int idx = 0;
+
+	/* HT rate format */
+	if (rate_n_flags & RATE_MCS_HT_MSK) {
+		idx = rs_extract_rate(rate_n_flags);
+
+		if (idx >= IWL_RATE_MIMO3_6M_PLCP)
+			idx = idx - IWL_RATE_MIMO3_6M_PLCP;
+		else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+			idx = idx - IWL_RATE_MIMO2_6M_PLCP;
+
+		idx += IWL_FIRST_OFDM_RATE;
+		/* skip 9M not supported in ht*/
+		if (idx >= IWL_RATE_9M_INDEX)
+			idx += 1;
+		if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
+			return idx;
+
+	/* legacy rate format, search for match in table */
+	} else {
+		for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+			if (iwl_rates[idx].plcp ==
+					rs_extract_rate(rate_n_flags))
+				return idx;
+	}
+
+	return -1;
+}
+
+static void rs_rate_scale_perform(struct iwl_mvm *mvm,
+				   struct sk_buff *skb,
+				   struct ieee80211_sta *sta,
+				   struct iwl_lq_sta *lq_sta);
+static void rs_fill_link_cmd(struct iwl_mvm *mvm,
+			     struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+			     u32 *rate_n_flags, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+			     u32 *rate_n_flags, int index)
+{}
+#endif
+
+/**
+ * The following tables contain the expected throughput metrics for all rates
+ *
+ *	1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ *
+ * where invalid entries are zeros.
+ *
+ * CCK rates are only valid in legacy table and will only be used in G
+ * (2.4 GHz) band.
+ */
+
+static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+	7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
+};
+
+static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0, 42, 0,  76, 102, 124, 159, 183, 193, 202}, /* Norm */
+	{0, 0, 0, 0, 46, 0,  82, 110, 132, 168, 192, 202, 210}, /* SGI */
+	{0, 0, 0, 0, 47, 0,  91, 133, 171, 242, 305, 334, 362}, /* AGG */
+	{0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0,  77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
+	{0, 0, 0, 0,  83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
+	{0, 0, 0, 0,  94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
+	{0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0,  74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
+	{0, 0, 0, 0,  81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
+	{0, 0, 0, 0,  89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
+	{0, 0, 0, 0,  97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
+};
+
+static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
+	{0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
+	{0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
+	{0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0,  99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
+	{0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
+	{0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
+	{0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
+	{0, 0, 0, 0, 152, 0, 211, 239, 255, 279,  290,  294,  297}, /* Norm */
+	{0, 0, 0, 0, 160, 0, 219, 245, 261, 284,  294,  297,  300}, /* SGI */
+	{0, 0, 0, 0, 254, 0, 443, 584, 695, 868,  984, 1030, 1070}, /* AGG */
+	{0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
+};
+
+/* mbps, mcs */
+static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
+	{  "1", "BPSK DSSS"},
+	{  "2", "QPSK DSSS"},
+	{"5.5", "BPSK CCK"},
+	{ "11", "QPSK CCK"},
+	{  "6", "BPSK 1/2"},
+	{  "9", "BPSK 1/2"},
+	{ "12", "QPSK 1/2"},
+	{ "18", "QPSK 3/4"},
+	{ "24", "16QAM 1/2"},
+	{ "36", "16QAM 3/4"},
+	{ "48", "64QAM 2/3"},
+	{ "54", "64QAM 3/4"},
+	{ "60", "64QAM 5/6"},
+};
+
+#define MCS_INDEX_PER_STREAM	(8)
+
+static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+	window->data = 0;
+	window->success_counter = 0;
+	window->success_ratio = IWL_INVALID_VALUE;
+	window->counter = 0;
+	window->average_tpt = IWL_INVALID_VALUE;
+	window->stamp = 0;
+}
+
+static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
+{
+	return (ant_type & valid_antenna) == ant_type;
+}
+
+/*
+ *	removes the old data from the statistics. All data that is older than
+ *	TID_MAX_TIME_DIFF, will be deleted.
+ */
+static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
+{
+	/* The oldest age we want to keep */
+	u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
+
+	while (tl->queue_count &&
+	       (tl->time_stamp < oldest_time)) {
+		tl->total -= tl->packet_count[tl->head];
+		tl->packet_count[tl->head] = 0;
+		tl->time_stamp += TID_QUEUE_CELL_SPACING;
+		tl->queue_count--;
+		tl->head++;
+		if (tl->head >= TID_QUEUE_MAX_SIZE)
+			tl->head = 0;
+	}
+}
+
+/*
+ *	increment traffic load value for tid and also remove
+ *	any old values if passed the certain time period
+ */
+static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
+			   struct ieee80211_hdr *hdr)
+{
+	u32 curr_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	struct iwl_traffic_load *tl = NULL;
+	u8 tid;
+
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		tid = qc[0] & 0xf;
+	} else {
+		return IWL_MAX_TID_COUNT;
+	}
+
+	if (unlikely(tid >= IWL_MAX_TID_COUNT))
+		return IWL_MAX_TID_COUNT;
+
+	tl = &lq_data->load[tid];
+
+	curr_time -= curr_time % TID_ROUND_VALUE;
+
+	/* Happens only for the first packet. Initialize the data */
+	if (!(tl->queue_count)) {
+		tl->total = 1;
+		tl->time_stamp = curr_time;
+		tl->queue_count = 1;
+		tl->head = 0;
+		tl->packet_count[0] = 1;
+		return IWL_MAX_TID_COUNT;
+	}
+
+	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	/* The history is too long: remove data that is older than */
+	/* TID_MAX_TIME_DIFF */
+	if (index >= TID_QUEUE_MAX_SIZE)
+		rs_tl_rm_old_stats(tl, curr_time);
+
+	index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
+	tl->packet_count[index] = tl->packet_count[index] + 1;
+	tl->total = tl->total + 1;
+
+	if ((index + 1) > tl->queue_count)
+		tl->queue_count = index + 1;
+
+	return tid;
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
+static void rs_program_fix_rate(struct iwl_mvm *mvm,
+				struct iwl_lq_sta *lq_sta)
+{
+	lq_sta->active_legacy_rate = 0x0FFF;	/* 1 - 54 MBits, includes CCK */
+	lq_sta->active_siso_rate   = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+	lq_sta->active_mimo2_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+	lq_sta->active_mimo3_rate  = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+
+	IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n",
+		       lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+
+	if (lq_sta->dbg_fixed_rate) {
+		rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
+		iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
+	}
+}
+#endif
+
+/*
+	get the traffic load value for tid
+*/
+static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
+{
+	u32 curr_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	struct iwl_traffic_load *tl = NULL;
+
+	if (tid >= IWL_MAX_TID_COUNT)
+		return 0;
+
+	tl = &(lq_data->load[tid]);
+
+	curr_time -= curr_time % TID_ROUND_VALUE;
+
+	if (!(tl->queue_count))
+		return 0;
+
+	time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	/* The history is too long: remove data that is older than */
+	/* TID_MAX_TIME_DIFF */
+	if (index >= TID_QUEUE_MAX_SIZE)
+		rs_tl_rm_old_stats(tl, curr_time);
+
+	return tl->total;
+}
+
+static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
+				      struct iwl_lq_sta *lq_data, u8 tid,
+				      struct ieee80211_sta *sta)
+{
+	int ret = -EAGAIN;
+	u32 load;
+
+	load = rs_tl_get_load(lq_data, tid);
+
+	if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
+		IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n",
+			     sta->addr, tid);
+		ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
+		if (ret == -EAGAIN) {
+			/*
+			 * driver and mac80211 is out of sync
+			 * this might be cause by reloading firmware
+			 * stop the tx ba session here
+			 */
+			IWL_ERR(mvm, "Fail start Tx agg on tid: %d\n",
+				tid);
+			ieee80211_stop_tx_ba_session(sta, tid);
+		}
+	} else {
+		IWL_DEBUG_HT(mvm,
+			     "Aggregation not enabled for tid %d because load = %u\n",
+			     tid, load);
+	}
+	return ret;
+}
+
+static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, u8 tid,
+			      struct iwl_lq_sta *lq_data,
+			      struct ieee80211_sta *sta)
+{
+	if (tid < IWL_MAX_TID_COUNT)
+		rs_tl_turn_on_agg_for_tid(mvm, lq_data, tid, sta);
+	else
+		IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n",
+			tid, IWL_MAX_TID_COUNT);
+}
+
+static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+{
+	return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+	       !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+	       !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
+}
+
+/*
+ * Static function to get the expected throughput from an iwl_scale_tbl_info
+ * that wraps a NULL pointer check
+ */
+static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
+{
+	if (tbl->expected_tpt)
+		return tbl->expected_tpt[rs_index];
+	return 0;
+}
+
+/**
+ * rs_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 62 packets transmitted
+ * at this rate.  window->data contains the bitmask of successful
+ * packets.
+ */
+static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+			      int scale_index, int attempts, int successes)
+{
+	struct iwl_rate_scale_data *window = NULL;
+	static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
+	s32 fail_count, tpt;
+
+	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+		return -EINVAL;
+
+	/* Select window for current tx bit rate */
+	window = &(tbl->win[scale_index]);
+
+	/* Get expected throughput */
+	tpt = get_expected_tpt(tbl, scale_index);
+
+	/*
+	 * Keep track of only the latest 62 tx frame attempts in this rate's
+	 * history window; anything older isn't really relevant any more.
+	 * If we have filled up the sliding window, drop the oldest attempt;
+	 * if the oldest attempt (highest bit in bitmap) shows "success",
+	 * subtract "1" from the success counter (this is the main reason
+	 * we keep these bitmaps!).
+	 */
+	while (attempts > 0) {
+		if (window->counter >= IWL_RATE_MAX_WINDOW) {
+			/* remove earliest */
+			window->counter = IWL_RATE_MAX_WINDOW - 1;
+
+			if (window->data & mask) {
+				window->data &= ~mask;
+				window->success_counter--;
+			}
+		}
+
+		/* Increment frames-attempted counter */
+		window->counter++;
+
+		/* Shift bitmap by one frame to throw away oldest history */
+		window->data <<= 1;
+
+		/* Mark the most recent #successes attempts as successful */
+		if (successes > 0) {
+			window->success_counter++;
+			window->data |= 0x1;
+			successes--;
+		}
+
+		attempts--;
+	}
+
+	/* Calculate current success ratio, avoid divide-by-0! */
+	if (window->counter > 0)
+		window->success_ratio = 128 * (100 * window->success_counter)
+					/ window->counter;
+	else
+		window->success_ratio = IWL_INVALID_VALUE;
+
+	fail_count = window->counter - window->success_counter;
+
+	/* Calculate average throughput, if we have enough history. */
+	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+	else
+		window->average_tpt = IWL_INVALID_VALUE;
+
+	/* Tag this window as having been updated */
+	window->stamp = jiffies;
+
+	return 0;
+}
+
+/*
+ * Fill uCode API rate_n_flags field, based on "search" or "active" table.
+ */
+/* FIXME:RS:remove this function and put the flags statically in the table */
+static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm,
+				 struct iwl_scale_tbl_info *tbl,
+				 int index, u8 use_green)
+{
+	u32 rate_n_flags = 0;
+
+	if (is_legacy(tbl->lq_type)) {
+		rate_n_flags = iwl_rates[index].plcp;
+		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+			rate_n_flags |= RATE_MCS_CCK_MSK;
+	} else if (is_Ht(tbl->lq_type)) {
+		if (index > IWL_LAST_OFDM_RATE) {
+			IWL_ERR(mvm, "Invalid HT rate index %d\n", index);
+			index = IWL_LAST_OFDM_RATE;
+		}
+		rate_n_flags = RATE_MCS_HT_MSK;
+
+		if (is_siso(tbl->lq_type))
+			rate_n_flags |=	iwl_rates[index].plcp_siso;
+		else if (is_mimo2(tbl->lq_type))
+			rate_n_flags |=	iwl_rates[index].plcp_mimo2;
+		else
+			rate_n_flags |=	iwl_rates[index].plcp_mimo3;
+	} else {
+		IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type);
+	}
+
+	rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
+						     RATE_MCS_ANT_ABC_MSK);
+
+	if (is_Ht(tbl->lq_type)) {
+		if (tbl->is_ht40)
+			rate_n_flags |= RATE_MCS_CHAN_WIDTH_40;
+		if (tbl->is_SGI)
+			rate_n_flags |= RATE_MCS_SGI_MSK;
+
+		if (use_green) {
+			rate_n_flags |= RATE_HT_MCS_GF_MSK;
+			if (is_siso(tbl->lq_type) && tbl->is_SGI) {
+				rate_n_flags &= ~RATE_MCS_SGI_MSK;
+				IWL_ERR(mvm, "GF was set with SGI:SISO\n");
+			}
+		}
+	}
+	return rate_n_flags;
+}
+
+/*
+ * Interpret uCode API's rate_n_flags format,
+ * fill "search" or "active" tx mode table.
+ */
+static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
+				    enum ieee80211_band band,
+				    struct iwl_scale_tbl_info *tbl,
+				    int *rate_idx)
+{
+	u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
+	u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
+	u8 mcs;
+
+	memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
+	*rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+
+	if (*rate_idx  == IWL_RATE_INVALID) {
+		*rate_idx = -1;
+		return -EINVAL;
+	}
+	tbl->is_SGI = 0;	/* default legacy setup */
+	tbl->is_ht40 = 0;
+	tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
+	tbl->lq_type = LQ_NONE;
+	tbl->max_search = IWL_MAX_SEARCH;
+
+	/* legacy rate format */
+	if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
+		if (num_of_ant == 1) {
+			if (band == IEEE80211_BAND_5GHZ)
+				tbl->lq_type = LQ_A;
+			else
+				tbl->lq_type = LQ_G;
+		}
+	/* HT rate format */
+	} else {
+		if (rate_n_flags & RATE_MCS_SGI_MSK)
+			tbl->is_SGI = 1;
+
+		if (rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */
+			tbl->is_ht40 = 1;
+
+		mcs = rs_extract_rate(rate_n_flags);
+
+		/* SISO */
+		if (mcs <= IWL_RATE_SISO_60M_PLCP) {
+			if (num_of_ant == 1)
+				tbl->lq_type = LQ_SISO; /*else NONE*/
+		/* MIMO2 */
+		} else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
+			if (num_of_ant == 2)
+				tbl->lq_type = LQ_MIMO2;
+		/* MIMO3 */
+		} else {
+			if (num_of_ant == 3) {
+				tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+				tbl->lq_type = LQ_MIMO3;
+			}
+		}
+	}
+	return 0;
+}
+
+/* switch to another antenna/antennas and return 1 */
+/* if no other valid antenna found, return 0 */
+static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
+			     struct iwl_scale_tbl_info *tbl)
+{
+	u8 new_ant_type;
+
+	if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
+		return 0;
+
+	if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
+		return 0;
+
+	new_ant_type = ant_toggle_lookup[tbl->ant_type];
+
+	while ((new_ant_type != tbl->ant_type) &&
+	       !rs_is_valid_ant(valid_ant, new_ant_type))
+		new_ant_type = ant_toggle_lookup[new_ant_type];
+
+	if (new_ant_type == tbl->ant_type)
+		return 0;
+
+	tbl->ant_type = new_ant_type;
+	*rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
+	*rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
+	return 1;
+}
+
+/**
+ * Green-field mode is valid if the station supports it and
+ * there are no non-GF stations present in the BSS.
+ */
+static bool rs_use_green(struct ieee80211_sta *sta)
+{
+	struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
+
+	bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode &
+				IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+
+	return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green;
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
+				  struct ieee80211_hdr *hdr,
+				  enum iwl_table_type rate_type)
+{
+	if (is_legacy(rate_type)) {
+		return lq_sta->active_legacy_rate;
+	} else {
+		if (is_siso(rate_type))
+			return lq_sta->active_siso_rate;
+		else if (is_mimo2(rate_type))
+			return lq_sta->active_mimo2_rate;
+		else
+			return lq_sta->active_mimo3_rate;
+	}
+}
+
+static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
+				int rate_type)
+{
+	u8 high = IWL_RATE_INVALID;
+	u8 low = IWL_RATE_INVALID;
+
+	/* 802.11A or ht walks to the next literal adjacent rate in
+	 * the rate table */
+	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+		int i;
+		u32 mask;
+
+		/* Find the previous rate that is in the rate mask */
+		i = index - 1;
+		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+			if (rate_mask & mask) {
+				low = i;
+				break;
+			}
+		}
+
+		/* Find the next rate that is in the rate mask */
+		i = index + 1;
+		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+			if (rate_mask & mask) {
+				high = i;
+				break;
+			}
+		}
+
+		return (high << 8) | low;
+	}
+
+	low = index;
+	while (low != IWL_RATE_INVALID) {
+		low = iwl_rates[low].prev_rs;
+		if (low == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << low))
+			break;
+		IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low);
+	}
+
+	high = index;
+	while (high != IWL_RATE_INVALID) {
+		high = iwl_rates[high].next_rs;
+		if (high == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << high))
+			break;
+		IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high);
+	}
+
+	return (high << 8) | low;
+}
+
+static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
+			     struct iwl_scale_tbl_info *tbl,
+			     u8 scale_index, u8 ht_possible)
+{
+	s32 low;
+	u16 rate_mask;
+	u16 high_low;
+	u8 switch_to_legacy = 0;
+	u8 is_green = lq_sta->is_green;
+	struct iwl_mvm *mvm = lq_sta->drv;
+
+	/* check if we need to switch from HT to legacy rates.
+	 * assumption is that mandatory rates (1Mbps or 6Mbps)
+	 * are always supported (spec demand) */
+	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+		switch_to_legacy = 1;
+		scale_index = rs_ht_to_legacy[scale_index];
+		if (lq_sta->band == IEEE80211_BAND_5GHZ)
+			tbl->lq_type = LQ_A;
+		else
+			tbl->lq_type = LQ_G;
+
+		if (num_of_ant(tbl->ant_type) > 1)
+			tbl->ant_type =
+			    first_antenna(mvm->nvm_data->valid_tx_ant);
+
+		tbl->is_ht40 = 0;
+		tbl->is_SGI = 0;
+		tbl->max_search = IWL_MAX_SEARCH;
+	}
+
+	rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
+
+	/* Mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		/* supp_rates has no CCK bits in A mode */
+		if (lq_sta->band == IEEE80211_BAND_5GHZ)
+			rate_mask  = (u16)(rate_mask &
+			   (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
+	}
+
+	/* If we switched from HT to legacy, check current rate */
+	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
+		low = scale_index;
+		goto out;
+	}
+
+	high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
+					tbl->lq_type);
+	low = high_low & 0xff;
+
+	if (low == IWL_RATE_INVALID)
+		low = scale_index;
+
+out:
+	return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
+}
+
+/*
+ * Simple function to compare two rate scale table types
+ */
+static bool table_type_matches(struct iwl_scale_tbl_info *a,
+			       struct iwl_scale_tbl_info *b)
+{
+	return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
+		(a->is_SGI == b->is_SGI);
+}
+
+/*
+ * mac80211 sends us Tx status
+ */
+static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
+			 struct ieee80211_sta *sta, void *priv_sta,
+			 struct sk_buff *skb)
+{
+	int legacy_success;
+	int retries;
+	int rs_index, mac_index, i;
+	struct iwl_lq_sta *lq_sta = priv_sta;
+	struct iwl_lq_cmd *table;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r;
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	enum mac80211_rate_control_flags mac_flags;
+	u32 tx_rate;
+	struct iwl_scale_tbl_info tbl_type;
+	struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+
+	IWL_DEBUG_RATE_LIMIT(mvm,
+			     "get frame ack response, update rate scale window\n");
+
+	/* Treat uninitialized rate scaling data same as non-existing. */
+	if (!lq_sta) {
+		IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
+		return;
+	} else if (!lq_sta->drv) {
+		IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
+		return;
+	}
+
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    info->flags & IEEE80211_TX_CTL_NO_ACK)
+		return;
+
+	/* This packet was aggregated but doesn't carry status info */
+	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
+		return;
+
+	/*
+	 * Ignore this Tx frame response if its initial rate doesn't match
+	 * that of latest Link Quality command.  There may be stragglers
+	 * from a previous Link Quality command, but we're no longer interested
+	 * in those; they're either from the "active" mode while we're trying
+	 * to check "search" mode, or a prior "search" mode after we've moved
+	 * to a new "search" mode (which might become the new "active" mode).
+	 */
+	table = &lq_sta->lq;
+	tx_rate = le32_to_cpu(table->rs_table[0]);
+	rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index);
+	if (info->band == IEEE80211_BAND_5GHZ)
+		rs_index -= IWL_FIRST_OFDM_RATE;
+	mac_flags = info->status.rates[0].flags;
+	mac_index = info->status.rates[0].idx;
+	/* For HT packets, map MCS to PLCP */
+	if (mac_flags & IEEE80211_TX_RC_MCS) {
+		/* Remove # of streams */
+		mac_index &= RATE_HT_MCS_RATE_CODE_MSK;
+		if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
+			mac_index++;
+		/*
+		 * mac80211 HT index is always zero-indexed; we need to move
+		 * HT OFDM rates after CCK rates in 2.4 GHz band
+		 */
+		if (info->band == IEEE80211_BAND_2GHZ)
+			mac_index += IWL_FIRST_OFDM_RATE;
+	}
+	/* Here we actually compare this rate to the latest LQ command */
+	if ((mac_index < 0) ||
+	    (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
+	    (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+	    (tbl_type.ant_type != info->status.antenna) ||
+	    (!!(tx_rate & RATE_MCS_HT_MSK) !=
+				!!(mac_flags & IEEE80211_TX_RC_MCS)) ||
+	    (!!(tx_rate & RATE_HT_MCS_GF_MSK) !=
+				!!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
+	    (rs_index != mac_index)) {
+		IWL_DEBUG_RATE(mvm,
+			       "initial rate %d does not match %d (0x%x)\n",
+			       mac_index, rs_index, tx_rate);
+		/*
+		 * Since rates mis-match, the last LQ command may have failed.
+		 * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+		 * ... driver.
+		 */
+		lq_sta->missed_rate_counter++;
+		if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
+			lq_sta->missed_rate_counter = 0;
+			iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
+		}
+		/* Regardless, ignore this status info for outdated rate */
+		return;
+	} else
+		/* Rate did match, so reset the missed_rate_counter */
+		lq_sta->missed_rate_counter = 0;
+
+	/* Figure out if rate scale algorithm is in active or search table */
+	if (table_type_matches(&tbl_type,
+			       &(lq_sta->lq_info[lq_sta->active_tbl]))) {
+		curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+	} else if (table_type_matches(
+			&tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) {
+		curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+		other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	} else {
+		IWL_DEBUG_RATE(mvm,
+			       "Neither active nor search matches tx rate\n");
+		tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n",
+			       tmp_tbl->lq_type, tmp_tbl->ant_type,
+			       tmp_tbl->is_SGI);
+		tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+		IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n",
+			       tmp_tbl->lq_type, tmp_tbl->ant_type,
+			       tmp_tbl->is_SGI);
+		IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n",
+			       tbl_type.lq_type, tbl_type.ant_type,
+			       tbl_type.is_SGI);
+		/*
+		 * no matching table found, let's by-pass the data collection
+		 * and continue to perform rate scale to find the rate table
+		 */
+		rs_stay_in_table(lq_sta, true);
+		goto done;
+	}
+
+	/*
+	 * Updating the frame history depends on whether packets were
+	 * aggregated.
+	 *
+	 * For aggregation, all packets were transmitted at the same rate, the
+	 * first index into rate scale table.
+	 */
+	if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+		tx_rate = le32_to_cpu(table->rs_table[0]);
+		rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type,
+					 &rs_index);
+		rs_collect_tx_data(curr_tbl, rs_index,
+				   info->status.ampdu_len,
+				   info->status.ampdu_ack_len);
+
+		/* Update success/fail counts if not searching for new mode */
+		if (lq_sta->stay_in_tbl) {
+			lq_sta->total_success += info->status.ampdu_ack_len;
+			lq_sta->total_failed += (info->status.ampdu_len -
+					info->status.ampdu_ack_len);
+		}
+	} else {
+	/*
+	 * For legacy, update frame history with for each Tx retry.
+	 */
+		retries = info->status.rates[0].count - 1;
+		/* HW doesn't send more than 15 retries */
+		retries = min(retries, 15);
+
+		/* The last transmission may have been successful */
+		legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+		/* Collect data for each rate used during failed TX attempts */
+		for (i = 0; i <= retries; ++i) {
+			tx_rate = le32_to_cpu(table->rs_table[i]);
+			rs_get_tbl_info_from_mcs(tx_rate, info->band,
+						 &tbl_type, &rs_index);
+			/*
+			 * Only collect stats if retried rate is in the same RS
+			 * table as active/search.
+			 */
+			if (table_type_matches(&tbl_type, curr_tbl))
+				tmp_tbl = curr_tbl;
+			else if (table_type_matches(&tbl_type, other_tbl))
+				tmp_tbl = other_tbl;
+			else
+				continue;
+			rs_collect_tx_data(tmp_tbl, rs_index, 1,
+					   i < retries ? 0 : legacy_success);
+		}
+
+		/* Update success/fail counts if not searching for new mode */
+		if (lq_sta->stay_in_tbl) {
+			lq_sta->total_success += legacy_success;
+			lq_sta->total_failed += retries + (1 - legacy_success);
+		}
+	}
+	/* The last TX rate is cached in lq_sta; it's set in if/else above */
+	lq_sta->last_rate_n_flags = tx_rate;
+done:
+	/* See if there's a better rate or modulation mode to try. */
+	if (sta && sta->supp_rates[sband->band])
+		rs_rate_scale_perform(mvm, skb, sta, lq_sta);
+}
+
+/*
+ * Begin a period of staying with a selected modulation mode.
+ * Set "stay_in_tbl" flag to prevent any mode switches.
+ * Set frame tx success limits according to legacy vs. high-throughput,
+ * and reset overall (spanning all rates) tx success history statistics.
+ * These control how long we stay using same modulation mode before
+ * searching for a new mode.
+ */
+static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
+				 struct iwl_lq_sta *lq_sta)
+{
+	IWL_DEBUG_RATE(mvm, "we are staying in the same table\n");
+	lq_sta->stay_in_tbl = 1;	/* only place this gets set */
+	if (is_legacy) {
+		lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+		lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+		lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
+	} else {
+		lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+		lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+		lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+	}
+	lq_sta->table_count = 0;
+	lq_sta->total_failed = 0;
+	lq_sta->total_success = 0;
+	lq_sta->flush_timer = jiffies;
+	lq_sta->action_counter = 0;
+}
+
+/*
+ * Find correct throughput table for given mode of modulation
+ */
+static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+				      struct iwl_scale_tbl_info *tbl)
+{
+	/* Used to choose among HT tables */
+	s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+
+	/* Check for invalid LQ type */
+	if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
+		tbl->expected_tpt = expected_tpt_legacy;
+		return;
+	}
+
+	/* Legacy rates have only one table */
+	if (is_legacy(tbl->lq_type)) {
+		tbl->expected_tpt = expected_tpt_legacy;
+		return;
+	}
+
+	/* Choose among many HT tables depending on number of streams
+	 * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
+	 * status */
+	if (is_siso(tbl->lq_type) && !tbl->is_ht40)
+		ht_tbl_pointer = expected_tpt_siso20MHz;
+	else if (is_siso(tbl->lq_type))
+		ht_tbl_pointer = expected_tpt_siso40MHz;
+	else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40)
+		ht_tbl_pointer = expected_tpt_mimo2_20MHz;
+	else if (is_mimo2(tbl->lq_type))
+		ht_tbl_pointer = expected_tpt_mimo2_40MHz;
+	else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40)
+		ht_tbl_pointer = expected_tpt_mimo3_20MHz;
+	else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
+		ht_tbl_pointer = expected_tpt_mimo3_40MHz;
+
+	if (!tbl->is_SGI && !lq_sta->is_agg)		/* Normal */
+		tbl->expected_tpt = ht_tbl_pointer[0];
+	else if (tbl->is_SGI && !lq_sta->is_agg)	/* SGI */
+		tbl->expected_tpt = ht_tbl_pointer[1];
+	else if (!tbl->is_SGI && lq_sta->is_agg)	/* AGG */
+		tbl->expected_tpt = ht_tbl_pointer[2];
+	else						/* AGG+SGI */
+		tbl->expected_tpt = ht_tbl_pointer[3];
+}
+
+/*
+ * Find starting rate for new "search" high-throughput mode of modulation.
+ * Goal is to find lowest expected rate (under perfect conditions) that is
+ * above the current measured throughput of "active" mode, to give new mode
+ * a fair chance to prove itself without too many challenges.
+ *
+ * This gets called when transitioning to more aggressive modulation
+ * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
+ * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
+ * to decrease to match "active" throughput.  When moving from MIMO to SISO,
+ * bit rate will typically need to increase, but not if performance was bad.
+ */
+static s32 rs_get_best_rate(struct iwl_mvm *mvm,
+			    struct iwl_lq_sta *lq_sta,
+			    struct iwl_scale_tbl_info *tbl,	/* "search" */
+			    u16 rate_mask, s8 index)
+{
+	/* "active" values */
+	struct iwl_scale_tbl_info *active_tbl =
+	    &(lq_sta->lq_info[lq_sta->active_tbl]);
+	s32 active_sr = active_tbl->win[index].success_ratio;
+	s32 active_tpt = active_tbl->expected_tpt[index];
+
+	/* expected "search" throughput */
+	s32 *tpt_tbl = tbl->expected_tpt;
+
+	s32 new_rate, high, low, start_hi;
+	u16 high_low;
+	s8 rate = index;
+
+	new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+	while (1) {
+		high_low = rs_get_adjacent_rate(mvm, rate, rate_mask,
+						tbl->lq_type);
+
+		low = high_low & 0xff;
+		high = (high_low >> 8) & 0xff;
+
+		/*
+		 * Lower the "search" bit rate, to give new "search" mode
+		 * approximately the same throughput as "active" if:
+		 *
+		 * 1) "Active" mode has been working modestly well (but not
+		 *    great), and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above the actual
+		 *    measured "active" throughput (but less than expected
+		 *    "active" throughput under perfect conditions).
+		 * OR
+		 * 2) "Active" mode has been working perfectly or very well
+		 *    and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above expected
+		 *    "active" throughput (under perfect conditions).
+		 */
+		if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
+		     ((active_sr > IWL_RATE_DECREASE_TH) &&
+		      (active_sr <= IWL_RATE_HIGH_TH) &&
+		      (tpt_tbl[rate] <= active_tpt))) ||
+		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+		     (tpt_tbl[rate] > active_tpt))) {
+			/* (2nd or later pass)
+			 * If we've already tried to raise the rate, and are
+			 * now trying to lower it, use the higher rate. */
+			if (start_hi != IWL_RATE_INVALID) {
+				new_rate = start_hi;
+				break;
+			}
+
+			new_rate = rate;
+
+			/* Loop again with lower rate */
+			if (low != IWL_RATE_INVALID)
+				rate = low;
+
+			/* Lower rate not available, use the original */
+			else
+				break;
+
+		/* Else try to raise the "search" rate to match "active" */
+		} else {
+			/* (2nd or later pass)
+			 * If we've already tried to lower the rate, and are
+			 * now trying to raise it, use the lower rate. */
+			if (new_rate != IWL_RATE_INVALID)
+				break;
+
+			/* Loop again with higher rate */
+			else if (high != IWL_RATE_INVALID) {
+				start_hi = high;
+				rate = high;
+
+			/* Higher rate not available, use the original */
+			} else {
+				new_rate = rate;
+				break;
+			}
+		}
+	}
+
+	return new_rate;
+}
+
+static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta)
+{
+	return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+}
+
+/*
+ * Set up search table for MIMO2
+ */
+static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
+			     struct iwl_lq_sta *lq_sta,
+			     struct ieee80211_sta *sta,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	u16 rate_mask;
+	s32 rate;
+	s8 is_green = lq_sta->is_green;
+
+	if (!sta->ht_cap.ht_supported)
+		return -1;
+
+	if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+		return -1;
+
+	/* Need both Tx chains/antennas to support MIMO */
+	if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2)
+		return -1;
+
+	IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
+
+	tbl->lq_type = LQ_MIMO2;
+	tbl->action = 0;
+	tbl->max_search = IWL_MAX_SEARCH;
+	rate_mask = lq_sta->active_mimo2_rate;
+
+	if (iwl_is_ht40_tx_allowed(sta))
+		tbl->is_ht40 = 1;
+	else
+		tbl->is_ht40 = 0;
+
+	rs_set_expected_tpt_table(lq_sta, tbl);
+
+	rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+
+	IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n",
+		       rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
+			       rate, rate_mask);
+		return -1;
+	}
+	tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
+
+	IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
+		       tbl->current_rate, is_green);
+	return 0;
+}
+
+/*
+ * Set up search table for MIMO3
+ */
+static int rs_switch_to_mimo3(struct iwl_mvm *mvm,
+			     struct iwl_lq_sta *lq_sta,
+			     struct ieee80211_sta *sta,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	u16 rate_mask;
+	s32 rate;
+	s8 is_green = lq_sta->is_green;
+
+	if (!sta->ht_cap.ht_supported)
+		return -1;
+
+	if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+		return -1;
+
+	/* Need both Tx chains/antennas to support MIMO */
+	if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3)
+		return -1;
+
+	IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n");
+
+	tbl->lq_type = LQ_MIMO3;
+	tbl->action = 0;
+	tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+	rate_mask = lq_sta->active_mimo3_rate;
+
+	if (iwl_is_ht40_tx_allowed(sta))
+		tbl->is_ht40 = 1;
+	else
+		tbl->is_ht40 = 0;
+
+	rs_set_expected_tpt_table(lq_sta, tbl);
+
+	rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+
+	IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n",
+		       rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
+			       rate, rate_mask);
+		return -1;
+	}
+	tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
+
+	IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
+		       tbl->current_rate, is_green);
+	return 0;
+}
+
+/*
+ * Set up search table for SISO
+ */
+static int rs_switch_to_siso(struct iwl_mvm *mvm,
+			     struct iwl_lq_sta *lq_sta,
+			     struct ieee80211_sta *sta,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	u16 rate_mask;
+	u8 is_green = lq_sta->is_green;
+	s32 rate;
+
+	if (!sta->ht_cap.ht_supported)
+		return -1;
+
+	IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n");
+
+	tbl->lq_type = LQ_SISO;
+	tbl->action = 0;
+	tbl->max_search = IWL_MAX_SEARCH;
+	rate_mask = lq_sta->active_siso_rate;
+
+	if (iwl_is_ht40_tx_allowed(sta))
+		tbl->is_ht40 = 1;
+	else
+		tbl->is_ht40 = 0;
+
+	if (is_green)
+		tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
+
+	rs_set_expected_tpt_table(lq_sta, tbl);
+	rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+
+	IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_RATE(mvm,
+			       "can not switch with index %d rate mask %x\n",
+			       rate, rate_mask);
+		return -1;
+	}
+	tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
+	IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
+		       tbl->current_rate, is_green);
+	return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from legacy
+ */
+static int rs_move_legacy_other(struct iwl_mvm *mvm,
+				struct iwl_lq_sta *lq_sta,
+				struct ieee80211_sta *sta,
+				int index)
+{
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+	u8 tx_chains_num = num_of_ant(valid_tx_ant);
+	int ret;
+	u8 update_search_tbl_counter = 0;
+
+	start_action = tbl->action;
+	while (1) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_LEGACY_SWITCH_ANTENNA1:
+		case IWL_LEGACY_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n");
+
+			if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
+			     tx_chains_num <= 1) ||
+			    (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
+			     tx_chains_num <= 2))
+				break;
+
+			/* Don't change antenna if success has been great */
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			/* Set up search table to try other antenna */
+			memcpy(search_tbl, tbl, sz);
+
+			if (rs_toggle_antenna(valid_tx_ant,
+					      &search_tbl->current_rate,
+					      search_tbl)) {
+				update_search_tbl_counter = 1;
+				rs_set_expected_tpt_table(lq_sta, search_tbl);
+				goto out;
+			}
+			break;
+		case IWL_LEGACY_SWITCH_SISO:
+			IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n");
+
+			/* Set up search table to try SISO */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			ret = rs_switch_to_siso(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->action_counter = 0;
+				goto out;
+			}
+
+			break;
+		case IWL_LEGACY_SWITCH_MIMO2_AB:
+		case IWL_LEGACY_SWITCH_MIMO2_AC:
+		case IWL_LEGACY_SWITCH_MIMO2_BC:
+			IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n");
+
+			/* Set up search table to try MIMO */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+
+			if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->action_counter = 0;
+				goto out;
+			}
+			break;
+
+		case IWL_LEGACY_SWITCH_MIMO3_ABC:
+			IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n");
+
+			/* Set up search table to try MIMO3 */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+
+			search_tbl->ant_type = ANT_ABC;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->action_counter = 0;
+				goto out;
+			}
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+			tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+
+out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+		tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+	return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from SISO
+ */
+static int rs_move_siso_to_other(struct iwl_mvm *mvm,
+				 struct iwl_lq_sta *lq_sta,
+				 struct ieee80211_sta *sta, int index)
+{
+	u8 is_green = lq_sta->is_green;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+	u8 tx_chains_num = num_of_ant(valid_tx_ant);
+	u8 update_search_tbl_counter = 0;
+	int ret;
+
+	start_action = tbl->action;
+	while (1) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_SISO_SWITCH_ANTENNA1:
+		case IWL_SISO_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n");
+			if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
+			     tx_chains_num <= 1) ||
+			    (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
+			     tx_chains_num <= 2))
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+					      &search_tbl->current_rate,
+					      search_tbl)) {
+				update_search_tbl_counter = 1;
+				goto out;
+			}
+			break;
+		case IWL_SISO_SWITCH_MIMO2_AB:
+		case IWL_SISO_SWITCH_MIMO2_AC:
+		case IWL_SISO_SWITCH_MIMO2_BC:
+			IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+
+			if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+			break;
+		case IWL_SISO_SWITCH_GI:
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
+				break;
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
+				break;
+
+			IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n");
+
+			memcpy(search_tbl, tbl, sz);
+			if (is_green) {
+				if (!tbl->is_SGI)
+					break;
+				else
+					IWL_ERR(mvm,
+						"SGI was set in GF+SISO\n");
+			}
+			search_tbl->is_SGI = !tbl->is_SGI;
+			rs_set_expected_tpt_table(lq_sta, search_tbl);
+			if (tbl->is_SGI) {
+				s32 tpt = lq_sta->last_tpt / 100;
+				if (tpt >= search_tbl->expected_tpt[index])
+					break;
+			}
+			search_tbl->current_rate =
+				rate_n_flags_from_tbl(mvm, search_tbl,
+						      index, is_green);
+			update_search_tbl_counter = 1;
+			goto out;
+		case IWL_SISO_SWITCH_MIMO3_ABC:
+			IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			search_tbl->ant_type = ANT_ABC;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+			tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+
+ out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
+		tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+
+	return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO2
+ */
+static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
+				 struct iwl_lq_sta *lq_sta,
+				 struct ieee80211_sta *sta, int index)
+{
+	s8 is_green = lq_sta->is_green;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+	u8 tx_chains_num = num_of_ant(valid_tx_ant);
+	u8 update_search_tbl_counter = 0;
+	int ret;
+
+	start_action = tbl->action;
+	while (1) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_MIMO2_SWITCH_ANTENNA1:
+		case IWL_MIMO2_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle Antennas\n");
+
+			if (tx_chains_num <= 2)
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+					      &search_tbl->current_rate,
+					      search_tbl)) {
+				update_search_tbl_counter = 1;
+				goto out;
+			}
+			break;
+		case IWL_MIMO2_SWITCH_SISO_A:
+		case IWL_MIMO2_SWITCH_SISO_B:
+		case IWL_MIMO2_SWITCH_SISO_C:
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n");
+
+			/* Set up new search table for SISO */
+			memcpy(search_tbl, tbl, sz);
+
+			if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
+				search_tbl->ant_type = ANT_A;
+			else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
+				search_tbl->ant_type = ANT_B;
+			else
+				search_tbl->ant_type = ANT_C;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_siso(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+
+		case IWL_MIMO2_SWITCH_GI:
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
+				break;
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
+				break;
+
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n");
+
+			/* Set up new search table for MIMO2 */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = !tbl->is_SGI;
+			rs_set_expected_tpt_table(lq_sta, search_tbl);
+			/*
+			 * If active table already uses the fastest possible
+			 * modulation (dual stream with short guard interval),
+			 * and it's working well, there's no need to look
+			 * for a better type of modulation!
+			 */
+			if (tbl->is_SGI) {
+				s32 tpt = lq_sta->last_tpt / 100;
+				if (tpt >= search_tbl->expected_tpt[index])
+					break;
+			}
+			search_tbl->current_rate =
+				rate_n_flags_from_tbl(mvm, search_tbl,
+						      index, is_green);
+			update_search_tbl_counter = 1;
+			goto out;
+
+		case IWL_MIMO2_SWITCH_MIMO3_ABC:
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			search_tbl->ant_type = ANT_ABC;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+			tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+ out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+		tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+
+	return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO3
+ */
+static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
+				 struct iwl_lq_sta *lq_sta,
+				 struct ieee80211_sta *sta, int index)
+{
+	s8 is_green = lq_sta->is_green;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+				&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action;
+	u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+	u8 tx_chains_num = num_of_ant(valid_tx_ant);
+	int ret;
+	u8 update_search_tbl_counter = 0;
+
+	start_action = tbl->action;
+	while (1) {
+		lq_sta->action_counter++;
+		switch (tbl->action) {
+		case IWL_MIMO3_SWITCH_ANTENNA1:
+		case IWL_MIMO3_SWITCH_ANTENNA2:
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n");
+
+			if (tx_chains_num <= 3)
+				break;
+
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			if (rs_toggle_antenna(valid_tx_ant,
+					      &search_tbl->current_rate,
+					      search_tbl))
+				goto out;
+			break;
+		case IWL_MIMO3_SWITCH_SISO_A:
+		case IWL_MIMO3_SWITCH_SISO_B:
+		case IWL_MIMO3_SWITCH_SISO_C:
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n");
+
+			/* Set up new search table for SISO */
+			memcpy(search_tbl, tbl, sz);
+
+			if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
+				search_tbl->ant_type = ANT_A;
+			else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
+				search_tbl->ant_type = ANT_B;
+			else
+				search_tbl->ant_type = ANT_C;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_siso(mvm, lq_sta, sta,
+						search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+
+		case IWL_MIMO3_SWITCH_MIMO2_AB:
+		case IWL_MIMO3_SWITCH_MIMO2_AC:
+		case IWL_MIMO3_SWITCH_MIMO2_BC:
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n");
+
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = 0;
+			if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
+				search_tbl->ant_type = ANT_AB;
+			else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
+				search_tbl->ant_type = ANT_AC;
+			else
+				search_tbl->ant_type = ANT_BC;
+
+			if (!rs_is_valid_ant(valid_tx_ant,
+					     search_tbl->ant_type))
+				break;
+
+			ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
+						 search_tbl, index);
+			if (!ret)
+				goto out;
+
+			break;
+
+		case IWL_MIMO3_SWITCH_GI:
+			if (!tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_20))
+				break;
+			if (tbl->is_ht40 && !(ht_cap->cap &
+						IEEE80211_HT_CAP_SGI_40))
+				break;
+
+			IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n");
+
+			/* Set up new search table for MIMO */
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->is_SGI = !tbl->is_SGI;
+			rs_set_expected_tpt_table(lq_sta, search_tbl);
+			/*
+			 * If active table already uses the fastest possible
+			 * modulation (dual stream with short guard interval),
+			 * and it's working well, there's no need to look
+			 * for a better type of modulation!
+			 */
+			if (tbl->is_SGI) {
+				s32 tpt = lq_sta->last_tpt / 100;
+				if (tpt >= search_tbl->expected_tpt[index])
+					break;
+			}
+			search_tbl->current_rate =
+				rate_n_flags_from_tbl(mvm, search_tbl,
+						      index, is_green);
+			update_search_tbl_counter = 1;
+			goto out;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_MIMO3_SWITCH_GI)
+			tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	search_tbl->lq_type = LQ_NONE;
+	return 0;
+ out:
+	lq_sta->search_better_tbl = 1;
+	tbl->action++;
+	if (tbl->action > IWL_MIMO3_SWITCH_GI)
+		tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+	if (update_search_tbl_counter)
+		search_tbl->action = tbl->action;
+
+	return 0;
+}
+
+/*
+ * Check whether we should continue using same modulation mode, or
+ * begin search for a new mode, based on:
+ * 1) # tx successes or failures while using this mode
+ * 2) # times calling this function
+ * 3) elapsed time in this mode (not used, for now)
+ */
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
+{
+	struct iwl_scale_tbl_info *tbl;
+	int i;
+	int active_tbl;
+	int flush_interval_passed = 0;
+	struct iwl_mvm *mvm;
+
+	mvm = lq_sta->drv;
+	active_tbl = lq_sta->active_tbl;
+
+	tbl = &(lq_sta->lq_info[active_tbl]);
+
+	/* If we've been disallowing search, see if we should now allow it */
+	if (lq_sta->stay_in_tbl) {
+		/* Elapsed time using current modulation mode */
+		if (lq_sta->flush_timer)
+			flush_interval_passed =
+				time_after(jiffies,
+					   (unsigned long)(lq_sta->flush_timer +
+						IWL_RATE_SCALE_FLUSH_INTVL));
+
+		/*
+		 * Check if we should allow search for new modulation mode.
+		 * If many frames have failed or succeeded, or we've used
+		 * this same modulation for a long time, allow search, and
+		 * reset history stats that keep track of whether we should
+		 * allow a new search.  Also (below) reset all bitmaps and
+		 * stats in active history.
+		 */
+		if (force_search ||
+		    (lq_sta->total_failed > lq_sta->max_failure_limit) ||
+		    (lq_sta->total_success > lq_sta->max_success_limit) ||
+		    ((!lq_sta->search_better_tbl) &&
+		     (lq_sta->flush_timer) && (flush_interval_passed))) {
+			IWL_DEBUG_RATE(mvm,
+				       "LQ: stay is expired %d %d %d\n",
+				     lq_sta->total_failed,
+				     lq_sta->total_success,
+				     flush_interval_passed);
+
+			/* Allow search for new mode */
+			lq_sta->stay_in_tbl = 0;	/* only place reset */
+			lq_sta->total_failed = 0;
+			lq_sta->total_success = 0;
+			lq_sta->flush_timer = 0;
+		/*
+		 * Else if we've used this modulation mode enough repetitions
+		 * (regardless of elapsed time or success/failure), reset
+		 * history bitmaps and rate-specific stats for all rates in
+		 * active table.
+		 */
+		} else {
+			lq_sta->table_count++;
+			if (lq_sta->table_count >=
+			    lq_sta->table_count_limit) {
+				lq_sta->table_count = 0;
+
+				IWL_DEBUG_RATE(mvm,
+					       "LQ: stay in table clear win\n");
+				for (i = 0; i < IWL_RATE_COUNT; i++)
+					rs_rate_scale_clear_window(
+						&(tbl->win[i]));
+			}
+		}
+
+		/* If transitioning to allow "search", reset all history
+		 * bitmaps and stats in active table (this will become the new
+		 * "search" table). */
+		if (!lq_sta->stay_in_tbl) {
+			for (i = 0; i < IWL_RATE_COUNT; i++)
+				rs_rate_scale_clear_window(&(tbl->win[i]));
+		}
+	}
+}
+
+/*
+ * setup rate table in uCode
+ */
+static void rs_update_rate_tbl(struct iwl_mvm *mvm,
+			       struct iwl_lq_sta *lq_sta,
+			       struct iwl_scale_tbl_info *tbl,
+			       int index, u8 is_green)
+{
+	u32 rate;
+
+	/* Update uCode's rate table. */
+	rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green);
+	rs_fill_link_cmd(mvm, lq_sta, rate);
+	iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
+}
+
+/*
+ * Do rate scaling and search for new modulation mode.
+ */
+static void rs_rate_scale_perform(struct iwl_mvm *mvm,
+				  struct sk_buff *skb,
+				  struct ieee80211_sta *sta,
+				  struct iwl_lq_sta *lq_sta)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	int low = IWL_RATE_INVALID;
+	int high = IWL_RATE_INVALID;
+	int index;
+	int i;
+	struct iwl_rate_scale_data *window = NULL;
+	int current_tpt = IWL_INVALID_VALUE;
+	int low_tpt = IWL_INVALID_VALUE;
+	int high_tpt = IWL_INVALID_VALUE;
+	u32 fail_count;
+	s8 scale_action = 0;
+	u16 rate_mask;
+	u8 update_lq = 0;
+	struct iwl_scale_tbl_info *tbl, *tbl1;
+	u16 rate_scale_index_msk = 0;
+	u8 is_green = 0;
+	u8 active_tbl = 0;
+	u8 done_search = 0;
+	u16 high_low;
+	s32 sr;
+	u8 tid = IWL_MAX_TID_COUNT;
+	struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
+	struct iwl_mvm_tid_data *tid_data;
+
+	IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n");
+
+	/* Send management frames and NO_ACK data using lowest rate. */
+	/* TODO: this could probably be improved.. */
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    info->flags & IEEE80211_TX_CTL_NO_ACK)
+		return;
+
+	lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
+
+	tid = rs_tl_add_packet(lq_sta, hdr);
+	if ((tid != IWL_MAX_TID_COUNT) &&
+	    (lq_sta->tx_agg_tid_en & (1 << tid))) {
+		tid_data = &sta_priv->tid_data[tid];
+		if (tid_data->state == IWL_AGG_OFF)
+			lq_sta->is_agg = 0;
+		else
+			lq_sta->is_agg = 1;
+	} else {
+		lq_sta->is_agg = 0;
+	}
+
+	/*
+	 * Select rate-scale / modulation-mode table to work with in
+	 * the rest of this function:  "search" if searching for better
+	 * modulation mode, or "active" if doing rate scaling within a mode.
+	 */
+	if (!lq_sta->search_better_tbl)
+		active_tbl = lq_sta->active_tbl;
+	else
+		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(sta);
+	is_green = lq_sta->is_green;
+
+	/* current tx rate */
+	index = lq_sta->last_txrate_idx;
+
+	IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index,
+		       tbl->lq_type);
+
+	/* rates available for this association, and for modulation mode */
+	rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
+
+	IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask);
+
+	/* mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		if (lq_sta->band == IEEE80211_BAND_5GHZ)
+			/* supp_rates has no CCK bits in A mode */
+			rate_scale_index_msk = (u16) (rate_mask &
+				(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_scale_index_msk = (u16) (rate_mask &
+						      lq_sta->supp_rates);
+
+	} else {
+		rate_scale_index_msk = rate_mask;
+	}
+
+	if (!rate_scale_index_msk)
+		rate_scale_index_msk = rate_mask;
+
+	if (!((1 << index) & rate_scale_index_msk)) {
+		IWL_ERR(mvm, "Current Rate is not valid\n");
+		if (lq_sta->search_better_tbl) {
+			/* revert to active table if search table is not valid*/
+			tbl->lq_type = LQ_NONE;
+			lq_sta->search_better_tbl = 0;
+			tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+			/* get "active" rate info */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+			rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green);
+		}
+		return;
+	}
+
+	/* Get expected throughput table and history window for current rate */
+	if (!tbl->expected_tpt) {
+		IWL_ERR(mvm, "tbl->expected_tpt is NULL\n");
+		return;
+	}
+
+	/* force user max rate if set by user */
+	if ((lq_sta->max_rate_idx != -1) &&
+	    (lq_sta->max_rate_idx < index)) {
+		index = lq_sta->max_rate_idx;
+		update_lq = 1;
+		window = &(tbl->win[index]);
+		goto lq_update;
+	}
+
+	window = &(tbl->win[index]);
+
+	/*
+	 * If there is not enough history to calculate actual average
+	 * throughput, keep analyzing results of more tx frames, without
+	 * changing rate or mode (bypass most of the rest of this function).
+	 * Set up new rate table in uCode only if old rate is not supported
+	 * in current association (use new rate found above).
+	 */
+	fail_count = window->counter - window->success_counter;
+	if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+	    (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+		IWL_DEBUG_RATE(mvm,
+			       "LQ: still below TH. succ=%d total=%d for index %d\n",
+			       window->success_counter, window->counter, index);
+
+		/* Can't calculate this yet; not enough history */
+		window->average_tpt = IWL_INVALID_VALUE;
+
+		/* Should we stay with this modulation mode,
+		 * or search for a new one? */
+		rs_stay_in_table(lq_sta, false);
+
+		goto out;
+	}
+	/* Else we have enough samples; calculate estimate of
+	 * actual average throughput */
+	if (window->average_tpt != ((window->success_ratio *
+			tbl->expected_tpt[index] + 64) / 128)) {
+		IWL_ERR(mvm,
+			"expected_tpt should have been calculated by now\n");
+		window->average_tpt = ((window->success_ratio *
+					tbl->expected_tpt[index] + 64) / 128);
+	}
+
+	/* If we are searching for better modulation mode, check success. */
+	if (lq_sta->search_better_tbl) {
+		/* If good success, continue using the "search" mode;
+		 * no need to send new link quality command, since we're
+		 * continuing to use the setup that we've been trying. */
+		if (window->average_tpt > lq_sta->last_tpt) {
+			IWL_DEBUG_RATE(mvm,
+				       "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n",
+				       window->success_ratio,
+				       window->average_tpt,
+				       lq_sta->last_tpt);
+
+			if (!is_legacy(tbl->lq_type))
+				lq_sta->enable_counter = 1;
+
+			/* Swap tables; "search" becomes "active" */
+			lq_sta->active_tbl = active_tbl;
+			current_tpt = window->average_tpt;
+		/* Else poor success; go back to mode in "active" table */
+		} else {
+			IWL_DEBUG_RATE(mvm,
+				       "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n",
+				       window->success_ratio,
+				       window->average_tpt,
+				       lq_sta->last_tpt);
+
+			/* Nullify "search" table */
+			tbl->lq_type = LQ_NONE;
+
+			/* Revert to "active" table */
+			active_tbl = lq_sta->active_tbl;
+			tbl = &(lq_sta->lq_info[active_tbl]);
+
+			/* Revert to "active" rate and throughput info */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+			current_tpt = lq_sta->last_tpt;
+
+			/* Need to set up a new rate table in uCode */
+			update_lq = 1;
+		}
+
+		/* Either way, we've made a decision; modulation mode
+		 * search is done, allow rate adjustment next time. */
+		lq_sta->search_better_tbl = 0;
+		done_search = 1;	/* Don't switch modes below! */
+		goto lq_update;
+	}
+
+	/* (Else) not in search of better modulation mode, try for better
+	 * starting rate, while staying in this mode. */
+	high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk,
+					tbl->lq_type);
+	low = high_low & 0xff;
+	high = (high_low >> 8) & 0xff;
+
+	/* If user set max rate, dont allow higher than user constrain */
+	if ((lq_sta->max_rate_idx != -1) &&
+	    (lq_sta->max_rate_idx < high))
+		high = IWL_RATE_INVALID;
+
+	sr = window->success_ratio;
+
+	/* Collect measured throughputs for current and adjacent rates */
+	current_tpt = window->average_tpt;
+	if (low != IWL_RATE_INVALID)
+		low_tpt = tbl->win[low].average_tpt;
+	if (high != IWL_RATE_INVALID)
+		high_tpt = tbl->win[high].average_tpt;
+
+	scale_action = 0;
+
+	/* Too many failures, decrease rate */
+	if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
+		IWL_DEBUG_RATE(mvm,
+			       "decrease rate because of low success_ratio\n");
+		scale_action = -1;
+	/* No throughput measured yet for adjacent rates; try increase. */
+	} else if ((low_tpt == IWL_INVALID_VALUE) &&
+		   (high_tpt == IWL_INVALID_VALUE)) {
+		if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+			scale_action = 1;
+		else if (low != IWL_RATE_INVALID)
+			scale_action = 0;
+	}
+
+	/* Both adjacent throughputs are measured, but neither one has better
+	 * throughput; we're using the best rate, don't change it! */
+	else if ((low_tpt != IWL_INVALID_VALUE) &&
+		 (high_tpt != IWL_INVALID_VALUE) &&
+		 (low_tpt < current_tpt) &&
+		 (high_tpt < current_tpt))
+		scale_action = 0;
+
+	/* At least one adjacent rate's throughput is measured,
+	 * and may have better performance. */
+	else {
+		/* Higher adjacent rate's throughput is measured */
+		if (high_tpt != IWL_INVALID_VALUE) {
+			/* Higher rate has better throughput */
+			if (high_tpt > current_tpt &&
+			    sr >= IWL_RATE_INCREASE_TH) {
+				scale_action = 1;
+			} else {
+				scale_action = 0;
+			}
+
+		/* Lower adjacent rate's throughput is measured */
+		} else if (low_tpt != IWL_INVALID_VALUE) {
+			/* Lower rate has better throughput */
+			if (low_tpt > current_tpt) {
+				IWL_DEBUG_RATE(mvm,
+					       "decrease rate because of low tpt\n");
+				scale_action = -1;
+			} else if (sr >= IWL_RATE_INCREASE_TH) {
+				scale_action = 1;
+			}
+		}
+	}
+
+	/* Sanity check; asked for decrease, but success rate or throughput
+	 * has been good at old rate.  Don't change it. */
+	if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+	    ((sr > IWL_RATE_HIGH_TH) ||
+	     (current_tpt > (100 * tbl->expected_tpt[low]))))
+		scale_action = 0;
+
+	switch (scale_action) {
+	case -1:
+		/* Decrease starting rate, update uCode's rate table */
+		if (low != IWL_RATE_INVALID) {
+			update_lq = 1;
+			index = low;
+		}
+
+		break;
+	case 1:
+		/* Increase starting rate, update uCode's rate table */
+		if (high != IWL_RATE_INVALID) {
+			update_lq = 1;
+			index = high;
+		}
+
+		break;
+	case 0:
+		/* No change */
+	default:
+		break;
+	}
+
+	IWL_DEBUG_RATE(mvm,
+		       "choose rate scale index %d action %d low %d high %d type %d\n",
+		       index, scale_action, low, high, tbl->lq_type);
+
+lq_update:
+	/* Replace uCode's rate table for the destination station. */
+	if (update_lq)
+		rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green);
+
+	rs_stay_in_table(lq_sta, false);
+
+	/*
+	 * Search for new modulation mode if we're:
+	 * 1)  Not changing rates right now
+	 * 2)  Not just finishing up a search
+	 * 3)  Allowing a new search
+	 */
+	if (!update_lq && !done_search &&
+	    !lq_sta->stay_in_tbl && window->counter) {
+		/* Save current throughput to compare with "search" throughput*/
+		lq_sta->last_tpt = current_tpt;
+
+		/* Select a new "search" modulation mode to try.
+		 * If one is found, set up the new "search" table. */
+		if (is_legacy(tbl->lq_type))
+			rs_move_legacy_other(mvm, lq_sta, sta, index);
+		else if (is_siso(tbl->lq_type))
+			rs_move_siso_to_other(mvm, lq_sta, sta, index);
+		else if (is_mimo2(tbl->lq_type))
+			rs_move_mimo2_to_other(mvm, lq_sta, sta, index);
+		else
+			rs_move_mimo3_to_other(mvm, lq_sta, sta, index);
+
+		/* If new "search" mode was selected, set up in uCode table */
+		if (lq_sta->search_better_tbl) {
+			/* Access the "search" table, clear its history. */
+			tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+			for (i = 0; i < IWL_RATE_COUNT; i++)
+				rs_rate_scale_clear_window(&(tbl->win[i]));
+
+			/* Use new "search" start rate */
+			index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+
+			IWL_DEBUG_RATE(mvm,
+				       "Switch current  mcs: %X index: %d\n",
+				       tbl->current_rate, index);
+			rs_fill_link_cmd(mvm, lq_sta, tbl->current_rate);
+			iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
+		} else {
+			done_search = 1;
+		}
+	}
+
+	if (done_search && !lq_sta->stay_in_tbl) {
+		/* If the "active" (non-search) mode was legacy,
+		 * and we've tried switching antennas,
+		 * but we haven't been able to try HT modes (not available),
+		 * stay with best antenna legacy modulation for a while
+		 * before next round of mode comparisons. */
+		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
+		if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported &&
+		    lq_sta->action_counter > tbl1->max_search) {
+			IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n");
+			rs_set_stay_in_table(mvm, 1, lq_sta);
+		}
+
+		/* If we're in an HT mode, and all 3 mode switch actions
+		 * have been tried and compared, stay in this best modulation
+		 * mode for a while before next round of mode comparisons. */
+		if (lq_sta->enable_counter &&
+		    (lq_sta->action_counter >= tbl1->max_search)) {
+			if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
+			    (lq_sta->tx_agg_tid_en & (1 << tid)) &&
+			    (tid != IWL_MAX_TID_COUNT)) {
+				tid_data = &sta_priv->tid_data[tid];
+				if (tid_data->state == IWL_AGG_OFF) {
+					IWL_DEBUG_RATE(mvm,
+						       "try to aggregate tid %d\n",
+						       tid);
+					rs_tl_turn_on_agg(mvm, tid,
+							  lq_sta, sta);
+				}
+			}
+			rs_set_stay_in_table(mvm, 0, lq_sta);
+		}
+	}
+
+out:
+	tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green);
+	lq_sta->last_txrate_idx = index;
+}
+
+/**
+ * rs_initialize_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
+ */
+static void rs_initialize_lq(struct iwl_mvm *mvm,
+			     struct ieee80211_sta *sta,
+			     struct iwl_lq_sta *lq_sta,
+			     enum ieee80211_band band)
+{
+	struct iwl_scale_tbl_info *tbl;
+	int rate_idx;
+	int i;
+	u32 rate;
+	u8 use_green = rs_use_green(sta);
+	u8 active_tbl = 0;
+	u8 valid_tx_ant;
+
+	if (!sta || !lq_sta)
+		return;
+
+	i = lq_sta->last_txrate_idx;
+
+	valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+
+	if (!lq_sta->search_better_tbl)
+		active_tbl = lq_sta->active_tbl;
+	else
+		active_tbl = 1 - lq_sta->active_tbl;
+
+	tbl = &(lq_sta->lq_info[active_tbl]);
+
+	if ((i < 0) || (i >= IWL_RATE_COUNT))
+		i = 0;
+
+	rate = iwl_rates[i].plcp;
+	tbl->ant_type = first_antenna(valid_tx_ant);
+	rate |= tbl->ant_type << RATE_MCS_ANT_POS;
+
+	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+		rate |= RATE_MCS_CCK_MSK;
+
+	rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx);
+	if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
+		rs_toggle_antenna(valid_tx_ant, &rate, tbl);
+
+	rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx, use_green);
+	tbl->current_rate = rate;
+	rs_set_expected_tpt_table(lq_sta, tbl);
+	rs_fill_link_cmd(NULL, lq_sta, rate);
+	/* TODO restore station should remember the lq cmd */
+	iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true);
+}
+
+static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
+			struct ieee80211_tx_rate_control *txrc)
+{
+	struct sk_buff *skb = txrc->skb;
+	struct ieee80211_supported_band *sband = txrc->sband;
+	struct iwl_op_mode *op_mode __maybe_unused =
+			(struct iwl_op_mode *)mvm_r;
+	struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_lq_sta *lq_sta = mvm_sta;
+	int rate_idx;
+
+	IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n");
+
+	/* Get max rate if user set max rate */
+	if (lq_sta) {
+		lq_sta->max_rate_idx = txrc->max_rate_idx;
+		if ((sband->band == IEEE80211_BAND_5GHZ) &&
+		    (lq_sta->max_rate_idx != -1))
+			lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
+		if ((lq_sta->max_rate_idx < 0) ||
+		    (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
+			lq_sta->max_rate_idx = -1;
+	}
+
+	/* Treat uninitialized rate scaling data same as non-existing. */
+	if (lq_sta && !lq_sta->drv) {
+		IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
+		mvm_sta = NULL;
+	}
+
+	/* Send management frames and NO_ACK data using lowest rate. */
+	if (rate_control_send_low(sta, mvm_sta, txrc))
+		return;
+
+	rate_idx  = lq_sta->last_txrate_idx;
+
+	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_CHAN_WIDTH_40) /* TODO */
+			info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		if (lq_sta->last_rate_n_flags & RATE_HT_MCS_GF_MSK)
+			info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
+	} else {
+		/* Check for invalid rates */
+		if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
+		    ((sband->band == IEEE80211_BAND_5GHZ) &&
+		     (rate_idx < IWL_FIRST_OFDM_RATE)))
+			rate_idx = rate_lowest_index(sband, sta);
+		/* On valid 5 GHz rate, adjust index */
+		else if (sband->band == IEEE80211_BAND_5GHZ)
+			rate_idx -= IWL_FIRST_OFDM_RATE;
+		info->control.rates[0].flags = 0;
+	}
+	info->control.rates[0].idx = rate_idx;
+}
+
+static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
+			  gfp_t gfp)
+{
+	struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
+	struct iwl_op_mode *op_mode __maybe_unused =
+			(struct iwl_op_mode *)mvm_rate;
+	struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
+
+	IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
+
+	return &sta_priv->lq_sta;
+}
+
+/*
+ * Called after adding a new station to initialize rate scaling
+ */
+void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+			  enum ieee80211_band band)
+{
+	int i, j;
+	struct ieee80211_hw *hw = mvm->hw;
+	struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+	struct iwl_mvm_sta *sta_priv;
+	struct iwl_lq_sta *lq_sta;
+	struct ieee80211_supported_band *sband;
+	unsigned long supp; /* must be unsigned long for for_each_set_bit */
+
+	sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
+	lq_sta = &sta_priv->lq_sta;
+	sband = hw->wiphy->bands[band];
+
+	lq_sta->lq.sta_id = sta_priv->sta_id;
+
+	for (j = 0; j < LQ_SIZE; j++)
+		for (i = 0; i < IWL_RATE_COUNT; i++)
+			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+
+	lq_sta->flush_timer = 0;
+	lq_sta->supp_rates = sta->supp_rates[sband->band];
+	for (j = 0; j < LQ_SIZE; j++)
+		for (i = 0; i < IWL_RATE_COUNT; i++)
+			rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+
+	IWL_DEBUG_RATE(mvm,
+		       "LQ: *** rate scale station global init for station %d ***\n",
+		       sta_priv->sta_id);
+	/* TODO: what is a good starting rate for STA? About middle? Maybe not
+	 * the lowest or the highest rate.. Could consider using RSSI from
+	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
+	 * after assoc.. */
+
+	lq_sta->max_rate_idx = -1;
+	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
+	lq_sta->is_green = rs_use_green(sta);
+	lq_sta->band = sband->band;
+	/*
+	 * active legacy rates as per supported rates bitmap
+	 */
+	supp = sta->supp_rates[sband->band];
+	lq_sta->active_legacy_rate = 0;
+	for_each_set_bit(i, &supp, BITS_PER_LONG)
+		lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
+
+	/*
+	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
+	 */
+	lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+	lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
+	lq_sta->active_siso_rate &= ~((u16)0x2);
+	lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+
+	/* Same here */
+	lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+	lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
+	lq_sta->active_mimo2_rate &= ~((u16)0x2);
+	lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+	lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
+	lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
+	lq_sta->active_mimo3_rate &= ~((u16)0x2);
+	lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
+
+	IWL_DEBUG_RATE(mvm,
+		       "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
+		       lq_sta->active_siso_rate,
+		       lq_sta->active_mimo2_rate,
+		       lq_sta->active_mimo3_rate);
+
+	/* These values will be overridden later */
+	lq_sta->lq.single_stream_ant_msk =
+		first_antenna(mvm->nvm_data->valid_tx_ant);
+	lq_sta->lq.dual_stream_ant_msk =
+		mvm->nvm_data->valid_tx_ant &
+		~first_antenna(mvm->nvm_data->valid_tx_ant);
+	if (!lq_sta->lq.dual_stream_ant_msk) {
+		lq_sta->lq.dual_stream_ant_msk = ANT_AB;
+	} else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) {
+		lq_sta->lq.dual_stream_ant_msk =
+			mvm->nvm_data->valid_tx_ant;
+	}
+
+	/* as default allow aggregation for all tids */
+	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
+	lq_sta->drv = mvm;
+
+	/* Set last_txrate_idx to lowest rate */
+	lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
+	if (sband->band == IEEE80211_BAND_5GHZ)
+		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+	lq_sta->is_agg = 0;
+#ifdef CONFIG_MAC80211_DEBUGFS
+	lq_sta->dbg_fixed_rate = 0;
+#endif
+
+	rs_initialize_lq(mvm, sta, lq_sta, band);
+}
+
+static void rs_fill_link_cmd(struct iwl_mvm *mvm,
+			     struct iwl_lq_sta *lq_sta, u32 new_rate)
+{
+	struct iwl_scale_tbl_info tbl_type;
+	int index = 0;
+	int rate_idx;
+	int repeat_rate = 0;
+	u8 ant_toggle_cnt = 0;
+	u8 use_ht_possible = 1;
+	u8 valid_tx_ant = 0;
+	struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+
+	/* Override starting rate (index 0) if needed for debug purposes */
+	rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+	/* Interpret new_rate (rate_n_flags) */
+	rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
+				 &tbl_type, &rate_idx);
+
+	/* How many times should we repeat the initial rate? */
+	if (is_legacy(tbl_type.lq_type)) {
+		ant_toggle_cnt = 1;
+		repeat_rate = IWL_NUMBER_TRY;
+	} else {
+		repeat_rate = min(IWL_HT_NUMBER_TRY,
+				  LINK_QUAL_AGG_DISABLE_START_DEF - 1);
+	}
+
+	lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0;
+
+	/* Fill 1st table entry (index 0) */
+	lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+
+	if (num_of_ant(tbl_type.ant_type) == 1)
+		lq_cmd->single_stream_ant_msk = tbl_type.ant_type;
+	else if (num_of_ant(tbl_type.ant_type) == 2)
+		lq_cmd->dual_stream_ant_msk = tbl_type.ant_type;
+	/* otherwise we don't modify the existing value */
+
+	index++;
+	repeat_rate--;
+	if (mvm)
+		valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+
+	/* Fill rest of rate table */
+	while (index < LINK_QUAL_MAX_RETRY_NUM) {
+		/* Repeat initial/next rate.
+		 * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
+		 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
+		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+			if (is_legacy(tbl_type.lq_type)) {
+				if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+					ant_toggle_cnt++;
+				else if (mvm &&
+					 rs_toggle_antenna(valid_tx_ant,
+							&new_rate, &tbl_type))
+					ant_toggle_cnt = 1;
+			}
+
+			/* Override next rate if needed for debug purposes */
+			rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+			/* Fill next table entry */
+			lq_cmd->rs_table[index] =
+					cpu_to_le32(new_rate);
+			repeat_rate--;
+			index++;
+		}
+
+		rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
+					 &rate_idx);
+
+
+		/* Indicate to uCode which entries might be MIMO.
+		 * If initial rate was MIMO, this will finally end up
+		 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
+		if (is_mimo(tbl_type.lq_type))
+			lq_cmd->mimo_delim = index;
+
+		/* Get next rate */
+		new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
+					     use_ht_possible);
+
+		/* How many times should we repeat the next rate? */
+		if (is_legacy(tbl_type.lq_type)) {
+			if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+				ant_toggle_cnt++;
+			else if (mvm &&
+				 rs_toggle_antenna(valid_tx_ant,
+						   &new_rate, &tbl_type))
+				ant_toggle_cnt = 1;
+
+			repeat_rate = IWL_NUMBER_TRY;
+		} else {
+			repeat_rate = IWL_HT_NUMBER_TRY;
+		}
+
+		/* Don't allow HT rates after next pass.
+		 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
+		use_ht_possible = 0;
+
+		/* Override next rate if needed for debug purposes */
+		rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+		/* Fill next table entry */
+		lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+
+		index++;
+		repeat_rate--;
+	}
+
+	lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+	lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+
+	lq_cmd->agg_time_limit =
+		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+}
+
+static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+	return hw->priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *mvm_rate)
+{
+	return;
+}
+
+static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
+			void *mvm_sta)
+{
+	struct iwl_op_mode *op_mode __maybe_unused = mvm_r;
+	struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
+
+	IWL_DEBUG_RATE(mvm, "enter\n");
+	IWL_DEBUG_RATE(mvm, "leave\n");
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+			     u32 *rate_n_flags, int index)
+{
+	struct iwl_mvm *mvm;
+	u8 valid_tx_ant;
+	u8 ant_sel_tx;
+
+	mvm = lq_sta->drv;
+	valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+	if (lq_sta->dbg_fixed_rate) {
+		ant_sel_tx =
+		  ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
+		  >> RATE_MCS_ANT_POS);
+		if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
+			*rate_n_flags = lq_sta->dbg_fixed_rate;
+			IWL_DEBUG_RATE(mvm, "Fixed rate ON\n");
+		} else {
+			lq_sta->dbg_fixed_rate = 0;
+			IWL_ERR(mvm,
+				"Invalid antenna selection 0x%X, Valid is 0x%X\n",
+				ant_sel_tx, valid_tx_ant);
+			IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
+		}
+	} else {
+		IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
+	}
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+			const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct iwl_lq_sta *lq_sta = file->private_data;
+	struct iwl_mvm *mvm;
+	char buf[64];
+	size_t buf_size;
+	u32 parsed_rate;
+
+
+	mvm = lq_sta->drv;
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%x", &parsed_rate) == 1)
+		lq_sta->dbg_fixed_rate = parsed_rate;
+	else
+		lq_sta->dbg_fixed_rate = 0;
+
+	rs_program_fix_rate(mvm, lq_sta);
+
+	return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char *buff;
+	int desc = 0;
+	int i = 0;
+	int index = 0;
+	ssize_t ret;
+
+	struct iwl_lq_sta *lq_sta = file->private_data;
+	struct iwl_mvm *mvm;
+	struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+
+	mvm = lq_sta->drv;
+	buff = kmalloc(1024, GFP_KERNEL);
+	if (!buff)
+		return -ENOMEM;
+
+	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
+	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+			lq_sta->total_failed, lq_sta->total_success,
+			lq_sta->active_legacy_rate);
+	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+			lq_sta->dbg_fixed_rate);
+	desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
+	    (mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "",
+	    (mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "",
+	    (mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+	desc += sprintf(buff+desc, "lq type %s\n",
+	   (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
+	if (is_Ht(tbl->lq_type)) {
+		desc += sprintf(buff+desc, " %s",
+		   (is_siso(tbl->lq_type)) ? "SISO" :
+		   ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
+		   desc += sprintf(buff+desc, " %s",
+		   (tbl->is_ht40) ? "40MHz" : "20MHz");
+		   desc += sprintf(buff+desc, " %s %s %s\n",
+				   (tbl->is_SGI) ? "SGI" : "",
+		   (lq_sta->is_green) ? "GF enabled" : "",
+		   (lq_sta->is_agg) ? "AGG on" : "");
+	}
+	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
+			lq_sta->last_rate_n_flags);
+	desc += sprintf(buff+desc,
+			"general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+			lq_sta->lq.flags,
+			lq_sta->lq.mimo_delim,
+			lq_sta->lq.single_stream_ant_msk,
+			lq_sta->lq.dual_stream_ant_msk);
+
+	desc += sprintf(buff+desc,
+			"agg: time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+			le16_to_cpu(lq_sta->lq.agg_time_limit),
+			lq_sta->lq.agg_disable_start_th,
+			lq_sta->lq.agg_frame_cnt_limit);
+
+	desc += sprintf(buff+desc,
+			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+			lq_sta->lq.initial_rate_index[0],
+			lq_sta->lq.initial_rate_index[1],
+			lq_sta->lq.initial_rate_index[2],
+			lq_sta->lq.initial_rate_index[3]);
+
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+		index = iwl_hwrate_to_plcp_idx(
+			le32_to_cpu(lq_sta->lq.rs_table[i]));
+		if (is_legacy(tbl->lq_type)) {
+			desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
+					i, le32_to_cpu(lq_sta->lq.rs_table[i]),
+					iwl_rate_mcs[index].mbps);
+		} else {
+			desc += sprintf(buff+desc,
+					" rate[%d] 0x%X %smbps (%s)\n",
+					i, le32_to_cpu(lq_sta->lq.rs_table[i]),
+					iwl_rate_mcs[index].mbps,
+					iwl_rate_mcs[index].mcs);
+		}
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+	kfree(buff);
+	return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+	.write = rs_sta_dbgfs_scale_table_write,
+	.read = rs_sta_dbgfs_scale_table_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char *buff;
+	int desc = 0;
+	int i, j;
+	ssize_t ret;
+
+	struct iwl_lq_sta *lq_sta = file->private_data;
+
+	buff = kmalloc(1024, GFP_KERNEL);
+	if (!buff)
+		return -ENOMEM;
+
+	for (i = 0; i < LQ_SIZE; i++) {
+		desc += sprintf(buff+desc,
+				"%s type=%d SGI=%d HT40=%d DUP=0 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_ht40,
+				lq_sta->is_green,
+				lq_sta->lq_info[i].current_rate);
+		for (j = 0; j < IWL_RATE_COUNT; j++) {
+			desc += sprintf(buff+desc,
+				"counter=%d success=%d %%=%d\n",
+				lq_sta->lq_info[i].win[j].counter,
+				lq_sta->lq_info[i].win[j].success_counter,
+				lq_sta->lq_info[i].win[j].success_ratio);
+		}
+	}
+	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+	kfree(buff);
+	return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+	.read = rs_sta_dbgfs_stats_table_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct iwl_lq_sta *lq_sta = file->private_data;
+	struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+	char buff[120];
+	int desc = 0;
+
+	if (is_Ht(tbl->lq_type))
+		desc += sprintf(buff+desc,
+				"Bit Rate= %d Mb/s\n",
+				tbl->expected_tpt[lq_sta->last_txrate_idx]);
+	else
+		desc += sprintf(buff+desc,
+				"Bit Rate= %d Mb/s\n",
+				iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
+	.read = rs_sta_dbgfs_rate_scale_data_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+
+static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
+{
+	struct iwl_lq_sta *lq_sta = mvm_sta;
+	lq_sta->rs_sta_dbgfs_scale_table_file =
+		debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
+				    lq_sta, &rs_sta_dbgfs_scale_table_ops);
+	lq_sta->rs_sta_dbgfs_stats_table_file =
+		debugfs_create_file("rate_stats_table", S_IRUSR, dir,
+				    lq_sta, &rs_sta_dbgfs_stats_table_ops);
+	lq_sta->rs_sta_dbgfs_rate_scale_data_file =
+		debugfs_create_file("rate_scale_data", S_IRUSR, dir,
+				    lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
+	lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
+		debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
+				  &lq_sta->tx_agg_tid_en);
+}
+
+static void rs_remove_debugfs(void *mvm, void *mvm_sta)
+{
+	struct iwl_lq_sta *lq_sta = mvm_sta;
+	debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+}
+#endif
+
+/*
+ * Initialization of rate scaling information is done by driver after
+ * the station is added. Since mac80211 calls this function before a
+ * station is added we ignore it.
+ */
+static void rs_rate_init_stub(void *mvm_r,
+				 struct ieee80211_supported_band *sband,
+				 struct ieee80211_sta *sta, void *mvm_sta)
+{
+}
+static struct rate_control_ops rs_mvm_ops = {
+	.module = NULL,
+	.name = RS_NAME,
+	.tx_status = rs_tx_status,
+	.get_rate = rs_get_rate,
+	.rate_init = rs_rate_init_stub,
+	.alloc = rs_alloc,
+	.free = rs_free,
+	.alloc_sta = rs_alloc_sta,
+	.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = rs_add_debugfs,
+	.remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwl_mvm_rate_control_register(void)
+{
+	return ieee80211_rate_control_register(&rs_mvm_ops);
+}
+
+void iwl_mvm_rate_control_unregister(void)
+{
+	ieee80211_rate_control_unregister(&rs_mvm_ops);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
new file mode 100644
index 0000000..219c685
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -0,0 +1,393 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __rs_h__
+#define __rs_h__
+
+#include <net/mac80211.h>
+
+#include "iwl-config.h"
+
+#include "fw-api.h"
+#include "iwl-trans.h"
+
+struct iwl_rs_rate_info {
+	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
+	u8 plcp_mimo2;	/* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
+	u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
+	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
+	u8 prev_ieee;    /* previous rate in IEEE speeds */
+	u8 next_ieee;    /* next rate in IEEE speeds */
+	u8 prev_rs;      /* previous rate used in rs algo */
+	u8 next_rs;      /* next rate used in rs algo */
+	u8 prev_rs_tgg;  /* previous rate used in TGG rs algo */
+	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
+};
+
+#define IWL_RATE_60M_PLCP 3
+
+enum {
+	IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+	IWL_RATE_INVALID = IWL_RATE_COUNT,
+};
+
+#define LINK_QUAL_MAX_RETRY_NUM 16
+
+enum {
+	IWL_RATE_6M_INDEX_TABLE = 0,
+	IWL_RATE_9M_INDEX_TABLE,
+	IWL_RATE_12M_INDEX_TABLE,
+	IWL_RATE_18M_INDEX_TABLE,
+	IWL_RATE_24M_INDEX_TABLE,
+	IWL_RATE_36M_INDEX_TABLE,
+	IWL_RATE_48M_INDEX_TABLE,
+	IWL_RATE_54M_INDEX_TABLE,
+	IWL_RATE_1M_INDEX_TABLE,
+	IWL_RATE_2M_INDEX_TABLE,
+	IWL_RATE_5M_INDEX_TABLE,
+	IWL_RATE_11M_INDEX_TABLE,
+	IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define	IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
+#define	IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
+#define	IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
+#define	IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
+#define	IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
+#define	IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
+#define	IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
+#define	IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK  (1 << IWL_RATE_60M_INDEX)
+#define	IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
+#define	IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
+#define	IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
+#define	IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
+
+
+/* uCode API values for OFDM high-throughput (HT) bit rates */
+enum {
+	IWL_RATE_SISO_6M_PLCP = 0,
+	IWL_RATE_SISO_12M_PLCP = 1,
+	IWL_RATE_SISO_18M_PLCP = 2,
+	IWL_RATE_SISO_24M_PLCP = 3,
+	IWL_RATE_SISO_36M_PLCP = 4,
+	IWL_RATE_SISO_48M_PLCP = 5,
+	IWL_RATE_SISO_54M_PLCP = 6,
+	IWL_RATE_SISO_60M_PLCP = 7,
+	IWL_RATE_MIMO2_6M_PLCP  = 0x8,
+	IWL_RATE_MIMO2_12M_PLCP = 0x9,
+	IWL_RATE_MIMO2_18M_PLCP = 0xa,
+	IWL_RATE_MIMO2_24M_PLCP = 0xb,
+	IWL_RATE_MIMO2_36M_PLCP = 0xc,
+	IWL_RATE_MIMO2_48M_PLCP = 0xd,
+	IWL_RATE_MIMO2_54M_PLCP = 0xe,
+	IWL_RATE_MIMO2_60M_PLCP = 0xf,
+	IWL_RATE_MIMO3_6M_PLCP  = 0x10,
+	IWL_RATE_MIMO3_12M_PLCP = 0x11,
+	IWL_RATE_MIMO3_18M_PLCP = 0x12,
+	IWL_RATE_MIMO3_24M_PLCP = 0x13,
+	IWL_RATE_MIMO3_36M_PLCP = 0x14,
+	IWL_RATE_MIMO3_48M_PLCP = 0x15,
+	IWL_RATE_MIMO3_54M_PLCP = 0x16,
+	IWL_RATE_MIMO3_60M_PLCP = 0x17,
+	IWL_RATE_SISO_INVM_PLCP,
+	IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+	IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+/* MAC header values for bit rates */
+enum {
+	IWL_RATE_6M_IEEE  = 12,
+	IWL_RATE_9M_IEEE  = 18,
+	IWL_RATE_12M_IEEE = 24,
+	IWL_RATE_18M_IEEE = 36,
+	IWL_RATE_24M_IEEE = 48,
+	IWL_RATE_36M_IEEE = 72,
+	IWL_RATE_48M_IEEE = 96,
+	IWL_RATE_54M_IEEE = 108,
+	IWL_RATE_60M_IEEE = 120,
+	IWL_RATE_1M_IEEE  = 2,
+	IWL_RATE_2M_IEEE  = 4,
+	IWL_RATE_5M_IEEE  = 11,
+	IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
+
+#define IWL_INVALID_VALUE    -1
+
+#define IWL_MIN_RSSI_VAL                 -100
+#define IWL_MAX_RSSI_VAL                    0
+
+/* These values specify how many Tx frame attempts before
+ * searching for a new modulation mode */
+#define IWL_LEGACY_FAILURE_LIMIT	160
+#define IWL_LEGACY_SUCCESS_LIMIT	480
+#define IWL_LEGACY_TABLE_COUNT		160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT	400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
+#define IWL_NONE_LEGACY_TABLE_COUNT	1500
+
+/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
+#define IWL_RS_GOOD_RATIO		12800	/* 100% */
+#define IWL_RATE_SCALE_SWITCH		10880	/*  85% */
+#define IWL_RATE_HIGH_TH		10880	/*  85% */
+#define IWL_RATE_INCREASE_TH		6400	/*  50% */
+#define IWL_RATE_DECREASE_TH		1920	/*  15% */
+
+/* possible actions when in legacy mode */
+#define IWL_LEGACY_SWITCH_ANTENNA1      0
+#define IWL_LEGACY_SWITCH_ANTENNA2      1
+#define IWL_LEGACY_SWITCH_SISO          2
+#define IWL_LEGACY_SWITCH_MIMO2_AB      3
+#define IWL_LEGACY_SWITCH_MIMO2_AC      4
+#define IWL_LEGACY_SWITCH_MIMO2_BC      5
+#define IWL_LEGACY_SWITCH_MIMO3_ABC     6
+
+/* possible actions when in siso mode */
+#define IWL_SISO_SWITCH_ANTENNA1        0
+#define IWL_SISO_SWITCH_ANTENNA2        1
+#define IWL_SISO_SWITCH_MIMO2_AB        2
+#define IWL_SISO_SWITCH_MIMO2_AC        3
+#define IWL_SISO_SWITCH_MIMO2_BC        4
+#define IWL_SISO_SWITCH_GI              5
+#define IWL_SISO_SWITCH_MIMO3_ABC       6
+
+
+/* possible actions when in mimo mode */
+#define IWL_MIMO2_SWITCH_ANTENNA1       0
+#define IWL_MIMO2_SWITCH_ANTENNA2       1
+#define IWL_MIMO2_SWITCH_SISO_A         2
+#define IWL_MIMO2_SWITCH_SISO_B         3
+#define IWL_MIMO2_SWITCH_SISO_C         4
+#define IWL_MIMO2_SWITCH_GI             5
+#define IWL_MIMO2_SWITCH_MIMO3_ABC      6
+
+
+/* possible actions when in mimo3 mode */
+#define IWL_MIMO3_SWITCH_ANTENNA1       0
+#define IWL_MIMO3_SWITCH_ANTENNA2       1
+#define IWL_MIMO3_SWITCH_SISO_A         2
+#define IWL_MIMO3_SWITCH_SISO_B         3
+#define IWL_MIMO3_SWITCH_SISO_C         4
+#define IWL_MIMO3_SWITCH_MIMO2_AB       5
+#define IWL_MIMO3_SWITCH_MIMO2_AC       6
+#define IWL_MIMO3_SWITCH_MIMO2_BC       7
+#define IWL_MIMO3_SWITCH_GI             8
+
+
+#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
+#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
+
+/*FIXME:RS:add possible actions for MIMO3*/
+
+#define IWL_ACTION_LIMIT		3	/* # possible actions */
+
+#define LINK_QUAL_AGG_TIME_LIMIT_DEF	(4000) /* 4 milliseconds */
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX	(8000)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN	(100)
+
+#define LINK_QUAL_AGG_DISABLE_START_DEF	(3)
+#define LINK_QUAL_AGG_DISABLE_START_MAX	(255)
+#define LINK_QUAL_AGG_DISABLE_START_MIN	(0)
+
+#define LINK_QUAL_AGG_FRAME_LIMIT_DEF	(63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX	(63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MIN	(0)
+
+#define LQ_SIZE		2	/* 2 mode tables:  "Active" and "Search" */
+
+/* load per tid defines for A-MPDU activation */
+#define IWL_AGG_TPT_THREHOLD	0
+#define IWL_AGG_LOAD_THRESHOLD	10
+#define IWL_AGG_ALL_TID		0xff
+#define TID_QUEUE_CELL_SPACING	50	/*mS */
+#define TID_QUEUE_MAX_SIZE	20
+#define TID_ROUND_VALUE		5	/* mS */
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+enum iwl_table_type {
+	LQ_NONE,
+	LQ_G,		/* legacy types */
+	LQ_A,
+	LQ_SISO,	/* high-throughput types */
+	LQ_MIMO2,
+	LQ_MIMO3,
+	LQ_MAX,
+};
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) ((tbl) == LQ_SISO)
+#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
+#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
+#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) ((tbl) == LQ_A)
+#define is_g_and(tbl) ((tbl) == LQ_G)
+
+#define IWL_MAX_MCS_DISPLAY_SIZE	12
+
+struct iwl_rate_mcs_info {
+	char	mbps[IWL_MAX_MCS_DISPLAY_SIZE];
+	char	mcs[IWL_MAX_MCS_DISPLAY_SIZE];
+};
+
+/**
+ * struct iwl_rate_scale_data -- tx success history for one rate
+ */
+struct iwl_rate_scale_data {
+	u64 data;		/* bitmap of successful frames */
+	s32 success_counter;	/* number of frames successful */
+	s32 success_ratio;	/* per-cent * 128  */
+	s32 counter;		/* number of frames attempted */
+	s32 average_tpt;	/* success ratio * expected throughput */
+	unsigned long stamp;
+};
+
+/**
+ * struct iwl_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_lq_sta,
+ * one for "active", and one for "search".
+ */
+struct iwl_scale_tbl_info {
+	enum iwl_table_type lq_type;
+	u8 ant_type;
+	u8 is_SGI;	/* 1 = short guard interval */
+	u8 is_ht40;	/* 1 = 40 MHz channel width */
+	u8 action;	/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+	u8 max_search;	/* maximun number of tables we can search */
+	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
+	u32 current_rate;  /* rate_n_flags, uCode API format */
+	struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+};
+
+struct iwl_traffic_load {
+	unsigned long time_stamp;	/* age of the oldest statistics */
+	u32 packet_count[TID_QUEUE_MAX_SIZE];   /* packet count in this time
+						 * slice */
+	u32 total;			/* total num of packets during the
+					 * last TID_MAX_TIME_DIFF */
+	u8 queue_count;			/* number of queues that has
+					 * been used since the last cleanup */
+	u8 head;			/* start of the circular buffer */
+};
+
+/**
+ * struct iwl_lq_sta -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl_lq_sta {
+	u8 active_tbl;		/* index of active table, range 0-1 */
+	u8 enable_counter;	/* indicates HT mode */
+	u8 stay_in_tbl;		/* 1: disallow, 0: allow search for new mode */
+	u8 search_better_tbl;	/* 1: currently trying alternate mode */
+	s32 last_tpt;
+
+	/* The following determine when to search for a new mode */
+	u32 table_count_limit;
+	u32 max_failure_limit;	/* # failed frames before new search */
+	u32 max_success_limit;	/* # successful frames before new search */
+	u32 table_count;
+	u32 total_failed;	/* total failed frames, any/all rates */
+	u32 total_success;	/* total successful frames, any/all rates */
+	u64 flush_timer;	/* time staying in mode before new search */
+
+	u8 action_counter;	/* # mode-switch actions tried */
+	u8 is_green;
+	enum ieee80211_band band;
+
+	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
+	u32 supp_rates;
+	u16 active_legacy_rate;
+	u16 active_siso_rate;
+	u16 active_mimo2_rate;
+	u16 active_mimo3_rate;
+	s8 max_rate_idx;     /* Max rate set by user */
+	u8 missed_rate_counter;
+
+	struct iwl_lq_cmd lq;
+	struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+	struct iwl_traffic_load load[IWL_MAX_TID_COUNT];
+	u8 tx_agg_tid_en;
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *rs_sta_dbgfs_scale_table_file;
+	struct dentry *rs_sta_dbgfs_stats_table_file;
+	struct dentry *rs_sta_dbgfs_rate_scale_data_file;
+	struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+	u32 dbg_fixed_rate;
+#endif
+	struct iwl_mvm *drv;
+
+	/* used to be in sta_info */
+	int last_txrate_idx;
+	/* last tx rate_n_flags */
+	u32 last_rate_n_flags;
+	/* packets destined for this STA are aggregated */
+	u8 is_agg;
+	/* BT traffic this sta was last updated in */
+	u8 last_bt_traffic;
+};
+
+static inline u8 num_of_ant(u8 mask)
+{
+	return  !!((mask) & ANT_A) +
+		!!((mask) & ANT_B) +
+		!!((mask) & ANT_C);
+}
+
+/* Initialize station's rate scaling information after adding station */
+extern void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm,
+				 struct ieee80211_sta *sta,
+				 enum ieee80211_band band);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module.  The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem.  This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern int iwl_mvm_rate_control_register(void);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_mvm_rate_control_unregister(void);
+
+#endif /* __rs__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
new file mode 100644
index 0000000..3f40ab0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -0,0 +1,356 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *****************************************************************************/
+#include "iwl-trans.h"
+
+#include "mvm.h"
+#include "fw-api.h"
+
+/*
+ * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler
+ *
+ * Copies the phy information in mvm->last_phy_info, it will be used when the
+ * actual data will come from the fw in the next packet.
+ */
+int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+	memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
+	mvm->ampdu_ref++;
+	return 0;
+}
+
+/*
+ * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211
+ *
+ * Adds the rxb to a new skb and give it to mac80211
+ */
+static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
+					    struct ieee80211_hdr *hdr, u16 len,
+					    u32 ampdu_status,
+					    struct iwl_rx_cmd_buffer *rxb,
+					    struct ieee80211_rx_status *stats)
+{
+	struct sk_buff *skb;
+	unsigned int hdrlen, fraglen;
+
+	/* Dont use dev_alloc_skb(), we'll have enough headroom once
+	 * ieee80211_hdr pulled.
+	 */
+	skb = alloc_skb(128, GFP_ATOMIC);
+	if (!skb) {
+		IWL_ERR(mvm, "alloc_skb failed\n");
+		return;
+	}
+	/* If frame is small enough to fit in skb->head, pull it completely.
+	 * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
+	 * are more efficient.
+	 */
+	hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
+
+	memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
+	fraglen = len - hdrlen;
+
+	if (fraglen) {
+		int offset = (void *)hdr + hdrlen -
+			     rxb_addr(rxb) + rxb_offset(rxb);
+
+		skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
+				fraglen, rxb->truesize);
+	}
+
+	memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+	ieee80211_rx_ni(mvm->hw, skb);
+}
+
+/*
+ * iwl_mvm_calc_rssi - calculate the rssi in dBm
+ * @phy_info: the phy information for the coming packet
+ */
+static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm,
+			     struct iwl_rx_phy_info *phy_info)
+{
+	u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db;
+	u32 val;
+
+	/* Find max rssi among 3 possible receivers.
+	 * These values are measured by the Digital Signal Processor (DSP).
+	 * They should stay fairly constant even as the signal strength varies,
+	 * if the radio's Automatic Gain Control (AGC) is working right.
+	 * AGC value (see below) will provide the "interesting" info.
+	 */
+	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);
+	rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;
+	rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS;
+	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]);
+	rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS;
+
+	val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]);
+	agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS;
+
+	max_rssi = max_t(u32, rssi_a, rssi_b);
+	max_rssi = max_t(u32, max_rssi, rssi_c);
+
+	IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+			rssi_a, rssi_b, rssi_c, max_rssi, agc_db);
+
+	/* dBm = max_rssi dB - agc dB - constant.
+	 * Higher AGC (higher radio gain) means lower signal. */
+	return max_rssi - agc_db - IWL_RSSI_OFFSET;
+}
+
+/*
+ * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format
+ * @mvm: the mvm object
+ * @hdr: 80211 header
+ * @stats: status in mac80211's format
+ * @rx_pkt_status: status coming from fw
+ *
+ * returns non 0 value if the packet should be dropped
+ */
+static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
+					struct ieee80211_hdr *hdr,
+					struct ieee80211_rx_status *stats,
+					u32 rx_pkt_status)
+{
+	if (!ieee80211_has_protected(hdr->frame_control) ||
+	    (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
+			     RX_MPDU_RES_STATUS_SEC_NO_ENC)
+		return 0;
+
+	/* packet was encrypted with unknown alg */
+	if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
+					RX_MPDU_RES_STATUS_SEC_ENC_ERR)
+		return 0;
+
+	switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) {
+	case RX_MPDU_RES_STATUS_SEC_CCM_ENC:
+		/* alg is CCM: check MIC only */
+		if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
+			return -1;
+
+		stats->flag |= RX_FLAG_DECRYPTED;
+		IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n");
+		return 0;
+
+	case RX_MPDU_RES_STATUS_SEC_TKIP_ENC:
+		/* Don't drop the frame and decrypt it in SW */
+		if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
+			return 0;
+		/* fall through if TTAK OK */
+
+	case RX_MPDU_RES_STATUS_SEC_WEP_ENC:
+		if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK))
+			return -1;
+
+		stats->flag |= RX_FLAG_DECRYPTED;
+		return 0;
+
+	default:
+		IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
+	}
+
+	return 0;
+}
+
+/*
+ * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler
+ *
+ * Handles the actual data of the Rx packet from the fw
+ */
+int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+		       struct iwl_device_cmd *cmd)
+{
+	struct ieee80211_hdr *hdr;
+	struct ieee80211_rx_status rx_status = {};
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_rx_phy_info *phy_info;
+	struct iwl_rx_mpdu_res_start *rx_res;
+	u32 len;
+	u32 ampdu_status;
+	u32 rate_n_flags;
+	u32 rx_pkt_status;
+
+	phy_info = &mvm->last_phy_info;
+	rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
+	hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res));
+	len = le16_to_cpu(rx_res->byte_count);
+	rx_pkt_status = le32_to_cpup((__le32 *)
+		(pkt->data + sizeof(*rx_res) + len));
+
+	memset(&rx_status, 0, sizeof(rx_status));
+
+	/*
+	 * drop the packet if it has failed being decrypted by HW
+	 */
+	if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) {
+		IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",
+			       rx_pkt_status);
+		return 0;
+	}
+
+	if ((unlikely(phy_info->cfg_phy_cnt > 20))) {
+		IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n",
+			       phy_info->cfg_phy_cnt);
+		return 0;
+	}
+
+	if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) ||
+	    !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) {
+		IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status);
+		return 0;
+	}
+
+	/* This will be used in several places later */
+	rate_n_flags = le32_to_cpu(phy_info->rate_n_flags);
+
+	/* rx_status carries information about the packet to mac80211 */
+	rx_status.mactime = le64_to_cpu(phy_info->timestamp);
+	rx_status.device_timestamp = le32_to_cpu(phy_info->system_timestamp);
+	rx_status.band =
+		(phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
+				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+	rx_status.freq =
+		ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel),
+					       rx_status.band);
+	/*
+	 * TSF as indicated by the fw is at INA time, but mac80211 expects the
+	 * TSF at the beginning of the MPDU.
+	 */
+	/*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
+
+	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
+	rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info);
+
+	IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal,
+			      (unsigned long long)rx_status.mactime);
+
+	/*
+	 * "antenna number"
+	 *
+	 * It seems that the antenna field in the phy flags value
+	 * is actually a bit field. This is undefined by radiotap,
+	 * it wants an actual antenna number but I always get "7"
+	 * for most legacy frames I receive indicating that the
+	 * same frame was received on all three RX chains.
+	 *
+	 * I think this field should be removed in favor of a
+	 * new 802.11n radiotap field "RX chains" that is defined
+	 * as a bitmask.
+	 */
+	rx_status.antenna = (le16_to_cpu(phy_info->phy_flags) &
+				RX_RES_PHY_FLAGS_ANTENNA)
+				>> RX_RES_PHY_FLAGS_ANTENNA_POS;
+
+	/* set the preamble flag if appropriate */
+	if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
+		rx_status.flag |= RX_FLAG_SHORTPRE;
+
+	if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
+		/*
+		 * We know which subframes of an A-MPDU belong
+		 * together since we get a single PHY response
+		 * from the firmware for all of them
+		 */
+		rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
+		rx_status.ampdu_reference = mvm->ampdu_ref;
+	}
+
+	/* Set up the HT phy flags */
+	switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+	case RATE_MCS_CHAN_WIDTH_20:
+		break;
+	case RATE_MCS_CHAN_WIDTH_40:
+		rx_status.flag |= RX_FLAG_40MHZ;
+		break;
+	case RATE_MCS_CHAN_WIDTH_80:
+		rx_status.flag |= RX_FLAG_80MHZ;
+		break;
+	case RATE_MCS_CHAN_WIDTH_160:
+		rx_status.flag |= RX_FLAG_160MHZ;
+		break;
+	}
+	if (rate_n_flags & RATE_MCS_SGI_MSK)
+		rx_status.flag |= RX_FLAG_SHORT_GI;
+	if (rate_n_flags & RATE_HT_MCS_GF_MSK)
+		rx_status.flag |= RX_FLAG_HT_GF;
+	if (rate_n_flags & RATE_MCS_HT_MSK) {
+		rx_status.flag |= RX_FLAG_HT;
+		rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+	} else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+		rx_status.vht_nss =
+			((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+						RATE_VHT_MCS_NSS_POS) + 1;
+		rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+		rx_status.flag |= RX_FLAG_VHT;
+	} else {
+		rx_status.rate_idx =
+			iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
+							    rx_status.band);
+	}
+
+	iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status,
+					rxb, &rx_status);
+	return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
new file mode 100644
index 0000000..9b21b92
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -0,0 +1,442 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "mvm.h"
+#include "iwl-eeprom-parse.h"
+#include "fw-api-scan.h"
+
+#define IWL_PLCP_QUIET_THRESH 1
+#define IWL_ACTIVE_QUIET_TIME 10
+
+static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
+{
+	u16 rx_chain;
+	u8 rx_ant = mvm->nvm_data->valid_rx_ant;
+
+	rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
+	rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
+	rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS;
+	rx_chain |= 0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS;
+	return cpu_to_le16(rx_chain);
+}
+
+static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif)
+{
+	if (vif->bss_conf.assoc)
+		return cpu_to_le32(200 * 1024);
+	else
+		return 0;
+}
+
+static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif)
+{
+	if (vif->bss_conf.assoc)
+		return cpu_to_le32(vif->bss_conf.beacon_int);
+	else
+		return 0;
+}
+
+static inline __le32
+iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req)
+{
+	if (req->channels[0]->band == IEEE80211_BAND_2GHZ)
+		return cpu_to_le32(PHY_BAND_24);
+	else
+		return cpu_to_le32(PHY_BAND_5);
+}
+
+static inline __le32
+iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
+			  bool no_cck)
+{
+	u32 tx_ant;
+
+	mvm->scan_last_antenna_idx =
+		iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+				     mvm->scan_last_antenna_idx);
+	tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
+
+	if (band == IEEE80211_BAND_2GHZ && !no_cck)
+		return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK |
+				   tx_ant);
+	else
+		return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant);
+}
+
+/*
+ * We insert the SSIDs in an inverted order, because the FW will
+ * invert it back. The most prioritized SSID, which is first in the
+ * request list, is not copied here, but inserted directly to the probe
+ * request.
+ */
+static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
+				    struct cfg80211_scan_request *req)
+{
+	int fw_idx, req_idx;
+
+	fw_idx = 0;
+	for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+		cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
+		cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
+		memcpy(cmd->direct_scan[fw_idx].ssid,
+		       req->ssids[req_idx].ssid,
+		       req->ssids[req_idx].ssid_len);
+	}
+}
+
+/*
+ * If req->n_ssids > 0, it means we should do an active scan.
+ * In case of active scan w/o directed scan, we receive a zero-length SSID
+ * just to notify that this scan is active and not passive.
+ * In order to notify the FW of the number of SSIDs we wish to scan (including
+ * the zero-length one), we need to set the corresponding bits in chan->type,
+ * one for each SSID, and set the active bit (first).
+ */
+static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
+{
+	if (band == IEEE80211_BAND_2GHZ)
+		return 30  + 3 * (n_ssids + 1);
+	return 20  + 2 * (n_ssids + 1);
+}
+
+static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
+{
+	return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
+}
+
+static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
+				       struct cfg80211_scan_request *req)
+{
+	u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band);
+	u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band,
+						    req->n_ssids);
+	struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
+		(cmd->data + le16_to_cpu(cmd->tx_cmd.len));
+	int i;
+	__le32 chan_type_value;
+
+	if (req->n_ssids > 0)
+		chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
+	else
+		chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
+
+	for (i = 0; i < cmd->channel_count; i++) {
+		chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+		if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+			chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
+		else
+			chan->type = chan_type_value;
+		chan->active_dwell = cpu_to_le16(active_dwell);
+		chan->passive_dwell = cpu_to_le16(passive_dwell);
+		chan->iteration_count = cpu_to_le16(1);
+		chan++;
+	}
+}
+
+/*
+ * Fill in probe request with the following parameters:
+ * TA is our vif HW address, which mac80211 ensures we have.
+ * Packet is broadcasted, so this is both SA and DA.
+ * The probe request IE is made out of two: first comes the most prioritized
+ * SSID if a directed scan is requested. Second comes whatever extra
+ * information was given to us as the scan request IE.
+ */
+static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
+				  int n_ssids, const u8 *ssid, int ssid_len,
+				  const u8 *ie, int ie_len,
+				  int left)
+{
+	int len = 0;
+	u8 *pos = NULL;
+
+	/* Make sure there is enough space for the probe request,
+	 * two mandatory IEs and the data */
+	left -= 24;
+	if (left < 0)
+		return 0;
+
+	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+	eth_broadcast_addr(frame->da);
+	memcpy(frame->sa, ta, ETH_ALEN);
+	eth_broadcast_addr(frame->bssid);
+	frame->seq_ctrl = 0;
+
+	len += 24;
+
+	/* for passive scans, no need to fill anything */
+	if (n_ssids == 0)
+		return (u16)len;
+
+	/* points to the payload of the request */
+	pos = &frame->u.probe_req.variable[0];
+
+	/* fill in our SSID IE */
+	left -= ssid_len + 2;
+	if (left < 0)
+		return 0;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ssid_len;
+	if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
+		memcpy(pos, ssid, ssid_len);
+		pos += ssid_len;
+	}
+
+	len += ssid_len + 2;
+
+	if (WARN_ON(left < ie_len))
+		return len;
+
+	if (ie && ie_len) {
+		memcpy(pos, ie, ie_len);
+		len += ie_len;
+	}
+
+	return (u16)len;
+}
+
+int iwl_mvm_scan_request(struct iwl_mvm *mvm,
+			 struct ieee80211_vif *vif,
+			 struct cfg80211_scan_request *req)
+{
+	struct iwl_host_cmd hcmd = {
+		.id = SCAN_REQUEST_CMD,
+		.len = { 0, },
+		.data = { mvm->scan_cmd, },
+		.flags = CMD_SYNC,
+		.dataflags = { IWL_HCMD_DFL_NOCOPY, },
+	};
+	struct iwl_scan_cmd *cmd = mvm->scan_cmd;
+	int ret;
+	u32 status;
+	int ssid_len = 0;
+	u8 *ssid = NULL;
+
+	lockdep_assert_held(&mvm->mutex);
+	BUG_ON(mvm->scan_cmd == NULL);
+
+	IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n");
+	mvm->scan_status = IWL_MVM_SCAN_OS;
+	memset(cmd, 0, sizeof(struct iwl_scan_cmd) +
+	       mvm->fw->ucode_capa.max_probe_length +
+	       (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
+
+	cmd->channel_count = (u8)req->n_channels;
+	cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
+	cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
+	cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
+	cmd->max_out_time = iwl_mvm_scan_max_out_time(vif);
+	cmd->suspend_time = iwl_mvm_scan_suspend_time(vif);
+	cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req);
+	cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
+					MAC_FILTER_IN_BEACON);
+
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+		cmd->type = cpu_to_le32(SCAN_TYPE_DISCOVERY_FORCED);
+	else
+		cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
+
+	cmd->repeats = cpu_to_le32(1);
+
+	/*
+	 * If the user asked for passive scan, don't change to active scan if
+	 * you see any activity on the channel - remain passive.
+	 */
+	if (req->n_ssids > 0) {
+		cmd->passive2active = cpu_to_le16(1);
+		ssid = req->ssids[0].ssid;
+		ssid_len = req->ssids[0].ssid_len;
+	} else {
+		cmd->passive2active = 0;
+	}
+
+	iwl_mvm_scan_fill_ssids(cmd, req);
+
+	cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
+	cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
+	cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+	cmd->tx_cmd.rate_n_flags =
+			iwl_mvm_scan_rate_n_flags(mvm, req->channels[0]->band,
+						  req->no_cck);
+
+	cmd->tx_cmd.len =
+		cpu_to_le16(iwl_mvm_fill_probe_req(
+			    (struct ieee80211_mgmt *)cmd->data,
+			    vif->addr,
+			    req->n_ssids, ssid, ssid_len,
+			    req->ie, req->ie_len,
+			    mvm->fw->ucode_capa.max_probe_length));
+
+	iwl_mvm_scan_fill_channels(cmd, req);
+
+	cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
+		le16_to_cpu(cmd->tx_cmd.len) +
+		(cmd->channel_count * sizeof(struct iwl_scan_channel)));
+	hcmd.len[0] = le16_to_cpu(cmd->len);
+
+	status = SCAN_RESPONSE_OK;
+	ret = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
+	if (!ret && status == SCAN_RESPONSE_OK) {
+		IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
+	} else {
+		/*
+		 * If the scan failed, it usually means that the FW was unable
+		 * to allocate the time events. Warn on it, but maybe we
+		 * should try to send the command again with different params.
+		 */
+		IWL_ERR(mvm, "Scan failed! status 0x%x ret %d\n",
+			status, ret);
+		mvm->scan_status = IWL_MVM_SCAN_NONE;
+		ret = -EIO;
+	}
+	return ret;
+}
+
+int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_cmd_response *resp = (void *)pkt->data;
+
+	IWL_DEBUG_SCAN(mvm, "Scan response received. status 0x%x\n",
+		       le32_to_cpu(resp->status));
+	return 0;
+}
+
+int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+
+	IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
+		       notif->status, notif->scanned_channels);
+
+	mvm->scan_status = IWL_MVM_SCAN_NONE;
+	ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
+
+	return 0;
+}
+
+static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
+				     struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_mvm *mvm =
+		container_of(notif_wait, struct iwl_mvm, notif_wait);
+	struct iwl_scan_complete_notif *notif;
+	u32 *resp;
+
+	switch (pkt->hdr.cmd) {
+	case SCAN_ABORT_CMD:
+		resp = (void *)pkt->data;
+		if (*resp == CAN_ABORT_STATUS) {
+			IWL_DEBUG_SCAN(mvm,
+				       "Scan can be aborted, wait until completion\n");
+			return false;
+		}
+
+		IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n",
+			       *resp);
+		return true;
+
+	case SCAN_COMPLETE_NOTIFICATION:
+		notif = (void *)pkt->data;
+		IWL_DEBUG_SCAN(mvm, "Scan aborted: status 0x%x\n",
+			       notif->status);
+		return true;
+
+	default:
+		WARN_ON(1);
+		return false;
+	};
+}
+
+void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
+{
+	struct iwl_notification_wait wait_scan_abort;
+	static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
+					       SCAN_COMPLETE_NOTIFICATION };
+	int ret;
+
+	iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
+				   scan_abort_notif,
+				   ARRAY_SIZE(scan_abort_notif),
+				   iwl_mvm_scan_abort_notif, NULL);
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL);
+	if (ret) {
+		IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
+		goto out_remove_notif;
+	}
+
+	ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ);
+	if (ret)
+		IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
+
+	return;
+
+out_remove_notif:
+	iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
new file mode 100644
index 0000000..861a7f9
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -0,0 +1,1241 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include <net/mac80211.h>
+
+#include "mvm.h"
+#include "sta.h"
+
+static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm)
+{
+	int sta_id;
+
+	WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/* Don't take rcu_read_lock() since we are protected by mvm->mutex */
+	for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++)
+		if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+					       lockdep_is_held(&mvm->mutex)))
+			return sta_id;
+	return IWL_MVM_STATION_COUNT;
+}
+
+/* send station add/update command to firmware */
+int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+			   bool update)
+{
+	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+	struct iwl_mvm_add_sta_cmd add_sta_cmd;
+	int ret;
+	u32 status;
+	u32 agg_size = 0, mpdu_dens = 0;
+
+	memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
+
+	add_sta_cmd.sta_id = mvm_sta->sta_id;
+	add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+	if (!update) {
+		add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
+		memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN);
+	}
+	add_sta_cmd.add_modify = update ? 1 : 0;
+
+	/* STA_FLG_FAT_EN_MSK ? */
+	/* STA_FLG_MIMO_EN_MSK ? */
+
+	if (sta->ht_cap.ht_supported) {
+		add_sta_cmd.station_flags_msk |=
+			cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK |
+				    STA_FLG_AGG_MPDU_DENS_MSK);
+
+		mpdu_dens = sta->ht_cap.ampdu_density;
+	}
+
+	if (sta->vht_cap.vht_supported) {
+		agg_size = sta->vht_cap.cap &
+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+		agg_size >>=
+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+	} else if (sta->ht_cap.ht_supported) {
+		agg_size = sta->ht_cap.ampdu_factor;
+	}
+
+	add_sta_cmd.station_flags |=
+		cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT);
+	add_sta_cmd.station_flags |=
+		cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
+
+	status = ADD_STA_SUCCESS;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd),
+					  &add_sta_cmd, &status);
+	if (ret)
+		return ret;
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n");
+		break;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "ADD_STA failed\n");
+		break;
+	}
+
+	return ret;
+}
+
+int iwl_mvm_add_sta(struct iwl_mvm *mvm,
+		    struct ieee80211_vif *vif,
+		    struct ieee80211_sta *sta)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+	int i, ret, sta_id;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+		sta_id = iwl_mvm_find_free_sta_id(mvm);
+	else
+		sta_id = mvm_sta->sta_id;
+
+	if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
+		return -ENOSPC;
+
+	spin_lock_init(&mvm_sta->lock);
+
+	mvm_sta->sta_id = sta_id;
+	mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id,
+						      mvmvif->color);
+	mvm_sta->vif = vif;
+	mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+	/* HW restart, don't assume the memory has been zeroed */
+	atomic_set(&mvm_sta->pending_frames, 0);
+	mvm_sta->tid_disable_agg = 0;
+	mvm_sta->tfd_queue_msk = 0;
+	for (i = 0; i < IEEE80211_NUM_ACS; i++)
+		if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
+			mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
+
+	if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+		mvm_sta->tfd_queue_msk |= BIT(vif->cab_queue);
+
+	/* for HW restart - need to reset the seq_number etc... */
+	memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data));
+
+	ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
+	if (ret)
+		return ret;
+
+	/* The first station added is the AP, the others are TDLS STAs */
+	if (vif->type == NL80211_IFTYPE_STATION &&
+	    mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
+		mvmvif->ap_sta_id = sta_id;
+
+	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
+
+	return 0;
+}
+
+int iwl_mvm_update_sta(struct iwl_mvm *mvm,
+		       struct ieee80211_vif *vif,
+		       struct ieee80211_sta *sta)
+{
+	return iwl_mvm_sta_send_to_fw(mvm, sta, true);
+}
+
+int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
+		      bool drain)
+{
+	struct iwl_mvm_add_sta_cmd cmd = {};
+	int ret;
+	u32 status;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
+	cmd.sta_id = mvmsta->sta_id;
+	cmd.add_modify = STA_MODE_MODIFY;
+	cmd.station_flags = drain ? cpu_to_le32(STA_FLG_DRAIN_FLOW) : 0;
+	cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
+
+	status = ADD_STA_SUCCESS;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+					  &cmd, &status);
+	if (ret)
+		return ret;
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n",
+			       mvmsta->sta_id);
+		break;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "Couldn't drain frames for staid %d\n",
+			mvmsta->sta_id);
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Remove a station from the FW table. Before sending the command to remove
+ * the station validate that the station is indeed known to the driver (sanity
+ * only).
+ */
+static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id)
+{
+	struct ieee80211_sta *sta;
+	struct iwl_mvm_rm_sta_cmd rm_sta_cmd = {
+		.sta_id = sta_id,
+	};
+	int ret;
+
+	sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+					lockdep_is_held(&mvm->mutex));
+
+	/* Note: internal stations are marked as error values */
+	if (!sta) {
+		IWL_ERR(mvm, "Invalid station id\n");
+		return -EINVAL;
+	}
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, REMOVE_STA, CMD_SYNC,
+				   sizeof(rm_sta_cmd), &rm_sta_cmd);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id);
+		return ret;
+	}
+
+	return 0;
+}
+
+void iwl_mvm_sta_drained_wk(struct work_struct *wk)
+{
+	struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk);
+	u8 sta_id;
+
+	/*
+	 * The mutex is needed because of the SYNC cmd, but not only: if the
+	 * work would run concurrently with iwl_mvm_rm_sta, it would run before
+	 * iwl_mvm_rm_sta sets the station as busy, and exit. Then
+	 * iwl_mvm_rm_sta would set the station as busy, and nobody will clean
+	 * that later.
+	 */
+	mutex_lock(&mvm->mutex);
+
+	for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) {
+		int ret;
+		struct ieee80211_sta *sta =
+			rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+						  lockdep_is_held(&mvm->mutex));
+
+		/* This station is in use */
+		if (!IS_ERR(sta))
+			continue;
+
+		if (PTR_ERR(sta) == -EINVAL) {
+			IWL_ERR(mvm, "Drained sta %d, but it is internal?\n",
+				sta_id);
+			continue;
+		}
+
+		if (!sta) {
+			IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n",
+				sta_id);
+			continue;
+		}
+
+		WARN_ON(PTR_ERR(sta) != -EBUSY);
+		/* This station was removed and we waited until it got drained,
+		 * we can now proceed and remove it.
+		 */
+		ret = iwl_mvm_rm_sta_common(mvm, sta_id);
+		if (ret) {
+			IWL_ERR(mvm,
+				"Couldn't remove sta %d after it was drained\n",
+				sta_id);
+			continue;
+		}
+		rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL);
+		clear_bit(sta_id, mvm->sta_drained);
+	}
+
+	mutex_unlock(&mvm->mutex);
+}
+
+int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
+		   struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	if (vif->type == NL80211_IFTYPE_STATION &&
+	    mvmvif->ap_sta_id == mvm_sta->sta_id) {
+		/*
+		 * Put a non-NULL since the fw station isn't removed.
+		 * It will be removed after the MAC will be set as
+		 * unassoc.
+		 */
+		rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+				   ERR_PTR(-EINVAL));
+
+		/* flush its queues here since we are freeing mvm_sta */
+		ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
+
+		/* if we are associated - we can't remove the AP STA now */
+		if (vif->bss_conf.assoc)
+			return ret;
+
+		/* unassoc - go ahead - remove the AP STA now */
+		mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+	}
+
+	/*
+	 * There are frames pending on the AC queues for this station.
+	 * We need to wait until all the frames are drained...
+	 */
+	if (atomic_read(&mvm_sta->pending_frames)) {
+		ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
+		rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+				   ERR_PTR(-EBUSY));
+	} else {
+		ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
+		rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
+	}
+
+	return ret;
+}
+
+int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
+		      struct ieee80211_vif *vif,
+		      u8 sta_id)
+{
+	int ret = iwl_mvm_rm_sta_common(mvm, sta_id);
+
+	lockdep_assert_held(&mvm->mutex);
+
+	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL);
+	return ret;
+}
+
+int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
+			     u32 qmask)
+{
+	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+		sta->sta_id = iwl_mvm_find_free_sta_id(mvm);
+		if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT))
+			return -ENOSPC;
+	}
+
+	sta->tfd_queue_msk = qmask;
+
+	/* put a non-NULL value so iterating over the stations won't stop */
+	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], ERR_PTR(-EINVAL));
+	return 0;
+}
+
+void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
+{
+	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
+	memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
+	sta->sta_id = IWL_MVM_STATION_COUNT;
+}
+
+static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
+				      struct iwl_mvm_int_sta *sta,
+				      const u8 *addr,
+				      u16 mac_id, u16 color)
+{
+	struct iwl_mvm_add_sta_cmd cmd;
+	int ret;
+	u32 status;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd));
+	cmd.sta_id = sta->sta_id;
+	cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
+							     color));
+
+	cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk);
+
+	if (addr)
+		memcpy(cmd.addr, addr, ETH_ALEN);
+
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+					  &cmd, &status);
+	if (ret)
+		return ret;
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		IWL_DEBUG_INFO(mvm, "Internal station added.\n");
+		return 0;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "Add internal station failed, status=0x%x\n",
+			status);
+		break;
+	}
+	return ret;
+}
+
+int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
+{
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/* Add the aux station, but without any queues */
+	ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0);
+	if (ret)
+		return ret;
+
+	ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL,
+					 MAC_INDEX_AUX, 0);
+
+	if (ret)
+		iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+	return ret;
+}
+
+/*
+ * Send the add station command for the vif's broadcast station.
+ * Assumes that the station was already allocated.
+ *
+ * @mvm: the mvm component
+ * @vif: the interface to which the broadcast station is added
+ * @bsta: the broadcast station to add.
+ */
+int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			   struct iwl_mvm_int_sta *bsta)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+	lockdep_assert_held(&mvm->mutex);
+
+	if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT))
+		return -ENOSPC;
+
+	return iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
+					  mvmvif->id, mvmvif->color);
+}
+
+/* Send the FW a request to remove the station from it's internal data
+ * structures, but DO NOT remove the entry from the local data structures. */
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
+			      struct iwl_mvm_int_sta *bsta)
+{
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+	if (ret)
+		IWL_WARN(mvm, "Failed sending remove station\n");
+	return ret;
+}
+
+/* Allocate a new station entry for the broadcast station to the given vif,
+ * and send it to the FW.
+ * Note that each P2P mac should have its own broadcast station.
+ *
+ * @mvm: the mvm component
+ * @vif: the interface to which the broadcast station is added
+ * @bsta: the broadcast station to add. */
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			  struct iwl_mvm_int_sta *bsta)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+	u32 qmask;
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+	ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask);
+	if (ret)
+		return ret;
+
+	ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
+					 mvmvif->id, mvmvif->color);
+
+	if (ret)
+		iwl_mvm_dealloc_int_sta(mvm, bsta);
+	return ret;
+}
+
+/*
+ * Send the FW a request to remove the station from it's internal data
+ * structures, and in addition remove it from the local data structure.
+ */
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
+{
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+	if (ret)
+		return ret;
+
+	iwl_mvm_dealloc_int_sta(mvm, bsta);
+	return ret;
+}
+
+int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+		       int tid, u16 ssn, bool start)
+{
+	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+	struct iwl_mvm_add_sta_cmd cmd = {};
+	int ret;
+	u32 status;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+	cmd.sta_id = mvm_sta->sta_id;
+	cmd.add_modify = STA_MODE_MODIFY;
+	cmd.add_immediate_ba_tid = (u8) tid;
+	cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+	cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
+				  STA_MODIFY_REMOVE_BA_TID;
+
+	status = ADD_STA_SUCCESS;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+					  &cmd, &status);
+	if (ret)
+		return ret;
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n",
+			       start ? "start" : "stopp");
+		break;
+	case ADD_STA_IMMEDIATE_BA_FAILURE:
+		IWL_WARN(mvm, "RX BA Session refused by fw\n");
+		ret = -ENOSPC;
+		break;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "RX BA Session failed %sing, status 0x%x\n",
+			start ? "start" : "stopp", status);
+		break;
+	}
+
+	return ret;
+}
+
+static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+			      int tid, u8 queue, bool start)
+{
+	struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+	struct iwl_mvm_add_sta_cmd cmd = {};
+	int ret;
+	u32 status;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	if (start) {
+		mvm_sta->tfd_queue_msk |= BIT(queue);
+		mvm_sta->tid_disable_agg &= ~BIT(tid);
+	} else {
+		mvm_sta->tfd_queue_msk &= ~BIT(queue);
+		mvm_sta->tid_disable_agg |= BIT(tid);
+	}
+
+	cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+	cmd.sta_id = mvm_sta->sta_id;
+	cmd.add_modify = STA_MODE_MODIFY;
+	cmd.modify_mask = STA_MODIFY_QUEUES | STA_MODIFY_TID_DISABLE_TX;
+	cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
+	cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
+
+	status = ADD_STA_SUCCESS;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+					  &cmd, &status);
+	if (ret)
+		return ret;
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		break;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "TX BA Session failed %sing, status 0x%x\n",
+			start ? "start" : "stopp", status);
+		break;
+	}
+
+	return ret;
+}
+
+static const u8 tid_to_ac[] = {
+	IEEE80211_AC_BE,
+	IEEE80211_AC_BK,
+	IEEE80211_AC_BK,
+	IEEE80211_AC_BE,
+	IEEE80211_AC_VI,
+	IEEE80211_AC_VI,
+	IEEE80211_AC_VO,
+	IEEE80211_AC_VO,
+};
+
+int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			     struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+	struct iwl_mvm_tid_data *tid_data;
+	int txq_id;
+
+	if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+		return -EINVAL;
+
+	if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) {
+		IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n",
+			mvmsta->tid_data[tid].state);
+		return -ENXIO;
+	}
+
+	lockdep_assert_held(&mvm->mutex);
+
+	for (txq_id = IWL_MVM_FIRST_AGG_QUEUE;
+	     txq_id <= IWL_MVM_LAST_AGG_QUEUE; txq_id++)
+		if (mvm->queue_to_mac80211[txq_id] ==
+		    IWL_INVALID_MAC80211_QUEUE)
+			break;
+
+	if (txq_id > IWL_MVM_LAST_AGG_QUEUE) {
+		IWL_ERR(mvm, "Failed to allocate agg queue\n");
+		return -EIO;
+	}
+
+	/* the new tx queue is still connected to the same mac80211 queue */
+	mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]];
+
+	spin_lock_bh(&mvmsta->lock);
+	tid_data = &mvmsta->tid_data[tid];
+	tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+	tid_data->txq_id = txq_id;
+	*ssn = tid_data->ssn;
+
+	IWL_DEBUG_TX_QUEUES(mvm,
+			    "Start AGG: sta %d tid %d queue %d - ssn = %d, next_recl = %d\n",
+			    mvmsta->sta_id, tid, txq_id, tid_data->ssn,
+			    tid_data->next_reclaimed);
+
+	if (tid_data->ssn == tid_data->next_reclaimed) {
+		tid_data->state = IWL_AGG_STARTING;
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+	} else {
+		tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+	}
+
+	spin_unlock_bh(&mvmsta->lock);
+
+	return 0;
+}
+
+int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta, u16 tid, u8 buf_size)
+{
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+	int queue, fifo, ret;
+	u16 ssn;
+
+	buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+	spin_lock_bh(&mvmsta->lock);
+	ssn = tid_data->ssn;
+	queue = tid_data->txq_id;
+	tid_data->state = IWL_AGG_ON;
+	tid_data->ssn = 0xffff;
+	spin_unlock_bh(&mvmsta->lock);
+
+	fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]];
+
+	ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
+	if (ret)
+		return -EIO;
+
+	iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid,
+			     buf_size, ssn);
+
+	/*
+	 * Even though in theory the peer could have different
+	 * aggregation reorder buffer sizes for different sessions,
+	 * our ucode doesn't allow for that and has a global limit
+	 * for each station. Therefore, use the minimum of all the
+	 * aggregation sessions and our default value.
+	 */
+	mvmsta->max_agg_bufsize =
+		min(mvmsta->max_agg_bufsize, buf_size);
+	mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
+
+	if (mvm->cfg->ht_params->use_rts_for_aggregation) {
+		/*
+		 * switch to RTS/CTS if it is the prefer protection
+		 * method for HT traffic
+		 */
+		mvmsta->lq_sta.lq.flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK;
+		/*
+		 * TODO: remove the TLC_RTS flag when we tear down the last
+		 * AGG session (agg_tids_count in DVM)
+		 */
+	}
+
+	IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
+		     sta->addr, tid);
+
+	return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false);
+}
+
+int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta, u16 tid)
+{
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+	u16 txq_id;
+	int err;
+
+	spin_lock_bh(&mvmsta->lock);
+
+	txq_id = tid_data->txq_id;
+
+	IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n",
+			    mvmsta->sta_id, tid, txq_id, tid_data->state);
+
+	switch (tid_data->state) {
+	case IWL_AGG_ON:
+		tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+
+		IWL_DEBUG_TX_QUEUES(mvm,
+				    "ssn = %d, next_recl = %d\n",
+				    tid_data->ssn, tid_data->next_reclaimed);
+
+		/* There are still packets for this RA / TID in the HW */
+		if (tid_data->ssn != tid_data->next_reclaimed) {
+			tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA;
+			err = 0;
+			break;
+		}
+
+		tid_data->ssn = 0xffff;
+		iwl_trans_txq_disable(mvm->trans, txq_id);
+		/* fall through */
+	case IWL_AGG_STARTING:
+	case IWL_EMPTYING_HW_QUEUE_ADDBA:
+		/*
+		 * The agg session has been stopped before it was set up. This
+		 * can happen when the AddBA timer times out for example.
+		 */
+
+		/* No barriers since we are under mutex */
+		lockdep_assert_held(&mvm->mutex);
+		mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
+
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		tid_data->state = IWL_AGG_OFF;
+		err = 0;
+		break;
+	default:
+		IWL_ERR(mvm,
+			"Stopping AGG while state not ON or starting for %d on %d (%d)\n",
+			mvmsta->sta_id, tid, tid_data->state);
+		IWL_ERR(mvm,
+			"\ttid_data->txq_id = %d\n", tid_data->txq_id);
+		err = -EINVAL;
+	}
+
+	spin_unlock_bh(&mvmsta->lock);
+
+	return err;
+}
+
+static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
+{
+	int i;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM);
+
+	if (i == STA_KEY_MAX_NUM)
+		return STA_KEY_IDX_INVALID;
+
+	__set_bit(i, mvm->fw_key_table);
+
+	return i;
+}
+
+static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
+				 struct ieee80211_sta *sta)
+{
+	struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+
+	if (sta) {
+		struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+		return mvm_sta->sta_id;
+	}
+
+	/*
+	 * The device expects GTKs for station interfaces to be
+	 * installed as GTKs for the AP station. If we have no
+	 * station ID, then use AP's station ID.
+	 */
+	if (vif->type == NL80211_IFTYPE_STATION &&
+	    mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
+		return mvmvif->ap_sta_id;
+
+	return IWL_INVALID_STATION;
+}
+
+static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
+				struct iwl_mvm_sta *mvm_sta,
+				struct ieee80211_key_conf *keyconf,
+				u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
+				u32 cmd_flags)
+{
+	__le16 key_flags;
+	struct iwl_mvm_add_sta_cmd cmd = {};
+	int ret, status;
+	u16 keyidx;
+	int i;
+
+	keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
+		 STA_KEY_FLG_KEYID_MSK;
+	key_flags = cpu_to_le16(keyidx);
+	key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP);
+
+	switch (keyconf->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP);
+		cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
+		for (i = 0; i < 5; i++)
+			cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
+		memcpy(cmd.key.key, keyconf->key, keyconf->keylen);
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		key_flags |= cpu_to_le16(STA_KEY_FLG_CCM);
+		memcpy(cmd.key.key, keyconf->key, keyconf->keylen);
+		break;
+	default:
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+		key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
+
+	cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+	cmd.key.key_offset = keyconf->hw_key_idx;
+	cmd.key.key_flags = key_flags;
+	cmd.add_modify = STA_MODE_MODIFY;
+	cmd.modify_mask = STA_MODIFY_KEY;
+	cmd.sta_id = sta_id;
+
+	status = ADD_STA_SUCCESS;
+	if (cmd_flags == CMD_SYNC)
+		ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+						  &cmd, &status);
+	else
+		ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+					   sizeof(cmd), &cmd);
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		IWL_DEBUG_WEP(mvm, "MODIFY_STA: set dynamic key passed\n");
+		break;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "MODIFY_STA: set dynamic key failed\n");
+		break;
+	}
+
+	return ret;
+}
+
+static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
+				 struct ieee80211_key_conf *keyconf,
+				 u8 sta_id, bool remove_key)
+{
+	struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {};
+
+	/* verify the key details match the required command's expectations */
+	if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) ||
+		    (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
+		    (keyconf->keyidx != 4 && keyconf->keyidx != 5)))
+		return -EINVAL;
+
+	igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx);
+	igtk_cmd.sta_id = cpu_to_le32(sta_id);
+
+	if (remove_key) {
+		igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID);
+	} else {
+		struct ieee80211_key_seq seq;
+		const u8 *pn;
+
+		memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen);
+		ieee80211_aes_cmac_calculate_k1_k2(keyconf,
+						   igtk_cmd.K1, igtk_cmd.K2);
+		ieee80211_get_key_rx_seq(keyconf, 0, &seq);
+		pn = seq.aes_cmac.pn;
+		igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) |
+						       ((u64) pn[4] << 8) |
+						       ((u64) pn[3] << 16) |
+						       ((u64) pn[2] << 24) |
+						       ((u64) pn[1] << 32) |
+						       ((u64) pn[0] << 40));
+	}
+
+	IWL_DEBUG_INFO(mvm, "%s igtk for sta %u\n",
+		       remove_key ? "removing" : "installing",
+		       igtk_cmd.sta_id);
+
+	return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, CMD_SYNC,
+				    sizeof(igtk_cmd), &igtk_cmd);
+}
+
+
+static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
+				       struct ieee80211_vif *vif,
+				       struct ieee80211_sta *sta)
+{
+	struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+
+	if (sta)
+		return sta->addr;
+
+	if (vif->type == NL80211_IFTYPE_STATION &&
+	    mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+		u8 sta_id = mvmvif->ap_sta_id;
+		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+						lockdep_is_held(&mvm->mutex));
+		return sta->addr;
+	}
+
+
+	return NULL;
+}
+
+int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
+			struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta,
+			struct ieee80211_key_conf *keyconf,
+			bool have_key_offset)
+{
+	struct iwl_mvm_sta *mvm_sta;
+	int ret;
+	u8 *addr, sta_id;
+	struct ieee80211_key_seq seq;
+	u16 p1k[5];
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/* Get the station id from the mvm local station table */
+	sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_ERR(mvm, "Failed to find station id\n");
+		return -EINVAL;
+	}
+
+	if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
+		goto end;
+	}
+
+	/*
+	 * It is possible that the 'sta' parameter is NULL, and thus
+	 * there is a need to retrieve  the sta from the local station table.
+	 */
+	if (!sta) {
+		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+						lockdep_is_held(&mvm->mutex));
+		if (IS_ERR_OR_NULL(sta)) {
+			IWL_ERR(mvm, "Invalid station id\n");
+			return -EINVAL;
+		}
+	}
+
+	mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+	if (WARN_ON_ONCE(mvm_sta->vif != vif))
+		return -EINVAL;
+
+	if (!have_key_offset) {
+		/*
+		 * The D3 firmware hardcodes the PTK offset to 0, so we have to
+		 * configure it there. As a result, this workaround exists to
+		 * let the caller set the key offset (hw_key_idx), see d3.c.
+		 */
+		keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
+		if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
+			return -ENOSPC;
+	}
+
+	switch (keyconf->cipher) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		addr = iwl_mvm_get_mac_addr(mvm, vif, sta);
+		/* get phase 1 key from mac80211 */
+		ieee80211_get_key_rx_seq(keyconf, 0, &seq);
+		ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
+		ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
+					   seq.tkip.iv32, p1k, CMD_SYNC);
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
+					   0, NULL, CMD_SYNC);
+		break;
+	default:
+		IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher);
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
+
+end:
+	IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
+		      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
+		      sta->addr, ret);
+	return ret;
+}
+
+int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
+			   struct ieee80211_vif *vif,
+			   struct ieee80211_sta *sta,
+			   struct ieee80211_key_conf *keyconf)
+{
+	struct iwl_mvm_sta *mvm_sta;
+	struct iwl_mvm_add_sta_cmd cmd = {};
+	__le16 key_flags;
+	int ret, status;
+	u8 sta_id;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/* Get the station id from the mvm local station table */
+	sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+
+	IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
+		      keyconf->keyidx, sta_id);
+
+	if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+		return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
+
+	ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
+	if (!ret) {
+		IWL_ERR(mvm, "offset %d not used in fw key table.\n",
+			keyconf->hw_key_idx);
+		return -ENOENT;
+	}
+
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
+		return 0;
+	}
+
+	/*
+	 * It is possible that the 'sta' parameter is NULL, and thus
+	 * there is a need to retrieve the sta from the local station table,
+	 * for example when a GTK is removed (where the sta_id will then be
+	 * the AP ID, and no station was passed by mac80211.)
+	 */
+	if (!sta) {
+		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+						lockdep_is_held(&mvm->mutex));
+		if (!sta) {
+			IWL_ERR(mvm, "Invalid station id\n");
+			return -EINVAL;
+		}
+	}
+
+	mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+	if (WARN_ON_ONCE(mvm_sta->vif != vif))
+		return -EINVAL;
+
+	key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
+				 STA_KEY_FLG_KEYID_MSK);
+	key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
+	key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
+
+	if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+		key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
+
+	cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+	cmd.key.key_flags = key_flags;
+	cmd.key.key_offset = keyconf->hw_key_idx;
+	cmd.sta_id = sta_id;
+
+	cmd.modify_mask = STA_MODIFY_KEY;
+	cmd.add_modify = STA_MODE_MODIFY;
+
+	status = ADD_STA_SUCCESS;
+	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+					  &cmd, &status);
+
+	switch (status) {
+	case ADD_STA_SUCCESS:
+		IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n");
+		break;
+	default:
+		ret = -EIO;
+		IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n");
+		break;
+	}
+
+	return ret;
+}
+
+void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_key_conf *keyconf,
+			     struct ieee80211_sta *sta, u32 iv32,
+			     u16 *phase1key)
+{
+	struct iwl_mvm_sta *mvm_sta;
+	u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+
+	if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+		return;
+
+	rcu_read_lock();
+
+	if (!sta) {
+		sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+		if (WARN_ON(IS_ERR_OR_NULL(sta))) {
+			rcu_read_unlock();
+			return;
+		}
+	}
+
+	mvm_sta = (void *)sta->drv_priv;
+	iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
+			     iv32, phase1key, CMD_ASYNC);
+	rcu_read_unlock();
+}
+
+void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
+				struct ieee80211_sta *sta)
+{
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+	struct iwl_mvm_add_sta_cmd cmd = {
+		.add_modify = STA_MODE_MODIFY,
+		.sta_id = mvmsta->sta_id,
+		.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
+		.sleep_state_flags = cpu_to_le16(STA_SLEEP_STATE_AWAKE),
+		.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
+	};
+	int ret;
+
+	/*
+	 * Same modify mask for sleep_tx_count and sleep_state_flags but this
+	 * should be fine since if we set the STA as "awake", then
+	 * sleep_tx_count is not relevant.
+	 */
+	ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
+}
+
+void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
+				       struct ieee80211_sta *sta,
+				       enum ieee80211_frame_release_type reason,
+				       u16 cnt)
+{
+	u16 sleep_state_flags =
+		(reason == IEEE80211_FRAME_RELEASE_UAPSD) ?
+			STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL;
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+	struct iwl_mvm_add_sta_cmd cmd = {
+		.add_modify = STA_MODE_MODIFY,
+		.sta_id = mvmsta->sta_id,
+		.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
+		.sleep_tx_count = cpu_to_le16(cnt),
+		.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
+		/*
+		 * Same modify mask for sleep_tx_count and sleep_state_flags so
+		 * we must set the sleep_state_flags too.
+		 */
+		.sleep_state_flags = cpu_to_le16(sleep_state_flags),
+	};
+	int ret;
+
+	/* TODO: somehow the fw doesn't seem to take PS_POLL into account */
+	ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
new file mode 100644
index 0000000..896f88a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -0,0 +1,374 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __sta_h__
+#define __sta_h__
+
+#include <linux/spinlock.h>
+#include <net/mac80211.h>
+#include <linux/wait.h>
+
+#include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */
+#include "fw-api.h" /* IWL_MVM_STATION_COUNT */
+#include "rs.h"
+
+struct iwl_mvm;
+
+/**
+ * DOC: station table - introduction
+ *
+ * The station table is a list of data structure that reprensent the stations.
+ * In STA/P2P client mode, the driver will hold one station for the AP/ GO.
+ * In GO/AP mode, the driver will have as many stations as associated clients.
+ * All these stations are reflected in the fw's station table. The driver
+ * keeps the fw's station table up to date with the ADD_STA command. Stations
+ * can be removed by the REMOVE_STA command.
+ *
+ * All the data related to a station is held in the structure %iwl_mvm_sta
+ * which is embed in the mac80211's %ieee80211_sta (in the drv_priv) area.
+ * This data includes the index of the station in the fw, per tid information
+ * (sequence numbers, Block-ack state machine, etc...). The stations are
+ * created and deleted by the %sta_state callback from %ieee80211_ops.
+ *
+ * The driver holds a map: %fw_id_to_mac_id that allows to fetch a
+ * %ieee80211_sta (and the %iwl_mvm_sta embedded into it) based on a fw
+ * station index. That way, the driver is able to get the tid related data in
+ * O(1) in time sensitive paths (Tx / Tx response / BA notification). These
+ * paths are triggered by the fw, and the driver needs to get a pointer to the
+ * %ieee80211 structure. This map helps to get that pointer quickly.
+ */
+
+/**
+ * DOC: station table - locking
+ *
+ * As stated before, the station is created / deleted by mac80211's %sta_state
+ * callback from %ieee80211_ops which can sleep. The next paragraph explains
+ * the locking of a single stations, the next ones relates to the station
+ * table.
+ *
+ * The station holds the sequence number per tid. So this data needs to be
+ * accessed in the Tx path (which is softIRQ). It also holds the Block-Ack
+ * information (the state machine / and the logic that checks if the queues
+ * were drained), so it also needs to be accessible from the Tx response flow.
+ * In short, the station needs to be access from sleepable context as well as
+ * from tasklets, so the station itself needs a spinlock.
+ *
+ * The writers of %fw_id_to_mac_id map are serialized by the global mutex of
+ * the mvm op_mode. This is possible since %sta_state can sleep.
+ * The pointers in this map are RCU protected, hence we won't replace the
+ * station while we have Tx / Tx response / BA notification running.
+ *
+ * If a station is deleted while it still has packets in its A-MPDU queues,
+ * then the reclaim flow will notice that there is no station in the map for
+ * sta_id and it will dump the responses.
+ */
+
+/**
+ * DOC: station table - internal stations
+ *
+ * The FW needs a few internal stations that are not reflected in
+ * mac80211, such as broadcast station in AP / GO mode, or AUX sta for
+ * scanning and P2P device (during the GO negotiation).
+ * For these kind of stations we have %iwl_mvm_int_sta struct which holds the
+ * data relevant for them from both %iwl_mvm_sta and %ieee80211_sta.
+ * Usually the data for these stations is static, so no locking is required,
+ * and no TID data as this is also not needed.
+ * One thing to note, is that these stations have an ID in the fw, but not
+ * in mac80211. In order to "reserve" them a sta_id in %fw_id_to_mac_id
+ * we fill ERR_PTR(EINVAL) in this mapping and all other dereferencing of
+ * pointers from this mapping need to check that the value is not error
+ * or NULL.
+ *
+ * Currently there is only one auxiliary station for scanning, initialized
+ * on init.
+ */
+
+/**
+ * DOC: station table - AP Station in STA mode
+ *
+ * %iwl_mvm_vif includes the index of the AP station in the fw's STA table:
+ * %ap_sta_id. To get the point to the coresponsding %ieee80211_sta,
+ * &fw_id_to_mac_id can be used. Due to the way the fw works, we must not remove
+ * the AP station from the fw before setting the MAC context as unassociated.
+ * Hence, %fw_id_to_mac_id[%ap_sta_id] will be NULLed when the AP station is
+ * removed by mac80211, but the station won't be removed in the fw until the
+ * VIF is set as unassociated. Then, %ap_sta_id will be invalidated.
+ */
+
+/**
+ * DOC: station table - Drain vs. Flush
+ *
+ * Flush means that all the frames in the SCD queue are dumped regardless the
+ * station to which they were sent. We do that when we disassociate and before
+ * we remove the STA of the AP. The flush can be done synchronously against the
+ * fw.
+ * Drain means that the fw will drop all the frames sent to a specific station.
+ * This is useful when a client (if we are IBSS / GO or AP) disassociates. In
+ * that case, we need to drain all the frames for that client from the AC queues
+ * that are shared with the other clients. Only then, we can remove the STA in
+ * the fw. In order to do so, we track the non-AMPDU packets for each station.
+ * If mac80211 removes a STA and if it still has non-AMPDU packets pending in
+ * the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all
+ * the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped
+ * (we know about it with its Tx response), we remove the station in fw and set
+ * it as %NULL in %fw_id_to_mac_id: this is the purpose of
+ * %iwl_mvm_sta_drained_wk.
+ */
+
+/**
+ * DOC: station table - fw restart
+ *
+ * When the fw asserts, or we have any other issue that requires to reset the
+ * driver, we require mac80211 to reconfigure the driver. Since the private
+ * data of the stations is embed in mac80211's %ieee80211_sta, that data will
+ * not be zeroed and needs to be reinitialized manually.
+ * %IWL_MVM_STATUS_IN_HW_RESTART is set during restart and that will hint us
+ * that we must not allocate a new sta_id but reuse the previous one. This
+ * means that the stations being re-added after the reset will have the same
+ * place in the fw as before the reset. We do need to zero the %fw_id_to_mac_id
+ * map, since the stations aren't in the fw any more. Internal stations that
+ * are not added by mac80211 will be re-added in the init flow that is called
+ * after the restart: mac80211 call's %iwl_mvm_mac_start which calls to
+ * %iwl_mvm_up.
+ */
+
+/**
+ * DOC: AP mode - PS
+ *
+ * When a station is asleep, the fw will set it as "asleep". All the
+ * non-aggregation frames to that station will be dropped by the fw
+ * (%TX_STATUS_FAIL_DEST_PS failure code).
+ * AMPDUs are in a separate queue that is stopped by the fw. We just need to
+ * let mac80211 know how many frames we have in these queues so that it can
+ * properly handle trigger frames.
+ * When the a trigger frame is received, mac80211 tells the driver to send
+ * frames from the AMPDU queues or AC queue depending on which queue are
+ * delivery-enabled and what TID has frames to transmit (Note that mac80211 has
+ * all the knowledege since all the non-agg frames are buffered / filtered, and
+ * the driver tells mac80211 about agg frames). The driver needs to tell the fw
+ * to let frames out even if the station is asleep. This is done by
+ * %iwl_mvm_sta_modify_sleep_tx_count.
+ * When we receive a frame from that station with PM bit unset, the
+ * driver needs to let the fw know that this station isn't alseep any more.
+ * This is done by %iwl_mvm_sta_modify_ps_wake.
+ *
+ * TODO - EOSP handling
+ */
+
+/**
+ * enum iwl_mvm_agg_state
+ *
+ * The state machine of the BA agreement establishment / tear down.
+ * These states relate to a specific RA / TID.
+ *
+ * @IWL_AGG_OFF: aggregation is not used
+ * @IWL_AGG_STARTING: aggregation are starting (between start and oper)
+ * @IWL_AGG_ON: aggregation session is up
+ * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
+ *	HW queue to be empty from packets for this RA /TID.
+ * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
+ *	HW queue to be empty from packets for this RA /TID.
+ */
+enum iwl_mvm_agg_state {
+	IWL_AGG_OFF = 0,
+	IWL_AGG_STARTING,
+	IWL_AGG_ON,
+	IWL_EMPTYING_HW_QUEUE_ADDBA,
+	IWL_EMPTYING_HW_QUEUE_DELBA,
+};
+
+/**
+ * struct iwl_mvm_tid_data - holds the states for each RA / TID
+ * @seq_number: the next WiFi sequence number to use
+ * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
+ *	This is basically (last acked packet++).
+ * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
+ *	Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
+ * @state: state of the BA agreement establishment / tear down.
+ * @txq_id: Tx queue used by the BA session
+ * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
+ *	the first packet to be sent in legacy HW queue in Tx AGG stop flow.
+ *	Basically when next_reclaimed reaches ssn, we can tell mac80211 that
+ *	we are ready to finish the Tx AGG stop / start flow.
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ */
+struct iwl_mvm_tid_data {
+	u16 seq_number;
+	u16 next_reclaimed;
+	/* The rest is Tx AGG related */
+	u32 rate_n_flags;
+	enum iwl_mvm_agg_state state;
+	u16 txq_id;
+	u16 ssn;
+	bool wait_for_ba;
+};
+
+/**
+ * struct iwl_mvm_sta - representation of a station in the driver
+ * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
+ * @tfd_queue_msk: the tfd queues used by the station
+ * @mac_id_n_color: the MAC context this station is linked to
+ * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
+ *	tid.
+ * @max_agg_bufsize: the maximal size of the AGG buffer for this station
+ * @lock: lock to protect the whole struct. Since %tid_data is access from Tx
+ * and from Tx response flow, it needs a spinlock.
+ * @pending_frames: number of frames for this STA on the shared Tx queues.
+ * @tid_data: per tid data. Look at %iwl_mvm_tid_data.
+ *
+ * When mac80211 creates a station it reserves some space (hw->sta_data_size)
+ * in the structure for use by driver. This structure is placed in that
+ * space.
+ *
+ */
+struct iwl_mvm_sta {
+	u32 sta_id;
+	u32 tfd_queue_msk;
+	u32 mac_id_n_color;
+	u16 tid_disable_agg;
+	u8 max_agg_bufsize;
+	spinlock_t lock;
+	atomic_t pending_frames;
+	struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
+	struct iwl_lq_sta lq_sta;
+	struct ieee80211_vif *vif;
+
+#ifdef CONFIG_PM_SLEEP
+	u16 last_seq_ctl;
+#endif
+};
+
+/**
+ * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or
+ * broadcast)
+ * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
+ * @tfd_queue_msk: the tfd queues used by the station
+ */
+struct iwl_mvm_int_sta {
+	u32 sta_id;
+	u32 tfd_queue_msk;
+};
+
+int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+			   bool update);
+int iwl_mvm_add_sta(struct iwl_mvm *mvm,
+		    struct ieee80211_vif *vif,
+		    struct ieee80211_sta *sta);
+int iwl_mvm_update_sta(struct iwl_mvm *mvm,
+		       struct ieee80211_vif *vif,
+		       struct ieee80211_sta *sta);
+int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
+		   struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta);
+int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
+		      struct ieee80211_vif *vif,
+		      u8 sta_id);
+int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
+			struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta,
+			struct ieee80211_key_conf *key,
+			bool have_key_offset);
+int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
+			   struct ieee80211_vif *vif,
+			   struct ieee80211_sta *sta,
+			   struct ieee80211_key_conf *keyconf);
+
+void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_key_conf *keyconf,
+			     struct ieee80211_sta *sta, u32 iv32,
+			     u16 *phase1key);
+
+/* AMPDU */
+int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+		       int tid, u16 ssn, bool start);
+int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta, u16 tid, u8 buf_size);
+int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta, u16 tid);
+
+int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
+int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
+			     u32 qmask);
+void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
+			     struct iwl_mvm_int_sta *sta);
+int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			   struct iwl_mvm_int_sta *bsta);
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
+			      struct iwl_mvm_int_sta *bsta);
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			  struct iwl_mvm_int_sta *bsta);
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta);
+void iwl_mvm_sta_drained_wk(struct work_struct *wk);
+void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
+				struct ieee80211_sta *sta);
+void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
+				       struct ieee80211_sta *sta,
+				       enum ieee80211_frame_release_type reason,
+				       u16 cnt);
+int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
+		      bool drain);
+
+#endif /* __sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
new file mode 100644
index 0000000..e437e02
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -0,0 +1,519 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#include <linux/jiffies.h>
+#include <net/mac80211.h>
+
+#include "iwl-notif-wait.h"
+#include "iwl-trans.h"
+#include "fw-api.h"
+#include "time-event.h"
+#include "mvm.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+
+/* A TimeUnit is 1024 microsecond */
+#define TU_TO_JIFFIES(_tu)	(usecs_to_jiffies((_tu) * 1024))
+#define MSEC_TO_TU(_msec)	(_msec*1000/1024)
+
+/* For ROC use a TE type which has priority high enough to be scheduled when
+ * there is a concurrent BSS or GO/AP. Currently, use a TE type that has
+ * priority similar to the TE priority used for action scans by the FW.
+ * TODO: This needs to be changed, based on the reason for the ROC, i.e., use
+ * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use
+ * TE_P2P_DEVICE_ACTION_SCAN
+ */
+#define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN
+
+void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
+			   struct iwl_mvm_time_event_data *te_data)
+{
+	lockdep_assert_held(&mvm->time_event_lock);
+
+	if (te_data->id == TE_MAX)
+		return;
+
+	list_del(&te_data->list);
+	te_data->running = false;
+	te_data->uid = 0;
+	te_data->id = TE_MAX;
+	te_data->vif = NULL;
+}
+
+void iwl_mvm_roc_done_wk(struct work_struct *wk)
+{
+	struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
+
+	synchronize_net();
+
+	/*
+	 * Flush the offchannel queue -- this is called when the time
+	 * event finishes or is cancelled, so that frames queued for it
+	 * won't get stuck on the queue and be transmitted in the next
+	 * time event.
+	 * We have to send the command asynchronously since this cannot
+	 * be under the mutex for locking reasons, but that's not an
+	 * issue as it will have to complete before the next command is
+	 * executed, and a new time event means a new command.
+	 */
+	iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false);
+}
+
+static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
+{
+	/*
+	 * First, clear the ROC_RUNNING status bit. This will cause the TX
+	 * path to drop offchannel transmissions. That would also be done
+	 * by mac80211, but it is racy, in particular in the case that the
+	 * time event actually completed in the firmware (which is handled
+	 * in iwl_mvm_te_handle_notif).
+	 */
+	clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+
+	/*
+	 * Of course, our status bit is just as racy as mac80211, so in
+	 * addition, fire off the work struct which will drop all frames
+	 * from the hardware queues that made it through the race. First
+	 * it will of course synchronize the TX path to make sure that
+	 * any *new* TX will be rejected.
+	 */
+	schedule_work(&mvm->roc_done_wk);
+}
+
+/*
+ * Handles a FW notification for an event that is known to the driver.
+ *
+ * @mvm: the mvm component
+ * @te_data: the time event data
+ * @notif: the notification data corresponding the time event data.
+ */
+static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
+				    struct iwl_mvm_time_event_data *te_data,
+				    struct iwl_time_event_notif *notif)
+{
+	lockdep_assert_held(&mvm->time_event_lock);
+
+	IWL_DEBUG_TE(mvm, "Handle time event notif - UID = 0x%x action %d\n",
+		     le32_to_cpu(notif->unique_id),
+		     le32_to_cpu(notif->action));
+
+	/*
+	 * The FW sends the start/end time event notifications even for events
+	 * that it fails to schedule. This is indicated in the status field of
+	 * the notification. This happens in cases that the scheduler cannot
+	 * find a schedule that can handle the event (for example requesting a
+	 * P2P Device discoveribility, while there are other higher priority
+	 * events in the system).
+	 */
+	WARN_ONCE(!le32_to_cpu(notif->status),
+		  "Failed to schedule time event\n");
+
+	if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) {
+		IWL_DEBUG_TE(mvm,
+			     "TE ended - current time %lu, estimated end %lu\n",
+			     jiffies, te_data->end_jiffies);
+
+		if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+			ieee80211_remain_on_channel_expired(mvm->hw);
+			iwl_mvm_roc_finished(mvm);
+		}
+
+		/*
+		 * By now, we should have finished association
+		 * and know the dtim period.
+		 */
+		if (te_data->vif->type == NL80211_IFTYPE_STATION &&
+		    (!te_data->vif->bss_conf.assoc ||
+		     !te_data->vif->bss_conf.dtim_period)) {
+			IWL_ERR(mvm,
+				"No assocation and the time event is over already...\n");
+			ieee80211_connection_loss(te_data->vif);
+		}
+
+		iwl_mvm_te_clear_data(mvm, te_data);
+	} else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) {
+		te_data->running = true;
+		te_data->end_jiffies = jiffies +
+			TU_TO_JIFFIES(te_data->duration);
+
+		if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+			set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+			ieee80211_ready_on_channel(mvm->hw);
+		}
+	} else {
+		IWL_WARN(mvm, "Got TE with unknown action\n");
+	}
+}
+
+/*
+ * The Rx handler for time event notifications
+ */
+int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
+				struct iwl_rx_cmd_buffer *rxb,
+				struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_time_event_notif *notif = (void *)pkt->data;
+	struct iwl_mvm_time_event_data *te_data, *tmp;
+
+	IWL_DEBUG_TE(mvm, "Time event notification - UID = 0x%x action %d\n",
+		     le32_to_cpu(notif->unique_id),
+		     le32_to_cpu(notif->action));
+
+	spin_lock_bh(&mvm->time_event_lock);
+	list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
+		if (le32_to_cpu(notif->unique_id) == te_data->uid)
+			iwl_mvm_te_handle_notif(mvm, te_data, notif);
+	}
+	spin_unlock_bh(&mvm->time_event_lock);
+
+	return 0;
+}
+
+static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
+					struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_mvm *mvm =
+		container_of(notif_wait, struct iwl_mvm, notif_wait);
+	struct iwl_mvm_time_event_data *te_data = data;
+	struct iwl_time_event_resp *resp;
+	int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+	if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD))
+		return true;
+
+	if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
+		IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n");
+		return true;
+	}
+
+	resp = (void *)pkt->data;
+
+	/* we should never get a response to another TIME_EVENT_CMD here */
+	if (WARN_ON_ONCE(le32_to_cpu(resp->id) != te_data->id))
+		return false;
+
+	te_data->uid = le32_to_cpu(resp->unique_id);
+	IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
+		     te_data->uid);
+	return true;
+}
+
+static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
+				       struct ieee80211_vif *vif,
+				       struct iwl_mvm_time_event_data *te_data,
+				       struct iwl_time_event_cmd *te_cmd)
+{
+	static const u8 time_event_response[] = { TIME_EVENT_CMD };
+	struct iwl_notification_wait wait_time_event;
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	IWL_DEBUG_TE(mvm, "Add new TE, duration %d TU\n",
+		     le32_to_cpu(te_cmd->duration));
+
+	spin_lock_bh(&mvm->time_event_lock);
+	if (WARN_ON(te_data->id != TE_MAX)) {
+		spin_unlock_bh(&mvm->time_event_lock);
+		return -EIO;
+	}
+	te_data->vif = vif;
+	te_data->duration = le32_to_cpu(te_cmd->duration);
+	te_data->id = le32_to_cpu(te_cmd->id);
+	list_add_tail(&te_data->list, &mvm->time_event_list);
+	spin_unlock_bh(&mvm->time_event_lock);
+
+	/*
+	 * Use a notification wait, which really just processes the
+	 * command response and doesn't wait for anything, in order
+	 * to be able to process the response and get the UID inside
+	 * the RX path. Using CMD_WANT_SKB doesn't work because it
+	 * stores the buffer and then wakes up this thread, by which
+	 * time another notification (that the time event started)
+	 * might already be processed unsuccessfully.
+	 */
+	iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
+				   time_event_response,
+				   ARRAY_SIZE(time_event_response),
+				   iwl_mvm_time_event_response, te_data);
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+				   sizeof(*te_cmd), te_cmd);
+	if (ret) {
+		IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
+		iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
+		goto out_clear_te;
+	}
+
+	/* No need to wait for anything, so just pass 1 (0 isn't valid) */
+	ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
+	/* should never fail */
+	WARN_ON_ONCE(ret);
+
+	if (ret) {
+ out_clear_te:
+		spin_lock_bh(&mvm->time_event_lock);
+		iwl_mvm_te_clear_data(mvm, te_data);
+		spin_unlock_bh(&mvm->time_event_lock);
+	}
+	return ret;
+}
+
+void iwl_mvm_protect_session(struct iwl_mvm *mvm,
+			     struct ieee80211_vif *vif,
+			     u32 duration, u32 min_duration)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+	struct iwl_time_event_cmd time_cmd = {};
+
+	lockdep_assert_held(&mvm->mutex);
+
+	if (te_data->running &&
+	    time_after(te_data->end_jiffies,
+		       jiffies + TU_TO_JIFFIES(min_duration))) {
+		IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
+			     jiffies_to_msecs(te_data->end_jiffies - jiffies));
+		return;
+	}
+
+	if (te_data->running) {
+		IWL_DEBUG_TE(mvm, "extend 0x%x: only %u ms left\n",
+			     te_data->uid,
+			     jiffies_to_msecs(te_data->end_jiffies - jiffies));
+		/*
+		 * we don't have enough time
+		 * cancel the current TE and issue a new one
+		 * Of course it would be better to remove the old one only
+		 * when the new one is added, but we don't care if we are off
+		 * channel for a bit. All we need to do, is not to return
+		 * before we actually begin to be on the channel.
+		 */
+		iwl_mvm_stop_session_protection(mvm, vif);
+	}
+
+	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
+	time_cmd.id_and_color =
+		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+	time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC);
+
+	time_cmd.apply_time =
+		cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
+
+	time_cmd.dep_policy = TE_INDEPENDENT;
+	time_cmd.is_present = cpu_to_le32(1);
+	time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE);
+	time_cmd.max_delay = cpu_to_le32(500);
+	/* TODO: why do we need to interval = bi if it is not periodic? */
+	time_cmd.interval = cpu_to_le32(1);
+	time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1));
+	time_cmd.duration = cpu_to_le32(duration);
+	time_cmd.repeat = cpu_to_le32(1);
+	time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
+
+	iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+}
+
+/*
+ * Explicit request to remove a time event. The removal of a time event needs to
+ * be synchronized with the flow of a time event's end notification, which also
+ * removes the time event from the op mode data structures.
+ */
+void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
+			       struct iwl_mvm_vif *mvmvif,
+			       struct iwl_mvm_time_event_data *te_data)
+{
+	struct iwl_time_event_cmd time_cmd = {};
+	u32 id, uid;
+	int ret;
+
+	/*
+	 * It is possible that by the time we got to this point the time
+	 * event was already removed.
+	 */
+	spin_lock_bh(&mvm->time_event_lock);
+
+	/* Save time event uid before clearing its data */
+	uid = te_data->uid;
+	id = te_data->id;
+
+	/*
+	 * The clear_data function handles time events that were already removed
+	 */
+	iwl_mvm_te_clear_data(mvm, te_data);
+	spin_unlock_bh(&mvm->time_event_lock);
+
+	/*
+	 * It is possible that by the time we try to remove it, the time event
+	 * has already ended and removed. In such a case there is no need to
+	 * send a removal command.
+	 */
+	if (id == TE_MAX) {
+		IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid);
+		return;
+	}
+
+	/* When we remove a TE, the UID is to be set in the id field */
+	time_cmd.id = cpu_to_le32(uid);
+	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
+	time_cmd.id_and_color =
+		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+
+	IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
+	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+				   sizeof(time_cmd), &time_cmd);
+	if (WARN_ON(ret))
+		return;
+}
+
+void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
+				     struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+
+	lockdep_assert_held(&mvm->mutex);
+	iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
+}
+
+int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			  int duration)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+	struct iwl_time_event_cmd time_cmd = {};
+
+	lockdep_assert_held(&mvm->mutex);
+	if (te_data->running) {
+		IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Flush the done work, just in case it's still pending, so that
+	 * the work it does can complete and we can accept new frames.
+	 */
+	flush_work(&mvm->roc_done_wk);
+
+	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
+	time_cmd.id_and_color =
+		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+	time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE);
+
+	time_cmd.apply_time = cpu_to_le32(0);
+	time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
+	time_cmd.is_present = cpu_to_le32(1);
+
+	time_cmd.interval = cpu_to_le32(1);
+
+	/*
+	 * IWL_MVM_ROC_TE_TYPE can have lower priority than other events
+	 * that are being scheduled by the driver/fw, and thus it might not be
+	 * scheduled. To improve the chances of it being scheduled, allow it to
+	 * be fragmented.
+	 * In addition, for the same reasons, allow to delay the scheduling of
+	 * the time event.
+	 */
+	time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20);
+	time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
+	time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
+	time_cmd.repeat = cpu_to_le32(1);
+	time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
+
+	return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+}
+
+void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
+{
+	struct iwl_mvm_vif *mvmvif;
+	struct iwl_mvm_time_event_data *te_data;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/*
+	 * Iterate over the list of time events and find the time event that is
+	 * associated with a P2P_DEVICE interface.
+	 * This assumes that a P2P_DEVICE interface can have only a single time
+	 * event at any given time and this time event coresponds to a ROC
+	 * request
+	 */
+	mvmvif = NULL;
+	spin_lock_bh(&mvm->time_event_lock);
+	list_for_each_entry(te_data, &mvm->time_event_list, list) {
+		if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+			mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+			break;
+		}
+	}
+	spin_unlock_bh(&mvm->time_event_lock);
+
+	if (!mvmvif) {
+		IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n");
+		return;
+	}
+
+	iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
+
+	iwl_mvm_roc_finished(mvm);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h
new file mode 100644
index 0000000..64fb57a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h
@@ -0,0 +1,214 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+
+#ifndef __time_event_h__
+#define __time_event_h__
+
+#include "fw-api.h"
+
+#include "mvm.h"
+
+/**
+ * DOC: Time Events - what is it?
+ *
+ * Time Events are a fw feature that allows the driver to control the presence
+ * of the device on the channel. Since the fw supports multiple channels
+ * concurrently, the fw may choose to jump to another channel at any time.
+ * In order to make sure that the fw is on a specific channel at a certain time
+ * and for a certain duration, the driver needs to issue a time event.
+ *
+ * The simplest example is for BSS association. The driver issues a time event,
+ * waits for it to start, and only then tells mac80211 that we can start the
+ * association. This way, we make sure that the association will be done
+ * smoothly and won't be interrupted by channel switch decided within the fw.
+ */
+
+ /**
+ * DOC: The flow against the fw
+ *
+ * When the driver needs to make sure we are in a certain channel, at a certain
+ * time and for a certain duration, it sends a Time Event. The flow against the
+ * fw goes like this:
+ *	1) Driver sends a TIME_EVENT_CMD to the fw
+ *	2) Driver gets the response for that command. This response contains the
+ *	   Unique ID (UID) of the event.
+ *	3) The fw sends notification when the event starts.
+ *
+ * Of course the API provides various options that allow to cover parameters
+ * of the flow.
+ *	What is the duration of the event?
+ *	What is the start time of the event?
+ *	Is there an end-time for the event?
+ *	How much can the event be delayed?
+ *	Can the event be split?
+ *	If yes what is the maximal number of chunks?
+ *	etc...
+ */
+
+/**
+ * DOC: Abstraction to the driver
+ *
+ * In order to simplify the use of time events to the rest of the driver,
+ * we abstract the use of time events. This component provides the functions
+ * needed by the driver.
+ */
+
+#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500
+#define IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400
+
+/**
+ * iwl_mvm_protect_session - start / extend the session protection.
+ * @mvm: the mvm component
+ * @vif: the virtual interface for which the session is issued
+ * @duration: the duration of the session in TU.
+ * @min_duration: will start a new session if the current session will end
+ *	in less than min_duration.
+ *
+ * This function can be used to start a session protection which means that the
+ * fw will stay on the channel for %duration_ms milliseconds. This function
+ * will block (sleep) until the session starts. This function can also be used
+ * to extend a currently running session.
+ * This function is meant to be used for BSS association for example, where we
+ * want to make sure that the fw stays on the channel during the association.
+ */
+void iwl_mvm_protect_session(struct iwl_mvm *mvm,
+			     struct ieee80211_vif *vif,
+			     u32 duration, u32 min_duration);
+
+/**
+ * iwl_mvm_stop_session_protection - cancel the session protection.
+ * @mvm: the mvm component
+ * @vif: the virtual interface for which the session is issued
+ *
+ * This functions cancels the session protection which is an act of good
+ * citizenship. If it is not needed any more it should be cancelled because
+ * the other bindings wait for the medium during that time.
+ * This funtions doesn't sleep.
+ */
+void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
+				      struct ieee80211_vif *vif);
+
+/*
+ * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION.
+ */
+int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
+				struct iwl_rx_cmd_buffer *rxb,
+				struct iwl_device_cmd *cmd);
+
+/**
+ * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionlity
+ * @mvm: the mvm component
+ * @vif: the virtual interface for which the roc is requested. It is assumed
+ * that the vif type is NL80211_IFTYPE_P2P_DEVICE
+ * @duration: the requested duration in millisecond for the fw to be on the
+ * channel that is bound to the vif.
+ *
+ * This function can be used to issue a remain on channel session,
+ * which means that the fw will stay in the channel for the request %duration
+ * milliseconds. The function is async, meaning that it only issues the ROC
+ * request but does not wait for it to start. Once the FW is ready to serve the
+ * ROC request, it will issue a notification to the driver that it is on the
+ * requested channel. Once the FW completes the ROC request it will issue
+ * another notification to the driver.
+ */
+int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			  int duration);
+
+/**
+ * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity
+ * @mvm: the mvm component
+ *
+ * This function can be used to cancel an ongoing ROC session.
+ * The function is async, it will instruct the FW to stop serving the ROC
+ * session, but will not wait for the actual stopping of the session.
+ */
+void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm);
+
+/**
+ * iwl_mvm_remove_time_event - general function to clean up of time event
+ * @mvm: the mvm component
+ * @vif: the vif to which the time event belongs
+ * @te_data: the time event data that corresponds to that time event
+ *
+ * This function can be used to cancel a time event regardless its type.
+ * It is useful for cleaning up time events running before removing an
+ * interface.
+ */
+void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
+			       struct iwl_mvm_vif *mvmvif,
+			       struct iwl_mvm_time_event_data *te_data);
+
+/**
+ * iwl_mvm_te_clear_data - remove time event from list
+ * @mvm: the mvm component
+ * @te_data: the time event data to remove
+ *
+ * This function is mostly internal, it is made available here only
+ * for firmware restart purposes.
+ */
+void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
+			   struct iwl_mvm_time_event_data *te_data);
+
+void iwl_mvm_roc_done_wk(struct work_struct *wk);
+
+#endif /* __time_event_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
new file mode 100644
index 0000000..6b67ce3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -0,0 +1,916 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include <linux/ieee80211.h>
+#include <linux/etherdevice.h>
+
+#include "iwl-trans.h"
+#include "iwl-eeprom-parse.h"
+#include "mvm.h"
+#include "sta.h"
+
+/*
+ * Sets most of the Tx cmd's fields
+ */
+static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
+			       struct iwl_tx_cmd *tx_cmd,
+			       struct ieee80211_tx_info *info, u8 sta_id)
+{
+	struct ieee80211_hdr *hdr = (void *)skb->data;
+	__le16 fc = hdr->frame_control;
+	u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags);
+	u32 len = skb->len + FCS_LEN;
+
+	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+		tx_flags |= TX_CMD_FLG_ACK;
+	else
+		tx_flags &= ~TX_CMD_FLG_ACK;
+
+	if (ieee80211_is_probe_resp(fc))
+		tx_flags |= TX_CMD_FLG_TSF;
+	else if (ieee80211_is_back_req(fc))
+		tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
+
+	/* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */
+	if (info->band == IEEE80211_BAND_2GHZ        &&
+	    (skb->protocol == cpu_to_be16(ETH_P_PAE)  ||
+	     is_multicast_ether_addr(hdr->addr1)      ||
+	     ieee80211_is_back_req(fc)                ||
+	     ieee80211_is_mgmt(fc)))
+		tx_flags |= TX_CMD_FLG_BT_DIS;
+
+	if (ieee80211_has_morefrags(fc))
+		tx_flags |= TX_CMD_FLG_MORE_FRAG;
+
+	if (ieee80211_is_data_qos(fc)) {
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		tx_cmd->tid_tspec = qc[0] & 0xf;
+		tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+	} else {
+		tx_cmd->tid_tspec = IWL_TID_NON_QOS;
+		if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL;
+		else
+			tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+	}
+
+	if (ieee80211_is_mgmt(fc)) {
+		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
+			tx_cmd->pm_frame_timeout = cpu_to_le16(3);
+		else
+			tx_cmd->pm_frame_timeout = cpu_to_le16(2);
+
+		/* The spec allows Action frames in A-MPDU, we don't support
+		 * it
+		 */
+		WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);
+	} else {
+		tx_cmd->pm_frame_timeout = 0;
+	}
+
+	if (info->flags & IEEE80211_TX_CTL_AMPDU)
+		tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
+
+	if (ieee80211_is_data(fc) && len > mvm->rts_threshold &&
+	    !is_multicast_ether_addr(ieee80211_get_DA(hdr)))
+		tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
+
+	tx_cmd->driver_txop = 0;
+	tx_cmd->tx_flags = cpu_to_le32(tx_flags);
+	/* Total # bytes to be transmitted */
+	tx_cmd->len = cpu_to_le16((u16)skb->len);
+	tx_cmd->next_frame_len = 0;
+	tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+	tx_cmd->sta_id = sta_id;
+}
+
+/*
+ * Sets the fields in the Tx cmd that are rate related
+ */
+static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
+				    struct iwl_tx_cmd *tx_cmd,
+				    struct ieee80211_tx_info *info,
+				    struct ieee80211_sta *sta,
+				    __le16 fc)
+{
+	u32 rate_flags;
+	int rate_idx;
+	u8 rate_plcp;
+
+	/* Set retry limit on RTS packets */
+	tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT;
+
+	/* Set retry limit on DATA packets and Probe Responses*/
+	if (ieee80211_is_probe_resp(fc)) {
+		tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT;
+		tx_cmd->rts_retry_limit =
+			min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit);
+	} else if (ieee80211_is_back_req(fc)) {
+		tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT;
+	} else {
+		tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY;
+	}
+
+	/*
+	 * for data packets, rate info comes from the table inside he fw. This
+	 * table is controlled by LINK_QUALITY commands
+	 */
+
+	if (ieee80211_is_data(fc)) {
+		tx_cmd->initial_rate_index = 0;
+		tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
+		return;
+	} else if (ieee80211_is_back_req(fc)) {
+		tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
+	}
+
+	/* HT rate doesn't make sense for a non data frame */
+	WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
+		  "Got an HT rate for a non data frame 0x%x\n",
+		  info->control.rates[0].flags);
+
+	rate_idx = info->control.rates[0].idx;
+	/* if the rate isn't a well known legacy rate, take the lowest one */
+	if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT_LEGACY)
+		rate_idx = rate_lowest_index(
+				&mvm->nvm_data->bands[info->band], sta);
+
+	/* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+	if (info->band == IEEE80211_BAND_5GHZ)
+		rate_idx += IWL_FIRST_OFDM_RATE;
+
+	/* For 2.4 GHZ band, check that there is no need to remap */
+	BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
+
+	/* Get PLCP rate for tx_cmd->rate_n_flags */
+	rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
+
+	mvm->mgmt_last_antenna_idx =
+		iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+				     mvm->mgmt_last_antenna_idx);
+	rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
+
+	/* Set CCK flag as needed */
+	if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+		rate_flags |= RATE_MCS_CCK_MSK;
+
+	/* Set the rate in the TX cmd */
+	tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags);
+}
+
+/*
+ * Sets the fields in the Tx cmd that are crypto related
+ */
+static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
+				      struct ieee80211_tx_info *info,
+				      struct iwl_tx_cmd *tx_cmd,
+				      struct sk_buff *skb_frag)
+{
+	struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+	switch (keyconf->cipher) {
+	case WLAN_CIPHER_SUITE_CCMP:
+		tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+		memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+		if (info->flags & IEEE80211_TX_CTL_AMPDU)
+			tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG);
+		break;
+
+	case WLAN_CIPHER_SUITE_TKIP:
+		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
+		break;
+
+	case WLAN_CIPHER_SUITE_WEP104:
+		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+		/* fall through */
+	case WLAN_CIPHER_SUITE_WEP40:
+		tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
+			((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) &
+			  TX_CMD_SEC_WEP_KEY_IDX_MSK);
+
+		memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+		break;
+	default:
+		IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher);
+		break;
+	}
+}
+
+/*
+ * Allocates and sets the Tx cmd the driver data pointers in the skb
+ */
+static struct iwl_device_cmd *
+iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
+		      struct ieee80211_sta *sta, u8 sta_id)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_device_cmd *dev_cmd;
+	struct iwl_tx_cmd *tx_cmd;
+
+	dev_cmd = iwl_trans_alloc_tx_cmd(mvm->trans);
+
+	if (unlikely(!dev_cmd))
+		return NULL;
+
+	memset(dev_cmd, 0, sizeof(*dev_cmd));
+	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+
+	if (info->control.hw_key)
+		iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb);
+
+	iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id);
+
+	iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
+
+	memset(&info->status, 0, sizeof(info->status));
+
+	info->driver_data[0] = NULL;
+	info->driver_data[1] = dev_cmd;
+
+	return dev_cmd;
+}
+
+int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_device_cmd *dev_cmd;
+	struct iwl_tx_cmd *tx_cmd;
+	u8 sta_id;
+
+	if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU))
+		return -1;
+
+	if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
+			 (!info->control.vif ||
+			  info->hw_queue != info->control.vif->cab_queue)))
+		return -1;
+
+	/*
+	 * If the interface on which frame is sent is the P2P_DEVICE
+	 * or an AP/GO interface use the broadcast station associated
+	 * with it; otherwise use the AUX station.
+	 */
+	if (info->control.vif &&
+	    (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
+	     info->control.vif->type == NL80211_IFTYPE_AP)) {
+		struct iwl_mvm_vif *mvmvif =
+			iwl_mvm_vif_from_mac80211(info->control.vif);
+		sta_id = mvmvif->bcast_sta.sta_id;
+	} else {
+		sta_id = mvm->aux_sta.sta_id;
+	}
+
+	IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue);
+
+	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id);
+	if (!dev_cmd)
+		return -1;
+
+	/* From now on, we cannot access info->control */
+	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+
+	/* Copy MAC header from skb into command buffer */
+	memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control));
+
+	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) {
+		iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Sets the fields in the Tx cmd that are crypto related
+ */
+int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
+		   struct ieee80211_sta *sta)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct iwl_mvm_sta *mvmsta;
+	struct iwl_device_cmd *dev_cmd;
+	struct iwl_tx_cmd *tx_cmd;
+	__le16 fc;
+	u16 seq_number = 0;
+	u8 tid = IWL_MAX_TID_COUNT;
+	u8 txq_id = info->hw_queue;
+	bool is_data_qos = false, is_ampdu = false;
+
+	mvmsta = (void *)sta->drv_priv;
+	fc = hdr->frame_control;
+
+	if (WARN_ON_ONCE(!mvmsta))
+		return -1;
+
+	if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION))
+		return -1;
+
+	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id);
+	if (!dev_cmd)
+		goto drop;
+
+	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+	/* From now on, we cannot access info->control */
+
+	spin_lock(&mvmsta->lock);
+
+	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
+		u8 *qc = NULL;
+		qc = ieee80211_get_qos_ctl(hdr);
+		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+		if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+			goto drop_unlock_sta;
+
+		seq_number = mvmsta->tid_data[tid].seq_number;
+		seq_number &= IEEE80211_SCTL_SEQ;
+		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+		hdr->seq_ctrl |= cpu_to_le16(seq_number);
+		seq_number += 0x10;
+		is_data_qos = true;
+		is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
+	}
+
+	/* Copy MAC header from skb into command buffer */
+	memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc));
+
+	WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
+
+	if (is_ampdu) {
+		if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON))
+			goto drop_unlock_sta;
+		txq_id = mvmsta->tid_data[tid].txq_id;
+	}
+
+	IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id,
+		     tid, txq_id, seq_number);
+
+	/* NOTE: aggregation will need changes here (for txq id) */
+	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))
+		goto drop_unlock_sta;
+
+	if (is_data_qos && !ieee80211_has_morefrags(fc))
+		mvmsta->tid_data[tid].seq_number = seq_number;
+
+	spin_unlock(&mvmsta->lock);
+
+	if (mvmsta->vif->type == NL80211_IFTYPE_AP &&
+	    txq_id < IWL_FIRST_AMPDU_QUEUE)
+		atomic_inc(&mvmsta->pending_frames);
+
+	return 0;
+
+drop_unlock_sta:
+	iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
+	spin_unlock(&mvmsta->lock);
+drop:
+	return -1;
+}
+
+static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
+				      struct ieee80211_sta *sta, u8 tid)
+{
+	struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+	struct ieee80211_vif *vif = mvmsta->vif;
+
+	lockdep_assert_held(&mvmsta->lock);
+
+	if (tid_data->ssn != tid_data->next_reclaimed)
+		return;
+
+	switch (tid_data->state) {
+	case IWL_EMPTYING_HW_QUEUE_ADDBA:
+		IWL_DEBUG_TX_QUEUES(mvm,
+				    "Can continue addBA flow ssn = next_recl = %d\n",
+				    tid_data->next_reclaimed);
+		tid_data->state = IWL_AGG_STARTING;
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+
+	case IWL_EMPTYING_HW_QUEUE_DELBA:
+		IWL_DEBUG_TX_QUEUES(mvm,
+				    "Can continue DELBA flow ssn = next_recl = %d\n",
+				    tid_data->next_reclaimed);
+		iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+		tid_data->state = IWL_AGG_OFF;
+		/*
+		 * we can't hold the mutex - but since we are after a sequence
+		 * point (call to iwl_trans_txq_disable), so we don't even need
+		 * a memory barrier.
+		 */
+		mvm->queue_to_mac80211[tid_data->txq_id] =
+					IWL_INVALID_MAC80211_QUEUE;
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+
+	default:
+		break;
+	}
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_mvm_get_tx_fail_reason(u32 status)
+{
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
+
+	switch (status & TX_STATUS_MSK) {
+	case TX_STATUS_SUCCESS:
+		return "SUCCESS";
+	TX_STATUS_POSTPONE(DELAY);
+	TX_STATUS_POSTPONE(FEW_BYTES);
+	TX_STATUS_POSTPONE(BT_PRIO);
+	TX_STATUS_POSTPONE(QUIET_PERIOD);
+	TX_STATUS_POSTPONE(CALC_TTAK);
+	TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+	TX_STATUS_FAIL(SHORT_LIMIT);
+	TX_STATUS_FAIL(LONG_LIMIT);
+	TX_STATUS_FAIL(UNDERRUN);
+	TX_STATUS_FAIL(DRAIN_FLOW);
+	TX_STATUS_FAIL(RFKILL_FLUSH);
+	TX_STATUS_FAIL(LIFE_EXPIRE);
+	TX_STATUS_FAIL(DEST_PS);
+	TX_STATUS_FAIL(HOST_ABORTED);
+	TX_STATUS_FAIL(BT_RETRY);
+	TX_STATUS_FAIL(STA_INVALID);
+	TX_STATUS_FAIL(FRAG_DROPPED);
+	TX_STATUS_FAIL(TID_DISABLE);
+	TX_STATUS_FAIL(FIFO_FLUSHED);
+	TX_STATUS_FAIL(SMALL_CF_POLL);
+	TX_STATUS_FAIL(FW_DROP);
+	TX_STATUS_FAIL(STA_COLOR_MISMATCH);
+	}
+
+	return "UNKNOWN";
+
+#undef TX_STATUS_FAIL
+#undef TX_STATUS_POSTPONE
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
+					 struct ieee80211_tx_info *info)
+{
+	struct ieee80211_tx_rate *r = &info->status.rates[0];
+
+	info->status.antenna =
+		((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+	if (rate_n_flags & RATE_HT_MCS_GF_MSK)
+		r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+	switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+	case RATE_MCS_CHAN_WIDTH_20:
+		break;
+	case RATE_MCS_CHAN_WIDTH_40:
+		r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+		break;
+	case RATE_MCS_CHAN_WIDTH_80:
+		r->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
+		break;
+	case RATE_MCS_CHAN_WIDTH_160:
+		r->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH;
+		break;
+	}
+	if (rate_n_flags & RATE_MCS_SGI_MSK)
+		r->flags |= IEEE80211_TX_RC_SHORT_GI;
+	if (rate_n_flags & RATE_MCS_HT_MSK) {
+		r->flags |= IEEE80211_TX_RC_MCS;
+		r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+	} else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+		ieee80211_rate_set_vht(
+			r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK,
+			((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+						RATE_VHT_MCS_NSS_POS) + 1);
+		r->flags |= IEEE80211_TX_RC_VHT_MCS;
+	} else {
+		r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
+							     info->band);
+	}
+}
+
+static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
+				     struct iwl_rx_packet *pkt)
+{
+	struct ieee80211_sta *sta;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+	int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
+	int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
+	u32 status = le16_to_cpu(tx_resp->status.status);
+	u16 ssn = iwl_mvm_get_scd_ssn(tx_resp);
+	struct iwl_mvm_sta *mvmsta;
+	struct sk_buff_head skbs;
+	u8 skb_freed = 0;
+	u16 next_reclaimed, seq_ctl;
+
+	__skb_queue_head_init(&skbs);
+
+	seq_ctl = le16_to_cpu(tx_resp->seq_ctl);
+
+	/* we can free until ssn % q.n_bd not inclusive */
+	iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs);
+
+	while (!skb_queue_empty(&skbs)) {
+		struct sk_buff *skb = __skb_dequeue(&skbs);
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+		skb_freed++;
+
+		iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+
+		memset(&info->status, 0, sizeof(info->status));
+
+		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
+		/* inform mac80211 about what happened with the frame */
+		switch (status & TX_STATUS_MSK) {
+		case TX_STATUS_SUCCESS:
+		case TX_STATUS_DIRECT_DONE:
+			info->flags |= IEEE80211_TX_STAT_ACK;
+			break;
+		case TX_STATUS_FAIL_DEST_PS:
+			info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+			break;
+		default:
+			break;
+		}
+
+		info->status.rates[0].count = tx_resp->failure_frame + 1;
+		iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate),
+					     info);
+
+		/* Single frame failure in an AMPDU queue => send BAR */
+		if (txq_id >= IWL_FIRST_AMPDU_QUEUE &&
+		    !(info->flags & IEEE80211_TX_STAT_ACK)) {
+			/* there must be only one skb in the skb_list */
+			WARN_ON_ONCE(skb_freed > 1 ||
+				     !skb_queue_empty(&skbs));
+			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+		}
+
+		/* W/A FW bug: seq_ctl is wrong when the queue is flushed */
+		if (status == TX_STATUS_FAIL_FIFO_FLUSHED) {
+			struct ieee80211_hdr *hdr = (void *)skb->data;
+			seq_ctl = le16_to_cpu(hdr->seq_ctrl);
+		}
+
+		ieee80211_tx_status_ni(mvm->hw, skb);
+	}
+
+	if (txq_id >= IWL_FIRST_AMPDU_QUEUE) {
+		/* If this is an aggregation queue, we use the ssn since:
+		 * ssn = wifi seq_num % 256.
+		 * The seq_ctl is the sequence control of the packet to which
+		 * this Tx response relates. But if there is a hole in the
+		 * bitmap of the BA we received, this Tx response may allow to
+		 * reclaim the hole and all the subsequent packets that were
+		 * already acked. In that case, seq_ctl != ssn, and the next
+		 * packet to be reclaimed will be ssn and not seq_ctl. In that
+		 * case, several packets will be reclaimed even if
+		 * frame_count = 1.
+		 *
+		 * The ssn is the index (% 256) of the latest packet that has
+		 * treated (acked / dropped) + 1.
+		 */
+		next_reclaimed = ssn;
+	} else {
+		/* The next packet to be reclaimed is the one after this one */
+		next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10);
+	}
+
+	IWL_DEBUG_TX_REPLY(mvm,
+			   "TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x "
+			    "retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n",
+			   txq_id, iwl_mvm_get_tx_fail_reason(status),
+			   status, le32_to_cpu(tx_resp->initial_rate),
+			   tx_resp->failure_frame, SEQ_TO_INDEX(sequence),
+			   ssn, next_reclaimed, seq_ctl);
+
+	rcu_read_lock();
+
+	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+	if (!IS_ERR_OR_NULL(sta)) {
+		mvmsta = (void *)sta->drv_priv;
+
+		if (tid != IWL_TID_NON_QOS) {
+			struct iwl_mvm_tid_data *tid_data =
+				&mvmsta->tid_data[tid];
+
+			spin_lock_bh(&mvmsta->lock);
+			tid_data->next_reclaimed = next_reclaimed;
+			IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n",
+					   next_reclaimed);
+			iwl_mvm_check_ratid_empty(mvm, sta, tid);
+			spin_unlock_bh(&mvmsta->lock);
+		}
+
+#ifdef CONFIG_PM_SLEEP
+		mvmsta->last_seq_ctl = seq_ctl;
+#endif
+	} else {
+		sta = NULL;
+		mvmsta = NULL;
+	}
+
+	/*
+	 * If the txq is not an AMPDU queue, there is no chance we freed
+	 * several skbs. Check that out...
+	 * If there are no pending frames for this STA, notify mac80211 that
+	 * this station can go to sleep in its STA table.
+	 */
+	if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta &&
+	    !WARN_ON(skb_freed > 1) &&
+	    mvmsta->vif->type == NL80211_IFTYPE_AP &&
+	    atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) {
+		ieee80211_sta_block_awake(mvm->hw, sta, false);
+		set_bit(sta_id, mvm->sta_drained);
+		schedule_work(&mvm->sta_drained_wk);
+	}
+
+	rcu_read_unlock();
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define AGG_TX_STATE_(x) case AGG_TX_STATE_ ## x: return #x
+static const char *iwl_get_agg_tx_status(u16 status)
+{
+	switch (status & AGG_TX_STATE_STATUS_MSK) {
+	AGG_TX_STATE_(TRANSMITTED);
+	AGG_TX_STATE_(UNDERRUN);
+	AGG_TX_STATE_(BT_PRIO);
+	AGG_TX_STATE_(FEW_BYTES);
+	AGG_TX_STATE_(ABORT);
+	AGG_TX_STATE_(LAST_SENT_TTL);
+	AGG_TX_STATE_(LAST_SENT_TRY_CNT);
+	AGG_TX_STATE_(LAST_SENT_BT_KILL);
+	AGG_TX_STATE_(SCD_QUERY);
+	AGG_TX_STATE_(TEST_BAD_CRC32);
+	AGG_TX_STATE_(RESPONSE);
+	AGG_TX_STATE_(DUMP_TX);
+	AGG_TX_STATE_(DELAY_TX);
+	}
+
+	return "UNKNOWN";
+}
+
+static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,
+				      struct iwl_rx_packet *pkt)
+{
+	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+	struct agg_tx_status *frame_status = &tx_resp->status;
+	int i;
+
+	for (i = 0; i < tx_resp->frame_count; i++) {
+		u16 fstatus = le16_to_cpu(frame_status[i].status);
+
+		IWL_DEBUG_TX_REPLY(mvm,
+				   "status %s (0x%04x), try-count (%d) seq (0x%x)\n",
+				   iwl_get_agg_tx_status(fstatus),
+				   fstatus & AGG_TX_STATE_STATUS_MSK,
+				   (fstatus & AGG_TX_STATE_TRY_CNT_MSK) >>
+					AGG_TX_STATE_TRY_CNT_POS,
+				   le16_to_cpu(frame_status[i].sequence));
+	}
+}
+#else
+static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,
+				      struct iwl_rx_packet *pkt)
+{}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
+				  struct iwl_rx_packet *pkt)
+{
+	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+	int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
+	int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	struct ieee80211_sta *sta;
+
+	if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE))
+		return;
+
+	if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
+		return;
+
+	iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt);
+
+	rcu_read_lock();
+
+	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+	if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
+		struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+		mvmsta->tid_data[tid].rate_n_flags =
+			le32_to_cpu(tx_resp->initial_rate);
+	}
+
+	rcu_read_unlock();
+}
+
+int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+		      struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+
+	if (tx_resp->frame_count == 1)
+		iwl_mvm_rx_tx_cmd_single(mvm, pkt);
+	else
+		iwl_mvm_rx_tx_cmd_agg(mvm, pkt);
+
+	return 0;
+}
+
+int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
+	struct sk_buff_head reclaimed_skbs;
+	struct iwl_mvm_tid_data *tid_data;
+	struct ieee80211_tx_info *info;
+	struct ieee80211_sta *sta;
+	struct iwl_mvm_sta *mvmsta;
+	struct ieee80211_hdr *hdr;
+	struct sk_buff *skb;
+	int sta_id, tid, freed;
+
+	/* "flow" corresponds to Tx queue */
+	u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
+
+	/* "ssn" is start of block-ack Tx window, corresponds to index
+	 * (in Tx queue's circular buffer) of first TFD/frame in window */
+	u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
+
+	sta_id = ba_notif->sta_id;
+	tid = ba_notif->tid;
+
+	rcu_read_lock();
+
+	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+	/* Reclaiming frames for a station that has been deleted ? */
+	if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
+		rcu_read_unlock();
+		return 0;
+	}
+
+	mvmsta = (void *)sta->drv_priv;
+	tid_data = &mvmsta->tid_data[tid];
+
+	if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d",
+		      tid_data->txq_id, tid, scd_flow)) {
+		rcu_read_unlock();
+		return 0;
+	}
+
+	spin_lock_bh(&mvmsta->lock);
+
+	__skb_queue_head_init(&reclaimed_skbs);
+
+	/*
+	 * Release all TFDs before the SSN, i.e. all TFDs in front of
+	 * block-ack window (we assume that they've been successfully
+	 * transmitted ... if not, it's too late anyway).
+	 */
+	iwl_trans_reclaim(mvm->trans, scd_flow, ba_resp_scd_ssn,
+			  &reclaimed_skbs);
+
+	IWL_DEBUG_TX_REPLY(mvm,
+			   "BA_NOTIFICATION Received from %pM, sta_id = %d\n",
+			   (u8 *)&ba_notif->sta_addr_lo32,
+			   ba_notif->sta_id);
+	IWL_DEBUG_TX_REPLY(mvm,
+			   "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
+			   ba_notif->tid, le16_to_cpu(ba_notif->seq_ctl),
+			   (unsigned long long)le64_to_cpu(ba_notif->bitmap),
+			   scd_flow, ba_resp_scd_ssn, ba_notif->txed,
+			   ba_notif->txed_2_done);
+
+	tid_data->next_reclaimed = ba_resp_scd_ssn;
+
+	iwl_mvm_check_ratid_empty(mvm, sta, tid);
+
+	freed = 0;
+
+	skb_queue_walk(&reclaimed_skbs, skb) {
+		hdr = (struct ieee80211_hdr *)skb->data;
+
+		if (ieee80211_is_data_qos(hdr->frame_control))
+			freed++;
+		else
+			WARN_ON_ONCE(1);
+
+		info = IEEE80211_SKB_CB(skb);
+		iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+
+		if (freed == 1) {
+			/* this is the first skb we deliver in this batch */
+			/* put the rate scaling data there */
+			info = IEEE80211_SKB_CB(skb);
+			memset(&info->status, 0, sizeof(info->status));
+			info->flags |= IEEE80211_TX_STAT_ACK;
+			info->flags |= IEEE80211_TX_STAT_AMPDU;
+			info->status.ampdu_ack_len = ba_notif->txed_2_done;
+			info->status.ampdu_len = ba_notif->txed;
+			iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags,
+						     info);
+		}
+	}
+
+	spin_unlock_bh(&mvmsta->lock);
+
+	rcu_read_unlock();
+
+	while (!skb_queue_empty(&reclaimed_skbs)) {
+		skb = __skb_dequeue(&reclaimed_skbs);
+		ieee80211_tx_status_ni(mvm->hw, skb);
+	}
+
+	return 0;
+}
+
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync)
+{
+	int ret;
+	struct iwl_tx_path_flush_cmd flush_cmd = {
+		.queues_ctl = cpu_to_le32(tfd_msk),
+		.flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH),
+	};
+
+	u32 flags = sync ? CMD_SYNC : CMD_ASYNC;
+
+	ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags,
+				   sizeof(flush_cmd), &flush_cmd);
+	if (ret)
+		IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret);
+	return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
new file mode 100644
index 0000000..000e842
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -0,0 +1,472 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * 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 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.
+ *
+ *****************************************************************************/
+#include <net/mac80211.h>
+
+#include "iwl-debug.h"
+#include "iwl-io.h"
+
+#include "mvm.h"
+#include "fw-api-rs.h"
+
+/*
+ * Will return 0 even if the cmd failed when RFKILL is asserted unless
+ * CMD_WANT_SKB is set in cmd->flags.
+ */
+int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
+{
+	int ret;
+
+	/*
+	 * Synchronous commands from this op-mode must hold
+	 * the mutex, this ensures we don't try to send two
+	 * (or more) synchronous commands at a time.
+	 */
+	if (!(cmd->flags & CMD_ASYNC))
+		lockdep_assert_held(&mvm->mutex);
+
+	ret = iwl_trans_send_cmd(mvm->trans, cmd);
+
+	/*
+	 * If the caller wants the SKB, then don't hide any problems, the
+	 * caller might access the response buffer which will be NULL if
+	 * the command failed.
+	 */
+	if (cmd->flags & CMD_WANT_SKB)
+		return ret;
+
+	/* Silently ignore failures if RFKILL is asserted */
+	if (!ret || ret == -ERFKILL)
+		return 0;
+	return ret;
+}
+
+int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id,
+			 u32 flags, u16 len, const void *data)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = { len, },
+		.data = { data, },
+		.flags = flags,
+	};
+
+	return iwl_mvm_send_cmd(mvm, &cmd);
+}
+
+/*
+ * We assume that the caller set the status to the sucess value
+ */
+int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
+			    u32 *status)
+{
+	struct iwl_rx_packet *pkt;
+	struct iwl_cmd_response *resp;
+	int ret, resp_len;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/*
+	 * Only synchronous commands can wait for status,
+	 * we use WANT_SKB so the caller can't.
+	 */
+	if (WARN_ONCE(cmd->flags & (CMD_ASYNC | CMD_WANT_SKB),
+		      "cmd flags %x", cmd->flags))
+		return -EINVAL;
+
+	cmd->flags |= CMD_SYNC | CMD_WANT_SKB;
+
+	ret = iwl_trans_send_cmd(mvm->trans, cmd);
+	if (ret == -ERFKILL) {
+		/*
+		 * The command failed because of RFKILL, don't update
+		 * the status, leave it as success and return 0.
+		 */
+		return 0;
+	} else if (ret) {
+		return ret;
+	}
+
+	pkt = cmd->resp_pkt;
+	/* Can happen if RFKILL is asserted */
+	if (!pkt) {
+		ret = 0;
+		goto out_free_resp;
+	}
+
+	if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+		ret = -EIO;
+		goto out_free_resp;
+	}
+
+	resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+	if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
+		ret = -EIO;
+		goto out_free_resp;
+	}
+
+	resp = (void *)pkt->data;
+	*status = le32_to_cpu(resp->status);
+ out_free_resp:
+	iwl_free_resp(cmd);
+	return ret;
+}
+
+/*
+ * We assume that the caller set the status to the sucess value
+ */
+int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len,
+				const void *data, u32 *status)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = { len, },
+		.data = { data, },
+	};
+
+	return iwl_mvm_send_cmd_status(mvm, &cmd, status);
+}
+
+#define IWL_DECLARE_RATE_INFO(r) \
+	[IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
+
+/*
+ * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP
+ */
+static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(1),
+	IWL_DECLARE_RATE_INFO(2),
+	IWL_DECLARE_RATE_INFO(5),
+	IWL_DECLARE_RATE_INFO(11),
+	IWL_DECLARE_RATE_INFO(6),
+	IWL_DECLARE_RATE_INFO(9),
+	IWL_DECLARE_RATE_INFO(12),
+	IWL_DECLARE_RATE_INFO(18),
+	IWL_DECLARE_RATE_INFO(24),
+	IWL_DECLARE_RATE_INFO(36),
+	IWL_DECLARE_RATE_INFO(48),
+	IWL_DECLARE_RATE_INFO(54),
+};
+
+int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
+					enum ieee80211_band band)
+{
+	int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;
+	int idx;
+	int band_offset = 0;
+
+	/* Legacy rate format, search for match in table */
+	if (band == IEEE80211_BAND_5GHZ)
+		band_offset = IWL_FIRST_OFDM_RATE;
+	for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+		if (fw_rate_idx_to_plcp[idx] == rate)
+			return idx - band_offset;
+
+	return -1;
+}
+
+u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx)
+{
+	/* Get PLCP rate for tx_cmd->rate_n_flags */
+	return fw_rate_idx_to_plcp[rate_idx];
+}
+
+int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+			  struct iwl_device_cmd *cmd)
+{
+	struct iwl_rx_packet *pkt = rxb_addr(rxb);
+	struct iwl_error_resp *err_resp = (void *)pkt->data;
+
+	IWL_ERR(mvm, "FW Error notification: type 0x%08X cmd_id 0x%02X\n",
+		le32_to_cpu(err_resp->error_type), err_resp->cmd_id);
+	IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n",
+		le16_to_cpu(err_resp->bad_cmd_seq_num),
+		le32_to_cpu(err_resp->error_service));
+	IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n",
+		le64_to_cpu(err_resp->timestamp));
+	return 0;
+}
+
+/*
+ * Returns the first antenna as ANT_[ABC], as defined in iwl-config.h.
+ * The parameter should also be a combination of ANT_[ABC].
+ */
+u8 first_antenna(u8 mask)
+{
+	BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */
+	WARN_ON_ONCE(!mask); /* ffs will return 0 if mask is zeroed */
+	return (u8)(BIT(ffs(mask)));
+}
+
+/*
+ * Toggles between TX antennas to send the probe request on.
+ * Receives the bitmask of valid TX antennas and the *index* used
+ * for the last TX, and returns the next valid *index* to use.
+ * In order to set it in the tx_cmd, must do BIT(idx).
+ */
+u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)
+{
+	u8 ind = last_idx;
+	int i;
+
+	for (i = 0; i < RATE_MCS_ANT_NUM; i++) {
+		ind = (ind + 1) % RATE_MCS_ANT_NUM;
+		if (valid & BIT(ind))
+			return ind;
+	}
+
+	WARN_ONCE(1, "Failed to toggle between antennas 0x%x", valid);
+	return last_idx;
+}
+
+static struct {
+	char *name;
+	u8 num;
+} advanced_lookup[] = {
+	{ "NMI_INTERRUPT_WDG", 0x34 },
+	{ "SYSASSERT", 0x35 },
+	{ "UCODE_VERSION_MISMATCH", 0x37 },
+	{ "BAD_COMMAND", 0x38 },
+	{ "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+	{ "FATAL_ERROR", 0x3D },
+	{ "NMI_TRM_HW_ERR", 0x46 },
+	{ "NMI_INTERRUPT_TRM", 0x4C },
+	{ "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+	{ "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+	{ "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+	{ "NMI_INTERRUPT_HOST", 0x66 },
+	{ "NMI_INTERRUPT_ACTION_PT", 0x7C },
+	{ "NMI_INTERRUPT_UNKNOWN", 0x84 },
+	{ "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+	{ "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(advanced_lookup) - 1; i++)
+		if (advanced_lookup[i].num == num)
+			return advanced_lookup[i].name;
+
+	/* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */
+	return advanced_lookup[i].name;
+}
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table {
+	u32 valid;		/* (nonzero) valid, (0) log is empty */
+	u32 error_id;		/* type of error */
+	u32 pc;			/* program counter */
+	u32 blink1;		/* branch link */
+	u32 blink2;		/* branch link */
+	u32 ilink1;		/* interrupt link */
+	u32 ilink2;		/* interrupt link */
+	u32 data1;		/* error-specific data */
+	u32 data2;		/* error-specific data */
+	u32 data3;		/* error-specific data */
+	u32 bcon_time;		/* beacon timer */
+	u32 tsf_low;		/* network timestamp function timer */
+	u32 tsf_hi;		/* network timestamp function timer */
+	u32 gp1;		/* GP1 timer register */
+	u32 gp2;		/* GP2 timer register */
+	u32 gp3;		/* GP3 timer register */
+	u32 ucode_ver;		/* uCode version */
+	u32 hw_ver;		/* HW Silicon version */
+	u32 brd_ver;		/* HW board version */
+	u32 log_pc;		/* log program counter */
+	u32 frame_ptr;		/* frame pointer */
+	u32 stack_ptr;		/* stack pointer */
+	u32 hcmd;		/* last host command header */
+	u32 isr0;		/* isr status register LMPM_NIC_ISR0:
+				 * rxtx_flag */
+	u32 isr1;		/* isr status register LMPM_NIC_ISR1:
+				 * host_flag */
+	u32 isr2;		/* isr status register LMPM_NIC_ISR2:
+				 * enc_flag */
+	u32 isr3;		/* isr status register LMPM_NIC_ISR3:
+				 * time_flag */
+	u32 isr4;		/* isr status register LMPM_NIC_ISR4:
+				 * wico interrupt */
+	u32 isr_pref;		/* isr status register LMPM_NIC_PREF_STAT */
+	u32 wait_event;		/* wait event() caller address */
+	u32 l2p_control;	/* L2pControlField */
+	u32 l2p_duration;	/* L2pDurationField */
+	u32 l2p_mhvalid;	/* L2pMhValidBits */
+	u32 l2p_addr_match;	/* L2pAddrMatchStat */
+	u32 lmpm_pmg_sel;	/* indicate which clocks are turned on
+				 * (LMPM_PMG_SEL) */
+	u32 u_timestamp;	/* indicate when the date and time of the
+				 * compilation */
+	u32 flow_handler;	/* FH read/write pointers, RX credit */
+} __packed;
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
+{
+	struct iwl_trans *trans = mvm->trans;
+	struct iwl_error_event_table table;
+	u32 base;
+
+	base = mvm->error_event_table;
+	if (mvm->cur_ucode == IWL_UCODE_INIT) {
+		if (!base)
+			base = mvm->fw->init_errlog_ptr;
+	} else {
+		if (!base)
+			base = mvm->fw->inst_errlog_ptr;
+	}
+
+	if (base < 0x800000 || base >= 0x80C000) {
+		IWL_ERR(mvm,
+			"Not valid error log pointer 0x%08X for %s uCode\n",
+			base,
+			(mvm->cur_ucode == IWL_UCODE_INIT)
+					? "Init" : "RT");
+		return;
+	}
+
+	iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+	if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+		IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+		IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+			mvm->status, table.valid);
+	}
+
+	trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
+				      table.data1, table.data2, table.data3,
+				      table.blink1, table.blink2, table.ilink1,
+				      table.ilink2, table.bcon_time, table.gp1,
+				      table.gp2, table.gp3, table.ucode_ver,
+				      table.hw_ver, table.brd_ver);
+	IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
+		desc_lookup(table.error_id));
+	IWL_ERR(mvm, "0x%08X | uPc\n", table.pc);
+	IWL_ERR(mvm, "0x%08X | branchlink1\n", table.blink1);
+	IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2);
+	IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1);
+	IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2);
+	IWL_ERR(mvm, "0x%08X | data1\n", table.data1);
+	IWL_ERR(mvm, "0x%08X | data2\n", table.data2);
+	IWL_ERR(mvm, "0x%08X | data3\n", table.data3);
+	IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time);
+	IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low);
+	IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi);
+	IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1);
+	IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2);
+	IWL_ERR(mvm, "0x%08X | time gp3\n", table.gp3);
+	IWL_ERR(mvm, "0x%08X | uCode version\n", table.ucode_ver);
+	IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver);
+	IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver);
+	IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd);
+	IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0);
+	IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1);
+	IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2);
+	IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3);
+	IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4);
+	IWL_ERR(mvm, "0x%08X | isr_pref\n", table.isr_pref);
+	IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event);
+	IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control);
+	IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration);
+	IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+	IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+	IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+	IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
+	IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+/**
+ * iwl_mvm_send_lq_cmd() - Send link quality command
+ * @init: This command is sent as part of station initialization right
+ *        after station has been added.
+ *
+ * The link quality command is sent as the last step of station creation.
+ * This is the special case in which init is set and we call a callback in
+ * this case to clear the state indicating that station creation is in
+ * progress.
+ */
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
+			u8 flags, bool init)
+{
+	struct iwl_host_cmd cmd = {
+		.id = LQ_CMD,
+		.len = { sizeof(struct iwl_lq_cmd), },
+		.flags = flags,
+		.data = { lq, },
+	};
+
+	if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+		return -EINVAL;
+
+	if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
+		return -EINVAL;
+
+	return iwl_mvm_send_cmd(mvm, &cmd);
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/pcie/1000.c
index f8620ec..ff33897 100644
--- a/drivers/net/wireless/iwlwifi/pcie/1000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/1000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c
index 244019c..e7de331 100644
--- a/drivers/net/wireless/iwlwifi/pcie/2000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/2000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/pcie/5000.c b/drivers/net/wireless/iwlwifi/pcie/5000.c
index 83ca403..5096f7c 100644
--- a/drivers/net/wireless/iwlwifi/pcie/5000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/5000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/pcie/6000.c b/drivers/net/wireless/iwlwifi/pcie/6000.c
index d4df976..801ff49 100644
--- a/drivers/net/wireless/iwlwifi/pcie/6000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/6000.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
diff --git a/drivers/net/wireless/iwlwifi/pcie/7000.c b/drivers/net/wireless/iwlwifi/pcie/7000.c
new file mode 100644
index 0000000..6e35b2b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/7000.c
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+
+/* Highest firmware API version supported */
+#define IWL7260_UCODE_API_MAX	6
+#define IWL3160_UCODE_API_MAX	6
+
+/* Oldest version we won't warn about */
+#define IWL7260_UCODE_API_OK	6
+#define IWL3160_UCODE_API_OK	6
+
+/* Lowest firmware API version supported */
+#define IWL7260_UCODE_API_MIN	6
+#define IWL3160_UCODE_API_MIN	6
+
+/* NVM versions */
+#define IWL7260_NVM_VERSION		0x0a1d
+#define IWL7260_TX_POWER_VERSION	0xffff /* meaningless */
+#define IWL3160_NVM_VERSION		0x709
+#define IWL3160_TX_POWER_VERSION	0xffff /* meaningless */
+
+#define IWL7260_FW_PRE "iwlwifi-7260-"
+#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
+
+#define IWL3160_FW_PRE "iwlwifi-3160-"
+#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl7000_base_params = {
+	.eeprom_size = OTP_LOW_IMAGE_SIZE,
+	.num_of_queues = IWLAGN_NUM_QUEUES,
+	.pll_cfg_val = 0,
+	.shadow_ram_support = true,
+	.led_compensation = 57,
+	.adv_thermal_throttle = true,
+	.support_ct_kill_exit = true,
+	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+	.chain_noise_scale = 1000,
+	.wd_timeout = IWL_LONG_WD_TIMEOUT,
+	.max_event_log_size = 512,
+	.shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_ht_params iwl7000_ht_params = {
+	.ht_greenfield_support = true,
+	.use_rts_for_aggregation = true, /* use rts/cts protection */
+	.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+#define IWL_DEVICE_7000						\
+	.ucode_api_max = IWL7260_UCODE_API_MAX,			\
+	.ucode_api_ok = IWL7260_UCODE_API_OK,			\
+	.ucode_api_min = IWL7260_UCODE_API_MIN,			\
+	.device_family = IWL_DEVICE_FAMILY_7000,		\
+	.max_inst_size = IWL60_RTC_INST_SIZE,			\
+	.max_data_size = IWL60_RTC_DATA_SIZE,			\
+	.base_params = &iwl7000_base_params,			\
+	/* TODO: .bt_params? */					\
+	.need_temp_offset_calib = true,				\
+	.led_mode = IWL_LED_RF_STATE,				\
+	.adv_pm = true						\
+
+
+const struct iwl_cfg iwl7260_2ac_cfg = {
+	.name = "Intel(R) Dual Band Wireless AC7260",
+	.fw_name_pre = IWL7260_FW_PRE,
+	IWL_DEVICE_7000,
+	.ht_params = &iwl7000_ht_params,
+	.nvm_ver = IWL7260_NVM_VERSION,
+	.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
+};
+
+const struct iwl_cfg iwl3160_ac_cfg = {
+	.name = "Intel(R) Dual Band Wireless AC3160",
+	.fw_name_pre = IWL3160_FW_PRE,
+	IWL_DEVICE_7000,
+	.ht_params = &iwl7000_ht_params,
+	.nvm_ver = IWL3160_NVM_VERSION,
+	.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
+};
+
+MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h
index 82152311..c6f8e83 100644
--- a/drivers/net/wireless/iwlwifi/pcie/cfg.h
+++ b/drivers/net/wireless/iwlwifi/pcie/cfg.h
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -109,5 +109,7 @@
 extern const struct iwl_cfg iwl105_bgn_cfg;
 extern const struct iwl_cfg iwl105_bgn_d_cfg;
 extern const struct iwl_cfg iwl135_bgn_cfg;
+extern const struct iwl_cfg iwl7260_2ac_cfg;
+extern const struct iwl_cfg iwl3160_ac_cfg;
 
 #endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index c2e141a..7bc0fb9 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -255,6 +255,12 @@
 	{IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
 	{IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
 
+/* 7000 Series */
+	{IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)},
+
 	{0}
 };
 MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index d91d2e8..aa2a39a 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -222,8 +222,6 @@
  * @rx_replenish: work that will be called when buffers need to be allocated
  * @drv - pointer to iwl_drv
  * @trans: pointer to the generic transport area
- * @irq - the irq number for the device
- * @irq_requested: true when the irq has been requested
  * @scd_base_addr: scheduler sram base address in SRAM
  * @scd_bc_tbls: pointer to the byte count table of the scheduler
  * @kw: keep warm address
@@ -234,8 +232,10 @@
  * @status - transport specific status flags
  * @cmd_queue - command queue number
  * @rx_buf_size_8k: 8 kB RX buffer size
+ * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
  * @rx_page_order: page order for receive buffer size
  * @wd_timeout: queue watchdog timeout (jiffies)
+ * @reg_lock: protect hw register access
  */
 struct iwl_trans_pcie {
 	struct iwl_rxq rxq;
@@ -249,11 +249,8 @@
 	int ict_index;
 	u32 inta;
 	bool use_ict;
-	bool irq_requested;
-	struct tasklet_struct irq_tasklet;
 	struct isr_statistics isr_stats;
 
-	unsigned int irq;
 	spinlock_t irq_lock;
 	u32 inta_mask;
 	u32 scd_base_addr;
@@ -279,12 +276,16 @@
 	u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
 
 	bool rx_buf_size_8k;
+	bool bc_table_dword;
 	u32 rx_page_order;
 
 	const char **command_names;
 
 	/* queue watchdog */
 	unsigned long wd_timeout;
+
+	/*protect hw register */
+	spinlock_t reg_lock;
 };
 
 /**
@@ -328,7 +329,7 @@
 * RX
 ******************************************************/
 int iwl_pcie_rx_init(struct iwl_trans *trans);
-void iwl_pcie_tasklet(struct iwl_trans *trans);
+irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id);
 int iwl_pcie_rx_stop(struct iwl_trans *trans);
 void iwl_pcie_rx_free(struct iwl_trans *trans);
 
@@ -359,6 +360,8 @@
 			    struct iwl_rx_cmd_buffer *rxb, int handler_status);
 void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
 			    struct sk_buff_head *skbs);
+void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
+
 /*****************************************************
 * Error handling
 ******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 8389cd3..b0ae06d 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -81,10 +81,10 @@
  *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
  *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
- *   were enough free buffers and RX_STALLED is set it is cleared.
+ * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
+ *   rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
+ *   the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
+ *   If there were enough free buffers and RX_STALLED is set it is cleared.
  *
  *
  * Driver sequence:
@@ -214,9 +214,9 @@
 	/*
 	 * If the device isn't enabled - not need to try to add buffers...
 	 * This can happen when we stop the device and still have an interrupt
-	 * pending. We stop the APM before we sync the interrupts / tasklets
-	 * because we have to (see comment there). On the other hand, since
-	 * the APM is stopped, we cannot access the HW (in particular not prph).
+	 * pending. We stop the APM before we sync the interrupts because we
+	 * have to (see comment there). On the other hand, since the APM is
+	 * stopped, we cannot access the HW (in particular not prph).
 	 * So don't try to restock if the APM has been already stopped.
 	 */
 	if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
@@ -436,7 +436,7 @@
 err_rb_stts:
 	dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
 			  rxq->bd, rxq->bd_dma);
-	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+	rxq->bd_dma = 0;
 	rxq->bd = NULL;
 err_bd:
 	return -ENOMEM;
@@ -455,6 +455,10 @@
 
 	/* Stop Rx DMA */
 	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	/* reset and flush pointers */
+	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
+	iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
+	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
 
 	/* Reset driver's Rx queue write index */
 	iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@@ -491,7 +495,6 @@
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	struct iwl_rxq *rxq = &trans_pcie->rxq;
-
 	int i, err;
 	unsigned long flags;
 
@@ -518,6 +521,7 @@
 	rxq->read = rxq->write = 0;
 	rxq->write_actual = 0;
 	rxq->free_count = 0;
+	memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
 	spin_unlock_irqrestore(&rxq->lock, flags);
 
 	iwl_pcie_rx_replenish(trans);
@@ -545,13 +549,15 @@
 		return;
 	}
 
+	cancel_work_sync(&trans_pcie->rx_replenish);
+
 	spin_lock_irqsave(&rxq->lock, flags);
 	iwl_pcie_rxq_free_rbs(trans);
 	spin_unlock_irqrestore(&rxq->lock, flags);
 
 	dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
 			  rxq->bd, rxq->bd_dma);
-	memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+	rxq->bd_dma = 0;
 	rxq->bd = NULL;
 
 	if (rxq->rb_stts)
@@ -560,7 +566,7 @@
 				  rxq->rb_stts, rxq->rb_stts_dma);
 	else
 		IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-	memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+	rxq->rb_stts_dma = 0;
 	rxq->rb_stts = NULL;
 }
 
@@ -588,6 +594,7 @@
 		int index, cmd_index, err, len;
 		struct iwl_rx_cmd_buffer rxcb = {
 			._offset = offset,
+			._rx_page_order = trans_pcie->rx_page_order,
 			._page = rxb->page,
 			._page_stolen = false,
 			.truesize = max_len,
@@ -789,11 +796,14 @@
 	clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
 	wake_up(&trans_pcie->wait_command_queue);
 
+	local_bh_disable();
 	iwl_op_mode_nic_error(trans->op_mode);
+	local_bh_enable();
 }
 
-void iwl_pcie_tasklet(struct iwl_trans *trans)
+irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 {
+	struct iwl_trans *trans = dev_id;
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
 	u32 inta = 0;
@@ -804,6 +814,8 @@
 	u32 inta_mask;
 #endif
 
+	lock_map_acquire(&trans->sync_cmd_lockdep_map);
+
 	spin_lock_irqsave(&trans_pcie->irq_lock, flags);
 
 	/* Ack/clear/reset pending uCode interrupts.
@@ -848,7 +860,7 @@
 
 		handled |= CSR_INT_BIT_HW_ERR;
 
-		return;
+		goto out;
 	}
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -998,6 +1010,10 @@
 	/* Re-enable RF_KILL if it occurred */
 	else if (handled & CSR_INT_BIT_RF_KILL)
 		iwl_enable_rfkill_int(trans);
+
+out:
+	lock_map_release(&trans->sync_cmd_lockdep_map);
+	return IRQ_HANDLED;
 }
 
 /******************************************************************************
@@ -1120,7 +1136,7 @@
 
 	/* 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 have something to service, the irq thread will re-enable ints.
 	 * If we *don't* have something, we'll re-enable before leaving here. */
 	inta_mask = iwl_read32(trans, CSR_INT_MASK);
 	iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -1160,9 +1176,9 @@
 #endif
 
 	trans_pcie->inta |= inta;
-	/* iwl_pcie_tasklet() will service interrupts and re-enable them */
+	/* the thread will service interrupts and re-enable them */
 	if (likely(inta))
-		tasklet_schedule(&trans_pcie->irq_tasklet);
+		return IRQ_WAKE_THREAD;
 	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
 		 !trans_pcie->inta)
 		iwl_enable_interrupts(trans);
@@ -1270,9 +1286,10 @@
 	trans_pcie->inta |= inta;
 
 	/* iwl_pcie_tasklet() will service interrupts and re-enable them */
-	if (likely(inta))
-		tasklet_schedule(&trans_pcie->irq_tasklet);
-	else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+	if (likely(inta)) {
+		spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+		return IRQ_WAKE_THREAD;
+	} else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
 		 !trans_pcie->inta) {
 		/* Allow interrupt if was disabled by this handler and
 		 * no tasklet was schedules, We should not enable interrupt,
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 35708b9..17bedc5 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,21 +75,43 @@
 #include "iwl-agn-hw.h"
 #include "internal.h"
 
-static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans)
+static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
+						  u32 reg, u32 mask, u32 value)
 {
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
+	u32 v;
 
-		if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
-			iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-					       APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
-					       ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
+#ifdef CONFIG_IWLWIFI_DEBUG
+	WARN_ON_ONCE(value & ~mask);
+#endif
 
-	iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-			       APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
-			       ~APMG_PS_CTRL_MSK_PWR_SRC);
+	v = iwl_read32(trans, reg);
+	v &= ~mask;
+	v |= value;
+	iwl_write32(trans, reg, v);
+}
+
+static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
+					      u32 reg, u32 mask)
+{
+	__iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
+}
+
+static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
+					    u32 reg, u32 mask)
+{
+	__iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
+}
+
+static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
+{
+	if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
+		iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+				       APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+				       ~APMG_PS_CTRL_MSK_PWR_SRC);
+	else
+		iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+				       APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+				       ~APMG_PS_CTRL_MSK_PWR_SRC);
 }
 
 /* PCI registers */
@@ -259,7 +281,7 @@
 
 	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
-	iwl_pcie_set_pwr_vmain(trans);
+	iwl_pcie_set_pwr(trans, false);
 
 	iwl_op_mode_nic_config(trans->op_mode);
 
@@ -435,7 +457,7 @@
 }
 
 static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
-				   const struct fw_img *fw)
+				   const struct fw_img *fw, bool run_in_rfkill)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	int ret;
@@ -454,7 +476,7 @@
 	/* If platform's RF_KILL switch is NOT set to KILL */
 	hw_rfkill = iwl_is_rfkill_set(trans);
 	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-	if (hw_rfkill)
+	if (hw_rfkill && !run_in_rfkill)
 		return -ERFKILL;
 
 	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
@@ -534,12 +556,6 @@
 
 	iwl_enable_rfkill_int(trans);
 
-	/* wait to make sure we flush pending tasklet*/
-	synchronize_irq(trans_pcie->irq);
-	tasklet_kill(&trans_pcie->irq_tasklet);
-
-	cancel_work_sync(&trans_pcie->rx_replenish);
-
 	/* stop and reset the on-board processor */
 	iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
@@ -551,46 +567,87 @@
 	clear_bit(STATUS_RFKILL, &trans_pcie->status);
 }
 
-static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
+static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
 {
 	/* let the ucode operate on its own */
 	iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
 		    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
 	iwl_disable_interrupts(trans);
+	iwl_pcie_disable_ict(trans);
+
 	iwl_clear_bit(trans, CSR_GP_CNTRL,
 		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	iwl_clear_bit(trans, CSR_GP_CNTRL,
+		      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+	/*
+	 * reset TX queues -- some of their registers reset during S3
+	 * so if we don't reset everything here the D3 image would try
+	 * to execute some invalid memory upon resume
+	 */
+	iwl_trans_pcie_tx_reset(trans);
+
+	iwl_pcie_set_pwr(trans, true);
+}
+
+static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
+				    enum iwl_d3_status *status)
+{
+	u32 val;
+	int ret;
+
+	iwl_pcie_set_pwr(trans, false);
+
+	val = iwl_read32(trans, CSR_RESET);
+	if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
+		*status = IWL_D3_STATUS_RESET;
+		return 0;
+	}
+
+	/*
+	 * Also enables interrupts - none will happen as the device doesn't
+	 * know we're waking it up, only when the opmode actually tells it
+	 * after this call.
+	 */
+	iwl_pcie_reset_ict(trans);
+
+	iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			   25000);
+	if (ret) {
+		IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
+		return ret;
+	}
+
+	iwl_trans_pcie_tx_reset(trans);
+
+	ret = iwl_pcie_rx_init(trans);
+	if (ret) {
+		IWL_ERR(trans, "Failed to resume the device (RX reset)\n");
+		return ret;
+	}
+
+	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+	*status = IWL_D3_STATUS_ALIVE;
+	return 0;
 }
 
 static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 {
-	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	int err;
 	bool hw_rfkill;
-
-	trans_pcie->inta_mask = CSR_INI_SET_MASK;
-
-	if (!trans_pcie->irq_requested) {
-		tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-			iwl_pcie_tasklet, (unsigned long)trans);
-
-		iwl_pcie_alloc_ict(trans);
-
-		err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict,
-				  IRQF_SHARED, DRV_NAME, trans);
-		if (err) {
-			IWL_ERR(trans, "Error allocating IRQ %d\n",
-				trans_pcie->irq);
-			goto error;
-		}
-
-		trans_pcie->irq_requested = true;
-	}
+	int err;
 
 	err = iwl_pcie_prepare_card_hw(trans);
 	if (err) {
 		IWL_ERR(trans, "Error while preparing HW: %d\n", err);
-		goto err_free_irq;
+		return err;
 	}
 
 	iwl_pcie_apm_init(trans);
@@ -601,15 +658,7 @@
 	hw_rfkill = iwl_is_rfkill_set(trans);
 	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
-	return err;
-
-err_free_irq:
-	trans_pcie->irq_requested = false;
-	free_irq(trans_pcie->irq, trans);
-error:
-	iwl_pcie_free_ict(trans);
-	tasklet_kill(&trans_pcie->irq_tasklet);
-	return err;
+	return 0;
 }
 
 static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
@@ -703,19 +752,20 @@
 		msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
 
 	trans_pcie->command_names = trans_cfg->command_names;
+	trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
 }
 
 void iwl_trans_pcie_free(struct iwl_trans *trans)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
+	synchronize_irq(trans_pcie->pci_dev->irq);
+
 	iwl_pcie_tx_free(trans);
 	iwl_pcie_rx_free(trans);
 
-	if (trans_pcie->irq_requested == true) {
-		free_irq(trans_pcie->irq, trans);
-		iwl_pcie_free_ict(trans);
-	}
+	free_irq(trans_pcie->pci_dev->irq, trans);
+	iwl_pcie_free_ict(trans);
 
 	pci_disable_msi(trans_pcie->pci_dev);
 	iounmap(trans_pcie->hw_base);
@@ -751,13 +801,126 @@
 	hw_rfkill = iwl_is_rfkill_set(trans);
 	iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
-	if (!hw_rfkill)
-		iwl_enable_interrupts(trans);
-
 	return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
+static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
+						unsigned long *flags)
+{
+	int ret;
+	struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
+	spin_lock_irqsave(&pcie_trans->reg_lock, *flags);
+
+	/* this bit wakes up the NIC */
+	__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
+				 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	/*
+	 * These bits say the device is running, and should keep running for
+	 * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
+	 * but they do not indicate that embedded SRAM is restored yet;
+	 * 3945 and 4965 have volatile SRAM, and must save/restore contents
+	 * to/from host DRAM when sleeping/waking for power-saving.
+	 * Each direction takes approximately 1/4 millisecond; with this
+	 * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
+	 * series of register accesses are expected (e.g. reading Event Log),
+	 * to keep device from sleeping.
+	 *
+	 * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
+	 * SRAM is okay/restored.  We don't check that here because this call
+	 * is just for hardware register access; but GP1 MAC_SLEEP check is a
+	 * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
+	 *
+	 * 5000 series and later (including 1000 series) have non-volatile SRAM,
+	 * and do not save/restore SRAM when power cycling.
+	 */
+	ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
+	if (unlikely(ret < 0)) {
+		iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
+		if (!silent) {
+			u32 val = iwl_read32(trans, CSR_GP_CNTRL);
+			WARN_ONCE(1,
+				  "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
+				  val);
+			spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
+			return false;
+		}
+	}
+
+	/*
+	 * Fool sparse by faking we release the lock - sparse will
+	 * track nic_access anyway.
+	 */
+	__release(&pcie_trans->reg_lock);
+	return true;
+}
+
+static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
+					      unsigned long *flags)
+{
+	struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+	lockdep_assert_held(&pcie_trans->reg_lock);
+
+	/*
+	 * Fool sparse by faking we acquiring the lock - sparse will
+	 * track nic_access anyway.
+	 */
+	__acquire(&pcie_trans->reg_lock);
+
+	__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
+				   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	/*
+	 * Above we read the CSR_GP_CNTRL register, which will flush
+	 * any previous writes, but we need the write that clears the
+	 * MAC_ACCESS_REQ bit to be performed before any other writes
+	 * scheduled on different CPUs (after we drop reg_lock).
+	 */
+	mmiowb();
+	spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
+}
+
+static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
+				   void *buf, int dwords)
+{
+	unsigned long flags;
+	int offs, ret = 0;
+	u32 *vals = buf;
+
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+		iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
+		for (offs = 0; offs < dwords; offs++)
+			vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+		iwl_trans_release_nic_access(trans, &flags);
+	} else {
+		ret = -EBUSY;
+	}
+	return ret;
+}
+
+static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
+				    void *buf, int dwords)
+{
+	unsigned long flags;
+	int offs, ret = 0;
+	u32 *vals = buf;
+
+	if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+		iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
+		for (offs = 0; offs < dwords; offs++)
+			iwl_write32(trans, HBUS_TARG_MEM_WDAT,
+				    vals ? vals[offs] : 0);
+		iwl_trans_release_nic_access(trans, &flags);
+	} else {
+		ret = -EBUSY;
+	}
+	return ret;
+}
+
 #define IWL_FLUSH_WAIT_MS	2000
 
 static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
@@ -767,6 +930,8 @@
 	struct iwl_queue *q;
 	int cnt;
 	unsigned long now = jiffies;
+	u32 scd_sram_addr;
+	u8 buf[16];
 	int ret = 0;
 
 	/* waiting for all the tx frames complete might take a while */
@@ -780,14 +945,64 @@
 			msleep(1);
 
 		if (q->read_ptr != q->write_ptr) {
-			IWL_ERR(trans, "fail to flush all tx fifo queues\n");
+			IWL_ERR(trans,
+				"fail to flush all tx fifo queues Q %d\n", cnt);
 			ret = -ETIMEDOUT;
 			break;
 		}
 	}
+
+	if (!ret)
+		return 0;
+
+	IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
+		txq->q.read_ptr, txq->q.write_ptr);
+
+	scd_sram_addr = trans_pcie->scd_base_addr +
+			SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
+	iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+
+	iwl_print_hex_error(trans, buf, sizeof(buf));
+
+	for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++)
+		IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt,
+			iwl_read_direct32(trans, FH_TX_TRB_REG(cnt)));
+
+	for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+		u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt));
+		u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
+		bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
+		u32 tbl_dw =
+			iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr +
+					     SCD_TRANS_TBL_OFFSET_QUEUE(cnt));
+
+		if (cnt & 0x1)
+			tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
+		else
+			tbl_dw = tbl_dw & 0x0000FFFF;
+
+		IWL_ERR(trans,
+			"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
+			cnt, active ? "" : "in", fifo, tbl_dw,
+			iwl_read_prph(trans,
+				      SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1),
+			iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
+	}
+
 	return ret;
 }
 
+static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
+					 u32 mask, u32 value)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	unsigned long flags;
+
+	spin_lock_irqsave(&trans_pcie->reg_lock, flags);
+	__iwl_trans_pcie_set_bits_mask(trans, reg, mask, value);
+	spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+}
+
 static const char *get_fh_string(int cmd)
 {
 #define IWL_CMD(x) case x: return #x
@@ -1212,7 +1427,8 @@
 	.start_fw = iwl_trans_pcie_start_fw,
 	.stop_device = iwl_trans_pcie_stop_device,
 
-	.wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
+	.d3_suspend = iwl_trans_pcie_d3_suspend,
+	.d3_resume = iwl_trans_pcie_d3_resume,
 
 	.send_cmd = iwl_trans_pcie_send_hcmd,
 
@@ -1235,8 +1451,13 @@
 	.read32 = iwl_trans_pcie_read32,
 	.read_prph = iwl_trans_pcie_read_prph,
 	.write_prph = iwl_trans_pcie_write_prph,
+	.read_mem = iwl_trans_pcie_read_mem,
+	.write_mem = iwl_trans_pcie_write_mem,
 	.configure = iwl_trans_pcie_configure,
 	.set_pmi = iwl_trans_pcie_set_pmi,
+	.grab_nic_access = iwl_trans_pcie_grab_nic_access,
+	.release_nic_access = iwl_trans_pcie_release_nic_access,
+	.set_bits_mask = iwl_trans_pcie_set_bits_mask,
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
@@ -1258,8 +1479,10 @@
 
 	trans->ops = &trans_ops_pcie;
 	trans->cfg = cfg;
+	trans_lockdep_init(trans);
 	trans_pcie->trans = trans;
 	spin_lock_init(&trans_pcie->irq_lock);
+	spin_lock_init(&trans_pcie->reg_lock);
 	init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
 	/* W/A - seems to solve weird behavior. We need to remove this if we
@@ -1318,7 +1541,6 @@
 	}
 
 	trans->dev = &pdev->dev;
-	trans_pcie->irq = pdev->irq;
 	trans_pcie->pci_dev = pdev;
 	trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
 	trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
@@ -1327,7 +1549,6 @@
 
 	/* Initialize the wait queue for commands */
 	init_waitqueue_head(&trans_pcie->wait_command_queue);
-	spin_lock_init(&trans->reg_lock);
 
 	snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
 		 "iwl_cmd_pool:%s", dev_name(trans->dev));
@@ -1344,8 +1565,24 @@
 	if (!trans->dev_cmd_pool)
 		goto out_pci_disable_msi;
 
+	trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+	if (iwl_pcie_alloc_ict(trans))
+		goto out_free_cmd_pool;
+
+	if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
+				 iwl_pcie_irq_handler,
+				 IRQF_SHARED, DRV_NAME, trans)) {
+		IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
+		goto out_free_ict;
+	}
+
 	return trans;
 
+out_free_ict:
+	iwl_pcie_free_ict(trans);
+out_free_cmd_pool:
+	kmem_cache_destroy(trans->dev_cmd_pool);
 out_pci_disable_msi:
 	pci_disable_msi(pdev);
 out_pci_release_regions:
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 6c5b867..8e9e321 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -160,7 +160,7 @@
 	IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
 		txq->q.read_ptr, txq->q.write_ptr);
 
-	iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+	iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
 
 	iwl_print_hex_error(trans, buf, sizeof(buf));
 
@@ -173,9 +173,9 @@
 		u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
 		bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
 		u32 tbl_dw =
-			iwl_read_targ_mem(trans,
-					  trans_pcie->scd_base_addr +
-					  SCD_TRANS_TBL_OFFSET_QUEUE(i));
+			iwl_trans_read_mem32(trans,
+					     trans_pcie->scd_base_addr +
+					     SCD_TRANS_TBL_OFFSET_QUEUE(i));
 
 		if (i & 0x1)
 			tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
@@ -237,7 +237,10 @@
 		break;
 	}
 
-	bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+	if (trans_pcie->bc_table_dword)
+		len = DIV_ROUND_UP(len, 4);
+
+	bc_ent = cpu_to_le16(len | (sta_id << 12));
 
 	scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
 
@@ -306,6 +309,9 @@
 				return;
 			}
 
+			IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id,
+				     txq->q.write_ptr);
+
 			iwl_write_direct32(trans, HBUS_TARG_WRPTR,
 				     txq->q.write_ptr | (txq_id << 8));
 
@@ -612,7 +618,7 @@
 	if (txq->q.n_bd) {
 		dma_free_coherent(dev, sizeof(struct iwl_tfd) *
 				  txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-		memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+		txq->q.dma_addr = 0;
 	}
 
 	kfree(txq->entries);
@@ -638,9 +644,11 @@
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-	u32 a;
+	int nq = trans->cfg->base_params->num_of_queues;
 	int chan;
 	u32 reg_val;
+	int clear_dwords = (SCD_TRANS_TBL_OFFSET_QUEUE(nq) -
+				SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(u32);
 
 	/* make sure all queue are not stopped/used */
 	memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
@@ -652,20 +660,10 @@
 	WARN_ON(scd_base_addr != 0 &&
 		scd_base_addr != trans_pcie->scd_base_addr);
 
-	a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
-	/* reset conext data memory */
-	for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
-		a += 4)
-		iwl_write_targ_mem(trans, a, 0);
-	/* reset tx status memory */
-	for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
-		a += 4)
-		iwl_write_targ_mem(trans, a, 0);
-	for (; a < trans_pcie->scd_base_addr +
-	       SCD_TRANS_TBL_OFFSET_QUEUE(
-				trans->cfg->base_params->num_of_queues);
-	       a += 4)
-		iwl_write_targ_mem(trans, a, 0);
+	/* reset context data, TX status and translation data */
+	iwl_trans_write_mem(trans, trans_pcie->scd_base_addr +
+				   SCD_CONTEXT_MEM_LOWER_BOUND,
+			    NULL, clear_dwords);
 
 	iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
 		       trans_pcie->scd_bc_tbls.dma >> 10);
@@ -697,6 +695,29 @@
 			    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 }
 
+void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
+{
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int txq_id;
+
+	for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+	     txq_id++) {
+		struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+
+		iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
+				   txq->q.dma_addr >> 8);
+		iwl_pcie_txq_unmap(trans, txq_id);
+		txq->q.read_ptr = 0;
+		txq->q.write_ptr = 0;
+	}
+
+	/* Tell NIC where to find the "keep warm" buffer */
+	iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
+			   trans_pcie->kw.dma >> 4);
+
+	iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
+}
+
 /*
  * iwl_pcie_tx_stop - Stop all Tx DMA channels
  */
@@ -905,7 +926,7 @@
 	if (WARN_ON(txq_id == trans_pcie->cmd_queue))
 		return;
 
-	spin_lock(&txq->lock);
+	spin_lock_bh(&txq->lock);
 
 	if (txq->q.read_ptr == tfd_num)
 		goto out;
@@ -949,7 +970,7 @@
 	if (iwl_queue_space(&txq->q) > txq->q.low_mark)
 		iwl_wake_queue(trans, txq);
 out:
-	spin_unlock(&txq->lock);
+	spin_unlock_bh(&txq->lock);
 }
 
 /*
@@ -1002,14 +1023,14 @@
 	tbl_dw_addr = trans_pcie->scd_base_addr +
 			SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
 
-	tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
+	tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr);
 
 	if (txq_id & 0x1)
 		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
 	else
 		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
 
-	iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
+	iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw);
 
 	return 0;
 }
@@ -1068,9 +1089,9 @@
 	iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
 
 	/* Set up Tx window size and frame limit for this queue */
-	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+	iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
 			SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
-	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+	iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
 			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
 			((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
 				SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
@@ -1101,8 +1122,8 @@
 
 	iwl_pcie_txq_set_inactive(trans, txq_id);
 
-	_iwl_write_targ_mem_dwords(trans, stts_addr,
-				   zero_val, ARRAY_SIZE(zero_val));
+	iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+			    ARRAY_SIZE(zero_val));
 
 	iwl_pcie_txq_unmap(trans, txq_id);
 
@@ -1350,7 +1371,7 @@
 		return;
 	}
 
-	spin_lock(&txq->lock);
+	spin_lock_bh(&txq->lock);
 
 	cmd_index = get_cmd_index(&txq->q, index);
 	cmd = txq->entries[cmd_index].cmd;
@@ -1384,7 +1405,7 @@
 
 	meta->flags = 0;
 
-	spin_unlock(&txq->lock);
+	spin_unlock_bh(&txq->lock);
 }
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)
@@ -1642,10 +1663,6 @@
 	tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
 	tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
 
-	IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
-		     le16_to_cpu(dev_cmd->hdr.sequence));
-	IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-
 	/* Set up entry for this TFD in Tx byte-count array */
 	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
 
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index ec6d5d6..116f4ab 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -657,7 +657,7 @@
 					capa, intvl, ie, ielen,
 					LBS_SCAN_RSSI_TO_MBM(rssi),
 					GFP_KERNEL);
-				cfg80211_put_bss(bss);
+				cfg80211_put_bss(wiphy, bss);
 			}
 		} else
 			lbs_deb_scan("scan response: missing BSS channel IE\n");
@@ -1444,7 +1444,7 @@
 
  done:
 	if (bss)
-		cfg80211_put_bss(bss);
+		cfg80211_put_bss(wiphy, bss);
 	lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
 	return ret;
 }
@@ -1766,7 +1766,7 @@
 				  params->beacon_interval,
 				  fake_ie, fake - fake_ie,
 				  0, GFP_KERNEL);
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(priv->wdev->wiphy, bss);
 
 	memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
 	priv->wdev->ssid_len = params->ssid_len;
@@ -2011,7 +2011,7 @@
 
 	if (bss) {
 		ret = lbs_ibss_join_existing(priv, params, bss);
-		cfg80211_put_bss(bss);
+		cfg80211_put_bss(wiphy, bss);
 	} else
 		ret = lbs_ibss_start_new(priv, params);
 
@@ -2081,10 +2081,8 @@
 	lbs_deb_enter(LBS_DEB_CFG80211);
 
 	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
-	if (!wdev) {
-		dev_err(dev, "cannot allocate wireless device\n");
+	if (!wdev)
 		return ERR_PTR(-ENOMEM);
-	}
 
 	wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
 	if (!wdev->wiphy) {
@@ -2132,6 +2130,21 @@
 	lbs_deb_leave(LBS_DEB_CFG80211);
 }
 
+static void lbs_reg_notifier(struct wiphy *wiphy,
+			     struct regulatory_request *request)
+{
+	struct lbs_private *priv = wiphy_priv(wiphy);
+
+	lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+			"callback for domain %c%c\n", request->alpha2[0],
+			request->alpha2[1]);
+
+	memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+	if (lbs_iface_active(priv))
+		lbs_set_11d_domain_info(priv);
+
+	lbs_deb_leave(LBS_DEB_CFG80211);
+}
 
 /*
  * This function get's called after lbs_setup_firmware() determined the
@@ -2184,24 +2197,6 @@
 	return ret;
 }
 
-int lbs_reg_notifier(struct wiphy *wiphy,
-		struct regulatory_request *request)
-{
-	struct lbs_private *priv = wiphy_priv(wiphy);
-	int ret = 0;
-
-	lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
-			"callback for domain %c%c\n", request->alpha2[0],
-			request->alpha2[1]);
-
-	memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
-	if (lbs_iface_active(priv))
-		ret = lbs_set_11d_domain_info(priv);
-
-	lbs_deb_leave(LBS_DEB_CFG80211);
-	return ret;
-}
-
 void lbs_scan_deinit(struct lbs_private *priv)
 {
 	lbs_deb_enter(LBS_DEB_CFG80211);
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 558168c..10995f5 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -10,9 +10,6 @@
 int lbs_cfg_register(struct lbs_private *priv);
 void lbs_cfg_free(struct lbs_private *priv);
 
-int lbs_reg_notifier(struct wiphy *wiphy,
-		struct regulatory_request *request);
-
 void lbs_send_disconnect_notification(struct lbs_private *priv);
 void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
 
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ff90855..cffdf4f 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -48,6 +48,10 @@
 module_param(channels, int, 0444);
 MODULE_PARM_DESC(channels, "Number of concurrent channels");
 
+static bool paged_rx = false;
+module_param(paged_rx, bool, 0644);
+MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones");
+
 /**
  * enum hwsim_regtest - the type of regulatory tests we offer
  *
@@ -333,11 +337,11 @@
 	int scan_chan_idx;
 
 	struct ieee80211_channel *channel;
-	unsigned long beacon_int; /* in jiffies unit */
+	u64 beacon_int	/* beacon interval in us */;
 	unsigned int rx_filter;
 	bool started, idle, scanning;
 	struct mutex mutex;
-	struct timer_list beacon_timer;
+	struct tasklet_hrtimer beacon_timer;
 	enum ps_mode {
 		PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
 	} ps;
@@ -357,7 +361,10 @@
 	int power_level;
 
 	/* difference between this hw's clock and the real clock, in usecs */
-	u64 tsf_offset;
+	s64 tsf_offset;
+	s64 bcn_delta;
+	/* absolute beacon transmission time. Used to cover up "tx" delay. */
+	u64 abs_bcn_ts;
 };
 
 
@@ -405,15 +412,19 @@
 	return NETDEV_TX_OK;
 }
 
+static inline u64 mac80211_hwsim_get_tsf_raw(void)
+{
+	return ktime_to_us(ktime_get_real());
+}
+
 static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
 {
-	struct timeval tv = ktime_to_timeval(ktime_get_real());
-	u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+	u64 now = mac80211_hwsim_get_tsf_raw();
 	return cpu_to_le64(now + data->tsf_offset);
 }
 
 static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
-		struct ieee80211_vif *vif)
+				  struct ieee80211_vif *vif)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 	return le64_to_cpu(__mac80211_hwsim_get_tsf(data));
@@ -423,9 +434,13 @@
 		struct ieee80211_vif *vif, u64 tsf)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
-	struct timeval tv = ktime_to_timeval(ktime_get_real());
-	u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
-	data->tsf_offset = tsf - now;
+	u64 now = mac80211_hwsim_get_tsf(hw, vif);
+	u32 bcn_int = data->beacon_int;
+	s64 delta = tsf - now;
+
+	data->tsf_offset += delta;
+	/* adjust after beaconing with new timestamp at old TBTT */
+	data->bcn_delta = do_div(delta, bcn_int);
 }
 
 static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
@@ -696,7 +711,7 @@
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_rx_status rx_status;
-	struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
+	u64 now;
 
 	memset(&rx_status, 0, sizeof(rx_status));
 	rx_status.flag |= RX_FLAG_MACTIME_START;
@@ -722,11 +737,23 @@
 	secpath_reset(skb);
 	nf_reset(skb);
 
+	/*
+	 * Get absolute mactime here so all HWs RX at the "same time", and
+	 * absolute TX time for beacon mactime so the timestamp matches.
+	 * Giving beacons a different mactime than non-beacons looks messy, but
+	 * it helps the Toffset be exact and a ~10us mactime discrepancy
+	 * probably doesn't really matter.
+	 */
+	if (ieee80211_is_beacon(hdr->frame_control) ||
+	    ieee80211_is_probe_resp(hdr->frame_control))
+		now = data->abs_bcn_ts;
+	else
+		now = mac80211_hwsim_get_tsf_raw();
+
 	/* Copy skb to all enabled radios that are on the current frequency */
 	spin_lock(&hwsim_radio_lock);
 	list_for_each_entry(data2, &hwsim_radios, list) {
 		struct sk_buff *nskb;
-		struct ieee80211_mgmt *mgmt;
 		struct tx_iter_data tx_iter_data = {
 			.receive = false,
 			.channel = chan,
@@ -755,24 +782,30 @@
 		 * reserve some space for our vendor and the normal
 		 * radiotap header, since we're copying anyway
 		 */
-		nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC);
-		if (nskb == NULL)
-			continue;
+		if (skb->len < PAGE_SIZE && paged_rx) {
+			struct page *page = alloc_page(GFP_ATOMIC);
+
+			if (!page)
+				continue;
+
+			nskb = dev_alloc_skb(128);
+			if (!nskb) {
+				__free_page(page);
+				continue;
+			}
+
+			memcpy(page_address(page), skb->data, skb->len);
+			skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len);
+		} else {
+			nskb = skb_copy(skb, GFP_ATOMIC);
+			if (!nskb)
+				continue;
+		}
 
 		if (mac80211_hwsim_addr_match(data2, hdr->addr1))
 			ack = true;
 
-		/* set bcn timestamp relative to receiver mactime */
-		rx_status.mactime =
-				le64_to_cpu(__mac80211_hwsim_get_tsf(data2));
-		mgmt = (struct ieee80211_mgmt *) nskb->data;
-		if (ieee80211_is_beacon(mgmt->frame_control) ||
-		    ieee80211_is_probe_resp(mgmt->frame_control))
-			mgmt->u.beacon.timestamp = cpu_to_le64(
-				rx_status.mactime +
-				(data->tsf_offset - data2->tsf_offset) +
-				24 * 8 * 10 / txrate->bitrate);
-
+		rx_status.mactime = now + data2->tsf_offset;
 #if 0
 		/*
 		 * Don't enable this code by default as the OUI 00:00:00
@@ -896,7 +929,7 @@
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 	data->started = false;
-	del_timer(&data->beacon_timer);
+	tasklet_hrtimer_cancel(&data->beacon_timer);
 	wiphy_debug(hw->wiphy, "%s\n", __func__);
 }
 
@@ -962,7 +995,11 @@
 static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
 				     struct ieee80211_vif *vif)
 {
-	struct ieee80211_hw *hw = arg;
+	struct mac80211_hwsim_data *data = arg;
+	struct ieee80211_hw *hw = data->hw;
+	struct ieee80211_tx_info *info;
+	struct ieee80211_rate *txrate;
+	struct ieee80211_mgmt *mgmt;
 	struct sk_buff *skb;
 
 	hwsim_check_magic(vif);
@@ -975,26 +1012,48 @@
 	skb = ieee80211_beacon_get(hw, vif);
 	if (skb == NULL)
 		return;
+	info = IEEE80211_SKB_CB(skb);
+	txrate = ieee80211_get_tx_rate(hw, info);
+
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	/* fake header transmission time */
+	data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
+	mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
+					       data->tsf_offset +
+					       24 * 8 * 10 / txrate->bitrate);
 
 	mac80211_hwsim_tx_frame(hw, skb,
 				rcu_dereference(vif->chanctx_conf)->def.chan);
 }
 
-
-static void mac80211_hwsim_beacon(unsigned long arg)
+static enum hrtimer_restart
+mac80211_hwsim_beacon(struct hrtimer *timer)
 {
-	struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
-	struct mac80211_hwsim_data *data = hw->priv;
+	struct mac80211_hwsim_data *data =
+		container_of(timer, struct mac80211_hwsim_data,
+			     beacon_timer.timer);
+	struct ieee80211_hw *hw = data->hw;
+	u64 bcn_int = data->beacon_int;
+	ktime_t next_bcn;
 
 	if (!data->started)
-		return;
+		goto out;
 
 	ieee80211_iterate_active_interfaces_atomic(
 		hw, IEEE80211_IFACE_ITER_NORMAL,
-		mac80211_hwsim_beacon_tx, hw);
+		mac80211_hwsim_beacon_tx, data);
 
-	data->beacon_timer.expires = jiffies + data->beacon_int;
-	add_timer(&data->beacon_timer);
+	/* beacon at new TBTT + beacon interval */
+	if (data->bcn_delta) {
+		bcn_int -= data->bcn_delta;
+		data->bcn_delta = 0;
+	}
+
+	next_bcn = ktime_add(hrtimer_get_expires(timer),
+			     ns_to_ktime(bcn_int * 1000));
+	tasklet_hrtimer_start(&data->beacon_timer, next_bcn, HRTIMER_MODE_ABS);
+out:
+	return HRTIMER_NORESTART;
 }
 
 static const char *hwsim_chantypes[] = {
@@ -1032,9 +1091,16 @@
 
 	data->power_level = conf->power_level;
 	if (!data->started || !data->beacon_int)
-		del_timer(&data->beacon_timer);
-	else
-		mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
+		tasklet_hrtimer_cancel(&data->beacon_timer);
+	else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
+		u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
+		u32 bcn_int = data->beacon_int;
+		u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
+
+		tasklet_hrtimer_start(&data->beacon_timer,
+				      ns_to_ktime(until_tbtt * 1000),
+				      HRTIMER_MODE_REL);
+	}
 
 	return 0;
 }
@@ -1084,12 +1150,26 @@
 
 	if (changed & BSS_CHANGED_BEACON_INT) {
 		wiphy_debug(hw->wiphy, "  BCNINT: %d\n", info->beacon_int);
-		data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
-		if (WARN_ON(!data->beacon_int))
-			data->beacon_int = 1;
-		if (data->started)
-			mod_timer(&data->beacon_timer,
-				  jiffies + data->beacon_int);
+		data->beacon_int = info->beacon_int * 1024;
+	}
+
+	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+		wiphy_debug(hw->wiphy, "  BCN EN: %d\n", info->enable_beacon);
+		if (data->started &&
+		    !hrtimer_is_queued(&data->beacon_timer.timer) &&
+		    info->enable_beacon) {
+			u64 tsf, until_tbtt;
+			u32 bcn_int;
+			if (WARN_ON(!data->beacon_int))
+				data->beacon_int = 1000 * 1024;
+			tsf = mac80211_hwsim_get_tsf(hw, vif);
+			bcn_int = data->beacon_int;
+			until_tbtt = bcn_int - do_div(tsf, bcn_int);
+			tasklet_hrtimer_start(&data->beacon_timer,
+					      ns_to_ktime(until_tbtt * 1000),
+					      HRTIMER_MODE_REL);
+		} else if (!info->enable_beacon)
+			tasklet_hrtimer_cancel(&data->beacon_timer);
 	}
 
 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@@ -1292,7 +1372,9 @@
 	case IEEE80211_AMPDU_TX_START:
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -2165,6 +2247,7 @@
 		/* ask mac80211 to reserve space for magic */
 		hw->vif_data_size = sizeof(struct hwsim_vif_priv);
 		hw->sta_data_size = sizeof(struct hwsim_sta_priv);
+		hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv);
 
 		memcpy(data->channels_2ghz, hwsim_channels_2ghz,
 			sizeof(hwsim_channels_2ghz));
@@ -2370,8 +2453,9 @@
 							data->debugfs, data,
 							&hwsim_fops_group);
 
-		setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
-			    (unsigned long) hw);
+		tasklet_hrtimer_init(&data->beacon_timer,
+				     mac80211_hwsim_beacon,
+				     CLOCK_REALTIME, HRTIMER_MODE_ABS);
 
 		list_add_tail(&data->list, &hwsim_radios);
 	}
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
new file mode 100644
index 0000000..cf43b3c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -0,0 +1,261 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11ac
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "fw.h"
+#include "main.h"
+#include "11ac.h"
+
+/* This function converts the 2-bit MCS map to the highest long GI
+ * VHT data rate.
+ */
+static u16
+mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
+				  u8 bands, u16 mcs_map)
+{
+	u8 i, nss, max_mcs;
+	u16 max_rate = 0;
+	u32 usr_vht_cap_info = 0;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	/* tables of the MCS map to the highest data rate (in Mbps)
+	 * supported for long GI
+	 */
+	u16 max_rate_lgi_80MHZ[8][3] = {
+		{0x124, 0x15F, 0x186},	/* NSS = 1 */
+		{0x249, 0x2BE, 0x30C},  /* NSS = 2 */
+		{0x36D, 0x41D, 0x492},  /* NSS = 3 */
+		{0x492, 0x57C, 0x618},  /* NSS = 4 */
+		{0x5B6, 0x6DB, 0x79E},  /* NSS = 5 */
+		{0x6DB, 0x83A, 0x0},    /* NSS = 6 */
+		{0x7FF, 0x999, 0xAAA},  /* NSS = 7 */
+		{0x924, 0xAF8, 0xC30}   /* NSS = 8 */
+	};
+	u16 max_rate_lgi_160MHZ[8][3] = {
+		{0x249, 0x2BE, 0x30C},   /* NSS = 1 */
+		{0x492, 0x57C, 0x618},   /* NSS = 2 */
+		{0x6DB, 0x83A, 0x0},     /* NSS = 3 */
+		{0x924, 0xAF8, 0xC30},   /* NSS = 4 */
+		{0xB6D, 0xDB6, 0xF3C},   /* NSS = 5 */
+		{0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
+		{0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
+		{0x1248, 0x15F0, 0x1860} /* NSS = 8 */
+	};
+
+	if (bands & BAND_AAC)
+		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+	else
+		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+	/* find the max NSS supported */
+	nss = 0;
+	for (i = 0; i < 8; i++) {
+		max_mcs = (mcs_map >> (2 * i)) & 0x3;
+		if (max_mcs < 3)
+			nss = i;
+	}
+	max_mcs = (mcs_map >> (2 * nss)) & 0x3;
+
+	/* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */
+	if (max_mcs >= 3)
+		max_mcs = 2;
+
+	if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) {
+		/* support 160 MHz */
+		max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
+		if (!max_rate)
+			/* MCS9 is not supported in NSS6 */
+			max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1];
+	} else {
+		max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
+		if (!max_rate)
+			/* MCS9 is not supported in NSS3 */
+			max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1];
+	}
+
+	return max_rate;
+}
+
+static void
+mwifiex_fill_vht_cap_info(struct mwifiex_private *priv,
+			  struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	if (bands & BAND_A)
+		vht_cap->vht_cap.vht_cap_info =
+				cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
+	else
+		vht_cap->vht_cap.vht_cap_info =
+				cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
+}
+
+static void
+mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
+			 struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u16 mcs_map_user, mcs_map_resp, mcs_map_result;
+	u16 mcs_user, mcs_resp, nss, tmp;
+
+	/* Fill VHT cap info */
+	mwifiex_fill_vht_cap_info(priv, vht_cap, bands);
+
+	/* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */
+	mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+	mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.rx_mcs_map);
+	mcs_map_result = 0;
+
+	for (nss = 1; nss <= 8; nss++) {
+		mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+		mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+
+		if ((mcs_user == NO_NSS_SUPPORT) ||
+		    (mcs_resp == NO_NSS_SUPPORT))
+			SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+		else
+			SET_VHTNSSMCS(mcs_map_result, nss,
+				      min(mcs_user, mcs_resp));
+	}
+
+	vht_cap->vht_cap.supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
+
+	tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+	vht_cap->vht_cap.supp_mcs.rx_highest = cpu_to_le16(tmp);
+
+	/* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */
+	mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+	mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.tx_mcs_map);
+	mcs_map_result = 0;
+
+	for (nss = 1; nss <= 8; nss++) {
+		mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+		mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+		if ((mcs_user == NO_NSS_SUPPORT) ||
+		    (mcs_resp == NO_NSS_SUPPORT))
+			SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+		else
+			SET_VHTNSSMCS(mcs_map_result, nss,
+				      min(mcs_user, mcs_resp));
+	}
+
+	vht_cap->vht_cap.supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
+
+	tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+	vht_cap->vht_cap.supp_mcs.tx_highest = cpu_to_le16(tmp);
+
+	return;
+}
+
+int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
+			     struct mwifiex_bssdescriptor *bss_desc,
+			     u8 **buffer)
+{
+	struct mwifiex_ie_types_vhtcap *vht_cap;
+	struct mwifiex_ie_types_oper_mode_ntf *oper_ntf;
+	struct ieee_types_oper_mode_ntf *ieee_oper_ntf;
+	struct mwifiex_ie_types_vht_oper *vht_op;
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u8 supp_chwd_set;
+	u32 usr_vht_cap_info;
+	int ret_len = 0;
+
+	if (bss_desc->bss_band & BAND_A)
+		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+	else
+		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+	/* VHT Capabilities IE */
+	if (bss_desc->bcn_vht_cap) {
+		vht_cap = (struct mwifiex_ie_types_vhtcap *)*buffer;
+		memset(vht_cap, 0, sizeof(*vht_cap));
+		vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
+		vht_cap->header.len  =
+				cpu_to_le16(sizeof(struct ieee80211_vht_cap));
+		memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
+		       (u8 *)bss_desc->bcn_vht_cap +
+		       sizeof(struct ieee_types_header),
+		       le16_to_cpu(vht_cap->header.len));
+
+		mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
+		*buffer += sizeof(*vht_cap);
+		ret_len += sizeof(*vht_cap);
+	}
+
+	/* VHT Operation IE */
+	if (bss_desc->bcn_vht_oper) {
+		if (priv->bss_mode == HostCmd_BSS_MODE_IBSS) {
+			vht_op = (struct mwifiex_ie_types_vht_oper *)*buffer;
+			memset(vht_op, 0, sizeof(*vht_op));
+			vht_op->header.type =
+					cpu_to_le16(WLAN_EID_VHT_OPERATION);
+			vht_op->header.len  = cpu_to_le16(sizeof(*vht_op) -
+				      sizeof(struct mwifiex_ie_types_header));
+			memcpy((u8 *)vht_op +
+				sizeof(struct mwifiex_ie_types_header),
+			       (u8 *)bss_desc->bcn_vht_oper +
+			       sizeof(struct ieee_types_header),
+			       le16_to_cpu(vht_op->header.len));
+
+			/* negotiate the channel width and central freq
+			 * and keep the central freq as the peer suggests
+			 */
+			supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
+
+			switch (supp_chwd_set) {
+			case 0:
+				vht_op->chan_width =
+				     min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
+					   bss_desc->bcn_vht_oper->chan_width);
+				break;
+			case 1:
+				vht_op->chan_width =
+				     min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
+					   bss_desc->bcn_vht_oper->chan_width);
+				break;
+			case 2:
+				vht_op->chan_width =
+				     min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
+					   bss_desc->bcn_vht_oper->chan_width);
+				break;
+			default:
+				vht_op->chan_width =
+				     IEEE80211_VHT_CHANWIDTH_USE_HT;
+				break;
+			}
+
+			*buffer += sizeof(*vht_op);
+			ret_len += sizeof(*vht_op);
+		}
+	}
+
+	/* Operating Mode Notification IE */
+	if (bss_desc->oper_mode) {
+		ieee_oper_ntf = bss_desc->oper_mode;
+		oper_ntf = (void *)*buffer;
+		memset(oper_ntf, 0, sizeof(*oper_ntf));
+		oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF);
+		oper_ntf->header.len = cpu_to_le16(sizeof(u8));
+		oper_ntf->oper_mode = ieee_oper_ntf->oper_mode;
+		*buffer += sizeof(*oper_ntf);
+		ret_len += sizeof(*oper_ntf);
+	}
+
+	return ret_len;
+}
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h
new file mode 100644
index 0000000..80fd1ba
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11ac.h
@@ -0,0 +1,26 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11ac
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11AC_H_
+#define _MWIFIEX_11AC_H_
+
+int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
+				struct mwifiex_bssdescriptor *bss_desc,
+				u8 **buffer);
+#endif /* _MWIFIEX_11AC_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 245a371..45f1971 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -53,7 +53,9 @@
 	       sizeof(sband->ht_cap.mcs));
 
 	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
-	    sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+	    (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
+	     (priv->adapter->sec_chan_offset !=
+					IEEE80211_HT_PARAM_CHA_SEC_NONE)))
 		/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
 		SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
 
@@ -248,7 +250,8 @@
  *      - Setting HT Tx capability and HT Tx information fields
  *      - Ensuring correct endian-ness
  */
-int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *cmd, u16 cmd_action,
 			struct mwifiex_ds_11n_tx_cfg *txcfg)
 {
 	struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
@@ -258,6 +261,10 @@
 	htcfg->action = cpu_to_le16(cmd_action);
 	htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
 	htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
+
+	if (priv->adapter->is_hw_11ac_capable)
+		htcfg->misc_config = cpu_to_le16(txcfg->misc_config);
+
 	return 0;
 }
 
@@ -398,45 +405,6 @@
 }
 
 /*
- * This function reconfigures the Tx buffer size in firmware.
- *
- * This function prepares a firmware command and issues it, if
- * the current Tx buffer size is different from the one requested.
- * Maximum configurable Tx buffer size is limited by the HT capability
- * field value.
- */
-void
-mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
-		   struct mwifiex_bssdescriptor *bss_desc)
-{
-	u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
-	u16 tx_buf, curr_tx_buf_size = 0;
-
-	if (bss_desc->bcn_ht_cap) {
-		if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
-				IEEE80211_HT_CAP_MAX_AMSDU)
-			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
-		else
-			max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
-	}
-
-	tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
-
-	dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
-		max_amsdu, priv->adapter->max_tx_buf_size);
-
-	if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
-		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
-	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
-		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
-	else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
-		curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
-	if (curr_tx_buf_size != tx_buf)
-		mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
-				       HostCmd_ACT_GEN_SET, 0, &tx_buf);
-}
-
-/*
  * This function checks if the given pointer is valid entry of
  * Tx BA Stream table.
  */
@@ -531,11 +499,8 @@
 	if (!mwifiex_get_ba_tbl(priv, tid, ra)) {
 		new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
 				   GFP_ATOMIC);
-		if (!new_node) {
-			dev_err(priv->adapter->dev,
-				"%s: failed to alloc new_node\n", __func__);
+		if (!new_node)
 			return;
-		}
 
 		INIT_LIST_HEAD(&new_node->list);
 
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index 46006a5..375db01 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -28,14 +28,12 @@
 			  struct host_cmd_ds_command *resp);
 int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
 			      struct host_cmd_ds_command *resp);
-int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+			struct host_cmd_ds_command *cmd, u16 cmd_action,
 			struct mwifiex_ds_11n_tx_cfg *txcfg);
-
 int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
 			       struct mwifiex_bssdescriptor *bss_desc,
 			       u8 **buffer);
-void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
-			struct mwifiex_bssdescriptor *bss_desc);
 void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
 			   struct mwifiex_ie_types_htcap *);
 int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 68d52cf..af8fe63 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -278,14 +278,16 @@
 		dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
 		break;
 	case -1:
-		adapter->data_sent = false;
+		if (adapter->iface_type != MWIFIEX_PCIE)
+			adapter->data_sent = false;
 		dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
 			__func__, ret);
 		adapter->dbg.num_tx_host_to_card_failure++;
 		mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
 		return 0;
 	case -EINPROGRESS:
-		adapter->data_sent = false;
+		if (adapter->iface_type != MWIFIEX_PCIE)
+			adapter->data_sent = false;
 		break;
 	case 0:
 		mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 4a97acd..5e796f8 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -272,11 +272,8 @@
 	}
 	/* if !tbl then create one */
 	new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
-	if (!new_node) {
-		dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
-			__func__);
+	if (!new_node)
 		return;
-	}
 
 	INIT_LIST_HEAD(&new_node->list);
 	new_node->tid = tid;
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index b2e2772..4f614aa 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -20,12 +20,12 @@
 	  mwifiex_sdio.
 
 config MWIFIEX_PCIE
-	tristate "Marvell WiFi-Ex Driver for PCIE 8766"
+	tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897"
 	depends on MWIFIEX && PCI
 	select FW_LOADER
 	---help---
 	  This adds support for wireless adapters based on Marvell
-	  8766 chipset with PCIe interface.
+	  8766/8897 chipsets with PCIe interface.
 
 	  If you choose to build it as a module, it will be called
 	  mwifiex_pcie.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index dd0410d..97b245c 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -23,6 +23,7 @@
 mwifiex-y += txrx.o
 mwifiex-y += wmm.o
 mwifiex-y += 11n.o
+mwifiex-y += 11ac.o
 mwifiex-y += 11n_aggr.o
 mwifiex-y += 11n_rxreorder.o
 mwifiex-y += scan.o
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
index b55bade..3d64613 100644
--- a/drivers/net/wireless/mwifiex/README
+++ b/drivers/net/wireless/mwifiex/README
@@ -121,7 +121,6 @@
 	wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
 	wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
 	wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
-	max_tx_buf_size = <maximum Tx buffer size>
 	tx_buf_size = <current Tx buffer size>
 	curr_tx_buf_size = <current Tx buffer size>
 	ps_mode = <0/1, CAM mode/PS mode>
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index cdb11b3..a44023a 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -519,8 +519,8 @@
  *      - Set by user
  *      - Set bt Country IE
  */
-static int mwifiex_reg_notifier(struct wiphy *wiphy,
-				struct regulatory_request *request)
+static void mwifiex_reg_notifier(struct wiphy *wiphy,
+				 struct regulatory_request *request)
 {
 	struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
 
@@ -540,8 +540,6 @@
 		break;
 	}
 	mwifiex_send_domain_info_cmd_fw(wiphy);
-
-	return 0;
 }
 
 /*
@@ -836,6 +834,66 @@
 	return ret;
 }
 
+static void
+mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
+		     struct rate_info *rate)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+
+	if (adapter->is_hw_11ac_capable) {
+		/* bit[1-0]: 00=LG 01=HT 10=VHT */
+		if (tx_htinfo & BIT(0)) {
+			/* HT */
+			rate->mcs = priv->tx_rate;
+			rate->flags |= RATE_INFO_FLAGS_MCS;
+		}
+		if (tx_htinfo & BIT(1)) {
+			/* VHT */
+			rate->mcs = priv->tx_rate & 0x0F;
+			rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
+		}
+
+		if (tx_htinfo & (BIT(1) | BIT(0))) {
+			/* HT or VHT */
+			switch (tx_htinfo & (BIT(3) | BIT(2))) {
+			case 0:
+				/* This will be 20MHz */
+				break;
+			case (BIT(2)):
+				rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+				break;
+			case (BIT(3)):
+				rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+				break;
+			case (BIT(3) | BIT(2)):
+				rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+				break;
+			}
+
+			if (tx_htinfo & BIT(4))
+				rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+			if ((priv->tx_rate >> 4) == 1)
+				rate->nss = 2;
+			else
+				rate->nss = 1;
+		}
+	} else {
+		/*
+		 * Bit 0 in tx_htinfo indicates that current Tx rate
+		 * is 11n rate. Valid MCS index values for us are 0 to 15.
+		 */
+		if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
+			rate->mcs = priv->tx_rate;
+			rate->flags |= RATE_INFO_FLAGS_MCS;
+			if (tx_htinfo & BIT(1))
+				rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+			if (tx_htinfo & BIT(2))
+				rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+		}
+	}
+}
+
 /*
  * This function dumps the station information on a buffer.
  *
@@ -875,20 +933,7 @@
 			      HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
 			      &priv->dtim_period);
 
-	/*
-	 * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid
-	 * MCS index values for us are 0 to 15.
-	 */
-	if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
-		sinfo->txrate.mcs = priv->tx_rate;
-		sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
-		/* 40MHz rate */
-		if (priv->tx_htinfo & BIT(1))
-			sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
-		/* SGI enabled */
-		if (priv->tx_htinfo & BIT(2))
-			sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-	}
+	mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate);
 
 	sinfo->signal_avg = priv->bcn_rssi_avg;
 	sinfo->rx_bytes = priv->stats.rx_bytes;
@@ -1297,20 +1342,22 @@
 	/* Set appropriate bands */
 	if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
 		bss_cfg->band_cfg = BAND_CONFIG_BG;
+		config_bands = BAND_B | BAND_G;
 
-		if (cfg80211_get_chandef_type(&params->chandef) ==
-						NL80211_CHAN_NO_HT)
-			config_bands = BAND_B | BAND_G;
-		else
-			config_bands = BAND_B | BAND_G | BAND_GN;
+		if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+			config_bands |= BAND_GN;
+
+		if (params->chandef.width > NL80211_CHAN_WIDTH_40)
+			config_bands |= BAND_GAC;
 	} else {
 		bss_cfg->band_cfg = BAND_CONFIG_A;
+		config_bands = BAND_A;
 
-		if (cfg80211_get_chandef_type(&params->chandef) ==
-						NL80211_CHAN_NO_HT)
-			config_bands = BAND_A;
-		else
-			config_bands = BAND_AN | BAND_A;
+		if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+			config_bands |= BAND_AN;
+
+		if (params->chandef.width > NL80211_CHAN_WIDTH_40)
+			config_bands |= BAND_AAC;
 	}
 
 	if (!((config_bands | priv->adapter->fw_bands) &
@@ -1327,6 +1374,7 @@
 	}
 
 	mwifiex_set_ht_params(priv, bss_cfg, params);
+	mwifiex_set_wmm_params(priv, bss_cfg, params);
 
 	if (params->inactivity_timeout > 0) {
 		/* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
@@ -1431,7 +1479,7 @@
 	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
 				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
 				  0, ie_buf, ie_len, 0, GFP_KERNEL);
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(priv->wdev->wiphy, bss);
 	memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
 
 	return 0;
@@ -1821,10 +1869,8 @@
 
 	priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
 				      GFP_KERNEL);
-	if (!priv->user_scan_cfg) {
-		dev_err(priv->adapter->dev, "failed to alloc scan_req\n");
+	if (!priv->user_scan_cfg)
 		return -ENOMEM;
-	}
 
 	priv->scan_request = request;
 
@@ -1882,6 +1928,79 @@
 	return 0;
 }
 
+static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
+				   struct mwifiex_private *priv)
+{
+	struct mwifiex_adapter *adapter = priv->adapter;
+	u32 vht_cap = 0, cap = adapter->hw_dot_11ac_dev_cap;
+
+	vht_info->vht_supported = true;
+
+	switch (GET_VHTCAP_MAXMPDULEN(cap)) {
+	case 0x00:
+		vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
+		break;
+	case 0x01:
+		vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
+		break;
+	case 0x10:
+		vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+	    break;
+	default:
+	    dev_err(adapter->dev, "unsupported MAX MPDU len\n");
+	    break;
+	}
+
+	if (ISSUPP_11ACVHTHTCVHT(cap))
+		vht_cap |= IEEE80211_VHT_CAP_HTC_VHT;
+
+	if (ISSUPP_11ACVHTTXOPPS(cap))
+		vht_cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS;
+
+	if (ISSUPP_11ACMURXBEAMFORMEE(cap))
+		vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+	if (ISSUPP_11ACMUTXBEAMFORMEE(cap))
+		vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+	if (ISSUPP_11ACSUBEAMFORMER(cap))
+		vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
+
+	if (ISSUPP_11ACSUBEAMFORMEE(cap))
+		vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+	if (ISSUPP_11ACRXSTBC(cap))
+		vht_cap |= IEEE80211_VHT_CAP_RXSTBC_1;
+
+	if (ISSUPP_11ACTXSTBC(cap))
+		vht_cap |= IEEE80211_VHT_CAP_TXSTBC;
+
+	if (ISSUPP_11ACSGI160(cap))
+		vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
+
+	if (ISSUPP_11ACSGI80(cap))
+		vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
+
+	if (ISSUPP_11ACLDPC(cap))
+		vht_cap |= IEEE80211_VHT_CAP_RXLDPC;
+
+	if (ISSUPP_11ACBW8080(cap))
+		vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+
+	if (ISSUPP_11ACBW160(cap))
+		vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+
+	vht_info->cap = vht_cap;
+
+	/* Update MCS support for VHT */
+	vht_info->vht_mcs.rx_mcs_map = cpu_to_le16(
+				adapter->hw_dot_11ac_mcs_support & 0xFFFF);
+	vht_info->vht_mcs.rx_highest = 0;
+	vht_info->vht_mcs.tx_mcs_map = cpu_to_le16(
+				adapter->hw_dot_11ac_mcs_support >> 16);
+	vht_info->vht_mcs.tx_highest = 0;
+}
+
 /*
  * This function sets up the CFG802.11 specific HT capability fields
  * with default values.
@@ -2095,16 +2214,22 @@
 	priv->netdev = dev;
 
 	mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
+	if (adapter->is_hw_11ac_capable)
+		mwifiex_setup_vht_caps(
+			&wiphy->bands[IEEE80211_BAND_2GHZ]->vht_cap, priv);
 
 	if (adapter->config_bands & BAND_A)
 		mwifiex_setup_ht_caps(
 			&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
 
+	if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable)
+		mwifiex_setup_vht_caps(
+			&wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv);
+
 	dev_net_set(dev, wiphy_net(wiphy));
 	dev->ieee80211_ptr = priv->wdev;
 	dev->ieee80211_ptr->iftype = priv->bss_mode;
 	memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
-	memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
 	SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
 
 	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
@@ -2248,6 +2373,7 @@
 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
 	wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
 			WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
+			WIPHY_FLAG_AP_UAPSD |
 			WIPHY_FLAG_CUSTOM_REGULATORY |
 			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index f69300f..988552d 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -106,8 +106,8 @@
  * This function maps an index in supported rates table into
  * the corresponding data rate.
  */
-u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
-							u8 ht_info)
+u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
+				   u8 index, u8 ht_info)
 {
 	/*
 	 * For every mcs_rate line, the first 8 bytes are for stream 1x1,
@@ -130,10 +130,155 @@
 		{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
 		  0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
 	};
+	/* AC rates */
+	u16 ac_mcs_rate_nss1[8][10] = {
+		/* LG 160M */
+		{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
+		  0x492, 0x57C, 0x618 },
+
+		/* SG 160M */
+		{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
+		  0x514, 0x618, 0x6C6 },
+
+		/* LG 80M */
+		{ 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
+		  0x249, 0x2BE, 0x30C },
+
+		/* SG 80M */
+		{ 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
+		  0x28A, 0x30C, 0x363 },
+
+		/* LG 40M */
+		{ 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
+		  0x10E, 0x144, 0x168 },
+
+		/* SG 40M */
+		{ 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
+		  0x12C, 0x168, 0x190 },
+
+		/* LG 20M */
+		{ 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
+
+		/* SG 20M */
+		{ 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
+	};
+	/* NSS2 note: the value in the table is 2 multiplier of the actual
+	 * rate
+	 */
+	u16 ac_mcs_rate_nss2[8][10] = {
+		/* LG 160M */
+		{ 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
+		  0x924, 0xAF8, 0xC30 },
+
+		/* SG 160M */
+		{ 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
+		  0xA28, 0xC30, 0xD8B },
+
+		/* LG 80M */
+		{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
+		  0x492, 0x57C, 0x618 },
+
+		/* SG 80M */
+		{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
+		  0x514, 0x618, 0x6C6 },
+
+		/* LG 40M */
+		{ 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
+		  0x21C, 0x288, 0x2D0 },
+
+		/* SG 40M */
+		{ 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
+		  0x258, 0x2D0, 0x320 },
+
+		/* LG 20M */
+		{ 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
+		  0x138, 0x00 },
+
+		/* SG 20M */
+		{ 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
+		  0x15B, 0x00 },
+	};
+	u32 rate = 0;
+	u8 mcs_index = 0;
+	u8 bw = 0;
+	u8 gi = 0;
+
+	if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
+		mcs_index = min(index & 0xF, 9);
+
+		/* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
+		bw = (ht_info & 0xC) >> 2;
+
+		/* LGI: gi =0, SGI: gi = 1 */
+		gi = (ht_info & 0x10) >> 4;
+
+		if ((index >> 4) == 1)	/* NSS = 2 */
+			rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
+		else			/* NSS = 1 */
+			rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
+	} else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
+		/* 20M: bw=0, 40M: bw=1 */
+		bw = (ht_info & 0xC) >> 2;
+
+		/* LGI: gi =0, SGI: gi = 1 */
+		gi = (ht_info & 0x10) >> 4;
+
+		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
+			if (gi == 1)
+				rate = 0x0D;    /* MCS 32 SGI rate */
+			else
+				rate = 0x0C;    /* MCS 32 LGI rate */
+		} else if (index < 16) {
+			if ((bw == 1) || (bw == 0))
+				rate = mcs_rate[2 * (1 - bw) + gi][index];
+			else
+				rate = mwifiex_data_rates[0];
+		} else {
+			rate = mwifiex_data_rates[0];
+		}
+	} else {
+		/* 11n non-HT rates */
+		if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
+			index = 0;
+		rate = mwifiex_data_rates[index];
+	}
+
+	return rate;
+}
+
+/* This function maps an index in supported rates table into
+ * the corresponding data rate.
+ */
+u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
+			       u8 index, u8 ht_info)
+{
+	/* For every mcs_rate line, the first 8 bytes are for stream 1x1,
+	 * and all 16 bytes are for stream 2x2.
+	 */
+	u16  mcs_rate[4][16] = {
+		/* LGI 40M */
+		{ 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
+		  0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
+
+		/* SGI 40M */
+		{ 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
+		  0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
+
+		/* LGI 20M */
+		{ 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
+		  0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
+
+		/* SGI 20M */
+		{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
+		  0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
+	};
 	u32 mcs_num_supp =
 		(priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
 	u32 rate;
 
+	if (priv->adapter->is_hw_11ac_capable)
+		return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
+
 	if (ht_info & BIT(0)) {
 		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
 			if (ht_info & BIT(2))
@@ -269,6 +414,7 @@
 {
 	u32 k = 0;
 	struct mwifiex_adapter *adapter = priv->adapter;
+
 	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
 		switch (adapter->config_bands) {
 		case BAND_B:
@@ -279,6 +425,7 @@
 			break;
 		case BAND_G:
 		case BAND_G | BAND_GN:
+		case BAND_G | BAND_GN | BAND_GAC:
 			dev_dbg(adapter->dev, "info: infra band=%d "
 				"supported_rates_g\n", adapter->config_bands);
 			k = mwifiex_copy_rates(rates, k, supported_rates_g,
@@ -288,7 +435,11 @@
 		case BAND_A | BAND_B | BAND_G:
 		case BAND_A | BAND_B:
 		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
+		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
+		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN |
+		     BAND_AAC | BAND_GAC:
 		case BAND_B | BAND_G | BAND_GN:
+		case BAND_B | BAND_G | BAND_GN | BAND_GAC:
 			dev_dbg(adapter->dev, "info: infra band=%d "
 				"supported_rates_bg\n", adapter->config_bands);
 			k = mwifiex_copy_rates(rates, k, supported_rates_bg,
@@ -301,14 +452,18 @@
 			k = mwifiex_copy_rates(rates, k, supported_rates_a,
 					       sizeof(supported_rates_a));
 			break;
+		case BAND_AN:
 		case BAND_A | BAND_AN:
+		case BAND_A | BAND_AN | BAND_AAC:
 		case BAND_A | BAND_G | BAND_AN | BAND_GN:
+		case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
 			dev_dbg(adapter->dev, "info: infra band=%d "
 				"supported_rates_a\n", adapter->config_bands);
 			k = mwifiex_copy_rates(rates, k, supported_rates_a,
 					       sizeof(supported_rates_a));
 			break;
 		case BAND_GN:
+		case BAND_GN | BAND_GAC:
 			dev_dbg(adapter->dev, "info: infra band=%d "
 				"supported_rates_n\n", adapter->config_bands);
 			k = mwifiex_copy_rates(rates, k, supported_rates_n,
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 5f438e6..20a6c55 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -24,6 +24,7 @@
 #include "main.h"
 #include "wmm.h"
 #include "11n.h"
+#include "11ac.h"
 
 /*
  * This function initializes a command node.
@@ -334,20 +335,15 @@
 int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
 {
 	struct cmd_ctrl_node *cmd_array;
-	u32 buf_size;
 	u32 i;
 
 	/* Allocate and initialize struct cmd_ctrl_node */
-	buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER;
-	cmd_array = kzalloc(buf_size, GFP_KERNEL);
-	if (!cmd_array) {
-		dev_err(adapter->dev, "%s: failed to alloc cmd_array\n",
-			__func__);
+	cmd_array = kcalloc(MWIFIEX_NUM_OF_CMD_BUFFER,
+			    sizeof(struct cmd_ctrl_node), GFP_KERNEL);
+	if (!cmd_array)
 		return -ENOMEM;
-	}
 
 	adapter->cmd_pool = cmd_array;
-	memset(adapter->cmd_pool, 0, buf_size);
 
 	/* Allocate and initialize command buffers */
 	for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
@@ -1470,6 +1466,24 @@
 	adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
 	adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
 
+	if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
+		adapter->is_hw_11ac_capable = true;
+
+		/* Copy 11AC cap */
+		adapter->hw_dot_11ac_dev_cap =
+					le32_to_cpu(hw_spec->dot_11ac_dev_cap);
+		adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap;
+		adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap;
+
+		/* Copy 11AC mcs */
+		adapter->hw_dot_11ac_mcs_support =
+				le32_to_cpu(hw_spec->dot_11ac_mcs_support);
+		adapter->usr_dot_11ac_mcs_support =
+					adapter->hw_dot_11ac_mcs_support;
+	} else {
+		adapter->is_hw_11ac_capable = false;
+	}
+
 	dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
 		adapter->fw_release_number);
 	dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 46e34aa..753b568 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -58,8 +58,6 @@
 	 item_addr(packets_out[WMM_AC_BE]), 1},
 	{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
 	 item_addr(packets_out[WMM_AC_BK]), 1},
-	{"max_tx_buf_size", item_size(max_tx_buf_size),
-	 item_addr(max_tx_buf_size), 1},
 	{"tx_buf_size", item_size(tx_buf_size),
 	 item_addr(tx_buf_size), 1},
 	{"curr_tx_buf_size", item_size(curr_tx_buf_size),
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index e9357d8..e8a569a 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -26,6 +26,7 @@
 #include <linux/wait.h>
 #include <linux/timer.h>
 #include <linux/ieee80211.h>
+#include <net/mac80211.h>
 
 
 #define MWIFIEX_MAX_BSS_NUM         (3)
@@ -58,6 +59,8 @@
 #define MWIFIEX_RTS_MAX_VALUE              (2347)
 #define MWIFIEX_FRAG_MIN_VALUE             (256)
 #define MWIFIEX_FRAG_MAX_VALUE             (2346)
+#define MWIFIEX_WMM_VERSION                0x01
+#define MWIFIEX_WMM_SUBTYPE                0x01
 
 #define MWIFIEX_RETRY_LIMIT                14
 #define MWIFIEX_SDIO_BLOCK_SIZE            256
@@ -126,4 +129,19 @@
 	WMM_AC_VI,
 	WMM_AC_VO
 } __packed;
+
+struct ieee_types_wmm_ac_parameters {
+	u8 aci_aifsn_bitmap;
+	u8 ecw_bitmap;
+	__le16 tx_op_limit;
+} __packed;
+
+struct mwifiex_types_wmm_info {
+	u8 oui[4];
+	u8 subtype;
+	u8 version;
+	u8 qos_info;
+	u8 reserved;
+	struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
+} __packed;
 #endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 4dc8e2e..25acb06 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -49,13 +49,23 @@
 #define A_SUPPORTED_RATES               9
 #define HOSTCMD_SUPPORTED_RATES         14
 #define N_SUPPORTED_RATES               3
-#define ALL_802_11_BANDS           (BAND_A | BAND_B | BAND_G | BAND_GN)
+#define ALL_802_11_BANDS           (BAND_A | BAND_B | BAND_G | BAND_GN | \
+				    BAND_AN | BAND_GAC | BAND_AAC)
 
-#define FW_MULTI_BANDS_SUPPORT  (BIT(8) | BIT(9) | BIT(10) | BIT(11))
+#define FW_MULTI_BANDS_SUPPORT  (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \
+				 BIT(12) | BIT(13))
 #define IS_SUPPORT_MULTI_BANDS(adapter)        \
 	(adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+
+/* shift bit 12 and bit 13 in fw_cap_info from the firmware to bit 13 and 14
+ * for 11ac so that bit 11 is for GN, bit 12 for AN, bit 13 for GAC, and bit
+ * bit 14 for AAC, in order to be compatible with the band capability
+ * defined in the driver after right shift of 8 bits.
+ */
 #define GET_FW_DEFAULT_BANDS(adapter)  \
-	((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+	    (((((adapter->fw_cap_info & 0x3000) << 1) | \
+	       (adapter->fw_cap_info & ~0xF000)) >> 8) & \
+	     ALL_802_11_BANDS)
 
 #define HostCmd_WEP_KEY_INDEX_MASK              0x3fff
 
@@ -216,6 +226,47 @@
 
 #define LLC_SNAP_LEN    8
 
+/* HW_SPEC fw_cap_info */
+
+#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14)))
+
+#define GET_VHTCAP_MAXMPDULEN(vht_cap_info) (vht_cap_info & 0x3)
+#define GET_VHTCAP_CHWDSET(vht_cap_info)    ((vht_cap_info >> 2) & 0x3)
+#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
+#define SET_VHTNSSMCS(mcs_mapset, nss, value) (mcs_mapset |= (value & 0x3) << \
+					      (2 * (nss - 1)))
+#define NO_NSS_SUPPORT		0x3
+
+/* HW_SPEC: HTC-VHT supported */
+#define ISSUPP_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap & BIT(22))
+/* HW_SPEC: VHT TXOP PS support */
+#define ISSUPP_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap & BIT(21))
+/* HW_SPEC: MU RX beamformee support */
+#define ISSUPP_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(20))
+/* HW_SPEC: MU TX beamformee support */
+#define ISSUPP_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(19))
+/* HW_SPEC: SU Beamformee support */
+#define ISSUPP_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(10))
+/* HW_SPEC: SU Beamformer support */
+#define ISSUPP_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap & BIT(9))
+/* HW_SPEC: Rx STBC support */
+#define ISSUPP_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(8))
+/* HW_SPEC: Tx STBC support */
+#define ISSUPP_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(7))
+/* HW_SPEC: Short GI support for 160MHz BW */
+#define ISSUPP_11ACSGI160(Dot11acDevCap) (Dot11acDevCap & BIT(6))
+/* HW_SPEC: Short GI support for 80MHz BW */
+#define ISSUPP_11ACSGI80(Dot11acDevCap) (Dot11acDevCap & BIT(5))
+/* HW_SPEC: LDPC coding support */
+#define ISSUPP_11ACLDPC(Dot11acDevCap) (Dot11acDevCap & BIT(4))
+/* HW_SPEC: Channel BW 20/40/80/160/80+80 MHz support */
+#define ISSUPP_11ACBW8080(Dot11acDevCap) (Dot11acDevCap & BIT(3))
+/* HW_SPEC: Channel BW 20/40/80/160 MHz support */
+#define ISSUPP_11ACBW160(Dot11acDevCap) (Dot11acDevCap & BIT(2))
+
+#define GET_DEVTXMCSMAP(dev_mcs_map)      (dev_mcs_map >> 16)
+#define GET_DEVRXMCSMAP(dev_mcs_map)      (dev_mcs_map & 0xFFFF)
+
 #define MOD_CLASS_HR_DSSS       0x03
 #define MOD_CLASS_OFDM          0x07
 #define MOD_CLASS_HT            0x08
@@ -330,6 +381,9 @@
 #define HOST_SLEEP_CFG_GPIO_DEF		0xff
 #define HOST_SLEEP_CFG_GAP_DEF		0
 
+#define MWIFIEX_TIMEOUT_FOR_AP_RESP		0xfffc
+#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT	2
+
 #define CMD_F_HOSTCMD           (1 << 0)
 #define CMD_F_CANCELED          (1 << 1)
 
@@ -452,9 +506,22 @@
 	u8 rx_rate;
 	s8 snr;
 	s8 nf;
-	/* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+
+	/* For: Non-802.11 AC cards
+	 *
+	 * Ht Info [Bit 0] RxRate format: LG=0, HT=1
 	 * [Bit 1]  HT Bandwidth: BW20 = 0, BW40 = 1
-	 * [Bit 2]  HT Guard Interval: LGI = 0, SGI = 1 */
+	 * [Bit 2]  HT Guard Interval: LGI = 0, SGI = 1
+	 *
+	 * For: 802.11 AC cards
+	 * [Bit 1] [Bit 0] RxRate format: legacy rate = 00 HT = 01 VHT = 10
+	 * [Bit 3] [Bit 2] HT/VHT Bandwidth BW20 = 00 BW40 = 01
+	 *						BW80 = 10  BW160 = 11
+	 * [Bit 4] HT/VHT Guard interval LGI = 0 SGI = 1
+	 * [Bit 5] STBC support Enabled = 1
+	 * [Bit 6] LDPC support Enabled = 1
+	 * [Bit 7] Reserved
+	 */
 	u8 ht_info;
 	u8 reserved;
 } __packed;
@@ -677,7 +744,11 @@
 	__le32 dot_11n_dev_cap;
 	u8 dev_mcs_support;
 	__le16 mp_end_port;	/* SDIO only, reserved for other interfacces */
-	__le16 reserved_4;
+	__le16 mgmt_buf_count;	/* mgmt IE buffer count */
+	__le32 reserved_5;
+	__le32 reserved_6;
+	__le32 dot_11ac_dev_cap;
+	__le32 dot_11ac_mcs_support;
 } __packed;
 
 struct host_cmd_ds_802_11_rssi_info {
@@ -783,6 +854,12 @@
 	struct ieee_types_ds_param_set ds_param_set;
 } __packed;
 
+struct ieee_types_oper_mode_ntf {
+	u8 element_id;
+	u8 len;
+	u8 oper_mode;
+} __packed;
+
 struct host_cmd_ds_802_11_ad_hoc_start {
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 bss_mode;
@@ -843,11 +920,27 @@
 	__le32 wep_icv_err_cnt[4];
 };
 
+/* Enumeration for rate format */
+enum _mwifiex_rate_format {
+	MWIFIEX_RATE_FORMAT_LG = 0,
+	MWIFIEX_RATE_FORMAT_HT,
+	MWIFIEX_RATE_FORMAT_VHT,
+	MWIFIEX_RATE_FORMAT_AUTO = 0xFF,
+};
+
 struct host_cmd_ds_tx_rate_query {
 	u8 tx_rate;
-	/* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+	/* Tx Rate Info: For 802.11 AC cards
+	 *
+	 * [Bit 0-1] tx rate formate: LG = 0, HT = 1, VHT = 2
+	 * [Bit 2-3] HT/VHT Bandwidth: BW20 = 0, BW40 = 1, BW80 = 2, BW160 = 3
+	 * [Bit 4]   HT/VHT Guard Interval: LGI = 0, SGI = 1
+	 *
+	 * For non-802.11 AC cards
+	 * Ht Info [Bit 0] RxRate format: LG=0, HT=1
 	 * [Bit 1]  HT Bandwidth: BW20 = 0, BW40 = 1
-	 * [Bit 2]  HT Guard Interval: LGI = 0, SGI = 1 */
+	 * [Bit 2]  HT Guard Interval: LGI = 0, SGI = 1
+	 */
 	u8 ht_info;
 } __packed;
 
@@ -1093,6 +1186,7 @@
 	__le16 action;
 	__le16 ht_tx_cap;
 	__le16 ht_tx_info;
+	__le16 misc_config;	/* Needed for 802.11AC cards only */
 } __packed;
 
 struct host_cmd_ds_txbuf_cfg {
@@ -1131,12 +1225,6 @@
 	u8 version;
 } __packed;
 
-struct ieee_types_wmm_ac_parameters {
-	u8 aci_aifsn_bitmap;
-	u8 ecw_bitmap;
-	__le16 tx_op_limit;
-} __packed;
-
 struct ieee_types_wmm_parameter {
 	/*
 	 * WMM Parameter IE - Vendor Specific Header:
@@ -1186,6 +1274,31 @@
 	struct ieee80211_ht_cap ht_cap;
 } __packed;
 
+struct mwifiex_ie_types_vhtcap {
+	struct mwifiex_ie_types_header header;
+	struct ieee80211_vht_cap vht_cap;
+} __packed;
+
+struct mwifiex_ie_types_oper_mode_ntf {
+	struct mwifiex_ie_types_header header;
+	u8 oper_mode;
+} __packed;
+
+/* VHT Operations IE */
+struct mwifiex_ie_types_vht_oper {
+	struct mwifiex_ie_types_header header;
+	u8 chan_width;
+	u8 chan_center_freq_1;
+	u8 chan_center_freq_2;
+	/* Basic MCS set map, each 2 bits stands for a NSS */
+	u16 basic_mcs_map;
+} __packed;
+
+struct mwifiex_ie_types_wmmcap {
+	struct mwifiex_ie_types_header header;
+	struct mwifiex_types_wmm_info wmm_info;
+} __packed;
+
 struct mwifiex_ie_types_htinfo {
 	struct mwifiex_ie_types_header header;
 	struct ieee80211_ht_operation ht_oper;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 39f03ce..e38aa9b 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -39,11 +39,8 @@
 	unsigned long flags;
 
 	bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
-	if (!bss_prio) {
-		dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
-			__func__);
+	if (!bss_prio)
 		return -ENOMEM;
-	}
 
 	bss_prio->priv = priv;
 	INIT_LIST_HEAD(&bss_prio->list);
@@ -317,7 +314,6 @@
 
 	adapter->pm_wakeup_fw_try = false;
 
-	adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 	adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 	adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
 
@@ -591,6 +587,12 @@
 				return -1;
 		}
 	}
+
+	if (adapter->if_ops.init_fw_port) {
+		if (adapter->if_ops.init_fw_port(adapter))
+			return -1;
+	}
+
 	for (i = 0; i < adapter->priv_num; i++) {
 		if (adapter->priv[i]) {
 			ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 4e31c60..d85e6eb 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -20,7 +20,6 @@
 #ifndef _MWIFIEX_IOCTL_H_
 #define _MWIFIEX_IOCTL_H_
 
-#include <net/mac80211.h>
 #include <net/lib80211.h>
 
 enum {
@@ -61,6 +60,8 @@
 	BAND_A = 4,
 	BAND_GN = 8,
 	BAND_AN = 16,
+	BAND_GAC = 32,
+	BAND_AAC = 64,
 };
 
 #define MWIFIEX_WPA_PASSHPHRASE_LEN 64
@@ -104,9 +105,12 @@
 	struct wpa_param wpa_cfg;
 	struct wep_key wep_cfg[NUM_WEP_KEYS];
 	struct ieee80211_ht_cap ht_cap;
+	struct ieee80211_vht_cap vht_cap;
 	u8 rates[MWIFIEX_SUPPORTED_RATES];
 	u32 sta_ao_timer;
 	u32 ps_sta_ao_timer;
+	u8 qos_info;
+	struct mwifiex_types_wmm_info wmm_info;
 };
 
 enum {
@@ -177,7 +181,6 @@
 struct mwifiex_debug_info {
 	u32 int_counter;
 	u32 packets_out[MAX_NUM_TID];
-	u32 max_tx_buf_size;
 	u32 tx_buf_size;
 	u32 curr_tx_buf_size;
 	u32 tx_tbl_num;
@@ -272,6 +275,7 @@
 struct mwifiex_ds_11n_tx_cfg {
 	u16 tx_htcap;
 	u16 tx_htinfo;
+	u16 misc_config; /* Needed for 802.11AC cards only */
 };
 
 struct mwifiex_ds_11n_amsdu_aggr_ctrl {
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 88664ae..246aa62 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -24,6 +24,7 @@
 #include "main.h"
 #include "wmm.h"
 #include "11n.h"
+#include "11ac.h"
 
 #define CAPINFO_MASK    (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
 
@@ -157,8 +158,8 @@
 
 	memset(rate1, 0, rate1_size);
 
-	for (i = 0; rate2[i] && i < rate2_size; i++) {
-		for (j = 0; tmp[j] && j < rate1_size; j++) {
+	for (i = 0; i < rate2_size && rate2[i]; i++) {
+		for (j = 0; j < rate1_size && tmp[j]; j++) {
 			/* Check common rate, excluding the bit for
 			   basic rate */
 			if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
@@ -398,8 +399,6 @@
 
 	pos = (u8 *) assoc;
 
-	mwifiex_cfg_tx_buf(priv, bss_desc);
-
 	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
 
 	/* Save so we know which BSS Desc to use in the response handler */
@@ -514,6 +513,12 @@
 	     priv->adapter->config_bands & BAND_AN))
 		mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
 
+	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+	    !bss_desc->disable_11n && !bss_desc->disable_11ac &&
+	    (priv->adapter->config_bands & BAND_GAC ||
+	     priv->adapter->config_bands & BAND_AAC))
+		mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos);
+
 	/* Append vendor specific IE TLV */
 	mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
 
@@ -615,23 +620,33 @@
 	struct ieee_types_assoc_rsp *assoc_rsp;
 	struct mwifiex_bssdescriptor *bss_desc;
 	u8 enable_data = true;
+	u16 cap_info, status_code;
 
 	assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
 
+	cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
+	status_code = le16_to_cpu(assoc_rsp->status_code);
+
 	priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
 				   sizeof(priv->assoc_rsp_buf));
 
 	memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
 
-	if (le16_to_cpu(assoc_rsp->status_code)) {
+	if (status_code) {
 		priv->adapter->dbg.num_cmd_assoc_failure++;
 		dev_err(priv->adapter->dev,
 			"ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n",
-			le16_to_cpu(assoc_rsp->status_code),
-			le16_to_cpu(assoc_rsp->cap_info_bitmap),
-			le16_to_cpu(assoc_rsp->a_id));
+			status_code, cap_info, le16_to_cpu(assoc_rsp->a_id));
 
-		ret = le16_to_cpu(assoc_rsp->status_code);
+		if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) {
+			if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT)
+				ret = WLAN_STATUS_AUTH_TIMEOUT;
+			else
+				ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		} else {
+			ret = status_code;
+		}
+
 		goto done;
 	}
 
@@ -969,6 +984,16 @@
 					priv->adapter->config_bands);
 		mwifiex_fill_cap_info(priv, radio_type, ht_cap);
 
+		if (adapter->sec_chan_offset ==
+					IEEE80211_HT_PARAM_CHA_SEC_NONE) {
+			u16 tmp_ht_cap;
+
+			tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info);
+			tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40;
+			ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap);
+		}
+
 		pos += sizeof(struct mwifiex_ie_types_htcap);
 		cmd_append_size += sizeof(struct mwifiex_ie_types_htcap);
 
@@ -1403,6 +1428,7 @@
 	case BAND_A:
 	case BAND_AN:
 	case BAND_A | BAND_AN:
+	case BAND_A | BAND_AN | BAND_AAC:
 		return HostCmd_SCAN_RADIO_TYPE_A;
 	case BAND_B:
 	case BAND_G:
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 1b3cfc8..553adfb 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -295,6 +295,13 @@
 	u16 bss_co_2040_offset;
 	u8 *bcn_ext_cap;
 	u16 ext_cap_offset;
+	struct ieee80211_vht_cap *bcn_vht_cap;
+	u16 vht_cap_offset;
+	struct ieee80211_vht_operation *bcn_vht_oper;
+	u16 vht_info_offset;
+	struct ieee_types_oper_mode_ntf *oper_mode;
+	u16 oper_mode_offset;
+	u8 disable_11ac;
 	struct ieee_types_vendor_specific *bcn_wpa_ie;
 	u16 wpa_offset;
 	struct ieee_types_generic *bcn_rsn_ie;
@@ -499,6 +506,7 @@
 	u16 rsn_idx;
 	struct timer_list scan_delay_timer;
 	u8 ap_11n_enabled;
+	u8 ap_11ac_enabled;
 	u32 mgmt_frame_mask;
 	struct mwifiex_roc_cfg roc_cfg;
 };
@@ -599,8 +607,10 @@
 	int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *);
 	int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
 	int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);
+	int (*init_fw_port) (struct mwifiex_adapter *);
 	int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
 	void (*card_reset) (struct mwifiex_adapter *);
+	int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
 };
 
 struct mwifiex_adapter {
@@ -629,7 +639,6 @@
 	/* spin lock for main process */
 	spinlock_t main_proc_lock;
 	u32 mwifiex_processing;
-	u16 max_tx_buf_size;
 	u16 tx_buf_size;
 	u16 curr_tx_buf_size;
 	u32 ioport;
@@ -721,6 +730,15 @@
 	u16 max_mgmt_ie_index;
 	u8 scan_delay_cnt;
 	u8 empty_tx_q_cnt;
+
+	/* 11AC */
+	u32 is_hw_11ac_capable;
+	u32 hw_dot_11ac_dev_cap;
+	u32 hw_dot_11ac_mcs_support;
+	u32 usr_dot_11ac_dev_cap_bg;
+	u32 usr_dot_11ac_dev_cap_a;
+	u32 usr_dot_11ac_mcs_support;
+
 	atomic_t is_tx_received;
 	atomic_t pending_bridged_pkts;
 };
@@ -863,8 +881,10 @@
 int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd);
 struct mwifiex_chan_freq_power *mwifiex_get_cfp(struct mwifiex_private *priv,
 						u8 band, u16 channel, u32 freq);
-u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
-							u8 ht_info);
+u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
+			       u8 index, u8 ht_info);
+u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
+				   u8 index, u8 ht_info);
 u32 mwifiex_find_freq_from_band_chan(u8, u8);
 int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
 				u8 **buffer);
@@ -890,6 +910,10 @@
 			   struct cfg80211_ap_settings *params);
 void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
 			   struct cfg80211_ap_settings *params);
+void
+mwifiex_set_wmm_params(struct mwifiex_private *priv,
+		       struct mwifiex_uap_bss_param *bss_cfg,
+		       struct cfg80211_ap_settings *params);
 
 /*
  * This function checks if the queuing is RA based or not.
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index b879e13..4b54bcf 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -39,17 +39,20 @@
 static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
 static int mwifiex_pcie_resume(struct pci_dev *pdev);
 
-/*
- * This function is called after skb allocation to update
- * "skb->cb" with physical address of data pointer.
- */
-static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
+static int
+mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+		       int size, int flags)
 {
-	phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+	struct pcie_service_card *card = adapter->card;
+	dma_addr_t buf_pa;
 
-	*buf_pa = (phys_addr_t)virt_to_phys(skb->data);
-
-	return buf_pa;
+	buf_pa = pci_map_single(card->dev, skb->data, size, flags);
+	if (pci_dma_mapping_error(card->dev, buf_pa)) {
+		dev_err(adapter->dev, "failed to map pci memory!\n");
+		return -1;
+	}
+	memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t));
+	return 0;
 }
 
 /*
@@ -59,9 +62,13 @@
 {
 	u32 *cookie_addr;
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	if (card->sleep_cookie) {
-		cookie_addr = (u32 *)card->sleep_cookie->data;
+	if (!reg->sleep_cookie)
+		return true;
+
+	if (card->sleep_cookie_vbase) {
+		cookie_addr = (u32 *)card->sleep_cookie_vbase;
 		dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
 			*cookie_addr);
 		if (*cookie_addr == FW_AWAKE_COOKIE)
@@ -91,6 +98,13 @@
 
 	card->dev = pdev;
 
+	if (ent->driver_data) {
+		struct mwifiex_pcie_device *data = (void *)ent->driver_data;
+		card->pcie.firmware = data->firmware;
+		card->pcie.reg = data->reg;
+		card->pcie.blksz_fw_dl = data->blksz_fw_dl;
+	}
+
 	if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
 			     MWIFIEX_PCIE)) {
 		pr_err("%s failed\n", __func__);
@@ -227,13 +241,16 @@
 	return 0;
 }
 
-#define PCIE_VENDOR_ID_MARVELL              (0x11ab)
-#define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30)
-
 static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
 	{
 		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		.driver_data = (unsigned long) &mwifiex_pcie8766,
+	},
+	{
+		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		.driver_data = (unsigned long) &mwifiex_pcie8897,
 	},
 	{},
 };
@@ -286,8 +303,10 @@
 static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
 {
 	int i = 0;
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	while (mwifiex_pcie_ok_to_access_hw(adapter)) {
+	while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) {
 		i++;
 		usleep_range(10, 20);
 		/* 50ms max wait */
@@ -361,14 +380,246 @@
 }
 
 /*
- * This function creates buffer descriptor ring for TX
+ * This function initializes TX buffer ring descriptors
+ */
+static int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		card->tx_buf_list[i] = NULL;
+		if (reg->pfu_enabled) {
+			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
+					     (sizeof(*desc2) * i);
+			desc2 = card->txbd_ring[i];
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
+					     (sizeof(*desc) * i);
+			desc = card->txbd_ring[i];
+			memset(desc, 0, sizeof(*desc));
+		}
+	}
+
+	return 0;
+}
+
+/* This function initializes RX buffer ring descriptors. Each SKB is allocated
+ * here and after mapping PCI memory, its physical address is assigned to
+ * PCIE Rx buffer descriptor's physical address.
+ */
+static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct sk_buff *skb;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	dma_addr_t buf_pa;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		/* Allocate skb here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev,
+				"Unable to allocate skb for RX ring.\n");
+			kfree(card->rxbd_ring_vbase);
+			return -ENOMEM;
+		}
+
+		if (mwifiex_map_pci_memory(adapter, skb,
+					   MWIFIEX_RX_DATA_BUF_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+		dev_dbg(adapter->dev,
+			"info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+			skb, skb->len, skb->data, (u32)buf_pa,
+			(u32)((u64)buf_pa >> 32));
+
+		card->rx_buf_list[i] = skb;
+		if (reg->pfu_enabled) {
+			card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase +
+					     (sizeof(*desc2) * i);
+			desc2 = card->rxbd_ring[i];
+			desc2->paddr = buf_pa;
+			desc2->len = (u16)skb->len;
+			desc2->frag_len = (u16)skb->len;
+			desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop;
+			desc2->offset = 0;
+		} else {
+			card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase +
+					     (sizeof(*desc) * i));
+			desc = card->rxbd_ring[i];
+			desc->paddr = buf_pa;
+			desc->len = (u16)skb->len;
+			desc->flags = 0;
+		}
+	}
+
+	return 0;
+}
+
+/* This function initializes event buffer ring descriptors. Each SKB is
+ * allocated here and after mapping PCI memory, its physical address is assigned
+ * to PCIE Rx buffer descriptor's physical address
+ */
+static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct mwifiex_evt_buf_desc *desc;
+	struct sk_buff *skb;
+	dma_addr_t buf_pa;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+		/* Allocate skb here so that firmware can DMA data from it */
+		skb = dev_alloc_skb(MAX_EVENT_SIZE);
+		if (!skb) {
+			dev_err(adapter->dev,
+				"Unable to allocate skb for EVENT buf.\n");
+			kfree(card->evtbd_ring_vbase);
+			return -ENOMEM;
+		}
+		skb_put(skb, MAX_EVENT_SIZE);
+
+		if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+		dev_dbg(adapter->dev,
+			"info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+			skb, skb->len, skb->data, (u32)buf_pa,
+			(u32)((u64)buf_pa >> 32));
+
+		card->evt_buf_list[i] = skb;
+		card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
+				      (sizeof(*desc) * i));
+		desc = card->evtbd_ring[i];
+		desc->paddr = buf_pa;
+		desc->len = (u16)skb->len;
+		desc->flags = 0;
+	}
+
+	return 0;
+}
+
+/* This function cleans up TX buffer rings. If any of the buffer list has valid
+ * SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct sk_buff *skb;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		if (reg->pfu_enabled) {
+			desc2 = card->txbd_ring[i];
+			if (card->tx_buf_list[i]) {
+				skb = card->tx_buf_list[i];
+				pci_unmap_single(card->dev, desc2->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			desc = card->txbd_ring[i];
+			if (card->tx_buf_list[i]) {
+				skb = card->tx_buf_list[i];
+				pci_unmap_single(card->dev, desc->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc, 0, sizeof(*desc));
+		}
+		card->tx_buf_list[i] = NULL;
+	}
+
+	return;
+}
+
+/* This function cleans up RX buffer rings. If any of the buffer list has valid
+ * SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	struct sk_buff *skb;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+		if (reg->pfu_enabled) {
+			desc2 = card->rxbd_ring[i];
+			if (card->rx_buf_list[i]) {
+				skb = card->rx_buf_list[i];
+				pci_unmap_single(card->dev, desc2->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			desc = card->rxbd_ring[i];
+			if (card->rx_buf_list[i]) {
+				skb = card->rx_buf_list[i];
+				pci_unmap_single(card->dev, desc->paddr,
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_any(skb);
+			}
+			memset(desc, 0, sizeof(*desc));
+		}
+		card->rx_buf_list[i] = NULL;
+	}
+
+	return;
+}
+
+/* This function cleans up event buffer rings. If any of the buffer list has
+ * valid SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	struct mwifiex_evt_buf_desc *desc;
+	struct sk_buff *skb;
+	int i;
+
+	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+		desc = card->evtbd_ring[i];
+		if (card->evt_buf_list[i]) {
+			skb = card->evt_buf_list[i];
+			pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb_any(skb);
+		}
+		card->evt_buf_list[i] = NULL;
+		memset(desc, 0, sizeof(*desc));
+	}
+
+	return;
+}
+
+/* This function creates buffer descriptor ring for TX
  */
 static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
-	phys_addr_t *buf_pa;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 	/*
 	 * driver maintaines the write pointer and firmware maintaines the read
@@ -376,76 +627,56 @@
 	 * starts at zero with rollover bit set
 	 */
 	card->txbd_wrptr = 0;
-	card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+	if (reg->pfu_enabled)
+		card->txbd_rdptr = 0;
+	else
+		card->txbd_rdptr |= reg->tx_rollover_ind;
 
 	/* allocate shared memory for the BD ring and divide the same in to
 	   several descriptors */
-	card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
-							MWIFIEX_MAX_TXRX_BD;
+	if (reg->pfu_enabled)
+		card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+	else
+		card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+
 	dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
 		card->txbd_ring_size);
-	card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
+	card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
+						     card->txbd_ring_size,
+						     &card->txbd_ring_pbase);
 	if (!card->txbd_ring_vbase) {
-		dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n");
+		dev_err(adapter->dev,
+			"allocate consistent memory (%d bytes) failed!\n",
+			card->txbd_ring_size);
 		return -ENOMEM;
 	}
-	card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
-
 	dev_dbg(adapter->dev,
 		"info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
-		card->txbd_ring_vbase, (u32)card->txbd_ring_pbase,
+		card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
 		(u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
-				     (card->txbd_ring_vbase +
-				      (sizeof(struct mwifiex_pcie_buf_desc)
-				       * i));
-
-		/* Allocate buffer here so that firmware can DMA data from it */
-		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
-		if (!skb) {
-			dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
-			kfree(card->txbd_ring_vbase);
-			return -ENOMEM;
-		}
-		buf_pa = mwifiex_update_sk_buff_pa(skb);
-
-		skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
-		dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
-			"buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-			skb, skb->data, (u32)*buf_pa,
-			(u32)(((u64)*buf_pa >> 32)), skb->len);
-
-		card->tx_buf_list[i] = skb;
-		card->txbd_ring[i]->paddr = *buf_pa;
-		card->txbd_ring[i]->len = (u16)skb->len;
-		card->txbd_ring[i]->flags = 0;
-	}
-
-	return 0;
+	return mwifiex_init_txq_ring(adapter);
 }
 
 static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	int i;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		if (card->tx_buf_list[i])
-			dev_kfree_skb_any(card->tx_buf_list[i]);
-		card->tx_buf_list[i] = NULL;
-		card->txbd_ring[i]->paddr = 0;
-		card->txbd_ring[i]->len = 0;
-		card->txbd_ring[i]->flags = 0;
-		card->txbd_ring[i] = NULL;
-	}
+	mwifiex_cleanup_txq_ring(adapter);
 
-	kfree(card->txbd_ring_vbase);
+	if (card->txbd_ring_vbase)
+		pci_free_consistent(card->dev, card->txbd_ring_size,
+				    card->txbd_ring_vbase,
+				    card->txbd_ring_pbase);
 	card->txbd_ring_size = 0;
 	card->txbd_wrptr = 0;
-	card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->txbd_rdptr = 0 | reg->tx_rollover_ind;
 	card->txbd_ring_vbase = NULL;
+	card->txbd_ring_pbase = 0;
 
 	return 0;
 }
@@ -456,9 +687,7 @@
 static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
-	phys_addr_t *buf_pa;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 	/*
 	 * driver maintaines the read pointer and firmware maintaines the write
@@ -466,19 +695,26 @@
 	 * starts at zero with rollover bit set
 	 */
 	card->rxbd_wrptr = 0;
-	card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->rxbd_rdptr = reg->rx_rollover_ind;
 
-	card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
-							MWIFIEX_MAX_TXRX_BD;
+	if (reg->pfu_enabled)
+		card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+	else
+		card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+				       MWIFIEX_MAX_TXRX_BD;
+
 	dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
 		card->rxbd_ring_size);
-	card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
+	card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
+						     card->rxbd_ring_size,
+						     &card->rxbd_ring_pbase);
 	if (!card->rxbd_ring_vbase) {
-		dev_err(adapter->dev, "Unable to allocate buffer for "
-				"rxbd_ring.\n");
+		dev_err(adapter->dev,
+			"allocate consistent memory (%d bytes) failed!\n",
+			card->rxbd_ring_size);
 		return -ENOMEM;
 	}
-	card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
 
 	dev_dbg(adapter->dev,
 		"info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
@@ -486,35 +722,7 @@
 		(u32)((u64)card->rxbd_ring_pbase >> 32),
 		card->rxbd_ring_size);
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
-				     (card->rxbd_ring_vbase +
-				      (sizeof(struct mwifiex_pcie_buf_desc)
-				       * i));
-
-		/* Allocate skb here so that firmware can DMA data from it */
-		skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
-		if (!skb) {
-			dev_err(adapter->dev,
-				"Unable to allocate skb for RX ring.\n");
-			kfree(card->rxbd_ring_vbase);
-			return -ENOMEM;
-		}
-		buf_pa = mwifiex_update_sk_buff_pa(skb);
-		skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
-
-		dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
-			"buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-			skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
-			skb->len);
-
-		card->rx_buf_list[i] = skb;
-		card->rxbd_ring[i]->paddr = *buf_pa;
-		card->rxbd_ring[i]->len = (u16)skb->len;
-		card->rxbd_ring[i]->flags = 0;
-	}
-
-	return 0;
+	return mwifiex_init_rxq_ring(adapter);
 }
 
 /*
@@ -523,23 +731,19 @@
 static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	int i;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
-		if (card->rx_buf_list[i])
-			dev_kfree_skb_any(card->rx_buf_list[i]);
-		card->rx_buf_list[i] = NULL;
-		card->rxbd_ring[i]->paddr = 0;
-		card->rxbd_ring[i]->len = 0;
-		card->rxbd_ring[i]->flags = 0;
-		card->rxbd_ring[i] = NULL;
-	}
+	mwifiex_cleanup_rxq_ring(adapter);
 
-	kfree(card->rxbd_ring_vbase);
+	if (card->rxbd_ring_vbase)
+		pci_free_consistent(card->dev, card->rxbd_ring_size,
+				    card->rxbd_ring_vbase,
+				    card->rxbd_ring_pbase);
 	card->rxbd_ring_size = 0;
 	card->rxbd_wrptr = 0;
-	card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->rxbd_rdptr = 0 | reg->rx_rollover_ind;
 	card->rxbd_ring_vbase = NULL;
+	card->rxbd_ring_pbase = 0;
 
 	return 0;
 }
@@ -550,9 +754,7 @@
 static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	struct sk_buff *skb;
-	int i;
-	phys_addr_t *buf_pa;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 	/*
 	 * driver maintaines the read pointer and firmware maintaines the write
@@ -560,19 +762,22 @@
 	 * starts at zero with rollover bit set
 	 */
 	card->evtbd_wrptr = 0;
-	card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->evtbd_rdptr = reg->evt_rollover_ind;
 
-	card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
-							MWIFIEX_MAX_EVT_BD;
+	card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
+				MWIFIEX_MAX_EVT_BD;
+
 	dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
 		card->evtbd_ring_size);
-	card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
+	card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
+						      card->evtbd_ring_size,
+						      &card->evtbd_ring_pbase);
 	if (!card->evtbd_ring_vbase) {
 		dev_err(adapter->dev,
-			"Unable to allocate buffer. Terminating download\n");
+			"allocate consistent memory (%d bytes) failed!\n",
+			card->evtbd_ring_size);
 		return -ENOMEM;
 	}
-	card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
 
 	dev_dbg(adapter->dev,
 		"info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
@@ -580,35 +785,7 @@
 		(u32)((u64)card->evtbd_ring_pbase >> 32),
 		card->evtbd_ring_size);
 
-	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
-		card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
-				      (card->evtbd_ring_vbase +
-				       (sizeof(struct mwifiex_pcie_buf_desc)
-					* i));
-
-		/* Allocate skb here so that firmware can DMA data from it */
-		skb = dev_alloc_skb(MAX_EVENT_SIZE);
-		if (!skb) {
-			dev_err(adapter->dev,
-				"Unable to allocate skb for EVENT buf.\n");
-			kfree(card->evtbd_ring_vbase);
-			return -ENOMEM;
-		}
-		buf_pa = mwifiex_update_sk_buff_pa(skb);
-		skb_put(skb, MAX_EVENT_SIZE);
-
-		dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
-			"buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
-			skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
-			skb->len);
-
-		card->evt_buf_list[i] = skb;
-		card->evtbd_ring[i]->paddr = *buf_pa;
-		card->evtbd_ring[i]->len = (u16)skb->len;
-		card->evtbd_ring[i]->flags = 0;
-	}
-
-	return 0;
+	return mwifiex_pcie_init_evt_ring(adapter);
 }
 
 /*
@@ -617,23 +794,19 @@
 static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	int i;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
-		if (card->evt_buf_list[i])
-			dev_kfree_skb_any(card->evt_buf_list[i]);
-		card->evt_buf_list[i] = NULL;
-		card->evtbd_ring[i]->paddr = 0;
-		card->evtbd_ring[i]->len = 0;
-		card->evtbd_ring[i]->flags = 0;
-		card->evtbd_ring[i] = NULL;
-	}
+	mwifiex_cleanup_evt_ring(adapter);
 
-	kfree(card->evtbd_ring_vbase);
+	if (card->evtbd_ring_vbase)
+		pci_free_consistent(card->dev, card->evtbd_ring_size,
+				    card->evtbd_ring_vbase,
+				    card->evtbd_ring_pbase);
 	card->evtbd_wrptr = 0;
-	card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+	card->evtbd_rdptr = 0 | reg->evt_rollover_ind;
 	card->evtbd_ring_size = 0;
 	card->evtbd_ring_vbase = NULL;
+	card->evtbd_ring_pbase = 0;
 
 	return 0;
 }
@@ -653,21 +826,12 @@
 			"Unable to allocate skb for command response data.\n");
 		return -ENOMEM;
 	}
-	mwifiex_update_sk_buff_pa(skb);
 	skb_put(skb, MWIFIEX_UPLD_SIZE);
-	card->cmdrsp_buf = skb;
+	if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+				   PCI_DMA_FROMDEVICE))
+		return -1;
 
-	skb = NULL;
-	/* Allocate memory for sending command to firmware */
-	skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
-	if (!skb) {
-		dev_err(adapter->dev,
-			"Unable to allocate skb for command data.\n");
-		return -ENOMEM;
-	}
-	mwifiex_update_sk_buff_pa(skb);
-	skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
-	card->cmd_buf = skb;
+	card->cmdrsp_buf = skb;
 
 	return 0;
 }
@@ -678,18 +842,26 @@
 static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card;
+	dma_addr_t buf_pa;
 
 	if (!adapter)
 		return 0;
 
 	card = adapter->card;
 
-	if (card && card->cmdrsp_buf)
+	if (card && card->cmdrsp_buf) {
+		MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb_any(card->cmdrsp_buf);
+	}
 
-	if (card && card->cmd_buf)
+	if (card && card->cmd_buf) {
+		MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER,
+				 PCI_DMA_TODEVICE);
 		dev_kfree_skb_any(card->cmd_buf);
-
+	}
 	return 0;
 }
 
@@ -698,27 +870,19 @@
  */
 static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
 {
-	struct sk_buff *skb;
 	struct pcie_service_card *card = adapter->card;
 
-	/* Allocate memory for sleep cookie */
-	skb = dev_alloc_skb(sizeof(u32));
-	if (!skb) {
-		dev_err(adapter->dev,
-			"Unable to allocate skb for sleep cookie!\n");
+	card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
+						     &card->sleep_cookie_pbase);
+	if (!card->sleep_cookie_vbase) {
+		dev_err(adapter->dev, "pci_alloc_consistent failed!\n");
 		return -ENOMEM;
 	}
-	mwifiex_update_sk_buff_pa(skb);
-	skb_put(skb, sizeof(u32));
-
 	/* Init val of Sleep Cookie */
-	*(u32 *)skb->data = FW_AWAKE_COOKIE;
+	*(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE;
 
 	dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
-		*((u32 *)skb->data));
-
-	/* Save the sleep cookie */
-	card->sleep_cookie = skb;
+		*((u32 *)card->sleep_cookie_vbase));
 
 	return 0;
 }
@@ -735,86 +899,246 @@
 
 	card = adapter->card;
 
-	if (card && card->sleep_cookie) {
-		dev_kfree_skb_any(card->sleep_cookie);
-		card->sleep_cookie = NULL;
+	if (card && card->sleep_cookie_vbase) {
+		pci_free_consistent(card->dev, sizeof(u32),
+				    card->sleep_cookie_vbase,
+				    card->sleep_cookie_pbase);
+		card->sleep_cookie_vbase = NULL;
 	}
 
 	return 0;
 }
 
-/*
- * This function sends data buffer to device
+/* This function flushes the TX buffer descriptor ring
+ * This function defined as handler is also called while cleaning TXRX
+ * during disconnect/ bss stop.
  */
-static int
-mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	u32 wrindx, rdptr;
-	phys_addr_t *buf_pa;
-	__le16 *tmp;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	u32 rdptr;
+
+	/* Read the TX ring read pointer set by firmware */
+	if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
+		dev_err(adapter->dev,
+			"Flush TXBD: failed to read reg->tx_rdptr\n");
+		return -1;
+	}
+
+	if (!mwifiex_pcie_txbd_empty(card, rdptr)) {
+		card->txbd_flush = 1;
+		/* write pointer already set at last send
+		 * send dnld-rdy intr again, wait for completion.
+		 */
+		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+				      CPU_INTR_DNLD_RDY)) {
+			dev_err(adapter->dev,
+				"failed to assert dnld-rdy interrupt.\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * This function unmaps and frees downloaded data buffer
+ */
+static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
+{
+	struct sk_buff *skb;
+	dma_addr_t buf_pa;
+	u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 	if (!mwifiex_pcie_ok_to_access_hw(adapter))
 		mwifiex_pm_wakeup_card(adapter);
 
 	/* Read the TX ring read pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+	if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
 		dev_err(adapter->dev,
-			"SEND DATA: failed to read REG_TXBD_RDPTR\n");
+			"SEND COMP: failed to read reg->tx_rdptr\n");
 		return -1;
 	}
 
-	wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+	dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+		card->txbd_rdptr, rdptr);
 
-	dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
-		card->txbd_wrptr);
-	if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
-			(rdptr & MWIFIEX_TXBD_MASK)) ||
-	    ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
-			(rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
-		struct sk_buff *skb_data;
+	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
+	/* free from previous txbd_rdptr to current txbd_rdptr */
+	while (((card->txbd_rdptr & reg->tx_mask) !=
+		(rdptr & reg->tx_mask)) ||
+	       ((card->txbd_rdptr & reg->tx_rollover_ind) !=
+		(rdptr & reg->tx_rollover_ind))) {
+		wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >>
+			    reg->tx_start_ptr;
+
+		skb = card->tx_buf_list[wrdoneidx];
+		if (skb) {
+			dev_dbg(adapter->dev,
+				"SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
+				skb, wrdoneidx);
+			MWIFIEX_SKB_PACB(skb, &buf_pa);
+			pci_unmap_single(card->dev, buf_pa, skb->len,
+					 PCI_DMA_TODEVICE);
+
+			unmap_count++;
+
+			if (card->txbd_flush)
+				mwifiex_write_data_complete(adapter, skb, 0,
+							    -1);
+			else
+				mwifiex_write_data_complete(adapter, skb, 0, 0);
+		}
+
+		card->tx_buf_list[wrdoneidx] = NULL;
+
+		if (reg->pfu_enabled) {
+			desc2 = (void *)card->txbd_ring[wrdoneidx];
+			memset(desc2, 0, sizeof(*desc2));
+		} else {
+			desc = card->txbd_ring[wrdoneidx];
+			memset(desc, 0, sizeof(*desc));
+		}
+		switch (card->dev->device) {
+		case PCIE_DEVICE_ID_MARVELL_88W8766P:
+			card->txbd_rdptr++;
+			break;
+		case PCIE_DEVICE_ID_MARVELL_88W8897:
+			card->txbd_rdptr += reg->ring_tx_start_ptr;
+			break;
+		}
+
+
+		if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs)
+			card->txbd_rdptr = ((card->txbd_rdptr &
+					     reg->tx_rollover_ind) ^
+					     reg->tx_rollover_ind);
+	}
+
+	if (unmap_count)
+		adapter->data_sent = false;
+
+	if (card->txbd_flush) {
+		if (mwifiex_pcie_txbd_empty(card, card->txbd_rdptr))
+			card->txbd_flush = 0;
+		else
+			mwifiex_clean_pcie_ring_buf(adapter);
+	}
+
+	return 0;
+}
+
+/* This function sends data buffer to device. First 4 bytes of payload
+ * are filled with payload length and payload type. Then this payload
+ * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
+ * Download ready interrupt to FW is deffered if Tx ring is not full and
+ * additional payload can be accomodated.
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+		       struct mwifiex_tx_param *tx_param)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	u32 wrindx, num_tx_buffs, rx_val;
+	int ret;
+	dma_addr_t buf_pa;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+	__le16 *tmp;
+
+	if (!(skb->data && skb->len)) {
+		dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
+			__func__, skb->data, skb->len);
+		return -1;
+	}
+
+	if (!mwifiex_pcie_ok_to_access_hw(adapter))
+		mwifiex_pm_wakeup_card(adapter);
+
+	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
+	dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
+		card->txbd_rdptr, card->txbd_wrptr);
+	if (mwifiex_pcie_txbd_not_full(card)) {
 		u8 *payload;
 
 		adapter->data_sent = true;
-		skb_data = card->tx_buf_list[wrindx];
-		memcpy(skb_data->data, skb->data, skb->len);
-		payload = skb_data->data;
+		payload = skb->data;
 		tmp = (__le16 *)&payload[0];
 		*tmp = cpu_to_le16((u16)skb->len);
 		tmp = (__le16 *)&payload[2];
 		*tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
-		skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
-		skb_trim(skb_data, skb->len);
-		buf_pa = MWIFIEX_SKB_PACB(skb_data);
-		card->txbd_ring[wrindx]->paddr = *buf_pa;
-		card->txbd_ring[wrindx]->len = (u16)skb_data->len;
-		card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
-						MWIFIEX_BD_FLAG_LAST_DESC;
 
-		if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
-							MWIFIEX_MAX_TXRX_BD)
-			card->txbd_wrptr = ((card->txbd_wrptr &
-						MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-						MWIFIEX_BD_FLAG_ROLLOVER_IND);
+		if (mwifiex_map_pci_memory(adapter, skb, skb->len ,
+					   PCI_DMA_TODEVICE))
+			return -1;
 
-		/* Write the TX ring write pointer in to REG_TXBD_WRPTR */
-		if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR,
-				      card->txbd_wrptr)) {
-			dev_err(adapter->dev,
-				"SEND DATA: failed to write REG_TXBD_WRPTR\n");
-			return 0;
+		wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+		card->tx_buf_list[wrindx] = skb;
+
+		if (reg->pfu_enabled) {
+			desc2 = (void *)card->txbd_ring[wrindx];
+			desc2->paddr = buf_pa;
+			desc2->len = (u16)skb->len;
+			desc2->frag_len = (u16)skb->len;
+			desc2->offset = 0;
+			desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+					 MWIFIEX_BD_FLAG_LAST_DESC;
+		} else {
+			desc = card->txbd_ring[wrindx];
+			desc->paddr = buf_pa;
+			desc->len = (u16)skb->len;
+			desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+				      MWIFIEX_BD_FLAG_LAST_DESC;
 		}
 
-		/* Send the TX ready interrupt */
-		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
-				      CPU_INTR_DNLD_RDY)) {
+		switch (card->dev->device) {
+		case PCIE_DEVICE_ID_MARVELL_88W8766P:
+			card->txbd_wrptr++;
+			break;
+		case PCIE_DEVICE_ID_MARVELL_88W8897:
+			card->txbd_wrptr += reg->ring_tx_start_ptr;
+			break;
+		}
+
+		if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs)
+			card->txbd_wrptr = ((card->txbd_wrptr &
+						reg->tx_rollover_ind) ^
+						reg->tx_rollover_ind);
+
+		rx_val = card->rxbd_rdptr & reg->rx_wrap_mask;
+		/* Write the TX ring write pointer in to reg->tx_wrptr */
+		if (mwifiex_write_reg(adapter, reg->tx_wrptr,
+				      card->txbd_wrptr | rx_val)) {
 			dev_err(adapter->dev,
-				"SEND DATA: failed to assert door-bell intr\n");
-			return -1;
+				"SEND DATA: failed to write reg->tx_wrptr\n");
+			ret = -1;
+			goto done_unmap;
+		}
+		if ((mwifiex_pcie_txbd_not_full(card)) &&
+		    tx_param->next_pkt_len) {
+			/* have more packets and TxBD still can hold more */
+			dev_dbg(adapter->dev,
+				"SEND DATA: delay dnld-rdy interrupt.\n");
+			adapter->data_sent = false;
+		} else {
+			/* Send the TX ready interrupt */
+			if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+					      CPU_INTR_DNLD_RDY)) {
+				dev_err(adapter->dev,
+					"SEND DATA: failed to assert dnld-rdy interrupt.\n");
+				ret = -1;
+				goto done_unmap;
+			}
 		}
 		dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
 			"%#x> and sent packet to firmware successfully\n",
-			rdptr, card->txbd_wrptr);
+			card->txbd_rdptr, card->txbd_wrptr);
 	} else {
 		dev_dbg(adapter->dev,
 			"info: TX Ring full, can't send packets to fw\n");
@@ -827,7 +1151,17 @@
 		return -EBUSY;
 	}
 
-	return 0;
+	return -EINPROGRESS;
+done_unmap:
+	MWIFIEX_SKB_PACB(skb, &buf_pa);
+	pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
+	card->tx_buf_list[wrindx] = NULL;
+	if (reg->pfu_enabled)
+		memset(desc2, 0, sizeof(*desc2));
+	else
+		memset(desc, 0, sizeof(*desc));
+
+	return ret;
 }
 
 /*
@@ -837,78 +1171,119 @@
 static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
-	u32 wrptr, rd_index;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	u32 wrptr, rd_index, tx_val;
+	dma_addr_t buf_pa;
 	int ret = 0;
 	struct sk_buff *skb_tmp = NULL;
+	struct mwifiex_pcie_buf_desc *desc;
+	struct mwifiex_pfu_buf_desc *desc2;
+
+	if (!mwifiex_pcie_ok_to_access_hw(adapter))
+		mwifiex_pm_wakeup_card(adapter);
 
 	/* Read the RX ring Write pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+	if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
 		dev_err(adapter->dev,
-			"RECV DATA: failed to read REG_TXBD_RDPTR\n");
+			"RECV DATA: failed to read reg->rx_wrptr\n");
 		ret = -1;
 		goto done;
 	}
+	card->rxbd_wrptr = wrptr;
 
-	while (((wrptr & MWIFIEX_RXBD_MASK) !=
-		(card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
-	       ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
-		(card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+	while (((wrptr & reg->rx_mask) !=
+		(card->rxbd_rdptr & reg->rx_mask)) ||
+	       ((wrptr & reg->rx_rollover_ind) ==
+		(card->rxbd_rdptr & reg->rx_rollover_ind))) {
 		struct sk_buff *skb_data;
 		u16 rx_len;
+		__le16 pkt_len;
 
-		rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
+		rd_index = card->rxbd_rdptr & reg->rx_mask;
 		skb_data = card->rx_buf_list[rd_index];
 
+		MWIFIEX_SKB_PACB(skb_data, &buf_pa);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
+				 PCI_DMA_FROMDEVICE);
+		card->rx_buf_list[rd_index] = NULL;
+
 		/* Get data length from interface header -
-		   first byte is len, second byte is type */
-		rx_len = *((u16 *)skb_data->data);
+		 * first 2 bytes for len, next 2 bytes is for type
+		 */
+		pkt_len = *((__le16 *)skb_data->data);
+		rx_len = le16_to_cpu(pkt_len);
+		skb_put(skb_data, rx_len);
 		dev_dbg(adapter->dev,
 			"info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
 			card->rxbd_rdptr, wrptr, rx_len);
-		skb_tmp = dev_alloc_skb(rx_len);
+		skb_pull(skb_data, INTF_HEADER_LEN);
+		mwifiex_handle_rx_packet(adapter, skb_data);
+
+		skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
 		if (!skb_tmp) {
-			dev_dbg(adapter->dev,
-				"info: Failed to alloc skb for RX\n");
-			ret = -EBUSY;
-			goto done;
+			dev_err(adapter->dev,
+				"Unable to allocate skb.\n");
+			return -ENOMEM;
 		}
 
-		skb_put(skb_tmp, rx_len);
+		if (mwifiex_map_pci_memory(adapter, skb_tmp,
+					   MWIFIEX_RX_DATA_BUF_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
 
-		memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
-		if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
+		MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+
+		dev_dbg(adapter->dev,
+			"RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
+			skb_tmp, rd_index);
+		card->rx_buf_list[rd_index] = skb_tmp;
+
+		if (reg->pfu_enabled) {
+			desc2 = (void *)card->rxbd_ring[rd_index];
+			desc2->paddr = buf_pa;
+			desc2->len = skb_tmp->len;
+			desc2->frag_len = skb_tmp->len;
+			desc2->offset = 0;
+			desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop;
+		} else {
+			desc = card->rxbd_ring[rd_index];
+			desc->paddr = buf_pa;
+			desc->len = skb_tmp->len;
+			desc->flags = 0;
+		}
+
+		if ((++card->rxbd_rdptr & reg->rx_mask) ==
 							MWIFIEX_MAX_TXRX_BD) {
 			card->rxbd_rdptr = ((card->rxbd_rdptr &
-					     MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-					    MWIFIEX_BD_FLAG_ROLLOVER_IND);
+					     reg->rx_rollover_ind) ^
+					     reg->rx_rollover_ind);
 		}
 		dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
 			card->rxbd_rdptr, wrptr);
 
-		/* Write the RX ring read pointer in to REG_RXBD_RDPTR */
-		if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR,
-				      card->rxbd_rdptr)) {
+		tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
+		/* Write the RX ring read pointer in to reg->rx_rdptr */
+		if (mwifiex_write_reg(adapter, reg->rx_rdptr,
+				      card->rxbd_rdptr | tx_val)) {
 			dev_err(adapter->dev,
-				"RECV DATA: failed to write REG_RXBD_RDPTR\n");
+				"RECV DATA: failed to write reg->rx_rdptr\n");
 			ret = -1;
 			goto done;
 		}
 
 		/* Read the RX ring Write pointer set by firmware */
-		if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+		if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
 			dev_err(adapter->dev,
-				"RECV DATA: failed to read REG_TXBD_RDPTR\n");
+				"RECV DATA: failed to read reg->rx_wrptr\n");
 			ret = -1;
 			goto done;
 		}
 		dev_dbg(adapter->dev,
 			"info: RECV DATA: Rcvd packet from fw successfully\n");
-		mwifiex_handle_rx_packet(adapter, skb_tmp);
+		card->rxbd_wrptr = wrptr;
 	}
 
 done:
-	if (ret && skb_tmp)
-		dev_kfree_skb_any(skb_tmp);
 	return ret;
 }
 
@@ -918,40 +1293,54 @@
 static int
 mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 {
-	phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+	dma_addr_t buf_pa;
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	if (!(skb->data && skb->len && *buf_pa)) {
+	if (!(skb->data && skb->len)) {
 		dev_err(adapter->dev,
-			"Invalid parameter in %s <%p, %#x:%x, %x>\n",
-			__func__, skb->data, skb->len,
-			(u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
+			"Invalid parameter in %s <%p. len %d>\n",
+			__func__, skb->data, skb->len);
 		return -1;
 	}
 
-	/* Write the lower 32bits of the physical address to scratch
-	 * register 0 */
-	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
+	if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE))
+		return -1;
+
+	MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+	/* Write the lower 32bits of the physical address to low command
+	 * address scratch register
+	 */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
 		dev_err(adapter->dev,
 			"%s: failed to write download command to boot code.\n",
 			__func__);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+				 PCI_DMA_TODEVICE);
 		return -1;
 	}
 
-	/* Write the upper 32bits of the physical address to scratch
-	 * register 1 */
-	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
-			      (u32)((u64)*buf_pa >> 32))) {
+	/* Write the upper 32bits of the physical address to high command
+	 * address scratch register
+	 */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
+			      (u32)((u64)buf_pa >> 32))) {
 		dev_err(adapter->dev,
 			"%s: failed to write download command to boot code.\n",
 			__func__);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+				 PCI_DMA_TODEVICE);
 		return -1;
 	}
 
-	/* Write the command length to scratch register 2 */
-	if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) {
+	/* Write the command length to cmd_size scratch register */
+	if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
 		dev_err(adapter->dev,
-			"%s: failed to write command len to scratch reg 2\n",
+			"%s: failed to write command len to cmd_size scratch reg\n",
 			__func__);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+				 PCI_DMA_TODEVICE);
 		return -1;
 	}
 
@@ -960,22 +1349,43 @@
 			      CPU_INTR_DOOR_BELL)) {
 		dev_err(adapter->dev,
 			"%s: failed to assert door-bell intr\n", __func__);
+		pci_unmap_single(card->dev, buf_pa,
+				 MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE);
 		return -1;
 	}
 
 	return 0;
 }
 
-/*
- * This function downloads commands to the device
+/* This function init rx port in firmware which in turn enables to receive data
+ * from device before transmitting any packet.
+ */
+static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
+{
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+	int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;
+
+	/* Write the RX ring read pointer in to reg->rx_rdptr */
+	if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
+			      tx_wrap)) {
+		dev_err(adapter->dev,
+			"RECV DATA: failed to write reg->rx_rdptr\n");
+		return -1;
+	}
+	return 0;
+}
+
+/* This function downloads commands to the device
  */
 static int
 mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
 {
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	int ret = 0;
-	phys_addr_t *cmd_buf_pa;
-	phys_addr_t *cmdrsp_buf_pa;
+	dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
+	u8 *payload = (u8 *)skb->data;
 
 	if (!(skb->data && skb->len)) {
 		dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
@@ -990,21 +1400,22 @@
 		return -EBUSY;
 	}
 
-	/* Make sure a command buffer is available */
-	if (!card->cmd_buf) {
-		dev_err(adapter->dev, "Command buffer not available\n");
-		return -EBUSY;
-	}
+	if (!mwifiex_pcie_ok_to_access_hw(adapter))
+		mwifiex_pm_wakeup_card(adapter);
 
 	adapter->cmd_sent = true;
-	/* Copy the given skb in to DMA accessable shared buffer */
-	skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
-	skb_trim(card->cmd_buf, skb->len);
-	memcpy(card->cmd_buf->data, skb->data, skb->len);
+
+	*(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len);
+	*(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD);
+
+	if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE))
+		return -1;
+
+	card->cmd_buf = skb;
 
 	/* To send a command, the driver will:
 		1. Write the 64bit physical address of the data buffer to
-		   SCRATCH1 + SCRATCH0
+		   cmd response address low  + cmd response address high
 		2. Ring the door bell (i.e. set the door bell interrupt)
 
 		In response to door bell interrupt, the firmware will perform
@@ -1013,11 +1424,11 @@
 	*/
 
 	if (card->cmdrsp_buf) {
-		cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
+		MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
 		/* Write the lower 32bits of the cmdrsp buffer physical
 		   address */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
-				      (u32)*cmdrsp_buf_pa)) {
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
+				      (u32)cmdrsp_buf_pa)) {
 			dev_err(adapter->dev,
 				"Failed to write download cmd to boot code.\n");
 			ret = -1;
@@ -1025,8 +1436,8 @@
 		}
 		/* Write the upper 32bits of the cmdrsp buffer physical
 		   address */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
-				      (u32)((u64)*cmdrsp_buf_pa >> 32))) {
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
+				      (u32)((u64)cmdrsp_buf_pa >> 32))) {
 			dev_err(adapter->dev,
 				"Failed to write download cmd to boot code.\n");
 			ret = -1;
@@ -1034,27 +1445,29 @@
 		}
 	}
 
-	cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
-	/* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
-	if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) {
+	MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
+	/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
+			      (u32)cmd_buf_pa)) {
 		dev_err(adapter->dev,
 			"Failed to write download cmd to boot code.\n");
 		ret = -1;
 		goto done;
 	}
-	/* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
-	if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
-			      (u32)((u64)*cmd_buf_pa >> 32))) {
+	/* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
+	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
+			      (u32)((u64)cmd_buf_pa >> 32))) {
 		dev_err(adapter->dev,
 			"Failed to write download cmd to boot code.\n");
 		ret = -1;
 		goto done;
 	}
 
-	/* Write the command length to REG_CMD_SIZE */
-	if (mwifiex_write_reg(adapter, REG_CMD_SIZE, card->cmd_buf->len)) {
+	/* Write the command length to reg->cmd_size */
+	if (mwifiex_write_reg(adapter, reg->cmd_size,
+			      card->cmd_buf->len)) {
 		dev_err(adapter->dev,
-			"Failed to write cmd len to REG_CMD_SIZE\n");
+			"Failed to write cmd len to reg->cmd_size\n");
 		ret = -1;
 		goto done;
 	}
@@ -1081,18 +1494,30 @@
 static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	struct sk_buff *skb = card->cmdrsp_buf;
 	int count = 0;
+	u16 rx_len;
+	__le16 pkt_len;
+	dma_addr_t buf_pa;
 
 	dev_dbg(adapter->dev, "info: Rx CMD Response\n");
 
+	MWIFIEX_SKB_PACB(skb, &buf_pa);
+	pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+			 PCI_DMA_FROMDEVICE);
+
+	pkt_len = *((__le16 *)skb->data);
+	rx_len = le16_to_cpu(pkt_len);
+	skb_trim(skb, rx_len);
+	skb_pull(skb, INTF_HEADER_LEN);
+
 	if (!adapter->curr_cmd) {
-		skb_pull(skb, INTF_HEADER_LEN);
 		if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
 			mwifiex_process_sleep_confirm_resp(adapter, skb->data,
 							   skb->len);
-			while (mwifiex_pcie_ok_to_access_hw(adapter) &&
-							(count++ < 10))
+			while (reg->sleep_cookie && (count++ < 10) &&
+			       mwifiex_pcie_ok_to_access_hw(adapter))
 				usleep_range(50, 60);
 		} else {
 			dev_err(adapter->dev,
@@ -1100,9 +1525,12 @@
 		}
 		memcpy(adapter->upld_buf, skb->data,
 		       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
-		skb_push(skb, INTF_HEADER_LEN);
+		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
 	} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
-		skb_pull(skb, INTF_HEADER_LEN);
 		adapter->curr_cmd->resp_skb = skb;
 		adapter->cmd_resp_received = true;
 		/* Take the pointer and set it to CMD node and will
@@ -1112,14 +1540,14 @@
 		/* Clear the cmd-rsp buffer address in scratch registers. This
 		   will prevent firmware from writing to the same response
 		   buffer again. */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) {
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
 			dev_err(adapter->dev,
 				"cmd_done: failed to clear cmd_rsp_addr_lo\n");
 			return -1;
 		}
 		/* Write the upper 32bits of the cmdrsp buffer physical
 		   address */
-		if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) {
+		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
 			dev_err(adapter->dev,
 				"cmd_done: failed to clear cmd_rsp_addr_hi\n");
 			return -1;
@@ -1136,10 +1564,23 @@
 					struct sk_buff *skb)
 {
 	struct pcie_service_card *card = adapter->card;
+	dma_addr_t buf_pa;
+	struct sk_buff *skb_tmp;
 
 	if (skb) {
 		card->cmdrsp_buf = skb;
 		skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+	}
+
+	skb_tmp = card->cmd_buf;
+	if (skb_tmp) {
+		MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+		pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+				 PCI_DMA_FROMDEVICE);
+		card->cmd_buf = NULL;
 	}
 
 	return 0;
@@ -1151,8 +1592,14 @@
 static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
 	u32 wrptr, event;
+	dma_addr_t buf_pa;
+	struct mwifiex_evt_buf_desc *desc;
+
+	if (!mwifiex_pcie_ok_to_access_hw(adapter))
+		mwifiex_pm_wakeup_card(adapter);
 
 	if (adapter->event_received) {
 		dev_dbg(adapter->dev, "info: Event being processed, "
@@ -1166,9 +1613,9 @@
 	}
 
 	/* Read the event ring write pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
 		dev_err(adapter->dev,
-			"EventReady: failed to read REG_EVTBD_WRPTR\n");
+			"EventReady: failed to read reg->evt_wrptr\n");
 		return -1;
 	}
 
@@ -1176,20 +1623,23 @@
 		card->evtbd_rdptr, wrptr);
 	if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
 					      & MWIFIEX_EVTBD_MASK)) ||
-	    ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
-	     (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+	    ((wrptr & reg->evt_rollover_ind) ==
+	     (card->evtbd_rdptr & reg->evt_rollover_ind))) {
 		struct sk_buff *skb_cmd;
 		__le16 data_len = 0;
 		u16 evt_len;
 
 		dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
 		skb_cmd = card->evt_buf_list[rdptr];
+		MWIFIEX_SKB_PACB(skb_cmd, &buf_pa);
+		pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE,
+				 PCI_DMA_FROMDEVICE);
+
 		/* Take the pointer and set it to event pointer in adapter
 		   and will return back after event handling callback */
 		card->evt_buf_list[rdptr] = NULL;
-		card->evtbd_ring[rdptr]->paddr = 0;
-		card->evtbd_ring[rdptr]->len = 0;
-		card->evtbd_ring[rdptr]->flags = 0;
+		desc = card->evtbd_ring[rdptr];
+		memset(desc, 0, sizeof(*desc));
 
 		event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
 		adapter->event_cause = event;
@@ -1225,10 +1675,12 @@
 				       struct sk_buff *skb)
 {
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	int ret = 0;
 	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
 	u32 wrptr;
-	phys_addr_t *buf_pa;
+	dma_addr_t buf_pa;
+	struct mwifiex_evt_buf_desc *desc;
 
 	if (!skb)
 		return 0;
@@ -1240,19 +1692,25 @@
 	}
 
 	/* Read the event ring write pointer set by firmware */
-	if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
 		dev_err(adapter->dev,
-			"event_complete: failed to read REG_EVTBD_WRPTR\n");
+			"event_complete: failed to read reg->evt_wrptr\n");
 		return -1;
 	}
 
 	if (!card->evt_buf_list[rdptr]) {
 		skb_push(skb, INTF_HEADER_LEN);
+		if (mwifiex_map_pci_memory(adapter, skb,
+					   MAX_EVENT_SIZE,
+					   PCI_DMA_FROMDEVICE))
+			return -1;
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
 		card->evt_buf_list[rdptr] = skb;
-		buf_pa = MWIFIEX_SKB_PACB(skb);
-		card->evtbd_ring[rdptr]->paddr = *buf_pa;
-		card->evtbd_ring[rdptr]->len = (u16)skb->len;
-		card->evtbd_ring[rdptr]->flags = 0;
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+		desc = card->evtbd_ring[rdptr];
+		desc->paddr = buf_pa;
+		desc->len = (u16)skb->len;
+		desc->flags = 0;
 		skb = NULL;
 	} else {
 		dev_dbg(adapter->dev,
@@ -1262,17 +1720,18 @@
 
 	if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
 		card->evtbd_rdptr = ((card->evtbd_rdptr &
-					MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
-					MWIFIEX_BD_FLAG_ROLLOVER_IND);
+					reg->evt_rollover_ind) ^
+					reg->evt_rollover_ind);
 	}
 
 	dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
 		card->evtbd_rdptr, wrptr);
 
-	/* Write the event ring read pointer in to REG_EVTBD_RDPTR */
-	if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) {
+	/* Write the event ring read pointer in to reg->evt_rdptr */
+	if (mwifiex_write_reg(adapter, reg->evt_rdptr,
+			      card->evtbd_rdptr)) {
 		dev_err(adapter->dev,
-			"event_complete: failed to read REG_EVTBD_RDPTR\n");
+			"event_complete: failed to read reg->evt_rdptr\n");
 		return -1;
 	}
 
@@ -1299,11 +1758,9 @@
 	struct sk_buff *skb;
 	u32 txlen, tx_blocks = 0, tries, len;
 	u32 block_retry_cnt = 0;
-
-	if (!adapter) {
-		pr_err("adapter structure is not valid\n");
-		return -1;
-	}
+	dma_addr_t buf_pa;
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 	if (!firmware || !firmware_len) {
 		dev_err(adapter->dev,
@@ -1325,7 +1782,6 @@
 		ret = -ENOMEM;
 		goto done;
 	}
-	mwifiex_update_sk_buff_pa(skb);
 
 	/* Perform firmware data transfer */
 	do {
@@ -1336,7 +1792,7 @@
 			break;
 
 		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
-			ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG,
+			ret = mwifiex_read_reg(adapter, reg->cmd_size,
 					       &len);
 			if (ret) {
 				dev_warn(adapter->dev,
@@ -1382,16 +1838,15 @@
 
 			dev_dbg(adapter->dev, ".");
 
-			tx_blocks = (txlen +
-				     MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
-				     MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD;
+			tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
+				    card->pcie.blksz_fw_dl;
 
 			/* Copy payload to buffer */
 			memmove(skb->data, &firmware[offset], txlen);
 		}
 
 		skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
-		skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD);
+		skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl);
 
 		/* Send the boot command to device */
 		if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
@@ -1400,6 +1855,9 @@
 			ret = -1;
 			goto done;
 		}
+
+		MWIFIEX_SKB_PACB(skb, &buf_pa);
+
 		/* Wait for the command done interrupt */
 		do {
 			if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
@@ -1407,11 +1865,17 @@
 				dev_err(adapter->dev, "%s: Failed to read "
 					"interrupt status during fw dnld.\n",
 					__func__);
+				pci_unmap_single(card->dev, buf_pa, skb->len,
+						 PCI_DMA_TODEVICE);
 				ret = -1;
 				goto done;
 			}
 		} while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
 			 CPU_INTR_DOOR_BELL);
+
+		pci_unmap_single(card->dev, buf_pa, skb->len,
+				 PCI_DMA_TODEVICE);
+
 		offset += txlen;
 	} while (true);
 
@@ -1435,6 +1899,8 @@
 {
 	int ret = 0;
 	u32 firmware_stat, winner_status;
+	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 	u32 tries;
 
 	/* Mask spurios interrupts */
@@ -1445,7 +1911,8 @@
 	}
 
 	dev_dbg(adapter->dev, "Setting driver ready signature\n");
-	if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) {
+	if (mwifiex_write_reg(adapter, reg->drv_rdy,
+			      FIRMWARE_READY_PCIE)) {
 		dev_err(adapter->dev,
 			"Failed to write driver ready signature\n");
 		return -1;
@@ -1453,7 +1920,7 @@
 
 	/* Wait for firmware initialization event */
 	for (tries = 0; tries < poll_num; tries++) {
-		if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+		if (mwifiex_read_reg(adapter, reg->fw_status,
 				     &firmware_stat))
 			ret = -1;
 		else
@@ -1470,7 +1937,7 @@
 	}
 
 	if (ret) {
-		if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+		if (mwifiex_read_reg(adapter, reg->fw_status,
 				     &winner_status))
 			ret = -1;
 		else if (!winner_status) {
@@ -1594,39 +2061,40 @@
 static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
 {
 	int ret;
-	u32 pcie_ireg = 0;
+	u32 pcie_ireg;
 	unsigned long flags;
 
 	spin_lock_irqsave(&adapter->int_lock, flags);
 	/* Clear out unused interrupts */
-	adapter->int_status &= HOST_INTR_MASK;
+	pcie_ireg = adapter->int_status;
+	adapter->int_status = 0;
 	spin_unlock_irqrestore(&adapter->int_lock, flags);
 
-	while (adapter->int_status & HOST_INTR_MASK) {
-		if (adapter->int_status & HOST_INTR_DNLD_DONE) {
-			adapter->int_status &= ~HOST_INTR_DNLD_DONE;
-			if (adapter->data_sent) {
-				dev_dbg(adapter->dev, "info: DATA sent intr\n");
-				adapter->data_sent = false;
-			}
+	while (pcie_ireg & HOST_INTR_MASK) {
+		if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+			pcie_ireg &= ~HOST_INTR_DNLD_DONE;
+			dev_dbg(adapter->dev, "info: TX DNLD Done\n");
+			ret = mwifiex_pcie_send_data_complete(adapter);
+			if (ret)
+				return ret;
 		}
-		if (adapter->int_status & HOST_INTR_UPLD_RDY) {
-			adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+		if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+			pcie_ireg &= ~HOST_INTR_UPLD_RDY;
 			dev_dbg(adapter->dev, "info: Rx DATA\n");
 			ret = mwifiex_pcie_process_recv_data(adapter);
 			if (ret)
 				return ret;
 		}
-		if (adapter->int_status & HOST_INTR_EVENT_RDY) {
-			adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+		if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+			pcie_ireg &= ~HOST_INTR_EVENT_RDY;
 			dev_dbg(adapter->dev, "info: Rx EVENT\n");
 			ret = mwifiex_pcie_process_event_ready(adapter);
 			if (ret)
 				return ret;
 		}
 
-		if (adapter->int_status & HOST_INTR_CMD_DONE) {
-			adapter->int_status &= ~HOST_INTR_CMD_DONE;
+		if (pcie_ireg & HOST_INTR_CMD_DONE) {
+			pcie_ireg &= ~HOST_INTR_CMD_DONE;
 			if (adapter->cmd_sent) {
 				dev_dbg(adapter->dev,
 					"info: CMD sent Interrupt\n");
@@ -1654,8 +2122,6 @@
 						 "Write register failed\n");
 					return -1;
 				}
-				adapter->int_status |= pcie_ireg;
-				adapter->int_status &= HOST_INTR_MASK;
 			}
 
 		}
@@ -1687,7 +2153,7 @@
 	}
 
 	if (type == MWIFIEX_TYPE_DATA)
-		return mwifiex_pcie_send_data(adapter, skb);
+		return mwifiex_pcie_send_data(adapter, skb, tx_param);
 	else if (type == MWIFIEX_TYPE_CMD)
 		return mwifiex_pcie_send_cmd(adapter, skb);
 
@@ -1709,6 +2175,7 @@
 	struct pcie_service_card *card = adapter->card;
 	int ret;
 	struct pci_dev *pdev = card->dev;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
 	pci_set_drvdata(pdev, card);
 
@@ -1739,6 +2206,7 @@
 	card->pci_mmap = pci_iomap(pdev, 0, 0);
 	if (!card->pci_mmap) {
 		dev_err(adapter->dev, "iomap(0) error\n");
+		ret = -EIO;
 		goto err_iomap0;
 	}
 	ret = pci_request_region(pdev, 2, DRV_NAME);
@@ -1749,6 +2217,7 @@
 	card->pci_mmap1 = pci_iomap(pdev, 2, 0);
 	if (!card->pci_mmap1) {
 		dev_err(adapter->dev, "iomap(2) error\n");
+		ret = -EIO;
 		goto err_iomap2;
 	}
 
@@ -1769,10 +2238,13 @@
 	ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
 	if (ret)
 		goto err_alloc_cmdbuf;
-	ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
-	if (ret)
-		goto err_alloc_cookie;
-
+	if (reg->sleep_cookie) {
+		ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
+		if (ret)
+			goto err_alloc_cookie;
+	} else {
+		card->sleep_cookie_vbase = NULL;
+	}
 	return ret;
 
 err_alloc_cookie:
@@ -1813,17 +2285,11 @@
 {
 	struct pcie_service_card *card = adapter->card;
 	struct pci_dev *pdev = card->dev;
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-	mwifiex_pcie_delete_sleep_cookie_buf(adapter);
-	mwifiex_pcie_delete_cmdrsp_buf(adapter);
-	mwifiex_pcie_delete_evtbd_ring(adapter);
-	mwifiex_pcie_delete_rxbd_ring(adapter);
-	mwifiex_pcie_delete_txbd_ring(adapter);
-	card->cmdrsp_buf = NULL;
-
-	dev_dbg(adapter->dev, "Clearing driver ready signature\n");
 	if (user_rmmod) {
-		if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
+		dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+		if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
 			dev_err(adapter->dev,
 				"Failed to write driver not-ready signature\n");
 	}
@@ -1861,7 +2327,7 @@
 	}
 
 	adapter->dev = &pdev->dev;
-	strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
+	strcpy(adapter->fw_name, card->pcie.firmware);
 
 	return 0;
 }
@@ -1875,10 +2341,21 @@
 static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
 {
 	struct pcie_service_card *card = adapter->card;
+	const struct mwifiex_pcie_card_reg *reg;
 
 	if (card) {
 		dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
 		free_irq(card->dev->irq, card->dev);
+
+		reg = card->pcie.reg;
+		if (reg->sleep_cookie)
+			mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+
+		mwifiex_pcie_delete_cmdrsp_buf(adapter);
+		mwifiex_pcie_delete_evtbd_ring(adapter);
+		mwifiex_pcie_delete_rxbd_ring(adapter);
+		mwifiex_pcie_delete_txbd_ring(adapter);
+		card->cmdrsp_buf = NULL;
 	}
 }
 
@@ -1900,6 +2377,8 @@
 	.event_complete =		mwifiex_pcie_event_complete,
 	.update_mp_end_port =		NULL,
 	.cleanup_mpa_buf =		NULL,
+	.init_fw_port =			mwifiex_pcie_init_fw_port,
+	.clean_pcie_ring =		mwifiex_clean_pcie_ring_buf,
 };
 
 /*
@@ -1912,7 +2391,7 @@
 {
 	int ret;
 
-	pr_debug("Marvell 8766 PCIe Driver\n");
+	pr_debug("Marvell PCIe Driver\n");
 
 	sema_init(&add_remove_card_sem, 1);
 
@@ -1955,4 +2434,5 @@
 MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
 MODULE_VERSION(PCIE_VERSION);
 MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin");
+MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index 2f218f9..d322ab8 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -29,6 +29,11 @@
 #include    "main.h"
 
 #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
+
+#define PCIE_VENDOR_ID_MARVELL              (0x11ab)
+#define PCIE_DEVICE_ID_MARVELL_88W8766P		(0x2b30)
+#define PCIE_DEVICE_ID_MARVELL_88W8897		(0x2b38)
 
 /* Constants for Buffer Descriptor (BD) rings */
 #define MWIFIEX_MAX_TXRX_BD			0x20
@@ -57,6 +62,8 @@
 #define PCIE_SCRATCH_10_REG				0xCE8
 #define PCIE_SCRATCH_11_REG				0xCEC
 #define PCIE_SCRATCH_12_REG				0xCF0
+#define PCIE_RD_DATA_PTR_Q0_Q1                          0xC08C
+#define PCIE_WR_DATA_PTR_Q0_Q1                          0xC05C
 
 #define CPU_INTR_DNLD_RDY				BIT(0)
 #define CPU_INTR_DOOR_BELL				BIT(1)
@@ -75,27 +82,14 @@
 #define MWIFIEX_BD_FLAG_ROLLOVER_IND			BIT(7)
 #define MWIFIEX_BD_FLAG_FIRST_DESC			BIT(0)
 #define MWIFIEX_BD_FLAG_LAST_DESC			BIT(1)
-#define REG_CMD_ADDR_LO					PCIE_SCRATCH_0_REG
-#define REG_CMD_ADDR_HI					PCIE_SCRATCH_1_REG
-#define REG_CMD_SIZE					PCIE_SCRATCH_2_REG
-
-#define REG_CMDRSP_ADDR_LO				PCIE_SCRATCH_4_REG
-#define REG_CMDRSP_ADDR_HI				PCIE_SCRATCH_5_REG
-
-/* TX buffer description read pointer */
-#define REG_TXBD_RDPTR					PCIE_SCRATCH_6_REG
-/* TX buffer description write pointer */
-#define REG_TXBD_WRPTR					PCIE_SCRATCH_7_REG
-/* RX buffer description read pointer */
-#define REG_RXBD_RDPTR					PCIE_SCRATCH_8_REG
-/* RX buffer description write pointer */
-#define REG_RXBD_WRPTR					PCIE_SCRATCH_9_REG
-/* Event buffer description read pointer */
-#define REG_EVTBD_RDPTR					PCIE_SCRATCH_10_REG
-/* Event buffer description write pointer */
-#define REG_EVTBD_WRPTR					PCIE_SCRATCH_11_REG
-/* Driver ready signature write pointer */
-#define REG_DRV_READY					PCIE_SCRATCH_12_REG
+#define MWIFIEX_BD_FLAG_SOP				BIT(0)
+#define MWIFIEX_BD_FLAG_EOP				BIT(1)
+#define MWIFIEX_BD_FLAG_XS_SOP				BIT(2)
+#define MWIFIEX_BD_FLAG_XS_EOP				BIT(3)
+#define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND		BIT(7)
+#define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND			BIT(10)
+#define MWIFIEX_BD_FLAG_TX_START_PTR			BIT(16)
+#define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND			BIT(26)
 
 /* Max retry number of command write */
 #define MAX_WRITE_IOMEM_RETRY				2
@@ -104,45 +98,223 @@
 /* FW awake cookie after FW ready */
 #define FW_AWAKE_COOKIE						(0xAA55AA55)
 
+struct mwifiex_pcie_card_reg {
+	u16 cmd_addr_lo;
+	u16 cmd_addr_hi;
+	u16 fw_status;
+	u16 cmd_size;
+	u16 cmdrsp_addr_lo;
+	u16 cmdrsp_addr_hi;
+	u16 tx_rdptr;
+	u16 tx_wrptr;
+	u16 rx_rdptr;
+	u16 rx_wrptr;
+	u16 evt_rdptr;
+	u16 evt_wrptr;
+	u16 drv_rdy;
+	u16 tx_start_ptr;
+	u32 tx_mask;
+	u32 tx_wrap_mask;
+	u32 rx_mask;
+	u32 rx_wrap_mask;
+	u32 tx_rollover_ind;
+	u32 rx_rollover_ind;
+	u32 evt_rollover_ind;
+	u8 ring_flag_sop;
+	u8 ring_flag_eop;
+	u8 ring_flag_xs_sop;
+	u8 ring_flag_xs_eop;
+	u32 ring_tx_start_ptr;
+	u8 pfu_enabled;
+	u8 sleep_cookie;
+};
+
+static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
+	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
+	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
+	.cmd_size = PCIE_SCRATCH_2_REG,
+	.fw_status = PCIE_SCRATCH_3_REG,
+	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
+	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
+	.tx_rdptr = PCIE_SCRATCH_6_REG,
+	.tx_wrptr = PCIE_SCRATCH_7_REG,
+	.rx_rdptr = PCIE_SCRATCH_8_REG,
+	.rx_wrptr = PCIE_SCRATCH_9_REG,
+	.evt_rdptr = PCIE_SCRATCH_10_REG,
+	.evt_wrptr = PCIE_SCRATCH_11_REG,
+	.drv_rdy = PCIE_SCRATCH_12_REG,
+	.tx_start_ptr = 0,
+	.tx_mask = MWIFIEX_TXBD_MASK,
+	.tx_wrap_mask = 0,
+	.rx_mask = MWIFIEX_RXBD_MASK,
+	.rx_wrap_mask = 0,
+	.tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+	.rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+	.evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+	.ring_flag_sop = 0,
+	.ring_flag_eop = 0,
+	.ring_flag_xs_sop = 0,
+	.ring_flag_xs_eop = 0,
+	.ring_tx_start_ptr = 0,
+	.pfu_enabled = 0,
+	.sleep_cookie = 1,
+};
+
+static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
+	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
+	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
+	.cmd_size = PCIE_SCRATCH_2_REG,
+	.fw_status = PCIE_SCRATCH_3_REG,
+	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
+	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
+	.tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1,
+	.tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1,
+	.rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1,
+	.rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1,
+	.evt_rdptr = PCIE_SCRATCH_10_REG,
+	.evt_wrptr = PCIE_SCRATCH_11_REG,
+	.drv_rdy = PCIE_SCRATCH_12_REG,
+	.tx_start_ptr = 16,
+	.tx_mask = 0x03FF0000,
+	.tx_wrap_mask = 0x07FF0000,
+	.rx_mask = 0x000003FF,
+	.rx_wrap_mask = 0x000007FF,
+	.tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND,
+	.rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND,
+	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
+	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
+	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
+	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
+	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
+	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
+	.pfu_enabled = 1,
+	.sleep_cookie = 0,
+};
+
+struct mwifiex_pcie_device {
+	const char *firmware;
+	const struct mwifiex_pcie_card_reg *reg;
+	u16 blksz_fw_dl;
+};
+
+static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
+	.firmware       = PCIE8766_DEFAULT_FW_NAME,
+	.reg            = &mwifiex_reg_8766,
+	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+};
+
+static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
+	.firmware       = PCIE8897_DEFAULT_FW_NAME,
+	.reg            = &mwifiex_reg_8897,
+	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+};
+
+struct mwifiex_evt_buf_desc {
+	u64 paddr;
+	u16 len;
+	u16 flags;
+} __packed;
+
 struct mwifiex_pcie_buf_desc {
 	u64 paddr;
 	u16 len;
 	u16 flags;
 } __packed;
 
+struct mwifiex_pfu_buf_desc {
+	u16 flags;
+	u16 offset;
+	u16 frag_len;
+	u16 len;
+	u64 paddr;
+	u32 reserved;
+} __packed;
+
 struct pcie_service_card {
 	struct pci_dev *dev;
 	struct mwifiex_adapter *adapter;
+	struct mwifiex_pcie_device pcie;
 
+	u8 txbd_flush;
 	u32 txbd_wrptr;
 	u32 txbd_rdptr;
 	u32 txbd_ring_size;
 	u8 *txbd_ring_vbase;
-	phys_addr_t txbd_ring_pbase;
-	struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
+	dma_addr_t txbd_ring_pbase;
+	void *txbd_ring[MWIFIEX_MAX_TXRX_BD];
 	struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
 
 	u32 rxbd_wrptr;
 	u32 rxbd_rdptr;
 	u32 rxbd_ring_size;
 	u8 *rxbd_ring_vbase;
-	phys_addr_t rxbd_ring_pbase;
-	struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
+	dma_addr_t rxbd_ring_pbase;
+	void *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
 	struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
 
 	u32 evtbd_wrptr;
 	u32 evtbd_rdptr;
 	u32 evtbd_ring_size;
 	u8 *evtbd_ring_vbase;
-	phys_addr_t evtbd_ring_pbase;
-	struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
+	dma_addr_t evtbd_ring_pbase;
+	void *evtbd_ring[MWIFIEX_MAX_EVT_BD];
 	struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
 
 	struct sk_buff *cmd_buf;
 	struct sk_buff *cmdrsp_buf;
-	struct sk_buff *sleep_cookie;
+	u8 *sleep_cookie_vbase;
+	dma_addr_t sleep_cookie_pbase;
 	void __iomem *pci_mmap;
 	void __iomem *pci_mmap1;
 };
 
+static inline int
+mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
+{
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	switch (card->dev->device) {
+	case PCIE_DEVICE_ID_MARVELL_88W8766P:
+		if (((card->txbd_wrptr & reg->tx_mask) ==
+		     (rdptr & reg->tx_mask)) &&
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+		     (rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	case PCIE_DEVICE_ID_MARVELL_88W8897:
+		if (((card->txbd_wrptr & reg->tx_mask) ==
+		     (rdptr & reg->tx_mask)) &&
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) ==
+			(rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	}
+
+	return 0;
+}
+
+static inline int
+mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
+{
+	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+	switch (card->dev->device) {
+	case PCIE_DEVICE_ID_MARVELL_88W8766P:
+		if (((card->txbd_wrptr & reg->tx_mask) !=
+		     (card->txbd_rdptr & reg->tx_mask)) ||
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+		     (card->txbd_rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	case PCIE_DEVICE_ID_MARVELL_88W8897:
+		if (((card->txbd_wrptr & reg->tx_mask) !=
+		     (card->txbd_rdptr & reg->tx_mask)) ||
+		    ((card->txbd_wrptr & reg->tx_rollover_ind) ==
+		     (card->txbd_rdptr & reg->tx_rollover_ind)))
+			return 1;
+		break;
+	}
+
+	return 0;
+}
 #endif /* _MWIFIEX_PCIE_H */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 973a9d9..bb60c27 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1250,6 +1250,23 @@
 					sizeof(struct ieee_types_header) -
 					bss_entry->beacon_buf);
 			break;
+		case WLAN_EID_VHT_CAPABILITY:
+			bss_entry->disable_11ac = false;
+			bss_entry->bcn_vht_cap =
+				(void *)(current_ptr +
+					 sizeof(struct ieee_types_header));
+			bss_entry->vht_cap_offset =
+					(u16)((u8 *)bss_entry->bcn_vht_cap -
+					      bss_entry->beacon_buf);
+			break;
+		case WLAN_EID_VHT_OPERATION:
+			bss_entry->bcn_vht_oper =
+				(void *)(current_ptr +
+					 sizeof(struct ieee_types_header));
+			bss_entry->vht_info_offset =
+					(u16)((u8 *)bss_entry->bcn_vht_oper -
+					      bss_entry->beacon_buf);
+			break;
 		case WLAN_EID_BSS_COEX_2040:
 			bss_entry->bcn_bss_co_2040 = current_ptr +
 				sizeof(struct ieee_types_header);
@@ -1264,6 +1281,14 @@
 					sizeof(struct ieee_types_header) -
 					bss_entry->beacon_buf);
 			break;
+		case WLAN_EID_OPMODE_NOTIF:
+			bss_entry->oper_mode =
+				(void *)(current_ptr +
+					 sizeof(struct ieee_types_header));
+			bss_entry->oper_mode_offset =
+					(u16)((u8 *)bss_entry->oper_mode -
+					      bss_entry->beacon_buf);
+			break;
 		default:
 			break;
 		}
@@ -1309,7 +1334,6 @@
 	struct cmd_ctrl_node *cmd_node;
 	union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
 	struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
-	u32 buf_size;
 	struct mwifiex_chan_scan_param_set *scan_chan_list;
 	u8 filtered_scan;
 	u8 scan_current_chan_only;
@@ -1332,18 +1356,16 @@
 	spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 
 	scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
-								GFP_KERNEL);
+			       GFP_KERNEL);
 	if (!scan_cfg_out) {
-		dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
 		ret = -ENOMEM;
 		goto done;
 	}
 
-	buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
-						MWIFIEX_USER_SCAN_CHAN_MAX;
-	scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
+	scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX,
+				 sizeof(struct mwifiex_chan_scan_param_set),
+				 GFP_KERNEL);
 	if (!scan_chan_list) {
-		dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
 		kfree(scan_cfg_out);
 		ret = -ENOMEM;
 		goto done;
@@ -1461,12 +1483,9 @@
 	unsigned long flags;
 
 	/* Allocate and fill new bss descriptor */
-	bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
-			GFP_KERNEL);
-	if (!bss_desc) {
-		dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+	bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL);
+	if (!bss_desc)
 		return -ENOMEM;
-	}
 
 	ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
 	if (ret)
@@ -1485,20 +1504,26 @@
 	priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
 	priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
 	priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
-	priv->curr_bss_params.bss_descriptor.ht_cap_offset =
-		0;
+	priv->curr_bss_params.bss_descriptor.ht_cap_offset = 0;
 	priv->curr_bss_params.bss_descriptor.bcn_ht_oper = NULL;
-	priv->curr_bss_params.bss_descriptor.ht_info_offset =
-		0;
-	priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
-		NULL;
-	priv->curr_bss_params.bss_descriptor.
-		bss_co_2040_offset = 0;
+	priv->curr_bss_params.bss_descriptor.ht_info_offset = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = NULL;
+	priv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0;
 	priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
 	priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
 	priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
-	priv->curr_bss_params.bss_descriptor.beacon_buf_size =
-		0;
+	priv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_vht_cap = NULL;
+	priv->curr_bss_params.bss_descriptor.vht_cap_offset = 0;
+	priv->curr_bss_params.bss_descriptor.bcn_vht_oper = NULL;
+	priv->curr_bss_params.bss_descriptor.vht_info_offset = 0;
+	priv->curr_bss_params.bss_descriptor.oper_mode = NULL;
+	priv->curr_bss_params.bss_descriptor.oper_mode_offset = 0;
+
+	/* Disable 11ac by default. Enable it only where there
+	 * exist VHT_CAP IE in AP beacon
+	 */
+	priv->curr_bss_params.bss_descriptor.disable_11ac = true;
 
 	/* Make a copy of current BSSID descriptor */
 	memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
@@ -1747,7 +1772,7 @@
 					    .mac_address, ETH_ALEN))
 					mwifiex_update_curr_bss_params(priv,
 								       bss);
-				cfg80211_put_bss(bss);
+				cfg80211_put_bss(priv->wdev->wiphy, bss);
 			}
 		} else {
 			dev_dbg(adapter->dev, "missing BSS channel IE\n");
@@ -1880,10 +1905,8 @@
 	}
 
 	scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
-	if (!scan_cfg) {
-		dev_err(adapter->dev, "failed to alloc scan_cfg\n");
+	if (!scan_cfg)
 		return -ENOMEM;
-	}
 
 	scan_cfg->ssid_list = req_ssid;
 	scan_cfg->num_ssids = 1;
@@ -1997,11 +2020,8 @@
 		kfree(priv->curr_bcn_buf);
 		priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size,
 					     GFP_ATOMIC);
-		if (!priv->curr_bcn_buf) {
-			dev_err(priv->adapter->dev,
-				"failed to alloc curr_bcn_buf\n");
+		if (!priv->curr_bcn_buf)
 			return;
-		}
 	}
 
 	memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
@@ -2033,6 +2053,14 @@
 			(curr_bss->beacon_buf +
 			 curr_bss->ht_info_offset);
 
+	if (curr_bss->bcn_vht_cap)
+		curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
+						curr_bss->vht_cap_offset);
+
+	if (curr_bss->bcn_vht_oper)
+		curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
+						 curr_bss->vht_info_offset);
+
 	if (curr_bss->bcn_bss_co_2040)
 		curr_bss->bcn_bss_co_2040 =
 			(curr_bss->beacon_buf + curr_bss->bss_co_2040_offset);
@@ -2040,6 +2068,10 @@
 	if (curr_bss->bcn_ext_cap)
 		curr_bss->bcn_ext_cap = curr_bss->beacon_buf +
 			curr_bss->ext_cap_offset;
+
+	if (curr_bss->oper_mode)
+		curr_bss->oper_mode = (void *)(curr_bss->beacon_buf +
+					       curr_bss->oper_mode_offset);
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 5a1c1d0..e63f646 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -332,7 +332,7 @@
 			u8 *buffer, u32 pkt_len, u32 port)
 {
 	struct sdio_mmc_card *card = adapter->card;
-	int ret = -1;
+	int ret;
 	u8 blk_mode =
 		(port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
 	u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
@@ -350,8 +350,7 @@
 
 	sdio_claim_host(card->func);
 
-	if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size))
-		ret = 0;
+	ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size);
 
 	sdio_release_host(card->func);
 
@@ -365,7 +364,7 @@
 				  u32 len, u32 port, u8 claim)
 {
 	struct sdio_mmc_card *card = adapter->card;
-	int ret = -1;
+	int ret;
 	u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE
 		       : BLOCK_MODE;
 	u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
@@ -376,8 +375,7 @@
 	if (claim)
 		sdio_claim_host(card->func);
 
-	if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size))
-		ret = 0;
+	ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size);
 
 	if (claim)
 		sdio_release_host(card->func);
@@ -718,11 +716,8 @@
 
 	/* Assume that the allocated buffer is 8-byte aligned */
 	fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
-	if (!fwbuf) {
-		dev_err(adapter->dev,
-			"unable to alloc buffer for FW. Terminating dnld\n");
+	if (!fwbuf)
 		return -ENOMEM;
-	}
 
 	/* Perform firmware data transfer */
 	do {
@@ -1520,7 +1515,6 @@
 
 	card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL);
 	if (!card->mpa_tx.buf) {
-		dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n");
 		ret = -1;
 		goto error;
 	}
@@ -1529,7 +1523,6 @@
 
 	card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL);
 	if (!card->mpa_rx.buf) {
-		dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n");
 		ret = -1;
 		goto error;
 	}
@@ -1682,10 +1675,8 @@
 
 	/* Allocate buffers for SDIO MP-A */
 	card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
-	if (!card->mp_regs) {
-		dev_err(adapter->dev, "failed to alloc mp_regs\n");
+	if (!card->mp_regs)
 		return -ENOMEM;
-	}
 
 	ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
 					     SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
@@ -1752,6 +1743,8 @@
 static struct mmc_host *reset_host;
 static void sdio_card_reset_worker(struct work_struct *work)
 {
+	struct mmc_host *target = reset_host;
+
 	/* The actual reset operation must be run outside of driver thread.
 	 * This is because mmc_remove_host() will cause the device to be
 	 * instantly destroyed, and the driver then needs to end its thread,
@@ -1761,10 +1754,10 @@
 	 */
 
 	pr_err("Resetting card...\n");
-	mmc_remove_host(reset_host);
+	mmc_remove_host(target);
 	/* 20ms delay is based on experiment with sdhci controller */
 	mdelay(20);
-	mmc_add_host(reset_host);
+	mmc_add_host(target);
 }
 static DECLARE_WORK(card_reset_work, sdio_card_reset_worker);
 
@@ -1773,9 +1766,6 @@
 {
 	struct sdio_mmc_card *card = adapter->card;
 
-	if (work_pending(&card_reset_work))
-		return;
-
 	reset_host = card->func->card->host;
 	schedule_work(&card_reset_work);
 }
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 5d87195..c55c5bb 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -931,7 +931,6 @@
 	struct host_cmd_ds_pcie_details *host_spec =
 					&cmd->params.pcie_host_spec;
 	struct pcie_service_card *card = priv->adapter->card;
-	phys_addr_t *buf_pa;
 
 	cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
 	cmd->size = cpu_to_le16(sizeof(struct
@@ -953,10 +952,11 @@
 	host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase);
 	host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32);
 	host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
-	if (card->sleep_cookie) {
-		buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
-		host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
-		host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32);
+	if (card->sleep_cookie_vbase) {
+		host_spec->sleep_cookie_addr_lo =
+						(u32)(card->sleep_cookie_pbase);
+		host_spec->sleep_cookie_addr_hi =
+				 (u32)(((u64)(card->sleep_cookie_pbase)) >> 32);
 		dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n",
 			host_spec->sleep_cookie_addr_lo);
 	}
@@ -1230,7 +1230,7 @@
 						  data_buf);
 		break;
 	case HostCmd_CMD_11N_CFG:
-		ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, data_buf);
+		ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf);
 		break;
 	case HostCmd_CMD_WMM_GET_STATUS:
 		dev_dbg(priv->adapter->dev,
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 65c12eb..4669f8d 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -24,6 +24,7 @@
 #include "main.h"
 #include "wmm.h"
 #include "11n.h"
+#include "11ac.h"
 
 
 /*
@@ -935,9 +936,8 @@
 					/ MWIFIEX_SDIO_BLOCK_SIZE)
 				       * MWIFIEX_SDIO_BLOCK_SIZE;
 		adapter->curr_tx_buf_size = adapter->tx_buf_size;
-		dev_dbg(adapter->dev,
-			"cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
-			adapter->max_tx_buf_size, adapter->tx_buf_size);
+		dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n",
+			adapter->curr_tx_buf_size);
 
 		if (adapter->if_ops.update_mp_end_port)
 			adapter->if_ops.update_mp_end_port(adapter,
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index f542bb8..9f33c92 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -162,13 +162,9 @@
 
 	rcu_read_lock();
 	ies = rcu_dereference(bss->ies);
-	if (WARN_ON(!ies)) {
-		/* should never happen */
-		rcu_read_unlock();
-		return -EINVAL;
-	}
 	beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
 	beacon_ie_len = ies->len;
+	bss_desc->timestamp = ies->tsf;
 	rcu_read_unlock();
 
 	if (!beacon_ie) {
@@ -184,7 +180,6 @@
 	bss_desc->cap_info_bitmap = bss->capability;
 	bss_desc->bss_band = bss_priv->band;
 	bss_desc->fw_tsf = bss_priv->fw_tsf;
-	bss_desc->timestamp = bss->tsf;
 	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
 		dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
 		bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
@@ -266,11 +261,9 @@
 
 		/* Allocate and fill new bss descriptor */
 		bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
-				GFP_KERNEL);
-		if (!bss_desc) {
-			dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+				   GFP_KERNEL);
+		if (!bss_desc)
 			return -ENOMEM;
-		}
 
 		ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
 		if (ret)
@@ -288,9 +281,10 @@
 
 			if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
 			    == HostCmd_SCAN_RADIO_TYPE_BG)
-				config_bands = BAND_B | BAND_G | BAND_GN;
+				config_bands = BAND_B | BAND_G | BAND_GN |
+					       BAND_GAC;
 			else
-				config_bands = BAND_A | BAND_AN;
+				config_bands = BAND_A | BAND_AN | BAND_AAC;
 
 			if (!((config_bands | adapter->fw_bands) &
 			      ~adapter->fw_bands))
@@ -324,7 +318,7 @@
 		}
 
 		if (bss)
-			cfg80211_put_bss(bss);
+			cfg80211_put_bss(priv->adapter->wiphy, bss);
 	} else {
 		/* Adhoc mode */
 		/* If the requested SSID matches current SSID, return */
@@ -354,7 +348,7 @@
 							" list. Joining...\n");
 			ret = mwifiex_adhoc_join(priv, bss_desc);
 			if (bss)
-				cfg80211_put_bss(bss);
+				cfg80211_put_bss(priv->adapter->wiphy, bss);
 		} else {
 			dev_dbg(adapter->dev, "info: Network not found in "
 				"the list, creating adhoc with ssid = %s\n",
@@ -636,11 +630,8 @@
 		}
 	}
 	buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
-	if (!buf) {
-		dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
-			__func__);
+	if (!buf)
 		return -ENOMEM;
-	}
 
 	txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
 	txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 8c80024..296faec 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -117,14 +117,16 @@
 		dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
 		break;
 	case -1:
-		adapter->data_sent = false;
+		if (adapter->iface_type != MWIFIEX_PCIE)
+			adapter->data_sent = false;
 		dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
 			ret);
 		adapter->dbg.num_tx_host_to_card_failure++;
 		mwifiex_write_data_complete(adapter, skb, 0, ret);
 		break;
 	case -EINPROGRESS:
-		adapter->data_sent = false;
+		if (adapter->iface_type != MWIFIEX_PCIE)
+			adapter->data_sent = false;
 		break;
 	case 0:
 		mwifiex_write_data_complete(adapter, skb, 0, ret);
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 8dd7224..6e76a15 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -219,6 +219,7 @@
 	config->rts_threshold = 0x7FFF;
 	config->frag_threshold = 0x7FFF;
 	config->retry_limit = 0x7F;
+	config->qos_info = 0xFF;
 }
 
 /* This function parses BSS related parameters from structure
@@ -297,6 +298,38 @@
 	return;
 }
 
+/* This function parses WMM related parameters from cfg80211_ap_settings
+ * structure and updates bss_config structure.
+ */
+void
+mwifiex_set_wmm_params(struct mwifiex_private *priv,
+		       struct mwifiex_uap_bss_param *bss_cfg,
+		       struct cfg80211_ap_settings *params)
+{
+	const u8 *vendor_ie;
+	struct ieee_types_header *wmm_ie;
+	u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02};
+
+	vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+					    WLAN_OUI_TYPE_MICROSOFT_WMM,
+					    params->beacon.tail,
+					    params->beacon.tail_len);
+	if (vendor_ie) {
+		wmm_ie = (struct ieee_types_header *)vendor_ie;
+		memcpy(&bss_cfg->wmm_info, wmm_ie + 1,
+		       sizeof(bss_cfg->wmm_info));
+		priv->wmm_enabled = 1;
+	} else {
+		memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info));
+		memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui));
+		bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE;
+		bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION;
+		priv->wmm_enabled = 0;
+	}
+
+	bss_cfg->qos_info = 0x00;
+	return;
+}
 /* This function parses BSS related parameters from structure
  * and prepares TLVs specific to WEP encryption.
  * These TLVs are appended to command buffer.
@@ -354,6 +387,7 @@
 	struct host_cmd_tlv_rates *tlv_rates;
 	struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
 	struct mwifiex_ie_types_htcap *htcap;
+	struct mwifiex_ie_types_wmmcap *wmm_cap;
 	struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
 	int i;
 	u16 cmd_size = *param_size;
@@ -507,6 +541,16 @@
 		tlv += sizeof(struct mwifiex_ie_types_htcap);
 	}
 
+	if (bss_cfg->wmm_info.qos_info != 0xFF) {
+		wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv;
+		wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC);
+		wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info));
+		memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info,
+		       sizeof(wmm_cap->wmm_info));
+		cmd_size += sizeof(struct mwifiex_ie_types_wmmcap);
+		tlv += sizeof(struct mwifiex_ie_types_wmmcap);
+	}
+
 	if (bss_cfg->sta_ao_timer) {
 		ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
 		ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 63ac9f2..f90fe21 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -672,7 +672,7 @@
 			   *len, &actual_length, timeout);
 	if (ret) {
 		dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret);
-		ret = -1;
+		return ret;
 	}
 
 	*len = actual_length;
@@ -691,7 +691,7 @@
 			   *len, &actual_length, timeout);
 	if (ret) {
 		dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret);
-		ret = -1;
+		return ret;
 	}
 
 	*len = actual_length;
@@ -786,21 +786,6 @@
 	return 0;
 }
 
-/* This function reads one block of firmware data. */
-static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter,
-			       u32 offset, u32 len, u8 *buf)
-{
-	if (!buf || !len)
-		return -1;
-
-	if (offset + len > adapter->firmware->size)
-		return -1;
-
-	memcpy(buf, adapter->firmware->data + offset, len);
-
-	return 0;
-}
-
 static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 				    struct mwifiex_fw_image *fw)
 {
@@ -836,23 +821,14 @@
 			dlen = 0;
 		} else {
 			/* copy the header of the fw_data to get the length */
-			if (firmware)
-				memcpy(&fwdata->fw_hdr, &firmware[tlen],
-				       sizeof(struct fw_header));
-			else
-				mwifiex_get_fw_data(adapter, tlen,
-						    sizeof(struct fw_header),
-						    (u8 *)&fwdata->fw_hdr);
+			memcpy(&fwdata->fw_hdr, &firmware[tlen],
+			       sizeof(struct fw_header));
 
 			dlen = le32_to_cpu(fwdata->fw_hdr.data_len);
 			dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd);
 			tlen += sizeof(struct fw_header);
 
-			if (firmware)
-				memcpy(fwdata->data, &firmware[tlen], dlen);
-			else
-				mwifiex_get_fw_data(adapter, tlen, dlen,
-						    (u8 *)fwdata->data);
+			memcpy(fwdata->data, &firmware[tlen], dlen);
 
 			fwdata->seq_num = cpu_to_le32(fw_seqnum);
 			tlen += dlen;
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 0982375..2155397 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -91,7 +91,7 @@
 		memcpy(info->packets_out,
 		       priv->wmm.packets_out,
 		       sizeof(priv->wmm.packets_out));
-		info->max_tx_buf_size = (u32) adapter->max_tx_buf_size;
+		info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size;
 		info->tx_buf_size = (u32) adapter->tx_buf_size;
 		info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
 							      info->rx_tbl);
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index f6d36b9..cb2d058 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -22,16 +22,16 @@
 
 static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
 {
-	return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t));
+	return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t));
 }
 
 static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
 {
-	return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t));
+	return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t));
 }
 
-static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb)
+static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa)
 {
-	return (phys_addr_t *)skb->cb;
+	memcpy(buf_pa, skb->cb, sizeof(dma_addr_t));
 }
 #endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 818f871..32adc87 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -109,12 +109,9 @@
 	struct mwifiex_ra_list_tbl *ra_list;
 
 	ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC);
-
-	if (!ra_list) {
-		dev_err(adapter->dev, "%s: failed to alloc ra_list\n",
-			__func__);
+	if (!ra_list)
 		return NULL;
-	}
+
 	INIT_LIST_HEAD(&ra_list->list);
 	skb_queue_head_init(&ra_list->skb_head);
 
@@ -568,6 +565,8 @@
 	mwifiex_wmm_delete_all_ralist(priv);
 	memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
 
+	if (priv->adapter->if_ops.clean_pcie_ring)
+		priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
 	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }
 
@@ -1206,13 +1205,15 @@
 				       ra_list_flags);
 		break;
 	case -1:
-		adapter->data_sent = false;
+		if (adapter->iface_type != MWIFIEX_PCIE)
+			adapter->data_sent = false;
 		dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
 		adapter->dbg.num_tx_host_to_card_failure++;
 		mwifiex_write_data_complete(adapter, skb, 0, ret);
 		break;
 	case -EINPROGRESS:
-		adapter->data_sent = false;
+		if (adapter->iface_type != MWIFIEX_PCIE)
+			adapter->data_sent = false;
 	default:
 		break;
 	}
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 83564d3..091d9a6 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -101,6 +101,18 @@
 #define MWL8K_MAX_TX_QUEUES	(MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES)
 #define mwl8k_tx_queues(priv)	(MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues)
 
+/* txpriorities are mapped with hw queues.
+ * Each hw queue has a txpriority.
+ */
+#define TOTAL_HW_TX_QUEUES	8
+
+/* Each HW queue can have one AMPDU stream.
+ * But, because one of the hw queue is reserved,
+ * maximum AMPDU queues that can be created are
+ * one short of total tx queues.
+ */
+#define MWL8K_NUM_AMPDU_STREAMS	(TOTAL_HW_TX_QUEUES - 1)
+
 struct rxd_ops {
 	int rxd_size;
 	void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
@@ -160,7 +172,6 @@
 	u8 tid;
 	u8 state;
 	u8 idx;
-	u8 txq_idx; /* index of this stream in priv->txq */
 };
 
 struct mwl8k_priv {
@@ -202,6 +213,8 @@
 	int fw_mutex_depth;
 	struct completion *hostcmd_wait;
 
+	atomic_t watchdog_event_pending;
+
 	/* lock held over TX and TX reap */
 	spinlock_t tx_lock;
 
@@ -272,6 +285,9 @@
 	char *fw_pref;
 	char *fw_alt;
 	struct completion firmware_loading_complete;
+
+	/* bitmap of running BSSes */
+	u32 running_bsses;
 };
 
 #define MAX_WEP_KEY_LEN         13
@@ -318,20 +334,20 @@
 #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
 
 static const struct ieee80211_channel mwl8k_channels_24[] = {
-	{ .center_freq = 2412, .hw_value = 1, },
-	{ .center_freq = 2417, .hw_value = 2, },
-	{ .center_freq = 2422, .hw_value = 3, },
-	{ .center_freq = 2427, .hw_value = 4, },
-	{ .center_freq = 2432, .hw_value = 5, },
-	{ .center_freq = 2437, .hw_value = 6, },
-	{ .center_freq = 2442, .hw_value = 7, },
-	{ .center_freq = 2447, .hw_value = 8, },
-	{ .center_freq = 2452, .hw_value = 9, },
-	{ .center_freq = 2457, .hw_value = 10, },
-	{ .center_freq = 2462, .hw_value = 11, },
-	{ .center_freq = 2467, .hw_value = 12, },
-	{ .center_freq = 2472, .hw_value = 13, },
-	{ .center_freq = 2484, .hw_value = 14, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, },
 };
 
 static const struct ieee80211_rate mwl8k_rates_24[] = {
@@ -352,10 +368,10 @@
 };
 
 static const struct ieee80211_channel mwl8k_channels_50[] = {
-	{ .center_freq = 5180, .hw_value = 36, },
-	{ .center_freq = 5200, .hw_value = 40, },
-	{ .center_freq = 5220, .hw_value = 44, },
-	{ .center_freq = 5240, .hw_value = 48, },
+	{ .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, },
+	{ .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, },
+	{ .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, },
+	{ .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, },
 };
 
 static const struct ieee80211_rate mwl8k_rates_50[] = {
@@ -1133,7 +1149,6 @@
 
 	rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL);
 	if (rxq->buf == NULL) {
-		wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n");
 		pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
 		return -ENOMEM;
 	}
@@ -1426,7 +1441,6 @@
 
 	txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL);
 	if (txq->skb == NULL) {
-		wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n");
 		pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
 		return -ENOMEM;
 	}
@@ -1516,6 +1530,9 @@
 			return -EBUSY;
 	}
 
+	if (atomic_read(&priv->watchdog_event_pending))
+		return 0;
+
 	/*
 	 * The TX queues are stopped at this point, so this test
 	 * doesn't need to take ->tx_lock.
@@ -1537,6 +1554,14 @@
 		spin_unlock_bh(&priv->tx_lock);
 		timeout = wait_for_completion_timeout(&tx_wait,
 			    msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
+
+		if (atomic_read(&priv->watchdog_event_pending)) {
+			spin_lock_bh(&priv->tx_lock);
+			priv->tx_wait = NULL;
+			spin_unlock_bh(&priv->tx_lock);
+			return 0;
+		}
+
 		spin_lock_bh(&priv->tx_lock);
 
 		if (timeout) {
@@ -1564,6 +1589,7 @@
 
 		rc = -ETIMEDOUT;
 	}
+	priv->tx_wait = NULL;
 	spin_unlock_bh(&priv->tx_lock);
 
 	return rc;
@@ -1734,14 +1760,13 @@
 	struct mwl8k_priv *priv = hw->priv;
 	int i;
 
-	for (i = 0; i < priv->num_ampdu_queues; i++) {
+	for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
 		stream = &priv->ampdu[i];
 		if (stream->state == AMPDU_NO_STREAM) {
 			stream->sta = sta;
 			stream->state = AMPDU_STREAM_NEW;
 			stream->tid = tid;
 			stream->idx = i;
-			stream->txq_idx = MWL8K_TX_WMM_QUEUES + i;
 			wiphy_debug(hw->wiphy, "Added a new stream for %pM %d",
 				    sta->addr, tid);
 			return stream;
@@ -1782,7 +1807,7 @@
 	struct mwl8k_priv *priv = hw->priv;
 	int i;
 
-	for (i = 0 ; i < priv->num_ampdu_queues; i++) {
+	for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
 		struct mwl8k_ampdu_stream *stream;
 		stream = &priv->ampdu[i];
 		if (stream->state == AMPDU_NO_STREAM)
@@ -1829,6 +1854,13 @@
 		tx_stats->pkts++;
 }
 
+/* The hardware ampdu queues start from 5.
+ * txpriorities for ampdu queues are
+ * 5 6 7 0 1 2 3 4 ie., queue 5 is highest
+ * and queue 3 is lowest (queue 4 is reserved)
+ */
+#define BA_QUEUE		5
+
 static void
 mwl8k_txq_xmit(struct ieee80211_hw *hw,
 	       int index,
@@ -1928,8 +1960,13 @@
 		stream = mwl8k_lookup_stream(hw, sta->addr, tid);
 		if (stream != NULL) {
 			if (stream->state == AMPDU_STREAM_ACTIVE) {
-				txpriority = stream->txq_idx;
-				index = stream->txq_idx;
+				WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK));
+				txpriority = (BA_QUEUE + stream->idx) %
+					     TOTAL_HW_TX_QUEUES;
+				if (stream->idx <= 1)
+					index = stream->idx +
+						MWL8K_TX_WMM_QUEUES;
+
 			} else if (stream->state == AMPDU_STREAM_NEW) {
 				/* We get here if the driver sends us packets
 				 * after we've initiated a stream, but before
@@ -1971,6 +2008,9 @@
 			}
 		}
 		spin_unlock(&priv->stream_lock);
+	} else {
+		qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
+		qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
 	}
 
 	dma = pci_map_single(priv->pdev, skb->data,
@@ -2117,6 +2157,8 @@
 	}
 }
 
+static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable,
+			       u32 bitmap);
 
 /*
  * Command processing.
@@ -2135,6 +2177,34 @@
 	int rc;
 	unsigned long timeout = 0;
 	u8 buf[32];
+	u32 bitmap = 0;
+
+	wiphy_dbg(hw->wiphy, "Posting %s [%d]\n",
+		  mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), cmd->macid);
+
+	/* Before posting firmware commands that could change the hardware
+	 * characteristics, make sure that all BSSes are stopped temporary.
+	 * Enable these stopped BSSes after completion of the commands
+	 */
+
+	rc = mwl8k_fw_lock(hw);
+	if (rc)
+		return rc;
+
+	if (priv->ap_fw && priv->running_bsses) {
+		switch (le16_to_cpu(cmd->code)) {
+		case MWL8K_CMD_SET_RF_CHANNEL:
+		case MWL8K_CMD_RADIO_CONTROL:
+		case MWL8K_CMD_RF_TX_POWER:
+		case MWL8K_CMD_TX_POWER:
+		case MWL8K_CMD_RF_ANTENNA:
+		case MWL8K_CMD_RTS_THRESHOLD:
+		case MWL8K_CMD_MIMO_CONFIG:
+			bitmap = priv->running_bsses;
+			mwl8k_enable_bsses(hw, false, bitmap);
+			break;
+		}
+	}
 
 	cmd->result = (__force __le16) 0xffff;
 	dma_size = le16_to_cpu(cmd->length);
@@ -2143,13 +2213,6 @@
 	if (pci_dma_mapping_error(priv->pdev, dma_addr))
 		return -ENOMEM;
 
-	rc = mwl8k_fw_lock(hw);
-	if (rc) {
-		pci_unmap_single(priv->pdev, dma_addr, dma_size,
-						PCI_DMA_BIDIRECTIONAL);
-		return rc;
-	}
-
 	priv->hostcmd_wait = &cmd_wait;
 	iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
 	iowrite32(MWL8K_H2A_INT_DOORBELL,
@@ -2162,7 +2225,6 @@
 
 	priv->hostcmd_wait = NULL;
 
-	mwl8k_fw_unlock(hw);
 
 	pci_unmap_single(priv->pdev, dma_addr, dma_size,
 					PCI_DMA_BIDIRECTIONAL);
@@ -2189,6 +2251,11 @@
 				     ms);
 	}
 
+	if (bitmap)
+		mwl8k_enable_bsses(hw, true, bitmap);
+
+	mwl8k_fw_unlock(hw);
+
 	return rc;
 }
 
@@ -2450,7 +2517,7 @@
 		priv->hw_rev = cmd->hw_rev;
 		mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
 		priv->ap_macids_supported = 0x000000ff;
-		priv->sta_macids_supported = 0x00000000;
+		priv->sta_macids_supported = 0x00000100;
 		priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues);
 		if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) {
 			wiphy_warn(hw->wiphy, "fw reported %d ampdu queues"
@@ -3469,7 +3536,10 @@
 	mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
 	if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) {
 		if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported))
-			mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
+			if (priv->ap_fw)
+				mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
+			else
+				mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
 		else
 			mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
 	} else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) {
@@ -3578,7 +3648,11 @@
 	return rc;
 }
 
-#define INVALID_BA	0xAA
+#define MWL8K_WMM_QUEUE_NUMBER	3
+
+static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
+			     u8 idx);
+
 static void mwl8k_watchdog_ba_events(struct work_struct *work)
 {
 	int rc;
@@ -3586,24 +3660,41 @@
 	struct mwl8k_ampdu_stream *streams;
 	struct mwl8k_priv *priv =
 		container_of(work, struct mwl8k_priv, watchdog_ba_handle);
+	struct ieee80211_hw *hw = priv->hw;
+	int i;
+	u32 status = 0;
+
+	mwl8k_fw_lock(hw);
 
 	rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
 	if (rc)
-		return;
+		goto done;
 
-	if (bitmap == INVALID_BA)
-		return;
+	spin_lock(&priv->stream_lock);
 
 	/* the bitmap is the hw queue number.  Map it to the ampdu queue. */
-	stream_index = bitmap - MWL8K_TX_WMM_QUEUES;
+	for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) {
+		if (bitmap & (1 << i)) {
+			stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) %
+				       TOTAL_HW_TX_QUEUES;
+			streams = &priv->ampdu[stream_index];
+			if (streams->state == AMPDU_STREAM_ACTIVE) {
+				ieee80211_stop_tx_ba_session(streams->sta,
+							     streams->tid);
+				spin_unlock(&priv->stream_lock);
+				mwl8k_destroy_ba(hw, stream_index);
+				spin_lock(&priv->stream_lock);
+			}
+		}
+	}
 
-	BUG_ON(stream_index >= priv->num_ampdu_queues);
-
-	streams = &priv->ampdu[stream_index];
-
-	if (streams->state == AMPDU_STREAM_ACTIVE)
-		ieee80211_stop_tx_ba_session(streams->sta, streams->tid);
-
+	spin_unlock(&priv->stream_lock);
+done:
+	atomic_dec(&priv->watchdog_event_pending);
+	status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+	iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG),
+		  priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+	mwl8k_fw_unlock(hw);
 	return;
 }
 
@@ -3620,8 +3711,16 @@
 			       struct ieee80211_vif *vif, int enable)
 {
 	struct mwl8k_cmd_bss_start *cmd;
+	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+	struct mwl8k_priv *priv = hw->priv;
 	int rc;
 
+	if (enable && (priv->running_bsses & (1 << mwl8k_vif->macid)))
+		return 0;
+
+	if (!enable && !(priv->running_bsses & (1 << mwl8k_vif->macid)))
+		return 0;
+
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
 		return -ENOMEM;
@@ -3633,9 +3732,31 @@
 	rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
 	kfree(cmd);
 
+	if (!rc) {
+		if (enable)
+			priv->running_bsses |= (1 << mwl8k_vif->macid);
+		else
+			priv->running_bsses &= ~(1 << mwl8k_vif->macid);
+	}
 	return rc;
 }
 
+static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, u32 bitmap)
+{
+	struct mwl8k_priv *priv = hw->priv;
+	struct mwl8k_vif *mwl8k_vif, *tmp_vif;
+	struct ieee80211_vif *vif;
+
+	list_for_each_entry_safe(mwl8k_vif, tmp_vif, &priv->vif_list, list) {
+		vif = mwl8k_vif->vif;
+
+		if (!(bitmap & (1 << mwl8k_vif->macid)))
+			continue;
+
+		if (vif->type == NL80211_IFTYPE_AP)
+			mwl8k_cmd_bss_start(hw, vif, enable);
+	}
+}
 /*
  * CMD_BASTREAM.
  */
@@ -3763,7 +3884,7 @@
 }
 
 static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
-			     struct mwl8k_ampdu_stream *stream)
+			     u8 idx)
 {
 	struct mwl8k_cmd_bastream *cmd;
 
@@ -3775,10 +3896,10 @@
 	cmd->header.length = cpu_to_le16(sizeof(*cmd));
 	cmd->action = cpu_to_le32(MWL8K_BA_DESTROY);
 
-	cmd->destroy_params.ba_context = cpu_to_le32(stream->idx);
+	cmd->destroy_params.ba_context = cpu_to_le32(idx);
 	mwl8k_post_cmd(hw, &cmd->header);
 
-	wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
+	wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx);
 
 	kfree(cmd);
 }
@@ -3875,7 +3996,30 @@
 				     struct ieee80211_vif *vif, u8 *addr)
 {
 	struct mwl8k_cmd_set_new_stn *cmd;
-	int rc;
+	struct mwl8k_priv *priv = hw->priv;
+	int rc, i;
+	u8 idx;
+
+	spin_lock(&priv->stream_lock);
+	/* Destroy any active ampdu streams for this sta */
+	for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
+		struct mwl8k_ampdu_stream *s;
+		s = &priv->ampdu[i];
+		if (s->state != AMPDU_NO_STREAM) {
+			if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) {
+				if (s->state == AMPDU_STREAM_ACTIVE) {
+					idx = s->idx;
+					spin_unlock(&priv->stream_lock);
+					mwl8k_destroy_ba(hw, idx);
+					spin_lock(&priv->stream_lock);
+				} else if (s->state == AMPDU_STREAM_NEW) {
+					mwl8k_remove_stream(hw, s);
+				}
+			}
+		}
+	}
+
+	spin_unlock(&priv->stream_lock);
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 	if (cmd == NULL)
@@ -4119,8 +4263,9 @@
 	u8 encr_type;
 	u8 *addr;
 	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+	struct mwl8k_priv *priv = hw->priv;
 
-	if (vif->type == NL80211_IFTYPE_STATION)
+	if (vif->type == NL80211_IFTYPE_STATION && !priv->ap_fw)
 		return -EOPNOTSUPP;
 
 	if (sta == NULL)
@@ -4303,6 +4448,10 @@
 	}
 
 	if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
+		iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG,
+			  priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+
+		atomic_inc(&priv->watchdog_event_pending);
 		status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
 		ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
 	}
@@ -4446,6 +4595,8 @@
 		priv->irq = -1;
 		tasklet_disable(&priv->poll_tx_task);
 		tasklet_disable(&priv->poll_rx_task);
+	} else {
+		ieee80211_wake_queues(hw);
 	}
 
 	return rc;
@@ -4520,12 +4671,18 @@
 		break;
 	case NL80211_IFTYPE_STATION:
 		if (priv->ap_fw && di->fw_image_sta) {
-			/* we must load the sta fw to meet this request */
-			if (!list_empty(&priv->vif_list))
-				return -EBUSY;
-			rc = mwl8k_reload_firmware(hw, di->fw_image_sta);
-			if (rc)
-				return rc;
+			if (!list_empty(&priv->vif_list)) {
+				wiphy_warn(hw->wiphy, "AP interface is running.\n"
+					   "Adding STA interface for WDS");
+			} else {
+				/* we must load the sta fw to
+				 * meet this request.
+				 */
+				rc = mwl8k_reload_firmware(hw,
+							   di->fw_image_sta);
+				if (rc)
+					return rc;
+			}
 		}
 		macids_supported = priv->sta_macids_supported;
 		break;
@@ -4549,7 +4706,7 @@
 	/* Set the mac address.  */
 	mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
 
-	if (priv->ap_fw)
+	if (vif->type == NL80211_IFTYPE_AP)
 		mwl8k_cmd_set_new_stn_add_self(hw, vif);
 
 	priv->macids_used |= 1 << mwl8k_vif->macid;
@@ -4574,7 +4731,7 @@
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
 
-	if (priv->ap_fw)
+	if (vif->type == NL80211_IFTYPE_AP)
 		mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr);
 
 	mwl8k_cmd_del_mac_addr(hw, vif, vif->addr);
@@ -4648,9 +4805,11 @@
 	if (rc)
 		goto out;
 
-	rc = mwl8k_cmd_set_rf_channel(hw, conf);
-	if (rc)
-		goto out;
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		rc = mwl8k_cmd_set_rf_channel(hw, conf);
+		if (rc)
+			goto out;
+	}
 
 	if (conf->power_level > 18)
 		conf->power_level = 18;
@@ -4663,12 +4822,6 @@
 				goto out;
 		}
 
-		rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3);
-		if (rc)
-			wiphy_warn(hw->wiphy, "failed to set # of RX antennas");
-		rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7);
-		if (rc)
-			wiphy_warn(hw->wiphy, "failed to set # of TX antennas");
 
 	} else {
 		rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
@@ -4726,7 +4879,8 @@
 		rcu_read_unlock();
 	}
 
-	if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) {
+	if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc &&
+	    !priv->ap_fw) {
 		rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates);
 		if (rc)
 			goto out;
@@ -4734,6 +4888,25 @@
 		rc = mwl8k_cmd_use_fixed_rate_sta(hw);
 		if (rc)
 			goto out;
+	} else {
+		if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc &&
+		    priv->ap_fw) {
+			int idx;
+			int rate;
+
+			/* Use AP firmware specific rate command.
+			 */
+			idx = ffs(vif->bss_conf.basic_rates);
+			if (idx)
+				idx--;
+
+			if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+				rate = mwl8k_rates_24[idx].hw_value;
+			else
+				rate = mwl8k_rates_50[idx].hw_value;
+
+			mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate);
+		}
 	}
 
 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -4743,13 +4916,13 @@
 			goto out;
 	}
 
-	if (changed & BSS_CHANGED_ERP_SLOT) {
+	if ((changed & BSS_CHANGED_ERP_SLOT) && !priv->ap_fw)  {
 		rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot);
 		if (rc)
 			goto out;
 	}
 
-	if (vif->bss_conf.assoc &&
+	if (vif->bss_conf.assoc && !priv->ap_fw &&
 	    (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT |
 			BSS_CHANGED_HT))) {
 		rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates);
@@ -4829,11 +5002,9 @@
 mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       struct ieee80211_bss_conf *info, u32 changed)
 {
-	struct mwl8k_priv *priv = hw->priv;
-
-	if (!priv->ap_fw)
+	if (vif->type == NL80211_IFTYPE_STATION)
 		mwl8k_bss_info_changed_sta(hw, vif, info, changed);
-	else
+	if (vif->type == NL80211_IFTYPE_AP)
 		mwl8k_bss_info_changed_ap(hw, vif, info, changed);
 }
 
@@ -5094,7 +5265,7 @@
 	int i, rc = 0;
 	struct mwl8k_priv *priv = hw->priv;
 	struct mwl8k_ampdu_stream *stream;
-	u8 *addr = sta->addr;
+	u8 *addr = sta->addr, idx;
 	struct mwl8k_sta *sta_info = MWL8K_STA(sta);
 
 	if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
@@ -5172,11 +5343,14 @@
 		}
 		ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		if (stream) {
 			if (stream->state == AMPDU_STREAM_ACTIVE) {
+				idx = stream->idx;
 				spin_unlock(&priv->stream_lock);
-				mwl8k_destroy_ba(hw, stream);
+				mwl8k_destroy_ba(hw, idx);
 				spin_lock(&priv->stream_lock);
 			}
 			mwl8k_remove_stream(hw, stream);
@@ -5192,8 +5366,9 @@
 		if (!rc)
 			stream->state = AMPDU_STREAM_ACTIVE;
 		else {
+			idx = stream->idx;
 			spin_unlock(&priv->stream_lock);
-			mwl8k_destroy_ba(hw, stream);
+			mwl8k_destroy_ba(hw, idx);
 			spin_lock(&priv->stream_lock);
 			wiphy_debug(hw->wiphy,
 				"Failed adding stream for sta %pM tid %d\n",
@@ -5256,7 +5431,7 @@
 	MWL8366,
 };
 
-#define MWL8K_8366_AP_FW_API 2
+#define MWL8K_8366_AP_FW_API 3
 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
 #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
 
@@ -5296,6 +5471,8 @@
 	{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, },
 	{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, },
+	{ PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, },
+	{ PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, },
 	{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
 	{ },
 };
@@ -5464,6 +5641,7 @@
 		if (priv->rxd_ops == NULL) {
 			wiphy_err(hw->wiphy,
 				  "Driver does not have AP firmware image support for this hardware\n");
+			rc = -ENOENT;
 			goto err_stop_firmware;
 		}
 	} else {
@@ -5473,6 +5651,7 @@
 	priv->sniffer_enabled = false;
 	priv->wmm_enabled = false;
 	priv->pending_tx_pkts = 0;
+	atomic_set(&priv->watchdog_event_pending, 0);
 
 	rc = mwl8k_rxq_init(hw, 0);
 	if (rc)
@@ -5552,6 +5731,15 @@
 		goto err_free_irq;
 	}
 
+	/* Configure Antennas */
+	rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3);
+	if (rc)
+		wiphy_warn(hw->wiphy, "failed to set # of RX antennas");
+	rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7);
+	if (rc)
+		wiphy_warn(hw->wiphy, "failed to set # of TX antennas");
+
+
 	/* Disable interrupts */
 	iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
 	free_irq(priv->pdev->irq, hw);
@@ -5639,6 +5827,7 @@
 
 static const struct ieee80211_iface_limit ap_if_limits[] = {
 	{ .max = 8,	.types = BIT(NL80211_IFTYPE_AP) },
+	{ .max = 1,	.types = BIT(NL80211_IFTYPE_STATION) },
 };
 
 static const struct ieee80211_iface_combination ap_if_comb = {
@@ -5731,6 +5920,7 @@
 
 	if (priv->ap_macids_supported || priv->device_info->fw_image_ap) {
 		hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+		hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
 		hw->wiphy->iface_combinations = &ap_if_comb;
 		hw->wiphy->n_iface_combinations = 1;
 	}
@@ -5809,6 +5999,7 @@
 	priv->sram = pci_iomap(pdev, 0, 0x10000);
 	if (priv->sram == NULL) {
 		wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
+		rc = -EIO;
 		goto err_iounmap;
 	}
 
@@ -5821,6 +6012,7 @@
 		priv->regs = pci_iomap(pdev, 2, 0x10000);
 		if (priv->regs == NULL) {
 			wiphy_err(hw->wiphy, "Cannot map device registers\n");
+			rc = -EIO;
 			goto err_iounmap;
 		}
 	}
@@ -5851,6 +6043,8 @@
 
 	priv->hw_restart_in_progress = false;
 
+	priv->running_bsses = 0;
+
 	return rc;
 
 err_stop_firmware:
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 88e3ad2..38ec8d1 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -853,12 +853,8 @@
 	int err;
 
 	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
-	if (!desc) {
-		printk(KERN_WARNING
-		       "%s: Can't allocate space for RX descriptor\n",
-		       dev->name);
+	if (!desc)
 		goto update_stats;
-	}
 
 	rxfid = hermes_read_regn(hw, RXFID);
 
@@ -1336,10 +1332,9 @@
 	unsigned long flags;
 
 	sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
-	if (!sd) {
-		printk(KERN_ERR "%s: failed to alloc memory\n", __func__);
+	if (!sd)
 		return;
-	}
+
 	sd->buf = buf;
 	sd->len = len;
 	sd->type = type;
@@ -1357,10 +1352,9 @@
 	unsigned long flags;
 
 	sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
-	if (!sd) {
-		printk(KERN_ERR "%s: failed to alloc memory\n", __func__);
+	if (!sd)
 		return;
-	}
+
 	sd->len = -1; /* Abort */
 
 	spin_lock_irqsave(&priv->scan_lock, flags);
@@ -2290,7 +2284,6 @@
 	netif_carrier_off(dev);
 
 	memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
-	memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
 
 	dev->base_addr = base_addr;
 	dev->irq = irq;
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 01624dc..7744f42 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -804,10 +804,15 @@
 static int ezusb_firmware_download(struct ezusb_priv *upriv,
 				   struct ez_usb_fw *fw)
 {
-	u8 fw_buffer[FW_BUF_SIZE];
+	u8 *fw_buffer;
 	int retval, addr;
 	int variant_offset;
 
+	fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL);
+	if (!fw_buffer) {
+		printk(KERN_ERR PFX "Out of memory for firmware buffer.\n");
+		return -ENOMEM;
+	}
 	/*
 	 * This byte is 1 and should be replaced with 0.  The offset is
 	 * 0x10AD in version 0.0.6.  The byte in question should follow
@@ -859,6 +864,7 @@
 	printk(KERN_ERR PFX "Firmware download failed, error %d\n",
 	       retval);
  exit:
+	kfree(fw_buffer);
 	return retval;
 }
 
@@ -1681,7 +1687,8 @@
 		firmware.code = fw_entry->data;
 	}
 	if (firmware.size && firmware.code) {
-		ezusb_firmware_download(upriv, &firmware);
+		if (ezusb_firmware_download(upriv, &firmware))
+			goto error;
 	} else {
 		err("No firmware to download");
 		goto error;
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 96e39ed..e8c5714 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -125,7 +125,7 @@
 	cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
 				   capability, beacon_interval, ie_buf, ie_len,
 				   signal, GFP_KERNEL);
-	cfg80211_put_bss(cbss);
+	cfg80211_put_bss(wiphy, cbss);
 }
 
 void orinoco_add_extscan_result(struct orinoco_private *priv,
@@ -158,7 +158,7 @@
 	cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
 				   capability, beacon_interval, ie, ie_len,
 				   signal, GFP_KERNEL);
-	cfg80211_put_bss(cbss);
+	cfg80211_put_bss(wiphy, cbss);
 }
 
 void orinoco_add_hostscan_results(struct orinoco_private *priv,
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 933e5d9..57e3af8 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -559,6 +559,7 @@
 	mem_len = pci_resource_len(pdev, 0);
 	if (mem_len < sizeof(struct p54p_csr)) {
 		dev_err(&pdev->dev, "Too short PCI resources\n");
+		err = -ENODEV;
 		goto err_disable_dev;
 	}
 
@@ -568,8 +569,10 @@
 		goto err_disable_dev;
 	}
 
-	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
-	    pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (err) {
 		dev_err(&pdev->dev, "No suitable DMA available\n");
 		goto err_free_reg;
 	}
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 800a165..b9deef6 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -84,8 +84,8 @@
 	{USB_DEVICE(0x06b9, 0x0121)},	/* Thomson SpeedTouch 121g */
 	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
 	{USB_DEVICE(0x0803, 0x4310)},	/* Zoom 4410a */
-	{USB_DEVICE(0x083a, 0x4503)},	/* T-Com Sinus 154 data II */
 	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
+	{USB_DEVICE(0x083a, 0x4531)},	/* T-Com Sinus 154 data II */
 	{USB_DEVICE(0x083a, 0xc501)},	/* Zoom Wireless-G 4410 */
 	{USB_DEVICE(0x083a, 0xf503)},	/* Accton FD7050E ver 1010ec  */
 	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */
@@ -510,11 +510,8 @@
 		return err;
 
 	tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
-	if (!buf) {
-		dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
-					  "upload buffer!\n");
+	if (!buf)
 		return -ENOMEM;
-	}
 
 	left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
 	strcpy(buf, p54u_firmware_upload_3887);
@@ -637,11 +634,8 @@
 	const u8 *data;
 
 	buf = kmalloc(512, GFP_KERNEL);
-	if (!buf) {
-		dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
-					  "alloc failed!\n");
+	if (!buf)
 		return -ENOMEM;
-	}
 
 #define P54U_WRITE(type, addr, data) \
 	do {\
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 4e44b1a..1c22b81 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1503,6 +1503,7 @@
 			case DOT11_AUTH_BOTH:
 			case DOT11_AUTH_SK:
 				param->value = IW_AUTH_ALG_SHARED_KEY;
+				break;
 			case DOT11_AUTH_NONE:
 			default:
 				param->value = 0;
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index c5404cb..9f19cce 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -123,11 +123,8 @@
 
 		if (buf->mem == NULL) {
 			buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
-			if (!buf->mem) {
-				printk(KERN_WARNING
-				       "Error allocating management frame.\n");
+			if (!buf->mem)
 				return -ENOMEM;
-			}
 			buf->size = MGMT_FRAME_SIZE;
 		}
 		if (buf->pci_addr == 0) {
@@ -356,14 +353,11 @@
 
 		/* Determine frame size, skipping OID_INL_TUNNEL headers. */
 		size = PIMFOR_HEADER_SIZE + header->length;
-		frame = kmalloc(sizeof (struct islpci_mgmtframe) + size,
+		frame = kmalloc(sizeof(struct islpci_mgmtframe) + size,
 				GFP_ATOMIC);
-		if (!frame) {
-			printk(KERN_WARNING
-			       "%s: Out of memory, cannot handle oid 0x%08x\n",
-			       ndev->name, header->oid);
+		if (!frame)
 			continue;
-		}
+
 		frame->ndev = ndev;
 		memcpy(&frame->buf, header, size);
 		frame->header = (pimfor_header_t *) frame->buf;
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 598ca1c..e7cf37f 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1107,12 +1107,15 @@
 			 union iwreq_data *wrqu, char *extra)
 {
 	ray_dev_t *local = netdev_priv(dev);
+	UCHAR tmp[IW_ESSID_MAX_SIZE + 1];
 
 	/* Get the essid that was set */
 	memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+	memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+	tmp[IW_ESSID_MAX_SIZE] = '\0';
 
 	/* Push it out ! */
-	wrqu->essid.length = strlen(extra);
+	wrqu->essid.length = strlen(tmp);
 	wrqu->essid.flags = 1;	/* active */
 
 	return 0;
@@ -1842,6 +1845,8 @@
 	UCHAR tmp;
 	UCHAR cmd;
 	UCHAR status;
+	UCHAR memtmp[ESSID_SIZE + 1];
+
 
 	if (dev == NULL)	/* Note that we want interrupts with dev->start == 0 */
 		return IRQ_NONE;
@@ -1901,17 +1906,21 @@
 			break;
 		case CCS_START_NETWORK:
 		case CCS_JOIN_NETWORK:
+			memcpy(memtmp, local->sparm.b4.a_current_ess_id,
+								ESSID_SIZE);
+			memtmp[ESSID_SIZE] = '\0';
+
 			if (status == CCS_COMMAND_COMPLETE) {
 				if (readb
 				    (&pccs->var.start_network.net_initiated) ==
 				    1) {
 					dev_dbg(&link->dev,
 					      "ray_cs interrupt network \"%s\" started\n",
-					      local->sparm.b4.a_current_ess_id);
+					      memtmp);
 				} else {
 					dev_dbg(&link->dev,
 					      "ray_cs interrupt network \"%s\" joined\n",
-					      local->sparm.b4.a_current_ess_id);
+					      memtmp);
 				}
 				memcpy_fromio(&local->bss_id,
 					      pccs->var.start_network.bssid,
@@ -1939,12 +1948,12 @@
 				if (status == CCS_START_NETWORK) {
 					dev_dbg(&link->dev,
 					      "ray_cs interrupt network \"%s\" start failed\n",
-					      local->sparm.b4.a_current_ess_id);
+					      memtmp);
 					local->timer.function = start_net;
 				} else {
 					dev_dbg(&link->dev,
 					      "ray_cs interrupt network \"%s\" join failed\n",
-					      local->sparm.b4.a_current_ess_id);
+					      memtmp);
 					local->timer.function = join_net;
 				}
 				add_timer(&local->timer);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index abe1d03..525fd75 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1621,11 +1621,8 @@
 	} else if (mc_count) {
 		int i = 0;
 
-		mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC);
+		mc_addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC);
 		if (!mc_addrs) {
-			netdev_warn(usbdev->net,
-				    "couldn't alloc %d bytes of memory\n",
-				    mc_count * ETH_ALEN);
 			netif_addr_unlock_bh(usbdev->net);
 			return;
 		}
@@ -2029,7 +2026,7 @@
 	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
 		timestamp, capability, beacon_interval, ie, ie_len, signal,
 		GFP_KERNEL);
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(priv->wdev.wiphy, bss);
 
 	return (bss != NULL);
 }
@@ -2718,7 +2715,7 @@
 	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
 		timestamp, capability, beacon_period, ie_buf, ie_len,
 		signal, GFP_KERNEL);
-	cfg80211_put_bss(bss);
+	cfg80211_put_bss(priv->wdev.wiphy, bss);
 }
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index a2d2bc2..221beaa 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1185,8 +1185,14 @@
 	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-	rt2x00queue_map_txskb(entry);
-
+	if (rt2x00queue_map_txskb(entry)) {
+		ERROR(rt2x00dev, "Fail to map beacon, aborting\n");
+		goto out;
+	}
+	/*
+	 * Enable beaconing again.
+	 */
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
 	/*
 	 * Write the TX descriptor for the beacon.
 	 */
@@ -1196,7 +1202,7 @@
 	 * Dump beacon to userspace through debugfs.
 	 */
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
-
+out:
 	/*
 	 * Enable beaconing again.
 	 */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 9bea10f..39edc59 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1338,7 +1338,10 @@
 	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-	rt2x00queue_map_txskb(entry);
+	if (rt2x00queue_map_txskb(entry)) {
+		ERROR(rt2x00dev, "Fail to map beacon, aborting\n");
+		goto out;
+	}
 
 	/*
 	 * Write the TX descriptor for the beacon.
@@ -1349,7 +1352,7 @@
 	 * Dump beacon to userspace through debugfs.
 	 */
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
-
+out:
 	/*
 	 * Enable beaconing again.
 	 */
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 197b446..a658b4b 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -80,7 +80,7 @@
 	    rt2x00_rf(rt2x00dev, RF3022))
 		return true;
 
-	NOTICE(rt2x00dev, "Unknown RF chipset on rt305x\n");
+	WARNING(rt2x00dev, "Unknown RF chipset on rt305x\n");
 	return false;
 }
 
@@ -1296,8 +1296,7 @@
 			   !(filter_flags & FIF_CONTROL));
 	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
 			   !(filter_flags & FIF_PSPOLL));
-	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
-			   !(filter_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 0);
 	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
 			   !(filter_flags & FIF_CONTROL));
 	rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
@@ -3866,6 +3865,400 @@
 	return rfcsr24;
 }
 
+static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
+	rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
+	rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
+	rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
+	rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+	rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
+	rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+}
+
+static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
+	rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+	rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
+}
+
+static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+	rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+	rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
+	rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
+	rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+	rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+	rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+	rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+	rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+	rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+	rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
+	rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+	rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+	rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+	rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
+	rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+	rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+	rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+	rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+	rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
+	rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+	rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
+}
+
+static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
+	rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
+	rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
+	rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
+	rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
+	rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
+	rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
+	rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
+	rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
+	rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
+	rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
+	rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
+	rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
+	rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
+	rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
+	rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
+	rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
+	rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
+	rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
+	rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
+	rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
+	rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
+	rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
+	rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
+	rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+}
+
+static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
+	rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
+	rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
+	rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
+	rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
+	rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+}
+
+static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
+	rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
+	rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
+	rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
+	rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
+	rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
+}
+
+static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+		rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+	else
+		rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
+
+	rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+	rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+		rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+	else
+		rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+	rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+	rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+	rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+	rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+	rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+		rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+	else
+		rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
+	rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+	rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
+	rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
+	rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+	rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+		rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+	else
+		rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
+	rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+
+	rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+		rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+	else
+		rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
+	rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+	rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
+	rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
+	rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+	rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
+
+	rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+	if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+		rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
+	else
+		rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
+	rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+}
+
+static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
+{
+	rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
+	rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+	rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+	rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+	rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+	rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+	rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+	rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+	rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
+	rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
+	rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+	rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
+	rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
+	rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+	rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+	rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+	rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
+	rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
+	rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+	rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+	rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+	rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
+	rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+	rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
+	rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+	rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+	rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
+	rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+	rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+	rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+	rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
+	rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+	rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+	rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
+	rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
+	rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
+	rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
+	rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
+	rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+	rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
+	rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
+	rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
+	rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
+	rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+	rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
+	rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
+	rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+}
+
 static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 {
 	struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
@@ -3889,6 +4282,7 @@
 	/*
 	 * Init RF calibration.
 	 */
+
 	if (rt2x00_rt(rt2x00dev, RT3290) ||
 	    rt2x00_rt(rt2x00dev, RT5390) ||
 	    rt2x00_rt(rt2x00dev, RT5392)) {
@@ -3907,379 +4301,35 @@
 		rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
 	}
 
-	if (rt2x00_rt(rt2x00dev, RT3070) ||
-	    rt2x00_rt(rt2x00dev, RT3071) ||
-	    rt2x00_rt(rt2x00dev, RT3090)) {
-		rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
-		rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-		rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
-	} else if (rt2x00_rt(rt2x00dev, RT3290)) {
-		rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
-		rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
-		rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
-		rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
-		rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-		rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-		rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-		rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-		rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-		rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
-		rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
-		rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-		rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-		rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-		rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
-		rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
-		rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
-		rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-		rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-		rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
-		rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-		rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
-	} else if (rt2x00_rt(rt2x00dev, RT3390)) {
-		rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
-		rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
-		rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
-		rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
-		rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
-		rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
-	} else if (rt2x00_rt(rt2x00dev, RT3572)) {
-		rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
-		rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
-		rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
-		rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
-		rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
-	} else if (rt2800_is_305x_soc(rt2x00dev)) {
-		rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
-		rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
-		rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
-		rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
-		rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-		rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
-		rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+	if (rt2800_is_305x_soc(rt2x00dev)) {
+		rt2800_init_rfcsr_305x_soc(rt2x00dev);
 		return 0;
-	} else if (rt2x00_rt(rt2x00dev, RT3352)) {
-		rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
-		rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
-		rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
-		rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-		rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
-		rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
-		rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
-		rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
-		rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
-		rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
-		rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
-		rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
-		rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
-		rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
-		rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
-		rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
-		rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
-		rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
-		rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
-		rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
-		rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
-		rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
-		rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
-		rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
-		rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
-		rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
-	} else if (rt2x00_rt(rt2x00dev, RT5390)) {
-		rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-		if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-			rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
-		else
-			rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
+	}
 
-		rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-		rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
-		if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-			rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-		else
-			rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-		rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-		rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-		rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-		rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
-		rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-
-		if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-			rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
-		else
-			rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
-		rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-		rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
-		rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
-		rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-		rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-		if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-			rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-		else
-			rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
-		rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-
-		rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
-		if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-			rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
-		else
-			rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
-		rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
-		rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
-		rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
-		rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-		rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
-
-		rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-		if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
-			rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
-		else
-			rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
-		rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
-	} else if (rt2x00_rt(rt2x00dev, RT5392)) {
-		rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
-		rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
-		rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
-		rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
-		rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
-		rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
-		rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
-		rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
-		rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
-		rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
-		rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
-		rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
-		rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
-		rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
-		rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
-		rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
-		rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
-		rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
-		rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
-		rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
-		rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
-		rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
-		rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-		rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
-		rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
-		rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
-		rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
-		rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
-		rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
-		rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
-		rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
-		rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
-		rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-		rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
-		rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
-		rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
-		rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
-		rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
-		rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
-		rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
-		rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
-		rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
-		rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
-		rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
-		rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
-		rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
-		rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+	switch (rt2x00dev->chip.rt) {
+	case RT3070:
+	case RT3071:
+	case RT3090:
+		rt2800_init_rfcsr_30xx(rt2x00dev);
+		break;
+	case RT3290:
+		rt2800_init_rfcsr_3290(rt2x00dev);
+		break;
+	case RT3352:
+		rt2800_init_rfcsr_3352(rt2x00dev);
+		break;
+	case RT3390:
+		rt2800_init_rfcsr_3390(rt2x00dev);
+		break;
+	case RT3572:
+		rt2800_init_rfcsr_3572(rt2x00dev);
+		break;
+	case RT5390:
+		rt2800_init_rfcsr_5390(rt2x00dev);
+		break;
+	case RT5392:
+		rt2800_init_rfcsr_5392(rt2x00dev);
+		break;
 	}
 
 	if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -4620,12 +4670,14 @@
 	mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
 	unsigned int i;
 
 	for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
 		rt2800_efuse_read(rt2x00dev, i);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
 
@@ -4635,11 +4687,14 @@
 	u16 word;
 	u8 *mac;
 	u8 default_lna_gain;
+	int retval;
 
 	/*
 	 * Read the EEPROM.
 	 */
-	rt2800_read_eeprom(rt2x00dev);
+	retval = rt2800_read_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
 
 	/*
 	 * Start validation of the data that has been read.
@@ -5090,8 +5145,7 @@
 	    IEEE80211_HW_SUPPORTS_PS |
 	    IEEE80211_HW_PS_NULLFUNC_STACK |
 	    IEEE80211_HW_AMPDU_AGGREGATION |
-	    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-	    IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL;
+	    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 
 	/*
 	 * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
@@ -5484,7 +5538,9 @@
 	case IEEE80211_AMPDU_TX_START:
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index a128cea..6ec7394 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -43,7 +43,7 @@
 			    const unsigned int offset,
 			    const struct rt2x00_field32 field, u32 *reg);
 
-	void (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
+	int (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
 	bool (*hwcrypt_disabled)(struct rt2x00_dev *rt2x00dev);
 
 	int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
@@ -117,11 +117,11 @@
 	return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
 }
 
-static inline void rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
 	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
 
-	rt2800ops->read_eeprom(rt2x00dev);
+	return rt2800ops->read_eeprom(rt2x00dev);
 }
 
 static inline bool rt2800_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
@@ -207,7 +207,7 @@
 void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
 
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 9224d87..48a01aa 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -90,17 +90,22 @@
 }
 
 #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
-static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
 	void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
 
+	if (!base_addr)
+		return -ENOMEM;
+
 	memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
 
 	iounmap(base_addr);
+	return 0;
 }
 #else
-static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
+	return -ENOMEM;
 }
 #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
 
@@ -135,7 +140,7 @@
 	rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
 }
 
-static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
 {
 	struct eeprom_93cx6 eeprom;
 	u32 reg;
@@ -164,6 +169,8 @@
 
 	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
 			       EEPROM_SIZE / sizeof(u16));
+
+	return 0;
 }
 
 static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
@@ -171,13 +178,14 @@
 	return rt2800_efuse_detect(rt2x00dev);
 }
 
-static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
-	rt2800_read_eeprom_efuse(rt2x00dev);
+	return rt2800_read_eeprom_efuse(rt2x00dev);
 }
 #else
-static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
 {
+	return -EOPNOTSUPP;
 }
 
 static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
@@ -185,8 +193,9 @@
 	return 0;
 }
 
-static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 {
+	return -EOPNOTSUPP;
 }
 #endif /* CONFIG_PCI */
 
@@ -970,14 +979,18 @@
 /*
  * Device probe functions.
  */
-static void rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
+	int retval;
+
 	if (rt2x00_is_soc(rt2x00dev))
-		rt2800pci_read_eeprom_soc(rt2x00dev);
+		retval = rt2800pci_read_eeprom_soc(rt2x00dev);
 	else if (rt2800pci_efuse_detect(rt2x00dev))
-		rt2800pci_read_eeprom_efuse(rt2x00dev);
+		retval = rt2800pci_read_eeprom_efuse(rt2x00dev);
 	else
-		rt2800pci_read_eeprom_pci(rt2x00dev);
+		retval = rt2800pci_read_eeprom_pci(rt2x00dev);
+
+	return retval;
 }
 
 static const struct ieee80211_ops rt2800pci_mac80211_ops = {
@@ -1139,6 +1152,7 @@
 	{ PCI_DEVICE(0x1814, 0x3562) },
 	{ PCI_DEVICE(0x1814, 0x3592) },
 	{ PCI_DEVICE(0x1814, 0x3593) },
+	{ PCI_DEVICE(0x1814, 0x359f) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT53XX
 	{ PCI_DEVICE(0x1814, 0x5360) },
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5c149b5..098613e 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -540,9 +540,9 @@
 	tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
 
 	if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
-		WARNING(entry->queue->rt2x00dev,
-			"TX status report missed for queue %d entry %d\n",
-			entry->queue->qid, entry->entry_idx);
+		DEBUG(entry->queue->rt2x00dev,
+		      "TX status report missed for queue %d entry %d\n",
+		      entry->queue->qid, entry->entry_idx);
 		return TXDONE_UNKNOWN;
 	}
 
@@ -735,13 +735,17 @@
 /*
  * Device probe functions.
  */
-static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
 {
+	int retval;
+
 	if (rt2800_efuse_detect(rt2x00dev))
-		rt2800_read_eeprom_efuse(rt2x00dev);
+		retval = rt2800_read_eeprom_efuse(rt2x00dev);
 	else
-		rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
-				      EEPROM_SIZE);
+		retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
+					       EEPROM_SIZE);
+
+	return retval;
 }
 
 static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -964,6 +968,7 @@
 	{ USB_DEVICE(0x07d1, 0x3c13) },
 	{ USB_DEVICE(0x07d1, 0x3c15) },
 	{ USB_DEVICE(0x07d1, 0x3c16) },
+	{ USB_DEVICE(0x07d1, 0x3c17) },
 	{ USB_DEVICE(0x2001, 0x3c1b) },
 	/* Draytek */
 	{ USB_DEVICE(0x07fa, 0x7712) },
@@ -1094,9 +1099,11 @@
 	{ USB_DEVICE(0x15a9, 0x0006) },
 	/* Sweex */
 	{ USB_DEVICE(0x177f, 0x0153) },
+	{ USB_DEVICE(0x177f, 0x0164) },
 	{ USB_DEVICE(0x177f, 0x0302) },
 	{ USB_DEVICE(0x177f, 0x0313) },
 	{ USB_DEVICE(0x177f, 0x0323) },
+	{ USB_DEVICE(0x177f, 0x0324) },
 	/* U-Media */
 	{ USB_DEVICE(0x157e, 0x300e) },
 	{ USB_DEVICE(0x157e, 0x3013) },
@@ -1111,6 +1118,7 @@
 	/* Zyxel */
 	{ USB_DEVICE(0x0586, 0x3416) },
 	{ USB_DEVICE(0x0586, 0x3418) },
+	{ USB_DEVICE(0x0586, 0x341a) },
 	{ USB_DEVICE(0x0586, 0x341e) },
 	{ USB_DEVICE(0x0586, 0x343e) },
 #ifdef CONFIG_RT2800USB_RT33XX
@@ -1127,6 +1135,9 @@
 	{ USB_DEVICE(0x148f, 0x8070) },
 	/* Sitecom */
 	{ USB_DEVICE(0x0df6, 0x0050) },
+	/* Sweex */
+	{ USB_DEVICE(0x177f, 0x0163) },
+	{ USB_DEVICE(0x177f, 0x0165) },
 #endif
 #ifdef CONFIG_RT2800USB_RT35XX
 	/* Allwin */
@@ -1162,6 +1173,7 @@
 #ifdef CONFIG_RT2800USB_RT53XX
 	/* Arcadyan */
 	{ USB_DEVICE(0x043e, 0x7a12) },
+	{ USB_DEVICE(0x043e, 0x7a32) },
 	/* Azurewave */
 	{ USB_DEVICE(0x13d3, 0x3329) },
 	{ USB_DEVICE(0x13d3, 0x3365) },
@@ -1173,16 +1185,20 @@
 	{ USB_DEVICE(0x2001, 0x3c1e) },
 	/* LG innotek */
 	{ USB_DEVICE(0x043e, 0x7a22) },
+	{ USB_DEVICE(0x043e, 0x7a42) },
 	/* Panasonic */
 	{ USB_DEVICE(0x04da, 0x1801) },
 	{ USB_DEVICE(0x04da, 0x1800) },
+	{ USB_DEVICE(0x04da, 0x23f6) },
 	/* Philips */
 	{ USB_DEVICE(0x0471, 0x2104) },
+	{ USB_DEVICE(0x0471, 0x2126) },
+	{ USB_DEVICE(0x0471, 0x2180) },
+	{ USB_DEVICE(0x0471, 0x2181) },
+	{ USB_DEVICE(0x0471, 0x2182) },
 	/* Ralink */
 	{ USB_DEVICE(0x148f, 0x5370) },
 	{ USB_DEVICE(0x148f, 0x5372) },
-	/* Unknown */
-	{ USB_DEVICE(0x04da, 0x23f6) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
 	/*
@@ -1203,10 +1219,15 @@
 	{ USB_DEVICE(0x0b05, 0x1760) },
 	{ USB_DEVICE(0x0b05, 0x1761) },
 	{ USB_DEVICE(0x0b05, 0x1790) },
+	{ USB_DEVICE(0x0b05, 0x17a7) },
 	/* AzureWave */
 	{ USB_DEVICE(0x13d3, 0x3262) },
 	{ USB_DEVICE(0x13d3, 0x3284) },
 	{ USB_DEVICE(0x13d3, 0x3322) },
+	{ USB_DEVICE(0x13d3, 0x3340) },
+	{ USB_DEVICE(0x13d3, 0x3399) },
+	{ USB_DEVICE(0x13d3, 0x3400) },
+	{ USB_DEVICE(0x13d3, 0x3401) },
 	/* Belkin */
 	{ USB_DEVICE(0x050d, 0x1003) },
 	/* Buffalo */
@@ -1219,13 +1240,17 @@
 	{ USB_DEVICE(0x18c5, 0x0008) },
 	/* D-Link */
 	{ USB_DEVICE(0x07d1, 0x3c0b) },
-	{ USB_DEVICE(0x07d1, 0x3c17) },
 	/* Encore */
 	{ USB_DEVICE(0x203d, 0x14a1) },
+	/* EnGenius */
+	{ USB_DEVICE(0x1740, 0x0600) },
+	{ USB_DEVICE(0x1740, 0x0602) },
 	/* Gemtek */
 	{ USB_DEVICE(0x15a9, 0x0010) },
 	/* Gigabyte */
 	{ USB_DEVICE(0x1044, 0x800c) },
+	/* Hercules */
+	{ USB_DEVICE(0x06f8, 0xe036) },
 	/* Huawei */
 	{ USB_DEVICE(0x148f, 0xf101) },
 	/* I-O DATA */
@@ -1252,13 +1277,17 @@
 	{ USB_DEVICE(0x0df6, 0x004a) },
 	{ USB_DEVICE(0x0df6, 0x004d) },
 	{ USB_DEVICE(0x0df6, 0x0053) },
+	{ USB_DEVICE(0x0df6, 0x0069) },
+	{ USB_DEVICE(0x0df6, 0x006f) },
 	/* SMC */
 	{ USB_DEVICE(0x083a, 0xa512) },
 	{ USB_DEVICE(0x083a, 0xc522) },
 	{ USB_DEVICE(0x083a, 0xd522) },
 	{ USB_DEVICE(0x083a, 0xf511) },
-	/* Zyxel */
-	{ USB_DEVICE(0x0586, 0x341a) },
+	/* Sweex */
+	{ USB_DEVICE(0x177f, 0x0254) },
+	/* TP-LINK */
+	{ USB_DEVICE(0xf201, 0x5370) },
 #endif
 	{ 0, }
 };
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0751b35..086abb4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -88,11 +88,9 @@
 #define ERROR_PROBE(__msg, __args...) \
 	DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args)
 #define WARNING(__dev, __msg, __args...) \
-	DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args)
-#define NOTICE(__dev, __msg, __args...) \
-	DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args)
+	DEBUG_PRINTK_MSG(__dev, KERN_WARNING, "Warning", __msg, ##__args)
 #define INFO(__dev, __msg, __args...) \
-	DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args)
+	DEBUG_PRINTK_MSG(__dev, KERN_INFO, "Info", __msg, ##__args)
 #define DEBUG(__dev, __msg, __args...) \
 	DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args)
 #define EEPROM(__dev, __msg, __args...) \
@@ -1016,6 +1014,26 @@
 	 * Protect the interrupt mask register.
 	 */
 	spinlock_t irqmask_lock;
+
+	/*
+	 * List of BlockAckReq TX entries that need driver BlockAck processing.
+	 */
+	struct list_head bar_list;
+	spinlock_t bar_list_lock;
+};
+
+struct rt2x00_bar_list_entry {
+	struct list_head list;
+	struct rcu_head head;
+
+	struct queue_entry *entry;
+	int block_acked;
+
+	/* Relevant parts of the IEEE80211 BAR header */
+	__u8 ra[6];
+	__u8 ta[6];
+	__le16 control;
+	__le16 start_seq_num;
 };
 
 /*
@@ -1151,8 +1169,10 @@
 /**
  * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
  * @entry: Pointer to &struct queue_entry
+ *
+ * Returns -ENOMEM if mapping fail, 0 otherwise.
  */
-void rt2x00queue_map_txskb(struct queue_entry *entry);
+int rt2x00queue_map_txskb(struct queue_entry *entry);
 
 /**
  * rt2x00queue_unmap_skb - Unmap a skb from DMA.
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 44f8b3f..1031db6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -271,6 +271,50 @@
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
 
+static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct ieee80211_bar *bar = (void *) entry->skb->data;
+	struct rt2x00_bar_list_entry *bar_entry;
+	int ret;
+
+	if (likely(!ieee80211_is_back_req(bar->frame_control)))
+		return 0;
+
+	/*
+	 * Unlike all other frames, the status report for BARs does
+	 * not directly come from the hardware as it is incapable of
+	 * matching a BA to a previously send BAR. The hardware will
+	 * report all BARs as if they weren't acked at all.
+	 *
+	 * Instead the RX-path will scan for incoming BAs and set the
+	 * block_acked flag if it sees one that was likely caused by
+	 * a BAR from us.
+	 *
+	 * Remove remaining BARs here and return their status for
+	 * TX done processing.
+	 */
+	ret = 0;
+	rcu_read_lock();
+	list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) {
+		if (bar_entry->entry != entry)
+			continue;
+
+		spin_lock_bh(&rt2x00dev->bar_list_lock);
+		/* Return whether this BAR was blockacked or not */
+		ret = bar_entry->block_acked;
+		/* Remove the BAR from our checklist */
+		list_del_rcu(&bar_entry->list);
+		spin_unlock_bh(&rt2x00dev->bar_list_lock);
+		kfree_rcu(bar_entry, head);
+
+		break;
+	}
+	rcu_read_unlock();
+
+	return ret;
+}
+
 void rt2x00lib_txdone(struct queue_entry *entry,
 		      struct txdone_entry_desc *txdesc)
 {
@@ -324,9 +368,12 @@
 	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
 
 	/*
-	 * Determine if the frame has been successfully transmitted.
+	 * Determine if the frame has been successfully transmitted and
+	 * remove BARs from our check list while checking for their
+	 * TX status.
 	 */
 	success =
+	    rt2x00lib_txdone_bar_status(entry) ||
 	    test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
 	    test_bit(TXDONE_UNKNOWN, &txdesc->flags);
 
@@ -491,6 +538,50 @@
 				 IEEE80211_CONF_CHANGE_PS);
 }
 
+static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
+				      struct sk_buff *skb,
+				      struct rxdone_entry_desc *rxdesc)
+{
+	struct rt2x00_bar_list_entry *entry;
+	struct ieee80211_bar *ba = (void *)skb->data;
+
+	if (likely(!ieee80211_is_back(ba->frame_control)))
+		return;
+
+	if (rxdesc->size < sizeof(*ba) + FCS_LEN)
+		return;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) {
+
+		if (ba->start_seq_num != entry->start_seq_num)
+			continue;
+
+#define TID_CHECK(a, b) (						\
+	((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) ==	\
+	((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)))		\
+
+		if (!TID_CHECK(ba->control, entry->control))
+			continue;
+
+#undef TID_CHECK
+
+		if (compare_ether_addr(ba->ra, entry->ta))
+			continue;
+
+		if (compare_ether_addr(ba->ta, entry->ra))
+			continue;
+
+		/* Mark BAR since we received the according BA */
+		spin_lock_bh(&rt2x00dev->bar_list_lock);
+		entry->block_acked = 1;
+		spin_unlock_bh(&rt2x00dev->bar_list_lock);
+		break;
+	}
+	rcu_read_unlock();
+
+}
+
 static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
 				      struct sk_buff *skb,
 				      struct rxdone_entry_desc *rxdesc)
@@ -674,6 +765,12 @@
 	rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);
 
 	/*
+	 * Check for incoming BlockAcks to match to the BlockAckReqs
+	 * we've send out.
+	 */
+	rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc);
+
+	/*
 	 * Update extra components
 	 */
 	rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
@@ -1139,7 +1236,8 @@
 	 */
 	if_limit = &rt2x00dev->if_limits_ap;
 	if_limit->max = rt2x00dev->ops->max_ap_intf;
-	if_limit->types = BIT(NL80211_IFTYPE_AP);
+	if_limit->types = BIT(NL80211_IFTYPE_AP) |
+			BIT(NL80211_IFTYPE_MESH_POINT);
 
 	/*
 	 * Build up AP interface combinations structure.
@@ -1183,6 +1281,8 @@
 
 	spin_lock_init(&rt2x00dev->irqmask_lock);
 	mutex_init(&rt2x00dev->csr_mutex);
+	INIT_LIST_HEAD(&rt2x00dev->bar_list);
+	spin_lock_init(&rt2x00dev->bar_list_lock);
 
 	set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
 
@@ -1347,7 +1447,7 @@
 #ifdef CONFIG_PM
 int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
 {
-	NOTICE(rt2x00dev, "Going to sleep.\n");
+	DEBUG(rt2x00dev, "Going to sleep.\n");
 
 	/*
 	 * Prevent mac80211 from accessing driver while suspended.
@@ -1387,7 +1487,7 @@
 
 int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
 {
-	NOTICE(rt2x00dev, "Waking up.\n");
+	DEBUG(rt2x00dev, "Waking up.\n");
 
 	/*
 	 * Restore/enable extra components.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index ed7a1bb..20c6ecc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -731,9 +731,9 @@
 	queue->aifs = params->aifs;
 	queue->txop = params->txop;
 
-	INFO(rt2x00dev,
-	     "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
-	     queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
+	DEBUG(rt2x00dev,
+	      "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
+	      queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index e488b94..4d91795 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -87,24 +87,35 @@
 	skbdesc->entry = entry;
 
 	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) {
-		skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
-						  skb->data,
-						  skb->len,
-						  DMA_FROM_DEVICE);
+		dma_addr_t skb_dma;
+
+		skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
+					 DMA_FROM_DEVICE);
+		if (unlikely(dma_mapping_error(rt2x00dev->dev, skb_dma))) {
+			dev_kfree_skb_any(skb);
+			return NULL;
+		}
+
+		skbdesc->skb_dma = skb_dma;
 		skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
 	}
 
 	return skb;
 }
 
-void rt2x00queue_map_txskb(struct queue_entry *entry)
+int rt2x00queue_map_txskb(struct queue_entry *entry)
 {
 	struct device *dev = entry->queue->rt2x00dev->dev;
 	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
 
 	skbdesc->skb_dma =
 	    dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
+
+	if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma)))
+		return -ENOMEM;
+
 	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
 
@@ -343,10 +354,7 @@
 		 * when using more then one tx stream (>MCS7).
 		 */
 		if (sta && txdesc->u.ht.mcs > 7 &&
-		    ((sta->ht_cap.cap &
-		      IEEE80211_HT_CAP_SM_PS) >>
-		     IEEE80211_HT_CAP_SM_PS_SHIFT) ==
-		    WLAN_HT_CAP_SM_PS_DYNAMIC)
+		    sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
 			__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
 	} else {
 		txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
@@ -545,8 +553,9 @@
 	/*
 	 * Map the skb to DMA.
 	 */
-	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
-		rt2x00queue_map_txskb(entry);
+	if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) &&
+	    rt2x00queue_map_txskb(entry))
+		return -ENOMEM;
 
 	return 0;
 }
@@ -582,6 +591,48 @@
 		queue->rt2x00dev->ops->lib->kick_queue(queue);
 }
 
+static void rt2x00queue_bar_check(struct queue_entry *entry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+	struct ieee80211_bar *bar = (void *) (entry->skb->data +
+				    rt2x00dev->ops->extra_tx_headroom);
+	struct rt2x00_bar_list_entry *bar_entry;
+
+	if (likely(!ieee80211_is_back_req(bar->frame_control)))
+		return;
+
+	bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC);
+
+	/*
+	 * If the alloc fails we still send the BAR out but just don't track
+	 * it in our bar list. And as a result we will report it to mac80211
+	 * back as failed.
+	 */
+	if (!bar_entry)
+		return;
+
+	bar_entry->entry = entry;
+	bar_entry->block_acked = 0;
+
+	/*
+	 * Copy the relevant parts of the 802.11 BAR into out check list
+	 * such that we can use RCU for less-overhead in the RX path since
+	 * sending BARs and processing the according BlockAck should be
+	 * the exception.
+	 */
+	memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra));
+	memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta));
+	bar_entry->control = bar->control;
+	bar_entry->start_seq_num = bar->start_seq_num;
+
+	/*
+	 * Insert BAR into our BAR check list.
+	 */
+	spin_lock_bh(&rt2x00dev->bar_list_lock);
+	list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list);
+	spin_unlock_bh(&rt2x00dev->bar_list_lock);
+}
+
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 			       bool local)
 {
@@ -680,6 +731,11 @@
 		goto out;
 	}
 
+	/*
+	 * Put BlockAckReqs into our check list for driver BA processing.
+	 */
+	rt2x00queue_bar_check(entry);
+
 	set_bit(ENTRY_DATA_PENDING, &entry->flags);
 
 	rt2x00queue_index_inc(entry, Q_INDEX);
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index b80bc46..b6aa0c4 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -1,8 +1,26 @@
+config RTLWIFI
+	tristate "Realtek wireless card support"
+	depends on MAC80211
+	select FW_LOADER
+	---help---
+	  This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE
+	  drivers.  This module does nothing by itself - the various front-end
+	  drivers need to be enabled to support any desired devices.
+
+	  If you choose to build as a module, it'll be called rtlwifi.
+
+config RTLWIFI_DEBUG
+	bool "Debugging output for rtlwifi driver family"
+	depends on RTLWIFI
+	default y
+	---help---
+	To use the module option that sets the dynamic-debugging level for,
+	the front-end driver, this parameter must be "Y". For memory-limited
+	systems, choose "N". If in doubt, choose "Y".
+
 config RTL8192CE
 	tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter"
-	depends on MAC80211 && PCI
-	select FW_LOADER
-	select RTLWIFI
+	depends on RTLWIFI && PCI
 	select RTL8192C_COMMON
 	---help---
 	This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
@@ -12,9 +30,7 @@
 
 config RTL8192SE
 	tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
-	depends on MAC80211 && PCI
-	select FW_LOADER
-	select RTLWIFI
+	depends on RTLWIFI && PCI
 	---help---
 	This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
 	wireless network adapters.
@@ -23,9 +39,7 @@
 
 config RTL8192DE
 	tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter"
-	depends on MAC80211 && PCI
-	select FW_LOADER
-	select RTLWIFI
+	depends on RTLWIFI && PCI
 	---help---
 	This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe
 	wireless network adapters.
@@ -34,9 +48,7 @@
 
 config RTL8723AE
 	tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
-	depends on MAC80211 && PCI && EXPERIMENTAL
-	select FW_LOADER
-	select RTLWIFI
+	depends on RTLWIFI && PCI
 	---help---
 	This is the driver for Realtek RTL8723AE 802.11n PCIe
 	wireless network adapters.
@@ -45,9 +57,7 @@
 
 config RTL8192CU
 	tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
-	depends on MAC80211 && USB
-	select FW_LOADER
-	select RTLWIFI
+	depends on RTLWIFI && USB
 	select RTL8192C_COMMON
 	---help---
 	This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB
@@ -55,16 +65,6 @@
 
 	If you choose to build it as a module, it will be called rtl8192cu
 
-config RTLWIFI
-	tristate
-	depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE
-	default m
-
-config RTLWIFI_DEBUG
-	bool "Additional debugging output"
-	depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE
-	default y
-
 config RTL8192C_COMMON
 	tristate
 	depends on RTL8192CE || RTL8192CU
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 0f8b051..99c5cea 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -523,8 +523,8 @@
 	if (mac->opmode == NL80211_IFTYPE_STATION)
 		bw_40 = mac->bw_40;
 	else if (mac->opmode == NL80211_IFTYPE_AP ||
-		mac->opmode == NL80211_IFTYPE_ADHOC)
-		bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		 mac->opmode == NL80211_IFTYPE_ADHOC)
+		bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 
 	if (bw_40 && sgi_40)
 		tcb_desc->use_shortgi = true;
@@ -634,8 +634,7 @@
 		return;
 	if (mac->opmode == NL80211_IFTYPE_AP ||
 	    mac->opmode == NL80211_IFTYPE_ADHOC) {
-		if (!(sta->ht_cap.ht_supported) ||
-		    !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+		if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
 			return;
 	} else if (mac->opmode == NL80211_IFTYPE_STATION) {
 		if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index be33aa1..d3ce9fb 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -879,7 +879,9 @@
 			 "IEEE80211_AMPDU_TX_START: TID:%d\n", tid);
 		return rtl_tx_agg_start(hw, sta, tid, ssn);
 		break;
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
 		return rtl_tx_agg_stop(hw, sta, tid);
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
index c1e065f..f9f059d 100644
--- a/drivers/net/wireless/rtlwifi/rc.c
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -116,9 +116,8 @@
 		if (txrc->short_preamble)
 			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
 		if (mac->opmode == NL80211_IFTYPE_AP ||
-			mac->opmode == NL80211_IFTYPE_ADHOC) {
-			if (sta && (sta->ht_cap.cap &
-			    IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+		    mac->opmode == NL80211_IFTYPE_ADHOC) {
+			if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40))
 				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
 		} else {
 			if (mac->bw_40)
@@ -223,13 +222,6 @@
 {
 }
 
-static void rtl_rate_update(void *ppriv,
-			    struct ieee80211_supported_band *sband,
-			    struct ieee80211_sta *sta, void *priv_sta,
-			    u32 changed)
-{
-}
-
 static void *rtl_rate_alloc(struct ieee80211_hw *hw,
 		struct dentry *debugfsdir)
 {
@@ -275,7 +267,6 @@
 	.alloc_sta = rtl_rate_alloc_sta,
 	.free_sta = rtl_rate_free_sta,
 	.rate_init = rtl_rate_init,
-	.rate_update = rtl_rate_update,
 	.tx_status = rtl_tx_status,
 	.get_rate = rtl_get_rate,
 };
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index c1608cd..d7d0d49 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -158,8 +158,6 @@
 	const struct ieee80211_reg_rule *reg_rule;
 	struct ieee80211_channel *ch;
 	unsigned int i;
-	u32 bandwidth = 0;
-	int r;
 
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
@@ -174,9 +172,8 @@
 			    (ch->flags & IEEE80211_CHAN_RADAR))
 				continue;
 			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-				r = freq_reg_info(wiphy, ch->center_freq,
-						  bandwidth, &reg_rule);
-				if (r)
+				reg_rule = freq_reg_info(wiphy, ch->center_freq);
+				if (IS_ERR(reg_rule))
 					continue;
 
 				/*
@@ -211,8 +208,6 @@
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *ch;
 	const struct ieee80211_reg_rule *reg_rule;
-	u32 bandwidth = 0;
-	int r;
 
 	if (!wiphy->bands[IEEE80211_BAND_2GHZ])
 		return;
@@ -240,16 +235,16 @@
 	 */
 
 	ch = &sband->channels[11];	/* CH 12 */
-	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-	if (!r) {
+	reg_rule = freq_reg_info(wiphy, ch->center_freq);
+	if (!IS_ERR(reg_rule)) {
 		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
 			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
 				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
 	}
 
 	ch = &sband->channels[12];	/* CH 13 */
-	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
-	if (!r) {
+	reg_rule = freq_reg_info(wiphy, ch->center_freq);
+	if (!IS_ERR(reg_rule)) {
 		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
 			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
 				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -303,9 +298,9 @@
 	return;
 }
 
-static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
-				   struct regulatory_request *request,
-				   struct rtl_regulatory *reg)
+static void _rtl_reg_notifier_apply(struct wiphy *wiphy,
+				    struct regulatory_request *request,
+				    struct rtl_regulatory *reg)
 {
 	/* We always apply this */
 	_rtl_reg_apply_radar_flags(wiphy);
@@ -319,8 +314,6 @@
 		_rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
 		break;
 	}
-
-	return 0;
 }
 
 static const struct ieee80211_regdomain *_rtl_regdomain_select(
@@ -353,9 +346,9 @@
 
 static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
 				struct wiphy *wiphy,
-				int (*reg_notifier) (struct wiphy *wiphy,
-						     struct regulatory_request *
-						     request))
+				void (*reg_notifier) (struct wiphy *wiphy,
+						      struct regulatory_request *
+						      request))
 {
 	const struct ieee80211_regdomain *regd;
 
@@ -384,7 +377,7 @@
 }
 
 int rtl_regd_init(struct ieee80211_hw *hw,
-		  int (*reg_notifier) (struct wiphy *wiphy,
+		  void (*reg_notifier) (struct wiphy *wiphy,
 				       struct regulatory_request *request))
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -426,12 +419,12 @@
 	return 0;
 }
 
-int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 {
 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, "\n");
 
-	return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
+	_rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
 }
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 70ef2f4..4e1f4f00 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -55,7 +55,7 @@
 };
 
 int rtl_regd_init(struct ieee80211_hw *hw,
-		  int (*reg_notifier) (struct wiphy *wiphy,
-				       struct regulatory_request *request));
-int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+		  void (*reg_notifier) (struct wiphy *wiphy,
+					struct regulatory_request *request));
+void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index 1cdf5a2..b793a65 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -669,7 +669,8 @@
 	u8 thermalvalue, delta, delta_lck, delta_iqk;
 	long ele_a, ele_d, temp_cck, val_x, value32;
 	long val_y, ele_c = 0;
-	u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
+	u8 ofdm_index[2], ofdm_index_old[2], cck_index_old = 0;
+	s8 cck_index = 0;
 	int i;
 	bool is2t = IS_92C_SERIAL(rtlhal->version);
 	s8 txpwr_level[2] = {0, 0};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index d1f34f6..1b65db7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -1846,9 +1846,9 @@
 	struct rtl_sta_info *sta_entry = NULL;
 	u32 ratr_bitmap;
 	u8 ratr_index;
-	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
-				? 1 : 0;
-	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
+	u8 curshortgi_40mhz = curtxbw_40mhz &&
+			      (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 				1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 				1 : 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index c31795e..b9b1a6e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -488,7 +488,7 @@
 	u8 *praddr;
 	__le16 fc;
 	u16 type, c_fc;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 
@@ -626,8 +626,7 @@
 	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 		mac->opmode == NL80211_IFTYPE_ADHOC) {
 		if (sta)
-			bw_40 = sta->ht_cap.cap &
-				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 	}
 
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index 32ff959..85b6bdb1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -1084,7 +1084,7 @@
 	u8 *praddr;
 	__le16 fc;
 	u16 type, cpu_fc;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 	hdr = (struct ieee80211_hdr *)tmp_buf;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index b7e6607..a73a17b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -76,7 +76,7 @@
 				      GFP_KERNEL, hw, rtl_fw_cb);
 
 
-	return 0;
+	return err;
 }
 
 static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw)
@@ -285,6 +285,7 @@
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
 	/* RTL8188CUS-VL */
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
+	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)},
 	/* 8188 Combo for BC4 */
 	{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 
@@ -363,9 +364,15 @@
 
 MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids);
 
+static int rtl8192cu_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	return rtl_usb_probe(intf, id, &rtl92cu_hal_cfg);
+}
+
 static struct usb_driver rtl8192cu_driver = {
 	.name = "rtl8192cu",
-	.probe = rtl_usb_probe,
+	.probe = rtl8192cu_probe,
 	.disconnect = rtl_usb_disconnect,
 	.id_table = rtl8192c_usb_ids,
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index fd8df23..5251fb8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -841,9 +841,9 @@
 	long ele_a = 0, ele_d, temp_cck, val_x, value32;
 	long val_y, ele_c = 0;
 	u8 ofdm_index[2];
-	u8 cck_index = 0;
+	s8 cck_index = 0;
 	u8 ofdm_index_old[2];
-	u8 cck_index_old = 0;
+	s8 cck_index_old = 0;
 	u8 index;
 	int i;
 	bool is2t = IS_92D_SINGLEPHY(rtlhal->version);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index f4051f4..aa5b425 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -1970,8 +1970,7 @@
 	struct rtl_sta_info *sta_entry = NULL;
 	u32 ratr_bitmap;
 	u8 ratr_index;
-	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
-							? 1 : 0;
+	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 							1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index a0fbf28..941080e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -452,7 +452,7 @@
 	u8 *praddr;
 	u16 type, cfc;
 	__le16 fc;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 	hdr = (struct ieee80211_hdr *)tmp_buf;
@@ -574,8 +574,7 @@
 	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 		mac->opmode == NL80211_IFTYPE_ADHOC) {
 		if (sta)
-			bw_40 = sta->ht_cap.cap &
-				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 	}
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index 28526a7..084e777 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -2085,8 +2085,7 @@
 	struct rtl_sta_info *sta_entry = NULL;
 	u32 ratr_bitmap;
 	u8 ratr_index = 0;
-	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
-				? 1 : 0;
+	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 				1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 206561d..7b0a2e7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -480,7 +480,7 @@
 	u8 *praddr;
 	__le16 fc;
 	u16 type, cfc;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
 
@@ -621,8 +621,7 @@
 	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 		mac->opmode == NL80211_IFTYPE_ADHOC) {
 		if (sta)
-			bw_40 = sta->ht_cap.cap &
-				    IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 	}
 
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
index f55b176..35cb8f8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
@@ -252,7 +252,7 @@
 	u16 box_reg = 0, box_extreg = 0;
 	u8 u1tmp;
 	bool isfw_rd = false;
-	bool bwrite_sucess = false;
+	bool bwrite_success = false;
 	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limmit = 100;
 	u8 boxcontent[4], boxextcontent[2];
@@ -291,7 +291,7 @@
 		}
 	}
 
-	while (!bwrite_sucess) {
+	while (!bwrite_success) {
 		wait_writeh2c_limmit--;
 		if (wait_writeh2c_limmit == 0) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -429,7 +429,7 @@
 			break;
 		}
 
-		bwrite_sucess = true;
+		bwrite_success = true;
 
 		rtlhal->last_hmeboxnum = boxnum + 1;
 		if (rtlhal->last_hmeboxnum == 4)
@@ -512,7 +512,6 @@
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring;
 	struct rtl_tx_desc *pdesc;
-	u8 own;
 	unsigned long flags;
 	struct sk_buff *pskb = NULL;
 
@@ -525,7 +524,6 @@
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
 	pdesc = &ring->desc[0];
-	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
 
 	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
index 887d521..68c2834 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
@@ -1433,7 +1433,6 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-	u8 bt_retry_cnt;
 	u8 bt_info_original;
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex] Get bt info by fw!!\n");
@@ -1445,7 +1444,6 @@
 				 "[BTCoex] c2h for btInfo not rcvd yet!!\n");
 	}
 
-	bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt;
 	bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original;
 
 	/* when bt inquiry or page scan, we have to set h2c 0x25
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 0a8c038..9a0c71c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -703,11 +703,9 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	u8 reg_bw_opmode;
-	u32 reg_ratr, reg_prsr;
+	u32 reg_prsr;
 
 	reg_bw_opmode = BW_OPMODE_20MHZ;
-	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
-	    RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
 	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 
 	rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
@@ -1868,8 +1866,7 @@
 	struct rtl_sta_info *sta_entry = NULL;
 	u32 ratr_bitmap;
 	u8 ratr_index;
-	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
-				? 1 : 0;
+	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 				1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
@@ -2030,7 +2027,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+	enum rf_pwrstate e_rfpowerstate_toset;
 	u8 u1tmp;
 	bool actuallyset = false;
 
@@ -2049,8 +2046,6 @@
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 	}
 
-	cur_rfstate = ppsc->rfpwr_state;
-
 	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
 		       rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1)));
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
index 3d8536b..eafbb18 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
@@ -614,17 +614,11 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int i;
-	bool rtstatus = true;
 	u32 *radioa_array_table;
-	u32 *radiob_array_table;
-	u16 radioa_arraylen, radiob_arraylen;
+	u16 radioa_arraylen;
 
 	radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH;
 	radioa_array_table = RTL8723E_RADIOA_1TARRAY;
-	radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH;
-	radiob_array_table = RTL8723E_RADIOB_1TARRAY;
-
-	rtstatus = true;
 
 	switch (rfpath) {
 	case RF90_PATH_A:
@@ -1531,11 +1525,8 @@
 		0x522, 0x550, 0x551, 0x040
 	};
 	const u32 retrycount = 2;
-	u32 bbvalue;
 
 	if (t == 0) {
-		bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
-
 		phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
 		phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
 	}
@@ -1712,8 +1703,7 @@
 	long result[4][8];
 	u8 i, final_candidate;
 	bool patha_ok, pathb_ok;
-	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
-	    reg_ecc, reg_tmp = 0;
+	long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
 	bool is12simular, is13simular, is23simular;
 	bool start_conttx = false, singletone = false;
 	u32 iqk_bb_reg[10] = {
@@ -1780,21 +1770,15 @@
 		reg_e94 = result[i][0];
 		reg_e9c = result[i][1];
 		reg_ea4 = result[i][2];
-		reg_eac = result[i][3];
 		reg_eb4 = result[i][4];
 		reg_ebc = result[i][5];
-		reg_ec4 = result[i][6];
-		reg_ecc = result[i][7];
 	}
 	if (final_candidate != 0xff) {
 		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
 		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
 		reg_ea4 = result[final_candidate][2];
-		reg_eac = result[final_candidate][3];
 		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
 		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
-		reg_ec4 = result[final_candidate][6];
-		reg_ecc = result[final_candidate][7];
 		patha_ok = pathb_ok = true;
 	} else {
 		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index a313be8..ac08129 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -244,10 +244,9 @@
 	struct ieee80211_hdr *hdr;
 	u8 *tmp_buf;
 	u8 *praddr;
-	u8 *psaddr;
 	__le16 fc;
 	u16 type;
-	bool packet_matchbssid, packet_toself, packet_beacon;
+	bool packet_matchbssid, packet_toself, packet_beacon = false;
 
 	tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
 
@@ -255,7 +254,6 @@
 	fc = hdr->frame_control;
 	type = WLAN_FC_GET_TYPE(fc);
 	praddr = hdr->addr1;
-	psaddr = ieee80211_get_SA(hdr);
 
 	packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
 			    (!compare_ether_addr(mac->bssid,
@@ -397,8 +395,7 @@
 	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 		mac->opmode == NL80211_IFTYPE_ADHOC) {
 		if (sta)
-			bw_40 = sta->ht_cap.cap &
-				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
 	}
 
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 1535efd..156b527 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -42,8 +42,12 @@
 
 static void usbctrl_async_callback(struct urb *urb)
 {
-	if (urb)
-		kfree(urb->context);
+	if (urb) {
+		/* free dr */
+		kfree(urb->setup_packet);
+		/* free databuf */
+		kfree(urb->transfer_buffer);
+	}
 }
 
 static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
@@ -55,25 +59,31 @@
 	u8 reqtype;
 	struct usb_ctrlrequest *dr;
 	struct urb *urb;
-	struct rtl819x_async_write_data {
-		u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE];
-		struct usb_ctrlrequest dr;
-	} *buf;
+	const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
+	u8 *databuf;
+
+	if (WARN_ON_ONCE(len > databuf_maxlen))
+		len = databuf_maxlen;
 
 	pipe = usb_sndctrlpipe(udev, 0); /* write_out */
 	reqtype =  REALTEK_USB_VENQT_WRITE;
 
-	buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
-	if (!buf)
+	dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+	if (!dr)
 		return -ENOMEM;
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (!urb) {
-		kfree(buf);
+	databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
+	if (!databuf) {
+		kfree(dr);
 		return -ENOMEM;
 	}
 
-	dr = &buf->dr;
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		kfree(databuf);
+		kfree(dr);
+		return -ENOMEM;
+	}
 
 	dr->bRequestType = reqtype;
 	dr->bRequest = request;
@@ -81,13 +91,15 @@
 	dr->wIndex = cpu_to_le16(index);
 	dr->wLength = cpu_to_le16(len);
 	/* data are already in little-endian order */
-	memcpy(buf, pdata, len);
+	memcpy(databuf, pdata, len);
 	usb_fill_control_urb(urb, udev, pipe,
-			     (unsigned char *)dr, buf, len,
-			     usbctrl_async_callback, buf);
+			     (unsigned char *)dr, databuf, len,
+			     usbctrl_async_callback, NULL);
 	rc = usb_submit_urb(urb, GFP_ATOMIC);
-	if (rc < 0)
-		kfree(buf);
+	if (rc < 0) {
+		kfree(databuf);
+		kfree(dr);
+	}
 	usb_free_urb(urb);
 	return rc;
 }
@@ -825,8 +837,6 @@
 	u32 ep_num;
 	struct urb *_urb = NULL;
 	struct sk_buff *_skb = NULL;
-	struct sk_buff_head *skb_list;
-	struct usb_anchor *urb_list;
 
 	WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl);
 	if (unlikely(IS_USB_STOP(rtlusb))) {
@@ -836,7 +846,6 @@
 		return;
 	}
 	ep_num = rtlusb->ep_map.ep_mapping[qnum];
-	skb_list = &rtlusb->tx_skb_queue[ep_num];
 	_skb = skb;
 	_urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num);
 	if (unlikely(!_urb)) {
@@ -844,7 +853,6 @@
 			 "Can't allocate urb. Drop skb!\n");
 		return;
 	}
-	urb_list = &rtlusb->tx_pending[ep_num];
 	_rtl_submit_tx_urb(hw, _urb);
 }
 
@@ -941,7 +949,8 @@
 };
 
 int rtl_usb_probe(struct usb_interface *intf,
-			const struct usb_device_id *id)
+		  const struct usb_device_id *id,
+		  struct rtl_hal_cfg *rtl_hal_cfg)
 {
 	int err;
 	struct ieee80211_hw *hw = NULL;
@@ -976,7 +985,7 @@
 	usb_set_intfdata(intf, hw);
 	/* init cfg & intf_ops */
 	rtlpriv->rtlhal.interface = INTF_USB;
-	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info);
+	rtlpriv->cfg = rtl_hal_cfg;
 	rtlpriv->intf_ops = &rtl_usb_ops;
 	rtl_dbgp_flag_init(hw);
 	/* Init IO handler */
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h
index 5235136..fb986f9 100644
--- a/drivers/net/wireless/rtlwifi/usb.h
+++ b/drivers/net/wireless/rtlwifi/usb.h
@@ -157,7 +157,8 @@
 
 
 int rtl_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *id);
+		  const struct usb_device_id *id,
+		  struct rtl_hal_cfg *rtl92cu_hal_cfg);
 void rtl_usb_disconnect(struct usb_interface *intf);
 int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message);
 int rtl_usb_resume(struct usb_interface *pusb_intf);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 21a5f4f..f13258a 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1702,7 +1702,7 @@
 
 struct rtl_debug {
 	u32 dbgp_type[DBGP_TYPE_MAX];
-	u32 global_debuglevel;
+	int global_debuglevel;
 	u64 global_debugcomponents;
 
 	/* add for proc debug */
diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig
index be80011..cbe1e7f 100644
--- a/drivers/net/wireless/ti/Kconfig
+++ b/drivers/net/wireless/ti/Kconfig
@@ -12,4 +12,13 @@
 
 # keep last for automatic dependencies
 source "drivers/net/wireless/ti/wlcore/Kconfig"
+
+config WILINK_PLATFORM_DATA
+	bool "TI WiLink platform data"
+	depends on WLCORE_SDIO || WL1251_SDIO
+	default y
+	---help---
+	Small platform data bit needed to pass data to the sdio modules.
+
+
 endif # WL_TI
diff --git a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile
index 4d68239..af14231 100644
--- a/drivers/net/wireless/ti/Makefile
+++ b/drivers/net/wireless/ti/Makefile
@@ -1,5 +1,7 @@
 obj-$(CONFIG_WLCORE)			+= wlcore/
 obj-$(CONFIG_WL12XX)			+= wl12xx/
-obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wlcore/
 obj-$(CONFIG_WL1251)			+= wl1251/
 obj-$(CONFIG_WL18XX)			+= wl18xx/
+
+# small builtin driver bit
+obj-$(CONFIG_WILINK_PLATFORM_DATA)	+= wilink_platform_data.o
diff --git a/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c
similarity index 100%
rename from drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c
rename to drivers/net/wireless/ti/wilink_platform_data.c
diff --git a/drivers/net/wireless/ti/wl1251/Kconfig b/drivers/net/wireless/ti/wl1251/Kconfig
index 1fb6584..8fec4ed 100644
--- a/drivers/net/wireless/ti/wl1251/Kconfig
+++ b/drivers/net/wireless/ti/wl1251/Kconfig
@@ -1,6 +1,6 @@
 menuconfig WL1251
 	tristate "TI wl1251 driver support"
-	depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS
+	depends on MAC80211 && GENERIC_HARDIRQS
 	select FW_LOADER
 	select CRC7
 	---help---
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c
index 5ec50a4..74ae8e1 100644
--- a/drivers/net/wireless/ti/wl1251/event.c
+++ b/drivers/net/wireless/ti/wl1251/event.c
@@ -29,6 +29,8 @@
 static int wl1251_event_scan_complete(struct wl1251 *wl,
 				      struct event_mailbox *mbox)
 {
+	int ret = 0;
+
 	wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
 		     mbox->scheduled_scan_status,
 		     mbox->scheduled_scan_channels);
@@ -37,9 +39,11 @@
 		ieee80211_scan_completed(wl->hw, false);
 		wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
 		wl->scanning = false;
+		if (wl->hw->conf.flags & IEEE80211_CONF_IDLE)
+			ret = wl1251_ps_set_mode(wl, STATION_IDLE);
 	}
 
-	return 0;
+	return ret;
 }
 
 static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index f47e8b0..bbbf68c 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -623,7 +623,7 @@
 		}
 	}
 
-	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+	if (changed & IEEE80211_CONF_CHANGE_IDLE && !wl->scanning) {
 		if (conf->flags & IEEE80211_CONF_IDLE) {
 			ret = wl1251_ps_set_mode(wl, STATION_IDLE);
 			if (ret < 0)
@@ -895,11 +895,21 @@
 	if (ret < 0)
 		goto out;
 
+	if (hw->conf.flags & IEEE80211_CONF_IDLE) {
+		ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+		if (ret < 0)
+			goto out_sleep;
+		ret = wl1251_join(wl, wl->bss_type, wl->channel,
+				  wl->beacon_int, wl->dtim_period);
+		if (ret < 0)
+			goto out_sleep;
+	}
+
 	skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
 				     req->ie_len);
 	if (!skb) {
 		ret = -ENOMEM;
-		goto out;
+		goto out_idle;
 	}
 	if (req->ie_len)
 		memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
@@ -908,11 +918,11 @@
 				      skb->len);
 	dev_kfree_skb(skb);
 	if (ret < 0)
-		goto out_sleep;
+		goto out_idle;
 
 	ret = wl1251_cmd_trigger_scan_to(wl, 0);
 	if (ret < 0)
-		goto out_sleep;
+		goto out_idle;
 
 	wl->scanning = true;
 
@@ -920,9 +930,13 @@
 			      req->n_channels, WL1251_SCAN_NUM_PROBES);
 	if (ret < 0) {
 		wl->scanning = false;
-		goto out_sleep;
+		goto out_idle;
 	}
+	goto out_sleep;
 
+out_idle:
+	if (hw->conf.flags & IEEE80211_CONF_IDLE)
+		ret = wl1251_ps_set_mode(wl, STATION_IDLE);
 out_sleep:
 	wl1251_ps_elp_sleep(wl);
 
diff --git a/drivers/net/wireless/ti/wl1251/ps.c b/drivers/net/wireless/ti/wl1251/ps.c
index db719f7..b9e27b9 100644
--- a/drivers/net/wireless/ti/wl1251/ps.c
+++ b/drivers/net/wireless/ti/wl1251/ps.c
@@ -68,8 +68,7 @@
 	unsigned long timeout, start;
 	u32 elp_reg;
 
-	if (delayed_work_pending(&wl->elp_work))
-		cancel_delayed_work(&wl->elp_work);
+	cancel_delayed_work(&wl->elp_work);
 
 	if (!wl->elp)
 		return 0;
diff --git a/drivers/net/wireless/ti/wl12xx/Makefile b/drivers/net/wireless/ti/wl12xx/Makefile
index da509aa..e6a2405 100644
--- a/drivers/net/wireless/ti/wl12xx/Makefile
+++ b/drivers/net/wireless/ti/wl12xx/Makefile
@@ -1,3 +1,3 @@
-wl12xx-objs	= main.o cmd.o acx.o debugfs.o
+wl12xx-objs	= main.o cmd.o acx.o debugfs.o scan.o event.o
 
 obj-$(CONFIG_WL12XX)		+= wl12xx.o
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c
index 6222062..7dc9f96 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.c
+++ b/drivers/net/wireless/ti/wl12xx/cmd.c
@@ -284,3 +284,40 @@
 	kfree(radio_parms);
 	return ret;
 }
+
+int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
+			      struct ieee80211_channel_switch *ch_switch)
+{
+	struct wl12xx_cmd_channel_switch *cmd;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "cmd channel switch");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->role_id = wlvif->role_id;
+	cmd->channel = ch_switch->channel->hw_value;
+	cmd->switch_time = ch_switch->count;
+	cmd->stop_tx = ch_switch->block_tx;
+
+	/* FIXME: control from mac80211 in the future */
+	/* Enable TX on the target channel */
+	cmd->post_switch_tx_disable = 0;
+
+	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send channel switch command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(cmd);
+
+out:
+	return ret;
+}
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.h b/drivers/net/wireless/ti/wl12xx/cmd.h
index 140a0e8..32cbad5 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.h
+++ b/drivers/net/wireless/ti/wl12xx/cmd.h
@@ -103,10 +103,30 @@
 	u8 padding[3];
 } __packed;
 
+struct wl12xx_cmd_channel_switch {
+	struct wl1271_cmd_header header;
+
+	u8 role_id;
+
+	/* The new serving channel */
+	u8 channel;
+	/* Relative time of the serving channel switch in TBTT units */
+	u8 switch_time;
+	/* Stop the role TX, should expect it after radar detection */
+	u8 stop_tx;
+	/* The target channel tx status 1-stopped 0-open*/
+	u8 post_switch_tx_disable;
+
+	u8 padding[3];
+} __packed;
+
 int wl1271_cmd_general_parms(struct wl1271 *wl);
 int wl128x_cmd_general_parms(struct wl1271 *wl);
 int wl1271_cmd_radio_parms(struct wl1271 *wl);
 int wl128x_cmd_radio_parms(struct wl1271 *wl);
 int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
+int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
+			      struct ieee80211_channel_switch *ch_switch);
 
 #endif /* __WL12XX_CMD_H__ */
diff --git a/drivers/net/wireless/ti/wl12xx/event.c b/drivers/net/wireless/ti/wl12xx/event.c
new file mode 100644
index 0000000..6ac0ed7
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/event.c
@@ -0,0 +1,116 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "event.h"
+#include "scan.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+
+int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+			  bool *timeout)
+{
+	u32 local_event;
+
+	switch (event) {
+	case WLCORE_EVENT_ROLE_STOP_COMPLETE:
+		local_event = ROLE_STOP_COMPLETE_EVENT_ID;
+		break;
+
+	case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
+		local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
+		break;
+
+	default:
+		/* event not implemented */
+		return 0;
+	}
+	return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
+}
+
+int wl12xx_process_mailbox_events(struct wl1271 *wl)
+{
+	struct wl12xx_event_mailbox *mbox = wl->mbox;
+	u32 vector;
+
+
+	vector = le32_to_cpu(mbox->events_vector);
+	vector &= ~(le32_to_cpu(mbox->events_mask));
+
+	wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
+
+	if (vector & SCAN_COMPLETE_EVENT_ID) {
+		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
+			     mbox->scheduled_scan_status);
+
+		if (wl->scan_wlvif)
+			wl12xx_scan_completed(wl, wl->scan_wlvif);
+	}
+
+	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+		wl1271_debug(DEBUG_EVENT,
+			     "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)",
+			     mbox->scheduled_scan_status);
+
+		wlcore_scan_sched_scan_results(wl);
+	}
+
+	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
+		wlcore_event_sched_scan_completed(wl,
+						  mbox->scheduled_scan_status);
+	if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
+		wlcore_event_soft_gemini_sense(wl,
+					       mbox->soft_gemini_sense_info);
+
+	if (vector & BSS_LOSE_EVENT_ID)
+		wlcore_event_beacon_loss(wl, 0xff);
+
+	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
+		wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
+
+	if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
+		wlcore_event_ba_rx_constraint(wl,
+					      BIT(mbox->role_id),
+					      mbox->rx_ba_allowed);
+
+	if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
+		wlcore_event_channel_switch(wl, 0xff,
+					    mbox->channel_switch_status);
+
+	if (vector & DUMMY_PACKET_EVENT_ID)
+		wlcore_event_dummy_packet(wl);
+
+	/*
+	 * "TX retries exceeded" has a different meaning according to mode.
+	 * In AP mode the offending station is disconnected.
+	 */
+	if (vector & MAX_TX_RETRY_EVENT_ID)
+		wlcore_event_max_tx_failure(wl,
+				le16_to_cpu(mbox->sta_tx_retry_exceeded));
+
+	if (vector & INACTIVE_STA_EVENT_ID)
+		wlcore_event_inactive_sta(wl,
+					  le16_to_cpu(mbox->sta_aging_status));
+
+	if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
+		wlcore_event_roc_complete(wl);
+
+	return 0;
+}
diff --git a/drivers/net/wireless/ti/wl12xx/event.h b/drivers/net/wireless/ti/wl12xx/event.h
new file mode 100644
index 0000000..a5cc3fc
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/event.h
@@ -0,0 +1,111 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL12XX_EVENT_H__
+#define __WL12XX_EVENT_H__
+
+#include "../wlcore/wlcore.h"
+
+enum {
+	MEASUREMENT_START_EVENT_ID		 = BIT(8),
+	MEASUREMENT_COMPLETE_EVENT_ID		 = BIT(9),
+	SCAN_COMPLETE_EVENT_ID			 = BIT(10),
+	WFD_DISCOVERY_COMPLETE_EVENT_ID		 = BIT(11),
+	AP_DISCOVERY_COMPLETE_EVENT_ID		 = BIT(12),
+	RESERVED1			         = BIT(13),
+	PSPOLL_DELIVERY_FAILURE_EVENT_ID	 = BIT(14),
+	ROLE_STOP_COMPLETE_EVENT_ID		 = BIT(15),
+	RADAR_DETECTED_EVENT_ID                  = BIT(16),
+	CHANNEL_SWITCH_COMPLETE_EVENT_ID	 = BIT(17),
+	BSS_LOSE_EVENT_ID			 = BIT(18),
+	REGAINED_BSS_EVENT_ID			 = BIT(19),
+	MAX_TX_RETRY_EVENT_ID			 = BIT(20),
+	DUMMY_PACKET_EVENT_ID			 = BIT(21),
+	SOFT_GEMINI_SENSE_EVENT_ID		 = BIT(22),
+	CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID	 = BIT(23),
+	SOFT_GEMINI_AVALANCHE_EVENT_ID		 = BIT(24),
+	PLT_RX_CALIBRATION_COMPLETE_EVENT_ID	 = BIT(25),
+	INACTIVE_STA_EVENT_ID			 = BIT(26),
+	PEER_REMOVE_COMPLETE_EVENT_ID		 = BIT(27),
+	PERIODIC_SCAN_COMPLETE_EVENT_ID		 = BIT(28),
+	PERIODIC_SCAN_REPORT_EVENT_ID		 = BIT(29),
+	BA_SESSION_RX_CONSTRAINT_EVENT_ID	 = BIT(30),
+	REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID	 = BIT(31),
+};
+
+struct wl12xx_event_mailbox {
+	__le32 events_vector;
+	__le32 events_mask;
+	__le32 reserved_1;
+	__le32 reserved_2;
+
+	u8 number_of_scan_results;
+	u8 scan_tag;
+	u8 completed_scan_status;
+	u8 reserved_3;
+
+	u8 soft_gemini_sense_info;
+	u8 soft_gemini_protective_info;
+	s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
+	u8 change_auto_mode_timeout;
+	u8 scheduled_scan_status;
+	u8 reserved4;
+	/* tuned channel (roc) */
+	u8 roc_channel;
+
+	__le16 hlid_removed_bitmap;
+
+	/* bitmap of aged stations (by HLID) */
+	__le16 sta_aging_status;
+
+	/* bitmap of stations (by HLID) which exceeded max tx retries */
+	__le16 sta_tx_retry_exceeded;
+
+	/* discovery completed results */
+	u8 discovery_tag;
+	u8 number_of_preq_results;
+	u8 number_of_prsp_results;
+	u8 reserved_5;
+
+	/* rx ba constraint */
+	u8 role_id; /* 0xFF means any role. */
+	u8 rx_ba_allowed;
+	u8 reserved_6[2];
+
+	/* Channel switch results */
+
+	u8 channel_switch_role_id;
+	u8 channel_switch_status;
+	u8 reserved_7[2];
+
+	u8 ps_poll_delivery_failure_role_ids;
+	u8 stopped_role_ids;
+	u8 started_role_ids;
+
+	u8 reserved_8[9];
+} __packed;
+
+int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+			  bool *timeout);
+int wl12xx_process_mailbox_events(struct wl1271 *wl);
+
+#endif
+
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index e5f5f8f..09694e3 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -38,6 +38,8 @@
 #include "reg.h"
 #include "cmd.h"
 #include "acx.h"
+#include "scan.h"
+#include "event.h"
 #include "debugfs.h"
 
 static char *fref_param;
@@ -208,6 +210,8 @@
 		.tmpl_short_retry_limit      = 10,
 		.tmpl_long_retry_limit       = 10,
 		.tx_watchdog_timeout         = 5000,
+		.slow_link_thold             = 3,
+		.fast_link_thold             = 10,
 	},
 	.conn = {
 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
@@ -265,8 +269,10 @@
 	.scan = {
 		.min_dwell_time_active        = 7500,
 		.max_dwell_time_active        = 30000,
-		.min_dwell_time_passive       = 100000,
-		.max_dwell_time_passive       = 100000,
+		.min_dwell_time_active_long   = 25000,
+		.max_dwell_time_active_long   = 50000,
+		.dwell_time_passive           = 100000,
+		.dwell_time_dfs               = 150000,
 		.num_probe_reqs               = 2,
 		.split_scan_timeout           = 50000,
 	},
@@ -368,6 +374,10 @@
 		.increase_time              = 1,
 		.window_size                = 16,
 	},
+	.recovery = {
+		.bug_on_recovery	    = 0,
+		.no_recovery		    = 0,
+	},
 };
 
 static struct wl12xx_priv_conf wl12xx_default_priv_conf = {
@@ -601,9 +611,9 @@
 {
 	int ret;
 
-	if (wl->chip.id != CHIP_ID_1283_PG20) {
+	if (wl->chip.id != CHIP_ID_128X_PG20) {
 		struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
-		struct wl127x_rx_mem_pool_addr rx_mem_addr;
+		struct wl12xx_priv *priv = wl->priv;
 
 		/*
 		 * Choose the block we want to read
@@ -612,13 +622,13 @@
 		 */
 		u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK;
 
-		rx_mem_addr.addr = (mem_block << 8) +
+		priv->rx_mem_addr->addr = (mem_block << 8) +
 			le32_to_cpu(wl_mem_map->packet_memory_pool_start);
 
-		rx_mem_addr.addr_extra = rx_mem_addr.addr + 4;
+		priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4;
 
-		ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr,
-				   sizeof(rx_mem_addr), false);
+		ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr,
+				   sizeof(*priv->rx_mem_addr), false);
 		if (ret < 0)
 			return ret;
 	}
@@ -631,13 +641,15 @@
 	int ret = 0;
 
 	switch (wl->chip.id) {
-	case CHIP_ID_1271_PG10:
+	case CHIP_ID_127X_PG10:
 		wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
 			       wl->chip.id);
 
 		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
-			      WLCORE_QUIRK_TKIP_HEADER_SPACE;
+			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
+			      WLCORE_QUIRK_START_STA_FAILS |
+			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
 		memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
@@ -646,18 +658,22 @@
 		/* read data preparation is only needed by wl127x */
 		wl->ops->prepare_read = wl127x_prepare_read;
 
-		wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER,
-				      WL127X_MAJOR_VER, WL127X_SUBTYPE_VER,
-				      WL127X_MINOR_VER);
+		wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER,
+			      WL127X_IFTYPE_SR_VER,  WL127X_MAJOR_SR_VER,
+			      WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER,
+			      WL127X_IFTYPE_MR_VER,  WL127X_MAJOR_MR_VER,
+			      WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER);
 		break;
 
-	case CHIP_ID_1271_PG20:
+	case CHIP_ID_127X_PG20:
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
 			     wl->chip.id);
 
 		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
-			      WLCORE_QUIRK_TKIP_HEADER_SPACE;
+			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
+			      WLCORE_QUIRK_START_STA_FAILS |
+			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
 		wl->plt_fw_name = WL127X_PLT_FW_NAME;
 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
@@ -667,12 +683,14 @@
 		/* read data preparation is only needed by wl127x */
 		wl->ops->prepare_read = wl127x_prepare_read;
 
-		wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER,
-				      WL127X_MAJOR_VER, WL127X_SUBTYPE_VER,
-				      WL127X_MINOR_VER);
+		wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER,
+			      WL127X_IFTYPE_SR_VER,  WL127X_MAJOR_SR_VER,
+			      WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER,
+			      WL127X_IFTYPE_MR_VER,  WL127X_MAJOR_MR_VER,
+			      WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER);
 		break;
 
-	case CHIP_ID_1283_PG20:
+	case CHIP_ID_128X_PG20:
 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
 			     wl->chip.id);
 		wl->plt_fw_name = WL128X_PLT_FW_NAME;
@@ -682,19 +700,29 @@
 		/* wl128x requires TX blocksize alignment */
 		wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
-			      WLCORE_QUIRK_TKIP_HEADER_SPACE;
+			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
+			      WLCORE_QUIRK_START_STA_FAILS |
+			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
 
-		wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER,
-				      WL128X_MAJOR_VER, WL128X_SUBTYPE_VER,
-				      WL128X_MINOR_VER);
+		wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER,
+			      WL128X_IFTYPE_SR_VER,  WL128X_MAJOR_SR_VER,
+			      WL128X_SUBTYPE_SR_VER, WL128X_MINOR_SR_VER,
+			      WL128X_IFTYPE_MR_VER,  WL128X_MAJOR_MR_VER,
+			      WL128X_SUBTYPE_MR_VER, WL128X_MINOR_MR_VER);
 		break;
-	case CHIP_ID_1283_PG10:
+	case CHIP_ID_128X_PG10:
 	default:
 		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
 		ret = -ENODEV;
 		goto out;
 	}
 
+	/* common settings */
+	wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY;
+	wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY;
+	wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+	wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+	wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
 out:
 	return ret;
 }
@@ -1067,7 +1095,7 @@
 	u32 clk;
 	int selected_clock = -1;
 
-	if (wl->chip.id == CHIP_ID_1283_PG20) {
+	if (wl->chip.id == CHIP_ID_128X_PG20) {
 		ret = wl128x_boot_clk(wl, &selected_clock);
 		if (ret < 0)
 			goto out;
@@ -1098,7 +1126,7 @@
 
 	wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
 
-	if (wl->chip.id == CHIP_ID_1283_PG20)
+	if (wl->chip.id == CHIP_ID_128X_PG20)
 		clk |= ((selected_clock & 0x3) << 1) << 4;
 	else
 		clk |= (priv->ref_clock << 1) << 4;
@@ -1152,7 +1180,7 @@
 	/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
 	 * to upload_fw) */
 
-	if (wl->chip.id == CHIP_ID_1283_PG20) {
+	if (wl->chip.id == CHIP_ID_128X_PG20) {
 		ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
 		if (ret < 0)
 			goto out;
@@ -1219,6 +1247,23 @@
 	if (ret < 0)
 		goto out;
 
+	wl->event_mask = BSS_LOSE_EVENT_ID |
+		REGAINED_BSS_EVENT_ID |
+		SCAN_COMPLETE_EVENT_ID |
+		ROLE_STOP_COMPLETE_EVENT_ID |
+		RSSI_SNR_TRIGGER_0_EVENT_ID |
+		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
+		SOFT_GEMINI_SENSE_EVENT_ID |
+		PERIODIC_SCAN_REPORT_EVENT_ID |
+		PERIODIC_SCAN_COMPLETE_EVENT_ID |
+		DUMMY_PACKET_EVENT_ID |
+		PEER_REMOVE_COMPLETE_EVENT_ID |
+		BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
+		INACTIVE_STA_EVENT_ID |
+		MAX_TX_RETRY_EVENT_ID |
+		CHANNEL_SWITCH_COMPLETE_EVENT_ID;
+
 	ret = wlcore_boot_run_firmware(wl);
 	if (ret < 0)
 		goto out;
@@ -1261,7 +1306,7 @@
 wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
 			  u32 blks, u32 spare_blks)
 {
-	if (wl->chip.id == CHIP_ID_1283_PG20) {
+	if (wl->chip.id == CHIP_ID_128X_PG20) {
 		desc->wl128x_mem.total_mem_blocks = blks;
 	} else {
 		desc->wl127x_mem.extra_blocks = spare_blks;
@@ -1275,7 +1320,7 @@
 {
 	u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len);
 
-	if (wl->chip.id == CHIP_ID_1283_PG20) {
+	if (wl->chip.id == CHIP_ID_128X_PG20) {
 		desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
 		desc->length = cpu_to_le16(aligned_len >> 2);
 
@@ -1339,7 +1384,7 @@
 {
 	int ret;
 
-	if (wl->chip.id == CHIP_ID_1283_PG20) {
+	if (wl->chip.id == CHIP_ID_128X_PG20) {
 		u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
 
 		ret = wl128x_cmd_general_parms(wl);
@@ -1394,22 +1439,6 @@
 	return wlvif->rate_set;
 }
 
-static int wl12xx_identify_fw(struct wl1271 *wl)
-{
-	unsigned int *fw_ver = wl->chip.fw_ver;
-
-	/* Only new station firmwares support routing fw logs to the host */
-	if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
-	    (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
-		wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
-
-	/* This feature is not yet supported for AP mode */
-	if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
-		wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
-
-	return 0;
-}
-
 static void wl12xx_conf_init(struct wl1271 *wl)
 {
 	struct wl12xx_priv *priv = wl->priv;
@@ -1426,7 +1455,7 @@
 	bool supported = false;
 	u8 major, minor;
 
-	if (wl->chip.id == CHIP_ID_1283_PG20) {
+	if (wl->chip.id == CHIP_ID_128X_PG20) {
 		major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
 		minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
 
@@ -1482,7 +1511,7 @@
 	u16 die_info;
 	int ret;
 
-	if (wl->chip.id == CHIP_ID_1283_PG20)
+	if (wl->chip.id == CHIP_ID_128X_PG20)
 		ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1,
 					  &die_info);
 	else
@@ -1589,16 +1618,46 @@
 	return wlcore_set_key(wl, cmd, vif, sta, key_conf);
 }
 
+static int wl12xx_set_peer_cap(struct wl1271 *wl,
+			       struct ieee80211_sta_ht_cap *ht_cap,
+			       bool allow_ht_operation,
+			       u32 rate_set, u8 hlid)
+{
+	return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
+					      hlid);
+}
+
+static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+				 struct wl1271_link *lnk)
+{
+	u8 thold;
+
+	if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
+		thold = wl->conf.tx.fast_link_thold;
+	else
+		thold = wl->conf.tx.slow_link_thold;
+
+	return lnk->allocated_pkts < thold;
+}
+
+static bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+				struct wl1271_link *lnk)
+{
+	/* any link is good for low priority */
+	return true;
+}
+
 static int wl12xx_setup(struct wl1271 *wl);
 
 static struct wlcore_ops wl12xx_ops = {
 	.setup			= wl12xx_setup,
 	.identify_chip		= wl12xx_identify_chip,
-	.identify_fw		= wl12xx_identify_fw,
 	.boot			= wl12xx_boot,
 	.plt_init		= wl12xx_plt_init,
 	.trigger_cmd		= wl12xx_trigger_cmd,
 	.ack_event		= wl12xx_ack_event,
+	.wait_for_event		= wl12xx_wait_for_event,
+	.process_mailbox_events	= wl12xx_process_mailbox_events,
 	.calc_tx_blocks		= wl12xx_calc_tx_blocks,
 	.set_tx_desc_blocks	= wl12xx_set_tx_desc_blocks,
 	.set_tx_desc_data_len	= wl12xx_set_tx_desc_data_len,
@@ -1615,9 +1674,17 @@
 	.set_rx_csum		= NULL,
 	.ap_get_mimo_wide_rate_mask = NULL,
 	.debugfs_init		= wl12xx_debugfs_add_files,
+	.scan_start		= wl12xx_scan_start,
+	.scan_stop		= wl12xx_scan_stop,
+	.sched_scan_start	= wl12xx_sched_scan_start,
+	.sched_scan_stop	= wl12xx_scan_sched_scan_stop,
 	.get_spare_blocks	= wl12xx_get_spare_blocks,
 	.set_key		= wl12xx_set_key,
+	.channel_switch		= wl12xx_cmd_channel_switch,
 	.pre_pkt_send		= NULL,
+	.set_peer_cap		= wl12xx_set_peer_cap,
+	.lnk_high_prio		= wl12xx_lnk_high_prio,
+	.lnk_low_prio		= wl12xx_lnk_low_prio,
 };
 
 static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
@@ -1636,11 +1703,13 @@
 static int wl12xx_setup(struct wl1271 *wl)
 {
 	struct wl12xx_priv *priv = wl->priv;
-	struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data;
+	struct wlcore_platdev_data *pdev_data = wl->pdev->dev.platform_data;
+	struct wl12xx_platform_data *pdata = pdev_data->pdata;
 
 	wl->rtable = wl12xx_rtable;
 	wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
 	wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
+	wl->num_channels = 1;
 	wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
 	wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
 	wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
@@ -1693,6 +1762,10 @@
 			wl1271_error("Invalid tcxo parameter %s", tcxo_param);
 	}
 
+	priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL);
+	if (!priv->rx_mem_addr)
+		return -ENOMEM;
+
 	return 0;
 }
 
@@ -1703,7 +1776,8 @@
 	int ret;
 
 	hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv),
-			     WL12XX_AGGR_BUFFER_SIZE);
+			     WL12XX_AGGR_BUFFER_SIZE,
+			     sizeof(struct wl12xx_event_mailbox));
 	if (IS_ERR(hw)) {
 		wl1271_error("can't allocate hw");
 		ret = PTR_ERR(hw);
@@ -1725,6 +1799,21 @@
 	return ret;
 }
 
+static int wl12xx_remove(struct platform_device *pdev)
+{
+	struct wl1271 *wl = platform_get_drvdata(pdev);
+	struct wl12xx_priv *priv;
+
+	if (!wl)
+		goto out;
+	priv = wl->priv;
+
+	kfree(priv->rx_mem_addr);
+
+out:
+	return wlcore_remove(pdev);
+}
+
 static const struct platform_device_id wl12xx_id_table[] = {
 	{ "wl12xx", 0 },
 	{  } /* Terminating Entry */
@@ -1733,7 +1822,7 @@
 
 static struct platform_driver wl12xx_driver = {
 	.probe		= wl12xx_probe,
-	.remove		= wlcore_remove,
+	.remove		= wl12xx_remove,
 	.id_table	= wl12xx_id_table,
 	.driver = {
 		.name	= "wl12xx_driver",
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c
new file mode 100644
index 0000000..affdb3e
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/scan.c
@@ -0,0 +1,501 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/tx.h"
+
+static int wl1271_get_scan_channels(struct wl1271 *wl,
+				    struct cfg80211_scan_request *req,
+				    struct basic_scan_channel_params *channels,
+				    enum ieee80211_band band, bool passive)
+{
+	struct conf_scan_settings *c = &wl->conf.scan;
+	int i, j;
+	u32 flags;
+
+	for (i = 0, j = 0;
+	     i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
+	     i++) {
+		flags = req->channels[i]->flags;
+
+		if (!test_bit(i, wl->scan.scanned_ch) &&
+		    !(flags & IEEE80211_CHAN_DISABLED) &&
+		    (req->channels[i]->band == band) &&
+		    /*
+		     * In passive scans, we scan all remaining
+		     * channels, even if not marked as such.
+		     * In active scans, we only scan channels not
+		     * marked as passive.
+		     */
+		    (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
+			wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
+				     req->channels[i]->band,
+				     req->channels[i]->center_freq);
+			wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
+				     req->channels[i]->hw_value,
+				     req->channels[i]->flags);
+			wl1271_debug(DEBUG_SCAN,
+				     "max_antenna_gain %d, max_power %d",
+				     req->channels[i]->max_antenna_gain,
+				     req->channels[i]->max_power);
+			wl1271_debug(DEBUG_SCAN, "beacon_found %d",
+				     req->channels[i]->beacon_found);
+
+			if (!passive) {
+				channels[j].min_duration =
+					cpu_to_le32(c->min_dwell_time_active);
+				channels[j].max_duration =
+					cpu_to_le32(c->max_dwell_time_active);
+			} else {
+				channels[j].min_duration =
+					cpu_to_le32(c->dwell_time_passive);
+				channels[j].max_duration =
+					cpu_to_le32(c->dwell_time_passive);
+			}
+			channels[j].early_termination = 0;
+			channels[j].tx_power_att = req->channels[i]->max_power;
+			channels[j].channel = req->channels[i]->hw_value;
+
+			memset(&channels[j].bssid_lsb, 0xff, 4);
+			memset(&channels[j].bssid_msb, 0xff, 2);
+
+			/* Mark the channels we already used */
+			set_bit(i, wl->scan.scanned_ch);
+
+			j++;
+		}
+	}
+
+	return j;
+}
+
+#define WL1271_NOTHING_TO_SCAN 1
+
+static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			    enum ieee80211_band band,
+			    bool passive, u32 basic_rate)
+{
+	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+	struct wl1271_cmd_scan *cmd;
+	struct wl1271_cmd_trigger_scan_to *trigger;
+	int ret;
+	u16 scan_options = 0;
+
+	/* skip active scans if we don't have SSIDs */
+	if (!passive && wl->scan.req->n_ssids == 0)
+		return WL1271_NOTHING_TO_SCAN;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+	if (!cmd || !trigger) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (wl->conf.scan.split_scan_timeout)
+		scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
+
+	if (passive)
+		scan_options |= WL1271_SCAN_OPT_PASSIVE;
+
+	cmd->params.role_id = wlvif->role_id;
+
+	if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	cmd->params.scan_options = cpu_to_le16(scan_options);
+
+	cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
+						    cmd->channels,
+						    band, passive);
+	if (cmd->params.n_ch == 0) {
+		ret = WL1271_NOTHING_TO_SCAN;
+		goto out;
+	}
+
+	cmd->params.tx_rate = cpu_to_le32(basic_rate);
+	cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
+	cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
+	cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
+
+	if (band == IEEE80211_BAND_2GHZ)
+		cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+	else
+		cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
+
+	if (wl->scan.ssid_len && wl->scan.ssid) {
+		cmd->params.ssid_len = wl->scan.ssid_len;
+		memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
+	}
+
+	memcpy(cmd->addr, vif->addr, ETH_ALEN);
+
+	ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+					 cmd->params.role_id, band,
+					 wl->scan.ssid, wl->scan.ssid_len,
+					 wl->scan.req->ie,
+					 wl->scan.req->ie_len, false);
+	if (ret < 0) {
+		wl1271_error("PROBE request template failed");
+		goto out;
+	}
+
+	trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
+	ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+			      sizeof(*trigger), 0);
+	if (ret < 0) {
+		wl1271_error("trigger scan to failed for hw scan");
+		goto out;
+	}
+
+	wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+	ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("SCAN failed");
+		goto out;
+	}
+
+out:
+	kfree(cmd);
+	kfree(trigger);
+	return ret;
+}
+
+int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	struct wl1271_cmd_header *cmd = NULL;
+	int ret = 0;
+
+	if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
+		return -EINVAL;
+
+	wl1271_debug(DEBUG_CMD, "cmd scan stop");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
+			      sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("cmd stop_scan failed");
+		goto out;
+	}
+out:
+	kfree(cmd);
+	return ret;
+}
+
+void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	int ret = 0;
+	enum ieee80211_band band;
+	u32 rate, mask;
+
+	switch (wl->scan.state) {
+	case WL1271_SCAN_STATE_IDLE:
+		break;
+
+	case WL1271_SCAN_STATE_2GHZ_ACTIVE:
+		band = IEEE80211_BAND_2GHZ;
+		mask = wlvif->bitrate_masks[band];
+		if (wl->scan.req->no_cck) {
+			mask &= ~CONF_TX_CCK_RATES;
+			if (!mask)
+				mask = CONF_TX_RATE_MASK_BASIC_P2P;
+		}
+		rate = wl1271_tx_min_rate_get(wl, mask);
+		ret = wl1271_scan_send(wl, wlvif, band, false, rate);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
+			wl1271_scan_stm(wl, wlvif);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_2GHZ_PASSIVE:
+		band = IEEE80211_BAND_2GHZ;
+		mask = wlvif->bitrate_masks[band];
+		if (wl->scan.req->no_cck) {
+			mask &= ~CONF_TX_CCK_RATES;
+			if (!mask)
+				mask = CONF_TX_RATE_MASK_BASIC_P2P;
+		}
+		rate = wl1271_tx_min_rate_get(wl, mask);
+		ret = wl1271_scan_send(wl, wlvif, band, true, rate);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			if (wl->enable_11a)
+				wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
+			else
+				wl->scan.state = WL1271_SCAN_STATE_DONE;
+			wl1271_scan_stm(wl, wlvif);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_5GHZ_ACTIVE:
+		band = IEEE80211_BAND_5GHZ;
+		rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
+		ret = wl1271_scan_send(wl, wlvif, band, false, rate);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
+			wl1271_scan_stm(wl, wlvif);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_5GHZ_PASSIVE:
+		band = IEEE80211_BAND_5GHZ;
+		rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
+		ret = wl1271_scan_send(wl, wlvif, band, true, rate);
+		if (ret == WL1271_NOTHING_TO_SCAN) {
+			wl->scan.state = WL1271_SCAN_STATE_DONE;
+			wl1271_scan_stm(wl, wlvif);
+		}
+
+		break;
+
+	case WL1271_SCAN_STATE_DONE:
+		wl->scan.failed = false;
+		cancel_delayed_work(&wl->scan_complete_work);
+		ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+					     msecs_to_jiffies(0));
+		break;
+
+	default:
+		wl1271_error("invalid scan state");
+		break;
+	}
+
+	if (ret < 0) {
+		cancel_delayed_work(&wl->scan_complete_work);
+		ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+					     msecs_to_jiffies(0));
+	}
+}
+
+static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd,
+				   struct wlcore_scan_channels *cmd_channels)
+{
+	memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+	memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+	cmd->dfs = cmd_channels->dfs;
+	cmd->n_pactive_ch = cmd_channels->passive_active;
+
+	memcpy(cmd->channels_2, cmd_channels->channels_2,
+	       sizeof(cmd->channels_2));
+	memcpy(cmd->channels_5, cmd_channels->channels_5,
+	       sizeof(cmd->channels_2));
+	/* channels_4 are not supported, so no need to copy them */
+}
+
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+				  struct wl12xx_vif *wlvif,
+				  struct cfg80211_sched_scan_request *req,
+				  struct ieee80211_sched_scan_ies *ies)
+{
+	struct wl1271_cmd_sched_scan_config *cfg = NULL;
+	struct wlcore_scan_channels *cfg_channels = NULL;
+	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+	int i, ret;
+	bool force_passive = !req->n_ssids;
+
+	wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	cfg->role_id = wlvif->role_id;
+	cfg->rssi_threshold = c->rssi_threshold;
+	cfg->snr_threshold  = c->snr_threshold;
+	cfg->n_probe_reqs = c->num_probe_reqs;
+	/* cycles set to 0 it means infinite (until manually stopped) */
+	cfg->cycles = 0;
+	/* report APs when at least 1 is found */
+	cfg->report_after = 1;
+	/* don't stop scanning automatically when something is found */
+	cfg->terminate = 0;
+	cfg->tag = WL1271_SCAN_DEFAULT_TAG;
+	/* don't filter on BSS type */
+	cfg->bss_type = SCAN_BSS_TYPE_ANY;
+	/* currently NL80211 supports only a single interval */
+	for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
+		cfg->intervals[i] = cpu_to_le32(req->interval);
+
+	cfg->ssid_len = 0;
+	ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+	if (ret < 0)
+		goto out;
+
+	cfg->filter_type = ret;
+
+	wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
+
+	cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL);
+	if (!cfg_channels) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels,
+					 req->n_channels, req->n_ssids,
+					 SCAN_TYPE_PERIODIC)) {
+		wl1271_error("scan channel list is empty");
+		ret = -EINVAL;
+		goto out;
+	}
+	wl12xx_adjust_channels(cfg, cfg_channels);
+
+	if (!force_passive && cfg->active[0]) {
+		u8 band = IEEE80211_BAND_2GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+						 wlvif->role_id, band,
+						 req->ssids[0].ssid,
+						 req->ssids[0].ssid_len,
+						 ies->ie[band],
+						 ies->len[band], true);
+		if (ret < 0) {
+			wl1271_error("2.4GHz PROBE request template failed");
+			goto out;
+		}
+	}
+
+	if (!force_passive && cfg->active[1]) {
+		u8 band = IEEE80211_BAND_5GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+						 wlvif->role_id, band,
+						 req->ssids[0].ssid,
+						 req->ssids[0].ssid_len,
+						 ies->ie[band],
+						 ies->len[band], true);
+		if (ret < 0) {
+			wl1271_error("5GHz PROBE request template failed");
+			goto out;
+		}
+	}
+
+	wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
+
+	ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
+			      sizeof(*cfg), 0);
+	if (ret < 0) {
+		wl1271_error("SCAN configuration failed");
+		goto out;
+	}
+out:
+	kfree(cfg_channels);
+	kfree(cfg);
+	return ret;
+}
+
+int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	struct wl1271_cmd_sched_scan_start *start;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
+
+	if (wlvif->bss_type != BSS_TYPE_STA_BSS)
+		return -EOPNOTSUPP;
+
+	if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) &&
+	    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
+		return -EBUSY;
+
+	start = kzalloc(sizeof(*start), GFP_KERNEL);
+	if (!start)
+		return -ENOMEM;
+
+	start->role_id = wlvif->role_id;
+	start->tag = WL1271_SCAN_DEFAULT_TAG;
+
+	ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
+			      sizeof(*start), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send scan start command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(start);
+	return ret;
+}
+
+int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif  *wlvif,
+			    struct cfg80211_sched_scan_request *req,
+			    struct ieee80211_sched_scan_ies *ies)
+{
+	int ret;
+
+	ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
+	if (ret < 0)
+		return ret;
+
+	return wl1271_scan_sched_scan_start(wl, wlvif);
+}
+
+void wl12xx_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
+{
+	struct wl1271_cmd_sched_scan_stop *stop;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+	/* FIXME: what to do if alloc'ing to stop fails? */
+	stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+	if (!stop) {
+		wl1271_error("failed to alloc memory to send sched scan stop");
+		return;
+	}
+
+	stop->role_id = wlvif->role_id;
+	stop->tag = WL1271_SCAN_DEFAULT_TAG;
+
+	ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
+			      sizeof(*stop), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send sched scan stop command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(stop);
+}
+
+int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+		      struct cfg80211_scan_request *req)
+{
+	wl1271_scan_stm(wl, wlvif);
+	return 0;
+}
+
+void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	wl1271_scan_stm(wl, wlvif);
+}
diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h
new file mode 100644
index 0000000..264af7a
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/scan.h
@@ -0,0 +1,140 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL12XX_SCAN_H__
+#define __WL12XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+#define WL12XX_MAX_CHANNELS_5GHZ 23
+
+struct basic_scan_params {
+	/* Scan option flags (WL1271_SCAN_OPT_*) */
+	__le16 scan_options;
+	u8 role_id;
+	/* Number of scan channels in the list (maximum 30) */
+	u8 n_ch;
+	/* This field indicates the number of probe requests to send
+	   per channel for an active scan */
+	u8 n_probe_reqs;
+	u8 tid_trigger;
+	u8 ssid_len;
+	u8 use_ssid_list;
+
+	/* Rate bit field for sending the probes */
+	__le32 tx_rate;
+
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	/* Band to scan */
+	u8 band;
+
+	u8 scan_tag;
+	u8 padding2[2];
+} __packed;
+
+struct basic_scan_channel_params {
+	/* Duration in TU to wait for frames on a channel for active scan */
+	__le32 min_duration;
+	__le32 max_duration;
+	__le32 bssid_lsb;
+	__le16 bssid_msb;
+	u8 early_termination;
+	u8 tx_power_att;
+	u8 channel;
+	/* FW internal use only! */
+	u8 dfs_candidate;
+	u8 activity_detected;
+	u8 pad;
+} __packed;
+
+struct wl1271_cmd_scan {
+	struct wl1271_cmd_header header;
+
+	struct basic_scan_params params;
+	struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+
+	/* src mac address */
+	u8 addr[ETH_ALEN];
+	u8 padding[2];
+} __packed;
+
+struct wl1271_cmd_sched_scan_config {
+	struct wl1271_cmd_header header;
+
+	__le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
+
+	s8 rssi_threshold; /* for filtering (in dBm) */
+	s8 snr_threshold;  /* for filtering (in dB) */
+
+	u8 cycles;       /* maximum number of scan cycles */
+	u8 report_after; /* report when this number of results are received */
+	u8 terminate;    /* stop scanning after reporting */
+
+	u8 tag;
+	u8 bss_type; /* for filtering */
+	u8 filter_type;
+
+	u8 ssid_len;     /* For SCAN_SSID_FILTER_SPECIFIC */
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+
+	u8 n_probe_reqs; /* Number of probes requests per channel */
+
+	u8 passive[SCAN_MAX_BANDS];
+	u8 active[SCAN_MAX_BANDS];
+
+	u8 dfs;
+
+	u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
+			    channels in BG band */
+	u8 role_id;
+	u8 padding[1];
+	struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+	struct conn_scan_ch_params channels_5[WL12XX_MAX_CHANNELS_5GHZ];
+	struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+} __packed;
+
+struct wl1271_cmd_sched_scan_start {
+	struct wl1271_cmd_header header;
+
+	u8 tag;
+	u8 role_id;
+	u8 padding[2];
+} __packed;
+
+struct wl1271_cmd_sched_scan_stop {
+	struct wl1271_cmd_header header;
+
+	u8 tag;
+	u8 role_id;
+	u8 padding[2];
+} __packed;
+
+int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+		      struct cfg80211_scan_request *req);
+int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif  *wlvif,
+			    struct cfg80211_sched_scan_request *req,
+			    struct ieee80211_sched_scan_ies *ies);
+void wl12xx_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif);
+#endif
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index 7182bbf..d455285 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -24,19 +24,37 @@
 
 #include "conf.h"
 
-/* minimum FW required for driver for wl127x */
-#define WL127X_CHIP_VER		6
-#define WL127X_IFTYPE_VER	3
-#define WL127X_MAJOR_VER	10
-#define WL127X_SUBTYPE_VER	2
-#define WL127X_MINOR_VER	115
+/* WiLink 6/7 chip IDs */
+#define CHIP_ID_127X_PG10              (0x04030101)
+#define CHIP_ID_127X_PG20              (0x04030111)
+#define CHIP_ID_128X_PG10              (0x05030101)
+#define CHIP_ID_128X_PG20              (0x05030111)
 
-/* minimum FW required for driver for wl128x */
+/* FW chip version for wl127x */
+#define WL127X_CHIP_VER		6
+/* minimum single-role FW version for wl127x */
+#define WL127X_IFTYPE_SR_VER	3
+#define WL127X_MAJOR_SR_VER	10
+#define WL127X_SUBTYPE_SR_VER	WLCORE_FW_VER_IGNORE
+#define WL127X_MINOR_SR_VER	115
+/* minimum multi-role FW version for wl127x */
+#define WL127X_IFTYPE_MR_VER	5
+#define WL127X_MAJOR_MR_VER	7
+#define WL127X_SUBTYPE_MR_VER	WLCORE_FW_VER_IGNORE
+#define WL127X_MINOR_MR_VER	115
+
+/* FW chip version for wl128x */
 #define WL128X_CHIP_VER		7
-#define WL128X_IFTYPE_VER	3
-#define WL128X_MAJOR_VER	10
-#define WL128X_SUBTYPE_VER	2
-#define WL128X_MINOR_VER	115
+/* minimum single-role FW version for wl128x */
+#define WL128X_IFTYPE_SR_VER	3
+#define WL128X_MAJOR_SR_VER	10
+#define WL128X_SUBTYPE_SR_VER	WLCORE_FW_VER_IGNORE
+#define WL128X_MINOR_SR_VER	115
+/* minimum multi-role FW version for wl128x */
+#define WL128X_IFTYPE_MR_VER	5
+#define WL128X_MAJOR_MR_VER	7
+#define WL128X_SUBTYPE_MR_VER	WLCORE_FW_VER_IGNORE
+#define WL128X_MINOR_MR_VER	42
 
 #define WL12XX_AGGR_BUFFER_SIZE	(4 * PAGE_SIZE)
 
@@ -55,6 +73,8 @@
 
 	int ref_clock;
 	int tcxo_clock;
+
+	struct wl127x_rx_mem_pool_addr *rx_mem_addr;
 };
 
 #endif /* __WL12XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/Makefile b/drivers/net/wireless/ti/wl18xx/Makefile
index 67c0987..ae2b817 100644
--- a/drivers/net/wireless/ti/wl18xx/Makefile
+++ b/drivers/net/wireless/ti/wl18xx/Makefile
@@ -1,3 +1,3 @@
-wl18xx-objs	= main.o acx.o tx.o io.o debugfs.o
+wl18xx-objs	= main.o acx.o tx.o io.o debugfs.o scan.o cmd.o event.o
 
 obj-$(CONFIG_WL18XX)		+= wl18xx.o
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index 72840e2..a169bb5 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -75,7 +75,7 @@
 
 	acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
 
-	ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
+	ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx));
 	if (ret < 0) {
 		wl1271_warning("failed to set Tx checksum state: %d", ret);
 		goto out;
@@ -109,3 +109,88 @@
 	kfree(acx);
 	return ret;
 }
+
+int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
+{
+	struct wlcore_peer_ht_operation_mode *acx;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
+		     hlid, wide);
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	acx->hlid = hlid;
+	acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
+
+	ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
+				   sizeof(*acx));
+
+	if (ret < 0) {
+		wl1271_warning("acx peer ht operation mode failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+
+}
+
+/*
+ * this command is basically the same as wl1271_acx_ht_capabilities,
+ * with the addition of supported rates. they should be unified in
+ * the next fw api change
+ */
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+			    struct ieee80211_sta_ht_cap *ht_cap,
+			    bool allow_ht_operation,
+			    u32 rate_set, u8 hlid)
+{
+	struct wlcore_acx_peer_cap *acx;
+	int ret = 0;
+	u32 ht_capabilites = 0;
+
+	wl1271_debug(DEBUG_ACX,
+		     "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
+		     ht_cap->ht_supported, ht_cap->cap, rate_set);
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (allow_ht_operation && ht_cap->ht_supported) {
+		/* no need to translate capabilities - use the spec values */
+		ht_capabilites = ht_cap->cap;
+
+		/*
+		 * this bit is not employed by the spec but only by FW to
+		 * indicate peer HT support
+		 */
+		ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
+
+		/* get data from A-MPDU parameters field */
+		acx->ampdu_max_length = ht_cap->ampdu_factor;
+		acx->ampdu_min_spacing = ht_cap->ampdu_density;
+	}
+
+	acx->hlid = hlid;
+	acx->ht_capabilites = cpu_to_le32(ht_capabilites);
+	acx->supported_rates = cpu_to_le32(rate_set);
+
+	ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("acx ht capabilities setting failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index e2609a6..0e636de 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -26,7 +26,13 @@
 #include "../wlcore/acx.h"
 
 enum {
-	ACX_CLEAR_STATISTICS		 = 0x0047,
+	ACX_NS_IPV6_FILTER		 = 0x0050,
+	ACX_PEER_HT_OPERATION_MODE_CFG	 = 0x0051,
+	ACX_CSUM_CONFIG			 = 0x0052,
+	ACX_SIM_CONFIG			 = 0x0053,
+	ACX_CLEAR_STATISTICS		 = 0x0054,
+	ACX_AUTO_RX_STREAMING		 = 0x0055,
+	ACX_PEER_CAP			 = 0x0056
 };
 
 /* numbers of bits the length field takes (add 1 for the actual number) */
@@ -278,10 +284,57 @@
 	struct acx_header header;
 };
 
+enum wlcore_bandwidth {
+	WLCORE_BANDWIDTH_20MHZ,
+	WLCORE_BANDWIDTH_40MHZ,
+};
+
+struct wlcore_peer_ht_operation_mode {
+	struct acx_header header;
+
+	u8 hlid;
+	u8 bandwidth; /* enum wlcore_bandwidth */
+	u8 padding[2];
+};
+
+/*
+ * ACX_PEER_CAP
+ * this struct is very similar to wl1271_acx_ht_capabilities, with the
+ * addition of supported rates
+ */
+struct wlcore_acx_peer_cap {
+	struct acx_header header;
+
+	/* bitmask of capability bits supported by the peer */
+	__le32 ht_capabilites;
+
+	/* rates supported by the remote peer */
+	__le32 supported_rates;
+
+	/* Indicates to which link these capabilities apply. */
+	u8 hlid;
+
+	/*
+	 * This the maximum A-MPDU length supported by the AP. The FW may not
+	 * exceed this length when sending A-MPDUs
+	 */
+	u8 ampdu_max_length;
+
+	/* This is the minimal spacing required when sending A-MPDUs to the AP*/
+	u8 ampdu_min_spacing;
+
+	u8 padding;
+} __packed;
+
 int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
 				  u32 sdio_blk_size, u32 extra_mem_blks,
 				  u32 len_field_size);
 int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
 int wl18xx_acx_clear_statistics(struct wl1271 *wl);
+int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide);
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+			    struct ieee80211_sta_ht_cap *ht_cap,
+			    bool allow_ht_operation,
+			    u32 rate_set, u8 hlid);
 
 #endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
new file mode 100644
index 0000000..1d1f6cc
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/hw_ops.h"
+
+#include "cmd.h"
+
+int wl18xx_cmd_channel_switch(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
+			      struct ieee80211_channel_switch *ch_switch)
+{
+	struct wl18xx_cmd_channel_switch *cmd;
+	u32 supported_rates;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "cmd channel switch");
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->role_id = wlvif->role_id;
+	cmd->channel = ch_switch->channel->hw_value;
+	cmd->switch_time = ch_switch->count;
+	cmd->stop_tx = ch_switch->block_tx;
+
+	switch (ch_switch->channel->band) {
+	case IEEE80211_BAND_2GHZ:
+		cmd->band = WLCORE_BAND_2_4GHZ;
+		break;
+	case IEEE80211_BAND_5GHZ:
+		cmd->band = WLCORE_BAND_5GHZ;
+		break;
+	default:
+		wl1271_error("invalid channel switch band: %d",
+			     ch_switch->channel->band);
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
+			  wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+	if (wlvif->p2p)
+		supported_rates &= ~CONF_TX_CCK_RATES;
+	cmd->local_supported_rates = cpu_to_le32(supported_rates);
+	cmd->channel_type = wlvif->channel_type;
+
+	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send channel switch command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(cmd);
+out:
+	return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
new file mode 100644
index 0000000..6687d10
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_CMD_H__
+#define __WL18XX_CMD_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/acx.h"
+
+struct wl18xx_cmd_channel_switch {
+	struct wl1271_cmd_header header;
+
+	u8 role_id;
+
+	/* The new serving channel */
+	u8 channel;
+	/* Relative time of the serving channel switch in TBTT units */
+	u8 switch_time;
+	/* Stop the role TX, should expect it after radar detection */
+	u8 stop_tx;
+
+	__le32 local_supported_rates;
+
+	u8 channel_type;
+	u8 band;
+
+	u8 padding[2];
+} __packed;
+
+int wl18xx_cmd_channel_switch(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
+			      struct ieee80211_channel_switch *ch_switch);
+
+#endif
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
index 4d426cc..e34302e 100644
--- a/drivers/net/wireless/ti/wl18xx/conf.h
+++ b/drivers/net/wireless/ti/wl18xx/conf.h
@@ -23,20 +23,21 @@
 #define __WL18XX_CONF_H__
 
 #define WL18XX_CONF_MAGIC	0x10e100ca
-#define WL18XX_CONF_VERSION	(WLCORE_CONF_VERSION | 0x0003)
+#define WL18XX_CONF_VERSION	(WLCORE_CONF_VERSION | 0x0006)
 #define WL18XX_CONF_MASK	0x0000ffff
 #define WL18XX_CONF_SIZE	(WLCORE_CONF_SIZE + \
 				 sizeof(struct wl18xx_priv_conf))
 
 #define NUM_OF_CHANNELS_11_ABG 150
 #define NUM_OF_CHANNELS_11_P 7
-#define WL18XX_NUM_OF_SUB_BANDS 9
 #define SRF_TABLE_LEN 16
 #define PIN_MUXING_SIZE 2
+#define WL18XX_TRACE_LOSS_GAPS_TX 10
+#define WL18XX_TRACE_LOSS_GAPS_RX 18
 
 struct wl18xx_mac_and_phy_params {
 	u8 phy_standalone;
-	u8 rdl;
+	u8 spare0;
 	u8 enable_clpc;
 	u8 enable_tx_low_pwr_on_siso_rdl;
 	u8 auto_detect;
@@ -69,18 +70,27 @@
 	u8 pwr_limit_reference_11_abg;
 	u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
 	u8 pwr_limit_reference_11p;
-	u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
-	u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
+	u8 spare1;
+	u8 per_chan_bo_mode_11_abg[13];
+	u8 per_chan_bo_mode_11_p[4];
 	u8 primary_clock_setting_time;
 	u8 clock_valid_on_wake_up;
 	u8 secondary_clock_setting_time;
 	u8 board_type;
 	/* enable point saturation */
 	u8 psat;
-	/* low/medium/high Tx power in dBm */
+	/* low/medium/high Tx power in dBm for STA-HP BG */
 	s8 low_power_val;
 	s8 med_power_val;
 	s8 high_power_val;
+	s8 per_sub_band_tx_trace_loss[WL18XX_TRACE_LOSS_GAPS_TX];
+	s8 per_sub_band_rx_trace_loss[WL18XX_TRACE_LOSS_GAPS_RX];
+	u8 tx_rf_margin;
+	/* low/medium/high Tx power in dBm for other role */
+	s8 low_power_val_2nd;
+	s8 med_power_val_2nd;
+	s8 high_power_val_2nd;
+
 	u8 padding[1];
 } __packed;
 
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
new file mode 100644
index 0000000..c9199d7
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "event.h"
+#include "scan.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+
+int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+			  bool *timeout)
+{
+	u32 local_event;
+
+	switch (event) {
+	case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
+		local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
+		break;
+
+	case WLCORE_EVENT_DFS_CONFIG_COMPLETE:
+		local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
+		break;
+
+	default:
+		/* event not implemented */
+		return 0;
+	}
+	return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
+}
+
+int wl18xx_process_mailbox_events(struct wl1271 *wl)
+{
+	struct wl18xx_event_mailbox *mbox = wl->mbox;
+	u32 vector;
+
+	vector = le32_to_cpu(mbox->events_vector);
+	wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
+
+	if (vector & SCAN_COMPLETE_EVENT_ID) {
+		wl1271_debug(DEBUG_EVENT, "scan results: %d",
+			     mbox->number_of_scan_results);
+
+		if (wl->scan_wlvif)
+			wl18xx_scan_completed(wl, wl->scan_wlvif);
+	}
+
+	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+		wl1271_debug(DEBUG_EVENT,
+			     "PERIODIC_SCAN_REPORT_EVENT (results %d)",
+			     mbox->number_of_sched_scan_results);
+
+		wlcore_scan_sched_scan_results(wl);
+	}
+
+	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
+		wlcore_event_sched_scan_completed(wl, 1);
+
+	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
+		wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
+
+	if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
+		wlcore_event_ba_rx_constraint(wl,
+				le16_to_cpu(mbox->rx_ba_role_id_bitmap),
+				le16_to_cpu(mbox->rx_ba_allowed_bitmap));
+
+	if (vector & BSS_LOSS_EVENT_ID)
+		wlcore_event_beacon_loss(wl,
+					 le16_to_cpu(mbox->bss_loss_bitmap));
+
+	if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
+		wlcore_event_channel_switch(wl,
+			le16_to_cpu(mbox->channel_switch_role_id_bitmap),
+			true);
+
+	if (vector & DUMMY_PACKET_EVENT_ID)
+		wlcore_event_dummy_packet(wl);
+
+	/*
+	 * "TX retries exceeded" has a different meaning according to mode.
+	 * In AP mode the offending station is disconnected.
+	 */
+	if (vector & MAX_TX_FAILURE_EVENT_ID)
+		wlcore_event_max_tx_failure(wl,
+				le32_to_cpu(mbox->tx_retry_exceeded_bitmap));
+
+	if (vector & INACTIVE_STA_EVENT_ID)
+		wlcore_event_inactive_sta(wl,
+				le32_to_cpu(mbox->inactive_sta_bitmap));
+
+	if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
+		wlcore_event_roc_complete(wl);
+
+	return 0;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
new file mode 100644
index 0000000..398f3d2
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -0,0 +1,77 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_EVENT_H__
+#define __WL18XX_EVENT_H__
+
+#include "../wlcore/wlcore.h"
+
+enum {
+	SCAN_COMPLETE_EVENT_ID                   = BIT(8),
+	RADAR_DETECTED_EVENT_ID                  = BIT(9),
+	CHANNEL_SWITCH_COMPLETE_EVENT_ID         = BIT(10),
+	BSS_LOSS_EVENT_ID                        = BIT(11),
+	MAX_TX_FAILURE_EVENT_ID                  = BIT(12),
+	DUMMY_PACKET_EVENT_ID                    = BIT(13),
+	INACTIVE_STA_EVENT_ID                    = BIT(14),
+	PEER_REMOVE_COMPLETE_EVENT_ID            = BIT(15),
+	PERIODIC_SCAN_COMPLETE_EVENT_ID          = BIT(16),
+	BA_SESSION_RX_CONSTRAINT_EVENT_ID        = BIT(17),
+	REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID      = BIT(18),
+	DFS_CHANNELS_CONFIG_COMPLETE_EVENT       = BIT(19),
+	PERIODIC_SCAN_REPORT_EVENT_ID            = BIT(20),
+};
+
+struct wl18xx_event_mailbox {
+	__le32 events_vector;
+
+	u8 number_of_scan_results;
+	u8 number_of_sched_scan_results;
+
+	__le16 channel_switch_role_id_bitmap;
+
+	s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
+
+	/* bitmap of removed links */
+	__le32 hlid_removed_bitmap;
+
+	/* rx ba constraint */
+	__le16 rx_ba_role_id_bitmap; /* 0xfff means any role. */
+	__le16 rx_ba_allowed_bitmap;
+
+	/* bitmap of roc completed (by role id) */
+	__le16 roc_completed_bitmap;
+
+	/* bitmap of stations (by role id) with bss loss */
+	__le16 bss_loss_bitmap;
+
+	/* bitmap of stations (by HLID) which exceeded max tx retries */
+	__le32 tx_retry_exceeded_bitmap;
+
+	/* bitmap of inactive stations (by HLID) */
+	__le32 inactive_sta_bitmap;
+} __packed;
+
+int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+			  bool *timeout);
+int wl18xx_process_mailbox_events(struct wl1271 *wl);
+
+#endif
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 8d8c1f8..da3ef1b 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -34,10 +34,13 @@
 
 #include "reg.h"
 #include "conf.h"
+#include "cmd.h"
 #include "acx.h"
 #include "tx.h"
 #include "wl18xx.h"
 #include "io.h"
+#include "scan.h"
+#include "event.h"
 #include "debugfs.h"
 
 #define WL18XX_RX_CHECKSUM_MASK      0x40
@@ -334,6 +337,8 @@
 		.tmpl_short_retry_limit      = 10,
 		.tmpl_long_retry_limit       = 10,
 		.tx_watchdog_timeout         = 5000,
+		.slow_link_thold             = 3,
+		.fast_link_thold             = 30,
 	},
 	.conn = {
 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
@@ -391,8 +396,10 @@
 	.scan = {
 		.min_dwell_time_active        = 7500,
 		.max_dwell_time_active        = 30000,
-		.min_dwell_time_passive       = 100000,
-		.max_dwell_time_passive       = 100000,
+		.min_dwell_time_active_long   = 25000,
+		.max_dwell_time_active_long   = 50000,
+		.dwell_time_passive           = 100000,
+		.dwell_time_dfs               = 150000,
 		.num_probe_reqs               = 2,
 		.split_scan_timeout           = 50000,
 	},
@@ -489,6 +496,10 @@
 		.increase_time              = 1,
 		.window_size                = 16,
 	},
+	.recovery = {
+		.bug_on_recovery	    = 0,
+		.no_recovery		    = 0,
+	},
 };
 
 static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
@@ -501,7 +512,6 @@
 		.clock_valid_on_wake_up		= 0x00,
 		.secondary_clock_setting_time	= 0x05,
 		.board_type 			= BOARD_TYPE_HDK_18XX,
-		.rdl				= 0x01,
 		.auto_detect			= 0x00,
 		.dedicated_fem			= FEM_NONE,
 		.low_band_component		= COMPONENT_3_WAY_SWITCH,
@@ -517,14 +527,44 @@
 		.enable_clpc			= 0x00,
 		.enable_tx_low_pwr_on_siso_rdl	= 0x00,
 		.rx_profile			= 0x00,
-		.pwr_limit_reference_11_abg	= 0xc8,
+		.pwr_limit_reference_11_abg	= 0x64,
+		.per_chan_pwr_limit_arr_11abg	= {
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+		.pwr_limit_reference_11p	= 0x64,
+		.per_chan_bo_mode_11_abg	= { 0x00, 0x00, 0x00, 0x00,
+						    0x00, 0x00, 0x00, 0x00,
+						    0x00, 0x00, 0x00, 0x00,
+						    0x00 },
+		.per_chan_bo_mode_11_p		= { 0x00, 0x00, 0x00, 0x00 },
+		.per_chan_pwr_limit_arr_11p	= { 0xff, 0xff, 0xff, 0xff,
+						    0xff, 0xff, 0xff },
 		.psat				= 0,
-		.low_power_val			= 0x00,
-		.med_power_val			= 0x0a,
-		.high_power_val			= 0x1e,
+		.low_power_val			= 0x08,
+		.med_power_val			= 0x12,
+		.high_power_val			= 0x18,
+		.low_power_val_2nd		= 0x05,
+		.med_power_val_2nd		= 0x0a,
+		.high_power_val_2nd		= 0x14,
 		.external_pa_dc2dc		= 0,
-		.number_of_assembled_ant2_4	= 1,
+		.number_of_assembled_ant2_4	= 2,
 		.number_of_assembled_ant5	= 1,
+		.tx_rf_margin			= 1,
 	},
 };
 
@@ -595,7 +635,7 @@
 };
 
 /* TODO: maybe move to a new header file? */
-#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin"
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-2.bin"
 
 static int wl18xx_identify_chip(struct wl1271 *wl)
 {
@@ -608,15 +648,18 @@
 		wl->sr_fw_name = WL18XX_FW_NAME;
 		/* wl18xx uses the same firmware for PLT */
 		wl->plt_fw_name = WL18XX_FW_NAME;
-		wl->quirks |= WLCORE_QUIRK_NO_ELP |
-			      WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
+		wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
 			      WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
 			      WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
-			      WLCORE_QUIRK_TX_PAD_LAST_FRAME;
+			      WLCORE_QUIRK_TX_PAD_LAST_FRAME |
+			      WLCORE_QUIRK_REGDOMAIN_CONF |
+			      WLCORE_QUIRK_DUAL_PROBE_TMPL;
 
-		wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER,
-				      WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER,
-				      WL18XX_MINOR_VER);
+		wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER,
+				      WL18XX_IFTYPE_VER,  WL18XX_MAJOR_VER,
+				      WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER,
+				      /* there's no separate multi-role FW */
+				      0, 0, 0, 0);
 		break;
 	case CHIP_ID_185x_PG10:
 		wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
@@ -630,6 +673,11 @@
 		goto out;
 	}
 
+	wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+	wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+	wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
+	wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
+	wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
 out:
 	return ret;
 }
@@ -843,6 +891,20 @@
 	if (ret < 0)
 		goto out;
 
+	wl->event_mask = BSS_LOSS_EVENT_ID |
+		SCAN_COMPLETE_EVENT_ID |
+		RSSI_SNR_TRIGGER_0_EVENT_ID |
+		PERIODIC_SCAN_COMPLETE_EVENT_ID |
+		PERIODIC_SCAN_REPORT_EVENT_ID |
+		DUMMY_PACKET_EVENT_ID |
+		PEER_REMOVE_COMPLETE_EVENT_ID |
+		BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
+		INACTIVE_STA_EVENT_ID |
+		MAX_TX_FAILURE_EVENT_ID |
+		CHANNEL_SWITCH_COMPLETE_EVENT_ID |
+		DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
+
 	ret = wlcore_boot_run_firmware(wl);
 	if (ret < 0)
 		goto out;
@@ -964,7 +1026,7 @@
 
 	/* (re)init private structures. Relevant on recovery as well. */
 	priv->last_fw_rls_idx = 0;
-	priv->extra_spare_vif_count = 0;
+	priv->extra_spare_key_count = 0;
 
 	/* set the default amount of spare blocks in the bitmap */
 	ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
@@ -1022,7 +1084,12 @@
 {
 	struct wl18xx_priv *priv = wl->priv;
 
-	return priv->conf.phy.number_of_assembled_ant2_4 >= 2;
+	/* only support MIMO with multiple antennas, and when SISO
+	 * is not forced through config
+	 */
+	return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) &&
+	       (priv->conf.ht.mode != HT_MODE_WIDE) &&
+	       (priv->conf.ht.mode != HT_MODE_SISO20);
 }
 
 /*
@@ -1223,8 +1290,8 @@
 {
 	struct wl18xx_priv *priv = wl->priv;
 
-	/* If we have VIFs requiring extra spare, indulge them */
-	if (priv->extra_spare_vif_count)
+	/* If we have keys requiring extra spare, indulge them */
+	if (priv->extra_spare_key_count)
 		return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
 
 	return WL18XX_TX_HW_BLOCK_SPARE;
@@ -1236,42 +1303,48 @@
 			  struct ieee80211_key_conf *key_conf)
 {
 	struct wl18xx_priv *priv = wl->priv;
-	bool change_spare = false;
+	bool change_spare = false, special_enc;
 	int ret;
 
-	/*
-	 * when adding the first or removing the last GEM/TKIP interface,
-	 * we have to adjust the number of spare blocks.
-	 */
-	change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
-		key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) &&
-		((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) ||
-		 (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY));
+	wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d",
+		     priv->extra_spare_key_count);
 
-	/* no need to change spare - just regular set_key */
-	if (!change_spare)
-		return wlcore_set_key(wl, cmd, vif, sta, key_conf);
+	special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
+		      key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
 
 	ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
 	if (ret < 0)
 		goto out;
 
+	/*
+	 * when adding the first or removing the last GEM/TKIP key,
+	 * we have to adjust the number of spare blocks.
+	 */
+	if (special_enc) {
+		if (cmd == SET_KEY) {
+			/* first key */
+			change_spare = (priv->extra_spare_key_count == 0);
+			priv->extra_spare_key_count++;
+		} else if (cmd == DISABLE_KEY) {
+			/* last key */
+			change_spare = (priv->extra_spare_key_count == 1);
+			priv->extra_spare_key_count--;
+		}
+	}
+
+	wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d",
+		     priv->extra_spare_key_count);
+
+	if (!change_spare)
+		goto out;
+
 	/* key is now set, change the spare blocks */
-	if (cmd == SET_KEY) {
+	if (priv->extra_spare_key_count)
 		ret = wl18xx_set_host_cfg_bitmap(wl,
 					WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
-		if (ret < 0)
-			goto out;
-
-		priv->extra_spare_vif_count++;
-	} else {
+	else
 		ret = wl18xx_set_host_cfg_bitmap(wl,
 					WL18XX_TX_HW_BLOCK_SPARE);
-		if (ret < 0)
-			goto out;
-
-		priv->extra_spare_vif_count--;
-	}
 
 out:
 	return ret;
@@ -1296,6 +1369,92 @@
 	return buf_offset;
 }
 
+static void wl18xx_sta_rc_update(struct wl1271 *wl,
+				 struct wl12xx_vif *wlvif,
+				 struct ieee80211_sta *sta,
+				 u32 changed)
+{
+	bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+
+	wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
+
+	if (!(changed & IEEE80211_RC_BW_CHANGED))
+		return;
+
+	mutex_lock(&wl->mutex);
+
+	/* sanity */
+	if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
+		goto out;
+
+	/* ignore the change before association */
+	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+		goto out;
+
+	/*
+	 * If we started out as wide, we can change the operation mode. If we
+	 * thought this was a 20mhz AP, we have to reconnect
+	 */
+	if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
+	    wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
+		wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
+	else
+		ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
+
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static int wl18xx_set_peer_cap(struct wl1271 *wl,
+			       struct ieee80211_sta_ht_cap *ht_cap,
+			       bool allow_ht_operation,
+			       u32 rate_set, u8 hlid)
+{
+	return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
+				       rate_set, hlid);
+}
+
+static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+				 struct wl1271_link *lnk)
+{
+	u8 thold;
+	struct wl18xx_fw_status_priv *status_priv =
+		(struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+	u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+
+	/* suspended links are never high priority */
+	if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+		return false;
+
+	/* the priority thresholds are taken from FW */
+	if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) &&
+	    !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
+		thold = status_priv->tx_fast_link_prio_threshold;
+	else
+		thold = status_priv->tx_slow_link_prio_threshold;
+
+	return lnk->allocated_pkts < thold;
+}
+
+static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+				struct wl1271_link *lnk)
+{
+	u8 thold;
+	struct wl18xx_fw_status_priv *status_priv =
+		(struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+	u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+
+	if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+		thold = status_priv->tx_suspend_threshold;
+	else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) &&
+		 !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
+		thold = status_priv->tx_fast_stop_threshold;
+	else
+		thold = status_priv->tx_slow_stop_threshold;
+
+	return lnk->allocated_pkts < thold;
+}
+
 static int wl18xx_setup(struct wl1271 *wl);
 
 static struct wlcore_ops wl18xx_ops = {
@@ -1305,6 +1464,8 @@
 	.plt_init	= wl18xx_plt_init,
 	.trigger_cmd	= wl18xx_trigger_cmd,
 	.ack_event	= wl18xx_ack_event,
+	.wait_for_event	= wl18xx_wait_for_event,
+	.process_mailbox_events = wl18xx_process_mailbox_events,
 	.calc_tx_blocks = wl18xx_calc_tx_blocks,
 	.set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
 	.set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
@@ -1320,16 +1481,26 @@
 	.ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
 	.get_mac	= wl18xx_get_mac,
 	.debugfs_init	= wl18xx_debugfs_add_files,
+	.scan_start	= wl18xx_scan_start,
+	.scan_stop	= wl18xx_scan_stop,
+	.sched_scan_start	= wl18xx_sched_scan_start,
+	.sched_scan_stop	= wl18xx_scan_sched_scan_stop,
 	.handle_static_data	= wl18xx_handle_static_data,
 	.get_spare_blocks = wl18xx_get_spare_blocks,
 	.set_key	= wl18xx_set_key,
+	.channel_switch	= wl18xx_cmd_channel_switch,
 	.pre_pkt_send	= wl18xx_pre_pkt_send,
+	.sta_rc_update	= wl18xx_sta_rc_update,
+	.set_peer_cap	= wl18xx_set_peer_cap,
+	.lnk_high_prio	= wl18xx_lnk_high_prio,
+	.lnk_low_prio	= wl18xx_lnk_low_prio,
 };
 
 /* HT cap appropriate for wide channels in 2Ghz */
 static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
 	.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
-	       IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
+	       IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 |
+	       IEEE80211_HT_CAP_GRN_FLD,
 	.ht_supported = true,
 	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1343,7 +1514,8 @@
 /* HT cap appropriate for wide channels in 5Ghz */
 static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
 	.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
-	       IEEE80211_HT_CAP_SUP_WIDTH_20_40,
+	       IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+	       IEEE80211_HT_CAP_GRN_FLD,
 	.ht_supported = true,
 	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1356,7 +1528,8 @@
 
 /* HT cap appropriate for SISO 20 */
 static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
-	.cap = IEEE80211_HT_CAP_SGI_20,
+	.cap = IEEE80211_HT_CAP_SGI_20 |
+	       IEEE80211_HT_CAP_GRN_FLD,
 	.ht_supported = true,
 	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1369,7 +1542,8 @@
 
 /* HT cap appropriate for MIMO rates in 20mhz channel */
 static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
-	.cap = IEEE80211_HT_CAP_SGI_20,
+	.cap = IEEE80211_HT_CAP_SGI_20 |
+	       IEEE80211_HT_CAP_GRN_FLD,
 	.ht_supported = true,
 	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1387,7 +1561,8 @@
 
 	wl->rtable = wl18xx_rtable;
 	wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
-	wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS;
+	wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
+	wl->num_channels = 2;
 	wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
 	wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
 	wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
@@ -1506,7 +1681,8 @@
 	int ret;
 
 	hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv),
-			     WL18XX_AGGR_BUFFER_SIZE);
+			     WL18XX_AGGR_BUFFER_SIZE,
+			     sizeof(struct wl18xx_event_mailbox));
 	if (IS_ERR(hw)) {
 		wl1271_error("can't allocate hw");
 		ret = PTR_ERR(hw);
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
new file mode 100644
index 0000000..09d9445
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -0,0 +1,326 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+
+static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
+				   struct wlcore_scan_channels *cmd_channels)
+{
+	memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+	memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+	cmd->dfs = cmd_channels->dfs;
+	cmd->passive_active = cmd_channels->passive_active;
+
+	memcpy(cmd->channels_2, cmd_channels->channels_2,
+	       sizeof(cmd->channels_2));
+	memcpy(cmd->channels_5, cmd_channels->channels_5,
+	       sizeof(cmd->channels_2));
+	/* channels_4 are not supported, so no need to copy them */
+}
+
+static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			    struct cfg80211_scan_request *req)
+{
+	struct wl18xx_cmd_scan_params *cmd;
+	struct wlcore_scan_channels *cmd_channels = NULL;
+	int ret;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->role_id = wlvif->role_id;
+
+	if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	cmd->scan_type = SCAN_TYPE_SEARCH;
+	cmd->rssi_threshold = -127;
+	cmd->snr_threshold = 0;
+
+	cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+	cmd->ssid_from_list = 0;
+	cmd->filter = 0;
+	cmd->add_broadcast = 0;
+
+	cmd->urgency = 0;
+	cmd->protect = 0;
+
+	cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
+	cmd->terminate_after = 0;
+
+	/* configure channels */
+	WARN_ON(req->n_ssids > 1);
+
+	cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+	if (!cmd_channels) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+				    req->n_channels, req->n_ssids,
+				    SCAN_TYPE_SEARCH);
+	wl18xx_adjust_channels(cmd, cmd_channels);
+
+	/*
+	 * all the cycles params (except total cycles) should
+	 * remain 0 for normal scan
+	 */
+	cmd->total_cycles = 1;
+
+	if (req->no_cck)
+		cmd->rate = WL18XX_SCAN_RATE_6;
+
+	cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+	if (req->n_ssids) {
+		cmd->ssid_len = req->ssids[0].ssid_len;
+		memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
+	}
+
+	/* TODO: per-band ies? */
+	if (cmd->active[0]) {
+		u8 band = IEEE80211_BAND_2GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+				 cmd->role_id, band,
+				 req->ssids ? req->ssids[0].ssid : NULL,
+				 req->ssids ? req->ssids[0].ssid_len : 0,
+				 req->ie,
+				 req->ie_len,
+				 false);
+		if (ret < 0) {
+			wl1271_error("2.4GHz PROBE request template failed");
+			goto out;
+		}
+	}
+
+	if (cmd->active[1] || cmd->dfs) {
+		u8 band = IEEE80211_BAND_5GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+				 cmd->role_id, band,
+				 req->ssids ? req->ssids[0].ssid : NULL,
+				 req->ssids ? req->ssids[0].ssid_len : 0,
+				 req->ie,
+				 req->ie_len,
+				 false);
+		if (ret < 0) {
+			wl1271_error("5GHz PROBE request template failed");
+			goto out;
+		}
+	}
+
+	wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+	ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("SCAN failed");
+		goto out;
+	}
+
+out:
+	kfree(cmd_channels);
+	kfree(cmd);
+	return ret;
+}
+
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	wl->scan.failed = false;
+	cancel_delayed_work(&wl->scan_complete_work);
+	ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+				     msecs_to_jiffies(0));
+}
+
+static
+int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
+				  struct wl12xx_vif *wlvif,
+				  struct cfg80211_sched_scan_request *req,
+				  struct ieee80211_sched_scan_ies *ies)
+{
+	struct wl18xx_cmd_scan_params *cmd;
+	struct wlcore_scan_channels *cmd_channels = NULL;
+	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+	int ret;
+	int filter_type;
+
+	wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+	filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+	if (filter_type < 0)
+		return filter_type;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->role_id = wlvif->role_id;
+
+	if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	cmd->scan_type = SCAN_TYPE_PERIODIC;
+	cmd->rssi_threshold = c->rssi_threshold;
+	cmd->snr_threshold = c->snr_threshold;
+
+	/* don't filter on BSS type */
+	cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+	cmd->ssid_from_list = 1;
+	if (filter_type == SCAN_SSID_FILTER_LIST)
+		cmd->filter = 1;
+	cmd->add_broadcast = 0;
+
+	cmd->urgency = 0;
+	cmd->protect = 0;
+
+	cmd->n_probe_reqs = c->num_probe_reqs;
+	/* don't stop scanning automatically when something is found */
+	cmd->terminate_after = 0;
+
+	cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+	if (!cmd_channels) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* configure channels */
+	wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+				    req->n_channels, req->n_ssids,
+				    SCAN_TYPE_PERIODIC);
+	wl18xx_adjust_channels(cmd, cmd_channels);
+
+	cmd->short_cycles_sec = 0;
+	cmd->long_cycles_sec = cpu_to_le16(req->interval);
+	cmd->short_cycles_count = 0;
+
+	cmd->total_cycles = 0;
+
+	cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+	/* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
+	cmd->report_threshold = 1;
+	cmd->terminate_on_report = 0;
+
+	if (cmd->active[0]) {
+		u8 band = IEEE80211_BAND_2GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+				 cmd->role_id, band,
+				 req->ssids ? req->ssids[0].ssid : NULL,
+				 req->ssids ? req->ssids[0].ssid_len : 0,
+				 ies->ie[band],
+				 ies->len[band],
+				 true);
+		if (ret < 0) {
+			wl1271_error("2.4GHz PROBE request template failed");
+			goto out;
+		}
+	}
+
+	if (cmd->active[1] || cmd->dfs) {
+		u8 band = IEEE80211_BAND_5GHZ;
+		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+				 cmd->role_id, band,
+				 req->ssids ? req->ssids[0].ssid : NULL,
+				 req->ssids ? req->ssids[0].ssid_len : 0,
+				 ies->ie[band],
+				 ies->len[band],
+				 true);
+		if (ret < 0) {
+			wl1271_error("5GHz PROBE request template failed");
+			goto out;
+		}
+	}
+
+	wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+	ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("SCAN failed");
+		goto out;
+	}
+
+out:
+	kfree(cmd_channels);
+	kfree(cmd);
+	return ret;
+}
+
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			    struct cfg80211_sched_scan_request *req,
+			    struct ieee80211_sched_scan_ies *ies)
+{
+	return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
+}
+
+static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			       u8 scan_type)
+{
+	struct wl18xx_cmd_scan_stop *stop;
+	int ret;
+
+	wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+	stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+	if (!stop) {
+		wl1271_error("failed to alloc memory to send sched scan stop");
+		return -ENOMEM;
+	}
+
+	stop->role_id = wlvif->role_id;
+	stop->scan_type = scan_type;
+
+	ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send sched scan stop command");
+		goto out_free;
+	}
+
+out_free:
+	kfree(stop);
+	return ret;
+}
+
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	__wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
+}
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+		      struct cfg80211_scan_request *req)
+{
+	return wl18xx_scan_send(wl, wlvif, req);
+}
+
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
+}
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h
new file mode 100644
index 0000000..eadee42
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.h
@@ -0,0 +1,127 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_SCAN_H__
+#define __WL18XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+struct tracking_ch_params {
+	struct conn_scan_ch_params channel;
+
+	__le32 bssid_lsb;
+	__le16 bssid_msb;
+
+	u8 padding[2];
+} __packed;
+
+/* probe request rate */
+enum
+{
+	WL18XX_SCAN_RATE_1	= 0,
+	WL18XX_SCAN_RATE_5_5	= 1,
+	WL18XX_SCAN_RATE_6	= 2,
+};
+
+#define WL18XX_MAX_CHANNELS_5GHZ 32
+
+struct wl18xx_cmd_scan_params {
+	struct wl1271_cmd_header header;
+
+	u8 role_id;
+	u8 scan_type;
+
+	s8 rssi_threshold; /* for filtering (in dBm) */
+	s8 snr_threshold;  /* for filtering (in dB) */
+
+	u8 bss_type;	   /* for filtering */
+	u8 ssid_from_list; /* use ssid from configured ssid list */
+	u8 filter;	   /* forward only results with matching ssids */
+
+	/*
+	 * add broadcast ssid in addition to the configured ssids.
+	 * the driver should add dummy entry for it (?).
+	 */
+	u8 add_broadcast;
+
+	u8 urgency;
+	u8 protect;	 /* ??? */
+	u8 n_probe_reqs;    /* Number of probes requests per channel */
+	u8 terminate_after; /* early terminate scan operation */
+
+	u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+	u8 active[SCAN_MAX_BANDS];  /* number of active scan channels */
+	u8 dfs;		   /* number of dfs channels in 5ghz */
+	u8 passive_active; /* number of passive before active channels 2.4ghz */
+
+	__le16 short_cycles_sec;
+	__le16 long_cycles_sec;
+	u8 short_cycles_count;
+	u8 total_cycles; /* 0 - infinite */
+	u8 padding[2];
+
+	union {
+		struct {
+			struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+			struct conn_scan_ch_params channels_5[WL18XX_MAX_CHANNELS_5GHZ];
+			struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+		};
+		struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS];
+	} ;
+
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 ssid_len;	 /* For SCAN_SSID_FILTER_SPECIFIC */
+	u8 tag;
+	u8 rate;
+
+	/* send SCAN_REPORT_EVENT in periodic scans after each cycle
+	* if number of results >= report_threshold. Must be 0 for
+	* non periodic scans
+	*/
+	u8 report_threshold;
+
+	/* Should periodic scan stop after a report event was created.
+	* Must be 0 for non periodic scans.
+	*/
+	u8 terminate_on_report;
+
+	u8 padding1[3];
+} __packed;
+
+struct wl18xx_cmd_scan_stop {
+	struct wl1271_cmd_header header;
+
+	u8 role_id;
+	u8 scan_type;
+	u8 padding[2];
+} __packed;
+
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+		      struct cfg80211_scan_request *req);
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			    struct cfg80211_sched_scan_request *req,
+			    struct ieee80211_sched_scan_ies *ies);
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+#endif
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c
index 5b1fb10..57c6943 100644
--- a/drivers/net/wireless/ti/wl18xx/tx.c
+++ b/drivers/net/wireless/ti/wl18xx/tx.c
@@ -28,6 +28,49 @@
 #include "wl18xx.h"
 #include "tx.h"
 
+static
+void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
+			     struct ieee80211_tx_rate *rate)
+{
+	u8 fw_rate = wl->fw_status_2->counters.tx_last_rate;
+
+	if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
+		wl1271_error("last Tx rate invalid: %d", fw_rate);
+		rate->idx = 0;
+		rate->flags = 0;
+		return;
+	}
+
+	if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) {
+		rate->idx = fw_rate;
+		rate->flags = 0;
+	} else {
+		rate->flags = IEEE80211_TX_RC_MCS;
+		rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0;
+
+		/* SGI modifier is counted as a separate rate */
+		if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI)
+			(rate->idx)--;
+		if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
+			(rate->idx)--;
+
+		/* this also covers the 40Mhz SGI case (= MCS15) */
+		if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI ||
+		    fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
+			rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+
+		if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) {
+			struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+			if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
+			    wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
+				/* adjustment needed for range 0-7 */
+				rate->idx -= 8;
+				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+			}
+		}
+	}
+}
+
 static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
 {
 	struct ieee80211_tx_info *info;
@@ -44,7 +87,6 @@
 	/* a zero bit indicates Tx success */
 	tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
 
-
 	skb = wl->tx_frames[id];
 	info = IEEE80211_SKB_CB(skb);
 
@@ -56,11 +98,13 @@
 	/* update the TX status info */
 	if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
 		info->flags |= IEEE80211_TX_STAT_ACK;
+	/*
+	 * first pass info->control.vif while it's valid, and then fill out
+	 * the info->status structures
+	 */
+	wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]);
 
-	/* no real data about Tx completion */
-	info->status.rates[0].idx = -1;
-	info->status.rates[0].count = 0;
-	info->status.rates[0].flags = 0;
+	info->status.rates[0].count = 1; /* no data about retries */
 	info->status.ack_signal = -1;
 
 	if (!tx_success)
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 96a1e43..b6739e7 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -26,10 +26,10 @@
 
 /* minimum FW required for driver */
 #define WL18XX_CHIP_VER		8
-#define WL18XX_IFTYPE_VER	2
-#define WL18XX_MAJOR_VER	0
-#define WL18XX_SUBTYPE_VER	0
-#define WL18XX_MINOR_VER	100
+#define WL18XX_IFTYPE_VER	5
+#define WL18XX_MAJOR_VER	WLCORE_FW_VER_IGNORE
+#define WL18XX_SUBTYPE_VER	WLCORE_FW_VER_IGNORE
+#define WL18XX_MINOR_VER	28
 
 #define WL18XX_CMD_MAX_SIZE          740
 
@@ -49,8 +49,8 @@
 	/* Index of last released Tx desc in FW */
 	u8 last_fw_rls_idx;
 
-	/* number of VIFs requiring extra spare mem-blocks */
-	int extra_spare_vif_count;
+	/* number of keys requiring extra spare mem-blocks */
+	int extra_spare_key_count;
 };
 
 #define WL18XX_FW_MAX_TX_STATUS_DESC 33
@@ -68,7 +68,43 @@
 	 */
 	u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
 
-	u8 padding[2];
+	/* A bitmap representing the currently suspended links. The suspend
+	 * is short lived, for multi-channel Tx requirements.
+	 */
+	__le32 link_suspend_bitmap;
+
+	/* packet threshold for an "almost empty" AC,
+	 * for Tx schedulng purposes
+	 */
+	u8 tx_ac_threshold;
+
+	/* number of packets to queue up for a link in PS */
+	u8 tx_ps_threshold;
+
+	/* number of packet to queue up for a suspended link */
+	u8 tx_suspend_threshold;
+
+	/* Should have less than this number of packets in queue of a slow
+	 * link to qualify as high priority link
+	 */
+	u8 tx_slow_link_prio_threshold;
+
+	/* Should have less than this number of packets in queue of a fast
+	 * link to qualify as high priority link
+	 */
+	u8 tx_fast_link_prio_threshold;
+
+	/* Should have less than this number of packets in queue of a slow
+	 * link before we stop queuing up packets for it.
+	 */
+	u8 tx_slow_stop_threshold;
+
+	/* Should have less than this number of packets in queue of a fast
+	 * link before we stop queuing up packets for it.
+	 */
+	u8 tx_fast_stop_threshold;
+
+	u8 padding[3];
 };
 
 #define WL18XX_PHY_VERSION_MAX_LEN 20
diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig
index d7b907e..2b83282 100644
--- a/drivers/net/wireless/ti/wlcore/Kconfig
+++ b/drivers/net/wireless/ti/wlcore/Kconfig
@@ -33,8 +33,3 @@
 
 	  If you choose to build a module, it'll be called wlcore_sdio.
 	  Say N if unsure.
-
-config WL12XX_PLATFORM_DATA
-	bool
-	depends on WLCORE_SDIO != n || WL1251_SDIO != n
-	default y
diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile
index d9fba9e..b21398f 100644
--- a/drivers/net/wireless/ti/wlcore/Makefile
+++ b/drivers/net/wireless/ti/wlcore/Makefile
@@ -9,7 +9,4 @@
 obj-$(CONFIG_WLCORE_SPI)		+= wlcore_spi.o
 obj-$(CONFIG_WLCORE_SDIO)		+= wlcore_sdio.o
 
-# small builtin driver bit
-obj-$(CONFIG_WL12XX_PLATFORM_DATA)	+= wl12xx_platform_data.o
-
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index ce108a7..c796543 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1340,6 +1340,8 @@
 	kfree(acx);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities);
+
 
 int wl1271_acx_set_ht_information(struct wl1271 *wl,
 				   struct wl12xx_vif *wlvif,
@@ -1433,13 +1435,22 @@
 	acx->win_size = wl->conf.ht.rx_ba_win_size;
 	acx->ssn = ssn;
 
-	ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
-				   sizeof(*acx));
+	ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx,
+					    sizeof(*acx),
+					    BIT(CMD_STATUS_NO_RX_BA_SESSION));
 	if (ret < 0) {
 		wl1271_warning("acx ba receiver session failed: %d", ret);
 		goto out;
 	}
 
+	/* sometimes we can't start the session */
+	if (ret == CMD_STATUS_NO_RX_BA_SESSION) {
+		wl1271_warning("no fw rx ba on tid %d", tid_index);
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = 0;
 out:
 	kfree(acx);
 	return ret;
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index d03215d..126536c 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -1025,7 +1025,6 @@
 	ACX_CONFIG_HANGOVER              = 0x0042,
 	ACX_FEATURE_CFG                  = 0x0043,
 	ACX_PROTECTION_CFG               = 0x0044,
-	ACX_CHECKSUM_CONFIG              = 0x0045,
 };
 
 
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c
index 375ea57..77752b0 100644
--- a/drivers/net/wireless/ti/wlcore/boot.c
+++ b/drivers/net/wireless/ti/wlcore/boot.c
@@ -84,47 +84,57 @@
 static int wlcore_validate_fw_ver(struct wl1271 *wl)
 {
 	unsigned int *fw_ver = wl->chip.fw_ver;
-	unsigned int *min_ver = wl->min_fw_ver;
+	unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_MULTI) ?
+		wl->min_mr_fw_ver : wl->min_sr_fw_ver;
+	char min_fw_str[32] = "";
+	int i;
 
 	/* the chip must be exactly equal */
-	if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP])
+	if ((min_ver[FW_VER_CHIP] != WLCORE_FW_VER_IGNORE) &&
+	    (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]))
 		goto fail;
 
-	/* always check the next digit if all previous ones are equal */
-
-	if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE])
-		goto out;
-	else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE])
+	/* the firmware type must be equal */
+	if ((min_ver[FW_VER_IF_TYPE] != WLCORE_FW_VER_IGNORE) &&
+	    (min_ver[FW_VER_IF_TYPE] != fw_ver[FW_VER_IF_TYPE]))
 		goto fail;
 
-	if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR])
-		goto out;
-	else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR])
+	/* the project number must be equal */
+	if ((min_ver[FW_VER_SUBTYPE] != WLCORE_FW_VER_IGNORE) &&
+	    (min_ver[FW_VER_SUBTYPE] != fw_ver[FW_VER_SUBTYPE]))
 		goto fail;
 
-	if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE])
-		goto out;
-	else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE])
+	/* the API version must be greater or equal */
+	if ((min_ver[FW_VER_MAJOR] != WLCORE_FW_VER_IGNORE) &&
+		 (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]))
 		goto fail;
 
-	if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR])
-		goto out;
-	else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])
+	/* if the API version is equal... */
+	if (((min_ver[FW_VER_MAJOR] == WLCORE_FW_VER_IGNORE) ||
+	     (min_ver[FW_VER_MAJOR] == fw_ver[FW_VER_MAJOR])) &&
+	    /* ...the minor must be greater or equal */
+	    ((min_ver[FW_VER_MINOR] != WLCORE_FW_VER_IGNORE) &&
+	     (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])))
 		goto fail;
 
-out:
 	return 0;
 
 fail:
-	wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n"
-		     "Please use at least FW %u.%u.%u.%u.%u.\n"
-		     "You can get more information at:\n"
-		     "http://wireless.kernel.org/en/users/Drivers/wl12xx",
+	for (i = 0; i < NUM_FW_VER; i++)
+		if (min_ver[i] == WLCORE_FW_VER_IGNORE)
+			snprintf(min_fw_str, sizeof(min_fw_str),
+				  "%s*.", min_fw_str);
+		else
+			snprintf(min_fw_str, sizeof(min_fw_str),
+				  "%s%u.", min_fw_str, min_ver[i]);
+
+	wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n"
+		     "Please use at least FW %s\n"
+		     "You can get the latest firmwares at:\n"
+		     "git://github.com/TI-OpenLink/firmwares.git",
 		     fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE],
 		     fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
-		     fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP],
-		     min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR],
-		     min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]);
+		     fw_ver[FW_VER_MINOR], min_fw_str);
 	return -EINVAL;
 }
 
@@ -491,7 +501,7 @@
 	if (ret < 0)
 		return ret;
 
-	wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
+	wl->mbox_ptr[1] = wl->mbox_ptr[0] + wl->mbox_size;
 
 	wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
 		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
@@ -508,23 +518,6 @@
 	 */
 
 	/* unmask required mbox events  */
-	wl->event_mask = BSS_LOSE_EVENT_ID |
-		REGAINED_BSS_EVENT_ID |
-		SCAN_COMPLETE_EVENT_ID |
-		ROLE_STOP_COMPLETE_EVENT_ID |
-		RSSI_SNR_TRIGGER_0_EVENT_ID |
-		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
-		SOFT_GEMINI_SENSE_EVENT_ID |
-		PERIODIC_SCAN_REPORT_EVENT_ID |
-		PERIODIC_SCAN_COMPLETE_EVENT_ID |
-		DUMMY_PACKET_EVENT_ID |
-		PEER_REMOVE_COMPLETE_EVENT_ID |
-		BA_SESSION_RX_CONSTRAINT_EVENT_ID |
-		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
-		INACTIVE_STA_EVENT_ID |
-		MAX_TX_RETRY_EVENT_ID |
-		CHANNEL_SWITCH_COMPLETE_EVENT_ID;
-
 	ret = wl1271_event_unmask(wl);
 	if (ret < 0) {
 		wl1271_error("EVENT mask setting failed");
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 27f83f7..6331f9e 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -48,14 +48,15 @@
  * @id: command id
  * @buf: buffer containing the command, must work with dma
  * @len: length of the buffer
+ * return the cmd status code on success.
  */
-int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
-		    size_t res_len)
+static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf,
+			     size_t len, size_t res_len)
 {
 	struct wl1271_cmd_header *cmd;
 	unsigned long timeout;
 	u32 intr;
-	int ret = 0;
+	int ret;
 	u16 status;
 	u16 poll_count = 0;
 
@@ -71,7 +72,7 @@
 
 	ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false);
 	if (ret < 0)
-		goto fail;
+		return ret;
 
 	/*
 	 * TODO: we just need this because one bit is in a different
@@ -79,19 +80,18 @@
 	 */
 	ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
 	if (ret < 0)
-		goto fail;
+		return ret;
 
 	timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
 
 	ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
 	if (ret < 0)
-		goto fail;
+		return ret;
 
 	while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
 		if (time_after(jiffies, timeout)) {
 			wl1271_error("command complete timeout");
-			ret = -ETIMEDOUT;
-			goto fail;
+			return -ETIMEDOUT;
 		}
 
 		poll_count++;
@@ -102,7 +102,7 @@
 
 		ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
 		if (ret < 0)
-			goto fail;
+			return ret;
 	}
 
 	/* read back the status code of the command */
@@ -111,33 +111,66 @@
 
 	ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false);
 	if (ret < 0)
-		goto fail;
+		return ret;
 
 	status = le16_to_cpu(cmd->status);
-	if (status != CMD_STATUS_SUCCESS) {
-		wl1271_error("command execute failure %d", status);
-		ret = -EIO;
-		goto fail;
-	}
 
 	ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
 			       WL1271_ACX_INTR_CMD_COMPLETE);
 	if (ret < 0)
+		return ret;
+
+	return status;
+}
+
+/*
+ * send command to fw and return cmd status on success
+ * valid_rets contains a bitmap of allowed error codes
+ */
+int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len,
+			     size_t res_len, unsigned long valid_rets)
+{
+	int ret = __wlcore_cmd_send(wl, id, buf, len, res_len);
+
+	if (ret < 0)
 		goto fail;
 
-	return 0;
+	/* success is always a valid status */
+	valid_rets |= BIT(CMD_STATUS_SUCCESS);
 
+	if (ret >= MAX_COMMAND_STATUS ||
+	    !test_bit(ret, &valid_rets)) {
+		wl1271_error("command execute failure %d", ret);
+		ret = -EIO;
+		goto fail;
+	}
+	return ret;
 fail:
 	wl12xx_queue_recovery_work(wl);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_cmd_send);
+
+/*
+ * wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS
+ * return 0 on success.
+ */
+int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
+		    size_t res_len)
+{
+	int ret = wlcore_cmd_send_failsafe(wl, id, buf, len, res_len, 0);
+
+	if (ret < 0)
+		return ret;
+	return 0;
+}
 
 /*
  * Poll the mailbox event field until any of the bits in the mask is set or a
  * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
  */
-static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
-						u32 mask, bool *timeout)
+int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+					 u32 mask, bool *timeout)
 {
 	u32 *events_vector;
 	u32 event;
@@ -187,20 +220,7 @@
 	kfree(events_vector);
 	return ret;
 }
-
-static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
-{
-	int ret;
-	bool timeout = false;
-
-	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
-	if (ret != 0 || timeout) {
-		wl12xx_queue_recovery_work(wl);
-		return ret;
-	}
-
-	return 0;
-}
+EXPORT_SYMBOL_GPL(wlcore_cmd_wait_for_event_or_timeout);
 
 int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
 			   u8 *role_id)
@@ -278,6 +298,16 @@
 	return ret;
 }
 
+static int wlcore_get_new_session_id(struct wl1271 *wl, u8 hlid)
+{
+	if (wl->session_ids[hlid] >= SESSION_COUNTER_MAX)
+		wl->session_ids[hlid] = 0;
+
+	wl->session_ids[hlid]++;
+
+	return wl->session_ids[hlid];
+}
+
 int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
 {
 	unsigned long flags;
@@ -285,12 +315,21 @@
 	if (link >= WL12XX_MAX_LINKS)
 		return -EBUSY;
 
+	wl->session_ids[link] = wlcore_get_new_session_id(wl, link);
+
 	/* these bits are used by op_tx */
 	spin_lock_irqsave(&wl->wl_lock, flags);
 	__set_bit(link, wl->links_map);
 	__set_bit(link, wlvif->links_map);
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+	/* take the last "freed packets" value from the current FW status */
+	wl->links[link].prev_freed_pkts =
+			wl->fw_status_2->counters.tx_lnk_free_pkts[link];
+	wl->links[link].wlvif = wlvif;
 	*hlid = link;
+
+	wl->active_link_count++;
 	return 0;
 }
 
@@ -307,24 +346,21 @@
 	__clear_bit(*hlid, wlvif->links_map);
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 
+	wl->links[*hlid].allocated_pkts = 0;
+	wl->links[*hlid].prev_freed_pkts = 0;
+	wl->links[*hlid].ba_bitmap = 0;
+	memset(wl->links[*hlid].addr, 0, ETH_ALEN);
+
 	/*
 	 * At this point op_tx() will not add more packets to the queues. We
 	 * can purge them.
 	 */
 	wl1271_tx_reset_link_queues(wl, *hlid);
+	wl->links[*hlid].wlvif = NULL;
 
 	*hlid = WL12XX_INVALID_LINK_ID;
-}
-
-static int wl12xx_get_new_session_id(struct wl1271 *wl,
-				     struct wl12xx_vif *wlvif)
-{
-	if (wlvif->session_counter >= SESSION_COUNTER_MAX)
-		wlvif->session_counter = 0;
-
-	wlvif->session_counter++;
-
-	return wlvif->session_counter;
+	wl->active_link_count--;
+	WARN_ON_ONCE(wl->active_link_count < 0);
 }
 
 static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
@@ -345,7 +381,9 @@
 }
 
 static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
-				     struct wl12xx_vif *wlvif)
+				     struct wl12xx_vif *wlvif,
+				     enum ieee80211_band band,
+				     int channel)
 {
 	struct wl12xx_cmd_role_start *cmd;
 	int ret;
@@ -359,9 +397,9 @@
 	wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id);
 
 	cmd->role_id = wlvif->dev_role_id;
-	if (wlvif->band == IEEE80211_BAND_5GHZ)
+	if (band == IEEE80211_BAND_5GHZ)
 		cmd->band = WLCORE_BAND_5GHZ;
-	cmd->channel = wlvif->channel;
+	cmd->channel = channel;
 
 	if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
 		ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid);
@@ -369,7 +407,7 @@
 			goto out_free;
 	}
 	cmd->device.hlid = wlvif->dev_hlid;
-	cmd->device.session = wl12xx_get_new_session_id(wl, wlvif);
+	cmd->device.session = wl->session_ids[wlvif->dev_hlid];
 
 	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
 		     cmd->role_id, cmd->device.hlid, cmd->device.session);
@@ -420,12 +458,6 @@
 		goto out_free;
 	}
 
-	ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID);
-	if (ret < 0) {
-		wl1271_error("cmd role stop dev event completion error");
-		goto out_free;
-	}
-
 	wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
 
 out_free:
@@ -439,6 +471,7 @@
 {
 	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 	struct wl12xx_cmd_role_start *cmd;
+	u32 supported_rates;
 	int ret;
 
 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -459,7 +492,14 @@
 	cmd->sta.ssid_len = wlvif->ssid_len;
 	memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
 	memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
-	cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
+
+	supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
+			  wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+	if (wlvif->p2p)
+		supported_rates &= ~CONF_TX_CCK_RATES;
+
+	cmd->sta.local_rates = cpu_to_le32(supported_rates);
+
 	cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
 
 	if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
@@ -468,8 +508,14 @@
 			goto out_free;
 	}
 	cmd->sta.hlid = wlvif->sta.hlid;
-	cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif);
-	cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
+	cmd->sta.session = wl->session_ids[wlvif->sta.hlid];
+	/*
+	 * We don't have the correct remote rates in this stage.  The
+	 * rates will be reconfigured later, after association, if the
+	 * firmware supports ACX_PEER_CAP.  Otherwise, there's nothing
+	 * we can do, so use all supported_rates here.
+	 */
+	cmd->sta.remote_rates = cpu_to_le32(supported_rates);
 
 	wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
 		     "basic_rate_set: 0x%x, remote_rates: 0x%x",
@@ -482,6 +528,7 @@
 		goto err_hlid;
 	}
 
+	wlvif->sta.role_chan_type = wlvif->channel_type;
 	goto out_free;
 
 err_hlid:
@@ -500,7 +547,6 @@
 {
 	struct wl12xx_cmd_role_stop *cmd;
 	int ret;
-	bool timeout = false;
 
 	if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID))
 		return -EINVAL;
@@ -523,17 +569,6 @@
 		goto out_free;
 	}
 
-	/*
-	 * Sometimes the firmware doesn't send this event, so we just
-	 * time out without failing.  Queue recovery for other
-	 * failures.
-	 */
-	ret = wl1271_cmd_wait_for_event_or_timeout(wl,
-						   ROLE_STOP_COMPLETE_EVENT_ID,
-						   &timeout);
-	if (ret)
-		wl12xx_queue_recovery_work(wl);
-
 	wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
 
 out_free:
@@ -579,12 +614,15 @@
 	cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
 	cmd->ap.global_hlid = wlvif->ap.global_hlid;
 	cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid;
+	cmd->ap.global_session_id = wl->session_ids[wlvif->ap.global_hlid];
+	cmd->ap.bcast_session_id = wl->session_ids[wlvif->ap.bcast_hlid];
 	cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
 	cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
 	cmd->ap.dtim_interval = bss_conf->dtim_period;
 	cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
 	/* FIXME: Change when adding DFS */
 	cmd->ap.reset_tsf = 1;  /* By default reset AP TSF */
+	cmd->ap.wmm = wlvif->wmm_enabled;
 	cmd->channel = wlvif->channel;
 	cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
 
@@ -599,8 +637,10 @@
 		memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
 	}
 
-	supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES |
+	supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
 		wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
+	if (wlvif->p2p)
+		supported_rates &= ~CONF_TX_CCK_RATES;
 
 	wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x",
 		     supported_rates);
@@ -799,8 +839,11 @@
  * @id: acx id
  * @buf: buffer containing acx, including all headers, must work with dma
  * @len: length of buf
+ * @valid_rets: bitmap of valid cmd status codes (i.e. return values).
+ * return the cmd status on success.
  */
-int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
+int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
+				  size_t len, unsigned long valid_rets)
 {
 	struct acx_header *acx = buf;
 	int ret;
@@ -812,12 +855,26 @@
 	/* payload length, does not include any headers */
 	acx->len = cpu_to_le16(len - sizeof(*acx));
 
-	ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0);
+	ret = wlcore_cmd_send_failsafe(wl, CMD_CONFIGURE, acx, len, 0,
+				       valid_rets);
 	if (ret < 0) {
 		wl1271_warning("CONFIGURE command NOK");
 		return ret;
 	}
 
+	return ret;
+}
+
+/*
+ * wrapper for wlcore_cmd_configure that accepts only success status.
+ * return 0 on success
+ */
+int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
+{
+	int ret = wlcore_cmd_configure_failsafe(wl, id, buf, len, 0);
+
+	if (ret < 0)
+		return ret;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(wl1271_cmd_configure);
@@ -1034,8 +1091,8 @@
 	struct sk_buff *skb;
 	int ret;
 	u32 rate;
-	u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
-	u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+	u16 template_id_2_4 = wl->scan_templ_id_2_4;
+	u16 template_id_5 = wl->scan_templ_id_5;
 
 	skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
 				     ie_len);
@@ -1048,10 +1105,10 @@
 
 	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
 
-	if (!sched_scan &&
+	if (sched_scan &&
 	    (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {
-		template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4;
-		template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5;
+		template_id_2_4 = wl->sched_scan_templ_id_2_4;
+		template_id_5 = wl->sched_scan_templ_id_5;
 	}
 
 	rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
@@ -1068,6 +1125,7 @@
 	dev_kfree_skb(skb);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(wl12xx_cmd_build_probe_req);
 
 struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
 					      struct wl12xx_vif *wlvif,
@@ -1379,7 +1437,8 @@
 	return ret;
 }
 
-int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			      u8 hlid)
 {
 	struct wl12xx_cmd_set_peer_state *cmd;
 	int ret = 0;
@@ -1395,6 +1454,10 @@
 	cmd->hlid = hlid;
 	cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
 
+	/* wmm param is valid only for station role */
+	if (wlvif->bss_type == BSS_TYPE_STA_BSS)
+		cmd->wmm = wlvif->wmm_enabled;
+
 	ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
 	if (ret < 0) {
 		wl1271_error("failed to send set peer state command");
@@ -1429,6 +1492,7 @@
 	cmd->hlid = hlid;
 	cmd->sp_len = sta->max_sp;
 	cmd->wmm = sta->wme ? 1 : 0;
+	cmd->session_id = wl->session_ids[hlid];
 
 	for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
 		if (sta->wme && (sta->uapsd_queues & BIT(i)))
@@ -1490,9 +1554,10 @@
 		goto out_free;
 	}
 
-	ret = wl1271_cmd_wait_for_event_or_timeout(wl,
-					   PEER_REMOVE_COMPLETE_EVENT_ID,
-					   &timeout);
+	ret = wl->ops->wait_for_event(wl,
+				      WLCORE_EVENT_PEER_REMOVE_COMPLETE,
+				      &timeout);
+
 	/*
 	 * We are ok with a timeout here. The event is sometimes not sent
 	 * due to a firmware bug. In case of another error (like SDIO timeout)
@@ -1508,6 +1573,131 @@
 	return ret;
 }
 
+static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch)
+{
+	int idx = -1;
+
+	switch (band) {
+	case IEEE80211_BAND_5GHZ:
+		if (ch >= 8 && ch <= 16)
+			idx = ((ch-8)/4 + 18);
+		else if (ch >= 34 && ch <= 64)
+			idx = ((ch-34)/2 + 3 + 18);
+		else if (ch >= 100 && ch <= 140)
+			idx = ((ch-100)/4 + 15 + 18);
+		else if (ch >= 149 && ch <= 165)
+			idx = ((ch-149)/4 + 26 + 18);
+		else
+			idx = -1;
+		break;
+	case IEEE80211_BAND_2GHZ:
+		if (ch >= 1 && ch <= 14)
+			idx = ch - 1;
+		else
+			idx = -1;
+		break;
+	default:
+		wl1271_error("get reg conf ch idx - unknown band: %d",
+			     (int)band);
+	}
+
+	return idx;
+}
+
+void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
+				     enum ieee80211_band band)
+{
+	int ch_bit_idx = 0;
+
+	if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
+		return;
+
+	ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel);
+
+	if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
+		set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending);
+}
+
+int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
+{
+	struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL;
+	int ret = 0, i, b, ch_bit_idx;
+	struct ieee80211_channel *channel;
+	u32 tmp_ch_bitmap[2];
+	u16 ch;
+	struct wiphy *wiphy = wl->hw->wiphy;
+	struct ieee80211_supported_band *band;
+	bool timeout = false;
+
+	if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
+		return 0;
+
+	wl1271_debug(DEBUG_CMD, "cmd reg domain config");
+
+	memset(tmp_ch_bitmap, 0, sizeof(tmp_ch_bitmap));
+
+	for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) {
+		band = wiphy->bands[b];
+		for (i = 0; i < band->n_channels; i++) {
+			channel = &band->channels[i];
+			ch = channel->hw_value;
+
+			if (channel->flags & (IEEE80211_CHAN_DISABLED |
+					      IEEE80211_CHAN_RADAR |
+					      IEEE80211_CHAN_PASSIVE_SCAN))
+				continue;
+
+			ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
+			if (ch_bit_idx < 0)
+				continue;
+
+			set_bit(ch_bit_idx, (long *)tmp_ch_bitmap);
+		}
+	}
+
+	tmp_ch_bitmap[0] |= wl->reg_ch_conf_pending[0];
+	tmp_ch_bitmap[1] |= wl->reg_ch_conf_pending[1];
+
+	if (!memcmp(tmp_ch_bitmap, wl->reg_ch_conf_last, sizeof(tmp_ch_bitmap)))
+		goto out;
+
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]);
+	cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]);
+
+	wl1271_debug(DEBUG_CMD,
+		     "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x",
+		     cmd->ch_bit_map1, cmd->ch_bit_map2);
+
+	ret = wl1271_cmd_send(wl, CMD_DFS_CHANNEL_CONFIG, cmd, sizeof(*cmd), 0);
+	if (ret < 0) {
+		wl1271_error("failed to send reg domain dfs config");
+		goto out;
+	}
+
+	ret = wl->ops->wait_for_event(wl,
+				      WLCORE_EVENT_DFS_CONFIG_COMPLETE,
+				      &timeout);
+	if (ret < 0 || timeout) {
+		wl1271_error("reg domain conf %serror",
+			     timeout ? "completion " : "");
+		ret = timeout ? -ETIMEDOUT : ret;
+		goto out;
+	}
+
+	memcpy(wl->reg_ch_conf_last, tmp_ch_bitmap, sizeof(tmp_ch_bitmap));
+	memset(wl->reg_ch_conf_pending, 0, sizeof(wl->reg_ch_conf_pending));
+
+out:
+	kfree(cmd);
+	return ret;
+}
+
 int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
 {
 	struct wl12xx_cmd_config_fwlog *cmd;
@@ -1593,12 +1783,12 @@
 }
 
 static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-			  u8 role_id)
+			  u8 role_id, enum ieee80211_band band, u8 channel)
 {
 	struct wl12xx_cmd_roc *cmd;
 	int ret = 0;
 
-	wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id);
+	wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", channel, role_id);
 
 	if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
 		return -EINVAL;
@@ -1610,8 +1800,8 @@
 	}
 
 	cmd->role_id = role_id;
-	cmd->channel = wlvif->channel;
-	switch (wlvif->band) {
+	cmd->channel = channel;
+	switch (band) {
 	case IEEE80211_BAND_2GHZ:
 		cmd->band = WLCORE_BAND_2_4GHZ;
 		break;
@@ -1666,30 +1856,18 @@
 	return ret;
 }
 
-int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
+int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
+	       enum ieee80211_band band, u8 channel)
 {
 	int ret = 0;
-	bool is_first_roc;
 
 	if (WARN_ON(test_bit(role_id, wl->roc_map)))
 		return 0;
 
-	is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >=
-			WL12XX_MAX_ROLES);
-
-	ret = wl12xx_cmd_roc(wl, wlvif, role_id);
+	ret = wl12xx_cmd_roc(wl, wlvif, role_id, band, channel);
 	if (ret < 0)
 		goto out;
 
-	if (is_first_roc) {
-		ret = wl1271_cmd_wait_for_event(wl,
-					   REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
-		if (ret < 0) {
-			wl1271_error("cmd roc event completion error");
-			goto out;
-		}
-	}
-
 	__set_bit(role_id, wl->roc_map);
 out:
 	return ret;
@@ -1719,43 +1897,7 @@
 	return ret;
 }
 
-int wl12xx_cmd_channel_switch(struct wl1271 *wl,
-			      struct wl12xx_vif *wlvif,
-			      struct ieee80211_channel_switch *ch_switch)
-{
-	struct wl12xx_cmd_channel_switch *cmd;
-	int ret;
-
-	wl1271_debug(DEBUG_ACX, "cmd channel switch");
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (!cmd) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	cmd->role_id = wlvif->role_id;
-	cmd->channel = ch_switch->channel->hw_value;
-	cmd->switch_time = ch_switch->count;
-	cmd->stop_tx = ch_switch->block_tx;
-
-	/* FIXME: control from mac80211 in the future */
-	cmd->post_switch_tx_disable = 0;  /* Enable TX on the target channel */
-
-	ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
-	if (ret < 0) {
-		wl1271_error("failed to send channel switch command");
-		goto out_free;
-	}
-
-out_free:
-	kfree(cmd);
-
-out:
-	return ret;
-}
-
-int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
+int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
 	struct wl12xx_cmd_stop_channel_switch *cmd;
 	int ret;
@@ -1768,6 +1910,8 @@
 		goto out;
 	}
 
+	cmd->role_id = wlvif->role_id;
+
 	ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0);
 	if (ret < 0) {
 		wl1271_error("failed to stop channel switch command");
@@ -1782,7 +1926,8 @@
 }
 
 /* start dev role and roc on its channel */
-int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+		     enum ieee80211_band band, int channel)
 {
 	int ret;
 
@@ -1797,11 +1942,11 @@
 	if (ret < 0)
 		goto out;
 
-	ret = wl12xx_cmd_role_start_dev(wl, wlvif);
+	ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel);
 	if (ret < 0)
 		goto out_disable;
 
-	ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
+	ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id, band, channel);
 	if (ret < 0)
 		goto out_stop;
 
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 2409f3d..fd34123 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -31,6 +31,8 @@
 
 int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
 		    size_t res_len);
+int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len,
+			     size_t res_len, unsigned long valid_rets);
 int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
 			   u8 *role_id);
 int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
@@ -39,11 +41,14 @@
 int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+		     enum ieee80211_band band, int channel);
 int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
+int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
+				  size_t len, unsigned long valid_rets);
 int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		       u8 ps_mode, u16 auto_ps_timeout);
@@ -75,22 +80,30 @@
 			  u16 action, u8 id, u8 key_type,
 			  u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
 			  u16 tx_seq_16);
-int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
-int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id);
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			      u8 hlid);
+int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
+	       enum ieee80211_band band, u8 channel);
 int wl12xx_croc(struct wl1271 *wl, u8 role_id);
 int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			struct ieee80211_sta *sta, u8 hlid);
 int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
+void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
+				     enum ieee80211_band band);
+int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl);
 int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
 int wl12xx_cmd_channel_switch(struct wl1271 *wl,
 			      struct wl12xx_vif *wlvif,
 			      struct ieee80211_channel_switch *ch_switch);
-int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
+int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl,
+				   struct wl12xx_vif *wlvif);
 int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			 u8 *hlid);
 void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
+int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+					 u32 mask, bool *timeout);
 
 enum wl1271_commands {
 	CMD_INTERROGATE	= 1, /* use this to read information elements */
@@ -149,8 +162,11 @@
 	CMD_WFD_START_DISCOVERY	= 45,
 	CMD_WFD_STOP_DISCOVERY	= 46,
 	CMD_WFD_ATTRIBUTE_CONFIG	= 47,
-	CMD_NOP			= 48,
-	CMD_LAST_COMMAND,
+	CMD_GENERIC_CFG			= 48,
+	CMD_NOP				= 49,
+
+	/* start of 18xx specific commands */
+	CMD_DFS_CHANNEL_CONFIG		= 60,
 
 	MAX_COMMAND_ID = 0xFFFF,
 };
@@ -167,8 +183,8 @@
 	CMD_TEMPL_PS_POLL,
 	CMD_TEMPL_KLV,
 	CMD_TEMPL_DISCONNECT,
-	CMD_TEMPL_APP_PROBE_REQ_2_4,
-	CMD_TEMPL_APP_PROBE_REQ_5,
+	CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY,
+	CMD_TEMPL_APP_PROBE_REQ_5_LEGACY,
 	CMD_TEMPL_BAR,           /* for firmware internal use only */
 	CMD_TEMPL_CTS,           /*
 				  * For CTS-to-self (FastCTS) mechanism
@@ -179,6 +195,8 @@
 	CMD_TEMPL_DEAUTH_AP,
 	CMD_TEMPL_TEMPORARY,
 	CMD_TEMPL_LINK_MEASUREMENT_REPORT,
+	CMD_TEMPL_PROBE_REQ_2_4_PERIODIC,
+	CMD_TEMPL_PROBE_REQ_5_PERIODIC,
 
 	CMD_TEMPL_MAX = 0xff
 };
@@ -220,7 +238,8 @@
 	CMD_STATUS_FW_RESET		= 22, /* Driver internal use.*/
 	CMD_STATUS_TEMPLATE_OOM		= 23,
 	CMD_STATUS_NO_RX_BA_SESSION	= 24,
-	MAX_COMMAND_STATUS		= 0xff
+
+	MAX_COMMAND_STATUS
 };
 
 #define CMDMBOX_HEADER_LEN 4
@@ -345,7 +364,15 @@
 
 			u8 reset_tsf;
 
-			u8 padding_1[4];
+			/*
+			 * ap supports wmm (note that there is additional
+			 * per-sta wmm configuration)
+			 */
+			u8 wmm;
+
+			u8 bcast_session_id;
+			u8 global_session_id;
+			u8 padding_1[1];
 		} __packed ap;
 	};
 } __packed;
@@ -515,7 +542,14 @@
 
 	u8 hlid;
 	u8 state;
-	u8 padding[2];
+
+	/*
+	 * wmm is relevant for sta role only.
+	 * ap role configures the per-sta wmm params in
+	 * the add_peer command.
+	 */
+	u8 wmm;
+	u8 padding[1];
 } __packed;
 
 struct wl12xx_cmd_roc {
@@ -558,7 +592,7 @@
 	u8 bss_index;
 	u8 sp_len;
 	u8 wmm;
-	u8 padding1;
+	u8 session_id;
 } __packed;
 
 struct wl12xx_cmd_remove_peer {
@@ -597,6 +631,13 @@
 	WL12XX_FWLOG_OUTPUT_HOST,
 };
 
+struct wl12xx_cmd_regdomain_dfs_config {
+	struct wl1271_cmd_header header;
+
+	__le32 ch_bit_map1;
+	__le32 ch_bit_map2;
+} __packed;
+
 struct wl12xx_cmd_config_fwlog {
 	struct wl1271_cmd_header header;
 
@@ -626,27 +667,13 @@
 	struct wl1271_cmd_header header;
 } __packed;
 
-struct wl12xx_cmd_channel_switch {
+struct wl12xx_cmd_stop_channel_switch {
 	struct wl1271_cmd_header header;
 
 	u8 role_id;
-
-	/* The new serving channel */
-	u8 channel;
-	/* Relative time of the serving channel switch in TBTT units */
-	u8 switch_time;
-	/* Stop the role TX, should expect it after radar detection */
-	u8 stop_tx;
-	/* The target channel tx status 1-stopped 0-open*/
-	u8 post_switch_tx_disable;
-
 	u8 padding[3];
 } __packed;
 
-struct wl12xx_cmd_stop_channel_switch {
-	struct wl1271_cmd_header header;
-} __packed;
-
 /* Used to check radio status after calibration */
 #define MAX_TLV_LENGTH		500
 #define TEST_CMD_P2G_CAL	2	/* TX BiP */
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index 9e40760..2b96ff8 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -57,20 +57,49 @@
 };
 
 enum {
-	CONF_HW_RATE_INDEX_1MBPS   = 0,
-	CONF_HW_RATE_INDEX_2MBPS   = 1,
-	CONF_HW_RATE_INDEX_5_5MBPS = 2,
-	CONF_HW_RATE_INDEX_6MBPS   = 3,
-	CONF_HW_RATE_INDEX_9MBPS   = 4,
-	CONF_HW_RATE_INDEX_11MBPS  = 5,
-	CONF_HW_RATE_INDEX_12MBPS  = 6,
-	CONF_HW_RATE_INDEX_18MBPS  = 7,
-	CONF_HW_RATE_INDEX_22MBPS  = 8,
-	CONF_HW_RATE_INDEX_24MBPS  = 9,
-	CONF_HW_RATE_INDEX_36MBPS  = 10,
-	CONF_HW_RATE_INDEX_48MBPS  = 11,
-	CONF_HW_RATE_INDEX_54MBPS  = 12,
-	CONF_HW_RATE_INDEX_MAX     = CONF_HW_RATE_INDEX_54MBPS,
+	CONF_HW_RATE_INDEX_1MBPS      = 0,
+	CONF_HW_RATE_INDEX_2MBPS      = 1,
+	CONF_HW_RATE_INDEX_5_5MBPS    = 2,
+	CONF_HW_RATE_INDEX_11MBPS     = 3,
+	CONF_HW_RATE_INDEX_6MBPS      = 4,
+	CONF_HW_RATE_INDEX_9MBPS      = 5,
+	CONF_HW_RATE_INDEX_12MBPS     = 6,
+	CONF_HW_RATE_INDEX_18MBPS     = 7,
+	CONF_HW_RATE_INDEX_24MBPS     = 8,
+	CONF_HW_RATE_INDEX_36MBPS     = 9,
+	CONF_HW_RATE_INDEX_48MBPS     = 10,
+	CONF_HW_RATE_INDEX_54MBPS     = 11,
+	CONF_HW_RATE_INDEX_MCS0       = 12,
+	CONF_HW_RATE_INDEX_MCS1       = 13,
+	CONF_HW_RATE_INDEX_MCS2       = 14,
+	CONF_HW_RATE_INDEX_MCS3       = 15,
+	CONF_HW_RATE_INDEX_MCS4       = 16,
+	CONF_HW_RATE_INDEX_MCS5       = 17,
+	CONF_HW_RATE_INDEX_MCS6       = 18,
+	CONF_HW_RATE_INDEX_MCS7       = 19,
+	CONF_HW_RATE_INDEX_MCS7_SGI   = 20,
+	CONF_HW_RATE_INDEX_MCS0_40MHZ = 21,
+	CONF_HW_RATE_INDEX_MCS1_40MHZ = 22,
+	CONF_HW_RATE_INDEX_MCS2_40MHZ = 23,
+	CONF_HW_RATE_INDEX_MCS3_40MHZ = 24,
+	CONF_HW_RATE_INDEX_MCS4_40MHZ = 25,
+	CONF_HW_RATE_INDEX_MCS5_40MHZ = 26,
+	CONF_HW_RATE_INDEX_MCS6_40MHZ = 27,
+	CONF_HW_RATE_INDEX_MCS7_40MHZ = 28,
+	CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI = 29,
+
+	/* MCS8+ rates overlap with 40Mhz rates */
+	CONF_HW_RATE_INDEX_MCS8       = 21,
+	CONF_HW_RATE_INDEX_MCS9       = 22,
+	CONF_HW_RATE_INDEX_MCS10      = 23,
+	CONF_HW_RATE_INDEX_MCS11      = 24,
+	CONF_HW_RATE_INDEX_MCS12      = 25,
+	CONF_HW_RATE_INDEX_MCS13      = 26,
+	CONF_HW_RATE_INDEX_MCS14      = 27,
+	CONF_HW_RATE_INDEX_MCS15      = 28,
+	CONF_HW_RATE_INDEX_MCS15_SGI  = 29,
+
+	CONF_HW_RATE_INDEX_MAX        = CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI,
 };
 
 #define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff
@@ -415,11 +444,11 @@
 #define CONF_TX_RATE_MASK_BASIC_P2P    CONF_HW_BIT_RATE_6MBPS
 
 /*
- * Rates supported for data packets when operating as AP. Note the absence
+ * Rates supported for data packets when operating as STA/AP. Note the absence
  * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
  * one. The rate dropped is not mandatory under any operating mode.
  */
-#define CONF_TX_AP_ENABLED_RATES       (CONF_HW_BIT_RATE_1MBPS | \
+#define CONF_TX_ENABLED_RATES       (CONF_HW_BIT_RATE_1MBPS |    \
 	CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS |      \
 	CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS |        \
 	CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS |      \
@@ -677,6 +706,18 @@
 
 	/* Time in ms for Tx watchdog timer to expire */
 	u32 tx_watchdog_timeout;
+
+	/*
+	 * when a slow link has this much packets pending, it becomes a low
+	 * priority link, scheduling-wise
+	 */
+	u8 slow_link_thold;
+
+	/*
+	 * when a fast link has this much packets pending, it becomes a low
+	 * priority link, scheduling-wise
+	 */
+	u8 fast_link_thold;
 } __packed;
 
 enum {
@@ -1047,6 +1088,7 @@
 struct conf_scan_settings {
 	/*
 	 * The minimum time to wait on each channel for active scans
+	 * This value will be used whenever there's a connected interface.
 	 *
 	 * Range: u32 tu/1000
 	 */
@@ -1054,24 +1096,37 @@
 
 	/*
 	 * The maximum time to wait on each channel for active scans
+	 * This value will be currently used whenever there's a
+	 * connected interface. It shouldn't exceed 30000 (~30ms) to avoid
+	 * possible interference of voip traffic going on while scanning.
 	 *
 	 * Range: u32 tu/1000
 	 */
 	u32 max_dwell_time_active;
 
-	/*
-	 * The minimum time to wait on each channel for passive scans
+	/* The minimum time to wait on each channel for active scans
+	 * when it's possible to have longer scan dwell times.
+	 * Currently this is used whenever we're idle on all interfaces.
+	 * Longer dwell times improve detection of networks within a
+	 * single scan.
 	 *
 	 * Range: u32 tu/1000
 	 */
-	u32 min_dwell_time_passive;
+	u32 min_dwell_time_active_long;
 
-	/*
-	 * The maximum time to wait on each channel for passive scans
+	/* The maximum time to wait on each channel for active scans
+	 * when it's possible to have longer scan dwell times.
+	 * See min_dwell_time_active_long
 	 *
 	 * Range: u32 tu/1000
 	 */
-	u32 max_dwell_time_passive;
+	u32 max_dwell_time_active_long;
+
+	/* time to wait on the channel for passive scans (in TU/1000) */
+	u32 dwell_time_passive;
+
+	/* time to wait on the channel for DFS scans (in TU/1000) */
+	u32 dwell_time_dfs;
 
 	/*
 	 * Number of probe requests to transmit on each active scan channel
@@ -1276,12 +1331,20 @@
 	u8 window_size;
 } __packed;
 
+struct conf_recovery_settings {
+	/* BUG() on fw recovery */
+	u8 bug_on_recovery;
+
+	/* Prevent HW recovery. FW will remain stuck. */
+	u8 no_recovery;
+} __packed;
+
 /*
  * The conf version consists of 4 bytes.  The two MSB are the wlcore
  * version, the two LSB are the lower driver's private conf
  * version.
  */
-#define WLCORE_CONF_VERSION	(0x0002 << 16)
+#define WLCORE_CONF_VERSION	(0x0005 << 16)
 #define WLCORE_CONF_MASK	0xffff0000
 #define WLCORE_CONF_SIZE	(sizeof(struct wlcore_conf_header) +	\
 				 sizeof(struct wlcore_conf))
@@ -1309,6 +1372,7 @@
 	struct conf_fwlog fwlog;
 	struct conf_rate_policy_settings rate;
 	struct conf_hangover_settings hangover;
+	struct conf_recovery_settings recovery;
 } __packed;
 
 struct wlcore_conf_file {
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index c86bb00..e70a7c8 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -490,7 +490,7 @@
 	DRIVER_STATE_PRINT_HEX(chip.id);
 	DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
 	DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);
-	DRIVER_STATE_PRINT_INT(sched_scanning);
+	DRIVER_STATE_PRINT_INT(recovery_count);
 
 #undef DRIVER_STATE_PRINT_INT
 #undef DRIVER_STATE_PRINT_LONG
@@ -560,7 +560,6 @@
 		if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
 		    wlvif->bss_type == BSS_TYPE_IBSS) {
 			VIF_STATE_PRINT_INT(sta.hlid);
-			VIF_STATE_PRINT_INT(sta.ba_rx_bitmap);
 			VIF_STATE_PRINT_INT(sta.basic_rate_idx);
 			VIF_STATE_PRINT_INT(sta.ap_rate_idx);
 			VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
@@ -577,6 +576,10 @@
 			VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]);
 		}
 		VIF_STATE_PRINT_INT(last_tx_hlid);
+		VIF_STATE_PRINT_INT(tx_queue_count[0]);
+		VIF_STATE_PRINT_INT(tx_queue_count[1]);
+		VIF_STATE_PRINT_INT(tx_queue_count[2]);
+		VIF_STATE_PRINT_INT(tx_queue_count[3]);
 		VIF_STATE_PRINT_LHEX(links_map[0]);
 		VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len);
 		VIF_STATE_PRINT_INT(band);
@@ -589,7 +592,6 @@
 		VIF_STATE_PRINT_INT(beacon_int);
 		VIF_STATE_PRINT_INT(default_key);
 		VIF_STATE_PRINT_INT(aid);
-		VIF_STATE_PRINT_INT(session_counter);
 		VIF_STATE_PRINT_INT(psm_entry_retry);
 		VIF_STATE_PRINT_INT(power_level);
 		VIF_STATE_PRINT_INT(rssi_thold);
@@ -993,7 +995,7 @@
 		return -EINVAL;
 	}
 
-	if (value < 0 || value > WL1271_PSM_MAX) {
+	if (value > WL1271_PSM_MAX) {
 		wl1271_warning("sleep_auth must be between 0 and %d",
 			       WL1271_PSM_MAX);
 		return -ERANGE;
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 4890705..70f289a 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -29,34 +29,39 @@
 #include "scan.h"
 #include "wl12xx_80211.h"
 
-static void wl1271_event_rssi_trigger(struct wl1271 *wl,
-				      struct wl12xx_vif *wlvif,
-				      struct event_mailbox *mbox)
+void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr)
 {
-	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+	struct wl12xx_vif *wlvif;
+	struct ieee80211_vif *vif;
 	enum nl80211_cqm_rssi_threshold_event event;
-	s8 metric = mbox->rssi_snr_trigger_metric[0];
+	s8 metric = metric_arr[0];
 
 	wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);
 
-	if (metric <= wlvif->rssi_thold)
-		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
-	else
-		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
+	/* TODO: check actual multi-role support */
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		if (metric <= wlvif->rssi_thold)
+			event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+		else
+			event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
 
-	if (event != wlvif->last_rssi_event)
-		ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
-	wlvif->last_rssi_event = event;
+		vif = wl12xx_wlvif_to_vif(wlvif);
+		if (event != wlvif->last_rssi_event)
+			ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
+		wlvif->last_rssi_event = event;
+	}
 }
+EXPORT_SYMBOL_GPL(wlcore_event_rssi_trigger);
 
 static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
 	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 
 	if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
-		if (!wlvif->sta.ba_rx_bitmap)
+		u8 hlid = wlvif->sta.hlid;
+		if (!wl->links[hlid].ba_bitmap)
 			return;
-		ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
+		ieee80211_stop_rx_ba_session(vif, wl->links[hlid].ba_bitmap,
 					     vif->bss_conf.bssid);
 	} else {
 		u8 hlid;
@@ -74,8 +79,7 @@
 	}
 }
 
-static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
-					       u8 enable)
+void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable)
 {
 	struct wl12xx_vif *wlvif;
 
@@ -87,201 +91,169 @@
 			wl1271_recalc_rx_streaming(wl, wlvif);
 		}
 	}
-
 }
+EXPORT_SYMBOL_GPL(wlcore_event_soft_gemini_sense);
 
-static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
+void wlcore_event_sched_scan_completed(struct wl1271 *wl,
+				       u8 status)
 {
-	wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
-	wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
-	wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+	wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)",
+		     status);
+
+	if (wl->sched_vif) {
+		ieee80211_sched_scan_stopped(wl->hw);
+		wl->sched_vif = NULL;
+	}
 }
+EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_completed);
 
-static int wl1271_event_process(struct wl1271 *wl)
+void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
+				   unsigned long roles_bitmap,
+				   unsigned long allowed_bitmap)
 {
-	struct event_mailbox *mbox = wl->mbox;
-	struct ieee80211_vif *vif;
 	struct wl12xx_vif *wlvif;
-	u32 vector;
-	bool disconnect_sta = false;
-	unsigned long sta_bitmap = 0;
-	int ret;
 
-	wl1271_event_mbox_dump(mbox);
+	wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx allowed=0x%lx",
+		     __func__, roles_bitmap, allowed_bitmap);
 
-	vector = le32_to_cpu(mbox->events_vector);
-	vector &= ~(le32_to_cpu(mbox->events_mask));
-	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+	wl12xx_for_each_wlvif(wl, wlvif) {
+		if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
+		    !test_bit(wlvif->role_id , &roles_bitmap))
+			continue;
 
-	if (vector & SCAN_COMPLETE_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
-			     mbox->scheduled_scan_status);
-
-		wl1271_scan_stm(wl, wl->scan_vif);
+		wlvif->ba_allowed = !!test_bit(wlvif->role_id,
+					       &allowed_bitmap);
+		if (!wlvif->ba_allowed)
+			wl1271_stop_ba_event(wl, wlvif);
 	}
+}
+EXPORT_SYMBOL_GPL(wlcore_event_ba_rx_constraint);
 
-	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
-			     "(status 0x%0x)", mbox->scheduled_scan_status);
+void wlcore_event_channel_switch(struct wl1271 *wl,
+				 unsigned long roles_bitmap,
+				 bool success)
+{
+	struct wl12xx_vif *wlvif;
+	struct ieee80211_vif *vif;
 
-		wl1271_scan_sched_scan_results(wl);
+	wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d",
+		     __func__, roles_bitmap, success);
+
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
+		    !test_bit(wlvif->role_id , &roles_bitmap))
+			continue;
+
+		if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
+					&wlvif->flags))
+			continue;
+
+		vif = wl12xx_wlvif_to_vif(wlvif);
+
+		ieee80211_chswitch_done(vif, success);
+		cancel_delayed_work(&wlvif->channel_switch_work);
 	}
+}
+EXPORT_SYMBOL_GPL(wlcore_event_channel_switch);
 
-	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
-			     "(status 0x%0x)", mbox->scheduled_scan_status);
-		if (wl->sched_scanning) {
-			ieee80211_sched_scan_stopped(wl->hw);
-			wl->sched_scanning = false;
+void wlcore_event_dummy_packet(struct wl1271 *wl)
+{
+	wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
+	wl1271_tx_dummy_packet(wl);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_dummy_packet);
+
+static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap)
+{
+	u32 num_packets = wl->conf.tx.max_tx_retries;
+	struct wl12xx_vif *wlvif;
+	struct ieee80211_vif *vif;
+	struct ieee80211_sta *sta;
+	const u8 *addr;
+	int h;
+
+	for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
+		bool found = false;
+		/* find the ap vif connected to this sta */
+		wl12xx_for_each_wlvif_ap(wl, wlvif) {
+			if (!test_bit(h, wlvif->ap.sta_hlid_map))
+				continue;
+			found = true;
+			break;
 		}
+		if (!found)
+			continue;
+
+		vif = wl12xx_wlvif_to_vif(wlvif);
+		addr = wl->links[h].addr;
+
+		rcu_read_lock();
+		sta = ieee80211_find_sta(vif, addr);
+		if (sta) {
+			wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
+			ieee80211_report_low_ack(sta, num_packets);
+		}
+		rcu_read_unlock();
 	}
+}
 
-	if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
-		wl12xx_event_soft_gemini_sense(wl,
-					       mbox->soft_gemini_sense_info);
+void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap)
+{
+	wl1271_debug(DEBUG_EVENT, "MAX_TX_FAILURE_EVENT_ID");
+	wlcore_disconnect_sta(wl, sta_bitmap);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_max_tx_failure);
 
+void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap)
+{
+	wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
+	wlcore_disconnect_sta(wl, sta_bitmap);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_inactive_sta);
+
+void wlcore_event_roc_complete(struct wl1271 *wl)
+{
+	wl1271_debug(DEBUG_EVENT, "REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID");
+	if (wl->roc_vif)
+		ieee80211_ready_on_channel(wl->hw);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_roc_complete);
+
+void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
+{
 	/*
 	 * We are HW_MONITOR device. On beacon loss - queue
 	 * connection loss work. Cancel it on REGAINED event.
 	 */
-	if (vector & BSS_LOSE_EVENT_ID) {
-		/* TODO: check for multi-role */
-		int delay = wl->conf.conn.synch_fail_thold *
-					wl->conf.conn.bss_lose_timeout;
-		wl1271_info("Beacon loss detected.");
+	struct wl12xx_vif *wlvif;
+	struct ieee80211_vif *vif;
+	int delay = wl->conf.conn.synch_fail_thold *
+				wl->conf.conn.bss_lose_timeout;
+
+	wl1271_info("Beacon loss detected. roles:0x%lx", roles_bitmap);
+
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
+		    !test_bit(wlvif->role_id , &roles_bitmap))
+			continue;
 
 		/*
-		 * if the work is already queued, it should take place. We
-		 * don't want to delay the connection loss indication
-		 * any more.
+		 * if the work is already queued, it should take place.
+		 * We don't want to delay the connection loss
+		 * indication any more.
 		 */
-		ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
+		ieee80211_queue_delayed_work(wl->hw,
+					     &wlvif->connection_loss_work,
 					     msecs_to_jiffies(delay));
 
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			vif = wl12xx_wlvif_to_vif(wlvif);
-
-			ieee80211_cqm_rssi_notify(
-					vif,
-					NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
-					GFP_KERNEL);
-		}
+		vif = wl12xx_wlvif_to_vif(wlvif);
+		ieee80211_cqm_rssi_notify(
+				vif,
+				NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
+				GFP_KERNEL);
 	}
-
-	if (vector & REGAINED_BSS_EVENT_ID) {
-		/* TODO: check for multi-role */
-		wl1271_info("Beacon regained.");
-		cancel_delayed_work(&wl->connection_loss_work);
-
-		/* sanity check - we can't lose and gain the beacon together */
-		WARN(vector & BSS_LOSE_EVENT_ID,
-		     "Concurrent beacon loss and gain from FW");
-	}
-
-	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
-		/* TODO: check actual multi-role support */
-		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			wl1271_event_rssi_trigger(wl, wlvif, mbox);
-		}
-	}
-
-	if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
-		u8 role_id = mbox->role_id;
-		wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
-			     "ba_allowed = 0x%x, role_id=%d",
-			     mbox->rx_ba_allowed, role_id);
-
-		wl12xx_for_each_wlvif(wl, wlvif) {
-			if (role_id != 0xff && role_id != wlvif->role_id)
-				continue;
-
-			wlvif->ba_allowed = !!mbox->rx_ba_allowed;
-			if (!wlvif->ba_allowed)
-				wl1271_stop_ba_event(wl, wlvif);
-		}
-	}
-
-	if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
-					  "status = 0x%x",
-					  mbox->channel_switch_status);
-		/*
-		 * That event uses for two cases:
-		 * 1) channel switch complete with status=0
-		 * 2) channel switch failed status=1
-		 */
-
-		/* TODO: configure only the relevant vif */
-		wl12xx_for_each_wlvif_sta(wl, wlvif) {
-			bool success;
-
-			if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
-						&wlvif->flags))
-				continue;
-
-			success = mbox->channel_switch_status ? false : true;
-			vif = wl12xx_wlvif_to_vif(wlvif);
-
-			ieee80211_chswitch_done(vif, success);
-		}
-	}
-
-	if ((vector & DUMMY_PACKET_EVENT_ID)) {
-		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
-		ret = wl1271_tx_dummy_packet(wl);
-		if (ret < 0)
-			return ret;
-	}
-
-	/*
-	 * "TX retries exceeded" has a different meaning according to mode.
-	 * In AP mode the offending station is disconnected.
-	 */
-	if (vector & MAX_TX_RETRY_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
-		sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
-		disconnect_sta = true;
-	}
-
-	if (vector & INACTIVE_STA_EVENT_ID) {
-		wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
-		sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
-		disconnect_sta = true;
-	}
-
-	if (disconnect_sta) {
-		u32 num_packets = wl->conf.tx.max_tx_retries;
-		struct ieee80211_sta *sta;
-		const u8 *addr;
-		int h;
-
-		for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
-			bool found = false;
-			/* find the ap vif connected to this sta */
-			wl12xx_for_each_wlvif_ap(wl, wlvif) {
-				if (!test_bit(h, wlvif->ap.sta_hlid_map))
-					continue;
-				found = true;
-				break;
-			}
-			if (!found)
-				continue;
-
-			vif = wl12xx_wlvif_to_vif(wlvif);
-			addr = wl->links[h].addr;
-
-			rcu_read_lock();
-			sta = ieee80211_find_sta(vif, addr);
-			if (sta) {
-				wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
-				ieee80211_report_low_ack(sta, num_packets);
-			}
-			rcu_read_unlock();
-		}
-	}
-	return 0;
 }
+EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss);
 
 int wl1271_event_unmask(struct wl1271 *wl)
 {
@@ -305,12 +277,12 @@
 
 	/* first we read the mbox descriptor */
 	ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
-			  sizeof(*wl->mbox), false);
+			  wl->mbox_size, false);
 	if (ret < 0)
 		return ret;
 
 	/* process the descriptor */
-	ret = wl1271_event_process(wl);
+	ret = wl->ops->process_mailbox_events(wl);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/net/wireless/ti/wlcore/event.h b/drivers/net/wireless/ti/wlcore/event.h
index 8adf18d..acc7a59 100644
--- a/drivers/net/wireless/ti/wlcore/event.h
+++ b/drivers/net/wireless/ti/wlcore/event.h
@@ -46,33 +46,17 @@
 	RSSI_SNR_TRIGGER_5_EVENT_ID              = BIT(5),
 	RSSI_SNR_TRIGGER_6_EVENT_ID              = BIT(6),
 	RSSI_SNR_TRIGGER_7_EVENT_ID              = BIT(7),
-	MEASUREMENT_START_EVENT_ID		 = BIT(8),
-	MEASUREMENT_COMPLETE_EVENT_ID		 = BIT(9),
-	SCAN_COMPLETE_EVENT_ID			 = BIT(10),
-	WFD_DISCOVERY_COMPLETE_EVENT_ID		 = BIT(11),
-	AP_DISCOVERY_COMPLETE_EVENT_ID		 = BIT(12),
-	RESERVED1			         = BIT(13),
-	PSPOLL_DELIVERY_FAILURE_EVENT_ID	 = BIT(14),
-	ROLE_STOP_COMPLETE_EVENT_ID		 = BIT(15),
-	RADAR_DETECTED_EVENT_ID                  = BIT(16),
-	CHANNEL_SWITCH_COMPLETE_EVENT_ID	 = BIT(17),
-	BSS_LOSE_EVENT_ID			 = BIT(18),
-	REGAINED_BSS_EVENT_ID			 = BIT(19),
-	MAX_TX_RETRY_EVENT_ID			 = BIT(20),
-	DUMMY_PACKET_EVENT_ID			 = BIT(21),
-	SOFT_GEMINI_SENSE_EVENT_ID		 = BIT(22),
-	CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID	 = BIT(23),
-	SOFT_GEMINI_AVALANCHE_EVENT_ID		 = BIT(24),
-	PLT_RX_CALIBRATION_COMPLETE_EVENT_ID	 = BIT(25),
-	INACTIVE_STA_EVENT_ID			 = BIT(26),
-	PEER_REMOVE_COMPLETE_EVENT_ID		 = BIT(27),
-	PERIODIC_SCAN_COMPLETE_EVENT_ID		 = BIT(28),
-	PERIODIC_SCAN_REPORT_EVENT_ID		 = BIT(29),
-	BA_SESSION_RX_CONSTRAINT_EVENT_ID	 = BIT(30),
-	REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID	 = BIT(31),
+
 	EVENT_MBOX_ALL_EVENT_ID			 = 0x7fffffff,
 };
 
+/* events the driver might want to wait for */
+enum wlcore_wait_event {
+	WLCORE_EVENT_ROLE_STOP_COMPLETE,
+	WLCORE_EVENT_PEER_REMOVE_COMPLETE,
+	WLCORE_EVENT_DFS_CONFIG_COMPLETE
+};
+
 enum {
 	EVENT_ENTER_POWER_SAVE_FAIL = 0,
 	EVENT_ENTER_POWER_SAVE_SUCCESS,
@@ -80,61 +64,24 @@
 
 #define NUM_OF_RSSI_SNR_TRIGGERS 8
 
-struct event_mailbox {
-	__le32 events_vector;
-	__le32 events_mask;
-	__le32 reserved_1;
-	__le32 reserved_2;
-
-	u8 number_of_scan_results;
-	u8 scan_tag;
-	u8 completed_scan_status;
-	u8 reserved_3;
-
-	u8 soft_gemini_sense_info;
-	u8 soft_gemini_protective_info;
-	s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
-	u8 change_auto_mode_timeout;
-	u8 scheduled_scan_status;
-	u8 reserved4;
-	/* tuned channel (roc) */
-	u8 roc_channel;
-
-	__le16 hlid_removed_bitmap;
-
-	/* bitmap of aged stations (by HLID) */
-	__le16 sta_aging_status;
-
-	/* bitmap of stations (by HLID) which exceeded max tx retries */
-	__le16 sta_tx_retry_exceeded;
-
-	/* discovery completed results */
-	u8 discovery_tag;
-	u8 number_of_preq_results;
-	u8 number_of_prsp_results;
-	u8 reserved_5;
-
-	/* rx ba constraint */
-	u8 role_id; /* 0xFF means any role. */
-	u8 rx_ba_allowed;
-	u8 reserved_6[2];
-
-	/* Channel switch results */
-
-	u8 channel_switch_role_id;
-	u8 channel_switch_status;
-	u8 reserved_7[2];
-
-	u8 ps_poll_delivery_failure_role_ids;
-	u8 stopped_role_ids;
-	u8 started_role_ids;
-
-	u8 reserved_8[9];
-} __packed;
-
 struct wl1271;
 
 int wl1271_event_unmask(struct wl1271 *wl);
 int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
 
+void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable);
+void wlcore_event_sched_scan_completed(struct wl1271 *wl,
+				       u8 status);
+void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
+				   unsigned long roles_bitmap,
+				   unsigned long allowed_bitmap);
+void wlcore_event_channel_switch(struct wl1271 *wl,
+				 unsigned long roles_bitmap,
+				 bool success);
+void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap);
+void wlcore_event_dummy_packet(struct wl1271 *wl);
+void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap);
+void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap);
+void wlcore_event_roc_complete(struct wl1271 *wl);
+void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr);
 #endif
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 2673d78..7fd260c 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -201,4 +201,45 @@
 	return buf_offset;
 }
 
+static inline void
+wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			struct ieee80211_sta *sta, u32 changed)
+{
+	if (wl->ops->sta_rc_update)
+		wl->ops->sta_rc_update(wl, wlvif, sta, changed);
+}
+
+static inline int
+wlcore_hw_set_peer_cap(struct wl1271 *wl,
+		       struct ieee80211_sta_ht_cap *ht_cap,
+		       bool allow_ht_operation,
+		       u32 rate_set, u8 hlid)
+{
+	if (wl->ops->set_peer_cap)
+		return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation,
+					     rate_set, hlid);
+
+	return 0;
+}
+
+static inline bool
+wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+			struct wl1271_link *lnk)
+{
+	if (!wl->ops->lnk_high_prio)
+		BUG_ON(1);
+
+	return wl->ops->lnk_high_prio(wl, hlid, lnk);
+}
+
+static inline bool
+wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+		       struct wl1271_link *lnk)
+{
+	if (!wl->ops->lnk_low_prio)
+		BUG_ON(1);
+
+	return wl->ops->lnk_low_prio(wl, hlid, lnk);
+}
+
 #endif
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 32d157f..5c6f11e 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -41,14 +41,14 @@
 
 	/* send empty templates for fw memory reservation */
 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-				      CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+				      wl->scan_templ_id_2_4, NULL,
 				      WL1271_CMD_TEMPL_MAX_SIZE,
 				      0, WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
 		return ret;
 
 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-				      CMD_TEMPL_CFG_PROBE_REQ_5,
+				      wl->scan_templ_id_5,
 				      NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
 				      WL1271_RATE_AUTOMATIC);
 	if (ret < 0)
@@ -56,14 +56,16 @@
 
 	if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-					      CMD_TEMPL_APP_PROBE_REQ_2_4, NULL,
+					      wl->sched_scan_templ_id_2_4,
+					      NULL,
 					      WL1271_CMD_TEMPL_MAX_SIZE,
 					      0, WL1271_RATE_AUTOMATIC);
 		if (ret < 0)
 			return ret;
 
 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
-					      CMD_TEMPL_APP_PROBE_REQ_5, NULL,
+					      wl->sched_scan_templ_id_5,
+					      NULL,
 					      WL1271_CMD_TEMPL_MAX_SIZE,
 					      0, WL1271_RATE_AUTOMATIC);
 		if (ret < 0)
@@ -463,7 +465,7 @@
 	if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
 		supported_rates = CONF_TX_OFDM_RATES;
 	else
-		supported_rates = CONF_TX_AP_ENABLED_RATES;
+		supported_rates = CONF_TX_ENABLED_RATES;
 
 	/* unconditionally enable HT rates */
 	supported_rates |= CONF_TX_MCS_RATES;
@@ -575,9 +577,6 @@
 		/* Configure for power according to debugfs */
 		if (sta_auth != WL1271_PSM_ILLEGAL)
 			ret = wl1271_acx_sleep_auth(wl, sta_auth);
-		/* Configure for power always on */
-		else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
-			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
 		/* Configure for ELP power saving */
 		else
 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
@@ -679,6 +678,10 @@
 	if (ret < 0)
 		return ret;
 
+	ret = wlcore_cmd_regdomain_config_locked(wl);
+	if (ret < 0)
+		return ret;
+
 	/* Bluetooth WLAN coexistence */
 	ret = wl1271_init_pta(wl);
 	if (ret < 0)
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
index f48530f..af7d9f9 100644
--- a/drivers/net/wireless/ti/wlcore/io.h
+++ b/drivers/net/wireless/ti/wlcore/io.h
@@ -105,13 +105,13 @@
 {
 	int ret;
 
-	ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
-			      sizeof(wl->buffer_32), false);
+	ret = wlcore_raw_read(wl, addr, wl->buffer_32,
+			      sizeof(*wl->buffer_32), false);
 	if (ret < 0)
 		return ret;
 
 	if (val)
-		*val = le32_to_cpu(wl->buffer_32);
+		*val = le32_to_cpu(*wl->buffer_32);
 
 	return 0;
 }
@@ -119,9 +119,9 @@
 static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
 						  u32 val)
 {
-	wl->buffer_32 = cpu_to_le32(val);
-	return wlcore_raw_write(wl, addr, &wl->buffer_32,
-				sizeof(wl->buffer_32), false);
+	*wl->buffer_32 = cpu_to_le32(val);
+	return wlcore_raw_write(wl, addr, wl->buffer_32,
+				sizeof(*wl->buffer_32), false);
 }
 
 static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index ea9d8e0..2c2ff3e 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -56,8 +56,8 @@
 #define WL1271_BOOT_RETRIES 3
 
 static char *fwlog_param;
-static bool bug_on_recovery;
-static bool no_recovery;
+static int bug_on_recovery = -1;
+static int no_recovery     = -1;
 
 static void __wl1271_op_remove_interface(struct wl1271 *wl,
 					 struct ieee80211_vif *vif,
@@ -79,22 +79,22 @@
 	if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
 		return 0;
 
-	ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
+	ret = wl12xx_cmd_set_peer_state(wl, wlvif, wlvif->sta.hlid);
 	if (ret < 0)
 		return ret;
 
-	wl12xx_croc(wl, wlvif->role_id);
-
 	wl1271_info("Association completed.");
 	return 0;
 }
 
-static int wl1271_reg_notify(struct wiphy *wiphy,
-			     struct regulatory_request *request)
+static void wl1271_reg_notify(struct wiphy *wiphy,
+			      struct regulatory_request *request)
 {
 	struct ieee80211_supported_band *band;
 	struct ieee80211_channel *ch;
 	int i;
+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+	struct wl1271 *wl = hw->priv;
 
 	band = wiphy->bands[IEEE80211_BAND_5GHZ];
 	for (i = 0; i < band->n_channels; i++) {
@@ -108,7 +108,8 @@
 
 	}
 
-	return 0;
+	if (likely(wl->state == WLCORE_STATE_ON))
+		wlcore_regdomain_config(wl);
 }
 
 static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -303,6 +304,7 @@
 static void wlcore_adjust_conf(struct wl1271 *wl)
 {
 	/* Adjust settings according to optional module parameters */
+
 	if (fwlog_param) {
 		if (!strcmp(fwlog_param, "continuous")) {
 			wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
@@ -318,16 +320,22 @@
 			wl1271_error("Unknown fwlog parameter %s", fwlog_param);
 		}
 	}
+
+	if (bug_on_recovery != -1)
+		wl->conf.recovery.bug_on_recovery = (u8) bug_on_recovery;
+
+	if (no_recovery != -1)
+		wl->conf.recovery.no_recovery = (u8) no_recovery;
 }
 
 static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
 					struct wl12xx_vif *wlvif,
 					u8 hlid, u8 tx_pkts)
 {
-	bool fw_ps, single_sta;
+	bool fw_ps, single_link;
 
 	fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
-	single_sta = (wl->active_sta_count == 1);
+	single_link = (wl->active_link_count == 1);
 
 	/*
 	 * Wake up from high level PS if the STA is asleep with too little
@@ -338,10 +346,10 @@
 
 	/*
 	 * Start high-level PS if the STA is asleep with enough blocks in FW.
-	 * Make an exception if this is the only connected station. In this
-	 * case FW-memory congestion is not a problem.
+	 * Make an exception if this is the only connected link. In this
+	 * case FW-memory congestion is less of a problem.
 	 */
-	else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+	else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
 		wl12xx_ps_link_start(wl, wlvif, hlid, true);
 }
 
@@ -349,11 +357,8 @@
 					   struct wl12xx_vif *wlvif,
 					   struct wl_fw_status_2 *status)
 {
-	struct wl1271_link *lnk;
 	u32 cur_fw_ps_map;
-	u8 hlid, cnt;
-
-	/* TODO: also use link_fast_bitmap here */
+	u8 hlid;
 
 	cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
 	if (wl->ap_fw_ps_map != cur_fw_ps_map) {
@@ -365,17 +370,9 @@
 		wl->ap_fw_ps_map = cur_fw_ps_map;
 	}
 
-	for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
-		lnk = &wl->links[hlid];
-		cnt = status->counters.tx_lnk_free_pkts[hlid] -
-			lnk->prev_freed_pkts;
-
-		lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid];
-		lnk->allocated_pkts -= cnt;
-
+	for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS)
 		wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
-					    lnk->allocated_pkts);
-	}
+					    wl->links[hlid].allocated_pkts);
 }
 
 static int wlcore_fw_status(struct wl1271 *wl,
@@ -389,6 +386,7 @@
 	int i;
 	size_t status_len;
 	int ret;
+	struct wl1271_link *lnk;
 
 	status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
 		sizeof(*status_2) + wl->fw_status_priv_len;
@@ -414,6 +412,17 @@
 		wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
 	}
 
+
+	for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
+		lnk = &wl->links[i];
+		/* prevent wrap-around in freed-packets counter */
+		lnk->allocated_pkts -=
+			(status_2->counters.tx_lnk_free_pkts[i] -
+			 lnk->prev_freed_pkts) & 0xff;
+
+		lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
+	}
+
 	/* prevent wrap-around in total blocks counter */
 	if (likely(wl->tx_blocks_freed <=
 		   le32_to_cpu(status_2->total_released_blks)))
@@ -466,6 +475,8 @@
 	wl->time_offset = (timespec_to_ns(&ts) >> 10) -
 		(s64)le32_to_cpu(status_2->fw_localtime);
 
+	wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap);
+
 	return 0;
 }
 
@@ -802,11 +813,13 @@
 
 	/*
 	 * Make sure the chip is awake and the logger isn't active.
-	 * Do not send a stop fwlog command if the fw is hanged.
+	 * Do not send a stop fwlog command if the fw is hanged or if
+	 * dbgpins are used (due to some fw bug).
 	 */
 	if (wl1271_ps_elp_wakeup(wl))
 		goto out;
-	if (!wl->watchdog_recovery)
+	if (!wl->watchdog_recovery &&
+	    wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS)
 		wl12xx_cmd_stop_fwlog(wl);
 
 	/* Read the first memory block address */
@@ -874,7 +887,8 @@
 	if (ret < 0)
 		return;
 
-	wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts);
+	wl1271_info("pc: 0x%x, hint_sts: 0x%08x count: %d",
+				pc, hint_sts, ++wl->recovery_count);
 
 	wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
 }
@@ -897,10 +911,10 @@
 		wlcore_print_recovery(wl);
 	}
 
-	BUG_ON(bug_on_recovery &&
+	BUG_ON(wl->conf.recovery.bug_on_recovery &&
 	       !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
 
-	if (no_recovery) {
+	if (wl->conf.recovery.no_recovery) {
 		wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
 		goto out_unlock;
 	}
@@ -920,11 +934,6 @@
 	/* Prevent spurious TX during FW restart */
 	wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
 
-	if (wl->sched_scanning) {
-		ieee80211_sched_scan_stopped(wl->hw);
-		wl->sched_scanning = false;
-	}
-
 	/* reboot the chipset */
 	while (!list_empty(&wl->wlvif_list)) {
 		wlvif = list_first_entry(&wl->wlvif_list,
@@ -1141,7 +1150,6 @@
 	cancel_work_sync(&wl->recovery_work);
 	cancel_delayed_work_sync(&wl->elp_work);
 	cancel_delayed_work_sync(&wl->tx_watchdog_work);
-	cancel_delayed_work_sync(&wl->connection_loss_work);
 
 	mutex_lock(&wl->mutex);
 	wl1271_power_off(wl);
@@ -1169,9 +1177,13 @@
 	int q, mapping;
 	u8 hlid;
 
-	if (vif)
-		wlvif = wl12xx_vif_to_data(vif);
+	if (!vif) {
+		wl1271_debug(DEBUG_TX, "DROP skb with no vif");
+		ieee80211_free_txskb(hw, skb);
+		return;
+	}
 
+	wlvif = wl12xx_vif_to_data(vif);
 	mapping = skb_get_queue_mapping(skb);
 	q = wl1271_tx_get_queue(mapping);
 
@@ -1185,9 +1197,9 @@
 	 * allow these packets through.
 	 */
 	if (hlid == WL12XX_INVALID_LINK_ID ||
-	    (wlvif && !test_bit(hlid, wlvif->links_map)) ||
-	     (wlcore_is_queue_stopped(wl, q) &&
-	      !wlcore_is_queue_stopped_by_reason(wl, q,
+	    (!test_bit(hlid, wlvif->links_map)) ||
+	     (wlcore_is_queue_stopped_locked(wl, wlvif, q) &&
+	      !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
 			WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
 		wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
 		ieee80211_free_txskb(hw, skb);
@@ -1199,16 +1211,17 @@
 	skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
 
 	wl->tx_queue_count[q]++;
+	wlvif->tx_queue_count[q]++;
 
 	/*
 	 * The workqueue is slow to process the tx_queue and we need stop
 	 * the queue here, otherwise the queue will get too long.
 	 */
-	if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
-	    !wlcore_is_queue_stopped_by_reason(wl, q,
+	if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
+	    !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
 					WLCORE_QUEUE_STOP_REASON_WATERMARK)) {
 		wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
-		wlcore_stop_queue_locked(wl, q,
+		wlcore_stop_queue_locked(wl, wlvif, q,
 					 WLCORE_QUEUE_STOP_REASON_WATERMARK);
 	}
 
@@ -1843,11 +1856,10 @@
 	cancel_work_sync(&wl->tx_work);
 	cancel_delayed_work_sync(&wl->elp_work);
 	cancel_delayed_work_sync(&wl->tx_watchdog_work);
-	cancel_delayed_work_sync(&wl->connection_loss_work);
 
 	/* let's notify MAC80211 about the remaining pending TX frames */
-	wl12xx_tx_reset(wl);
 	mutex_lock(&wl->mutex);
+	wl12xx_tx_reset(wl);
 
 	wl1271_power_off(wl);
 	/*
@@ -1870,14 +1882,17 @@
 	wl->time_offset = 0;
 	wl->ap_fw_ps_map = 0;
 	wl->ap_ps_map = 0;
-	wl->sched_scanning = false;
 	wl->sleep_auth = WL1271_PSM_ILLEGAL;
 	memset(wl->roles_map, 0, sizeof(wl->roles_map));
 	memset(wl->links_map, 0, sizeof(wl->links_map));
 	memset(wl->roc_map, 0, sizeof(wl->roc_map));
+	memset(wl->session_ids, 0, sizeof(wl->session_ids));
 	wl->active_sta_count = 0;
+	wl->active_link_count = 0;
 
 	/* The system link is always allocated */
+	wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0;
+	wl->links[WL12XX_SYSTEM_HLID].prev_freed_pkts = 0;
 	__set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
 
 	/*
@@ -1903,6 +1918,12 @@
 	wl->tx_res_if = NULL;
 	kfree(wl->target_mem_map);
 	wl->target_mem_map = NULL;
+
+	/*
+	 * FW channels must be re-calibrated after recovery,
+	 * clear the last Reg-Domain channel configuration.
+	 */
+	memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last));
 }
 
 static void wlcore_op_stop(struct ieee80211_hw *hw)
@@ -1918,6 +1939,71 @@
 	mutex_unlock(&wl->mutex);
 }
 
+static void wlcore_channel_switch_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct wl1271 *wl;
+	struct ieee80211_vif *vif;
+	struct wl12xx_vif *wlvif;
+	int ret;
+
+	dwork = container_of(work, struct delayed_work, work);
+	wlvif = container_of(dwork, struct wl12xx_vif, channel_switch_work);
+	wl = wlvif->wl;
+
+	wl1271_info("channel switch failed (role_id: %d).", wlvif->role_id);
+
+	mutex_lock(&wl->mutex);
+
+	if (unlikely(wl->state != WLCORE_STATE_ON))
+		goto out;
+
+	/* check the channel switch is still ongoing */
+	if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags))
+		goto out;
+
+	vif = wl12xx_wlvif_to_vif(wlvif);
+	ieee80211_chswitch_done(vif, false);
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	wl12xx_cmd_stop_channel_switch(wl, wlvif);
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static void wlcore_connection_loss_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct wl1271 *wl;
+	struct ieee80211_vif *vif;
+	struct wl12xx_vif *wlvif;
+
+	dwork = container_of(work, struct delayed_work, work);
+	wlvif = container_of(dwork, struct wl12xx_vif, connection_loss_work);
+	wl = wlvif->wl;
+
+	wl1271_info("Connection loss work (role_id: %d).", wlvif->role_id);
+
+	mutex_lock(&wl->mutex);
+
+	if (unlikely(wl->state != WLCORE_STATE_ON))
+		goto out;
+
+	/* Call mac80211 connection loss */
+	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+		goto out;
+
+	vif = wl12xx_wlvif_to_vif(wlvif);
+	ieee80211_connection_loss(vif);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
 static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
 {
 	u8 policy = find_first_zero_bit(wl->rate_policies_map,
@@ -2037,15 +2123,15 @@
 		for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
 			wl12xx_allocate_rate_policy(wl,
 						&wlvif->ap.ucast_rate_idx[i]);
-		wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
+		wlvif->basic_rate_set = CONF_TX_ENABLED_RATES;
 		/*
 		 * TODO: check if basic_rate shouldn't be
 		 * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
 		 * instead (the same thing for STA above).
 		*/
-		wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
+		wlvif->basic_rate = CONF_TX_ENABLED_RATES;
 		/* TODO: this seems to be used only for STA, check it */
-		wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
+		wlvif->rate_set = CONF_TX_ENABLED_RATES;
 	}
 
 	wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
@@ -2065,6 +2151,10 @@
 		  wl1271_rx_streaming_enable_work);
 	INIT_WORK(&wlvif->rx_streaming_disable_work,
 		  wl1271_rx_streaming_disable_work);
+	INIT_DELAYED_WORK(&wlvif->channel_switch_work,
+			  wlcore_channel_switch_work);
+	INIT_DELAYED_WORK(&wlvif->connection_loss_work,
+			  wlcore_connection_loss_work);
 	INIT_LIST_HEAD(&wlvif->list);
 
 	setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
@@ -2072,7 +2162,7 @@
 	return 0;
 }
 
-static bool wl12xx_init_fw(struct wl1271 *wl)
+static int wl12xx_init_fw(struct wl1271 *wl)
 {
 	int retries = WL1271_BOOT_RETRIES;
 	bool booted = false;
@@ -2138,7 +2228,7 @@
 
 	wl->state = WLCORE_STATE_ON;
 out:
-	return booted;
+	return ret;
 }
 
 static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
@@ -2198,6 +2288,81 @@
 	}
 }
 
+struct wlcore_hw_queue_iter_data {
+	unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)];
+	/* current vif */
+	struct ieee80211_vif *vif;
+	/* is the current vif among those iterated */
+	bool cur_running;
+};
+
+static void wlcore_hw_queue_iter(void *data, u8 *mac,
+				 struct ieee80211_vif *vif)
+{
+	struct wlcore_hw_queue_iter_data *iter_data = data;
+
+	if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE))
+		return;
+
+	if (iter_data->cur_running || vif == iter_data->vif) {
+		iter_data->cur_running = true;
+		return;
+	}
+
+	__set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map);
+}
+
+static int wlcore_allocate_hw_queue_base(struct wl1271 *wl,
+					 struct wl12xx_vif *wlvif)
+{
+	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+	struct wlcore_hw_queue_iter_data iter_data = {};
+	int i, q_base;
+
+	iter_data.vif = vif;
+
+	/* mark all bits taken by active interfaces */
+	ieee80211_iterate_active_interfaces_atomic(wl->hw,
+					IEEE80211_IFACE_ITER_RESUME_ALL,
+					wlcore_hw_queue_iter, &iter_data);
+
+	/* the current vif is already running in mac80211 (resume/recovery) */
+	if (iter_data.cur_running) {
+		wlvif->hw_queue_base = vif->hw_queue[0];
+		wl1271_debug(DEBUG_MAC80211,
+			     "using pre-allocated hw queue base %d",
+			     wlvif->hw_queue_base);
+
+		/* interface type might have changed type */
+		goto adjust_cab_queue;
+	}
+
+	q_base = find_first_zero_bit(iter_data.hw_queue_map,
+				     WLCORE_NUM_MAC_ADDRESSES);
+	if (q_base >= WLCORE_NUM_MAC_ADDRESSES)
+		return -EBUSY;
+
+	wlvif->hw_queue_base = q_base * NUM_TX_QUEUES;
+	wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d",
+		     wlvif->hw_queue_base);
+
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
+		wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0;
+		/* register hw queues in mac80211 */
+		vif->hw_queue[i] = wlvif->hw_queue_base + i;
+	}
+
+adjust_cab_queue:
+	/* the last places are reserved for cab queues per interface */
+	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+		vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES +
+				 wlvif->hw_queue_base / NUM_TX_QUEUES;
+	else
+		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+	return 0;
+}
+
 static int wl1271_op_add_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif)
 {
@@ -2206,7 +2371,6 @@
 	struct vif_counter_data vif_count;
 	int ret = 0;
 	u8 role_type;
-	bool booted = false;
 
 	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
 			     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
@@ -2244,6 +2408,10 @@
 		goto out;
 	}
 
+	ret = wlcore_allocate_hw_queue_base(wl, wlvif);
+	if (ret < 0)
+		goto out;
+
 	if (wl12xx_need_fw_change(wl, vif_count, true)) {
 		wl12xx_force_active_psm(wl);
 		set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
@@ -2263,11 +2431,9 @@
 		 */
 		memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
 
-		booted = wl12xx_init_fw(wl);
-		if (!booted) {
-			ret = -EINVAL;
+		ret = wl12xx_init_fw(wl);
+		if (ret < 0)
 			goto out;
-		}
 	}
 
 	ret = wl12xx_cmd_role_enable(wl, vif->addr,
@@ -2314,7 +2480,7 @@
 	wl1271_info("down");
 
 	if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
-	    wl->scan_vif == vif) {
+	    wl->scan_wlvif == wlvif) {
 		/*
 		 * Rearm the tx watchdog just before idling scan. This
 		 * prevents just-finished scans from triggering the watchdog
@@ -2323,11 +2489,21 @@
 
 		wl->scan.state = WL1271_SCAN_STATE_IDLE;
 		memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
-		wl->scan_vif = NULL;
+		wl->scan_wlvif = NULL;
 		wl->scan.req = NULL;
 		ieee80211_scan_completed(wl->hw, true);
 	}
 
+	if (wl->sched_vif == wlvif) {
+		ieee80211_sched_scan_stopped(wl->hw);
+		wl->sched_vif = NULL;
+	}
+
+	if (wl->roc_vif == vif) {
+		wl->roc_vif = NULL;
+		ieee80211_remain_on_channel_expired(wl->hw);
+	}
+
 	if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
 		/* disable active roles */
 		ret = wl1271_ps_elp_wakeup(wl);
@@ -2396,9 +2572,6 @@
 		/* Configure for power according to debugfs */
 		if (sta_auth != WL1271_PSM_ILLEGAL)
 			wl1271_acx_sleep_auth(wl, sta_auth);
-		/* Configure for power always on */
-		else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
-			wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
 		/* Configure for ELP power saving */
 		else
 			wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
@@ -2410,6 +2583,7 @@
 	del_timer_sync(&wlvif->rx_streaming_timer);
 	cancel_work_sync(&wlvif->rx_streaming_enable_work);
 	cancel_work_sync(&wlvif->rx_streaming_disable_work);
+	cancel_delayed_work_sync(&wlvif->connection_loss_work);
 
 	mutex_lock(&wl->mutex);
 }
@@ -2468,8 +2642,7 @@
 	return ret;
 }
 
-static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-			  bool set_assoc)
+static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
 	int ret;
 	bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
@@ -2489,18 +2662,111 @@
 	/* clear encryption type */
 	wlvif->encryption_type = KEY_NONE;
 
-	if (set_assoc)
-		set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
-
 	if (is_ibss)
 		ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
-	else
-		ret = wl12xx_cmd_role_start_sta(wl, wlvif);
-	if (ret < 0)
-		goto out;
+	else {
+		if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) {
+			/*
+			 * TODO: this is an ugly workaround for wl12xx fw
+			 * bug - we are not able to tx/rx after the first
+			 * start_sta, so make dummy start+stop calls,
+			 * and then call start_sta again.
+			 * this should be fixed in the fw.
+			 */
+			wl12xx_cmd_role_start_sta(wl, wlvif);
+			wl12xx_cmd_role_stop_sta(wl, wlvif);
+		}
 
-	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-		goto out;
+		ret = wl12xx_cmd_role_start_sta(wl, wlvif);
+	}
+
+	return ret;
+}
+
+static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb,
+			    int offset)
+{
+	u8 ssid_len;
+	const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
+					 skb->len - offset);
+
+	if (!ptr) {
+		wl1271_error("No SSID in IEs!");
+		return -ENOENT;
+	}
+
+	ssid_len = ptr[1];
+	if (ssid_len > IEEE80211_MAX_SSID_LEN) {
+		wl1271_error("SSID is too long!");
+		return -EINVAL;
+	}
+
+	wlvif->ssid_len = ssid_len;
+	memcpy(wlvif->ssid, ptr+2, ssid_len);
+	return 0;
+}
+
+static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+	struct sk_buff *skb;
+	int ieoffset;
+
+	/* we currently only support setting the ssid from the ap probe req */
+	if (wlvif->bss_type != BSS_TYPE_STA_BSS)
+		return -EINVAL;
+
+	skb = ieee80211_ap_probereq_get(wl->hw, vif);
+	if (!skb)
+		return -EINVAL;
+
+	ieoffset = offsetof(struct ieee80211_mgmt,
+			    u.probe_req.variable);
+	wl1271_ssid_set(wlvif, skb, ieoffset);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			    struct ieee80211_bss_conf *bss_conf,
+			    u32 sta_rate_set)
+{
+	int ieoffset;
+	int ret;
+
+	wlvif->aid = bss_conf->aid;
+	wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef);
+	wlvif->beacon_int = bss_conf->beacon_int;
+	wlvif->wmm_enabled = bss_conf->qos;
+
+	set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
+
+	/*
+	 * with wl1271, we don't need to update the
+	 * beacon_int and dtim_period, because the firmware
+	 * updates it by itself when the first beacon is
+	 * received after a join.
+	 */
+	ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Get a template for hardware connection maintenance
+	 */
+	dev_kfree_skb(wlvif->probereq);
+	wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
+							wlvif,
+							NULL);
+	ieoffset = offsetof(struct ieee80211_mgmt,
+			    u.probe_req.variable);
+	wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset);
+
+	/* enable the connection monitoring feature */
+	ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
+	if (ret < 0)
+		return ret;
 
 	/*
 	 * The join command disable the keep-alive mode, shut down its process,
@@ -2510,35 +2776,83 @@
 	 */
 	ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	ret = wl1271_acx_keep_alive_config(wl, wlvif,
 					   wlvif->sta.klv_template_id,
 					   ACX_KEEP_ALIVE_TPL_VALID);
 	if (ret < 0)
-		goto out;
+		return ret;
 
-out:
+	/*
+	 * The default fw psm configuration is AUTO, while mac80211 default
+	 * setting is off (ACTIVE), so sync the fw with the correct value.
+	 */
+	ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE);
+	if (ret < 0)
+		return ret;
+
+	if (sta_rate_set) {
+		wlvif->rate_set =
+			wl1271_tx_enabled_rates_get(wl,
+						    sta_rate_set,
+						    wlvif->band);
+		ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+		if (ret < 0)
+			return ret;
+	}
+
 	return ret;
 }
 
-static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
 	int ret;
+	bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+
+	/* make sure we are connected (sta) joined */
+	if (sta &&
+	    !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+		return false;
+
+	/* make sure we are joined (ibss) */
+	if (!sta &&
+	    test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))
+		return false;
+
+	if (sta) {
+		/* use defaults when not associated */
+		wlvif->aid = 0;
+
+		/* free probe-request template */
+		dev_kfree_skb(wlvif->probereq);
+		wlvif->probereq = NULL;
+
+		/* disable connection monitor features */
+		ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
+		if (ret < 0)
+			return ret;
+
+		/* Disable the keep-alive feature */
+		ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
+		if (ret < 0)
+			return ret;
+	}
 
 	if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
 		struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
 
-		wl12xx_cmd_stop_channel_switch(wl);
+		wl12xx_cmd_stop_channel_switch(wl, wlvif);
 		ieee80211_chswitch_done(vif, false);
+		cancel_delayed_work(&wlvif->channel_switch_work);
 	}
 
 	/* invalidate keep-alive template */
@@ -2546,17 +2860,11 @@
 				     wlvif->sta.klv_template_id,
 				     ACX_KEEP_ALIVE_TPL_INVALID);
 
-	/* to stop listening to a channel, we disconnect */
-	ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
-	if (ret < 0)
-		goto out;
-
 	/* reset TX security counters on a clean disconnect */
 	wlvif->tx_security_last_seq_lsb = 0;
 	wlvif->tx_security_seq = 0;
 
-out:
-	return ret;
+	return 0;
 }
 
 static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
@@ -2565,147 +2873,10 @@
 	wlvif->rate_set = wlvif->basic_rate_set;
 }
 
-static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
-				  bool idle)
-{
-	int ret;
-	bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
-
-	if (idle == cur_idle)
-		return 0;
-
-	if (idle) {
-		/* no need to croc if we weren't busy (e.g. during boot) */
-		if (wl12xx_dev_role_started(wlvif)) {
-			ret = wl12xx_stop_dev(wl, wlvif);
-			if (ret < 0)
-				goto out;
-		}
-		wlvif->rate_set =
-			wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-		ret = wl1271_acx_sta_rate_policies(wl, wlvif);
-		if (ret < 0)
-			goto out;
-		clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
-	} else {
-		/* The current firmware only supports sched_scan in idle */
-		if (wl->sched_scanning) {
-			wl1271_scan_sched_scan_stop(wl, wlvif);
-			ieee80211_sched_scan_stopped(wl->hw);
-		}
-
-		ret = wl12xx_start_dev(wl, wlvif);
-		if (ret < 0)
-			goto out;
-		set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
-	}
-
-out:
-	return ret;
-}
-
 static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			     struct ieee80211_conf *conf, u32 changed)
 {
-	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
-	int channel, ret;
-
-	channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
-
-	/* if the channel changes while joined, join again */
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
-	    ((wlvif->band != conf->channel->band) ||
-	     (wlvif->channel != channel) ||
-	     (wlvif->channel_type != conf->channel_type))) {
-		/* send all pending packets */
-		ret = wlcore_tx_work_locked(wl);
-		if (ret < 0)
-			return ret;
-
-		wlvif->band = conf->channel->band;
-		wlvif->channel = channel;
-		wlvif->channel_type = conf->channel_type;
-
-		if (is_ap) {
-			wl1271_set_band_rate(wl, wlvif);
-			ret = wl1271_init_ap_rates(wl, wlvif);
-			if (ret < 0)
-				wl1271_error("AP rate policy change failed %d",
-					     ret);
-		} else {
-			/*
-			 * FIXME: the mac80211 should really provide a fixed
-			 * rate to use here. for now, just use the smallest
-			 * possible rate for the band as a fixed rate for
-			 * association frames and other control messages.
-			 */
-			if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-				wl1271_set_band_rate(wl, wlvif);
-
-			wlvif->basic_rate =
-				wl1271_tx_min_rate_get(wl,
-						       wlvif->basic_rate_set);
-			ret = wl1271_acx_sta_rate_policies(wl, wlvif);
-			if (ret < 0)
-				wl1271_warning("rate policy for channel "
-					       "failed %d", ret);
-
-			/*
-			 * change the ROC channel. do it only if we are
-			 * not idle. otherwise, CROC will be called
-			 * anyway.
-			 */
-			if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED,
-				      &wlvif->flags) &&
-			    wl12xx_dev_role_started(wlvif) &&
-			    !(conf->flags & IEEE80211_CONF_IDLE)) {
-				ret = wl12xx_stop_dev(wl, wlvif);
-				if (ret < 0)
-					return ret;
-
-				ret = wl12xx_start_dev(wl, wlvif);
-				if (ret < 0)
-					return ret;
-			}
-		}
-	}
-
-	if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
-
-		if ((conf->flags & IEEE80211_CONF_PS) &&
-		    test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
-		    !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
-
-			int ps_mode;
-			char *ps_mode_str;
-
-			if (wl->conf.conn.forced_ps) {
-				ps_mode = STATION_POWER_SAVE_MODE;
-				ps_mode_str = "forced";
-			} else {
-				ps_mode = STATION_AUTO_PS_MODE;
-				ps_mode_str = "auto";
-			}
-
-			wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
-
-			ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
-
-			if (ret < 0)
-				wl1271_warning("enter %s ps failed %d",
-					       ps_mode_str, ret);
-
-		} else if (!(conf->flags & IEEE80211_CONF_PS) &&
-			   test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
-
-			wl1271_debug(DEBUG_PSM, "auto ps disabled");
-
-			ret = wl1271_ps_set_mode(wl, wlvif,
-						 STATION_ACTIVE_MODE);
-			if (ret < 0)
-				wl1271_warning("exit auto ps failed %d", ret);
-		}
-	}
+	int ret;
 
 	if (conf->power_level != wlvif->power_level) {
 		ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
@@ -2723,37 +2894,17 @@
 	struct wl1271 *wl = hw->priv;
 	struct wl12xx_vif *wlvif;
 	struct ieee80211_conf *conf = &hw->conf;
-	int channel, ret = 0;
+	int ret = 0;
 
-	channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
-
-	wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
+	wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s"
 		     " changed 0x%x",
-		     channel,
 		     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
 		     conf->power_level,
 		     conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
 			 changed);
 
-	/*
-	 * mac80211 will go to idle nearly immediately after transmitting some
-	 * frames, such as the deauth. To make sure those frames reach the air,
-	 * wait here until the TX queue is fully flushed.
-	 */
-	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
-	    ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
-	     (conf->flags & IEEE80211_CONF_IDLE)))
-		wl1271_tx_flush(wl);
-
 	mutex_lock(&wl->mutex);
 
-	/* we support configuring the channel and band even while off */
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-		wl->band = conf->channel->band;
-		wl->channel = channel;
-		wl->channel_type = conf->channel_type;
-	}
-
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
 		wl->power_level = conf->power_level;
 
@@ -3073,10 +3224,7 @@
 		 * stop the queues and flush to ensure the next packets are
 		 * in sync with FW spare block accounting
 		 */
-		mutex_lock(&wl->mutex);
 		wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
-		mutex_unlock(&wl->mutex);
-
 		wl1271_tx_flush(wl);
 	}
 
@@ -3202,6 +3350,29 @@
 }
 EXPORT_SYMBOL_GPL(wlcore_set_key);
 
+void wlcore_regdomain_config(struct wl1271 *wl)
+{
+	int ret;
+
+	if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
+		return;
+
+	mutex_lock(&wl->mutex);
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = wlcore_cmd_regdomain_config_locked(wl);
+	if (ret < 0) {
+		wl12xx_queue_recovery_work(wl);
+		goto out;
+	}
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
 static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif,
 			     struct cfg80211_scan_request *req)
@@ -3241,7 +3412,7 @@
 		goto out_sleep;
 	}
 
-	ret = wl1271_scan(hw->priv, vif, ssid, len, req);
+	ret = wlcore_scan(hw->priv, vif, ssid, len, req);
 out_sleep:
 	wl1271_ps_elp_sleep(wl);
 out:
@@ -3254,6 +3425,7 @@
 				     struct ieee80211_vif *vif)
 {
 	struct wl1271 *wl = hw->priv;
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int ret;
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
@@ -3271,7 +3443,7 @@
 		goto out;
 
 	if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
-		ret = wl1271_scan_stop(wl);
+		ret = wl->ops->scan_stop(wl, wlvif);
 		if (ret < 0)
 			goto out_sleep;
 	}
@@ -3284,7 +3456,7 @@
 
 	wl->scan.state = WL1271_SCAN_STATE_IDLE;
 	memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
-	wl->scan_vif = NULL;
+	wl->scan_wlvif = NULL;
 	wl->scan.req = NULL;
 	ieee80211_scan_completed(wl->hw, true);
 
@@ -3318,15 +3490,11 @@
 	if (ret < 0)
 		goto out;
 
-	ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
+	ret = wl->ops->sched_scan_start(wl, wlvif, req, ies);
 	if (ret < 0)
 		goto out_sleep;
 
-	ret = wl1271_scan_sched_scan_start(wl, wlvif);
-	if (ret < 0)
-		goto out_sleep;
-
-	wl->sched_scanning = true;
+	wl->sched_vif = wlvif;
 
 out_sleep:
 	wl1271_ps_elp_sleep(wl);
@@ -3353,7 +3521,7 @@
 	if (ret < 0)
 		goto out;
 
-	wl1271_scan_sched_scan_stop(wl, wlvif);
+	wl->ops->sched_scan_stop(wl, wlvif);
 
 	wl1271_ps_elp_sleep(wl);
 out:
@@ -3418,30 +3586,6 @@
 	return ret;
 }
 
-static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
-			    int offset)
-{
-	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-	u8 ssid_len;
-	const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
-					 skb->len - offset);
-
-	if (!ptr) {
-		wl1271_error("No SSID in IEs!");
-		return -ENOENT;
-	}
-
-	ssid_len = ptr[1];
-	if (ssid_len > IEEE80211_MAX_SSID_LEN) {
-		wl1271_error("SSID is too long!");
-		return -EINVAL;
-	}
-
-	wlvif->ssid_len = ssid_len;
-	memcpy(wlvif->ssid, ptr+2, ssid_len);
-	return 0;
-}
-
 static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
 {
 	int len;
@@ -3622,7 +3766,7 @@
 
 	wl1271_debug(DEBUG_MASTER, "beacon updated");
 
-	ret = wl1271_ssid_set(vif, beacon, ieoffset);
+	ret = wl1271_ssid_set(wlvif, beacon, ieoffset);
 	if (ret < 0) {
 		dev_kfree_skb(beacon);
 		goto out;
@@ -3639,6 +3783,12 @@
 		goto out;
 	}
 
+	wlvif->wmm_enabled =
+		cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+					WLAN_OUI_TYPE_MICROSOFT_WMM,
+					beacon->data + ieoffset,
+					beacon->len - ieoffset);
+
 	/*
 	 * In case we already have a probe-resp beacon set explicitly
 	 * by usermode, don't use the beacon data.
@@ -3692,7 +3842,7 @@
 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 	int ret = 0;
 
-	if ((changed & BSS_CHANGED_BEACON_INT)) {
+	if (changed & BSS_CHANGED_BEACON_INT) {
 		wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
 			bss_conf->beacon_int);
 
@@ -3705,7 +3855,7 @@
 		wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
 	}
 
-	if ((changed & BSS_CHANGED_BEACON)) {
+	if (changed & BSS_CHANGED_BEACON) {
 		ret = wlcore_set_beacon_template(wl, vif, is_ap);
 		if (ret < 0)
 			goto out;
@@ -3726,7 +3876,7 @@
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
 	int ret = 0;
 
-	if ((changed & BSS_CHANGED_BASIC_RATES)) {
+	if (changed & BSS_CHANGED_BASIC_RATES) {
 		u32 rates = bss_conf->basic_rates;
 
 		wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
@@ -3757,7 +3907,7 @@
 	if (ret < 0)
 		goto out;
 
-	if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
+	if (changed & BSS_CHANGED_BEACON_ENABLED) {
 		if (bss_conf->enable_beacon) {
 			if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
 				ret = wl12xx_cmd_role_start_ap(wl, wlvif);
@@ -3804,6 +3954,79 @@
 	return;
 }
 
+static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			    struct ieee80211_bss_conf *bss_conf,
+			    u32 sta_rate_set)
+{
+	u32 rates;
+	int ret;
+
+	wl1271_debug(DEBUG_MAC80211,
+	     "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x",
+	     bss_conf->bssid, bss_conf->aid,
+	     bss_conf->beacon_int,
+	     bss_conf->basic_rates, sta_rate_set);
+
+	wlvif->beacon_int = bss_conf->beacon_int;
+	rates = bss_conf->basic_rates;
+	wlvif->basic_rate_set =
+		wl1271_tx_enabled_rates_get(wl, rates,
+					    wlvif->band);
+	wlvif->basic_rate =
+		wl1271_tx_min_rate_get(wl,
+				       wlvif->basic_rate_set);
+
+	if (sta_rate_set)
+		wlvif->rate_set =
+			wl1271_tx_enabled_rates_get(wl,
+						sta_rate_set,
+						wlvif->band);
+
+	/* we only support sched_scan while not connected */
+	if (wl->sched_vif == wlvif)
+		wl->ops->sched_scan_stop(wl, wlvif);
+
+	ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+	if (ret < 0)
+		return ret;
+
+	ret = wl12xx_cmd_build_null_data(wl, wlvif);
+	if (ret < 0)
+		return ret;
+
+	ret = wl1271_build_qos_null_data(wl, wl12xx_wlvif_to_vif(wlvif));
+	if (ret < 0)
+		return ret;
+
+	wlcore_set_ssid(wl, wlvif);
+
+	set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
+
+	return 0;
+}
+
+static int wlcore_clear_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+	int ret;
+
+	/* revert back to minimum rates for the current band */
+	wl1271_set_band_rate(wl, wlvif);
+	wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+
+	ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+	if (ret < 0)
+		return ret;
+
+	if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
+	    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) {
+		ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
+		if (ret < 0)
+			return ret;
+	}
+
+	clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
+	return 0;
+}
 /* STA/IBSS mode changes */
 static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
 					struct ieee80211_vif *vif,
@@ -3811,7 +4034,7 @@
 					u32 changed)
 {
 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-	bool do_join = false, set_assoc = false;
+	bool do_join = false;
 	bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
 	bool ibss_joined = false;
 	u32 sta_rate_set = 0;
@@ -3832,9 +4055,8 @@
 			set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
 			ibss_joined = true;
 		} else {
-			if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
-					       &wlvif->flags))
-				wl1271_unjoin(wl, wlvif);
+			wlcore_unset_assoc(wl, wlvif);
+			wl12xx_cmd_role_stop_sta(wl, wlvif);
 		}
 	}
 
@@ -3852,13 +4074,7 @@
 		do_join = true;
 	}
 
-	if (changed & BSS_CHANGED_IDLE && !is_ibss) {
-		ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
-		if (ret < 0)
-			wl1271_warning("idle mode change failed %d", ret);
-	}
-
-	if ((changed & BSS_CHANGED_CQM)) {
+	if (changed & BSS_CHANGED_CQM) {
 		bool enable = false;
 		if (bss_conf->cqm_rssi_thold)
 			enable = true;
@@ -3870,150 +4086,39 @@
 		wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
 	}
 
-	if (changed & BSS_CHANGED_BSSID)
-		if (!is_zero_ether_addr(bss_conf->bssid)) {
-			ret = wl12xx_cmd_build_null_data(wl, wlvif);
-			if (ret < 0)
-				goto out;
-
-			ret = wl1271_build_qos_null_data(wl, vif);
-			if (ret < 0)
-				goto out;
-		}
-
-	if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
+	if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT |
+		       BSS_CHANGED_ASSOC)) {
 		rcu_read_lock();
 		sta = ieee80211_find_sta(vif, bss_conf->bssid);
-		if (!sta)
-			goto sta_not_found;
+		if (sta) {
+			u8 *rx_mask = sta->ht_cap.mcs.rx_mask;
 
-		/* save the supp_rates of the ap */
-		sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
-		if (sta->ht_cap.ht_supported)
-			sta_rate_set |=
-			  (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
-			  (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
-		sta_ht_cap = sta->ht_cap;
-		sta_exists = true;
+			/* save the supp_rates of the ap */
+			sta_rate_set = sta->supp_rates[wlvif->band];
+			if (sta->ht_cap.ht_supported)
+				sta_rate_set |=
+					(rx_mask[0] << HW_HT_RATES_OFFSET) |
+					(rx_mask[1] << HW_MIMO_RATES_OFFSET);
+			sta_ht_cap = sta->ht_cap;
+			sta_exists = true;
+		}
 
-sta_not_found:
 		rcu_read_unlock();
 	}
 
-	if ((changed & BSS_CHANGED_ASSOC)) {
-		if (bss_conf->assoc) {
-			u32 rates;
-			int ieoffset;
-			wlvif->aid = bss_conf->aid;
-			wlvif->channel_type =
-				cfg80211_get_chandef_type(&bss_conf->chandef);
-			wlvif->beacon_int = bss_conf->beacon_int;
+	if (changed & BSS_CHANGED_BSSID) {
+		if (!is_zero_ether_addr(bss_conf->bssid)) {
+			ret = wlcore_set_bssid(wl, wlvif, bss_conf,
+					       sta_rate_set);
+			if (ret < 0)
+				goto out;
+
+			/* Need to update the BSSID (for filtering etc) */
 			do_join = true;
-			set_assoc = true;
-
-			/*
-			 * use basic rates from AP, and determine lowest rate
-			 * to use with control frames.
-			 */
-			rates = bss_conf->basic_rates;
-			wlvif->basic_rate_set =
-				wl1271_tx_enabled_rates_get(wl, rates,
-							    wlvif->band);
-			wlvif->basic_rate =
-				wl1271_tx_min_rate_get(wl,
-						       wlvif->basic_rate_set);
-			if (sta_rate_set)
-				wlvif->rate_set =
-					wl1271_tx_enabled_rates_get(wl,
-								sta_rate_set,
-								wlvif->band);
-			ret = wl1271_acx_sta_rate_policies(wl, wlvif);
-			if (ret < 0)
-				goto out;
-
-			/*
-			 * with wl1271, we don't need to update the
-			 * beacon_int and dtim_period, because the firmware
-			 * updates it by itself when the first beacon is
-			 * received after a join.
-			 */
-			ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
-			if (ret < 0)
-				goto out;
-
-			/*
-			 * Get a template for hardware connection maintenance
-			 */
-			dev_kfree_skb(wlvif->probereq);
-			wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
-									wlvif,
-									NULL);
-			ieoffset = offsetof(struct ieee80211_mgmt,
-					    u.probe_req.variable);
-			wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
-
-			/* enable the connection monitoring feature */
-			ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
-			if (ret < 0)
-				goto out;
 		} else {
-			/* use defaults when not associated */
-			bool was_assoc =
-			    !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
-						 &wlvif->flags);
-			bool was_ifup =
-			    !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
-						 &wlvif->flags);
-			wlvif->aid = 0;
-
-			/* free probe-request template */
-			dev_kfree_skb(wlvif->probereq);
-			wlvif->probereq = NULL;
-
-			/* revert back to minimum rates for the current band */
-			wl1271_set_band_rate(wl, wlvif);
-			wlvif->basic_rate =
-				wl1271_tx_min_rate_get(wl,
-						       wlvif->basic_rate_set);
-			ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+			ret = wlcore_clear_bssid(wl, wlvif);
 			if (ret < 0)
 				goto out;
-
-			/* disable connection monitor features */
-			ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
-
-			/* Disable the keep-alive feature */
-			ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
-			if (ret < 0)
-				goto out;
-
-			/* restore the bssid filter and go to dummy bssid */
-			if (was_assoc) {
-				/*
-				 * we might have to disable roc, if there was
-				 * no IF_OPER_UP notification.
-				 */
-				if (!was_ifup) {
-					ret = wl12xx_croc(wl, wlvif->role_id);
-					if (ret < 0)
-						goto out;
-				}
-				/*
-				 * (we also need to disable roc in case of
-				 * roaming on the same channel. until we will
-				 * have a better flow...)
-				 */
-				if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
-					ret = wl12xx_croc(wl,
-							  wlvif->dev_role_id);
-					if (ret < 0)
-						goto out;
-				}
-
-				wl1271_unjoin(wl, wlvif);
-				if (!bss_conf->idle)
-					wl12xx_start_dev(wl, wlvif);
-			}
 		}
 	}
 
@@ -4043,68 +4148,84 @@
 		goto out;
 
 	if (do_join) {
-		ret = wl1271_join(wl, wlvif, set_assoc);
+		ret = wlcore_join(wl, wlvif);
 		if (ret < 0) {
 			wl1271_warning("cmd join failed %d", ret);
 			goto out;
 		}
+	}
 
-		/* ROC until connected (after EAPOL exchange) */
-		if (!is_ibss) {
-			ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
+	if (changed & BSS_CHANGED_ASSOC) {
+		if (bss_conf->assoc) {
+			ret = wlcore_set_assoc(wl, wlvif, bss_conf,
+					       sta_rate_set);
 			if (ret < 0)
 				goto out;
 
 			if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
 				wl12xx_set_authorized(wl, wlvif);
+		} else {
+			wlcore_unset_assoc(wl, wlvif);
 		}
-		/*
-		 * stop device role if started (we might already be in
-		 * STA/IBSS role).
-		 */
-		if (wl12xx_dev_role_started(wlvif)) {
-			ret = wl12xx_stop_dev(wl, wlvif);
+	}
+
+	if (changed & BSS_CHANGED_PS) {
+		if ((bss_conf->ps) &&
+		    test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
+		    !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
+			int ps_mode;
+			char *ps_mode_str;
+
+			if (wl->conf.conn.forced_ps) {
+				ps_mode = STATION_POWER_SAVE_MODE;
+				ps_mode_str = "forced";
+			} else {
+				ps_mode = STATION_AUTO_PS_MODE;
+				ps_mode_str = "auto";
+			}
+
+			wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
+
+			ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
 			if (ret < 0)
-				goto out;
+				wl1271_warning("enter %s ps failed %d",
+					       ps_mode_str, ret);
+		} else if (!bss_conf->ps &&
+			   test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
+			wl1271_debug(DEBUG_PSM, "auto ps disabled");
+
+			ret = wl1271_ps_set_mode(wl, wlvif,
+						 STATION_ACTIVE_MODE);
+			if (ret < 0)
+				wl1271_warning("exit auto ps failed %d", ret);
 		}
 	}
 
 	/* Handle new association with HT. Do this after join. */
-	if (sta_exists) {
-		if ((changed & BSS_CHANGED_HT) &&
-		    (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
-			ret = wl1271_acx_set_ht_capabilities(wl,
-							     &sta_ht_cap,
-							     true,
-							     wlvif->sta.hlid);
-			if (ret < 0) {
-				wl1271_warning("Set ht cap true failed %d",
-					       ret);
-				goto out;
-			}
-		}
-		/* handle new association without HT and disassociation */
-		else if (changed & BSS_CHANGED_ASSOC) {
-			ret = wl1271_acx_set_ht_capabilities(wl,
-							     &sta_ht_cap,
-							     false,
-							     wlvif->sta.hlid);
-			if (ret < 0) {
-				wl1271_warning("Set ht cap false failed %d",
-					       ret);
-				goto out;
-			}
-		}
-	}
+	if (sta_exists &&
+	    (changed & BSS_CHANGED_HT)) {
+		bool enabled =
+			bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
 
-	/* Handle HT information change. Done after join. */
-	if ((changed & BSS_CHANGED_HT) &&
-	    (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
-		ret = wl1271_acx_set_ht_information(wl, wlvif,
-					bss_conf->ht_operation_mode);
+		ret = wlcore_hw_set_peer_cap(wl,
+					     &sta_ht_cap,
+					     enabled,
+					     wlvif->rate_set,
+					     wlvif->sta.hlid);
 		if (ret < 0) {
-			wl1271_warning("Set ht information failed %d", ret);
+			wl1271_warning("Set ht cap failed %d", ret);
 			goto out;
+
+		}
+
+		if (enabled) {
+			ret = wl1271_acx_set_ht_information(wl, wlvif,
+						bss_conf->ht_operation_mode);
+			if (ret < 0) {
+				wl1271_warning("Set ht information failed %d",
+					       ret);
+				goto out;
+			}
 		}
 	}
 
@@ -4115,8 +4236,7 @@
 		wlvif->sta.qos = bss_conf->qos;
 		WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
 
-		if (bss_conf->arp_addr_cnt == 1 &&
-		    bss_conf->arp_filter_enabled) {
+		if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) {
 			wlvif->ip_addr = addr;
 			/*
 			 * The template should have been configured only upon
@@ -4157,15 +4277,15 @@
 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 	int ret;
 
-	wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
-		     (int)changed);
+	wl1271_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x",
+		     wlvif->role_id, (int)changed);
 
 	/*
 	 * make sure to cancel pending disconnections if our association
 	 * state changed
 	 */
 	if (!is_ap && (changed & BSS_CHANGED_ASSOC))
-		cancel_delayed_work_sync(&wl->connection_loss_work);
+		cancel_delayed_work_sync(&wlvif->connection_loss_work);
 
 	if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
 	    !bss_conf->enable_beacon)
@@ -4194,6 +4314,76 @@
 	mutex_unlock(&wl->mutex);
 }
 
+static int wlcore_op_add_chanctx(struct ieee80211_hw *hw,
+				 struct ieee80211_chanctx_conf *ctx)
+{
+	wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)",
+		     ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+		     cfg80211_get_chandef_type(&ctx->def));
+	return 0;
+}
+
+static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw,
+				     struct ieee80211_chanctx_conf *ctx)
+{
+	wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)",
+		     ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+		     cfg80211_get_chandef_type(&ctx->def));
+}
+
+static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
+				     struct ieee80211_chanctx_conf *ctx,
+				     u32 changed)
+{
+	wl1271_debug(DEBUG_MAC80211,
+		     "mac80211 change chanctx %d (type %d) changed 0x%x",
+		     ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+		     cfg80211_get_chandef_type(&ctx->def), changed);
+}
+
+static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
+					struct ieee80211_chanctx_conf *ctx)
+{
+	struct wl1271 *wl = hw->priv;
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+	int channel = ieee80211_frequency_to_channel(
+		ctx->def.chan->center_freq);
+
+	wl1271_debug(DEBUG_MAC80211,
+		     "mac80211 assign chanctx (role %d) %d (type %d)",
+		     wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
+
+	mutex_lock(&wl->mutex);
+
+	wlvif->band = ctx->def.chan->band;
+	wlvif->channel = channel;
+	wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
+
+	/* update default rates according to the band */
+	wl1271_set_band_rate(wl, wlvif);
+
+	mutex_unlock(&wl->mutex);
+
+	return 0;
+}
+
+static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif,
+					   struct ieee80211_chanctx_conf *ctx)
+{
+	struct wl1271 *wl = hw->priv;
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+
+	wl1271_debug(DEBUG_MAC80211,
+		     "mac80211 unassign chanctx (role %d) %d (type %d)",
+		     wlvif->role_id,
+		     ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+		     cfg80211_get_chandef_type(&ctx->def));
+
+	wl1271_tx_flush(wl);
+}
+
 static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
 			     struct ieee80211_vif *vif, u16 queue,
 			     const struct ieee80211_tx_queue_params *params)
@@ -4321,8 +4511,6 @@
 		return;
 
 	clear_bit(hlid, wlvif->ap.sta_hlid_map);
-	memset(wl->links[hlid].addr, 0, ETH_ALEN);
-	wl->links[hlid].ba_bitmap = 0;
 	__clear_bit(hlid, &wl->ap_ps_map);
 	__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
 	wl12xx_free_link(wl, wlvif, &hlid);
@@ -4382,6 +4570,45 @@
 	return ret;
 }
 
+static void wlcore_roc_if_possible(struct wl1271 *wl,
+				   struct wl12xx_vif *wlvif)
+{
+	if (find_first_bit(wl->roc_map,
+			   WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)
+		return;
+
+	if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID))
+		return;
+
+	wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
+}
+
+static void wlcore_update_inconn_sta(struct wl1271 *wl,
+				     struct wl12xx_vif *wlvif,
+				     struct wl1271_station *wl_sta,
+				     bool in_connection)
+{
+	if (in_connection) {
+		if (WARN_ON(wl_sta->in_connection))
+			return;
+		wl_sta->in_connection = true;
+		if (!wlvif->inconn_count++)
+			wlcore_roc_if_possible(wl, wlvif);
+	} else {
+		if (!wl_sta->in_connection)
+			return;
+
+		wl_sta->in_connection = false;
+		wlvif->inconn_count--;
+		if (WARN_ON(wlvif->inconn_count < 0))
+			return;
+
+		if (!wlvif->inconn_count)
+			if (test_bit(wlvif->role_id, wl->roc_map))
+				wl12xx_croc(wl, wlvif->role_id);
+	}
+}
+
 static int wl12xx_update_sta_state(struct wl1271 *wl,
 				   struct wl12xx_vif *wlvif,
 				   struct ieee80211_sta *sta,
@@ -4400,8 +4627,13 @@
 	/* Add station (AP mode) */
 	if (is_ap &&
 	    old_state == IEEE80211_STA_NOTEXIST &&
-	    new_state == IEEE80211_STA_NONE)
-		return wl12xx_sta_add(wl, wlvif, sta);
+	    new_state == IEEE80211_STA_NONE) {
+		ret = wl12xx_sta_add(wl, wlvif, sta);
+		if (ret)
+			return ret;
+
+		wlcore_update_inconn_sta(wl, wlvif, wl_sta, true);
+	}
 
 	/* Remove station (AP mode) */
 	if (is_ap &&
@@ -4409,35 +4641,59 @@
 	    new_state == IEEE80211_STA_NOTEXIST) {
 		/* must not fail */
 		wl12xx_sta_remove(wl, wlvif, sta);
-		return 0;
+
+		wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
 	}
 
 	/* Authorize station (AP mode) */
 	if (is_ap &&
 	    new_state == IEEE80211_STA_AUTHORIZED) {
-		ret = wl12xx_cmd_set_peer_state(wl, hlid);
+		ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid);
 		if (ret < 0)
 			return ret;
 
 		ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
 						     hlid);
-		return ret;
+		if (ret)
+			return ret;
+
+		wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
 	}
 
 	/* Authorize station */
 	if (is_sta &&
 	    new_state == IEEE80211_STA_AUTHORIZED) {
 		set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
-		return wl12xx_set_authorized(wl, wlvif);
+		ret = wl12xx_set_authorized(wl, wlvif);
+		if (ret)
+			return ret;
 	}
 
 	if (is_sta &&
 	    old_state == IEEE80211_STA_AUTHORIZED &&
 	    new_state == IEEE80211_STA_ASSOC) {
 		clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
-		return 0;
+		clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags);
 	}
 
+	/* clear ROCs on failure or authorization */
+	if (is_sta &&
+	    (new_state == IEEE80211_STA_AUTHORIZED ||
+	     new_state == IEEE80211_STA_NOTEXIST)) {
+		if (test_bit(wlvif->role_id, wl->roc_map))
+			wl12xx_croc(wl, wlvif->role_id);
+	}
+
+	if (is_sta &&
+	    old_state == IEEE80211_STA_NOTEXIST &&
+	    new_state == IEEE80211_STA_NONE) {
+		if (find_first_bit(wl->roc_map,
+				   WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) {
+			WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID);
+			wl12xx_roc(wl, wlvif, wlvif->role_id,
+				   wlvif->band, wlvif->channel);
+		}
+	}
 	return 0;
 }
 
@@ -4502,18 +4758,18 @@
 
 	if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
 		hlid = wlvif->sta.hlid;
-		ba_bitmap = &wlvif->sta.ba_rx_bitmap;
 	} else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
 		struct wl1271_station *wl_sta;
 
 		wl_sta = (struct wl1271_station *)sta->drv_priv;
 		hlid = wl_sta->hlid;
-		ba_bitmap = &wl->links[hlid].ba_bitmap;
 	} else {
 		ret = -EINVAL;
 		goto out;
 	}
 
+	ba_bitmap = &wl->links[hlid].ba_bitmap;
+
 	ret = wl1271_ps_elp_wakeup(wl);
 	if (ret < 0)
 		goto out;
@@ -4575,7 +4831,9 @@
 	 * Falling break here on purpose for all TX APDU commands.
 	 */
 	case IEEE80211_AMPDU_TX_START:
-	case IEEE80211_AMPDU_TX_STOP:
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 		ret = -EINVAL;
 		break;
@@ -4665,12 +4923,23 @@
 
 	/* TODO: change mac80211 to pass vif as param */
 	wl12xx_for_each_wlvif_sta(wl, wlvif) {
-		ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
+		unsigned long delay_usec;
 
-		if (!ret)
-			set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
+		ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
+		if (ret)
+			goto out_sleep;
+
+		set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
+
+		/* indicate failure 5 seconds after channel switch time */
+		delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
+			     ch_switch->count;
+		ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
+				usecs_to_jiffies(delay_usec) +
+				msecs_to_jiffies(5000));
 	}
 
+out_sleep:
 	wl1271_ps_elp_sleep(wl);
 
 out:
@@ -4684,6 +4953,144 @@
 	wl1271_tx_flush(wl);
 }
 
+static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif,
+				       struct ieee80211_channel *chan,
+				       int duration)
+{
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+	struct wl1271 *wl = hw->priv;
+	int channel, ret = 0;
+
+	channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+	wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)",
+		     channel, wlvif->role_id);
+
+	mutex_lock(&wl->mutex);
+
+	if (unlikely(wl->state != WLCORE_STATE_ON))
+		goto out;
+
+	/* return EBUSY if we can't ROC right now */
+	if (WARN_ON(wl->roc_vif ||
+		    find_first_bit(wl->roc_map,
+				   WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = wl12xx_start_dev(wl, wlvif, chan->band, channel);
+	if (ret < 0)
+		goto out_sleep;
+
+	wl->roc_vif = vif;
+	ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
+				     msecs_to_jiffies(duration));
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+	return ret;
+}
+
+static int __wlcore_roc_completed(struct wl1271 *wl)
+{
+	struct wl12xx_vif *wlvif;
+	int ret;
+
+	/* already completed */
+	if (unlikely(!wl->roc_vif))
+		return 0;
+
+	wlvif = wl12xx_vif_to_data(wl->roc_vif);
+
+	if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
+		return -EBUSY;
+
+	ret = wl12xx_stop_dev(wl, wlvif);
+	if (ret < 0)
+		return ret;
+
+	wl->roc_vif = NULL;
+
+	return 0;
+}
+
+static int wlcore_roc_completed(struct wl1271 *wl)
+{
+	int ret;
+
+	wl1271_debug(DEBUG_MAC80211, "roc complete");
+
+	mutex_lock(&wl->mutex);
+
+	if (unlikely(wl->state != WLCORE_STATE_ON)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	ret = __wlcore_roc_completed(wl);
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+
+	return ret;
+}
+
+static void wlcore_roc_complete_work(struct work_struct *work)
+{
+	struct delayed_work *dwork;
+	struct wl1271 *wl;
+	int ret;
+
+	dwork = container_of(work, struct delayed_work, work);
+	wl = container_of(dwork, struct wl1271, roc_complete_work);
+
+	ret = wlcore_roc_completed(wl);
+	if (!ret)
+		ieee80211_remain_on_channel_expired(wl->hw);
+}
+
+static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+	struct wl1271 *wl = hw->priv;
+
+	wl1271_debug(DEBUG_MAC80211, "mac80211 croc");
+
+	/* TODO: per-vif */
+	wl1271_tx_flush(wl);
+
+	/*
+	 * we can't just flush_work here, because it might deadlock
+	 * (as we might get called from the same workqueue)
+	 */
+	cancel_delayed_work_sync(&wl->roc_complete_work);
+	wlcore_roc_completed(wl);
+
+	return 0;
+}
+
+static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_sta *sta,
+				    u32 changed)
+{
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+	struct wl1271 *wl = hw->priv;
+
+	wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
+}
+
 static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
 {
 	struct wl1271 *wl = hw->priv;
@@ -4747,20 +5154,20 @@
 
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_channel wl1271_channels[] = {
-	{ .hw_value = 1, .center_freq = 2412, .max_power = 25 },
-	{ .hw_value = 2, .center_freq = 2417, .max_power = 25 },
-	{ .hw_value = 3, .center_freq = 2422, .max_power = 25 },
-	{ .hw_value = 4, .center_freq = 2427, .max_power = 25 },
-	{ .hw_value = 5, .center_freq = 2432, .max_power = 25 },
-	{ .hw_value = 6, .center_freq = 2437, .max_power = 25 },
-	{ .hw_value = 7, .center_freq = 2442, .max_power = 25 },
-	{ .hw_value = 8, .center_freq = 2447, .max_power = 25 },
-	{ .hw_value = 9, .center_freq = 2452, .max_power = 25 },
-	{ .hw_value = 10, .center_freq = 2457, .max_power = 25 },
-	{ .hw_value = 11, .center_freq = 2462, .max_power = 25 },
-	{ .hw_value = 12, .center_freq = 2467, .max_power = 25 },
-	{ .hw_value = 13, .center_freq = 2472, .max_power = 25 },
-	{ .hw_value = 14, .center_freq = 2484, .max_power = 25 },
+	{ .hw_value = 1, .center_freq = 2412, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 2, .center_freq = 2417, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 3, .center_freq = 2422, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 4, .center_freq = 2427, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 5, .center_freq = 2432, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 6, .center_freq = 2437, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 7, .center_freq = 2442, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 8, .center_freq = 2447, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 9, .center_freq = 2452, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 10, .center_freq = 2457, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR },
 };
 
 /* can't be const, mac80211 writes to this */
@@ -4801,40 +5208,40 @@
 
 /* 5 GHz band channels for WL1273 */
 static struct ieee80211_channel wl1271_channels_5ghz[] = {
-	{ .hw_value = 7, .center_freq = 5035, .max_power = 25 },
-	{ .hw_value = 8, .center_freq = 5040, .max_power = 25 },
-	{ .hw_value = 9, .center_freq = 5045, .max_power = 25 },
-	{ .hw_value = 11, .center_freq = 5055, .max_power = 25 },
-	{ .hw_value = 12, .center_freq = 5060, .max_power = 25 },
-	{ .hw_value = 16, .center_freq = 5080, .max_power = 25 },
-	{ .hw_value = 34, .center_freq = 5170, .max_power = 25 },
-	{ .hw_value = 36, .center_freq = 5180, .max_power = 25 },
-	{ .hw_value = 38, .center_freq = 5190, .max_power = 25 },
-	{ .hw_value = 40, .center_freq = 5200, .max_power = 25 },
-	{ .hw_value = 42, .center_freq = 5210, .max_power = 25 },
-	{ .hw_value = 44, .center_freq = 5220, .max_power = 25 },
-	{ .hw_value = 46, .center_freq = 5230, .max_power = 25 },
-	{ .hw_value = 48, .center_freq = 5240, .max_power = 25 },
-	{ .hw_value = 52, .center_freq = 5260, .max_power = 25 },
-	{ .hw_value = 56, .center_freq = 5280, .max_power = 25 },
-	{ .hw_value = 60, .center_freq = 5300, .max_power = 25 },
-	{ .hw_value = 64, .center_freq = 5320, .max_power = 25 },
-	{ .hw_value = 100, .center_freq = 5500, .max_power = 25 },
-	{ .hw_value = 104, .center_freq = 5520, .max_power = 25 },
-	{ .hw_value = 108, .center_freq = 5540, .max_power = 25 },
-	{ .hw_value = 112, .center_freq = 5560, .max_power = 25 },
-	{ .hw_value = 116, .center_freq = 5580, .max_power = 25 },
-	{ .hw_value = 120, .center_freq = 5600, .max_power = 25 },
-	{ .hw_value = 124, .center_freq = 5620, .max_power = 25 },
-	{ .hw_value = 128, .center_freq = 5640, .max_power = 25 },
-	{ .hw_value = 132, .center_freq = 5660, .max_power = 25 },
-	{ .hw_value = 136, .center_freq = 5680, .max_power = 25 },
-	{ .hw_value = 140, .center_freq = 5700, .max_power = 25 },
-	{ .hw_value = 149, .center_freq = 5745, .max_power = 25 },
-	{ .hw_value = 153, .center_freq = 5765, .max_power = 25 },
-	{ .hw_value = 157, .center_freq = 5785, .max_power = 25 },
-	{ .hw_value = 161, .center_freq = 5805, .max_power = 25 },
-	{ .hw_value = 165, .center_freq = 5825, .max_power = 25 },
+	{ .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 36, .center_freq = 5180, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 38, .center_freq = 5190, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 40, .center_freq = 5200, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 42, .center_freq = 5210, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 44, .center_freq = 5220, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 46, .center_freq = 5230, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 48, .center_freq = 5240, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 52, .center_freq = 5260, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 56, .center_freq = 5280, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 60, .center_freq = 5300, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 64, .center_freq = 5320, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 100, .center_freq = 5500, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 104, .center_freq = 5520, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 108, .center_freq = 5540, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 112, .center_freq = 5560, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 116, .center_freq = 5580, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 120, .center_freq = 5600, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 124, .center_freq = 5620, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 128, .center_freq = 5640, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 132, .center_freq = 5660, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 136, .center_freq = 5680, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 140, .center_freq = 5700, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 149, .center_freq = 5745, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 153, .center_freq = 5765, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 157, .center_freq = 5785, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 161, .center_freq = 5805, .max_power = WLCORE_MAX_TXPWR },
+	{ .hw_value = 165, .center_freq = 5825, .max_power = WLCORE_MAX_TXPWR },
 };
 
 static struct ieee80211_supported_band wl1271_band_5ghz = {
@@ -4875,6 +5282,14 @@
 	.set_bitrate_mask = wl12xx_set_bitrate_mask,
 	.channel_switch = wl12xx_op_channel_switch,
 	.flush = wlcore_op_flush,
+	.remain_on_channel = wlcore_op_remain_on_channel,
+	.cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel,
+	.add_chanctx = wlcore_op_add_chanctx,
+	.remove_chanctx = wlcore_op_remove_chanctx,
+	.change_chanctx = wlcore_op_change_chanctx,
+	.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
+	.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
+	.sta_rc_update = wlcore_op_sta_rc_update,
 	CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
@@ -5044,34 +5459,6 @@
 	.read = wl1271_sysfs_read_fwlog,
 };
 
-static void wl1271_connection_loss_work(struct work_struct *work)
-{
-	struct delayed_work *dwork;
-	struct wl1271 *wl;
-	struct ieee80211_vif *vif;
-	struct wl12xx_vif *wlvif;
-
-	dwork = container_of(work, struct delayed_work, work);
-	wl = container_of(dwork, struct wl1271, connection_loss_work);
-
-	wl1271_info("Connection loss work.");
-
-	mutex_lock(&wl->mutex);
-
-	if (unlikely(wl->state != WLCORE_STATE_ON))
-		goto out;
-
-	/* Call mac80211 connection loss */
-	wl12xx_for_each_wlvif_sta(wl, wlvif) {
-		if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-			goto out;
-		vif = wl12xx_wlvif_to_vif(wlvif);
-		ieee80211_connection_loss(vif);
-	}
-out:
-	mutex_unlock(&wl->mutex);
-}
-
 static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
 {
 	int i;
@@ -5117,7 +5504,7 @@
 
 	ret = wl12xx_set_power_on(wl);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
 	if (ret < 0)
@@ -5207,10 +5594,9 @@
 	},
 };
 
-static const struct ieee80211_iface_combination
+static struct ieee80211_iface_combination
 wlcore_iface_combinations[] = {
 	{
-	  .num_different_channels = 1,
 	  .max_interfaces = 3,
 	  .limits = wlcore_iface_limits,
 	  .n_limits = ARRAY_SIZE(wlcore_iface_limits),
@@ -5219,6 +5605,7 @@
 
 static int wl1271_init_ieee80211(struct wl1271 *wl)
 {
+	int i;
 	static const u32 cipher_suites[] = {
 		WLAN_CIPHER_SUITE_WEP40,
 		WLAN_CIPHER_SUITE_WEP104,
@@ -5249,7 +5636,7 @@
 		IEEE80211_HW_AP_LINK_PS |
 		IEEE80211_HW_AMPDU_AGGREGATION |
 		IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
-		IEEE80211_HW_SCAN_WHILE_IDLE;
+		IEEE80211_HW_QUEUE_CONTROL;
 
 	wl->hw->wiphy->cipher_suites = cipher_suites;
 	wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -5271,6 +5658,8 @@
 	wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
 		sizeof(struct ieee80211_header);
 
+	wl->hw->wiphy->max_remain_on_channel_duration = 5000;
+
 	wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
 				WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
@@ -5279,6 +5668,22 @@
 		     ARRAY_SIZE(wl1271_channels_5ghz) >
 		     WL1271_MAX_CHANNELS);
 	/*
+	* clear channel flags from the previous usage
+	* and restore max_power & max_antenna_gain values.
+	*/
+	for (i = 0; i < ARRAY_SIZE(wl1271_channels); i++) {
+		wl1271_band_2ghz.channels[i].flags = 0;
+		wl1271_band_2ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
+		wl1271_band_2ghz.channels[i].max_antenna_gain = 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wl1271_channels_5ghz); i++) {
+		wl1271_band_5ghz.channels[i].flags = 0;
+		wl1271_band_5ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
+		wl1271_band_5ghz.channels[i].max_antenna_gain = 0;
+	}
+
+	/*
 	 * We keep local copies of the band structs because we need to
 	 * modify them on a per-device basis.
 	 */
@@ -5298,7 +5703,14 @@
 	wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
 		&wl->bands[IEEE80211_BAND_5GHZ];
 
-	wl->hw->queues = 4;
+	/*
+	 * allow 4 queues per mac address we support +
+	 * 1 cab queue per mac + one global offchannel Tx queue
+	 */
+	wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1;
+
+	/* the last queue is the offchannel queue */
+	wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1;
 	wl->hw->max_rates = 1;
 
 	wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
@@ -5311,6 +5723,7 @@
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 
 	/* allowed interface combinations */
+	wlcore_iface_combinations[0].num_different_channels = wl->num_channels;
 	wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
 	wl->hw->wiphy->n_iface_combinations =
 		ARRAY_SIZE(wlcore_iface_combinations);
@@ -5327,7 +5740,8 @@
 
 #define WL1271_DEFAULT_CHANNEL 0
 
-struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
+struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
+				     u32 mbox_size)
 {
 	struct ieee80211_hw *hw;
 	struct wl1271 *wl;
@@ -5369,9 +5783,8 @@
 	INIT_WORK(&wl->tx_work, wl1271_tx_work);
 	INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
 	INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
+	INIT_DELAYED_WORK(&wl->roc_complete_work, wlcore_roc_complete_work);
 	INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
-	INIT_DELAYED_WORK(&wl->connection_loss_work,
-			  wl1271_connection_loss_work);
 
 	wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
 	if (!wl->freezable_wq) {
@@ -5387,14 +5800,15 @@
 	wl->flags = 0;
 	wl->sg_enabled = true;
 	wl->sleep_auth = WL1271_PSM_ILLEGAL;
+	wl->recovery_count = 0;
 	wl->hw_pg_ver = -1;
 	wl->ap_ps_map = 0;
 	wl->ap_fw_ps_map = 0;
 	wl->quirks = 0;
 	wl->platform_quirks = 0;
-	wl->sched_scanning = false;
 	wl->system_hlid = WL12XX_SYSTEM_HLID;
 	wl->active_sta_count = 0;
+	wl->active_link_count = 0;
 	wl->fwlog_size = 0;
 	init_waitqueue_head(&wl->fwlog_waitq);
 
@@ -5434,14 +5848,24 @@
 		goto err_dummy_packet;
 	}
 
-	wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA);
+	wl->mbox_size = mbox_size;
+	wl->mbox = kmalloc(wl->mbox_size, GFP_KERNEL | GFP_DMA);
 	if (!wl->mbox) {
 		ret = -ENOMEM;
 		goto err_fwlog;
 	}
 
+	wl->buffer_32 = kmalloc(sizeof(*wl->buffer_32), GFP_KERNEL);
+	if (!wl->buffer_32) {
+		ret = -ENOMEM;
+		goto err_mbox;
+	}
+
 	return hw;
 
+err_mbox:
+	kfree(wl->mbox);
+
 err_fwlog:
 	free_page((unsigned long)wl->fwlog);
 
@@ -5480,6 +5904,8 @@
 	device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
 
 	device_remove_file(wl->dev, &dev_attr_bt_coex_state);
+	kfree(wl->buffer_32);
+	kfree(wl->mbox);
 	free_page((unsigned long)wl->fwlog);
 	dev_kfree_skb(wl->dummy_packet);
 	free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size));
@@ -5536,7 +5962,8 @@
 {
 	struct wl1271 *wl = context;
 	struct platform_device *pdev = wl->pdev;
-	struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
+	struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data;
+	struct wl12xx_platform_data *pdata = pdev_data->pdata;
 	unsigned long irqflags;
 	int ret;
 
@@ -5565,8 +5992,7 @@
 
 	wl->irq = platform_get_irq(pdev, 0);
 	wl->platform_quirks = pdata->platform_quirks;
-	wl->set_power = pdata->set_power;
-	wl->if_ops = pdata->ops;
+	wl->if_ops = pdev_data->if_ops;
 
 	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
 		irqflags = IRQF_TRIGGER_RISING;
@@ -5712,10 +6138,10 @@
 MODULE_PARM_DESC(fwlog,
 		 "FW logger options: continuous, ondemand, dbgpins or disable");
 
-module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
+module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
 
-module_param(no_recovery, bool, S_IRUSR | S_IWUSR);
+module_param(no_recovery, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 4d1414a..9b7b6e2 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -151,9 +151,6 @@
 			wl12xx_queue_recovery_work(wl);
 			ret = -ETIMEDOUT;
 			goto err;
-		} else if (ret < 0) {
-			wl1271_error("ELP wakeup completion error.");
-			goto err;
 		}
 	}
 
@@ -242,11 +239,12 @@
 	struct ieee80211_tx_info *info;
 	unsigned long flags;
 	int filtered[NUM_TX_QUEUES];
+	struct wl1271_link *lnk = &wl->links[hlid];
 
 	/* filter all frames currently in the low level queues for this hlid */
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		filtered[i] = 0;
-		while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+		while ((skb = skb_dequeue(&lnk->tx_queue[i]))) {
 			filtered[i]++;
 
 			if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
@@ -260,8 +258,11 @@
 	}
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
-	for (i = 0; i < NUM_TX_QUEUES; i++)
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		wl->tx_queue_count[i] -= filtered[i];
+		if (lnk->wlvif)
+			lnk->wlvif->tx_queue_count[i] -= filtered[i];
+	}
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 
 	wl1271_handle_tx_low_watermark(wl);
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index 9ee0ec6..6791a1a 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -92,11 +92,16 @@
 		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
 				RX_FLAG_DECRYPTED;
 
-		if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
+		if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) {
 			status->flag |= RX_FLAG_MMIC_ERROR;
-			wl1271_warning("Michael MIC error");
+			wl1271_warning("Michael MIC error. Desc: 0x%x",
+				       desc_err_code);
 		}
 	}
+
+	if (beacon)
+		wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel,
+						status->band);
 }
 
 static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
@@ -108,7 +113,7 @@
 	u8 *buf;
 	u8 beacon = 0;
 	u8 is_data = 0;
-	u8 reserved = 0;
+	u8 reserved = 0, offset_to_data = 0;
 	u16 seq_num;
 	u32 pkt_data_len;
 
@@ -128,6 +133,8 @@
 
 	if (rx_align == WLCORE_RX_BUF_UNALIGNED)
 		reserved = RX_BUF_ALIGN;
+	else if (rx_align == WLCORE_RX_BUF_PADDED)
+		offset_to_data = RX_BUF_ALIGN;
 
 	/* the data read starts with the descriptor */
 	desc = (struct wl1271_rx_descriptor *) data;
@@ -139,19 +146,15 @@
 		return 0;
 	}
 
-	switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
 	/* discard corrupted packets */
-	case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
-	case WL1271_RX_DESC_DECRYPT_FAIL:
-		wl1271_warning("corrupted packet in RX with status: 0x%x",
-			       desc->status & WL1271_RX_DESC_STATUS_MASK);
-		return -EINVAL;
-	case WL1271_RX_DESC_SUCCESS:
-	case WL1271_RX_DESC_MIC_FAIL:
-		break;
-	default:
-		wl1271_error("invalid RX descriptor status: 0x%x",
-			     desc->status & WL1271_RX_DESC_STATUS_MASK);
+	if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) {
+		hdr = (void *)(data + sizeof(*desc) + offset_to_data);
+		wl1271_warning("corrupted packet in RX: status: 0x%x len: %d",
+			       desc->status & WL1271_RX_DESC_STATUS_MASK,
+			       pkt_data_len);
+		wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc),
+			    min(pkt_data_len,
+				ieee80211_hdrlen(hdr->frame_control)));
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h
index 71eba18..3363f60 100644
--- a/drivers/net/wireless/ti/wlcore/rx.h
+++ b/drivers/net/wireless/ti/wlcore/rx.h
@@ -84,12 +84,11 @@
  * Bits 3-5 - process_id tag (AP mode FW)
  * Bits 6-7 - reserved
  */
-#define WL1271_RX_DESC_STATUS_MASK      0x03
+#define WL1271_RX_DESC_STATUS_MASK      0x07
 
 #define WL1271_RX_DESC_SUCCESS          0x00
 #define WL1271_RX_DESC_DECRYPT_FAIL     0x01
 #define WL1271_RX_DESC_MIC_FAIL         0x02
-#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03
 
 #define RX_MEM_BLOCK_MASK            0xFF
 #define RX_BUF_SIZE_MASK             0xFFF00
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c
index d005014..f407101 100644
--- a/drivers/net/wireless/ti/wlcore/scan.c
+++ b/drivers/net/wireless/ti/wlcore/scan.c
@@ -35,7 +35,6 @@
 {
 	struct delayed_work *dwork;
 	struct wl1271 *wl;
-	struct ieee80211_vif *vif;
 	struct wl12xx_vif *wlvif;
 	int ret;
 
@@ -52,8 +51,7 @@
 	if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
 		goto out;
 
-	vif = wl->scan_vif;
-	wlvif = wl12xx_vif_to_data(vif);
+	wlvif = wl->scan_wlvif;
 
 	/*
 	 * Rearm the tx watchdog just before idling scan. This
@@ -64,7 +62,7 @@
 	wl->scan.state = WL1271_SCAN_STATE_IDLE;
 	memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
 	wl->scan.req = NULL;
-	wl->scan_vif = NULL;
+	wl->scan_wlvif = NULL;
 
 	ret = wl1271_ps_elp_wakeup(wl);
 	if (ret < 0)
@@ -82,6 +80,8 @@
 		wl12xx_queue_recovery_work(wl);
 	}
 
+	wlcore_cmd_regdomain_config_locked(wl);
+
 	ieee80211_scan_completed(wl->hw, false);
 
 out:
@@ -89,371 +89,99 @@
 
 }
 
-
-static int wl1271_get_scan_channels(struct wl1271 *wl,
-				    struct cfg80211_scan_request *req,
-				    struct basic_scan_channel_params *channels,
-				    enum ieee80211_band band, bool passive)
+static void wlcore_started_vifs_iter(void *data, u8 *mac,
+				     struct ieee80211_vif *vif)
 {
-	struct conf_scan_settings *c = &wl->conf.scan;
-	int i, j;
-	u32 flags;
+	int *count = (int *)data;
 
-	for (i = 0, j = 0;
-	     i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
-	     i++) {
-		flags = req->channels[i]->flags;
-
-		if (!test_bit(i, wl->scan.scanned_ch) &&
-		    !(flags & IEEE80211_CHAN_DISABLED) &&
-		    (req->channels[i]->band == band) &&
-		    /*
-		     * In passive scans, we scan all remaining
-		     * channels, even if not marked as such.
-		     * In active scans, we only scan channels not
-		     * marked as passive.
-		     */
-		    (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
-			wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
-				     req->channels[i]->band,
-				     req->channels[i]->center_freq);
-			wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
-				     req->channels[i]->hw_value,
-				     req->channels[i]->flags);
-			wl1271_debug(DEBUG_SCAN,
-				     "max_antenna_gain %d, max_power %d",
-				     req->channels[i]->max_antenna_gain,
-				     req->channels[i]->max_power);
-			wl1271_debug(DEBUG_SCAN, "beacon_found %d",
-				     req->channels[i]->beacon_found);
-
-			if (!passive) {
-				channels[j].min_duration =
-					cpu_to_le32(c->min_dwell_time_active);
-				channels[j].max_duration =
-					cpu_to_le32(c->max_dwell_time_active);
-			} else {
-				channels[j].min_duration =
-					cpu_to_le32(c->min_dwell_time_passive);
-				channels[j].max_duration =
-					cpu_to_le32(c->max_dwell_time_passive);
-			}
-			channels[j].early_termination = 0;
-			channels[j].tx_power_att = req->channels[i]->max_power;
-			channels[j].channel = req->channels[i]->hw_value;
-
-			memset(&channels[j].bssid_lsb, 0xff, 4);
-			memset(&channels[j].bssid_msb, 0xff, 2);
-
-			/* Mark the channels we already used */
-			set_bit(i, wl->scan.scanned_ch);
-
-			j++;
-		}
-	}
-
-	return j;
+	if (!vif->bss_conf.idle)
+		(*count)++;
 }
 
-#define WL1271_NOTHING_TO_SCAN 1
-
-static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
-			    enum ieee80211_band band,
-			    bool passive, u32 basic_rate)
+static int wlcore_count_started_vifs(struct wl1271 *wl)
 {
-	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-	struct wl1271_cmd_scan *cmd;
-	struct wl1271_cmd_trigger_scan_to *trigger;
-	int ret;
-	u16 scan_options = 0;
+	int count = 0;
 
-	/* skip active scans if we don't have SSIDs */
-	if (!passive && wl->scan.req->n_ssids == 0)
-		return WL1271_NOTHING_TO_SCAN;
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
-	if (!cmd || !trigger) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	if (wl->conf.scan.split_scan_timeout)
-		scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
-
-	if (passive)
-		scan_options |= WL1271_SCAN_OPT_PASSIVE;
-
-	cmd->params.role_id = wlvif->role_id;
-
-	if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	cmd->params.scan_options = cpu_to_le16(scan_options);
-
-	cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
-						    cmd->channels,
-						    band, passive);
-	if (cmd->params.n_ch == 0) {
-		ret = WL1271_NOTHING_TO_SCAN;
-		goto out;
-	}
-
-	cmd->params.tx_rate = cpu_to_le32(basic_rate);
-	cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
-	cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
-	cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
-
-	if (band == IEEE80211_BAND_2GHZ)
-		cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
-	else
-		cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
-
-	if (wl->scan.ssid_len && wl->scan.ssid) {
-		cmd->params.ssid_len = wl->scan.ssid_len;
-		memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
-	}
-
-	memcpy(cmd->addr, vif->addr, ETH_ALEN);
-
-	ret = wl12xx_cmd_build_probe_req(wl, wlvif,
-					 cmd->params.role_id, band,
-					 wl->scan.ssid, wl->scan.ssid_len,
-					 wl->scan.req->ie,
-					 wl->scan.req->ie_len, false);
-	if (ret < 0) {
-		wl1271_error("PROBE request template failed");
-		goto out;
-	}
-
-	trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
-	ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
-			      sizeof(*trigger), 0);
-	if (ret < 0) {
-		wl1271_error("trigger scan to failed for hw scan");
-		goto out;
-	}
-
-	wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
-
-	ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
-	if (ret < 0) {
-		wl1271_error("SCAN failed");
-		goto out;
-	}
-
-out:
-	kfree(cmd);
-	kfree(trigger);
-	return ret;
-}
-
-void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif)
-{
-	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-	int ret = 0;
-	enum ieee80211_band band;
-	u32 rate, mask;
-
-	switch (wl->scan.state) {
-	case WL1271_SCAN_STATE_IDLE:
-		break;
-
-	case WL1271_SCAN_STATE_2GHZ_ACTIVE:
-		band = IEEE80211_BAND_2GHZ;
-		mask = wlvif->bitrate_masks[band];
-		if (wl->scan.req->no_cck) {
-			mask &= ~CONF_TX_CCK_RATES;
-			if (!mask)
-				mask = CONF_TX_RATE_MASK_BASIC_P2P;
-		}
-		rate = wl1271_tx_min_rate_get(wl, mask);
-		ret = wl1271_scan_send(wl, vif, band, false, rate);
-		if (ret == WL1271_NOTHING_TO_SCAN) {
-			wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
-			wl1271_scan_stm(wl, vif);
-		}
-
-		break;
-
-	case WL1271_SCAN_STATE_2GHZ_PASSIVE:
-		band = IEEE80211_BAND_2GHZ;
-		mask = wlvif->bitrate_masks[band];
-		if (wl->scan.req->no_cck) {
-			mask &= ~CONF_TX_CCK_RATES;
-			if (!mask)
-				mask = CONF_TX_RATE_MASK_BASIC_P2P;
-		}
-		rate = wl1271_tx_min_rate_get(wl, mask);
-		ret = wl1271_scan_send(wl, vif, band, true, rate);
-		if (ret == WL1271_NOTHING_TO_SCAN) {
-			if (wl->enable_11a)
-				wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
-			else
-				wl->scan.state = WL1271_SCAN_STATE_DONE;
-			wl1271_scan_stm(wl, vif);
-		}
-
-		break;
-
-	case WL1271_SCAN_STATE_5GHZ_ACTIVE:
-		band = IEEE80211_BAND_5GHZ;
-		rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
-		ret = wl1271_scan_send(wl, vif, band, false, rate);
-		if (ret == WL1271_NOTHING_TO_SCAN) {
-			wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
-			wl1271_scan_stm(wl, vif);
-		}
-
-		break;
-
-	case WL1271_SCAN_STATE_5GHZ_PASSIVE:
-		band = IEEE80211_BAND_5GHZ;
-		rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
-		ret = wl1271_scan_send(wl, vif, band, true, rate);
-		if (ret == WL1271_NOTHING_TO_SCAN) {
-			wl->scan.state = WL1271_SCAN_STATE_DONE;
-			wl1271_scan_stm(wl, vif);
-		}
-
-		break;
-
-	case WL1271_SCAN_STATE_DONE:
-		wl->scan.failed = false;
-		cancel_delayed_work(&wl->scan_complete_work);
-		ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
-					     msecs_to_jiffies(0));
-		break;
-
-	default:
-		wl1271_error("invalid scan state");
-		break;
-	}
-
-	if (ret < 0) {
-		cancel_delayed_work(&wl->scan_complete_work);
-		ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
-					     msecs_to_jiffies(0));
-	}
-}
-
-int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
-		const u8 *ssid, size_t ssid_len,
-		struct cfg80211_scan_request *req)
-{
-	/*
-	 * cfg80211 should guarantee that we don't get more channels
-	 * than what we have registered.
-	 */
-	BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
-
-	if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
-		return -EBUSY;
-
-	wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
-
-	if (ssid_len && ssid) {
-		wl->scan.ssid_len = ssid_len;
-		memcpy(wl->scan.ssid, ssid, ssid_len);
-	} else {
-		wl->scan.ssid_len = 0;
-	}
-
-	wl->scan_vif = vif;
-	wl->scan.req = req;
-	memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
-
-	/* we assume failure so that timeout scenarios are handled correctly */
-	wl->scan.failed = true;
-	ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
-				     msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
-
-	wl1271_scan_stm(wl, vif);
-
-	return 0;
-}
-
-int wl1271_scan_stop(struct wl1271 *wl)
-{
-	struct wl1271_cmd_header *cmd = NULL;
-	int ret = 0;
-
-	if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
-		return -EINVAL;
-
-	wl1271_debug(DEBUG_CMD, "cmd scan stop");
-
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-	if (!cmd) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
-			      sizeof(*cmd), 0);
-	if (ret < 0) {
-		wl1271_error("cmd stop_scan failed");
-		goto out;
-	}
-out:
-	kfree(cmd);
-	return ret;
+	ieee80211_iterate_active_interfaces_atomic(wl->hw,
+					IEEE80211_IFACE_ITER_RESUME_ALL,
+					wlcore_started_vifs_iter, &count);
+	return count;
 }
 
 static int
-wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
-				    struct cfg80211_sched_scan_request *req,
-				    struct conn_scan_ch_params *channels,
-				    u32 band, bool radar, bool passive,
-				    int start, int max_channels,
-				    u8 *n_pactive_ch)
+wlcore_scan_get_channels(struct wl1271 *wl,
+			 struct ieee80211_channel *req_channels[],
+			 u32 n_channels,
+			 u32 n_ssids,
+			 struct conn_scan_ch_params *channels,
+			 u32 band, bool radar, bool passive,
+			 int start, int max_channels,
+			 u8 *n_pactive_ch,
+			 int scan_type)
 {
-	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
 	int i, j;
 	u32 flags;
-	bool force_passive = !req->n_ssids;
-	u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe;
+	bool force_passive = !n_ssids;
+	u32 min_dwell_time_active, max_dwell_time_active;
 	u32 dwell_time_passive, dwell_time_dfs;
 
-	if (band == IEEE80211_BAND_5GHZ)
-		delta_per_probe = c->dwell_time_delta_per_probe_5;
-	else
-		delta_per_probe = c->dwell_time_delta_per_probe;
+	/* configure dwell times according to scan type */
+	if (scan_type == SCAN_TYPE_SEARCH) {
+		struct conf_scan_settings *c = &wl->conf.scan;
+		bool active_vif_exists = !!wlcore_count_started_vifs(wl);
 
-	min_dwell_time_active = c->base_dwell_time +
-		 req->n_ssids * c->num_probe_reqs * delta_per_probe;
+		min_dwell_time_active = active_vif_exists ?
+			c->min_dwell_time_active :
+			c->min_dwell_time_active_long;
+		max_dwell_time_active = active_vif_exists ?
+			c->max_dwell_time_active :
+			c->max_dwell_time_active_long;
+		dwell_time_passive = c->dwell_time_passive;
+		dwell_time_dfs = c->dwell_time_dfs;
+	} else {
+		struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+		u32 delta_per_probe;
 
-	max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta;
+		if (band == IEEE80211_BAND_5GHZ)
+			delta_per_probe = c->dwell_time_delta_per_probe_5;
+		else
+			delta_per_probe = c->dwell_time_delta_per_probe;
 
+		min_dwell_time_active = c->base_dwell_time +
+			 n_ssids * c->num_probe_reqs * delta_per_probe;
+
+		max_dwell_time_active = min_dwell_time_active +
+					c->max_dwell_time_delta;
+		dwell_time_passive = c->dwell_time_passive;
+		dwell_time_dfs = c->dwell_time_dfs;
+	}
 	min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000);
 	max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000);
-	dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000);
-	dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000);
+	dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000);
+	dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000);
 
 	for (i = 0, j = start;
-	     i < req->n_channels && j < max_channels;
+	     i < n_channels && j < max_channels;
 	     i++) {
-		flags = req->channels[i]->flags;
+		flags = req_channels[i]->flags;
 
 		if (force_passive)
 			flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 
-		if ((req->channels[i]->band == band) &&
+		if ((req_channels[i]->band == band) &&
 		    !(flags & IEEE80211_CHAN_DISABLED) &&
 		    (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
 		    /* if radar is set, we ignore the passive flag */
 		    (radar ||
 		     !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
 			wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
-				     req->channels[i]->band,
-				     req->channels[i]->center_freq);
+				     req_channels[i]->band,
+				     req_channels[i]->center_freq);
 			wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
-				     req->channels[i]->hw_value,
-				     req->channels[i]->flags);
+				     req_channels[i]->hw_value,
+				     req_channels[i]->flags);
 			wl1271_debug(DEBUG_SCAN, "max_power %d",
-				     req->channels[i]->max_power);
+				     req_channels[i]->max_power);
 			wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
 				     min_dwell_time_active,
 				     max_dwell_time_active);
@@ -473,10 +201,11 @@
 			channels[j].max_duration =
 				cpu_to_le16(max_dwell_time_active);
 
-			channels[j].tx_power_att = req->channels[i]->max_power;
-			channels[j].channel = req->channels[i]->hw_value;
+			channels[j].tx_power_att = req_channels[i]->max_power;
+			channels[j].channel = req_channels[i]->hw_value;
 
-			if ((band == IEEE80211_BAND_2GHZ) &&
+			if (n_pactive_ch &&
+			    (band == IEEE80211_BAND_2GHZ) &&
 			    (channels[j].channel >= 12) &&
 			    (channels[j].channel <= 14) &&
 			    (flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
@@ -500,51 +229,80 @@
 	return j - start;
 }
 
-static bool
-wl1271_scan_sched_scan_channels(struct wl1271 *wl,
-				struct cfg80211_sched_scan_request *req,
-				struct wl1271_cmd_sched_scan_config *cfg)
+bool
+wlcore_set_scan_chan_params(struct wl1271 *wl,
+			    struct wlcore_scan_channels *cfg,
+			    struct ieee80211_channel *channels[],
+			    u32 n_channels,
+			    u32 n_ssids,
+			    int scan_type)
 {
 	u8 n_pactive_ch = 0;
 
 	cfg->passive[0] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
-						    IEEE80211_BAND_2GHZ,
-						    false, true, 0,
-						    MAX_CHANNELS_2GHZ,
-						    &n_pactive_ch);
+		wlcore_scan_get_channels(wl,
+					 channels,
+					 n_channels,
+					 n_ssids,
+					 cfg->channels_2,
+					 IEEE80211_BAND_2GHZ,
+					 false, true, 0,
+					 MAX_CHANNELS_2GHZ,
+					 &n_pactive_ch,
+					 scan_type);
 	cfg->active[0] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
-						    IEEE80211_BAND_2GHZ,
-						    false, false,
-						    cfg->passive[0],
-						    MAX_CHANNELS_2GHZ,
-						    &n_pactive_ch);
+		wlcore_scan_get_channels(wl,
+					 channels,
+					 n_channels,
+					 n_ssids,
+					 cfg->channels_2,
+					 IEEE80211_BAND_2GHZ,
+					 false, false,
+					 cfg->passive[0],
+					 MAX_CHANNELS_2GHZ,
+					 &n_pactive_ch,
+					 scan_type);
 	cfg->passive[1] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
-						    IEEE80211_BAND_5GHZ,
-						    false, true, 0,
-						    MAX_CHANNELS_5GHZ,
-						    &n_pactive_ch);
+		wlcore_scan_get_channels(wl,
+					 channels,
+					 n_channels,
+					 n_ssids,
+					 cfg->channels_5,
+					 IEEE80211_BAND_5GHZ,
+					 false, true, 0,
+					 wl->max_channels_5,
+					 &n_pactive_ch,
+					 scan_type);
 	cfg->dfs =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
-						    IEEE80211_BAND_5GHZ,
-						    true, true,
-						    cfg->passive[1],
-						    MAX_CHANNELS_5GHZ,
-						    &n_pactive_ch);
+		wlcore_scan_get_channels(wl,
+					 channels,
+					 n_channels,
+					 n_ssids,
+					 cfg->channels_5,
+					 IEEE80211_BAND_5GHZ,
+					 true, true,
+					 cfg->passive[1],
+					 wl->max_channels_5,
+					 &n_pactive_ch,
+					 scan_type);
 	cfg->active[1] =
-		wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
-						    IEEE80211_BAND_5GHZ,
-						    false, false,
-						    cfg->passive[1] + cfg->dfs,
-						    MAX_CHANNELS_5GHZ,
-						    &n_pactive_ch);
+		wlcore_scan_get_channels(wl,
+					 channels,
+					 n_channels,
+					 n_ssids,
+					 cfg->channels_5,
+					 IEEE80211_BAND_5GHZ,
+					 false, false,
+					 cfg->passive[1] + cfg->dfs,
+					 wl->max_channels_5,
+					 &n_pactive_ch,
+					 scan_type);
+
 	/* 802.11j channels are not supported yet */
 	cfg->passive[2] = 0;
 	cfg->active[2] = 0;
 
-	cfg->n_pactive_ch = n_pactive_ch;
+	cfg->passive_active = n_pactive_ch;
 
 	wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
 		     cfg->active[0], cfg->passive[0]);
@@ -556,10 +314,48 @@
 		cfg->passive[1] || cfg->active[1] || cfg->dfs ||
 		cfg->passive[2] || cfg->active[2];
 }
+EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params);
 
+int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
+		const u8 *ssid, size_t ssid_len,
+		struct cfg80211_scan_request *req)
+{
+	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+
+	/*
+	 * cfg80211 should guarantee that we don't get more channels
+	 * than what we have registered.
+	 */
+	BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
+
+	if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
+		return -EBUSY;
+
+	wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
+
+	if (ssid_len && ssid) {
+		wl->scan.ssid_len = ssid_len;
+		memcpy(wl->scan.ssid, ssid, ssid_len);
+	} else {
+		wl->scan.ssid_len = 0;
+	}
+
+	wl->scan_wlvif = wlvif;
+	wl->scan.req = req;
+	memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
+
+	/* we assume failure so that timeout scenarios are handled correctly */
+	wl->scan.failed = true;
+	ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+				     msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
+
+	wl->ops->scan_start(wl, wlvif, req);
+
+	return 0;
+}
 /* Returns the scan type to be used or a negative value on error */
-static int
-wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
+int
+wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
 				 struct wl12xx_vif *wlvif,
 				 struct cfg80211_sched_scan_request *req)
 {
@@ -662,160 +458,12 @@
 		return ret;
 	return type;
 }
+EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list);
 
-int wl1271_scan_sched_scan_config(struct wl1271 *wl,
-				  struct wl12xx_vif *wlvif,
-				  struct cfg80211_sched_scan_request *req,
-				  struct ieee80211_sched_scan_ies *ies)
-{
-	struct wl1271_cmd_sched_scan_config *cfg = NULL;
-	struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
-	int i, ret;
-	bool force_passive = !req->n_ssids;
-
-	wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
-
-	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
-	if (!cfg)
-		return -ENOMEM;
-
-	cfg->role_id = wlvif->role_id;
-	cfg->rssi_threshold = c->rssi_threshold;
-	cfg->snr_threshold  = c->snr_threshold;
-	cfg->n_probe_reqs = c->num_probe_reqs;
-	/* cycles set to 0 it means infinite (until manually stopped) */
-	cfg->cycles = 0;
-	/* report APs when at least 1 is found */
-	cfg->report_after = 1;
-	/* don't stop scanning automatically when something is found */
-	cfg->terminate = 0;
-	cfg->tag = WL1271_SCAN_DEFAULT_TAG;
-	/* don't filter on BSS type */
-	cfg->bss_type = SCAN_BSS_TYPE_ANY;
-	/* currently NL80211 supports only a single interval */
-	for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
-		cfg->intervals[i] = cpu_to_le32(req->interval);
-
-	cfg->ssid_len = 0;
-	ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req);
-	if (ret < 0)
-		goto out;
-
-	cfg->filter_type = ret;
-
-	wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
-
-	if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
-		wl1271_error("scan channel list is empty");
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (!force_passive && cfg->active[0]) {
-		u8 band = IEEE80211_BAND_2GHZ;
-		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
-						 wlvif->role_id, band,
-						 req->ssids[0].ssid,
-						 req->ssids[0].ssid_len,
-						 ies->ie[band],
-						 ies->len[band], true);
-		if (ret < 0) {
-			wl1271_error("2.4GHz PROBE request template failed");
-			goto out;
-		}
-	}
-
-	if (!force_passive && cfg->active[1]) {
-		u8 band = IEEE80211_BAND_5GHZ;
-		ret = wl12xx_cmd_build_probe_req(wl, wlvif,
-						 wlvif->role_id, band,
-						 req->ssids[0].ssid,
-						 req->ssids[0].ssid_len,
-						 ies->ie[band],
-						 ies->len[band], true);
-		if (ret < 0) {
-			wl1271_error("5GHz PROBE request template failed");
-			goto out;
-		}
-	}
-
-	wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
-
-	ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
-			      sizeof(*cfg), 0);
-	if (ret < 0) {
-		wl1271_error("SCAN configuration failed");
-		goto out;
-	}
-out:
-	kfree(cfg);
-	return ret;
-}
-
-int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
-{
-	struct wl1271_cmd_sched_scan_start *start;
-	int ret = 0;
-
-	wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
-
-	if (wlvif->bss_type != BSS_TYPE_STA_BSS)
-		return -EOPNOTSUPP;
-
-	if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) &&
-	    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
-		return -EBUSY;
-
-	start = kzalloc(sizeof(*start), GFP_KERNEL);
-	if (!start)
-		return -ENOMEM;
-
-	start->role_id = wlvif->role_id;
-	start->tag = WL1271_SCAN_DEFAULT_TAG;
-
-	ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
-			      sizeof(*start), 0);
-	if (ret < 0) {
-		wl1271_error("failed to send scan start command");
-		goto out_free;
-	}
-
-out_free:
-	kfree(start);
-	return ret;
-}
-
-void wl1271_scan_sched_scan_results(struct wl1271 *wl)
+void wlcore_scan_sched_scan_results(struct wl1271 *wl)
 {
 	wl1271_debug(DEBUG_SCAN, "got periodic scan results");
 
 	ieee80211_sched_scan_results(wl->hw);
 }
-
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
-{
-	struct wl1271_cmd_sched_scan_stop *stop;
-	int ret = 0;
-
-	wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
-
-	/* FIXME: what to do if alloc'ing to stop fails? */
-	stop = kzalloc(sizeof(*stop), GFP_KERNEL);
-	if (!stop) {
-		wl1271_error("failed to alloc memory to send sched scan stop");
-		return;
-	}
-
-	stop->role_id = wlvif->role_id;
-	stop->tag = WL1271_SCAN_DEFAULT_TAG;
-
-	ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
-			      sizeof(*stop), 0);
-	if (ret < 0) {
-		wl1271_error("failed to send sched scan stop command");
-		goto out_free;
-	}
-
-out_free:
-	kfree(stop);
-}
+EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results);
diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h
index 29f3c8d6..a6ab24b 100644
--- a/drivers/net/wireless/ti/wlcore/scan.h
+++ b/drivers/net/wireless/ti/wlcore/scan.h
@@ -26,22 +26,20 @@
 
 #include "wlcore.h"
 
-int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
+int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
 		const u8 *ssid, size_t ssid_len,
 		struct cfg80211_scan_request *req);
-int wl1271_scan_stop(struct wl1271 *wl);
 int wl1271_scan_build_probe_req(struct wl1271 *wl,
 				const u8 *ssid, size_t ssid_len,
 				const u8 *ie, size_t ie_len, u8 band);
-void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif);
+void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 void wl1271_scan_complete_work(struct work_struct *work);
 int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 				     struct wl12xx_vif *wlvif,
 				     struct cfg80211_sched_scan_request *req,
 				     struct ieee80211_sched_scan_ies *ies);
 int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_results(struct wl1271 *wl);
+void wlcore_scan_sched_scan_results(struct wl1271 *wl);
 
 #define WL1271_SCAN_MAX_CHANNELS       24
 #define WL1271_SCAN_DEFAULT_TAG        1
@@ -66,56 +64,6 @@
 	WL1271_SCAN_STATE_DONE
 };
 
-struct basic_scan_params {
-	/* Scan option flags (WL1271_SCAN_OPT_*) */
-	__le16 scan_options;
-	u8 role_id;
-	/* Number of scan channels in the list (maximum 30) */
-	u8 n_ch;
-	/* This field indicates the number of probe requests to send
-	   per channel for an active scan */
-	u8 n_probe_reqs;
-	u8 tid_trigger;
-	u8 ssid_len;
-	u8 use_ssid_list;
-
-	/* Rate bit field for sending the probes */
-	__le32 tx_rate;
-
-	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	/* Band to scan */
-	u8 band;
-
-	u8 scan_tag;
-	u8 padding2[2];
-} __packed;
-
-struct basic_scan_channel_params {
-	/* Duration in TU to wait for frames on a channel for active scan */
-	__le32 min_duration;
-	__le32 max_duration;
-	__le32 bssid_lsb;
-	__le16 bssid_msb;
-	u8 early_termination;
-	u8 tx_power_att;
-	u8 channel;
-	/* FW internal use only! */
-	u8 dfs_candidate;
-	u8 activity_detected;
-	u8 pad;
-} __packed;
-
-struct wl1271_cmd_scan {
-	struct wl1271_cmd_header header;
-
-	struct basic_scan_params params;
-	struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
-
-	/* src mac address */
-	u8 addr[ETH_ALEN];
-	u8 padding[2];
-} __packed;
-
 struct wl1271_cmd_trigger_scan_to {
 	struct wl1271_cmd_header header;
 
@@ -123,9 +71,17 @@
 } __packed;
 
 #define MAX_CHANNELS_2GHZ	14
-#define MAX_CHANNELS_5GHZ	23
 #define MAX_CHANNELS_4GHZ	4
 
+/*
+ * This max value here is used only for the struct definition of
+ * wlcore_scan_channels. This struct is used by both 12xx
+ * and 18xx (which have different max 5ghz channels value).
+ * In order to make sure this is large enough, just use the
+ * max possible 5ghz channels.
+ */
+#define MAX_CHANNELS_5GHZ	42
+
 #define SCAN_MAX_CYCLE_INTERVALS 16
 #define SCAN_MAX_BANDS 3
 
@@ -160,43 +116,6 @@
 	u8  padding[3];
 } __packed;
 
-struct wl1271_cmd_sched_scan_config {
-	struct wl1271_cmd_header header;
-
-	__le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
-
-	s8 rssi_threshold; /* for filtering (in dBm) */
-	s8 snr_threshold;  /* for filtering (in dB) */
-
-	u8 cycles;       /* maximum number of scan cycles */
-	u8 report_after; /* report when this number of results are received */
-	u8 terminate;    /* stop scanning after reporting */
-
-	u8 tag;
-	u8 bss_type; /* for filtering */
-	u8 filter_type;
-
-	u8 ssid_len;     /* For SCAN_SSID_FILTER_SPECIFIC */
-	u8 ssid[IEEE80211_MAX_SSID_LEN];
-
-	u8 n_probe_reqs; /* Number of probes requests per channel */
-
-	u8 passive[SCAN_MAX_BANDS];
-	u8 active[SCAN_MAX_BANDS];
-
-	u8 dfs;
-
-	u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
-			    channels in BG band */
-	u8 role_id;
-	u8 padding[1];
-
-	struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
-	struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
-	struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
-} __packed;
-
-
 #define SCHED_SCAN_MAX_SSIDS 16
 
 enum {
@@ -220,21 +139,34 @@
 	u8 padding[2];
 } __packed;
 
-struct wl1271_cmd_sched_scan_start {
-	struct wl1271_cmd_header header;
+struct wlcore_scan_channels {
+	u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+	u8 active[SCAN_MAX_BANDS];  /* number of active scan channels */
+	u8 dfs;		   /* number of dfs channels in 5ghz */
+	u8 passive_active; /* number of passive before active channels 2.4ghz */
 
-	u8 tag;
-	u8 role_id;
-	u8 padding[2];
-} __packed;
+	struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+	struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+	struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+};
 
-struct wl1271_cmd_sched_scan_stop {
-	struct wl1271_cmd_header header;
+enum {
+	SCAN_TYPE_SEARCH	= 0,
+	SCAN_TYPE_PERIODIC	= 1,
+	SCAN_TYPE_TRACKING	= 2,
+};
 
-	u8 tag;
-	u8 role_id;
-	u8 padding[2];
-} __packed;
+bool
+wlcore_set_scan_chan_params(struct wl1271 *wl,
+			    struct wlcore_scan_channels *cfg,
+			    struct ieee80211_channel *channels[],
+			    u32 n_channels,
+			    u32 n_ssids,
+			    int scan_type);
 
+int
+wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
+				 struct wl12xx_vif *wlvif,
+				 struct cfg80211_sched_scan_request *req);
 
 #endif /* __WL1271_SCAN_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index 646f703..29ef249 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -217,7 +217,7 @@
 static int wl1271_probe(struct sdio_func *func,
 				  const struct sdio_device_id *id)
 {
-	struct wl12xx_platform_data *wlan_data;
+	struct wlcore_platdev_data *pdev_data;
 	struct wl12xx_sdio_glue *glue;
 	struct resource res[1];
 	mmc_pm_flag_t mmcflags;
@@ -228,10 +228,16 @@
 	if (func->num != 0x02)
 		return -ENODEV;
 
+	pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
+	if (!pdev_data)
+		goto out;
+
+	pdev_data->if_ops = &sdio_ops;
+
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 		dev_err(&func->dev, "can't allocate glue\n");
-		goto out;
+		goto out_free_pdev_data;
 	}
 
 	glue->dev = &func->dev;
@@ -242,9 +248,9 @@
 	/* Use block mode for transferring over one block size of data */
 	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 
-	wlan_data = wl12xx_get_platform_data();
-	if (IS_ERR(wlan_data)) {
-		ret = PTR_ERR(wlan_data);
+	pdev_data->pdata = wl12xx_get_platform_data();
+	if (IS_ERR(pdev_data->pdata)) {
+		ret = PTR_ERR(pdev_data->pdata);
 		dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
 		goto out_free_glue;
 	}
@@ -254,9 +260,7 @@
 	dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
 
 	if (mmcflags & MMC_PM_KEEP_POWER)
-		wlan_data->pwr_in_suspend = true;
-
-	wlan_data->ops = &sdio_ops;
+		pdev_data->pdata->pwr_in_suspend = true;
 
 	sdio_set_drvdata(func, glue);
 
@@ -274,7 +278,7 @@
 	else
 		chip_family = "wl12xx";
 
-	glue->core = platform_device_alloc(chip_family, -1);
+	glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO);
 	if (!glue->core) {
 		dev_err(glue->dev, "can't allocate platform_device");
 		ret = -ENOMEM;
@@ -285,7 +289,7 @@
 
 	memset(res, 0x00, sizeof(res));
 
-	res[0].start = wlan_data->irq;
+	res[0].start = pdev_data->pdata->irq;
 	res[0].flags = IORESOURCE_IRQ;
 	res[0].name = "irq";
 
@@ -295,8 +299,8 @@
 		goto out_dev_put;
 	}
 
-	ret = platform_device_add_data(glue->core, wlan_data,
-				       sizeof(*wlan_data));
+	ret = platform_device_add_data(glue->core, pdev_data,
+				       sizeof(*pdev_data));
 	if (ret) {
 		dev_err(glue->dev, "can't add platform data\n");
 		goto out_dev_put;
@@ -315,6 +319,9 @@
 out_free_glue:
 	kfree(glue);
 
+out_free_pdev_data:
+	kfree(pdev_data);
+
 out:
 	return ret;
 }
@@ -326,8 +333,7 @@
 	/* Undo decrement done above in wl1271_probe */
 	pm_runtime_get_noresume(&func->dev);
 
-	platform_device_del(glue->core);
-	platform_device_put(glue->core);
+	platform_device_unregister(glue->core);
 	kfree(glue);
 }
 
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index f06f477..e264478 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -270,7 +270,7 @@
 					     void *buf, size_t len, bool fixed)
 {
 	struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
-	struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
+	struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)];
 	struct spi_message m;
 	u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
 	u32 *cmd;
@@ -327,22 +327,27 @@
 static int wl1271_probe(struct spi_device *spi)
 {
 	struct wl12xx_spi_glue *glue;
-	struct wl12xx_platform_data *pdata;
+	struct wlcore_platdev_data *pdev_data;
 	struct resource res[1];
 	int ret = -ENOMEM;
 
-	pdata = spi->dev.platform_data;
-	if (!pdata) {
+	pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
+	if (!pdev_data)
+		goto out;
+
+	pdev_data->pdata = spi->dev.platform_data;
+	if (!pdev_data->pdata) {
 		dev_err(&spi->dev, "no platform data\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto out_free_pdev_data;
 	}
 
-	pdata->ops = &spi_ops;
+	pdev_data->if_ops = &spi_ops;
 
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 		dev_err(&spi->dev, "can't allocate glue\n");
-		goto out;
+		goto out_free_pdev_data;
 	}
 
 	glue->dev = &spi->dev;
@@ -359,7 +364,7 @@
 		goto out_free_glue;
 	}
 
-	glue->core = platform_device_alloc("wl12xx", -1);
+	glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
 	if (!glue->core) {
 		dev_err(glue->dev, "can't allocate platform_device\n");
 		ret = -ENOMEM;
@@ -380,7 +385,8 @@
 		goto out_dev_put;
 	}
 
-	ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata));
+	ret = platform_device_add_data(glue->core, pdev_data,
+				       sizeof(*pdev_data));
 	if (ret) {
 		dev_err(glue->dev, "can't add platform data\n");
 		goto out_dev_put;
@@ -399,6 +405,10 @@
 
 out_free_glue:
 	kfree(glue);
+
+out_free_pdev_data:
+	kfree(pdev_data);
+
 out:
 	return ret;
 }
@@ -407,8 +417,7 @@
 {
 	struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
 
-	platform_device_del(glue->core);
-	platform_device_put(glue->core);
+	platform_device_unregister(glue->core);
 	kfree(glue);
 
 	return 0;
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index a90d3cd..ece392c 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -104,7 +104,7 @@
 				    struct wl12xx_vif *wlvif,
 				    u8 hlid)
 {
-	bool fw_ps, single_sta;
+	bool fw_ps, single_link;
 	u8 tx_pkts;
 
 	if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
@@ -112,15 +112,15 @@
 
 	fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
 	tx_pkts = wl->links[hlid].allocated_pkts;
-	single_sta = (wl->active_sta_count == 1);
+	single_link = (wl->active_link_count == 1);
 
 	/*
 	 * if in FW PS and there is enough data in FW we can put the link
 	 * into high-level PS and clean out its TX queues.
-	 * Make an exception if this is the only connected station. In this
-	 * case FW-memory congestion is not a problem.
+	 * Make an exception if this is the only connected link. In this
+	 * case FW-memory congestion is less of a problem.
 	 */
-	if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+	if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
 		wl12xx_ps_link_start(wl, wlvif, hlid, true);
 }
 
@@ -155,21 +155,18 @@
 u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		      struct sk_buff *skb, struct ieee80211_sta *sta)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
-	if (!wlvif || wl12xx_is_dummy_packet(wl, skb))
-		return wl->system_hlid;
+	struct ieee80211_tx_info *control;
 
 	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 		return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta);
 
-	if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
-	     test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
-	    !ieee80211_is_auth(hdr->frame_control) &&
-	    !ieee80211_is_assoc_req(hdr->frame_control))
-		return wlvif->sta.hlid;
-	else
+	control = IEEE80211_SKB_CB(skb);
+	if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
+		wl1271_debug(DEBUG_TX, "tx offchannel");
 		return wlvif->dev_hlid;
+	}
+
+	return wlvif->sta.hlid;
 }
 
 unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
@@ -224,9 +221,7 @@
 		ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
 		wl->tx_allocated_pkts[ac]++;
 
-		if (!wl12xx_is_dummy_packet(wl, skb) && wlvif &&
-		    wlvif->bss_type == BSS_TYPE_AP_BSS &&
-		    test_bit(hlid, wlvif->ap.sta_hlid_map))
+		if (test_bit(hlid, wl->links_map))
 			wl->links[hlid].allocated_pkts++;
 
 		ret = 0;
@@ -293,9 +288,14 @@
 
 		tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
 	} else if (wlvif) {
+		u8 session_id = wl->session_ids[hlid];
+
+		if ((wl->quirks & WLCORE_QUIRK_AP_ZERO_SESSION_ID) &&
+		    (wlvif->bss_type == BSS_TYPE_AP_BSS))
+			session_id = 0;
+
 		/* configure the tx attributes */
-		tx_attr = wlvif->session_counter <<
-			  TX_HW_ATTR_OFST_SESSION_COUNTER;
+		tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER;
 	}
 
 	desc->hlid = hlid;
@@ -452,20 +452,22 @@
 void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
 {
 	int i;
+	struct wl12xx_vif *wlvif;
 
-	for (i = 0; i < NUM_TX_QUEUES; i++) {
-		if (wlcore_is_queue_stopped_by_reason(wl, i,
-			WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
-		    wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
-			/* firmware buffer has space, restart queues */
-			wlcore_wake_queue(wl, i,
-					  WLCORE_QUEUE_STOP_REASON_WATERMARK);
+	wl12xx_for_each_wlvif(wl, wlvif) {
+		for (i = 0; i < NUM_TX_QUEUES; i++) {
+			if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i,
+					WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
+			    wlvif->tx_queue_count[i] <=
+					WL1271_TX_QUEUE_LOW_WATERMARK)
+				/* firmware buffer has space, restart queues */
+				wlcore_wake_queue(wl, wlvif, i,
+					WLCORE_QUEUE_STOP_REASON_WATERMARK);
 		}
 	}
 }
 
-static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
-						struct sk_buff_head *queues)
+static int wlcore_select_ac(struct wl1271 *wl)
 {
 	int i, q = -1, ac;
 	u32 min_pkts = 0xffffffff;
@@ -479,45 +481,60 @@
 	 */
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		ac = wl1271_tx_get_queue(i);
-		if (!skb_queue_empty(&queues[ac]) &&
-		    (wl->tx_allocated_pkts[ac] < min_pkts)) {
+		if (wl->tx_queue_count[ac] &&
+		    wl->tx_allocated_pkts[ac] < min_pkts) {
 			q = ac;
 			min_pkts = wl->tx_allocated_pkts[q];
 		}
 	}
 
-	if (q == -1)
-		return NULL;
-
-	return &queues[q];
+	return q;
 }
 
-static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
-					      struct wl1271_link *lnk)
+static struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl,
+					  struct wl1271_link *lnk, u8 q)
 {
 	struct sk_buff *skb;
 	unsigned long flags;
-	struct sk_buff_head *queue;
 
-	queue = wl1271_select_queue(wl, lnk->tx_queue);
-	if (!queue)
-		return NULL;
-
-	skb = skb_dequeue(queue);
+	skb = skb_dequeue(&lnk->tx_queue[q]);
 	if (skb) {
-		int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
 		spin_lock_irqsave(&wl->wl_lock, flags);
 		WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
 		wl->tx_queue_count[q]--;
+		if (lnk->wlvif) {
+			WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0);
+			lnk->wlvif->tx_queue_count[q]--;
+		}
 		spin_unlock_irqrestore(&wl->wl_lock, flags);
 	}
 
 	return skb;
 }
 
-static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
-					      struct wl12xx_vif *wlvif,
-					      u8 *hlid)
+static struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl,
+						    u8 hlid, u8 ac,
+						    u8 *low_prio_hlid)
+{
+	struct wl1271_link *lnk = &wl->links[hlid];
+
+	if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) {
+		if (*low_prio_hlid == WL12XX_INVALID_LINK_ID &&
+		    !skb_queue_empty(&lnk->tx_queue[ac]) &&
+		    wlcore_hw_lnk_low_prio(wl, hlid, lnk))
+			/* we found the first non-empty low priority queue */
+			*low_prio_hlid = hlid;
+
+		return NULL;
+	}
+
+	return wlcore_lnk_dequeue(wl, lnk, ac);
+}
+
+static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl,
+						    struct wl12xx_vif *wlvif,
+						    u8 ac, u8 *hlid,
+						    u8 *low_prio_hlid)
 {
 	struct sk_buff *skb = NULL;
 	int i, h, start_hlid;
@@ -533,7 +550,8 @@
 		if (!test_bit(h, wlvif->links_map))
 			continue;
 
-		skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]);
+		skb = wlcore_lnk_dequeue_high_prio(wl, h, ac,
+						   low_prio_hlid);
 		if (!skb)
 			continue;
 
@@ -553,42 +571,74 @@
 	unsigned long flags;
 	struct wl12xx_vif *wlvif = wl->last_wlvif;
 	struct sk_buff *skb = NULL;
+	int ac;
+	u8 low_prio_hlid = WL12XX_INVALID_LINK_ID;
+
+	ac = wlcore_select_ac(wl);
+	if (ac < 0)
+		goto out;
 
 	/* continue from last wlvif (round robin) */
 	if (wlvif) {
 		wl12xx_for_each_wlvif_continue(wl, wlvif) {
-			skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid);
-			if (skb) {
-				wl->last_wlvif = wlvif;
-				break;
-			}
+			if (!wlvif->tx_queue_count[ac])
+				continue;
+
+			skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
+							   &low_prio_hlid);
+			if (!skb)
+				continue;
+
+			wl->last_wlvif = wlvif;
+			break;
 		}
 	}
 
 	/* dequeue from the system HLID before the restarting wlvif list */
 	if (!skb) {
-		skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
-		*hlid = wl->system_hlid;
+		skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid,
+						   ac, &low_prio_hlid);
+		if (skb) {
+			*hlid = wl->system_hlid;
+			wl->last_wlvif = NULL;
+		}
 	}
 
-	/* do a new pass over the wlvif list */
+	/* Do a new pass over the wlvif list. But no need to continue
+	 * after last_wlvif. The previous pass should have found it. */
 	if (!skb) {
 		wl12xx_for_each_wlvif(wl, wlvif) {
-			skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid);
+			if (!wlvif->tx_queue_count[ac])
+				goto next;
+
+			skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
+							   &low_prio_hlid);
 			if (skb) {
 				wl->last_wlvif = wlvif;
 				break;
 			}
 
-			/*
-			 * No need to continue after last_wlvif. The previous
-			 * pass should have found it.
-			 */
+next:
 			if (wlvif == wl->last_wlvif)
 				break;
 		}
 	}
 
+	/* no high priority skbs found - but maybe a low priority one? */
+	if (!skb && low_prio_hlid != WL12XX_INVALID_LINK_ID) {
+		struct wl1271_link *lnk = &wl->links[low_prio_hlid];
+		skb = wlcore_lnk_dequeue(wl, lnk, ac);
+
+		WARN_ON(!skb); /* we checked this before */
+		*hlid = low_prio_hlid;
+
+		/* ensure proper round robin in the vif/link levels */
+		wl->last_wlvif = lnk->wlvif;
+		if (lnk->wlvif)
+			lnk->wlvif->last_tx_hlid = low_prio_hlid;
+
+	}
+
 	if (!skb &&
 	    test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
 		int q;
@@ -602,6 +652,7 @@
 		spin_unlock_irqrestore(&wl->wl_lock, flags);
 	}
 
+out:
 	return skb;
 }
 
@@ -623,6 +674,8 @@
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
 	wl->tx_queue_count[q]++;
+	if (wlvif)
+		wlvif->tx_queue_count[q]++;
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
@@ -699,7 +752,7 @@
 		bool has_data = false;
 
 		wlvif = NULL;
-		if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
+		if (!wl12xx_is_dummy_packet(wl, skb))
 			wlvif = wl12xx_vif_to_data(info->control.vif);
 		else
 			hlid = wl->system_hlid;
@@ -972,10 +1025,11 @@
 	unsigned long flags;
 	struct ieee80211_tx_info *info;
 	int total[NUM_TX_QUEUES];
+	struct wl1271_link *lnk = &wl->links[hlid];
 
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		total[i] = 0;
-		while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+		while ((skb = skb_dequeue(&lnk->tx_queue[i]))) {
 			wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
 
 			if (!wl12xx_is_dummy_packet(wl, skb)) {
@@ -990,8 +1044,11 @@
 	}
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
-	for (i = 0; i < NUM_TX_QUEUES; i++)
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		wl->tx_queue_count[i] -= total[i];
+		if (lnk->wlvif)
+			lnk->wlvif->tx_queue_count[i] -= total[i];
+	}
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 
 	wl1271_handle_tx_low_watermark(wl);
@@ -1004,16 +1061,18 @@
 
 	/* TX failure */
 	for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
-		if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+		if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
+			/* this calls wl12xx_free_link */
 			wl1271_free_sta(wl, wlvif, i);
-		else
-			wlvif->sta.ba_rx_bitmap = 0;
-
-		wl->links[i].allocated_pkts = 0;
-		wl->links[i].prev_freed_pkts = 0;
+		} else {
+			u8 hlid = i;
+			wl12xx_free_link(wl, wlvif, &hlid);
+		}
 	}
 	wlvif->last_tx_hlid = 0;
 
+	for (i = 0; i < NUM_TX_QUEUES; i++)
+		wlvif->tx_queue_count[i] = 0;
 }
 /* caller must hold wl->mutex and TX must be stopped */
 void wl12xx_tx_reset(struct wl1271 *wl)
@@ -1023,7 +1082,7 @@
 	struct ieee80211_tx_info *info;
 
 	/* only reset the queues if something bad happened */
-	if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) {
+	if (wl1271_tx_total_queue_count(wl) != 0) {
 		for (i = 0; i < WL12XX_MAX_LINKS; i++)
 			wl1271_tx_reset_link_queues(wl, i);
 
@@ -1135,45 +1194,48 @@
 
 	return BIT(__ffs(rate_set));
 }
+EXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get);
 
-void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
-			      enum wlcore_queue_stop_reason reason)
+void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			      u8 queue, enum wlcore_queue_stop_reason reason)
 {
-	bool stopped = !!wl->queue_stop_reasons[queue];
+	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
+	bool stopped = !!wl->queue_stop_reasons[hwq];
 
 	/* queue should not be stopped for this reason */
-	WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
+	WARN_ON_ONCE(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq]));
 
 	if (stopped)
 		return;
 
-	ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+	ieee80211_stop_queue(wl->hw, hwq);
 }
 
-void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
 		       enum wlcore_queue_stop_reason reason)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
-	wlcore_stop_queue_locked(wl, queue, reason);
+	wlcore_stop_queue_locked(wl, wlvif, queue, reason);
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
-void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
 		       enum wlcore_queue_stop_reason reason)
 {
 	unsigned long flags;
+	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
 
 	/* queue should not be clear for this reason */
-	WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
+	WARN_ON_ONCE(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq]));
 
-	if (wl->queue_stop_reasons[queue])
+	if (wl->queue_stop_reasons[hwq])
 		goto out;
 
-	ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+	ieee80211_wake_queue(wl->hw, hwq);
 
 out:
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
@@ -1183,48 +1245,74 @@
 			enum wlcore_queue_stop_reason reason)
 {
 	int i;
+	unsigned long flags;
 
-	for (i = 0; i < NUM_TX_QUEUES; i++)
-		wlcore_stop_queue(wl, i, reason);
+	spin_lock_irqsave(&wl->wl_lock, flags);
+
+	/* mark all possible queues as stopped */
+        for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
+                WARN_ON_ONCE(test_and_set_bit(reason,
+					      &wl->queue_stop_reasons[i]));
+
+	/* use the global version to make sure all vifs in mac80211 we don't
+	 * know are stopped.
+	 */
+	ieee80211_stop_queues(wl->hw);
+
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
-EXPORT_SYMBOL_GPL(wlcore_stop_queues);
 
 void wlcore_wake_queues(struct wl1271 *wl,
 			enum wlcore_queue_stop_reason reason)
 {
 	int i;
-
-	for (i = 0; i < NUM_TX_QUEUES; i++)
-		wlcore_wake_queue(wl, i, reason);
-}
-EXPORT_SYMBOL_GPL(wlcore_wake_queues);
-
-void wlcore_reset_stopped_queues(struct wl1271 *wl)
-{
-	int i;
 	unsigned long flags;
 
 	spin_lock_irqsave(&wl->wl_lock, flags);
 
-	for (i = 0; i < NUM_TX_QUEUES; i++) {
-		if (!wl->queue_stop_reasons[i])
-			continue;
+	/* mark all possible queues as awake */
+        for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
+		WARN_ON_ONCE(!test_and_clear_bit(reason,
+						 &wl->queue_stop_reasons[i]));
 
-		wl->queue_stop_reasons[i] = 0;
-		ieee80211_wake_queue(wl->hw,
-				     wl1271_tx_get_mac80211_queue(i));
-	}
+	/* use the global version to make sure all vifs in mac80211 we don't
+	 * know are woken up.
+	 */
+	ieee80211_wake_queues(wl->hw);
 
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
-bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
-			     enum wlcore_queue_stop_reason reason)
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
+				       struct wl12xx_vif *wlvif, u8 queue,
+				       enum wlcore_queue_stop_reason reason)
 {
-	return test_bit(reason, &wl->queue_stop_reasons[queue]);
+	unsigned long flags;
+	bool stopped;
+
+	spin_lock_irqsave(&wl->wl_lock, flags);
+	stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue,
+							   reason);
+	spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+	return stopped;
 }
 
-bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
+bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
+				       struct wl12xx_vif *wlvif, u8 queue,
+				       enum wlcore_queue_stop_reason reason)
 {
-	return !!wl->queue_stop_reasons[queue];
+	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
+
+	WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+	return test_bit(reason, &wl->queue_stop_reasons[hwq]);
+}
+
+bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+				    u8 queue)
+{
+	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
+
+	WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+	return !!wl->queue_stop_reasons[hwq];
 }
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 349520d..55aa4ac 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -207,19 +207,22 @@
 	}
 }
 
-static inline int wl1271_tx_get_mac80211_queue(int queue)
+static inline
+int wlcore_tx_get_mac80211_queue(struct wl12xx_vif *wlvif, int queue)
 {
+	int mac_queue = wlvif->hw_queue_base;
+
 	switch (queue) {
 	case CONF_TX_AC_VO:
-		return 0;
+		return mac_queue + 0;
 	case CONF_TX_AC_VI:
-		return 1;
+		return mac_queue + 1;
 	case CONF_TX_AC_BE:
-		return 2;
+		return mac_queue + 2;
 	case CONF_TX_AC_BK:
-		return 3;
+		return mac_queue + 3;
 	default:
-		return 2;
+		return mac_queue + 2;
 	}
 }
 
@@ -252,20 +255,26 @@
 unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
 					  unsigned int packet_length);
 void wl1271_free_tx_id(struct wl1271 *wl, int id);
-void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
-			      enum wlcore_queue_stop_reason reason);
-void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			      u8 queue, enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
 		       enum wlcore_queue_stop_reason reason);
-void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
 		       enum wlcore_queue_stop_reason reason);
 void wlcore_stop_queues(struct wl1271 *wl,
 			enum wlcore_queue_stop_reason reason);
 void wlcore_wake_queues(struct wl1271 *wl,
 			enum wlcore_queue_stop_reason reason);
-void wlcore_reset_stopped_queues(struct wl1271 *wl);
-bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
+				       struct wl12xx_vif *wlvif, u8 queue,
 				       enum wlcore_queue_stop_reason reason);
-bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
+bool
+wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
+					 struct wl12xx_vif *wlvif,
+					 u8 queue,
+					 enum wlcore_queue_stop_reason reason);
+bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+				    u8 queue);
 
 /* from main.c */
 void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index c388493..af9feca 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -37,6 +37,9 @@
  */
 #define WLCORE_NUM_MAC_ADDRESSES 3
 
+/* wl12xx/wl18xx maximum transmission power (in dBm) */
+#define WLCORE_MAX_TXPWR        25
+
 /* forward declaration */
 struct wl1271_tx_hw_descr;
 enum wl_rx_buf_align;
@@ -51,6 +54,9 @@
 	int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
 			   void *buf, size_t len);
 	int (*ack_event)(struct wl1271 *wl);
+	int (*wait_for_event)(struct wl1271 *wl, enum wlcore_wait_event event,
+			      bool *timeout);
+	int (*process_mailbox_events)(struct wl1271 *wl);
 	u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
 	void (*set_tx_desc_blocks)(struct wl1271 *wl,
 				   struct wl1271_tx_hw_descr *desc,
@@ -82,12 +88,32 @@
 	int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir);
 	int (*handle_static_data)(struct wl1271 *wl,
 				  struct wl1271_static_data *static_data);
+	int (*scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			  struct cfg80211_scan_request *req);
+	int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+	int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+				struct cfg80211_sched_scan_request *req,
+				struct ieee80211_sched_scan_ies *ies);
+	void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 	int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem);
 	int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd,
 		       struct ieee80211_vif *vif,
 		       struct ieee80211_sta *sta,
 		       struct ieee80211_key_conf *key_conf);
+	int (*channel_switch)(struct wl1271 *wl,
+			      struct wl12xx_vif *wlvif,
+			      struct ieee80211_channel_switch *ch_switch);
 	u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
+	void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+			      struct ieee80211_sta *sta, u32 changed);
+	int (*set_peer_cap)(struct wl1271 *wl,
+			    struct ieee80211_sta_ht_cap *ht_cap,
+			    bool allow_ht_operation,
+			    u32 rate_set, u8 hlid);
+	bool (*lnk_high_prio)(struct wl1271 *wl, u8 hlid,
+			      struct wl1271_link *lnk);
+	bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
+			     struct wl1271_link *lnk);
 };
 
 enum wlcore_partitions {
@@ -157,7 +183,6 @@
 
 	struct wl1271_if_operations *if_ops;
 
-	void (*set_power)(bool enable);
 	int irq;
 
 	spinlock_t wl_lock;
@@ -202,6 +227,8 @@
 	unsigned long klv_templates_map[
 			BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)];
 
+	u8 session_ids[WL12XX_MAX_LINKS];
+
 	struct list_head wlvif_list;
 
 	u8 sta_count;
@@ -227,7 +254,8 @@
 
 	/* Frames scheduled for transmission, not handled yet */
 	int tx_queue_count[NUM_TX_QUEUES];
-	unsigned long queue_stop_reasons[NUM_TX_QUEUES];
+	unsigned long queue_stop_reasons[
+				NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES];
 
 	/* Frames received, not handled yet by mac80211 */
 	struct sk_buff_head deferred_rx_queue;
@@ -269,24 +297,30 @@
 	struct work_struct recovery_work;
 	bool watchdog_recovery;
 
+	/* Reg domain last configuration */
+	u32 reg_ch_conf_last[2];
+	/* Reg domain pending configuration */
+	u32 reg_ch_conf_pending[2];
+
 	/* Pointer that holds DMA-friendly block for the mailbox */
-	struct event_mailbox *mbox;
+	void *mbox;
 
 	/* The mbox event mask */
 	u32 event_mask;
 
 	/* Mailbox pointers */
+	u32 mbox_size;
 	u32 mbox_ptr[2];
 
 	/* Are we currently scanning */
-	struct ieee80211_vif *scan_vif;
+	struct wl12xx_vif *scan_wlvif;
 	struct wl1271_scan scan;
 	struct delayed_work scan_complete_work;
 
-	/* Connection loss work */
-	struct delayed_work connection_loss_work;
+	struct ieee80211_vif *roc_vif;
+	struct delayed_work roc_complete_work;
 
-	bool sched_scanning;
+	struct wl12xx_vif *sched_vif;
 
 	/* The current band */
 	enum ieee80211_band band;
@@ -299,7 +333,7 @@
 
 	struct wl1271_stats stats;
 
-	__le32 buffer_32;
+	__le32 *buffer_32;
 	u32 buffer_cmd;
 	u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
 
@@ -314,6 +348,8 @@
 
 	bool enable_11a;
 
+	int recovery_count;
+
 	/* Most recently reported noise in dBm */
 	s8 noise;
 
@@ -333,6 +369,12 @@
 	 */
 	struct wl1271_link links[WL12XX_MAX_LINKS];
 
+	/* number of currently active links */
+	int active_link_count;
+
+	/* Fast/slow links bitmap according to FW */
+	u32 fw_fast_lnk_map;
+
 	/* AP-mode - a bitmap of links currently in PS mode according to FW */
 	u32 ap_fw_ps_map;
 
@@ -367,6 +409,12 @@
 	const char *sr_fw_name;
 	const char *mr_fw_name;
 
+	u8 scan_templ_id_2_4;
+	u8 scan_templ_id_5;
+	u8 sched_scan_templ_id_2_4;
+	u8 sched_scan_templ_id_5;
+	u8 max_channels_5;
+
 	/* per-chip-family private structure */
 	void *priv;
 
@@ -408,20 +456,28 @@
 	/* the number of allocated MAC addresses in this chip */
 	int num_mac_addr;
 
-	/* the minimum FW version required for the driver to work */
-	unsigned int min_fw_ver[NUM_FW_VER];
+	/* minimum FW version required for the driver to work in single-role */
+	unsigned int min_sr_fw_ver[NUM_FW_VER];
+
+	/* minimum FW version required for the driver to work in multi-role */
+	unsigned int min_mr_fw_ver[NUM_FW_VER];
 
 	struct completion nvs_loading_complete;
+
+	/* number of concurrent channels the HW supports */
+	u32 num_channels;
 };
 
 int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
 int wlcore_remove(struct platform_device *pdev);
-struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size);
+struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
+				     u32 mbox_size);
 int wlcore_free_hw(struct wl1271 *wl);
 int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
 		   struct ieee80211_vif *vif,
 		   struct ieee80211_sta *sta,
 		   struct ieee80211_key_conf *key_conf);
+void wlcore_regdomain_config(struct wl1271 *wl);
 
 static inline void
 wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
@@ -430,16 +486,27 @@
 	memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap));
 }
 
+/* Tell wlcore not to care about this element when checking the version */
+#define WLCORE_FW_VER_IGNORE	-1
+
 static inline void
 wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
-		      unsigned int iftype, unsigned int major,
-		      unsigned int subtype, unsigned int minor)
+		      unsigned int iftype_sr, unsigned int major_sr,
+		      unsigned int subtype_sr, unsigned int minor_sr,
+		      unsigned int iftype_mr, unsigned int major_mr,
+		      unsigned int subtype_mr, unsigned int minor_mr)
 {
-	wl->min_fw_ver[FW_VER_CHIP] = chip;
-	wl->min_fw_ver[FW_VER_IF_TYPE] = iftype;
-	wl->min_fw_ver[FW_VER_MAJOR] = major;
-	wl->min_fw_ver[FW_VER_SUBTYPE] = subtype;
-	wl->min_fw_ver[FW_VER_MINOR] = minor;
+	wl->min_sr_fw_ver[FW_VER_CHIP] = chip;
+	wl->min_sr_fw_ver[FW_VER_IF_TYPE] = iftype_sr;
+	wl->min_sr_fw_ver[FW_VER_MAJOR] = major_sr;
+	wl->min_sr_fw_ver[FW_VER_SUBTYPE] = subtype_sr;
+	wl->min_sr_fw_ver[FW_VER_MINOR] = minor_sr;
+
+	wl->min_mr_fw_ver[FW_VER_CHIP] = chip;
+	wl->min_mr_fw_ver[FW_VER_IF_TYPE] = iftype_mr;
+	wl->min_mr_fw_ver[FW_VER_MAJOR] = major_mr;
+	wl->min_mr_fw_ver[FW_VER_SUBTYPE] = subtype_mr;
+	wl->min_mr_fw_ver[FW_VER_MINOR] = minor_mr;
 }
 
 /* Firmware image load chunk size */
@@ -450,6 +517,9 @@
 /* Each RX/TX transaction requires an end-of-transaction transfer */
 #define WLCORE_QUIRK_END_OF_TRANSACTION		BIT(0)
 
+/* the first start_role(sta) sometimes doesn't work on wl12xx */
+#define WLCORE_QUIRK_START_STA_FAILS		BIT(1)
+
 /* wl127x and SPI don't support SDIO block size alignment */
 #define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN		BIT(2)
 
@@ -462,9 +532,6 @@
 /* Older firmwares use an old NVS format */
 #define WLCORE_QUIRK_LEGACY_NVS			BIT(5)
 
-/* Some firmwares may not support ELP */
-#define WLCORE_QUIRK_NO_ELP			BIT(6)
-
 /* pad only the last frame in the aggregate buffer */
 #define WLCORE_QUIRK_TX_PAD_LAST_FRAME		BIT(7)
 
@@ -477,11 +544,11 @@
 /* separate probe response templates for one-shot and sched scans */
 #define WLCORE_QUIRK_DUAL_PROBE_TMPL		BIT(10)
 
-/* TODO: move to the lower drivers when all usages are abstracted */
-#define CHIP_ID_1271_PG10              (0x4030101)
-#define CHIP_ID_1271_PG20              (0x4030111)
-#define CHIP_ID_1283_PG10              (0x05030101)
-#define CHIP_ID_1283_PG20              (0x05030111)
+/* Firmware requires reg domain configuration for active calibration */
+#define WLCORE_QUIRK_REGDOMAIN_CONF		BIT(11)
+
+/* The FW only support a zero session id for AP */
+#define WLCORE_QUIRK_AP_ZERO_SESSION_ID		BIT(12)
 
 /* TODO: move all these common registers and values elsewhere */
 #define HW_ACCESS_ELP_CTRL_REG		0x1FFFC
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 6678d4b..508f5b0 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -109,22 +109,11 @@
 	NUM_FW_VER
 };
 
-#define FW_VER_CHIP_WL127X 6
-#define FW_VER_CHIP_WL128X 7
-
-#define FW_VER_IF_TYPE_STA 1
-#define FW_VER_IF_TYPE_AP  2
-
-#define FW_VER_MINOR_1_SPARE_STA_MIN 58
-#define FW_VER_MINOR_1_SPARE_AP_MIN  47
-
-#define FW_VER_MINOR_FWLOG_STA_MIN 70
-
 struct wl1271_chip {
 	u32 id;
-	char fw_ver_str[ETHTOOL_BUSINFO_LEN];
+	char fw_ver_str[ETHTOOL_FWVERS_LEN];
 	unsigned int fw_ver[NUM_FW_VER];
-	char phy_fw_ver_str[ETHTOOL_BUSINFO_LEN];
+	char phy_fw_ver_str[ETHTOOL_FWVERS_LEN];
 };
 
 #define NUM_TX_QUEUES              4
@@ -141,7 +130,10 @@
 	/* Cumulative counter of released Voice memory blocks */
 	u8 tx_voice_released_blks;
 
-	u8 padding[3];
+	/* Tx rate of the last transmitted packet */
+	u8 tx_last_rate;
+
+	u8 padding[2];
 } __packed;
 
 /* FW status registers */
@@ -214,6 +206,11 @@
 	void (*set_block_size) (struct device *child, unsigned int blksz);
 };
 
+struct wlcore_platdev_data {
+	struct wl12xx_platform_data *pdata;
+	struct wl1271_if_operations *if_ops;
+};
+
 #define MAX_NUM_KEYS 14
 #define MAX_KEY_SIZE 32
 
@@ -260,6 +257,8 @@
 	WLVIF_FLAG_IN_USE,
 };
 
+struct wl12xx_vif;
+
 struct wl1271_link {
 	/* AP-mode - TX queue per AC in link */
 	struct sk_buff_head tx_queue[NUM_TX_QUEUES];
@@ -272,6 +271,9 @@
 
 	/* bitmap of TIDs where RX BA sessions are active for this link */
 	u8 ba_bitmap;
+
+	/* The wlvif this link belongs to. Might be null for global links */
+	struct wl12xx_vif *wlvif;
 };
 
 #define WL1271_MAX_RX_FILTERS 5
@@ -315,6 +317,7 @@
 
 struct wl1271_station {
 	u8 hlid;
+	bool in_connection;
 };
 
 struct wl12xx_vif {
@@ -332,7 +335,6 @@
 	union {
 		struct {
 			u8 hlid;
-			u8 ba_rx_bitmap;
 
 			u8 basic_rate_idx;
 			u8 ap_rate_idx;
@@ -341,6 +343,8 @@
 			u8 klv_template_id;
 
 			bool qos;
+			/* channel type we started the STA role with */
+			enum nl80211_channel_type role_chan_type;
 		} sta;
 		struct {
 			u8 global_hlid;
@@ -362,6 +366,9 @@
 	/* the hlid of the last transmitted skb */
 	int last_tx_hlid;
 
+	/* counters of packets per AC, across all links in the vif */
+	int tx_queue_count[NUM_TX_QUEUES];
+
 	unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
 
 	u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
@@ -396,9 +403,6 @@
 	/* Our association ID */
 	u16 aid;
 
-	/* Session counter for the chipset */
-	int session_counter;
-
 	/* retry counter for PSM entries */
 	u8 psm_entry_retry;
 
@@ -416,11 +420,28 @@
 	bool ba_support;
 	bool ba_allowed;
 
+	bool wmm_enabled;
+
 	/* Rx Streaming */
 	struct work_struct rx_streaming_enable_work;
 	struct work_struct rx_streaming_disable_work;
 	struct timer_list rx_streaming_timer;
 
+	struct delayed_work channel_switch_work;
+	struct delayed_work connection_loss_work;
+
+	/* number of in connection stations */
+	int inconn_count;
+
+	/*
+	 * This vif's queues are mapped to mac80211 HW queues as:
+	 * VO - hw_queue_base
+	 * VI - hw_queue_base + 1
+	 * BE - hw_queue_base + 2
+	 * BK - hw_queue_base + 3
+	 */
+	int hw_queue_base;
+
 	/*
 	 * This struct must be last!
 	 * data that has to be saved acrossed reconfigs (e.g. recovery)
@@ -443,6 +464,7 @@
 
 static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
 {
+	WARN_ON(!vif);
 	return (struct wl12xx_vif *)vif->drv_priv;
 }
 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index ef2b171..7ef0b4a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -155,7 +155,6 @@
 	 */
 	p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
 	if (!p) {
-		dev_err(&udev->dev, "out of memory\n");
 		r = -ENOMEM;
 		goto error;
 	}
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index b8c5193..d984141 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -132,6 +132,7 @@
 static void xenvif_down(struct xenvif *vif)
 {
 	disable_irq(vif->irq);
+	del_timer_sync(&vif->credit_timeout);
 	xen_netbk_deschedule_xenvif(vif);
 	xen_netbk_remove_xenvif(vif);
 }
@@ -238,6 +239,8 @@
 	.ndo_stop	= xenvif_close,
 	.ndo_change_mtu	= xenvif_change_mtu,
 	.ndo_fix_features = xenvif_fix_features,
+	.ndo_set_mac_address = eth_mac_addr,
+	.ndo_validate_addr   = eth_validate_addr,
 };
 
 struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
@@ -363,8 +366,6 @@
 	atomic_dec(&vif->refcnt);
 	wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
 
-	del_timer_sync(&vif->credit_timeout);
-
 	if (vif->irq)
 		unbind_from_irqhandler(vif->irq, vif);
 
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 2b9520c..cd49ba9 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -911,13 +911,13 @@
 		if (frags >= work_to_do) {
 			netdev_err(vif->dev, "Need more frags\n");
 			netbk_fatal_tx_err(vif);
-			return -frags;
+			return -ENODATA;
 		}
 
 		if (unlikely(frags >= MAX_SKB_FRAGS)) {
 			netdev_err(vif->dev, "Too many frags\n");
 			netbk_fatal_tx_err(vif);
-			return -frags;
+			return -E2BIG;
 		}
 
 		memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
@@ -925,7 +925,7 @@
 		if (txp->size > first->size) {
 			netdev_err(vif->dev, "Frag is bigger than frame.\n");
 			netbk_fatal_tx_err(vif);
-			return -frags;
+			return -EIO;
 		}
 
 		first->size -= txp->size;
@@ -935,7 +935,7 @@
 			netdev_err(vif->dev, "txp->offset: %x, size: %u\n",
 				 txp->offset, txp->size);
 			netbk_fatal_tx_err(vif);
-			return -frags;
+			return -EINVAL;
 		}
 	} while ((txp++)->flags & XEN_NETTXF_more_data);
 	return frags;
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index ec85767..e570349 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -5,19 +5,6 @@
 menu "Near Field Communication (NFC) devices"
 	depends on NFC
 
-config PN544_HCI_NFC
-	tristate "HCI PN544 NFC driver"
-	depends on I2C && NFC_HCI && NFC_SHDLC
-	select CRC_CCITT
-	default n
-	---help---
-	  NXP PN544 i2c driver.
-	  This is a driver based on the SHDLC and HCI NFC kernel layers and
-	  will thus not work with NXP libnfc library.
-
-	  To compile this driver as a module, choose m here. The module will
-	  be called pn544_hci.
-
 config NFC_PN533
 	tristate "NXP PN533 USB driver"
 	depends on USB
@@ -39,4 +26,7 @@
 	  Say Y here to compile support for Texas Instrument's NFC WiLink driver
 	  into the kernel or say M to compile it as module.
 
+source "drivers/nfc/pn544/Kconfig"
+source "drivers/nfc/microread/Kconfig"
+
 endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 36c3590..a189ada0 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -2,7 +2,8 @@
 # Makefile for nfc devices
 #
 
-obj-$(CONFIG_PN544_HCI_NFC)	+= pn544/
+obj-$(CONFIG_NFC_PN544)		+= pn544/
+obj-$(CONFIG_NFC_MICROREAD)	+= microread/
 obj-$(CONFIG_NFC_PN533)		+= pn533.o
 obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
 
diff --git a/drivers/nfc/microread/Kconfig b/drivers/nfc/microread/Kconfig
new file mode 100644
index 0000000..572305b
--- /dev/null
+++ b/drivers/nfc/microread/Kconfig
@@ -0,0 +1,35 @@
+config NFC_MICROREAD
+	tristate "Inside Secure microread NFC driver"
+	depends on NFC_HCI
+	select CRC_CCITT
+	default n
+	---help---
+	  This module contains the main code for Inside Secure microread
+	  NFC chipsets. It implements the chipset HCI logic and hooks into
+	  the NFC kernel APIs. Physical layers will register against it.
+
+	  To compile this driver as a module, choose m here. The module will
+	  be called microread.
+	  Say N if unsure.
+
+config NFC_MICROREAD_I2C
+	tristate "NFC Microread i2c support"
+	depends on NFC_MICROREAD && I2C && NFC_SHDLC
+	---help---
+	  This module adds support for the i2c interface of adapters using
+	  Inside microread chipsets.  Select this if your platform is using
+	  the i2c bus.
+
+	  If you choose to build a module, it'll be called microread_i2c.
+	  Say N if unsure.
+
+config NFC_MICROREAD_MEI
+	tristate "NFC Microread MEI support"
+	depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
+	---help---
+	  This module adds support for the mei interface of adapters using
+	  Inside microread chipsets.  Select this if your microread chipset
+	  is handled by Intel's Management Engine Interface on your platform.
+
+	  If you choose to build a module, it'll be called microread_mei.
+	  Say N if unsure.
diff --git a/drivers/nfc/microread/Makefile b/drivers/nfc/microread/Makefile
new file mode 100644
index 0000000..755c24c
--- /dev/null
+++ b/drivers/nfc/microread/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Microread HCI based NFC driver
+#
+
+microread_i2c-objs  = i2c.o
+microread_mei-objs  = mei.o
+
+obj-$(CONFIG_NFC_MICROREAD)     += microread.o
+obj-$(CONFIG_NFC_MICROREAD_I2C) += microread_i2c.o
+obj-$(CONFIG_NFC_MICROREAD_MEI) += microread_mei.o
diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c
new file mode 100644
index 0000000..1010894
--- /dev/null
+++ b/drivers/nfc/microread/i2c.c
@@ -0,0 +1,340 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip - i2c layer
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+#define MICROREAD_I2C_DRIVER_NAME "microread"
+
+#define MICROREAD_I2C_FRAME_HEADROOM 1
+#define MICROREAD_I2C_FRAME_TAILROOM 1
+
+/* framing in HCI mode */
+#define MICROREAD_I2C_LLC_LEN		1
+#define MICROREAD_I2C_LLC_CRC		1
+#define MICROREAD_I2C_LLC_LEN_CRC	(MICROREAD_I2C_LLC_LEN + \
+					MICROREAD_I2C_LLC_CRC)
+#define MICROREAD_I2C_LLC_MIN_SIZE	(1 + MICROREAD_I2C_LLC_LEN_CRC)
+#define MICROREAD_I2C_LLC_MAX_PAYLOAD	29
+#define MICROREAD_I2C_LLC_MAX_SIZE	(MICROREAD_I2C_LLC_LEN_CRC + 1 + \
+					MICROREAD_I2C_LLC_MAX_PAYLOAD)
+
+struct microread_i2c_phy {
+	struct i2c_client *i2c_dev;
+	struct nfc_hci_dev *hdev;
+
+	int irq;
+
+	int hard_fault;		/*
+				 * < 0 if hardware error occured (e.g. i2c err)
+				 * and prevents normal operation.
+				 */
+};
+
+#define I2C_DUMP_SKB(info, skb)					\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, 0);	\
+} while (0)
+
+static void microread_i2c_add_len_crc(struct sk_buff *skb)
+{
+	int i;
+	u8 crc = 0;
+	int len;
+
+	len = skb->len;
+	*skb_push(skb, 1) = len;
+
+	for (i = 0; i < skb->len; i++)
+		crc = crc ^ skb->data[i];
+
+	*skb_put(skb, 1) = crc;
+}
+
+static void microread_i2c_remove_len_crc(struct sk_buff *skb)
+{
+	skb_pull(skb, MICROREAD_I2C_FRAME_HEADROOM);
+	skb_trim(skb, MICROREAD_I2C_FRAME_TAILROOM);
+}
+
+static int check_crc(struct sk_buff *skb)
+{
+	int i;
+	u8 crc = 0;
+
+	for (i = 0; i < skb->len - 1; i++)
+		crc = crc ^ skb->data[i];
+
+	if (crc != skb->data[skb->len-1]) {
+		pr_err(MICROREAD_I2C_DRIVER_NAME
+		       ": CRC error 0x%x != 0x%x\n",
+		       crc, skb->data[skb->len-1]);
+
+		pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
+
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int microread_i2c_enable(void *phy_id)
+{
+	return 0;
+}
+
+static void microread_i2c_disable(void *phy_id)
+{
+	return;
+}
+
+static int microread_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+	int r;
+	struct microread_i2c_phy *phy = phy_id;
+	struct i2c_client *client = phy->i2c_dev;
+
+	if (phy->hard_fault != 0)
+		return phy->hard_fault;
+
+	usleep_range(3000, 6000);
+
+	microread_i2c_add_len_crc(skb);
+
+	I2C_DUMP_SKB("i2c frame written", skb);
+
+	r = i2c_master_send(client, skb->data, skb->len);
+
+	if (r == -EREMOTEIO) {	/* Retry, chip was in standby */
+		usleep_range(6000, 10000);
+		r = i2c_master_send(client, skb->data, skb->len);
+	}
+
+	if (r >= 0) {
+		if (r != skb->len)
+			r = -EREMOTEIO;
+		else
+			r = 0;
+	}
+
+	microread_i2c_remove_len_crc(skb);
+
+	return r;
+}
+
+
+static int microread_i2c_read(struct microread_i2c_phy *phy,
+			      struct sk_buff **skb)
+{
+	int r;
+	u8 len;
+	u8 tmp[MICROREAD_I2C_LLC_MAX_SIZE - 1];
+	struct i2c_client *client = phy->i2c_dev;
+
+	pr_debug("%s\n", __func__);
+
+	r = i2c_master_recv(client, &len, 1);
+	if (r != 1) {
+		dev_err(&client->dev, "cannot read len byte\n");
+		return -EREMOTEIO;
+	}
+
+	if ((len < MICROREAD_I2C_LLC_MIN_SIZE) ||
+	    (len > MICROREAD_I2C_LLC_MAX_SIZE)) {
+		dev_err(&client->dev, "invalid len byte\n");
+		pr_err("invalid len byte\n");
+		r = -EBADMSG;
+		goto flush;
+	}
+
+	*skb = alloc_skb(1 + len, GFP_KERNEL);
+	if (*skb == NULL) {
+		r = -ENOMEM;
+		goto flush;
+	}
+
+	*skb_put(*skb, 1) = len;
+
+	r = i2c_master_recv(client, skb_put(*skb, len), len);
+	if (r != len) {
+		kfree_skb(*skb);
+		return -EREMOTEIO;
+	}
+
+	I2C_DUMP_SKB("cc frame read", *skb);
+
+	r = check_crc(*skb);
+	if (r != 0) {
+		kfree_skb(*skb);
+		r = -EBADMSG;
+		goto flush;
+	}
+
+	skb_pull(*skb, 1);
+	skb_trim(*skb, (*skb)->len - MICROREAD_I2C_FRAME_TAILROOM);
+
+	usleep_range(3000, 6000);
+
+	return 0;
+
+flush:
+	if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
+		r = -EREMOTEIO;
+
+	usleep_range(3000, 6000);
+
+	return r;
+}
+
+static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
+{
+	struct microread_i2c_phy *phy = phy_id;
+	struct i2c_client *client;
+	struct sk_buff *skb = NULL;
+	int r;
+
+	if (!phy || irq != phy->i2c_dev->irq) {
+		WARN_ON_ONCE(1);
+		return IRQ_NONE;
+	}
+
+	client = phy->i2c_dev;
+	dev_dbg(&client->dev, "IRQ\n");
+
+	if (phy->hard_fault != 0)
+		return IRQ_HANDLED;
+
+	r = microread_i2c_read(phy, &skb);
+	if (r == -EREMOTEIO) {
+		phy->hard_fault = r;
+
+		nfc_hci_recv_frame(phy->hdev, NULL);
+
+		return IRQ_HANDLED;
+	} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
+		return IRQ_HANDLED;
+	}
+
+	nfc_hci_recv_frame(phy->hdev, skb);
+
+	return IRQ_HANDLED;
+}
+
+static struct nfc_phy_ops i2c_phy_ops = {
+	.write = microread_i2c_write,
+	.enable = microread_i2c_enable,
+	.disable = microread_i2c_disable,
+};
+
+static int microread_i2c_probe(struct i2c_client *client,
+			       const struct i2c_device_id *id)
+{
+	struct microread_i2c_phy *phy;
+	struct microread_nfc_platform_data *pdata =
+		dev_get_platdata(&client->dev);
+	int r;
+
+	dev_dbg(&client->dev, "client %p", client);
+
+	if (!pdata) {
+		dev_err(&client->dev, "client %p: missing platform data",
+			client);
+		return -EINVAL;
+	}
+
+	phy = devm_kzalloc(&client->dev, sizeof(struct microread_i2c_phy),
+			   GFP_KERNEL);
+	if (!phy) {
+		dev_err(&client->dev, "Can't allocate microread phy");
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, phy);
+	phy->i2c_dev = client;
+
+	r = request_threaded_irq(client->irq, NULL, microread_i2c_irq_thread_fn,
+				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				 MICROREAD_I2C_DRIVER_NAME, phy);
+	if (r) {
+		dev_err(&client->dev, "Unable to register IRQ handler");
+		return r;
+	}
+
+	r = microread_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+			    MICROREAD_I2C_FRAME_HEADROOM,
+			    MICROREAD_I2C_FRAME_TAILROOM,
+			    MICROREAD_I2C_LLC_MAX_PAYLOAD, &phy->hdev);
+	if (r < 0)
+		goto err_irq;
+
+	dev_info(&client->dev, "Probed");
+
+	return 0;
+
+err_irq:
+	free_irq(client->irq, phy);
+
+	return r;
+}
+
+static int microread_i2c_remove(struct i2c_client *client)
+{
+	struct microread_i2c_phy *phy = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	microread_remove(phy->hdev);
+
+	free_irq(client->irq, phy);
+
+	return 0;
+}
+
+static struct i2c_device_id microread_i2c_id[] = {
+	{ MICROREAD_I2C_DRIVER_NAME, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, microread_i2c_id);
+
+static struct i2c_driver microread_i2c_driver = {
+	.driver = {
+		.name = MICROREAD_I2C_DRIVER_NAME,
+	},
+	.probe		= microread_i2c_probe,
+	.remove		= microread_i2c_remove,
+	.id_table	= microread_i2c_id,
+};
+
+module_i2c_driver(microread_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c
new file mode 100644
index 0000000..eef38cf
--- /dev/null
+++ b/drivers/nfc/microread/mei.c
@@ -0,0 +1,246 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip
+ *
+ * Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mei_bus.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+#define MICROREAD_DRIVER_NAME "microread"
+
+#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
+			       0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
+
+struct mei_nfc_hdr {
+	u8 cmd;
+	u8 status;
+	u16 req_id;
+	u32 reserved;
+	u16 data_size;
+} __attribute__((packed));
+
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
+
+struct microread_mei_phy {
+	struct mei_device *mei_device;
+	struct nfc_hci_dev *hdev;
+
+	int powered;
+
+	int hard_fault;		/*
+				 * < 0 if hardware error occured (e.g. i2c err)
+				 * and prevents normal operation.
+				 */
+};
+
+#define MEI_DUMP_SKB_IN(info, skb)					\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, 0);	\
+} while (0)
+
+#define MEI_DUMP_SKB_OUT(info, skb)					\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, 0);	\
+} while (0)
+
+static int microread_mei_enable(void *phy_id)
+{
+	struct microread_mei_phy *phy = phy_id;
+
+	pr_info(DRIVER_DESC ": %s\n", __func__);
+
+	phy->powered = 1;
+
+	return 0;
+}
+
+static void microread_mei_disable(void *phy_id)
+{
+	struct microread_mei_phy *phy = phy_id;
+
+	pr_info(DRIVER_DESC ": %s\n", __func__);
+
+	phy->powered = 0;
+}
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int microread_mei_write(void *phy_id, struct sk_buff *skb)
+{
+	struct microread_mei_phy *phy = phy_id;
+	int r;
+
+	MEI_DUMP_SKB_OUT("mei frame sent", skb);
+
+	r = mei_send(phy->device, skb->data, skb->len);
+	if (r > 0)
+		r = 0;
+
+	return r;
+}
+
+static void microread_event_cb(struct mei_device *device, u32 events,
+			       void *context)
+{
+	struct microread_mei_phy *phy = context;
+
+	if (phy->hard_fault != 0)
+		return;
+
+	if (events & BIT(MEI_EVENT_RX)) {
+		struct sk_buff *skb;
+		int reply_size;
+
+		skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
+		if (!skb)
+			return;
+
+		reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ);
+		if (reply_size < MEI_NFC_HEADER_SIZE) {
+			kfree(skb);
+			return;
+		}
+
+		skb_put(skb, reply_size);
+		skb_pull(skb, MEI_NFC_HEADER_SIZE);
+
+		MEI_DUMP_SKB_IN("mei frame read", skb);
+
+		nfc_hci_recv_frame(phy->hdev, skb);
+	}
+}
+
+static struct nfc_phy_ops mei_phy_ops = {
+	.write = microread_mei_write,
+	.enable = microread_mei_enable,
+	.disable = microread_mei_disable,
+};
+
+static int microread_mei_probe(struct mei_device *device,
+			       const struct mei_id *id)
+{
+	struct microread_mei_phy *phy;
+	int r;
+
+	pr_info("Probing NFC microread\n");
+
+	phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
+	if (!phy) {
+		pr_err("Cannot allocate memory for microread mei phy.\n");
+		return -ENOMEM;
+	}
+
+	phy->device = device;
+	mei_set_clientdata(device, phy);
+
+	r = mei_register_event_cb(device, microread_event_cb, phy);
+	if (r) {
+		pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
+		goto err_out;
+	}
+
+	r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
+			    MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
+			    &phy->hdev);
+	if (r < 0)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	kfree(phy);
+
+	return r;
+}
+
+static int microread_mei_remove(struct mei_device *device)
+{
+	struct microread_mei_phy *phy = mei_get_clientdata(device);
+
+	pr_info("Removing microread\n");
+
+	microread_remove(phy->hdev);
+
+	if (phy->powered)
+		microread_mei_disable(phy);
+
+	kfree(phy);
+
+	return 0;
+}
+
+static struct mei_id microread_mei_tbl[] = {
+	{ MICROREAD_DRIVER_NAME, MICROREAD_UUID },
+
+	/* required last entry */
+	{ }
+};
+
+MODULE_DEVICE_TABLE(mei, microread_mei_tbl);
+
+static struct mei_driver microread_driver = {
+	.id_table = microread_mei_tbl,
+	.name = MICROREAD_DRIVER_NAME,
+
+	.probe = microread_mei_probe,
+	.remove = microread_mei_remove,
+};
+
+static int microread_mei_init(void)
+{
+	int r;
+
+	pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+	r = mei_driver_register(&microread_driver);
+	if (r) {
+		pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static void microread_mei_exit(void)
+{
+	mei_driver_unregister(&microread_driver);
+}
+
+module_init(microread_mei_init);
+module_exit(microread_mei_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c
new file mode 100644
index 0000000..3420d83
--- /dev/null
+++ b/drivers/nfc/microread/microread.c
@@ -0,0 +1,728 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip
+ *
+ * Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/crc-ccitt.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+/* Proprietary gates, events, commands and registers */
+/* Admin */
+#define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE
+#define MICROREAD_GATE_ID_MGT 0x01
+#define MICROREAD_GATE_ID_OS 0x02
+#define MICROREAD_GATE_ID_TESTRF 0x03
+#define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE
+#define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE
+#define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE
+
+/* Reader */
+#define MICROREAD_GATE_ID_MREAD_GEN 0x10
+#define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE
+#define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12
+#define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE
+#define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14
+#define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15
+#define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16
+#define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17
+#define MICROREAD_GATE_ID_MREAD_BPRIME 0x18
+#define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19
+
+/* Card */
+#define MICROREAD_GATE_ID_MCARD_GEN 0x20
+#define MICROREAD_GATE_ID_MCARD_ISO_B 0x21
+#define MICROREAD_GATE_ID_MCARD_BPRIME 0x22
+#define MICROREAD_GATE_ID_MCARD_ISO_A 0x23
+#define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24
+#define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25
+#define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26
+#define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27
+#define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28
+#define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F
+
+/* P2P */
+#define MICROREAD_GATE_ID_P2P_GEN 0x30
+#define MICROREAD_GATE_ID_P2P_TARGET 0x31
+#define MICROREAD_PAR_P2P_TARGET_MODE 0x01
+#define MICROREAD_PAR_P2P_TARGET_GT 0x04
+#define MICROREAD_GATE_ID_P2P_INITIATOR 0x32
+#define MICROREAD_PAR_P2P_INITIATOR_GI 0x01
+#define MICROREAD_PAR_P2P_INITIATOR_GT 0x03
+
+/* Those pipes are created/opened by default in the chip */
+#define MICROREAD_PIPE_ID_LMS 0x00
+#define MICROREAD_PIPE_ID_ADMIN 0x01
+#define MICROREAD_PIPE_ID_MGT 0x02
+#define MICROREAD_PIPE_ID_OS 0x03
+#define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04
+#define MICROREAD_PIPE_ID_HDS_IDT 0x05
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C
+#define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E
+#define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10
+#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14
+#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16
+#define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18
+#define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B
+#define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C
+#define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D
+#define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E
+#define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F
+#define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20
+
+/* Events */
+#define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED
+#define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D
+#define MICROREAD_EMCF_A_ATQA 0
+#define MICROREAD_EMCF_A_SAK 2
+#define MICROREAD_EMCF_A_LEN 3
+#define MICROREAD_EMCF_A_UID 4
+#define MICROREAD_EMCF_A3_ATQA 0
+#define MICROREAD_EMCF_A3_SAK 2
+#define MICROREAD_EMCF_A3_LEN 3
+#define MICROREAD_EMCF_A3_UID 4
+#define MICROREAD_EMCF_B_UID 0
+#define MICROREAD_EMCF_T1_ATQA 0
+#define MICROREAD_EMCF_T1_UID 4
+#define MICROREAD_EMCF_T3_UID 0
+#define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED
+#define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E
+#define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION
+#define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F
+#define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED
+#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20
+#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21
+#define MICROREAD_EVT_MCARD_FIELD_ON 0x11
+#define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13
+#define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12
+#define MICROREAD_EVT_MCARD_FIELD_OFF 0x14
+
+/* Commands */
+#define MICROREAD_CMD_MREAD_EXCHANGE 0x10
+#define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F
+
+/* Hosts IDs */
+#define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID
+#define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID
+#define MICROREAD_ELT_ID_SE1 0x03
+#define MICROREAD_ELT_ID_SE2 0x04
+#define MICROREAD_ELT_ID_SE3 0x05
+
+static struct nfc_hci_gate microread_gates[] = {
+	{MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN},
+	{MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK},
+	{MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT},
+	{MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS},
+	{MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B},
+	{MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A},
+	{MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3},
+	{MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT},
+	{MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS},
+	{MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1},
+	{MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3},
+	{MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET},
+	{MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR}
+};
+
+/* Largest headroom needed for outgoing custom commands */
+#define MICROREAD_CMDS_HEADROOM	2
+#define MICROREAD_CMD_TAILROOM	2
+
+struct microread_info {
+	struct nfc_phy_ops *phy_ops;
+	void *phy_id;
+
+	struct nfc_hci_dev *hdev;
+
+	int async_cb_type;
+	data_exchange_cb_t async_cb;
+	void *async_cb_context;
+};
+
+static int microread_open(struct nfc_hci_dev *hdev)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	return info->phy_ops->enable(info->phy_id);
+}
+
+static void microread_close(struct nfc_hci_dev *hdev)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	info->phy_ops->disable(info->phy_id);
+}
+
+static int microread_hci_ready(struct nfc_hci_dev *hdev)
+{
+	int r;
+	u8 param[4];
+
+	param[0] = 0x03;
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL);
+	if (r)
+		return r;
+
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
+	if (r)
+		return r;
+
+	param[0] = 0x00;
+	param[1] = 0x03;
+	param[2] = 0x00;
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL);
+	if (r)
+		return r;
+
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
+	if (r)
+		return r;
+
+	param[0] = 0xFF;
+	param[1] = 0xFF;
+	param[2] = 0x00;
+	param[3] = 0x00;
+	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3,
+			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL);
+
+	return r;
+}
+
+static int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	return info->phy_ops->write(info->phy_id, skb);
+}
+
+static int microread_start_poll(struct nfc_hci_dev *hdev,
+				u32 im_protocols, u32 tm_protocols)
+{
+	int r;
+
+	u8 param[2];
+	u8 mode;
+
+	param[0] = 0x00;
+	param[1] = 0x00;
+
+	if (im_protocols & NFC_PROTO_ISO14443_MASK)
+		param[0] |= (1 << 2);
+
+	if (im_protocols & NFC_PROTO_ISO14443_B_MASK)
+		param[0] |= 1;
+
+	if (im_protocols & NFC_PROTO_MIFARE_MASK)
+		param[1] |= 1;
+
+	if (im_protocols & NFC_PROTO_JEWEL_MASK)
+		param[0] |= (1 << 1);
+
+	if (im_protocols & NFC_PROTO_FELICA_MASK)
+		param[0] |= (1 << 5);
+
+	if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
+		param[1] |= (1 << 1);
+
+	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
+		hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
+						       &hdev->gb_len);
+		if (hdev->gb == NULL || hdev->gb_len == 0) {
+			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+		}
+	}
+
+	r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+			       MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
+	if (r)
+		return r;
+
+	mode = 0xff;
+	r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+			      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+	if (r)
+		return r;
+
+	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
+				      MICROREAD_PAR_P2P_INITIATOR_GI,
+				      hdev->gb, hdev->gb_len);
+		if (r)
+			return r;
+	}
+
+	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+				      MICROREAD_PAR_P2P_TARGET_GT,
+				      hdev->gb, hdev->gb_len);
+		if (r)
+			return r;
+
+		mode = 0x02;
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+				      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+		if (r)
+			return r;
+	}
+
+	return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+				  MICROREAD_EVT_MREAD_DISCOVERY_START_SOME,
+				  param, 2);
+}
+
+static int microread_dep_link_up(struct nfc_hci_dev *hdev,
+				struct nfc_target *target, u8 comm_mode,
+				u8 *gb, size_t gb_len)
+{
+	struct sk_buff *rgb_skb = NULL;
+	int r;
+
+	r = nfc_hci_get_param(hdev, target->hci_reader_gate,
+			      MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb);
+	if (r < 0)
+		return r;
+
+	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
+		r = -EPROTO;
+		goto exit;
+	}
+
+	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
+					 rgb_skb->len);
+	if (r == 0)
+		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
+				       NFC_RF_INITIATOR);
+exit:
+	kfree_skb(rgb_skb);
+
+	return r;
+}
+
+static int microread_dep_link_down(struct nfc_hci_dev *hdev)
+{
+	return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
+				  MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
+}
+
+static int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
+				      struct nfc_target *target)
+{
+	switch (gate) {
+	case MICROREAD_GATE_ID_P2P_INITIATOR:
+		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+		break;
+	default:
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+static int microread_complete_target_discovered(struct nfc_hci_dev *hdev,
+						u8 gate,
+						struct nfc_target *target)
+{
+	return 0;
+}
+
+#define MICROREAD_CB_TYPE_READER_ALL 1
+
+static void microread_im_transceive_cb(void *context, struct sk_buff *skb,
+				       int err)
+{
+	struct microread_info *info = context;
+
+	switch (info->async_cb_type) {
+	case MICROREAD_CB_TYPE_READER_ALL:
+		if (err == 0) {
+			if (skb->len == 0) {
+				err = -EPROTO;
+				kfree_skb(skb);
+				info->async_cb(info->async_cb_context, NULL,
+					       -EPROTO);
+				return;
+			}
+
+			if (skb->data[skb->len - 1] != 0) {
+				err = nfc_hci_result_to_errno(
+						       skb->data[skb->len - 1]);
+				kfree_skb(skb);
+				info->async_cb(info->async_cb_context, NULL,
+					       err);
+				return;
+			}
+
+			skb_trim(skb, skb->len - 1);	/* RF Error ind. */
+		}
+		info->async_cb(info->async_cb_context, skb, err);
+		break;
+	default:
+		if (err == 0)
+			kfree_skb(skb);
+		break;
+	}
+}
+
+/*
+ * Returns:
+ * <= 0: driver handled the data exchange
+ *    1: driver doesn't especially handle, please do standard processing
+ */
+static int microread_im_transceive(struct nfc_hci_dev *hdev,
+				   struct nfc_target *target,
+				   struct sk_buff *skb, data_exchange_cb_t cb,
+				   void *cb_context)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+	u8 control_bits;
+	u16 crc;
+
+	pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate);
+
+	if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) {
+		*skb_push(skb, 1) = 0;
+
+		return nfc_hci_send_event(hdev, target->hci_reader_gate,
+				     MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF,
+				     skb->data, skb->len);
+	}
+
+	switch (target->hci_reader_gate) {
+	case MICROREAD_GATE_ID_MREAD_ISO_A:
+		control_bits = 0xCB;
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+		control_bits = 0xCB;
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_B:
+		control_bits = 0xCB;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T1:
+		control_bits = 0x1B;
+
+		crc = crc_ccitt(0xffff, skb->data, skb->len);
+		crc = ~crc;
+		*skb_put(skb, 1) = crc & 0xff;
+		*skb_put(skb, 1) = crc >> 8;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T3:
+		control_bits = 0xDB;
+		break;
+	default:
+		pr_info("Abort im_transceive to invalid gate 0x%x\n",
+			target->hci_reader_gate);
+		return 1;
+	}
+
+	*skb_push(skb, 1) = control_bits;
+
+	info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL;
+	info->async_cb = cb;
+	info->async_cb_context = cb_context;
+
+	return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
+				      MICROREAD_CMD_MREAD_EXCHANGE,
+				      skb->data, skb->len,
+				      microread_im_transceive_cb, info);
+}
+
+static int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+	int r;
+
+	r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+			       MICROREAD_EVT_MCARD_EXCHANGE,
+			       skb->data, skb->len);
+
+	kfree_skb(skb);
+
+	return r;
+}
+
+static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
+					struct sk_buff *skb)
+{
+	struct nfc_target *targets;
+	int r = 0;
+
+	pr_info("target discovered to gate 0x%x\n", gate);
+
+	targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
+	if (targets == NULL) {
+		r = -ENOMEM;
+		goto exit;
+	}
+
+	targets->hci_reader_gate = gate;
+
+	switch (gate) {
+	case MICROREAD_GATE_ID_MREAD_ISO_A:
+		targets->supported_protocols =
+		      nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]);
+		targets->sens_res =
+			 be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]);
+		targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK];
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID],
+		       skb->data[MICROREAD_EMCF_A_LEN]);
+		targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN];
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+		targets->supported_protocols =
+		      nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]);
+		targets->sens_res =
+			 be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]);
+		targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK];
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID],
+		       skb->data[MICROREAD_EMCF_A3_LEN]);
+		targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN];
+		break;
+	case MICROREAD_GATE_ID_MREAD_ISO_B:
+		targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4);
+		targets->nfcid1_len = 4;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T1:
+		targets->supported_protocols = NFC_PROTO_JEWEL_MASK;
+		targets->sens_res =
+			le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]);
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4);
+		targets->nfcid1_len = 4;
+		break;
+	case MICROREAD_GATE_ID_MREAD_NFC_T3:
+		targets->supported_protocols = NFC_PROTO_FELICA_MASK;
+		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8);
+		targets->nfcid1_len = 8;
+		break;
+	default:
+		pr_info("discard target discovered to gate 0x%x\n", gate);
+		goto exit_free;
+	}
+
+	r = nfc_targets_found(hdev->ndev, targets, 1);
+
+exit_free:
+	kfree(targets);
+
+exit:
+	kfree_skb(skb);
+
+	if (r)
+		pr_err("Failed to handle discovered target err=%d", r);
+}
+
+static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate,
+				     u8 event, struct sk_buff *skb)
+{
+	int r;
+	u8 mode;
+
+	pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
+
+	switch (event) {
+	case MICROREAD_EVT_MREAD_CARD_FOUND:
+		microread_target_discovered(hdev, gate, skb);
+		return 0;
+
+	case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF:
+		if (skb->len < 1) {
+			kfree_skb(skb);
+			return -EPROTO;
+		}
+
+		if (skb->data[skb->len - 1]) {
+			kfree_skb(skb);
+			return -EIO;
+		}
+
+		skb_trim(skb, skb->len - 1);
+
+		r = nfc_tm_data_received(hdev->ndev, skb);
+		break;
+
+	case MICROREAD_EVT_MCARD_FIELD_ON:
+	case MICROREAD_EVT_MCARD_FIELD_OFF:
+		kfree_skb(skb);
+		return 0;
+
+	case MICROREAD_EVT_P2P_TARGET_ACTIVATED:
+		r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+				     NFC_COMM_PASSIVE, skb->data,
+				     skb->len);
+
+		kfree_skb(skb);
+		break;
+
+	case MICROREAD_EVT_MCARD_EXCHANGE:
+		if (skb->len < 1) {
+			kfree_skb(skb);
+			return -EPROTO;
+		}
+
+		if (skb->data[skb->len-1]) {
+			kfree_skb(skb);
+			return -EIO;
+		}
+
+		skb_trim(skb, skb->len - 1);
+
+		r = nfc_tm_data_received(hdev->ndev, skb);
+		break;
+
+	case MICROREAD_EVT_P2P_TARGET_DEACTIVATED:
+		kfree_skb(skb);
+
+		mode = 0xff;
+		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+				      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+		if (r)
+			break;
+
+		r = nfc_hci_send_event(hdev, gate,
+				       MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL,
+				       0);
+		break;
+
+	default:
+		return 1;
+	}
+
+	return r;
+}
+
+static struct nfc_hci_ops microread_hci_ops = {
+	.open = microread_open,
+	.close = microread_close,
+	.hci_ready = microread_hci_ready,
+	.xmit = microread_xmit,
+	.start_poll = microread_start_poll,
+	.dep_link_up = microread_dep_link_up,
+	.dep_link_down = microread_dep_link_down,
+	.target_from_gate = microread_target_from_gate,
+	.complete_target_discovered = microread_complete_target_discovered,
+	.im_transceive = microread_im_transceive,
+	.tm_send = microread_tm_send,
+	.check_presence = NULL,
+	.event_received = microread_event_received,
+};
+
+int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
+		    int phy_headroom, int phy_tailroom, int phy_payload,
+		    struct nfc_hci_dev **hdev)
+{
+	struct microread_info *info;
+	unsigned long quirks = 0;
+	u32 protocols, se;
+	struct nfc_hci_init_data init_data;
+	int r;
+
+	info = kzalloc(sizeof(struct microread_info), GFP_KERNEL);
+	if (!info) {
+		pr_err("Cannot allocate memory for microread_info.\n");
+		r = -ENOMEM;
+		goto err_info_alloc;
+	}
+
+	info->phy_ops = phy_ops;
+	info->phy_id = phy_id;
+
+	init_data.gate_count = ARRAY_SIZE(microread_gates);
+	memcpy(init_data.gates, microread_gates, sizeof(microread_gates));
+
+	strcpy(init_data.session_id, "MICROREA");
+
+	set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks);
+
+	protocols = NFC_PROTO_JEWEL_MASK |
+		    NFC_PROTO_MIFARE_MASK |
+		    NFC_PROTO_FELICA_MASK |
+		    NFC_PROTO_ISO14443_MASK |
+		    NFC_PROTO_ISO14443_B_MASK |
+		    NFC_PROTO_NFC_DEP_MASK;
+
+	se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
+	info->hdev = nfc_hci_allocate_device(&microread_hci_ops, &init_data,
+					     quirks, protocols, se, llc_name,
+					     phy_headroom +
+					     MICROREAD_CMDS_HEADROOM,
+					     phy_tailroom +
+					     MICROREAD_CMD_TAILROOM,
+					     phy_payload);
+	if (!info->hdev) {
+		pr_err("Cannot allocate nfc hdev.\n");
+		r = -ENOMEM;
+		goto err_alloc_hdev;
+	}
+
+	nfc_hci_set_clientdata(info->hdev, info);
+
+	r = nfc_hci_register_device(info->hdev);
+	if (r)
+		goto err_regdev;
+
+	*hdev = info->hdev;
+
+	return 0;
+
+err_regdev:
+	nfc_hci_free_device(info->hdev);
+
+err_alloc_hdev:
+	kfree(info);
+
+err_info_alloc:
+	return r;
+}
+EXPORT_SYMBOL(microread_probe);
+
+void microread_remove(struct nfc_hci_dev *hdev)
+{
+	struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+	nfc_hci_unregister_device(hdev);
+	nfc_hci_free_device(hdev);
+	kfree(info);
+}
+EXPORT_SYMBOL(microread_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/microread/microread.h b/drivers/nfc/microread/microread.h
new file mode 100644
index 0000000..64b447a
--- /dev/null
+++ b/drivers/nfc/microread/microread.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 - 2012  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LOCAL_MICROREAD_H_
+#define __LOCAL_MICROREAD_H_
+
+#include <net/nfc/hci.h>
+
+#define DRIVER_DESC "NFC driver for microread"
+
+int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
+		    int phy_headroom, int phy_tailroom, int phy_payload,
+		    struct nfc_hci_dev **hdev);
+
+void microread_remove(struct nfc_hci_dev *hdev);
+
+#endif /* __LOCAL_MICROREAD_H_ */
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
index 50b1ee4..3b731ac 100644
--- a/drivers/nfc/nfcwilink.c
+++ b/drivers/nfc/nfcwilink.c
@@ -526,7 +526,7 @@
 
 	nfc_dev_dbg(&pdev->dev, "probe entry");
 
-	drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL);
+	drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
 	if (!drv) {
 		rc = -ENOMEM;
 		goto exit;
@@ -542,12 +542,13 @@
 
 	drv->ndev = nci_allocate_device(&nfcwilink_ops,
 					protocols,
+					NFC_SE_NONE,
 					NFCWILINK_HDR_LEN,
 					0);
 	if (!drv->ndev) {
 		nfc_dev_err(&pdev->dev, "nci_allocate_device failed");
 		rc = -ENOMEM;
-		goto free_exit;
+		goto exit;
 	}
 
 	nci_set_parent_dev(drv->ndev, &pdev->dev);
@@ -566,9 +567,6 @@
 free_dev_exit:
 	nci_free_device(drv->ndev);
 
-free_exit:
-	kfree(drv);
-
 exit:
 	return rc;
 }
@@ -588,8 +586,6 @@
 	nci_unregister_device(ndev);
 	nci_free_device(ndev);
 
-	kfree(drv);
-
 	dev_set_drvdata(&pdev->dev, NULL);
 
 	return 0;
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index ada681b..f0f6763 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -41,11 +41,6 @@
 #define SONY_VENDOR_ID         0x054c
 #define PASORI_PRODUCT_ID      0x02e1
 
-#define PN533_QUIRKS_TYPE_A          BIT(0)
-#define PN533_QUIRKS_TYPE_F          BIT(1)
-#define PN533_QUIRKS_DEP             BIT(2)
-#define PN533_QUIRKS_RAW_EXCHANGE    BIT(3)
-
 #define PN533_DEVICE_STD    0x1
 #define PN533_DEVICE_PASORI 0x2
 
@@ -84,14 +79,18 @@
 #define PN533_LISTEN_TIME 2
 
 /* frame definitions */
-#define PN533_NORMAL_FRAME_MAX_LEN 262  /* 6   (PREAMBLE, SOF, LEN, LCS, TFI)
-					   254 (DATA)
-					   2   (DCS, postamble) */
+#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \
+					+ 2) /* data[0] TFI, data[1] CC */
+#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
 
-#define PN533_FRAME_TAIL_SIZE 2
-#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
-				PN533_FRAME_TAIL_SIZE)
-#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1)
+/*
+ * Max extended frame payload len, excluding TFI and CC
+ * which are already in PN533_FRAME_HEADER_LEN.
+ */
+#define PN533_FRAME_MAX_PAYLOAD_LEN 263
+
+#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
+				  Postamble (1) */
 #define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
 #define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
 
@@ -105,8 +104,6 @@
 
 /* PN533 Commands */
 #define PN533_FRAME_CMD(f) (f->data[1])
-#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2])
-#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2)
 
 #define PN533_CMD_GET_FIRMWARE_VERSION 0x02
 #define PN533_CMD_RF_CONFIGURATION 0x32
@@ -120,6 +117,7 @@
 #define PN533_CMD_TG_INIT_AS_TARGET 0x8c
 #define PN533_CMD_TG_GET_DATA 0x86
 #define PN533_CMD_TG_SET_DATA 0x8e
+#define PN533_CMD_UNDEF 0xff
 
 #define PN533_CMD_RESPONSE(cmd) (cmd + 1)
 
@@ -128,13 +126,12 @@
 #define PN533_CMD_MI_MASK 0x40
 #define PN533_CMD_RET_SUCCESS 0x00
 
-/* PN533 status codes */
-#define PN533_STATUS_TARGET_RELEASED 0x29
-
 struct pn533;
 
-typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
-					u8 *params, int params_len);
+typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status);
+
+typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
+					struct sk_buff *resp);
 
 /* structs for pn533 commands */
 
@@ -222,7 +219,7 @@
 	u8 len;
 };
 
-const struct pn533_poll_modulations poll_mod[] = {
+static const struct pn533_poll_modulations poll_mod[] = {
 	[PN533_POLL_MOD_106KBPS_A] = {
 		.data = {
 			.maxtg = 1,
@@ -282,11 +279,6 @@
 
 /* PN533_CMD_IN_ATR */
 
-struct pn533_cmd_activate_param {
-	u8 tg;
-	u8 next;
-} __packed;
-
 struct pn533_cmd_activate_response {
 	u8 status;
 	u8 nfcid3t[10];
@@ -299,14 +291,6 @@
 	u8 gt[];
 } __packed;
 
-/* PN533_CMD_IN_JUMP_FOR_DEP */
-struct pn533_cmd_jump_dep {
-	u8 active;
-	u8 baud;
-	u8 next;
-	u8 data[];
-} __packed;
-
 struct pn533_cmd_jump_dep_response {
 	u8 status;
 	u8 tg;
@@ -329,32 +313,13 @@
 #define PN533_INIT_TARGET_RESP_ACTIVE     0x1
 #define PN533_INIT_TARGET_RESP_DEP        0x4
 
-struct pn533_cmd_init_target {
-	u8 mode;
-	u8 mifare[6];
-	u8 felica[18];
-	u8 nfcid3[10];
-	u8 gb_len;
-	u8 gb[];
-} __packed;
-
-struct pn533_cmd_init_target_response {
-	u8 mode;
-	u8 cmd[];
-} __packed;
-
 struct pn533 {
 	struct usb_device *udev;
 	struct usb_interface *interface;
 	struct nfc_dev *nfc_dev;
 
 	struct urb *out_urb;
-	int out_maxlen;
-	struct pn533_frame *out_frame;
-
 	struct urb *in_urb;
-	int in_maxlen;
-	struct pn533_frame *in_frame;
 
 	struct sk_buff_head resp_q;
 
@@ -365,12 +330,12 @@
 	struct work_struct mi_work;
 	struct work_struct tg_work;
 	struct timer_list listen_timer;
-	struct pn533_frame *wq_in_frame;
 	int wq_in_error;
 	int cancel_listen;
 
 	pn533_cmd_complete_t cmd_complete;
 	void *cmd_complete_arg;
+	void *cmd_complete_mi_arg;
 	struct mutex cmd_lock;
 	u8 cmd;
 
@@ -391,16 +356,17 @@
 
 	struct list_head cmd_queue;
 	u8 cmd_pending;
+
+	struct pn533_frame_ops *ops;
 };
 
 struct pn533_cmd {
 	struct list_head queue;
-	struct pn533_frame *out_frame;
-	struct pn533_frame *in_frame;
-	int in_frame_len;
-	pn533_cmd_complete_t cmd_complete;
+	u8 cmd_code;
+	struct sk_buff *req;
+	struct sk_buff *resp;
+	int resp_len;
 	void *arg;
-	gfp_t flags;
 };
 
 struct pn533_frame {
@@ -411,6 +377,22 @@
 	u8 data[];
 } __packed;
 
+struct pn533_frame_ops {
+	void (*tx_frame_init)(void *frame, u8 cmd_code);
+	void (*tx_frame_finish)(void *frame);
+	void (*tx_update_payload_len)(void *frame, int len);
+	int tx_header_len;
+	int tx_tail_len;
+
+	bool (*rx_is_frame_valid)(void *frame);
+	int (*rx_frame_size)(void *frame);
+	int rx_header_len;
+	int rx_tail_len;
+
+	int max_payload_len;
+	u8 (*get_cmd_code)(void *frame);
+};
+
 /* The rule: value + checksum = 0 */
 static inline u8 pn533_checksum(u8 value)
 {
@@ -429,37 +411,21 @@
 	return pn533_checksum(sum);
 }
 
-/**
- * pn533_tx_frame_ack - create a ack frame
- * @frame:	The frame to be set as ack
- *
- * Ack is different type of standard frame. As a standard frame, it has
- * preamble and start_frame. However the checksum of this frame must fail,
- * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test
- * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack.
- * After datalen_checksum field, the postamble is placed.
- */
-static void pn533_tx_frame_ack(struct pn533_frame *frame)
+static void pn533_tx_frame_init(void *_frame, u8 cmd_code)
 {
-	frame->preamble = 0;
-	frame->start_frame = cpu_to_be16(PN533_SOF);
-	frame->datalen = 0;
-	frame->datalen_checksum = 0xFF;
-	/* data[0] is used as postamble */
-	frame->data[0] = 0;
-}
+	struct pn533_frame *frame = _frame;
 
-static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd)
-{
 	frame->preamble = 0;
 	frame->start_frame = cpu_to_be16(PN533_SOF);
 	PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
-	PN533_FRAME_CMD(frame) = cmd;
+	PN533_FRAME_CMD(frame) = cmd_code;
 	frame->datalen = 2;
 }
 
-static void pn533_tx_frame_finish(struct pn533_frame *frame)
+static void pn533_tx_frame_finish(void *_frame)
 {
+	struct pn533_frame *frame = _frame;
+
 	frame->datalen_checksum = pn533_checksum(frame->datalen);
 
 	PN533_FRAME_CHECKSUM(frame) =
@@ -468,9 +434,17 @@
 	PN533_FRAME_POSTAMBLE(frame) = 0;
 }
 
-static bool pn533_rx_frame_is_valid(struct pn533_frame *frame)
+static void pn533_tx_update_payload_len(void *_frame, int len)
+{
+	struct pn533_frame *frame = _frame;
+
+	frame->datalen += len;
+}
+
+static bool pn533_rx_frame_is_valid(void *_frame)
 {
 	u8 checksum;
+	struct pn533_frame *frame = _frame;
 
 	if (frame->start_frame != cpu_to_be16(PN533_SOF))
 		return false;
@@ -497,28 +471,48 @@
 	return true;
 }
 
-static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
+static inline int pn533_rx_frame_size(void *frame)
 {
-	return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd));
+	struct pn533_frame *f = frame;
+
+	return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN;
+}
+
+static u8 pn533_get_cmd_code(void *frame)
+{
+	struct pn533_frame *f = frame;
+
+	return PN533_FRAME_CMD(f);
+}
+
+static struct pn533_frame_ops pn533_std_frame_ops = {
+	.tx_frame_init = pn533_tx_frame_init,
+	.tx_frame_finish = pn533_tx_frame_finish,
+	.tx_update_payload_len = pn533_tx_update_payload_len,
+	.tx_header_len = PN533_FRAME_HEADER_LEN,
+	.tx_tail_len = PN533_FRAME_TAIL_LEN,
+
+	.rx_is_frame_valid = pn533_rx_frame_is_valid,
+	.rx_frame_size = pn533_rx_frame_size,
+	.rx_header_len = PN533_FRAME_HEADER_LEN,
+	.rx_tail_len = PN533_FRAME_TAIL_LEN,
+
+	.max_payload_len =  PN533_FRAME_MAX_PAYLOAD_LEN,
+	.get_cmd_code = pn533_get_cmd_code,
+};
+
+static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
+{
+	return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd));
 }
 
 
 static void pn533_wq_cmd_complete(struct work_struct *work)
 {
 	struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
-	struct pn533_frame *in_frame;
 	int rc;
 
-	in_frame = dev->wq_in_frame;
-
-	if (dev->wq_in_error)
-		rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL,
-							dev->wq_in_error);
-	else
-		rc = dev->cmd_complete(dev, dev->cmd_complete_arg,
-					PN533_FRAME_CMD_PARAMS_PTR(in_frame),
-					PN533_FRAME_CMD_PARAMS_LEN(in_frame));
-
+	rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
 	if (rc != -EINPROGRESS)
 		queue_work(dev->wq, &dev->cmd_work);
 }
@@ -526,46 +520,46 @@
 static void pn533_recv_response(struct urb *urb)
 {
 	struct pn533 *dev = urb->context;
-	struct pn533_frame *in_frame;
-
-	dev->wq_in_frame = NULL;
+	u8 *in_frame;
 
 	switch (urb->status) {
 	case 0:
-		/* success */
-		break;
+		break; /* success */
 	case -ECONNRESET:
 	case -ENOENT:
-	case -ESHUTDOWN:
-		nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
-						" status: %d", urb->status);
+		nfc_dev_dbg(&dev->interface->dev,
+			    "The urb has been canceled (status %d)",
+			    urb->status);
 		dev->wq_in_error = urb->status;
 		goto sched_wq;
+	case -ESHUTDOWN:
 	default:
-		nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
-							" %d", urb->status);
+		nfc_dev_err(&dev->interface->dev,
+			    "Urb failure (status %d)", urb->status);
 		dev->wq_in_error = urb->status;
 		goto sched_wq;
 	}
 
 	in_frame = dev->in_urb->transfer_buffer;
 
-	if (!pn533_rx_frame_is_valid(in_frame)) {
+	nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
+	print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1,
+		       in_frame, dev->ops->rx_frame_size(in_frame), false);
+
+	if (!dev->ops->rx_is_frame_valid(in_frame)) {
 		nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
 		dev->wq_in_error = -EIO;
 		goto sched_wq;
 	}
 
-	if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) {
-		nfc_dev_err(&dev->interface->dev, "The received frame is not "
-						"response to the last command");
+	if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
+		nfc_dev_err(&dev->interface->dev,
+			    "It it not the response to the last command");
 		dev->wq_in_error = -EIO;
 		goto sched_wq;
 	}
 
-	nfc_dev_dbg(&dev->interface->dev, "Received a valid frame");
 	dev->wq_in_error = 0;
-	dev->wq_in_frame = in_frame;
 
 sched_wq:
 	queue_work(dev->wq, &dev->cmd_complete_work);
@@ -586,18 +580,18 @@
 
 	switch (urb->status) {
 	case 0:
-		/* success */
-		break;
+		break; /* success */
 	case -ECONNRESET:
 	case -ENOENT:
-	case -ESHUTDOWN:
-		nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
-						" status: %d", urb->status);
+		nfc_dev_dbg(&dev->interface->dev,
+			    "The urb has been stopped (status %d)",
+			    urb->status);
 		dev->wq_in_error = urb->status;
 		goto sched_wq;
+	case -ESHUTDOWN:
 	default:
-		nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
-							" %d", urb->status);
+		nfc_dev_err(&dev->interface->dev,
+			    "Urb failure (status %d)", urb->status);
 		dev->wq_in_error = urb->status;
 		goto sched_wq;
 	}
@@ -610,12 +604,10 @@
 		goto sched_wq;
 	}
 
-	nfc_dev_dbg(&dev->interface->dev, "Received a valid ack");
-
 	rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
 	if (rc) {
-		nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with"
-							" result %d", rc);
+		nfc_dev_err(&dev->interface->dev,
+			    "usb_submit_urb failed with result %d", rc);
 		dev->wq_in_error = rc;
 		goto sched_wq;
 	}
@@ -623,7 +615,6 @@
 	return;
 
 sched_wq:
-	dev->wq_in_frame = NULL;
 	queue_work(dev->wq, &dev->cmd_complete_work);
 }
 
@@ -636,47 +627,46 @@
 
 static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
 {
+	u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
+	/* spec 7.1.1.3:  Preamble, SoPC (2), ACK Code (2), Postamble */
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	pn533_tx_frame_ack(dev->out_frame);
-
-	dev->out_urb->transfer_buffer = dev->out_frame;
-	dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE;
+	dev->out_urb->transfer_buffer = ack;
+	dev->out_urb->transfer_buffer_length = sizeof(ack);
 	rc = usb_submit_urb(dev->out_urb, flags);
 
 	return rc;
 }
 
-static int __pn533_send_cmd_frame_async(struct pn533 *dev,
-					struct pn533_frame *out_frame,
-					struct pn533_frame *in_frame,
-					int in_frame_len,
+static int __pn533_send_frame_async(struct pn533 *dev,
+					struct sk_buff *out,
+					struct sk_buff *in,
+					int in_len,
 					pn533_cmd_complete_t cmd_complete,
-					void *arg, gfp_t flags)
+					void *arg)
 {
 	int rc;
 
-	nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x",
-						PN533_FRAME_CMD(out_frame));
-
-	dev->cmd = PN533_FRAME_CMD(out_frame);
+	dev->cmd = dev->ops->get_cmd_code(out->data);
 	dev->cmd_complete = cmd_complete;
 	dev->cmd_complete_arg = arg;
 
-	dev->out_urb->transfer_buffer = out_frame;
-	dev->out_urb->transfer_buffer_length =
-				PN533_FRAME_SIZE(out_frame);
+	dev->out_urb->transfer_buffer = out->data;
+	dev->out_urb->transfer_buffer_length = out->len;
 
-	dev->in_urb->transfer_buffer = in_frame;
-	dev->in_urb->transfer_buffer_length = in_frame_len;
+	dev->in_urb->transfer_buffer = in->data;
+	dev->in_urb->transfer_buffer_length = in_len;
 
-	rc = usb_submit_urb(dev->out_urb, flags);
+	print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
+		       out->data, out->len, false);
+
+	rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
 	if (rc)
 		return rc;
 
-	rc = pn533_submit_urb_for_ack(dev, flags);
+	rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
 	if (rc)
 		goto error;
 
@@ -687,6 +677,213 @@
 	return rc;
 }
 
+static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
+				  struct sk_buff *skb)
+{
+	/* payload is already there, just update datalen */
+	int payload_len = skb->len;
+	struct pn533_frame_ops *ops = dev->ops;
+
+
+	skb_push(skb, ops->tx_header_len);
+	skb_put(skb, ops->tx_tail_len);
+
+	ops->tx_frame_init(skb->data, cmd_code);
+	ops->tx_update_payload_len(skb->data, payload_len);
+	ops->tx_frame_finish(skb->data);
+}
+
+struct pn533_send_async_complete_arg {
+	pn533_send_async_complete_t  complete_cb;
+	void *complete_cb_context;
+	struct sk_buff *resp;
+	struct sk_buff *req;
+};
+
+static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status)
+{
+	struct pn533_send_async_complete_arg *arg = _arg;
+
+	struct sk_buff *req = arg->req;
+	struct sk_buff *resp = arg->resp;
+
+	int rc;
+
+	dev_kfree_skb(req);
+
+	if (status < 0) {
+		arg->complete_cb(dev, arg->complete_cb_context,
+				 ERR_PTR(status));
+		dev_kfree_skb(resp);
+		kfree(arg);
+		return status;
+	}
+
+	skb_put(resp, dev->ops->rx_frame_size(resp->data));
+	skb_pull(resp, dev->ops->rx_header_len);
+	skb_trim(resp, resp->len - dev->ops->rx_tail_len);
+
+	rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
+
+	kfree(arg);
+	return rc;
+}
+
+static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
+			      struct sk_buff *req, struct sk_buff *resp,
+			      int resp_len,
+			      pn533_send_async_complete_t complete_cb,
+			      void *complete_cb_context)
+{
+	struct pn533_cmd *cmd;
+	struct pn533_send_async_complete_arg *arg;
+	int rc = 0;
+
+	nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
+
+	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg)
+		return -ENOMEM;
+
+	arg->complete_cb = complete_cb;
+	arg->complete_cb_context = complete_cb_context;
+	arg->resp = resp;
+	arg->req = req;
+
+	pn533_build_cmd_frame(dev, cmd_code, req);
+
+	mutex_lock(&dev->cmd_lock);
+
+	if (!dev->cmd_pending) {
+		rc = __pn533_send_frame_async(dev, req, resp, resp_len,
+					      pn533_send_async_complete, arg);
+		if (rc)
+			goto error;
+
+		dev->cmd_pending = 1;
+		goto unlock;
+	}
+
+	nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__,
+		    cmd_code);
+
+	cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL);
+	if (!cmd) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	INIT_LIST_HEAD(&cmd->queue);
+	cmd->cmd_code = cmd_code;
+	cmd->req = req;
+	cmd->resp = resp;
+	cmd->resp_len = resp_len;
+	cmd->arg = arg;
+
+	list_add_tail(&cmd->queue, &dev->cmd_queue);
+
+	goto unlock;
+
+error:
+	kfree(arg);
+unlock:
+	mutex_unlock(&dev->cmd_lock);
+	return rc;
+}
+
+static int pn533_send_data_async(struct pn533 *dev, u8 cmd_code,
+				 struct sk_buff *req,
+				 pn533_send_async_complete_t complete_cb,
+				 void *complete_cb_context)
+{
+	struct sk_buff *resp;
+	int rc;
+	int  resp_len = dev->ops->rx_header_len +
+			dev->ops->max_payload_len +
+			dev->ops->rx_tail_len;
+
+	resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+				complete_cb_context);
+	if (rc)
+		dev_kfree_skb(resp);
+
+	return rc;
+}
+
+static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code,
+				struct sk_buff *req,
+				pn533_send_async_complete_t complete_cb,
+				void *complete_cb_context)
+{
+	struct sk_buff *resp;
+	int rc;
+	int  resp_len = dev->ops->rx_header_len +
+			dev->ops->max_payload_len +
+			dev->ops->rx_tail_len;
+
+	resp = alloc_skb(resp_len, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+				complete_cb_context);
+	if (rc)
+		dev_kfree_skb(resp);
+
+	return rc;
+}
+
+/*
+ * pn533_send_cmd_direct_async
+ *
+ * The function sends a piority cmd directly to the chip omiting the cmd
+ * queue. It's intended to be used by chaining mechanism of received responses
+ * where the host has to request every single chunk of data before scheduling
+ * next cmd from the queue.
+ */
+static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
+				       struct sk_buff *req,
+				       pn533_send_async_complete_t complete_cb,
+				       void *complete_cb_context)
+{
+	struct pn533_send_async_complete_arg *arg;
+	struct sk_buff *resp;
+	int rc;
+	int resp_len = dev->ops->rx_header_len +
+		       dev->ops->max_payload_len +
+		       dev->ops->rx_tail_len;
+
+	resp = alloc_skb(resp_len, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg) {
+		dev_kfree_skb(resp);
+		return -ENOMEM;
+	}
+
+	arg->complete_cb = complete_cb;
+	arg->complete_cb_context = complete_cb_context;
+	arg->resp = resp;
+	arg->req = req;
+
+	pn533_build_cmd_frame(dev, cmd_code, req);
+
+	rc = __pn533_send_frame_async(dev, req, resp, resp_len,
+				      pn533_send_async_complete, arg);
+	if (rc < 0) {
+		dev_kfree_skb(resp);
+		kfree(arg);
+	}
+
+	return rc;
+}
+
 static void pn533_wq_cmd(struct work_struct *work)
 {
 	struct pn533 *dev = container_of(work, struct pn533, cmd_work);
@@ -706,127 +903,99 @@
 
 	mutex_unlock(&dev->cmd_lock);
 
-	__pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame,
-				     cmd->in_frame_len, cmd->cmd_complete,
-				     cmd->arg, cmd->flags);
+	__pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
+				 pn533_send_async_complete, cmd->arg);
 
 	kfree(cmd);
 }
 
-static int pn533_send_cmd_frame_async(struct pn533 *dev,
-					struct pn533_frame *out_frame,
-					struct pn533_frame *in_frame,
-					int in_frame_len,
-					pn533_cmd_complete_t cmd_complete,
-					void *arg, gfp_t flags)
-{
-	struct pn533_cmd *cmd;
-	int rc = 0;
-
-	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
-	mutex_lock(&dev->cmd_lock);
-
-	if (!dev->cmd_pending) {
-		rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
-						  in_frame_len, cmd_complete,
-						  arg, flags);
-		if (!rc)
-			dev->cmd_pending = 1;
-
-		goto unlock;
-	}
-
-	nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__);
-
-	cmd = kzalloc(sizeof(struct pn533_cmd), flags);
-	if (!cmd) {
-		rc = -ENOMEM;
-		goto unlock;
-	}
-
-	INIT_LIST_HEAD(&cmd->queue);
-	cmd->out_frame = out_frame;
-	cmd->in_frame = in_frame;
-	cmd->in_frame_len = in_frame_len;
-	cmd->cmd_complete = cmd_complete;
-	cmd->arg = arg;
-	cmd->flags = flags;
-
-	list_add_tail(&cmd->queue, &dev->cmd_queue);
-
-unlock:
-	mutex_unlock(&dev->cmd_lock);
-
-	return rc;
-}
-
 struct pn533_sync_cmd_response {
-	int rc;
+	struct sk_buff *resp;
 	struct completion done;
 };
 
-static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg,
-					u8 *params, int params_len)
+static int pn533_send_sync_complete(struct pn533 *dev, void *_arg,
+				    struct sk_buff *resp)
 {
 	struct pn533_sync_cmd_response *arg = _arg;
 
-	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
-	arg->rc = 0;
-
-	if (params_len < 0) /* error */
-		arg->rc = params_len;
-
+	arg->resp = resp;
 	complete(&arg->done);
 
 	return 0;
 }
 
-static int pn533_send_cmd_frame_sync(struct pn533 *dev,
-						struct pn533_frame *out_frame,
-						struct pn533_frame *in_frame,
-						int in_frame_len)
+/*  pn533_send_cmd_sync
+ *
+ *  Please note the req parameter is freed inside the function to
+ *  limit a number of return value interpretations by the caller.
+ *
+ *  1. negative in case of error during TX path -> req should be freed
+ *
+ *  2. negative in case of error during RX path -> req should not be freed
+ *     as it's been already freed at the begining of RX path by
+ *     async_complete_cb.
+ *
+ *  3. valid pointer in case of succesfult RX path
+ *
+ *  A caller has to check a return value with IS_ERR macro. If the test pass,
+ *  the returned pointer is valid.
+ *
+ * */
+static struct sk_buff *pn533_send_cmd_sync(struct pn533 *dev, u8 cmd_code,
+					       struct sk_buff *req)
 {
 	int rc;
 	struct pn533_sync_cmd_response arg;
 
-	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
 	init_completion(&arg.done);
 
-	rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len,
-				pn533_sync_cmd_complete, &arg, GFP_KERNEL);
-	if (rc)
-		return rc;
+	rc = pn533_send_cmd_async(dev, cmd_code, req,
+				  pn533_send_sync_complete, &arg);
+	if (rc) {
+		dev_kfree_skb(req);
+		return ERR_PTR(rc);
+	}
 
 	wait_for_completion(&arg.done);
 
-	return arg.rc;
+	return arg.resp;
 }
 
 static void pn533_send_complete(struct urb *urb)
 {
 	struct pn533 *dev = urb->context;
 
-	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
 	switch (urb->status) {
 	case 0:
-		/* success */
-		break;
+		break; /* success */
 	case -ECONNRESET:
 	case -ENOENT:
-	case -ESHUTDOWN:
-		nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
-						" status: %d", urb->status);
+		nfc_dev_dbg(&dev->interface->dev,
+			    "The urb has been stopped (status %d)",
+			    urb->status);
 		break;
+	case -ESHUTDOWN:
 	default:
-		nfc_dev_dbg(&dev->interface->dev, "Nonzero urb status received:"
-							" %d", urb->status);
+		nfc_dev_err(&dev->interface->dev,
+			    "Urb failure (status %d)", urb->status);
 	}
 }
 
+static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(dev->ops->tx_header_len +
+			size +
+			dev->ops->tx_tail_len, GFP_KERNEL);
+
+	if (skb)
+		skb_reserve(skb, dev->ops->tx_header_len);
+
+	return skb;
+}
+
 struct pn533_target_type_a {
 	__be16 sens_res;
 	u8 sel_res;
@@ -867,9 +1036,9 @@
 	platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res);
 
 	if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-			platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
-			(ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-			platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+	     platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+	    (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+	     platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
 		return false;
 
 	/* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */
@@ -884,7 +1053,7 @@
 {
 	struct pn533_target_type_a *tgt_type_a;
 
-	tgt_type_a = (struct pn533_target_type_a *) tgt_data;
+	tgt_type_a = (struct pn533_target_type_a *)tgt_data;
 
 	if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len))
 		return -EPROTO;
@@ -942,14 +1111,13 @@
 {
 	struct pn533_target_felica *tgt_felica;
 
-	tgt_felica = (struct pn533_target_felica *) tgt_data;
+	tgt_felica = (struct pn533_target_felica *)tgt_data;
 
 	if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len))
 		return -EPROTO;
 
-	if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 &&
-					tgt_felica->nfcid2[1] ==
-					PN533_FELICA_SENSF_NFCID2_DEP_B2)
+	if ((tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1) &&
+	    (tgt_felica->nfcid2[1] == PN533_FELICA_SENSF_NFCID2_DEP_B2))
 		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
 	else
 		nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
@@ -979,9 +1147,9 @@
 	platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res);
 
 	if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-			platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
-			(ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
-			platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+	     platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+	    (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+	     platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
 		return false;
 
 	return true;
@@ -992,7 +1160,7 @@
 {
 	struct pn533_target_jewel *tgt_jewel;
 
-	tgt_jewel = (struct pn533_target_jewel *) tgt_data;
+	tgt_jewel = (struct pn533_target_jewel *)tgt_data;
 
 	if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len))
 		return -EPROTO;
@@ -1051,7 +1219,7 @@
 {
 	struct pn533_target_type_b *tgt_type_b;
 
-	tgt_type_b = (struct pn533_target_type_b *) tgt_data;
+	tgt_type_b = (struct pn533_target_type_b *)tgt_data;
 
 	if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len))
 		return -EPROTO;
@@ -1061,50 +1229,37 @@
 	return 0;
 }
 
-struct pn533_poll_response {
-	u8 nbtg;
-	u8 tg;
-	u8 target_data[];
-} __packed;
-
-static int pn533_target_found(struct pn533 *dev,
-			struct pn533_poll_response *resp, int resp_len)
+static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata,
+			      int tgdata_len)
 {
-	int target_data_len;
 	struct nfc_target nfc_tgt;
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s - modulation=%d", __func__,
-							dev->poll_mod_curr);
+		    dev->poll_mod_curr);
 
-	if (resp->tg != 1)
+	if (tg != 1)
 		return -EPROTO;
 
 	memset(&nfc_tgt, 0, sizeof(struct nfc_target));
 
-	target_data_len = resp_len - sizeof(struct pn533_poll_response);
-
 	switch (dev->poll_mod_curr) {
 	case PN533_POLL_MOD_106KBPS_A:
-		rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data,
-							target_data_len);
+		rc = pn533_target_found_type_a(&nfc_tgt, tgdata, tgdata_len);
 		break;
 	case PN533_POLL_MOD_212KBPS_FELICA:
 	case PN533_POLL_MOD_424KBPS_FELICA:
-		rc = pn533_target_found_felica(&nfc_tgt, resp->target_data,
-							target_data_len);
+		rc = pn533_target_found_felica(&nfc_tgt, tgdata, tgdata_len);
 		break;
 	case PN533_POLL_MOD_106KBPS_JEWEL:
-		rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data,
-							target_data_len);
+		rc = pn533_target_found_jewel(&nfc_tgt, tgdata, tgdata_len);
 		break;
 	case PN533_POLL_MOD_847KBPS_B:
-		rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data,
-							target_data_len);
+		rc = pn533_target_found_type_b(&nfc_tgt, tgdata, tgdata_len);
 		break;
 	default:
-		nfc_dev_err(&dev->interface->dev, "Unknown current poll"
-								" modulation");
+		nfc_dev_err(&dev->interface->dev,
+			    "Unknown current poll modulation");
 		return -EPROTO;
 	}
 
@@ -1112,13 +1267,14 @@
 		return rc;
 
 	if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) {
-		nfc_dev_dbg(&dev->interface->dev, "The target found does not"
-						" have the desired protocol");
+		nfc_dev_dbg(&dev->interface->dev,
+			    "The Tg found doesn't have the desired protocol");
 		return -EAGAIN;
 	}
 
-	nfc_dev_dbg(&dev->interface->dev, "Target found - supported protocols: "
-					"0x%x", nfc_tgt.supported_protocols);
+	nfc_dev_dbg(&dev->interface->dev,
+		    "Target found - supported protocols: 0x%x",
+		    nfc_tgt.supported_protocols);
 
 	dev->tgt_available_prots = nfc_tgt.supported_protocols;
 
@@ -1140,7 +1296,7 @@
 static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
 {
 	dev->poll_mod_active[dev->poll_mod_count] =
-		(struct pn533_poll_modulations *) &poll_mod[mod_index];
+		(struct pn533_poll_modulations *)&poll_mod[mod_index];
 	dev->poll_mod_count++;
 }
 
@@ -1149,13 +1305,13 @@
 {
 	pn533_poll_reset_mod_list(dev);
 
-	if (im_protocols & NFC_PROTO_MIFARE_MASK
-	    || im_protocols & NFC_PROTO_ISO14443_MASK
-	    || im_protocols & NFC_PROTO_NFC_DEP_MASK)
+	if ((im_protocols & NFC_PROTO_MIFARE_MASK) ||
+	    (im_protocols & NFC_PROTO_ISO14443_MASK) ||
+	    (im_protocols & NFC_PROTO_NFC_DEP_MASK))
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
 
-	if (im_protocols & NFC_PROTO_FELICA_MASK
-	    || im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+	if (im_protocols & NFC_PROTO_FELICA_MASK ||
+	    im_protocols & NFC_PROTO_NFC_DEP_MASK) {
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
 		pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
 	}
@@ -1170,16 +1326,20 @@
 		pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
 }
 
-static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)
+static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp)
 {
-	struct pn533_poll_response *resp;
-	int rc;
+	u8 nbtg, tg, *tgdata;
+	int rc, tgdata_len;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	resp = (struct pn533_poll_response *) params;
-	if (resp->nbtg) {
-		rc = pn533_target_found(dev, resp, params_len);
+	nbtg = resp->data[0];
+	tg = resp->data[1];
+	tgdata = &resp->data[2];
+	tgdata_len = resp->len - 2;  /* nbtg + tg */
+
+	if (nbtg) {
+		rc = pn533_target_found(dev, tg, tgdata, tgdata_len);
 
 		/* We must stop the poll after a valid target found */
 		if (rc == 0) {
@@ -1191,158 +1351,134 @@
 	return -EAGAIN;
 }
 
-static int pn533_init_target_frame(struct pn533_frame *frame,
-				   u8 *gb, size_t gb_len)
+static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev)
 {
-	struct pn533_cmd_init_target *cmd;
-	size_t cmd_len;
+	struct sk_buff *skb;
+	u8 *felica, *nfcid3, *gb;
+
+	u8 *gbytes = dev->gb;
+	size_t gbytes_len = dev->gb_len;
+
 	u8 felica_params[18] = {0x1, 0xfe, /* DEP */
 				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
 				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
 				0xff, 0xff}; /* System code */
+
 	u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
 			       0x0, 0x0, 0x0,
 			       0x40}; /* SEL_RES for DEP */
 
-	cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
-	cmd = kzalloc(cmd_len, GFP_KERNEL);
-	if (cmd == NULL)
-		return -ENOMEM;
+	unsigned int skb_len = 36 + /* mode (1), mifare (6),
+				       felica (18), nfcid3 (10), gb_len (1) */
+			       gbytes_len +
+			       1;  /* len Tk*/
 
-	pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+	skb = pn533_alloc_skb(dev, skb_len);
+	if (!skb)
+		return NULL;
 
 	/* DEP support only */
-	cmd->mode |= PN533_INIT_TARGET_DEP;
-
-	/* Felica params */
-	memcpy(cmd->felica, felica_params, 18);
-	get_random_bytes(cmd->felica + 2, 6);
-
-	/* NFCID3 */
-	memset(cmd->nfcid3, 0, 10);
-	memcpy(cmd->nfcid3, cmd->felica, 8);
+	*skb_put(skb, 1) = PN533_INIT_TARGET_DEP;
 
 	/* MIFARE params */
-	memcpy(cmd->mifare, mifare_params, 6);
+	memcpy(skb_put(skb, 6), mifare_params, 6);
+
+	/* Felica params */
+	felica = skb_put(skb, 18);
+	memcpy(felica, felica_params, 18);
+	get_random_bytes(felica + 2, 6);
+
+	/* NFCID3 */
+	nfcid3 = skb_put(skb, 10);
+	memset(nfcid3, 0, 10);
+	memcpy(nfcid3, felica, 8);
 
 	/* General bytes */
-	cmd->gb_len = gb_len;
-	memcpy(cmd->gb, gb, gb_len);
+	*skb_put(skb, 1) = gbytes_len;
+
+	gb = skb_put(skb, gbytes_len);
+	memcpy(gb, gbytes, gbytes_len);
 
 	/* Len Tk */
-	cmd->gb[gb_len] = 0;
+	*skb_put(skb, 1) = 0;
 
-	memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
-
-	frame->datalen += cmd_len;
-
-	pn533_tx_frame_finish(frame);
-
-	kfree(cmd);
-
-	return 0;
+	return skb;
 }
 
-#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_HEAD_LEN 1
 #define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
 static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
-				      u8 *params, int params_len)
+				      struct sk_buff *resp)
 {
-	struct sk_buff *skb_resp = arg;
-	struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
+	u8 status;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	if (params_len < 0) {
-		nfc_dev_err(&dev->interface->dev,
-			    "Error %d when starting as a target",
-			    params_len);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
 
-		return params_len;
-	}
+	status = resp->data[0];
+	skb_pull(resp, sizeof(status));
 
-	if (params_len > 0 && params[0] != 0) {
+	if (status != 0) {
 		nfc_tm_deactivated(dev->nfc_dev);
-
 		dev->tgt_mode = 0;
-
-		kfree_skb(skb_resp);
+		dev_kfree_skb(resp);
 		return 0;
 	}
 
-	skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
-	skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
-	skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
-
-	return nfc_tm_data_received(dev->nfc_dev, skb_resp);
+	return nfc_tm_data_received(dev->nfc_dev, resp);
 }
 
 static void pn533_wq_tg_get_data(struct work_struct *work)
 {
 	struct pn533 *dev = container_of(work, struct pn533, tg_work);
-	struct pn533_frame *in_frame;
-	struct sk_buff *skb_resp;
-	size_t skb_resp_len;
+
+	struct sk_buff *skb;
+	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
-		PN533_CMD_DATAEXCH_DATA_MAXLEN +
-		PN533_FRAME_TAIL_SIZE;
-
-	skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
-	if (!skb_resp)
+	skb = pn533_alloc_skb(dev, 0);
+	if (!skb)
 		return;
 
-	in_frame = (struct pn533_frame *)skb_resp->data;
+	rc = pn533_send_data_async(dev, PN533_CMD_TG_GET_DATA, skb,
+				   pn533_tm_get_data_complete, NULL);
 
-	pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
-	pn533_tx_frame_finish(dev->out_frame);
-
-	pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
-				   skb_resp_len,
-				   pn533_tm_get_data_complete,
-				   skb_resp, GFP_KERNEL);
+	if (rc < 0)
+		dev_kfree_skb(skb);
 
 	return;
 }
 
 #define ATR_REQ_GB_OFFSET 17
-static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)
+static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp)
 {
-	struct pn533_cmd_init_target_response *resp;
-	u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+	u8 mode, *cmd, comm_mode = NFC_COMM_PASSIVE, *gb;
 	size_t gb_len;
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	if (params_len < 0) {
-		nfc_dev_err(&dev->interface->dev,
-			    "Error %d when starting as a target",
-			    params_len);
-
-		return params_len;
-	}
-
-	if (params_len < ATR_REQ_GB_OFFSET + 1)
+	if (resp->len < ATR_REQ_GB_OFFSET + 1)
 		return -EINVAL;
 
-	resp = (struct pn533_cmd_init_target_response *) params;
+	mode = resp->data[0];
+	cmd = &resp->data[1];
 
-	nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
-		    resp->mode, params_len);
+	nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x len %d\n",
+		    mode, resp->len);
 
-	frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
-	if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+	if ((mode & PN533_INIT_TARGET_RESP_FRAME_MASK) ==
+	    PN533_INIT_TARGET_RESP_ACTIVE)
 		comm_mode = NFC_COMM_ACTIVE;
 
-	/* Again, only DEP */
-	if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+	if ((mode & PN533_INIT_TARGET_RESP_DEP) == 0)  /* Only DEP supported */
 		return -EOPNOTSUPP;
 
-	gb = resp->cmd + ATR_REQ_GB_OFFSET;
-	gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+	gb = cmd + ATR_REQ_GB_OFFSET;
+	gb_len = resp->len - (ATR_REQ_GB_OFFSET + 1);
 
 	rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
 			      comm_mode, gb, gb_len);
@@ -1353,7 +1489,6 @@
 	}
 
 	dev->tgt_mode = 1;
-
 	queue_work(dev->wq, &dev->tg_work);
 
 	return 0;
@@ -1361,7 +1496,7 @@
 
 static void pn533_listen_mode_timer(unsigned long data)
 {
-	struct pn533 *dev = (struct pn533 *) data;
+	struct pn533 *dev = (struct pn533 *)data;
 
 	nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
 
@@ -1376,88 +1511,104 @@
 }
 
 static int pn533_poll_complete(struct pn533 *dev, void *arg,
-			       u8 *params, int params_len)
+			       struct sk_buff *resp)
 {
 	struct pn533_poll_modulations *cur_mod;
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	if (params_len == -ENOENT) {
-		if (dev->poll_mod_count != 0)
-			return 0;
+	if (IS_ERR(resp)) {
+		rc = PTR_ERR(resp);
 
-		nfc_dev_err(&dev->interface->dev,
-			    "Polling operation has been stopped");
+		nfc_dev_err(&dev->interface->dev, "%s  Poll complete error %d",
+			    __func__, rc);
 
-		goto stop_poll;
-	}
-
-	if (params_len < 0) {
-		nfc_dev_err(&dev->interface->dev,
-			    "Error %d when running poll", params_len);
-
-		goto stop_poll;
+		if (rc == -ENOENT) {
+			if (dev->poll_mod_count != 0)
+				return rc;
+			else
+				goto stop_poll;
+		} else if (rc < 0) {
+			nfc_dev_err(&dev->interface->dev,
+				    "Error %d when running poll", rc);
+			goto stop_poll;
+		}
 	}
 
 	cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
 
-	if (cur_mod->len == 0) {
+	if (cur_mod->len == 0) { /* Target mode */
 		del_timer(&dev->listen_timer);
-
-		return pn533_init_target_complete(dev, params, params_len);
-	} else {
-		rc = pn533_start_poll_complete(dev, params, params_len);
-		if (!rc)
-			return rc;
+		rc = pn533_init_target_complete(dev, resp);
+		goto done;
 	}
 
+	/* Initiator mode */
+	rc = pn533_start_poll_complete(dev, resp);
+	if (!rc)
+		goto done;
+
 	pn533_poll_next_mod(dev);
-
 	queue_work(dev->wq, &dev->poll_work);
 
-	return 0;
+done:
+	dev_kfree_skb(resp);
+	return rc;
 
 stop_poll:
+	nfc_dev_err(&dev->interface->dev, "Polling operation has been stopped");
+
 	pn533_poll_reset_mod_list(dev);
 	dev->poll_protocols = 0;
-	return 0;
+	return rc;
 }
 
-static void pn533_build_poll_frame(struct pn533 *dev,
-				   struct pn533_frame *frame,
-				   struct pn533_poll_modulations *mod)
+static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev,
+					struct pn533_poll_modulations *mod)
 {
-	nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
+	struct sk_buff *skb;
 
-	if (mod->len == 0) {
-		/* Listen mode */
-		pn533_init_target_frame(frame, dev->gb, dev->gb_len);
-	} else {
-		/* Polling mode */
-		pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+	skb = pn533_alloc_skb(dev, mod->len);
+	if (!skb)
+		return NULL;
 
-		memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
-		frame->datalen += mod->len;
+	memcpy(skb_put(skb, mod->len), &mod->data, mod->len);
 
-		pn533_tx_frame_finish(frame);
-	}
+	return skb;
 }
 
 static int pn533_send_poll_frame(struct pn533 *dev)
 {
-	struct pn533_poll_modulations *cur_mod;
+	struct pn533_poll_modulations *mod;
+	struct sk_buff *skb;
 	int rc;
+	u8 cmd_code;
 
-	cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+	mod = dev->poll_mod_active[dev->poll_mod_curr];
 
-	pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
+	nfc_dev_dbg(&dev->interface->dev, "%s mod len %d\n",
+		    __func__, mod->len);
 
-	rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-				dev->in_maxlen,	pn533_poll_complete,
-				NULL, GFP_KERNEL);
-	if (rc)
+	if (mod->len == 0) {  /* Listen mode */
+		cmd_code = PN533_CMD_TG_INIT_AS_TARGET;
+		skb = pn533_alloc_poll_tg_frame(dev);
+	} else {  /* Polling mode */
+		cmd_code =  PN533_CMD_IN_LIST_PASSIVE_TARGET;
+		skb = pn533_alloc_poll_in_frame(dev, mod);
+	}
+
+	if (!skb) {
+		nfc_dev_err(&dev->interface->dev, "Failed to allocate skb.");
+		return -ENOMEM;
+	}
+
+	rc = pn533_send_cmd_async(dev, cmd_code, skb, pn533_poll_complete,
+				  NULL);
+	if (rc < 0) {
+		dev_kfree_skb(skb);
 		nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
+	}
 
 	return rc;
 }
@@ -1533,8 +1684,8 @@
 	del_timer(&dev->listen_timer);
 
 	if (!dev->poll_mod_count) {
-		nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
-								" running");
+		nfc_dev_dbg(&dev->interface->dev,
+			    "Polling operation was not running");
 		return;
 	}
 
@@ -1549,38 +1700,38 @@
 
 static int pn533_activate_target_nfcdep(struct pn533 *dev)
 {
-	struct pn533_cmd_activate_param param;
-	struct pn533_cmd_activate_response *resp;
+	struct pn533_cmd_activate_response *rsp;
 	u16 gt_len;
 	int rc;
 
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_ATR);
+	skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/
+	if (!skb)
+		return -ENOMEM;
 
-	param.tg = 1;
-	param.next = 0;
-	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &param,
-				sizeof(struct pn533_cmd_activate_param));
-	dev->out_frame->datalen += sizeof(struct pn533_cmd_activate_param);
+	*skb_put(skb, sizeof(u8)) = 1; /* TG */
+	*skb_put(skb, sizeof(u8)) = 0; /* Next */
 
-	pn533_tx_frame_finish(dev->out_frame);
+	resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
 
-	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-								dev->in_maxlen);
-	if (rc)
-		return rc;
-
-	resp = (struct pn533_cmd_activate_response *)
-				PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
-	rc = resp->status & PN533_CMD_RET_MASK;
-	if (rc != PN533_CMD_RET_SUCCESS)
+	rsp = (struct pn533_cmd_activate_response *)resp->data;
+	rc = rsp->status & PN533_CMD_RET_MASK;
+	if (rc != PN533_CMD_RET_SUCCESS) {
+		dev_kfree_skb(resp);
 		return -EIO;
+	}
 
 	/* ATR_RES general bytes are located at offset 16 */
-	gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 16;
-	rc = nfc_set_remote_general_bytes(dev->nfc_dev, resp->gt, gt_len);
+	gt_len = resp->len - 16;
+	rc = nfc_set_remote_general_bytes(dev->nfc_dev, rsp->gt, gt_len);
 
+	dev_kfree_skb(resp);
 	return rc;
 }
 
@@ -1591,38 +1742,38 @@
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s - protocol=%u", __func__,
-								protocol);
+		    protocol);
 
 	if (dev->poll_mod_count) {
-		nfc_dev_err(&dev->interface->dev, "Cannot activate while"
-								" polling");
+		nfc_dev_err(&dev->interface->dev,
+			    "Cannot activate while polling");
 		return -EBUSY;
 	}
 
 	if (dev->tgt_active_prot) {
-		nfc_dev_err(&dev->interface->dev, "There is already an active"
-								" target");
+		nfc_dev_err(&dev->interface->dev,
+			    "There is already an active target");
 		return -EBUSY;
 	}
 
 	if (!dev->tgt_available_prots) {
-		nfc_dev_err(&dev->interface->dev, "There is no available target"
-								" to activate");
+		nfc_dev_err(&dev->interface->dev,
+			    "There is no available target to activate");
 		return -EINVAL;
 	}
 
 	if (!(dev->tgt_available_prots & (1 << protocol))) {
-		nfc_dev_err(&dev->interface->dev, "The target does not support"
-					" the requested protocol %u", protocol);
+		nfc_dev_err(&dev->interface->dev,
+			    "Target doesn't support requested proto %u",
+			    protocol);
 		return -EINVAL;
 	}
 
 	if (protocol == NFC_PROTO_NFC_DEP) {
 		rc = pn533_activate_target_nfcdep(dev);
 		if (rc) {
-			nfc_dev_err(&dev->interface->dev, "Error %d when"
-						" activating target with"
-						" NFC_DEP protocol", rc);
+			nfc_dev_err(&dev->interface->dev,
+				    "Activating target with DEP failed %d", rc);
 			return rc;
 		}
 	}
@@ -1637,8 +1788,10 @@
 				    struct nfc_target *target)
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-	u8 tg;
-	u8 status;
+
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1649,83 +1802,69 @@
 	}
 
 	dev->tgt_active_prot = 0;
-
 	skb_queue_purge(&dev->resp_q);
 
-	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE);
-
-	tg = 1;
-	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &tg, sizeof(u8));
-	dev->out_frame->datalen += sizeof(u8);
-
-	pn533_tx_frame_finish(dev->out_frame);
-
-	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-								dev->in_maxlen);
-	if (rc) {
-		nfc_dev_err(&dev->interface->dev, "Error when sending release"
-						" command to the controller");
+	skb = pn533_alloc_skb(dev, sizeof(u8));
+	if (!skb)
 		return;
-	}
 
-	status = PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame)[0];
-	rc = status & PN533_CMD_RET_MASK;
+	*skb_put(skb, 1) = 1; /* TG*/
+
+	resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_RELEASE, skb);
+	if (IS_ERR(resp))
+		return;
+
+	rc = resp->data[0] & PN533_CMD_RET_MASK;
 	if (rc != PN533_CMD_RET_SUCCESS)
-		nfc_dev_err(&dev->interface->dev, "Error 0x%x when releasing"
-							" the target", rc);
+		nfc_dev_err(&dev->interface->dev,
+			    "Error 0x%x when releasing the target", rc);
 
+	dev_kfree_skb(resp);
 	return;
 }
 
 
 static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
-						u8 *params, int params_len)
+					 struct sk_buff *resp)
 {
-	struct pn533_cmd_jump_dep_response *resp;
-	struct nfc_target nfc_target;
+	struct pn533_cmd_jump_dep_response *rsp;
 	u8 target_gt_len;
 	int rc;
-	struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg;
-	u8 active = cmd->active;
+	u8 active = *(u8 *)arg;
 
 	kfree(arg);
 
-	if (params_len == -ENOENT) {
-		nfc_dev_dbg(&dev->interface->dev, "");
-		return 0;
-	}
-
-	if (params_len < 0) {
-		nfc_dev_err(&dev->interface->dev,
-				"Error %d when bringing DEP link up",
-								params_len);
-		return 0;
-	}
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
 
 	if (dev->tgt_available_prots &&
 	    !(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) {
 		nfc_dev_err(&dev->interface->dev,
-			"The target does not support DEP");
-		return -EINVAL;
+			    "The target does not support DEP");
+		rc =  -EINVAL;
+		goto error;
 	}
 
-	resp = (struct pn533_cmd_jump_dep_response *) params;
-	rc = resp->status & PN533_CMD_RET_MASK;
+	rsp = (struct pn533_cmd_jump_dep_response *)resp->data;
+
+	rc = rsp->status & PN533_CMD_RET_MASK;
 	if (rc != PN533_CMD_RET_SUCCESS) {
 		nfc_dev_err(&dev->interface->dev,
-				"Bringing DEP link up failed %d", rc);
-		return 0;
+			    "Bringing DEP link up failed %d", rc);
+		goto error;
 	}
 
 	if (!dev->tgt_available_prots) {
+		struct nfc_target nfc_target;
+
 		nfc_dev_dbg(&dev->interface->dev, "Creating new target");
 
 		nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
 		nfc_target.nfcid1_len = 10;
-		memcpy(nfc_target.nfcid1, resp->nfcid3t, nfc_target.nfcid1_len);
+		memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len);
 		rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1);
 		if (rc)
-			return 0;
+			goto error;
 
 		dev->tgt_available_prots = 0;
 	}
@@ -1733,15 +1872,17 @@
 	dev->tgt_active_prot = NFC_PROTO_NFC_DEP;
 
 	/* ATR_RES general bytes are located at offset 17 */
-	target_gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 17;
+	target_gt_len = resp->len - 17;
 	rc = nfc_set_remote_general_bytes(dev->nfc_dev,
-						resp->gt, target_gt_len);
+					  rsp->gt, target_gt_len);
 	if (rc == 0)
 		rc = nfc_dep_link_is_up(dev->nfc_dev,
-						dev->nfc_dev->targets[0].idx,
-						!active, NFC_RF_INITIATOR);
+					dev->nfc_dev->targets[0].idx,
+					!active, NFC_RF_INITIATOR);
 
-	return 0;
+error:
+	dev_kfree_skb(resp);
+	return rc;
 }
 
 static int pn533_mod_to_baud(struct pn533 *dev)
@@ -1760,25 +1901,26 @@
 
 #define PASSIVE_DATA_LEN 5
 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
-			     u8 comm_mode, u8* gb, size_t gb_len)
+			     u8 comm_mode, u8 *gb, size_t gb_len)
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-	struct pn533_cmd_jump_dep *cmd;
-	u8 cmd_len, *data_ptr;
+	struct sk_buff *skb;
+	int rc, baud, skb_len;
+	u8 *next, *arg;
+
 	u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
-	int rc, baud;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
 	if (dev->poll_mod_count) {
 		nfc_dev_err(&dev->interface->dev,
-				"Cannot bring the DEP link up while polling");
+			    "Cannot bring the DEP link up while polling");
 		return -EBUSY;
 	}
 
 	if (dev->tgt_active_prot) {
 		nfc_dev_err(&dev->interface->dev,
-				"There is already an active target");
+			    "There is already an active target");
 		return -EBUSY;
 	}
 
@@ -1789,43 +1931,48 @@
 		return baud;
 	}
 
-	cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
+	skb_len = 3 + gb_len; /* ActPass + BR + Next */
 	if (comm_mode == NFC_COMM_PASSIVE)
-		cmd_len += PASSIVE_DATA_LEN;
+		skb_len += PASSIVE_DATA_LEN;
 
-	cmd = kzalloc(cmd_len, GFP_KERNEL);
-	if (cmd == NULL)
+	skb = pn533_alloc_skb(dev, skb_len);
+	if (!skb)
 		return -ENOMEM;
 
-	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
+	*skb_put(skb, 1) = !comm_mode;  /* ActPass */
+	*skb_put(skb, 1) = baud;  /* Baud rate */
 
-	cmd->active = !comm_mode;
-	cmd->next = 0;
-	cmd->baud = baud;
-	data_ptr = cmd->data;
-	if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
-		memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
-		cmd->next |= 1;
-		data_ptr += PASSIVE_DATA_LEN;
+	next = skb_put(skb, 1);  /* Next */
+	*next = 0;
+
+	if (comm_mode == NFC_COMM_PASSIVE && baud > 0) {
+		memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data,
+		       PASSIVE_DATA_LEN);
+		*next |= 1;
 	}
 
 	if (gb != NULL && gb_len > 0) {
-		cmd->next |= 4; /* We have some Gi */
-		memcpy(data_ptr, gb, gb_len);
+		memcpy(skb_put(skb, gb_len), gb, gb_len);
+		*next |= 4; /* We have some Gi */
 	} else {
-		cmd->next = 0;
+		*next = 0;
 	}
 
-	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), cmd, cmd_len);
-	dev->out_frame->datalen += cmd_len;
+	arg = kmalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg) {
+		dev_kfree_skb(skb);
+		return -ENOMEM;
+	}
 
-	pn533_tx_frame_finish(dev->out_frame);
+	*arg = !comm_mode;
 
-	rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-				dev->in_maxlen,	pn533_in_dep_link_up_complete,
-				cmd, GFP_KERNEL);
-	if (rc < 0)
-		kfree(cmd);
+	rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb,
+				  pn533_in_dep_link_up_complete, arg);
+
+	if (rc < 0) {
+		dev_kfree_skb(skb);
+		kfree(arg);
+	}
 
 	return rc;
 }
@@ -1834,6 +1981,8 @@
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
 
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
 	pn533_poll_reset_mod_list(dev);
 
 	if (dev->tgt_mode || dev->tgt_active_prot) {
@@ -1849,68 +1998,7 @@
 	return 0;
 }
 
-static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
-				bool target)
-{
-	int payload_len = skb->len;
-	struct pn533_frame *out_frame;
-	u8 tg;
-
-	nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
-								payload_len);
-
-	if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
-		/* TODO: Implement support to multi-part data exchange */
-		nfc_dev_err(&dev->interface->dev, "Data length greater than the"
-						" max allowed: %d",
-						PN533_CMD_DATAEXCH_DATA_MAXLEN);
-		return -ENOSYS;
-	}
-
-	if (target == true) {
-		switch (dev->device_type) {
-		case PN533_DEVICE_PASORI:
-			if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
-				skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
-				out_frame = (struct pn533_frame *) skb->data;
-				pn533_tx_frame_init(out_frame,
-						    PN533_CMD_IN_COMM_THRU);
-
-				break;
-			}
-
-		default:
-			skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
-			out_frame = (struct pn533_frame *) skb->data;
-			pn533_tx_frame_init(out_frame,
-					    PN533_CMD_IN_DATA_EXCHANGE);
-			tg = 1;
-			memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame),
-			       &tg, sizeof(u8));
-			out_frame->datalen += sizeof(u8);
-
-			break;
-		}
-
-	} else {
-		skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
-		out_frame = (struct pn533_frame *) skb->data;
-		pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
-	}
-
-
-	/* The data is already in the out_frame, just update the datalen */
-	out_frame->datalen += payload_len;
-
-	pn533_tx_frame_finish(out_frame);
-	skb_put(skb, PN533_FRAME_TAIL_SIZE);
-
-	return 0;
-}
-
 struct pn533_data_exchange_arg {
-	struct sk_buff *skb_resp;
-	struct sk_buff *skb_out;
 	data_exchange_cb_t cb;
 	void *cb_context;
 };
@@ -1920,7 +2008,7 @@
 	struct sk_buff *skb, *tmp, *t;
 	unsigned int skb_len = 0, tmp_len = 0;
 
-	nfc_dev_dbg(&dev->interface->dev, "%s\n", __func__);
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
 	if (skb_queue_empty(&dev->resp_q))
 		return NULL;
@@ -1954,46 +2042,44 @@
 }
 
 static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
-						u8 *params, int params_len)
+					struct sk_buff *resp)
 {
 	struct pn533_data_exchange_arg *arg = _arg;
-	struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp;
-	struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
-	int err = 0;
-	u8 status;
-	u8 cmd_ret;
+	struct sk_buff *skb;
+	int rc = 0;
+	u8 status, ret, mi;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	dev_kfree_skb(arg->skb_out);
+	if (IS_ERR(resp)) {
+		rc = PTR_ERR(resp);
+		goto _error;
+	}
 
-	if (params_len < 0) { /* error */
-		err = params_len;
+	status = resp->data[0];
+	ret = status & PN533_CMD_RET_MASK;
+	mi = status & PN533_CMD_MI_MASK;
+
+	skb_pull(resp, sizeof(status));
+
+	if (ret != PN533_CMD_RET_SUCCESS) {
+		nfc_dev_err(&dev->interface->dev,
+			    "PN533 reported error %d when exchanging data",
+			    ret);
+		rc = -EIO;
 		goto error;
 	}
 
-	status = params[0];
+	skb_queue_tail(&dev->resp_q, resp);
 
-	cmd_ret = status & PN533_CMD_RET_MASK;
-	if (cmd_ret != PN533_CMD_RET_SUCCESS) {
-		nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when"
-						" exchanging data", cmd_ret);
-		err = -EIO;
-		goto error;
-	}
-
-	skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
-	skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
-	skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
-	skb_queue_tail(&dev->resp_q, skb_resp);
-
-	if (status & PN533_CMD_MI_MASK) {
+	if (mi) {
+		dev->cmd_complete_mi_arg = arg;
 		queue_work(dev->wq, &dev->mi_work);
 		return -EINPROGRESS;
 	}
 
 	skb = pn533_build_response(dev);
-	if (skb == NULL)
+	if (!skb)
 		goto error;
 
 	arg->cb(arg->cb_context, skb, 0);
@@ -2001,11 +2087,12 @@
 	return 0;
 
 error:
+	dev_kfree_skb(resp);
+_error:
 	skb_queue_purge(&dev->resp_q);
-	dev_kfree_skb(skb_resp);
-	arg->cb(arg->cb_context, NULL, err);
+	arg->cb(arg->cb_context, NULL, rc);
 	kfree(arg);
-	return 0;
+	return rc;
 }
 
 static int pn533_transceive(struct nfc_dev *nfc_dev,
@@ -2013,87 +2100,82 @@
 			    data_exchange_cb_t cb, void *cb_context)
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-	struct pn533_frame *out_frame, *in_frame;
-	struct pn533_data_exchange_arg *arg;
-	struct sk_buff *skb_resp;
-	int skb_resp_len;
+	struct pn533_data_exchange_arg *arg = NULL;
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
+	if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+		/* TODO: Implement support to multi-part data exchange */
+		nfc_dev_err(&dev->interface->dev,
+			    "Data length greater than the max allowed: %d",
+			    PN533_CMD_DATAEXCH_DATA_MAXLEN);
+		rc = -ENOSYS;
+		goto error;
+	}
+
 	if (!dev->tgt_active_prot) {
-		nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
-						" there is no active target");
+		nfc_dev_err(&dev->interface->dev,
+			    "Can't exchange data if there is no active target");
 		rc = -EINVAL;
 		goto error;
 	}
 
-	rc = pn533_build_tx_frame(dev, skb, true);
-	if (rc)
-		goto error;
-
-	skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
-			PN533_CMD_DATAEXCH_DATA_MAXLEN +
-			PN533_FRAME_TAIL_SIZE;
-
-	skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
-	if (!skb_resp) {
-		rc = -ENOMEM;
-		goto error;
-	}
-
-	in_frame = (struct pn533_frame *) skb_resp->data;
-	out_frame = (struct pn533_frame *) skb->data;
-
-	arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL);
+	arg = kmalloc(sizeof(*arg), GFP_KERNEL);
 	if (!arg) {
 		rc = -ENOMEM;
-		goto free_skb_resp;
+		goto error;
 	}
 
-	arg->skb_resp = skb_resp;
-	arg->skb_out = skb;
 	arg->cb = cb;
 	arg->cb_context = cb_context;
 
-	rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
-					pn533_data_exchange_complete, arg,
-					GFP_KERNEL);
-	if (rc) {
-		nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-						" perform data_exchange", rc);
-		goto free_arg;
+	switch (dev->device_type) {
+	case PN533_DEVICE_PASORI:
+		if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+			rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU,
+						   skb,
+						   pn533_data_exchange_complete,
+						   arg);
+
+			break;
+		}
+	default:
+		*skb_push(skb, sizeof(u8)) =  1; /*TG*/
+
+		rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE,
+					   skb, pn533_data_exchange_complete,
+					   arg);
+
+		break;
 	}
 
+	if (rc < 0) /* rc from send_async */
+		goto error;
+
 	return 0;
 
-free_arg:
-	kfree(arg);
-free_skb_resp:
-	kfree_skb(skb_resp);
 error:
-	kfree_skb(skb);
+	kfree(arg);
+	dev_kfree_skb(skb);
 	return rc;
 }
 
 static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
-				  u8 *params, int params_len)
+				  struct sk_buff *resp)
 {
-	struct sk_buff *skb_out = arg;
+	u8 status;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	dev_kfree_skb(skb_out);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
 
-	if (params_len < 0) {
-		nfc_dev_err(&dev->interface->dev,
-			    "Error %d when sending data",
-			    params_len);
+	status = resp->data[0];
 
-		return params_len;
-	}
+	dev_kfree_skb(resp);
 
-	if (params_len > 0 && params[0] != 0) {
+	if (status != 0) {
 		nfc_tm_deactivated(dev->nfc_dev);
 
 		dev->tgt_mode = 0;
@@ -2109,30 +2191,21 @@
 static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
 {
 	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-	struct pn533_frame *out_frame;
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	rc = pn533_build_tx_frame(dev, skb, false);
-	if (rc)
-		goto error;
-
-	out_frame = (struct pn533_frame *) skb->data;
-
-	rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
-					dev->in_maxlen, pn533_tm_send_complete,
-					skb, GFP_KERNEL);
-	if (rc) {
+	if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
 		nfc_dev_err(&dev->interface->dev,
-			    "Error %d when trying to send data", rc);
-		goto error;
+			    "Data length greater than the max allowed: %d",
+			    PN533_CMD_DATAEXCH_DATA_MAXLEN);
+		return -ENOSYS;
 	}
 
-	return 0;
-
-error:
-	kfree_skb(skb);
+	rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb,
+				   pn533_tm_send_complete, NULL);
+	if (rc < 0)
+		dev_kfree_skb(skb);
 
 	return rc;
 }
@@ -2140,107 +2213,123 @@
 static void pn533_wq_mi_recv(struct work_struct *work)
 {
 	struct pn533 *dev = container_of(work, struct pn533, mi_work);
-	struct sk_buff *skb_cmd;
-	struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg;
-	struct pn533_frame *out_frame, *in_frame;
-	struct sk_buff *skb_resp;
-	int skb_resp_len;
+
+	struct sk_buff *skb;
 	int rc;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	/* This is a zero payload size skb */
-	skb_cmd = alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN + PN533_FRAME_TAIL_SIZE,
-			    GFP_KERNEL);
-	if (skb_cmd == NULL)
-		goto error_cmd;
+	skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN);
+	if (!skb)
+		goto error;
 
-	skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
+	switch (dev->device_type) {
+	case PN533_DEVICE_PASORI:
+		if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+			rc = pn533_send_cmd_direct_async(dev,
+						PN533_CMD_IN_COMM_THRU,
+						skb,
+						pn533_data_exchange_complete,
+						 dev->cmd_complete_mi_arg);
 
-	rc = pn533_build_tx_frame(dev, skb_cmd, true);
-	if (rc)
-		goto error_frame;
+			break;
+		}
+	default:
+		*skb_put(skb, sizeof(u8)) =  1; /*TG*/
 
-	skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
-			PN533_CMD_DATAEXCH_DATA_MAXLEN +
-			PN533_FRAME_TAIL_SIZE;
-	skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL);
-	if (!skb_resp) {
-		rc = -ENOMEM;
-		goto error_frame;
+		rc = pn533_send_cmd_direct_async(dev,
+						 PN533_CMD_IN_DATA_EXCHANGE,
+						 skb,
+						 pn533_data_exchange_complete,
+						 dev->cmd_complete_mi_arg);
+
+		break;
 	}
 
-	in_frame = (struct pn533_frame *) skb_resp->data;
-	out_frame = (struct pn533_frame *) skb_cmd->data;
-
-	arg->skb_resp = skb_resp;
-	arg->skb_out = skb_cmd;
-
-	rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
-					  skb_resp_len,
-					  pn533_data_exchange_complete,
-					  dev->cmd_complete_arg, GFP_KERNEL);
-	if (!rc)
+	if (rc == 0) /* success */
 		return;
 
-	nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-						" perform data_exchange", rc);
+	nfc_dev_err(&dev->interface->dev,
+		    "Error %d when trying to perform data_exchange", rc);
 
-	kfree_skb(skb_resp);
+	dev_kfree_skb(skb);
+	kfree(dev->cmd_complete_arg);
 
-error_frame:
-	kfree_skb(skb_cmd);
-
-error_cmd:
+error:
 	pn533_send_ack(dev, GFP_KERNEL);
-
-	kfree(arg);
-
 	queue_work(dev->wq, &dev->cmd_work);
 }
 
 static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
 								u8 cfgdata_len)
 {
-	int rc;
-	u8 *params;
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	int skb_len;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	pn533_tx_frame_init(dev->out_frame, PN533_CMD_RF_CONFIGURATION);
+	skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */
 
-	params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
-	params[0] = cfgitem;
-	memcpy(&params[1], cfgdata, cfgdata_len);
-	dev->out_frame->datalen += (1 + cfgdata_len);
+	skb = pn533_alloc_skb(dev, skb_len);
+	if (!skb)
+		return -ENOMEM;
 
-	pn533_tx_frame_finish(dev->out_frame);
+	*skb_put(skb, sizeof(cfgitem)) = cfgitem;
+	memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len);
 
-	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-								dev->in_maxlen);
+	resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
 
-	return rc;
+	dev_kfree_skb(resp);
+	return 0;
+}
+
+static int pn533_get_firmware_version(struct pn533 *dev,
+				      struct pn533_fw_version *fv)
+{
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	skb = pn533_alloc_skb(dev, 0);
+	if (!skb)
+		return -ENOMEM;
+
+	resp = pn533_send_cmd_sync(dev, PN533_CMD_GET_FIRMWARE_VERSION, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	fv->ic = resp->data[0];
+	fv->ver = resp->data[1];
+	fv->rev = resp->data[2];
+	fv->support = resp->data[3];
+
+	dev_kfree_skb(resp);
+	return 0;
 }
 
 static int pn533_fw_reset(struct pn533 *dev)
 {
-	int rc;
-	u8 *params;
+	struct sk_buff *skb;
+	struct sk_buff *resp;
 
 	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-	pn533_tx_frame_init(dev->out_frame, 0x18);
+	skb = pn533_alloc_skb(dev, sizeof(u8));
+	if (!skb)
+		return -ENOMEM;
 
-	params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
-	params[0] = 0x1;
-	dev->out_frame->datalen += 1;
+	*skb_put(skb, sizeof(u8)) = 0x1;
 
-	pn533_tx_frame_finish(dev->out_frame);
+	resp = pn533_send_cmd_sync(dev, 0x18, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
 
-	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-				       dev->in_maxlen);
+	dev_kfree_skb(resp);
 
-	return rc;
+	return 0;
 }
 
 static struct nfc_ops pn533_nfc_ops = {
@@ -2337,7 +2426,7 @@
 static int pn533_probe(struct usb_interface *interface,
 			const struct usb_device_id *id)
 {
-	struct pn533_fw_version *fw_ver;
+	struct pn533_fw_version fw_ver;
 	struct pn533 *dev;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
@@ -2359,41 +2448,32 @@
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
 
-		if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
-			dev->in_maxlen = le16_to_cpu(endpoint->wMaxPacketSize);
+		if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint))
 			in_endpoint = endpoint->bEndpointAddress;
-		}
 
-		if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) {
-			dev->out_maxlen =
-				le16_to_cpu(endpoint->wMaxPacketSize);
+		if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint))
 			out_endpoint = endpoint->bEndpointAddress;
-		}
 	}
 
 	if (!in_endpoint || !out_endpoint) {
-		nfc_dev_err(&interface->dev, "Could not find bulk-in or"
-							" bulk-out endpoint");
+		nfc_dev_err(&interface->dev,
+			    "Could not find bulk-in or bulk-out endpoint");
 		rc = -ENODEV;
 		goto error;
 	}
 
-	dev->in_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
 	dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
-	dev->out_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
 	dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
 
-	if (!dev->in_frame || !dev->out_frame ||
-		!dev->in_urb || !dev->out_urb)
+	if (!dev->in_urb || !dev->out_urb)
 		goto error;
 
 	usb_fill_bulk_urb(dev->in_urb, dev->udev,
-			usb_rcvbulkpipe(dev->udev, in_endpoint),
-			NULL, 0, NULL, dev);
+			  usb_rcvbulkpipe(dev->udev, in_endpoint),
+			  NULL, 0, NULL, dev);
 	usb_fill_bulk_urb(dev->out_urb, dev->udev,
-			usb_sndbulkpipe(dev->udev, out_endpoint),
-			NULL, 0,
-			pn533_send_complete, dev);
+			  usb_sndbulkpipe(dev->udev, out_endpoint),
+			  NULL, 0, pn533_send_complete, dev);
 
 	INIT_WORK(&dev->cmd_work, pn533_wq_cmd);
 	INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete);
@@ -2414,18 +2494,7 @@
 
 	usb_set_intfdata(interface, dev);
 
-	pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
-	pn533_tx_frame_finish(dev->out_frame);
-
-	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
-								dev->in_maxlen);
-	if (rc)
-		goto destroy_wq;
-
-	fw_ver = (struct pn533_fw_version *)
-				PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
-	nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now"
-					" attached", fw_ver->ver, fw_ver->rev);
+	dev->ops = &pn533_std_frame_ops;
 
 	dev->device_type = id->driver_info;
 	switch (dev->device_type) {
@@ -2444,9 +2513,21 @@
 		goto destroy_wq;
 	}
 
+	memset(&fw_ver, 0, sizeof(fw_ver));
+	rc = pn533_get_firmware_version(dev, &fw_ver);
+	if (rc < 0)
+		goto destroy_wq;
+
+	nfc_dev_info(&dev->interface->dev,
+		     "NXP PN533 firmware ver %d.%d now attached",
+		     fw_ver.ver, fw_ver.rev);
+
+
 	dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
+					   NFC_SE_NONE,
+					   dev->ops->tx_header_len +
 					   PN533_CMD_DATAEXCH_HEAD_LEN,
-					   PN533_FRAME_TAIL_SIZE);
+					   dev->ops->tx_tail_len);
 	if (!dev->nfc_dev)
 		goto destroy_wq;
 
@@ -2472,9 +2553,7 @@
 destroy_wq:
 	destroy_workqueue(dev->wq);
 error:
-	kfree(dev->in_frame);
 	usb_free_urb(dev->in_urb);
-	kfree(dev->out_frame);
 	usb_free_urb(dev->out_urb);
 	kfree(dev);
 	return rc;
@@ -2505,9 +2584,7 @@
 		kfree(cmd);
 	}
 
-	kfree(dev->in_frame);
 	usb_free_urb(dev->in_urb);
-	kfree(dev->out_frame);
 	usb_free_urb(dev->out_urb);
 	kfree(dev);
 
diff --git a/drivers/nfc/pn544/Kconfig b/drivers/nfc/pn544/Kconfig
new file mode 100644
index 0000000..c277790
--- /dev/null
+++ b/drivers/nfc/pn544/Kconfig
@@ -0,0 +1,23 @@
+config NFC_PN544
+	tristate "NXP PN544 NFC driver"
+	depends on NFC_HCI
+	select CRC_CCITT
+	default n
+	---help---
+	  NXP PN544 core driver.
+	  This is a driver based on the HCI NFC kernel layers and
+	  will thus not work with NXP libnfc library.
+
+	  To compile this driver as a module, choose m here. The module will
+	  be called pn544.
+	  Say N if unsure.
+
+config NFC_PN544_I2C
+	tristate "NFC PN544 i2c support"
+	depends on NFC_PN544 && I2C && NFC_SHDLC
+	---help---
+	  This module adds support for the NXP pn544 i2c interface.
+	  Select this if your platform is using the i2c bus.
+
+	  If you choose to build a module, it'll be called pn544_i2c.
+	  Say N if unsure.
\ No newline at end of file
diff --git a/drivers/nfc/pn544/Makefile b/drivers/nfc/pn544/Makefile
index 7257338..ac07679 100644
--- a/drivers/nfc/pn544/Makefile
+++ b/drivers/nfc/pn544/Makefile
@@ -2,6 +2,7 @@
 # Makefile for PN544 HCI based NFC driver
 #
 
-obj-$(CONFIG_PN544_HCI_NFC)	+= pn544_i2c.o
+pn544_i2c-objs  = i2c.o
 
-pn544_i2c-y		:= pn544.o i2c.o
+obj-$(CONFIG_NFC_PN544)     += pn544.o
+obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index 2a9c8d9..8cf64c1 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -376,12 +376,12 @@
 		return -ENODEV;
 	}
 
-	phy = kzalloc(sizeof(struct pn544_i2c_phy), GFP_KERNEL);
+	phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
+			   GFP_KERNEL);
 	if (!phy) {
 		dev_err(&client->dev,
 			"Cannot allocate memory for pn544 i2c phy.\n");
-		r = -ENOMEM;
-		goto err_phy_alloc;
+		return -ENOMEM;
 	}
 
 	phy->i2c_dev = client;
@@ -390,20 +390,18 @@
 	pdata = client->dev.platform_data;
 	if (pdata == NULL) {
 		dev_err(&client->dev, "No platform data\n");
-		r = -EINVAL;
-		goto err_pdata;
+		return -EINVAL;
 	}
 
 	if (pdata->request_resources == NULL) {
 		dev_err(&client->dev, "request_resources() missing\n");
-		r = -EINVAL;
-		goto err_pdata;
+		return -EINVAL;
 	}
 
 	r = pdata->request_resources(client);
 	if (r) {
 		dev_err(&client->dev, "Cannot get platform resources\n");
-		goto err_pdata;
+		return r;
 	}
 
 	phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
@@ -435,10 +433,6 @@
 	if (pdata->free_resources != NULL)
 		pdata->free_resources();
 
-err_pdata:
-	kfree(phy);
-
-err_phy_alloc:
 	return r;
 }
 
@@ -458,8 +452,6 @@
 	if (pdata->free_resources)
 		pdata->free_resources();
 
-	kfree(phy);
-
 	return 0;
 }
 
@@ -472,29 +464,7 @@
 	.remove = pn544_hci_i2c_remove,
 };
 
-static int __init pn544_hci_i2c_init(void)
-{
-	int r;
-
-	pr_debug(DRIVER_DESC ": %s\n", __func__);
-
-	r = i2c_add_driver(&pn544_hci_i2c_driver);
-	if (r) {
-		pr_err(PN544_HCI_I2C_DRIVER_NAME
-		       ": driver registration failed\n");
-		return r;
-	}
-
-	return 0;
-}
-
-static void __exit pn544_hci_i2c_exit(void)
-{
-	i2c_del_driver(&pn544_hci_i2c_driver);
-}
-
-module_init(pn544_hci_i2c_init);
-module_exit(pn544_hci_i2c_exit);
+module_i2c_driver(pn544_hci_i2c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index cc666de..9c5f16e 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -20,6 +20,7 @@
 
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include <linux/nfc.h>
 #include <net/nfc/hci.h>
@@ -675,11 +676,17 @@
 
 static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
 {
+	int r;
+
 	/* Set default false for multiple information chaining */
 	*skb_push(skb, 1) = 0;
 
-	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
-				PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+	r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+			       PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+
+	kfree_skb(skb);
+
+	return r;
 }
 
 static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
@@ -714,35 +721,40 @@
 	return 0;
 }
 
-static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
-					u8 event, struct sk_buff *skb)
+/*
+ * Returns:
+ * <= 0: driver handled the event, skb consumed
+ *    1: driver does not handle the event, please do standard processing
+ */
+static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+				    struct sk_buff *skb)
 {
 	struct sk_buff *rgb_skb = NULL;
-	int r = 0;
+	int r;
 
 	pr_debug("hci event %d", event);
 	switch (event) {
 	case PN544_HCI_EVT_ACTIVATED:
-		if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
-			nfc_hci_target_discovered(hdev, gate);
-		else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
+		if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
+			r = nfc_hci_target_discovered(hdev, gate);
+		} else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
 			r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
-						&rgb_skb);
-
+					      &rgb_skb);
 			if (r < 0)
 				goto exit;
 
-			nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
-					NFC_COMM_PASSIVE, rgb_skb->data,
-					rgb_skb->len);
+			r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+					     NFC_COMM_PASSIVE, rgb_skb->data,
+					     rgb_skb->len);
 
 			kfree_skb(rgb_skb);
+		} else {
+			r = -EINVAL;
 		}
-
 		break;
 	case PN544_HCI_EVT_DEACTIVATED:
-		nfc_hci_send_event(hdev, gate,
-			NFC_HCI_EVT_END_OPERATION, NULL, 0);
+		r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
+				       NULL, 0);
 		break;
 	case PN544_HCI_EVT_RCV_DATA:
 		if (skb->len < 2) {
@@ -757,15 +769,15 @@
 		}
 
 		skb_pull(skb, 2);
-		nfc_tm_data_received(hdev->ndev, skb);
-
-		return;
+		return nfc_tm_data_received(hdev->ndev, skb);
 	default:
-		break;
+		return 1;
 	}
 
 exit:
 	kfree_skb(skb);
+
+	return r;
 }
 
 static struct nfc_hci_ops pn544_hci_ops = {
@@ -789,7 +801,7 @@
 		    struct nfc_hci_dev **hdev)
 {
 	struct pn544_hci_info *info;
-	u32 protocols;
+	u32 protocols, se;
 	struct nfc_hci_init_data init_data;
 	int r;
 
@@ -822,8 +834,10 @@
 		    NFC_PROTO_ISO14443_B_MASK |
 		    NFC_PROTO_NFC_DEP_MASK;
 
-	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
-					     protocols, llc_name,
+	se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
+	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
+					     protocols, se, llc_name,
 					     phy_headroom + PN544_CMDS_HEADROOM,
 					     phy_tailroom, phy_payload);
 	if (!info->hdev) {
@@ -851,6 +865,7 @@
 err_info_alloc:
 	return r;
 }
+EXPORT_SYMBOL(pn544_hci_probe);
 
 void pn544_hci_remove(struct nfc_hci_dev *hdev)
 {
@@ -860,3 +875,7 @@
 	nfc_hci_free_device(hdev);
 	kfree(info);
 }
+EXPORT_SYMBOL(pn544_hci_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 2390ddb..321d3ef 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -24,38 +24,21 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 
-/**
- * struct alias_prop - Alias property in 'aliases' node
- * @link:	List node to link the structure in aliases_lookup list
- * @alias:	Alias property name
- * @np:		Pointer to device_node that the alias stands for
- * @id:		Index value from end of alias name
- * @stem:	Alias string without the index
- *
- * The structure represents one alias property of 'aliases' node as
- * an entry in aliases_lookup list.
- */
-struct alias_prop {
-	struct list_head link;
-	const char *alias;
-	struct device_node *np;
-	int id;
-	char stem[0];
-};
+#include "of_private.h"
 
-static LIST_HEAD(aliases_lookup);
+LIST_HEAD(aliases_lookup);
 
 struct device_node *of_allnodes;
 EXPORT_SYMBOL(of_allnodes);
 struct device_node *of_chosen;
 struct device_node *of_aliases;
 
-static DEFINE_MUTEX(of_aliases_mutex);
+DEFINE_MUTEX(of_aliases_mutex);
 
 /* use when traversing tree through the allnext, child, sibling,
  * or parent members of struct device_node.
  */
-DEFINE_RWLOCK(devtree_lock);
+DEFINE_RAW_SPINLOCK(devtree_lock);
 
 int of_n_addr_cells(struct device_node *np)
 {
@@ -164,16 +147,14 @@
 EXPORT_SYMBOL(of_node_put);
 #endif /* CONFIG_OF_DYNAMIC */
 
-struct property *of_find_property(const struct device_node *np,
-				  const char *name,
-				  int *lenp)
+static struct property *__of_find_property(const struct device_node *np,
+					   const char *name, int *lenp)
 {
 	struct property *pp;
 
 	if (!np)
 		return NULL;
 
-	read_lock(&devtree_lock);
 	for (pp = np->properties; pp; pp = pp->next) {
 		if (of_prop_cmp(pp->name, name) == 0) {
 			if (lenp)
@@ -181,7 +162,20 @@
 			break;
 		}
 	}
-	read_unlock(&devtree_lock);
+
+	return pp;
+}
+
+struct property *of_find_property(const struct device_node *np,
+				  const char *name,
+				  int *lenp)
+{
+	struct property *pp;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+	pp = __of_find_property(np, name, lenp);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 	return pp;
 }
@@ -199,13 +193,13 @@
 {
 	struct device_node *np;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock(&devtree_lock);
 	np = prev ? prev->allnext : of_allnodes;
 	for (; np != NULL; np = np->allnext)
 		if (of_node_get(np))
 			break;
 	of_node_put(prev);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock(&devtree_lock);
 	return np;
 }
 EXPORT_SYMBOL(of_find_all_nodes);
@@ -214,8 +208,20 @@
  * Find a property with a given name for a given node
  * and return the value.
  */
+static const void *__of_get_property(const struct device_node *np,
+				     const char *name, int *lenp)
+{
+	struct property *pp = __of_find_property(np, name, lenp);
+
+	return pp ? pp->value : NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
 const void *of_get_property(const struct device_node *np, const char *name,
-			 int *lenp)
+			    int *lenp)
 {
 	struct property *pp = of_find_property(np, name, lenp);
 
@@ -226,13 +232,13 @@
 /** Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
-int of_device_is_compatible(const struct device_node *device,
-		const char *compat)
+static int __of_device_is_compatible(const struct device_node *device,
+				     const char *compat)
 {
 	const char* cp;
 	int cplen, l;
 
-	cp = of_get_property(device, "compatible", &cplen);
+	cp = __of_get_property(device, "compatible", &cplen);
 	if (cp == NULL)
 		return 0;
 	while (cplen > 0) {
@@ -245,6 +251,21 @@
 
 	return 0;
 }
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+		const char *compat)
+{
+	unsigned long flags;
+	int res;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+	res = __of_device_is_compatible(device, compat);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
+	return res;
+}
 EXPORT_SYMBOL(of_device_is_compatible);
 
 /**
@@ -269,19 +290,19 @@
 EXPORT_SYMBOL(of_machine_is_compatible);
 
 /**
- *  of_device_is_available - check if a device is available for use
+ *  __of_device_is_available - check if a device is available for use
  *
- *  @device: Node to check for availability
+ *  @device: Node to check for availability, with locks already held
  *
  *  Returns 1 if the status property is absent or set to "okay" or "ok",
  *  0 otherwise
  */
-int of_device_is_available(const struct device_node *device)
+static int __of_device_is_available(const struct device_node *device)
 {
 	const char *status;
 	int statlen;
 
-	status = of_get_property(device, "status", &statlen);
+	status = __of_get_property(device, "status", &statlen);
 	if (status == NULL)
 		return 1;
 
@@ -292,6 +313,26 @@
 
 	return 0;
 }
+
+/**
+ *  of_device_is_available - check if a device is available for use
+ *
+ *  @device: Node to check for availability
+ *
+ *  Returns 1 if the status property is absent or set to "okay" or "ok",
+ *  0 otherwise
+ */
+int of_device_is_available(const struct device_node *device)
+{
+	unsigned long flags;
+	int res;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+	res = __of_device_is_available(device);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
+	return res;
+
+}
 EXPORT_SYMBOL(of_device_is_available);
 
 /**
@@ -304,13 +345,14 @@
 struct device_node *of_get_parent(const struct device_node *node)
 {
 	struct device_node *np;
+	unsigned long flags;
 
 	if (!node)
 		return NULL;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np = of_node_get(node->parent);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_get_parent);
@@ -329,14 +371,15 @@
 struct device_node *of_get_next_parent(struct device_node *node)
 {
 	struct device_node *parent;
+	unsigned long flags;
 
 	if (!node)
 		return NULL;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	parent = of_node_get(node->parent);
 	of_node_put(node);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return parent;
 }
 
@@ -352,14 +395,15 @@
 	struct device_node *prev)
 {
 	struct device_node *next;
+	unsigned long flags;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	next = prev ? prev->sibling : node->child;
 	for (; next; next = next->sibling)
 		if (of_node_get(next))
 			break;
 	of_node_put(prev);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return next;
 }
 EXPORT_SYMBOL(of_get_next_child);
@@ -377,16 +421,16 @@
 {
 	struct device_node *next;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock(&devtree_lock);
 	next = prev ? prev->sibling : node->child;
 	for (; next; next = next->sibling) {
-		if (!of_device_is_available(next))
+		if (!__of_device_is_available(next))
 			continue;
 		if (of_node_get(next))
 			break;
 	}
 	of_node_put(prev);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock(&devtree_lock);
 	return next;
 }
 EXPORT_SYMBOL(of_get_next_available_child);
@@ -424,14 +468,15 @@
 struct device_node *of_find_node_by_path(const char *path)
 {
 	struct device_node *np = of_allnodes;
+	unsigned long flags;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	for (; np; np = np->allnext) {
 		if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
 		    && of_node_get(np))
 			break;
 	}
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_find_node_by_path);
@@ -451,15 +496,16 @@
 	const char *name)
 {
 	struct device_node *np;
+	unsigned long flags;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np = from ? from->allnext : of_allnodes;
 	for (; np; np = np->allnext)
 		if (np->name && (of_node_cmp(np->name, name) == 0)
 		    && of_node_get(np))
 			break;
 	of_node_put(from);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_find_node_by_name);
@@ -480,15 +526,16 @@
 	const char *type)
 {
 	struct device_node *np;
+	unsigned long flags;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np = from ? from->allnext : of_allnodes;
 	for (; np; np = np->allnext)
 		if (np->type && (of_node_cmp(np->type, type) == 0)
 		    && of_node_get(np))
 			break;
 	of_node_put(from);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_find_node_by_type);
@@ -511,18 +558,20 @@
 	const char *type, const char *compatible)
 {
 	struct device_node *np;
+	unsigned long flags;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np = from ? from->allnext : of_allnodes;
 	for (; np; np = np->allnext) {
 		if (type
 		    && !(np->type && (of_node_cmp(np->type, type) == 0)))
 			continue;
-		if (of_device_is_compatible(np, compatible) && of_node_get(np))
+		if (__of_device_is_compatible(np, compatible) &&
+		    of_node_get(np))
 			break;
 	}
 	of_node_put(from);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_find_compatible_node);
@@ -544,8 +593,9 @@
 {
 	struct device_node *np;
 	struct property *pp;
+	unsigned long flags;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np = from ? from->allnext : of_allnodes;
 	for (; np; np = np->allnext) {
 		for (pp = np->properties; pp; pp = pp->next) {
@@ -557,20 +607,14 @@
 	}
 out:
 	of_node_put(from);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_find_node_with_property);
 
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- *	@matches:	array of of device match structures to search in
- *	@node:		the of device structure to match against
- *
- *	Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
-					 const struct device_node *node)
+static
+const struct of_device_id *__of_match_node(const struct of_device_id *matches,
+					   const struct device_node *node)
 {
 	if (!matches)
 		return NULL;
@@ -584,14 +628,33 @@
 			match &= node->type
 				&& !strcmp(matches->type, node->type);
 		if (matches->compatible[0])
-			match &= of_device_is_compatible(node,
-						matches->compatible);
+			match &= __of_device_is_compatible(node,
+							   matches->compatible);
 		if (match)
 			return matches;
 		matches++;
 	}
 	return NULL;
 }
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ *	@matches:	array of of device match structures to search in
+ *	@node:		the of device structure to match against
+ *
+ *	Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+					 const struct device_node *node)
+{
+	const struct of_device_id *match;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&devtree_lock, flags);
+	match = __of_match_node(matches, node);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
+	return match;
+}
 EXPORT_SYMBOL(of_match_node);
 
 /**
@@ -612,21 +675,24 @@
 					const struct of_device_id **match)
 {
 	struct device_node *np;
+	const struct of_device_id *m;
+	unsigned long flags;
 
 	if (match)
 		*match = NULL;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np = from ? from->allnext : of_allnodes;
 	for (; np; np = np->allnext) {
-		if (of_match_node(matches, np) && of_node_get(np)) {
+		m = __of_match_node(matches, np);
+		if (m && of_node_get(np)) {
 			if (match)
-				*match = matches;
+				*match = m;
 			break;
 		}
 	}
 	of_node_put(from);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
 }
 EXPORT_SYMBOL(of_find_matching_node_and_match);
@@ -669,12 +735,12 @@
 {
 	struct device_node *np;
 
-	read_lock(&devtree_lock);
+	raw_spin_lock(&devtree_lock);
 	for (np = of_allnodes; np; np = np->allnext)
 		if (np->phandle == handle)
 			break;
 	of_node_get(np);
-	read_unlock(&devtree_lock);
+	raw_spin_unlock(&devtree_lock);
 	return np;
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
@@ -1025,12 +1091,13 @@
  * To get a device_node of the `node2' node you may call this:
  * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
  */
-int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
-				const char *cells_name, int index,
-				struct of_phandle_args *out_args)
+static int __of_parse_phandle_with_args(const struct device_node *np,
+					const char *list_name,
+					const char *cells_name, int index,
+					struct of_phandle_args *out_args)
 {
 	const __be32 *list, *list_end;
-	int size, cur_index = 0;
+	int rc = 0, size, cur_index = 0;
 	uint32_t count = 0;
 	struct device_node *node = NULL;
 	phandle phandle;
@@ -1043,6 +1110,7 @@
 
 	/* Loop over the phandles until all the requested entry is found */
 	while (list < list_end) {
+		rc = -EINVAL;
 		count = 0;
 
 		/*
@@ -1059,13 +1127,13 @@
 			if (!node) {
 				pr_err("%s: could not find phandle\n",
 					 np->full_name);
-				break;
+				goto err;
 			}
 			if (of_property_read_u32(node, cells_name, &count)) {
 				pr_err("%s: could not get %s for %s\n",
 					 np->full_name, cells_name,
 					 node->full_name);
-				break;
+				goto err;
 			}
 
 			/*
@@ -1075,7 +1143,7 @@
 			if (list + count > list_end) {
 				pr_err("%s: arguments longer than property\n",
 					 np->full_name);
-				break;
+				goto err;
 			}
 		}
 
@@ -1085,9 +1153,10 @@
 		 * index matches, then fill the out_args structure and return,
 		 * or return -ENOENT for an empty entry.
 		 */
+		rc = -ENOENT;
 		if (cur_index == index) {
 			if (!phandle)
-				return -ENOENT;
+				goto err;
 
 			if (out_args) {
 				int i;
@@ -1098,6 +1167,10 @@
 				for (i = 0; i < count; i++)
 					out_args->args[i] = be32_to_cpup(list++);
 			}
+
+			/* Found it! return success */
+			if (node)
+				of_node_put(node);
 			return 0;
 		}
 
@@ -1107,13 +1180,51 @@
 		cur_index++;
 	}
 
-	/* Loop exited without finding a valid entry; return an error */
+	/*
+	 * Unlock node before returning result; will be one of:
+	 * -ENOENT : index is for empty phandle
+	 * -EINVAL : parsing error on data
+	 * [1..n]  : Number of phandle (count mode; when index = -1)
+	 */
+	rc = index < 0 ? cur_index : -ENOENT;
+ err:
 	if (node)
 		of_node_put(node);
-	return -EINVAL;
+	return rc;
+}
+
+int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
+				const char *cells_name, int index,
+				struct of_phandle_args *out_args)
+{
+	if (index < 0)
+		return -EINVAL;
+	return __of_parse_phandle_with_args(np, list_name, cells_name, index, out_args);
 }
 EXPORT_SYMBOL(of_parse_phandle_with_args);
 
+/**
+ * of_count_phandle_with_args() - Find the number of phandles references in a property
+ * @np:		pointer to a device tree node containing a list
+ * @list_name:	property name that contains a list
+ * @cells_name:	property name that specifies phandles' arguments count
+ *
+ * Returns the number of phandle + argument tuples within a property. It
+ * is a typical pattern to encode a list of phandle and variable
+ * arguments into a single property. The number of arguments is encoded
+ * by a property in the phandle-target node. For example, a gpios
+ * property would contain a list of GPIO specifies consisting of a
+ * phandle and 1 or more arguments. The number of arguments are
+ * determined by the #gpio-cells property in the node pointed to by the
+ * phandle.
+ */
+int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
+				const char *cells_name)
+{
+	return __of_parse_phandle_with_args(np, list_name, cells_name, -1, NULL);
+}
+EXPORT_SYMBOL(of_count_phandle_with_args);
+
 #if defined(CONFIG_OF_DYNAMIC)
 static int of_property_notify(int action, struct device_node *np,
 			      struct property *prop)
@@ -1146,18 +1257,18 @@
 		return rc;
 
 	prop->next = NULL;
-	write_lock_irqsave(&devtree_lock, flags);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	next = &np->properties;
 	while (*next) {
 		if (strcmp(prop->name, (*next)->name) == 0) {
 			/* duplicate ! don't insert it */
-			write_unlock_irqrestore(&devtree_lock, flags);
+			raw_spin_unlock_irqrestore(&devtree_lock, flags);
 			return -1;
 		}
 		next = &(*next)->next;
 	}
 	*next = prop;
-	write_unlock_irqrestore(&devtree_lock, flags);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 #ifdef CONFIG_PROC_DEVICETREE
 	/* try to add to proc as well if it was initialized */
@@ -1187,7 +1298,7 @@
 	if (rc)
 		return rc;
 
-	write_lock_irqsave(&devtree_lock, flags);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	next = &np->properties;
 	while (*next) {
 		if (*next == prop) {
@@ -1200,7 +1311,7 @@
 		}
 		next = &(*next)->next;
 	}
-	write_unlock_irqrestore(&devtree_lock, flags);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 	if (!found)
 		return -ENODEV;
@@ -1240,7 +1351,7 @@
 	if (!oldprop)
 		return of_add_property(np, newprop);
 
-	write_lock_irqsave(&devtree_lock, flags);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	next = &np->properties;
 	while (*next) {
 		if (*next == oldprop) {
@@ -1254,7 +1365,7 @@
 		}
 		next = &(*next)->next;
 	}
-	write_unlock_irqrestore(&devtree_lock, flags);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 	if (!found)
 		return -ENODEV;
@@ -1327,12 +1438,12 @@
 	if (rc)
 		return rc;
 
-	write_lock_irqsave(&devtree_lock, flags);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 	np->sibling = np->parent->child;
 	np->allnext = of_allnodes;
 	np->parent->child = np;
 	of_allnodes = np;
-	write_unlock_irqrestore(&devtree_lock, flags);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 	of_add_proc_dt_entry(np);
 	return 0;
@@ -1375,17 +1486,17 @@
 	if (rc)
 		return rc;
 
-	write_lock_irqsave(&devtree_lock, flags);
+	raw_spin_lock_irqsave(&devtree_lock, flags);
 
 	if (of_node_check_flag(np, OF_DETACHED)) {
 		/* someone already detached it */
-		write_unlock_irqrestore(&devtree_lock, flags);
+		raw_spin_unlock_irqrestore(&devtree_lock, flags);
 		return rc;
 	}
 
 	parent = np->parent;
 	if (!parent) {
-		write_unlock_irqrestore(&devtree_lock, flags);
+		raw_spin_unlock_irqrestore(&devtree_lock, flags);
 		return rc;
 	}
 
@@ -1412,7 +1523,7 @@
 	}
 
 	of_node_set_flag(np, OF_DETACHED);
-	write_unlock_irqrestore(&devtree_lock, flags);
+	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 	of_remove_proc_dt_entry(np);
 	return rc;
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 4c74e4f..f685e55 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -8,6 +8,7 @@
 #include <linux/slab.h>
 
 #include <asm/errno.h>
+#include "of_private.h"
 
 /**
  * of_match_device - Tell if a struct device matches an of_device_id list
@@ -131,6 +132,7 @@
 void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	const char *compat;
+	struct alias_prop *app;
 	int seen = 0, cplen, sl;
 
 	if ((!dev) || (!dev->of_node))
@@ -153,6 +155,17 @@
 		seen++;
 	}
 	add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
+
+	seen = 0;
+	mutex_lock(&of_aliases_mutex);
+	list_for_each_entry(app, &aliases_lookup, link) {
+		if (dev->of_node == app->np) {
+			add_uevent_var(env, "OF_ALIAS_%d=%s", seen,
+				       app->alias);
+			seen++;
+		}
+	}
+	mutex_unlock(&of_aliases_mutex);
 }
 
 int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 83ca06f..e3a8b22 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -157,7 +157,7 @@
 	if (!phy)
 		return NULL;
 
-	return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
+	return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy;
 }
 EXPORT_SYMBOL(of_phy_connect);
 
@@ -194,7 +194,7 @@
 
 	sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
 
-	phy = phy_connect(dev, bus_id, hndlr, 0, iface);
+	phy = phy_connect(dev, bus_id, hndlr, iface);
 	return IS_ERR(phy) ? NULL : phy;
 }
 EXPORT_SYMBOL(of_phy_connect_fixed_link);
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
new file mode 100644
index 0000000..ff350c8
--- /dev/null
+++ b/drivers/of/of_private.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_OF_PRIVATE_H
+#define _LINUX_OF_PRIVATE_H
+/*
+ * Private symbols used by OF support code
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link:	List node to link the structure in aliases_lookup list
+ * @alias:	Alias property name
+ * @np:		Pointer to device_node that the alias stands for
+ * @id:		Index value from end of alias name
+ * @stem:	Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+	struct list_head link;
+	const char *alias;
+	struct device_node *np;
+	int id;
+	char stem[0];
+};
+
+extern struct mutex of_aliases_mutex;
+extern struct list_head aliases_lookup;
+#endif /* _LINUX_OF_PRIVATE_H */
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index f24ffd7..0eb5c38 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -2,7 +2,7 @@
  * Self tests for device tree subsystem
  */
 
-#define pr_fmt(fmt) "### %s(): " fmt, __func__
+#define pr_fmt(fmt) "### dt-test ### " fmt
 
 #include <linux/clk.h>
 #include <linux/err.h>
@@ -16,26 +16,30 @@
 
 static bool selftest_passed = true;
 #define selftest(result, fmt, ...) { \
-	selftest_passed &= (result); \
-	if (!(result)) \
+	if (!(result)) { \
 		pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
+		selftest_passed = false; \
+	} else { \
+		pr_info("pass %s:%i\n", __FILE__, __LINE__); \
+	} \
 }
 
 static void __init of_selftest_parse_phandle_with_args(void)
 {
 	struct device_node *np;
 	struct of_phandle_args args;
-	int rc, i;
-	bool passed_all = true;
+	int i, rc;
 
-	pr_info("start\n");
 	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
 	if (!np) {
 		pr_err("missing testcase data\n");
 		return;
 	}
 
-	for (i = 0; i < 7; i++) {
+	rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
+	selftest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
+
+	for (i = 0; i < 8; i++) {
 		bool passed = true;
 		rc = of_parse_phandle_with_args(np, "phandle-list",
 						"#phandle-cells", i, &args);
@@ -79,45 +83,47 @@
 			passed &= (args.args[0] == (i + 1));
 			break;
 		case 7:
-			passed &= (rc == -EINVAL);
+			passed &= (rc == -ENOENT);
 			break;
 		default:
 			passed = false;
 		}
 
-		if (!passed) {
-			int j;
-			pr_err("index %i - data error on node %s rc=%i regs=[",
-				i, args.np->full_name, rc);
-			for (j = 0; j < args.args_count; j++)
-				printk(" %i", args.args[j]);
-			printk(" ]\n");
-
-			passed_all = false;
-		}
+		selftest(passed, "index %i - data error on node %s rc=%i\n",
+			 i, args.np->full_name, rc);
 	}
 
 	/* Check for missing list property */
 	rc = of_parse_phandle_with_args(np, "phandle-list-missing",
 					"#phandle-cells", 0, &args);
-	passed_all &= (rc == -EINVAL);
+	selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+	rc = of_count_phandle_with_args(np, "phandle-list-missing",
+					"#phandle-cells");
+	selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
 
 	/* Check for missing cells property */
 	rc = of_parse_phandle_with_args(np, "phandle-list",
 					"#phandle-cells-missing", 0, &args);
-	passed_all &= (rc == -EINVAL);
+	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+	rc = of_count_phandle_with_args(np, "phandle-list",
+					"#phandle-cells-missing");
+	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
 	/* Check for bad phandle in list */
 	rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
 					"#phandle-cells", 0, &args);
-	passed_all &= (rc == -EINVAL);
+	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+	rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
+					"#phandle-cells");
+	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
 	/* Check for incorrectly formed argument list */
 	rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
 					"#phandle-cells", 1, &args);
-	passed_all &= (rc == -EINVAL);
-
-	pr_info("end - %s\n", passed_all ? "PASS" : "FAIL");
+	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+	rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
+					"#phandle-cells");
+	selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 }
 
 static void __init of_selftest_property_match_string(void)
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 3d6d4fd..a951c22 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -734,34 +734,24 @@
  */
 static int acpiphp_bus_add(struct acpiphp_func *func)
 {
-	acpi_handle phandle;
-	struct acpi_device *device, *pdevice;
+	struct acpi_device *device;
 	int ret_val;
 
-	acpi_get_parent(func->handle, &phandle);
-	if (acpi_bus_get_device(phandle, &pdevice)) {
-		dbg("no parent device, assuming NULL\n");
-		pdevice = NULL;
-	}
 	if (!acpi_bus_get_device(func->handle, &device)) {
 		dbg("bus exists... trim\n");
 		/* this shouldn't be in here, so remove
 		 * the bus then re-add it...
 		 */
-		ret_val = acpi_bus_trim(device, 1);
-		dbg("acpi_bus_trim return %x\n", ret_val);
+		acpi_bus_trim(device);
 	}
 
-	ret_val = acpi_bus_add(&device, pdevice, func->handle,
-		ACPI_BUS_TYPE_DEVICE);
-	if (ret_val) {
-		dbg("error adding bus, %x\n",
-			-ret_val);
-		goto acpiphp_bus_add_out;
-	}
-	ret_val = acpi_bus_start(device);
+	ret_val = acpi_bus_scan(func->handle);
+	if (!ret_val)
+		ret_val = acpi_bus_get_device(func->handle, &device);
 
-acpiphp_bus_add_out:
+	if (ret_val)
+		dbg("error adding bus, %x\n", -ret_val);
+
 	return ret_val;
 }
 
@@ -781,11 +771,8 @@
 		return retval;
 	}
 
-	retval = acpi_bus_trim(device, 1);
-	if (retval)
-		err("cannot remove from acpi list\n");
-
-	return retval;
+	acpi_bus_trim(device);
+	return 0;
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -1130,8 +1117,7 @@
 
 static void handle_bridge_insertion(acpi_handle handle, u32 type)
 {
-	struct acpi_device *device, *pdevice;
-	acpi_handle phandle;
+	struct acpi_device *device;
 
 	if ((type != ACPI_NOTIFY_BUS_CHECK) &&
 			(type != ACPI_NOTIFY_DEVICE_CHECK)) {
@@ -1139,17 +1125,15 @@
 		return;
 	}
 
-	acpi_get_parent(handle, &phandle);
-	if (acpi_bus_get_device(phandle, &pdevice)) {
-		dbg("no parent device, assuming NULL\n");
-		pdevice = NULL;
-	}
-	if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
+	if (acpi_bus_scan(handle)) {
 		err("cannot add bridge to acpi list\n");
 		return;
 	}
-	if (!acpiphp_configure_bridge(handle) &&
-		!acpi_bus_start(device))
+	if (acpi_bus_get_device(handle, &device)) {
+		err("ACPI device object missing\n");
+		return;
+	}
+	if (!acpiphp_configure_bridge(handle))
 		add_bridge(handle);
 	else
 		err("cannot configure and start bridge\n");
@@ -1234,6 +1218,8 @@
 	handle = hp_work->handle;
 	type = hp_work->type;
 
+	acpi_scan_lock_acquire();
+
 	if (acpi_bus_get_device(handle, &device)) {
 		/* This bridge must have just been physically inserted */
 		handle_bridge_insertion(handle, type);
@@ -1311,6 +1297,7 @@
 	}
 
 out:
+	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
 }
 
@@ -1357,6 +1344,8 @@
 
 	func = (struct acpiphp_func *)context;
 
+	acpi_scan_lock_acquire();
+
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
@@ -1387,6 +1376,7 @@
 		break;
 	}
 
+	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event_func */
 }
 
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index f64ca92..574421b 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -412,7 +412,6 @@
 	if (SN_ACPI_BASE_SUPPORT() && ssdt) {
 		unsigned long long adr;
 		struct acpi_device *pdevice;
-		struct acpi_device *device;
 		acpi_handle phandle;
 		acpi_handle chandle = NULL;
 		acpi_handle rethandle;
@@ -426,6 +425,7 @@
 			pdevice = NULL;
 		}
 
+		acpi_scan_lock_acquire();
 		/*
 		 * Walk the rootbus node's immediate children looking for
 		 * the slot's device node(s). There can be more than
@@ -448,20 +448,18 @@
 			if (ACPI_SUCCESS(ret) &&
 			    (adr>>16) == (slot->device_num + 1)) {
 
-				ret = acpi_bus_add(&device, pdevice, chandle,
-						   ACPI_BUS_TYPE_DEVICE);
+				ret = acpi_bus_scan(chandle);
 				if (ACPI_FAILURE(ret)) {
-					printk(KERN_ERR "%s: acpi_bus_add "
+					printk(KERN_ERR "%s: acpi_bus_scan "
 					       "failed (0x%x) for slot %d "
 					       "func %d\n", __func__,
 					       ret, (int)(adr>>16),
 					       (int)(adr&0xffff));
 					/* try to continue on */
-				} else {
-					acpi_bus_start(device);
 				}
 			}
 		}
+		acpi_scan_lock_release();
 	}
 
 	/* Call the driver for the new device */
@@ -512,6 +510,7 @@
 		/* Get the rootbus node pointer */
 		phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
 
+		acpi_scan_lock_acquire();
 		/*
 		 * Walk the rootbus node's immediate children looking for
 		 * the slot's device node(s). There can be more than
@@ -539,10 +538,10 @@
 				ret = acpi_bus_get_device(chandle,
 							  &device);
 				if (ACPI_SUCCESS(ret))
-					acpi_bus_trim(device, 1);
+					acpi_bus_trim(device);
 			}
 		}
-
+		acpi_scan_lock_release();
 	}
 
 	/* Free the SN resources assigned to the Linux device.*/
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 5099636..00cc78c7 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -845,6 +845,32 @@
 }
 EXPORT_SYMBOL(pci_enable_msi_block);
 
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
+{
+	int ret, pos, nvec;
+	u16 msgctl;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	if (!pos)
+		return -EINVAL;
+
+	pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+	ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
+
+	if (maxvec)
+		*maxvec = ret;
+
+	do {
+		nvec = ret;
+		ret = pci_enable_msi_block(dev, nvec);
+	} while (ret > 0);
+
+	if (ret < 0)
+		return ret;
+	return nvec;
+}
+EXPORT_SYMBOL(pci_enable_msi_block_auto);
+
 void pci_msi_shutdown(struct pci_dev *dev)
 {
 	struct msi_desc *desc;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 1af4008..e407c61 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -283,7 +283,6 @@
 	.is_manageable = acpi_pci_power_manageable,
 	.set_state = acpi_pci_set_power_state,
 	.choose_state = acpi_pci_choose_state,
-	.can_wakeup = acpi_pci_can_wakeup,
 	.sleep_wake = acpi_pci_sleep_wake,
 	.run_wake = acpi_pci_run_wake,
 };
@@ -321,10 +320,65 @@
 	return 0;
 }
 
+static void pci_acpi_setup(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	acpi_handle handle = ACPI_HANDLE(dev);
+	struct acpi_device *adev;
+	acpi_status status;
+	acpi_handle dummy;
+
+	/*
+	 * Evaluate and parse _PRT, if exists.  This code allows parsing of
+	 * _PRT objects within the scope of non-bridge devices.  Note that
+	 * _PRTs within the scope of a PCI bridge assume the bridge's
+	 * subordinate bus number.
+	 *
+	 * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
+	 */
+	status = acpi_get_handle(handle, METHOD_NAME__PRT, &dummy);
+	if (ACPI_SUCCESS(status)) {
+		unsigned char bus;
+
+		bus = pci_dev->subordinate ?
+			pci_dev->subordinate->number : pci_dev->bus->number;
+		acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus);
+	}
+
+	if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid)
+		return;
+
+	device_set_wakeup_capable(dev, true);
+	acpi_pci_sleep_wake(pci_dev, false);
+
+	pci_acpi_add_pm_notifier(adev, pci_dev);
+	if (adev->wakeup.flags.run_wake)
+		device_set_run_wake(dev, true);
+}
+
+static void pci_acpi_cleanup(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	acpi_handle handle = ACPI_HANDLE(dev);
+	struct acpi_device *adev;
+
+	if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) {
+		device_set_wakeup_capable(dev, false);
+		device_set_run_wake(dev, false);
+		pci_acpi_remove_pm_notifier(adev);
+	}
+
+	if (pci_dev->subordinate)
+		acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus),
+				     pci_dev->subordinate->number);
+}
+
 static struct acpi_bus_type acpi_pci_bus = {
 	.bus = &pci_bus_type,
 	.find_device = acpi_pci_find_device,
 	.find_bridge = acpi_pci_find_root_bridge,
+	.setup = pci_acpi_setup,
+	.cleanup = pci_acpi_cleanup,
 };
 
 static int __init acpi_pci_init(void)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5cb5820..0c4f641 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -450,7 +450,7 @@
 int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
 {
 	if (!ops->is_manageable || !ops->set_state || !ops->choose_state
-	    || !ops->sleep_wake || !ops->can_wakeup)
+	    || !ops->sleep_wake)
 		return -EINVAL;
 	pci_platform_pm = ops;
 	return 0;
@@ -473,11 +473,6 @@
 			pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
 }
 
-static inline bool platform_pci_can_wakeup(struct pci_dev *dev)
-{
-	return pci_platform_pm ? pci_platform_pm->can_wakeup(dev) : false;
-}
-
 static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
 {
 	return pci_platform_pm ?
@@ -1985,25 +1980,6 @@
 	}
 }
 
-/**
- * platform_pci_wakeup_init - init platform wakeup if present
- * @dev: PCI device
- *
- * Some devices don't have PCI PM caps but can still generate wakeup
- * events through platform methods (like ACPI events).  If @dev supports
- * platform wakeup events, set the device flag to indicate as much.  This
- * may be redundant if the device also supports PCI PM caps, but double
- * initialization should be safe in that case.
- */
-void platform_pci_wakeup_init(struct pci_dev *dev)
-{
-	if (!platform_pci_can_wakeup(dev))
-		return;
-
-	device_set_wakeup_capable(&dev->dev, true);
-	platform_pci_sleep_wake(dev, false);
-}
-
 static void pci_add_saved_cap(struct pci_dev *pci_dev,
 	struct pci_cap_saved_state *new_cap)
 {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index e851829..adfd172 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -43,9 +43,6 @@
  *                platform; to be used during system-wide transitions from a
  *                sleeping state to the working state and vice versa
  *
- * @can_wakeup: returns 'true' if given device is capable of waking up the
- *              system from a sleeping state
- *
  * @sleep_wake: enables/disables the system wake up capability of given device
  *
  * @run_wake: enables/disables the platform to generate run-time wake-up events
@@ -59,7 +56,6 @@
 	bool (*is_manageable)(struct pci_dev *dev);
 	int (*set_state)(struct pci_dev *dev, pci_power_t state);
 	pci_power_t (*choose_state)(struct pci_dev *dev);
-	bool (*can_wakeup)(struct pci_dev *dev);
 	int (*sleep_wake)(struct pci_dev *dev, bool enable);
 	int (*run_wake)(struct pci_dev *dev, bool enable);
 };
@@ -74,7 +70,6 @@
 extern void pci_config_pm_runtime_get(struct pci_dev *dev);
 extern void pci_config_pm_runtime_put(struct pci_dev *dev);
 extern void pci_pm_init(struct pci_dev *dev);
-extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
 void pci_free_cap_save_buffers(struct pci_dev *dev);
 
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
index 3ea5173..5ab1425 100644
--- a/drivers/pci/pcie/aer/aerdrv_errprint.c
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -23,6 +23,9 @@
 
 #include "aerdrv.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/ras.h>
+
 #define AER_AGENT_RECEIVER		0
 #define AER_AGENT_REQUESTER		1
 #define AER_AGENT_COMPLETER		2
@@ -121,12 +124,11 @@
 	"Transmitter ID"
 };
 
-static void __aer_print_error(const char *prefix,
+static void __aer_print_error(struct pci_dev *dev,
 			      struct aer_err_info *info)
 {
 	int i, status;
 	const char *errmsg = NULL;
-
 	status = (info->status & ~info->mask);
 
 	for (i = 0; i < 32; i++) {
@@ -141,26 +143,22 @@
 				aer_uncorrectable_error_string[i] : NULL;
 
 		if (errmsg)
-			printk("%s""   [%2d] %-22s%s\n", prefix, i, errmsg,
+			dev_err(&dev->dev, "   [%2d] %-22s%s\n", i, errmsg,
 				info->first_error == i ? " (First)" : "");
 		else
-			printk("%s""   [%2d] Unknown Error Bit%s\n", prefix, i,
-				info->first_error == i ? " (First)" : "");
+			dev_err(&dev->dev, "   [%2d] Unknown Error Bit%s\n",
+				i, info->first_error == i ? " (First)" : "");
 	}
 }
 
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
 {
 	int id = ((dev->bus->number << 8) | dev->devfn);
-	char prefix[44];
-
-	snprintf(prefix, sizeof(prefix), "%s%s %s: ",
-		 (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR,
-		 dev_driver_string(&dev->dev), dev_name(&dev->dev));
 
 	if (info->status == 0) {
-		printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, "
-			"id=%04x(Unregistered Agent ID)\n", prefix,
+		dev_err(&dev->dev,
+			"PCIe Bus Error: severity=%s, type=Unaccessible, "
+			"id=%04x(Unregistered Agent ID)\n",
 			aer_error_severity_string[info->severity], id);
 	} else {
 		int layer, agent;
@@ -168,22 +166,24 @@
 		layer = AER_GET_LAYER_ERROR(info->severity, info->status);
 		agent = AER_GET_AGENT(info->severity, info->status);
 
-		printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
-			prefix, aer_error_severity_string[info->severity],
+		dev_err(&dev->dev,
+			"PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
+			aer_error_severity_string[info->severity],
 			aer_error_layer[layer], id, aer_agent_string[agent]);
 
-		printk("%s""  device [%04x:%04x] error status/mask=%08x/%08x\n",
-			prefix, dev->vendor, dev->device,
+		dev_err(&dev->dev,
+			"  device [%04x:%04x] error status/mask=%08x/%08x\n",
+			dev->vendor, dev->device,
 			info->status, info->mask);
 
-		__aer_print_error(prefix, info);
+		__aer_print_error(dev, info);
 
 		if (info->tlp_header_valid) {
 			unsigned char *tlp = (unsigned char *) &info->tlp;
-			printk("%s""  TLP Header:"
+			dev_err(&dev->dev, "  TLP Header:"
 				" %02x%02x%02x%02x %02x%02x%02x%02x"
 				" %02x%02x%02x%02x %02x%02x%02x%02x\n",
-				prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+				*(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
 				*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
 				*(tlp + 11), *(tlp + 10), *(tlp + 9),
 				*(tlp + 8), *(tlp + 15), *(tlp + 14),
@@ -192,8 +192,11 @@
 	}
 
 	if (info->id && info->error_dev_num > 1 && info->id == id)
-		printk("%s""  Error of this Agent(%04x) is reported first\n",
-			prefix, id);
+		dev_err(&dev->dev,
+			   "  Error of this Agent(%04x) is reported first\n",
+			id);
+	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
+			info->severity);
 }
 
 void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
@@ -217,7 +220,7 @@
 }
 EXPORT_SYMBOL_GPL(cper_severity_to_aer);
 
-void cper_print_aer(const char *prefix, int cper_severity,
+void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity,
 		    struct aer_capability_regs *aer)
 {
 	int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
@@ -239,25 +242,27 @@
 	}
 	layer = AER_GET_LAYER_ERROR(aer_severity, status);
 	agent = AER_GET_AGENT(aer_severity, status);
-	printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n",
-	       prefix, status, mask);
+	dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n",
+	       status, mask);
 	cper_print_bits(prefix, status, status_strs, status_strs_size);
-	printk("%s""aer_layer=%s, aer_agent=%s\n", prefix,
+	dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n",
 	       aer_error_layer[layer], aer_agent_string[agent]);
 	if (aer_severity != AER_CORRECTABLE)
-		printk("%s""aer_uncor_severity: 0x%08x\n",
-		       prefix, aer->uncor_severity);
+		dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n",
+		       aer->uncor_severity);
 	if (tlp_header_valid) {
 		const unsigned char *tlp;
 		tlp = (const unsigned char *)&aer->header_log;
-		printk("%s""aer_tlp_header:"
+		dev_err(&dev->dev, "aer_tlp_header:"
 			" %02x%02x%02x%02x %02x%02x%02x%02x"
 			" %02x%02x%02x%02x %02x%02x%02x%02x\n",
-			prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+			*(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
 			*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
 			*(tlp + 11), *(tlp + 10), *(tlp + 9),
 			*(tlp + 8), *(tlp + 15), *(tlp + 14),
 			*(tlp + 13), *(tlp + 12));
 	}
+	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
+			aer_severity);
 }
 #endif
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6186f03..2dcd22d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1280,7 +1280,6 @@
 
 	/* Power Management */
 	pci_pm_init(dev);
-	platform_pci_wakeup_init(dev);
 
 	/* Vital Product Data */
 	pci_vpd_pci22_init(dev);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 7c0fd92..84954a7 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -19,6 +19,8 @@
 
 static void pci_stop_dev(struct pci_dev *dev)
 {
+	pci_pme_active(dev, false);
+
 	if (dev->is_added) {
 		pci_proc_detach_device(dev);
 		pci_remove_sysfs_dev_files(dev);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index a5f3c8c..393b0ec 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,6 +26,29 @@
 	help
 	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINCTRL_ABX500
+	bool "ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions"
+	depends on AB8500_CORE
+	select GENERIC_PINCONF
+	help
+	  Select this to enable the ABx500 family IC GPIO driver
+
+config PINCTRL_AB8500
+	bool "AB8500 pin controller driver"
+	depends on PINCTRL_ABX500 && ARCH_U8500
+
+config PINCTRL_AB8540
+	bool "AB8540 pin controller driver"
+	depends on PINCTRL_ABX500 && ARCH_U8500
+
+config PINCTRL_AB9540
+	bool "AB9540 pin controller driver"
+	depends on PINCTRL_ABX500 && ARCH_U8500
+
+config PINCTRL_AB8505
+	bool "AB8505 pin controller driver"
+	depends on PINCTRL_ABX500 && ARCH_U8500
+
 config PINCTRL_AT91
 	bool "AT91 pinctrl driver"
 	depends on OF
@@ -151,6 +174,11 @@
 	depends on ARCH_SIRF
 	select PINMUX
 
+config PINCTRL_SUNXI
+	bool
+	select PINMUX
+	select GENERIC_PINCONF
+
 config PINCTRL_TEGRA
 	bool
 	select PINMUX
@@ -164,6 +192,10 @@
 	bool
 	select PINCTRL_TEGRA
 
+config PINCTRL_TEGRA114
+	bool
+	select PINCTRL_TEGRA
+
 config PINCTRL_U300
 	bool "U300 pin controller driver"
 	depends on ARCH_U300
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 6e87e52..0fd5f57 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,11 @@
 obj-$(CONFIG_PINCTRL)		+= devicetree.o
 endif
 obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
+obj-$(CONFIG_PINCTRL_ABX500)	+= pinctrl-abx500.o
+obj-$(CONFIG_PINCTRL_AB8500)	+= pinctrl-ab8500.o
+obj-$(CONFIG_PINCTRL_AB8540)	+= pinctrl-ab8540.o
+obj-$(CONFIG_PINCTRL_AB9540)	+= pinctrl-ab9540.o
+obj-$(CONFIG_PINCTRL_AB8505)	+= pinctrl-ab8505.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)	+= pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_IMX)	+= pinctrl-imx.o
@@ -30,9 +35,11 @@
 obj-$(CONFIG_PINCTRL_PXA910)	+= pinctrl-pxa910.o
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= pinctrl-sirf.o
+obj-$(CONFIG_PINCTRL_SUNXI)	+= pinctrl-sunxi.o
 obj-$(CONFIG_PINCTRL_TEGRA)	+= pinctrl-tegra.o
 obj-$(CONFIG_PINCTRL_TEGRA20)	+= pinctrl-tegra20.o
 obj-$(CONFIG_PINCTRL_TEGRA30)	+= pinctrl-tegra30.o
+obj-$(CONFIG_PINCTRL_TEGRA114)	+= pinctrl-tegra114.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)	+= pinctrl-coh901.o
 obj-$(CONFIG_PINCTRL_SAMSUNG)	+= pinctrl-samsung.o
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 59f5a96..b0de6e7 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) "pinctrl core: " fmt
 
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/device.h>
@@ -31,17 +32,6 @@
 #include "pinmux.h"
 #include "pinconf.h"
 
-/**
- * struct pinctrl_maps - a list item containing part of the mapping table
- * @node: mapping table list node
- * @maps: array of mapping table entries
- * @num_maps: the number of entries in @maps
- */
-struct pinctrl_maps {
-	struct list_head node;
-	struct pinctrl_map const *maps;
-	unsigned num_maps;
-};
 
 static bool pinctrl_dummy_state;
 
@@ -55,13 +45,8 @@
 static LIST_HEAD(pinctrl_list);
 
 /* List of pinctrl maps (struct pinctrl_maps) */
-static LIST_HEAD(pinctrl_maps);
+LIST_HEAD(pinctrl_maps);
 
-#define for_each_maps(_maps_node_, _i_, _map_) \
-	list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
-		for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
-			_i_ < _maps_node_->num_maps; \
-			_i_++, _map_ = &_maps_node_->maps[_i_])
 
 /**
  * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
@@ -83,6 +68,12 @@
 }
 EXPORT_SYMBOL_GPL(pinctrl_dev_get_name);
 
+const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev)
+{
+	return dev_name(pctldev->dev);
+}
+EXPORT_SYMBOL_GPL(pinctrl_dev_get_devname);
+
 void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev)
 {
 	return pctldev->driver_data;
@@ -609,13 +600,16 @@
 
 	setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
 	if (setting->pctldev == NULL) {
-		dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
-			map->ctrl_dev_name);
 		kfree(setting);
+		/* Do not defer probing of hogs (circular loop) */
+		if (!strcmp(map->ctrl_dev_name, map->dev_name))
+			return -ENODEV;
 		/*
 		 * OK let us guess that the driver is not there yet, and
 		 * let's defer obtaining this pinctrl handle to later...
 		 */
+		dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
+			map->ctrl_dev_name);
 		return -EPROBE_DEFER;
 	}
 
@@ -694,11 +688,31 @@
 			continue;
 
 		ret = add_setting(p, map);
-		if (ret < 0) {
+		/*
+		 * At this point the adding of a setting may:
+		 *
+		 * - Defer, if the pinctrl device is not yet available
+		 * - Fail, if the pinctrl device is not yet available,
+		 *   AND the setting is a hog. We cannot defer that, since
+		 *   the hog will kick in immediately after the device
+		 *   is registered.
+		 *
+		 * If the error returned was not -EPROBE_DEFER then we
+		 * accumulate the errors to see if we end up with
+		 * an -EPROBE_DEFER later, as that is the worst case.
+		 */
+		if (ret == -EPROBE_DEFER) {
 			pinctrl_put_locked(p, false);
 			return ERR_PTR(ret);
 		}
 	}
+	if (ret < 0) {
+		/* If some other error than deferral occured, return here */
+		pinctrl_put_locked(p, false);
+		return ERR_PTR(ret);
+	}
+
+	kref_init(&p->users);
 
 	/* Add the pinctrl handle to the global list */
 	list_add_tail(&p->node, &pinctrl_list);
@@ -713,9 +727,17 @@
 	if (WARN_ON(!dev))
 		return ERR_PTR(-EINVAL);
 
+	/*
+	 * See if somebody else (such as the device core) has already
+	 * obtained a handle to the pinctrl for this device. In that case,
+	 * return another pointer to it.
+	 */
 	p = find_pinctrl(dev);
-	if (p != NULL)
-		return ERR_PTR(-EBUSY);
+	if (p != NULL) {
+		dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");
+		kref_get(&p->users);
+		return p;
+	}
 
 	return create_pinctrl(dev);
 }
@@ -771,13 +793,24 @@
 }
 
 /**
- * pinctrl_put() - release a previously claimed pinctrl handle
+ * pinctrl_release() - release the pinctrl handle
+ * @kref: the kref in the pinctrl being released
+ */
+static void pinctrl_release(struct kref *kref)
+{
+	struct pinctrl *p = container_of(kref, struct pinctrl, users);
+
+	pinctrl_put_locked(p, true);
+}
+
+/**
+ * pinctrl_put() - decrease use count on a previously claimed pinctrl handle
  * @p: the pinctrl handle to release
  */
 void pinctrl_put(struct pinctrl *p)
 {
 	mutex_lock(&pinctrl_mutex);
-	pinctrl_put_locked(p, true);
+	kref_put(&p->users, pinctrl_release);
 	mutex_unlock(&pinctrl_mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_put);
@@ -1055,6 +1088,30 @@
 	}
 }
 
+/**
+ * pinctrl_force_sleep() - turn a given controller device into sleep state
+ * @pctldev: pin controller device
+ */
+int pinctrl_force_sleep(struct pinctrl_dev *pctldev)
+{
+	if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep))
+		return pinctrl_select_state(pctldev->p, pctldev->hog_sleep);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_force_sleep);
+
+/**
+ * pinctrl_force_default() - turn a given controller device into default state
+ * @pctldev: pin controller device
+ */
+int pinctrl_force_default(struct pinctrl_dev *pctldev)
+{
+	if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default))
+		return pinctrl_select_state(pctldev->p, pctldev->hog_default);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_force_default);
+
 #ifdef CONFIG_DEBUG_FS
 
 static int pinctrl_pins_show(struct seq_file *s, void *what)
@@ -1500,16 +1557,23 @@
 
 	pctldev->p = pinctrl_get_locked(pctldev->dev);
 	if (!IS_ERR(pctldev->p)) {
-		struct pinctrl_state *s =
+		pctldev->hog_default =
 			pinctrl_lookup_state_locked(pctldev->p,
 						    PINCTRL_STATE_DEFAULT);
-		if (IS_ERR(s)) {
+		if (IS_ERR(pctldev->hog_default)) {
 			dev_dbg(dev, "failed to lookup the default state\n");
 		} else {
-			if (pinctrl_select_state_locked(pctldev->p, s))
+			if (pinctrl_select_state_locked(pctldev->p,
+						pctldev->hog_default))
 				dev_err(dev,
 					"failed to select default state\n");
 		}
+
+		pctldev->hog_sleep =
+			pinctrl_lookup_state_locked(pctldev->p,
+						    PINCTRL_STATE_SLEEP);
+		if (IS_ERR(pctldev->hog_sleep))
+			dev_dbg(dev, "failed to lookup the sleep state\n");
 	}
 
 	mutex_unlock(&pinctrl_mutex);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 12f5694..ee72f1f 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -9,6 +9,7 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#include <linux/kref.h>
 #include <linux/mutex.h>
 #include <linux/radix-tree.h>
 #include <linux/pinctrl/pinconf.h>
@@ -30,6 +31,8 @@
  * @driver_data: driver data for drivers registering to the pin controller
  *	subsystem
  * @p: result of pinctrl_get() for this device
+ * @hog_default: default state for pins hogged by this device
+ * @hog_sleep: sleep state for pins hogged by this device
  * @device_root: debugfs root for this device
  */
 struct pinctrl_dev {
@@ -41,6 +44,8 @@
 	struct module *owner;
 	void *driver_data;
 	struct pinctrl *p;
+	struct pinctrl_state *hog_default;
+	struct pinctrl_state *hog_sleep;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *device_root;
 #endif
@@ -54,6 +59,7 @@
  * @state: the current state
  * @dt_maps: the mapping table chunks dynamically parsed from device tree for
  *	this device, if any
+ * @users: reference count
  */
 struct pinctrl {
 	struct list_head node;
@@ -61,6 +67,7 @@
 	struct list_head states;
 	struct pinctrl_state *state;
 	struct list_head dt_maps;
+	struct kref users;
 };
 
 /**
@@ -148,6 +155,18 @@
 #endif
 };
 
+/**
+ * struct pinctrl_maps - a list item containing part of the mapping table
+ * @node: mapping table list node
+ * @maps: array of mapping table entries
+ * @num_maps: the number of entries in @maps
+ */
+struct pinctrl_maps {
+	struct list_head node;
+	struct pinctrl_map const *maps;
+	unsigned num_maps;
+};
+
 struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
 int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
 const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
@@ -164,5 +183,15 @@
 			 bool dup, bool locked);
 void pinctrl_unregister_map(struct pinctrl_map const *map);
 
+extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
+extern int pinctrl_force_default(struct pinctrl_dev *pctldev);
+
 extern struct mutex pinctrl_mutex;
 extern struct list_head pinctrldev_list;
+extern struct list_head pinctrl_maps;
+
+#define for_each_maps(_maps_node_, _i_, _map_) \
+	list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
+		for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
+			_i_ < _maps_node_->num_maps; \
+			_i_++, _map_ = &_maps_node_->maps[_i_])
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index fe2d1af..fd40a11 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -141,6 +141,11 @@
 		pctldev = find_pinctrl_by_of_node(np_pctldev);
 		if (pctldev)
 			break;
+		/* Do not defer probing of hogs (circular loop) */
+		if (np_pctldev == p->dev->of_node) {
+			of_node_put(np_pctldev);
+			return -ENODEV;
+		}
 	}
 	of_node_put(np_pctldev);
 
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 833a364..06c304a 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -41,11 +41,13 @@
 	PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
 	PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
 	PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
-	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL),
+	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
 	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
 	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
 	PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
+	PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
 	PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
+	PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level"),
 };
 
 void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index baee2cc..ac8d382 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -574,6 +574,207 @@
 	.release	= single_release,
 };
 
+/* 32bit read/write ressources */
+#define MAX_NAME_LEN 16
+char dbg_pinname[MAX_NAME_LEN]; /* shared: name of the state of the pin*/
+char dbg_state_name[MAX_NAME_LEN]; /* shared: state of the pin*/
+static u32 dbg_config; /* shared: config to be read/set for the pin & state*/
+
+static int pinconf_dbg_pinname_print(struct seq_file *s, void *d)
+{
+	if (strlen(dbg_pinname))
+		seq_printf(s, "%s\n", dbg_pinname);
+	else
+		seq_printf(s, "No pin name set\n");
+	return 0;
+}
+
+static int pinconf_dbg_pinname_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pinconf_dbg_pinname_print, inode->i_private);
+}
+
+static int pinconf_dbg_pinname_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err;
+
+	if (count > MAX_NAME_LEN)
+		return -EINVAL;
+
+	err = sscanf(user_buf, "%15s", dbg_pinname);
+
+	if (err != 1)
+		return -EINVAL;
+
+	return count;
+}
+
+static const struct file_operations pinconf_dbg_pinname_fops = {
+	.open = pinconf_dbg_pinname_open,
+	.write = pinconf_dbg_pinname_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int pinconf_dbg_state_print(struct seq_file *s, void *d)
+{
+	if (strlen(dbg_state_name))
+		seq_printf(s, "%s\n", dbg_pinname);
+	else
+		seq_printf(s, "No pin state set\n");
+	return 0;
+}
+
+static int pinconf_dbg_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pinconf_dbg_state_print, inode->i_private);
+}
+
+static int pinconf_dbg_state_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err;
+
+	if (count > MAX_NAME_LEN)
+		return -EINVAL;
+
+	err = sscanf(user_buf, "%15s", dbg_state_name);
+
+	if (err != 1)
+		return -EINVAL;
+
+	return count;
+}
+
+static const struct file_operations pinconf_dbg_pinstate_fops = {
+	.open = pinconf_dbg_state_open,
+	.write = pinconf_dbg_state_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+/**
+ * pinconf_dbg_config_print() - display the pinctrl config from the pinctrl
+ * map, of a pin/state pair based on pinname and state that have been
+ * selected with the debugfs entries pinconf-name and pinconf-state
+ * @s: contains the 32bits config to be written
+ * @d: not used
+ */
+static int pinconf_dbg_config_print(struct seq_file *s, void *d)
+{
+	struct pinctrl_maps *maps_node;
+	struct pinctrl_map const *map;
+	struct pinctrl_dev *pctldev = NULL;
+	struct pinconf_ops *confops = NULL;
+	int i, j;
+	bool found = false;
+
+	mutex_lock(&pinctrl_mutex);
+
+	/* Parse the pinctrl map and look for the elected pin/state */
+	for_each_maps(maps_node, i, map) {
+		if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+			continue;
+
+		if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+			continue;
+
+		for (j = 0; j < map->data.configs.num_configs; j++) {
+			if (0 == strncmp(map->data.configs.group_or_pin,
+						dbg_pinname, MAX_NAME_LEN)) {
+				/* We found the right pin / state, read the
+				 * config and store the pctldev */
+				dbg_config = map->data.configs.configs[j];
+				pctldev = get_pinctrl_dev_from_devname
+					(map->ctrl_dev_name);
+				found = true;
+				break;
+			}
+		}
+	}
+
+	mutex_unlock(&pinctrl_mutex);
+
+	if (found) {
+		seq_printf(s, "Config of %s in state %s: 0x%08X\n", dbg_pinname,
+				 dbg_state_name, dbg_config);
+
+		if (pctldev)
+			confops = pctldev->desc->confops;
+
+		if (confops && confops->pin_config_config_dbg_show)
+			confops->pin_config_config_dbg_show(pctldev,
+					s, dbg_config);
+	} else {
+		seq_printf(s, "No pin found for defined name/state\n");
+	}
+
+	return 0;
+}
+
+static int pinconf_dbg_config_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pinconf_dbg_config_print, inode->i_private);
+}
+
+/**
+ * pinconf_dbg_config_write() - overwrite the pinctrl config in thepinctrl
+ * map, of a pin/state pair based on pinname and state that have been
+ * selected with the debugfs entries pinconf-name and pinconf-state
+ */
+static int pinconf_dbg_config_write(struct file *file,
+	const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	int err;
+	unsigned long config;
+	struct pinctrl_maps *maps_node;
+	struct pinctrl_map const *map;
+	int i, j;
+
+	err = kstrtoul_from_user(user_buf, count, 0, &config);
+
+	if (err)
+		return err;
+
+	dbg_config = config;
+
+	mutex_lock(&pinctrl_mutex);
+
+	/* Parse the pinctrl map and look for the selected pin/state */
+	for_each_maps(maps_node, i, map) {
+		if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+			continue;
+
+		if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+			continue;
+
+		/*  we found the right pin / state, so overwrite config */
+		for (j = 0; j < map->data.configs.num_configs; j++) {
+			if (strncmp(map->data.configs.group_or_pin, dbg_pinname,
+						MAX_NAME_LEN) == 0)
+				map->data.configs.configs[j] = dbg_config;
+		}
+	}
+
+	mutex_unlock(&pinctrl_mutex);
+
+	return count;
+}
+
+static const struct file_operations pinconf_dbg_pinconfig_fops = {
+	.open = pinconf_dbg_config_open,
+	.write = pinconf_dbg_config_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 void pinconf_init_device_debugfs(struct dentry *devroot,
 			 struct pinctrl_dev *pctldev)
 {
@@ -581,6 +782,12 @@
 			    devroot, pctldev, &pinconf_pins_ops);
 	debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO,
 			    devroot, pctldev, &pinconf_groups_ops);
+	debugfs_create_file("pinconf-name", (S_IRUGO | S_IWUSR | S_IWGRP),
+			    devroot, pctldev, &pinconf_dbg_pinname_fops);
+	debugfs_create_file("pinconf-state",  (S_IRUGO | S_IWUSR | S_IWGRP),
+			    devroot, pctldev, &pinconf_dbg_pinstate_fops);
+	debugfs_create_file("pinconf-config",  (S_IRUGO | S_IWUSR | S_IWGRP),
+			    devroot, pctldev, &pinconf_dbg_pinconfig_fops);
 }
 
 #endif
diff --git a/drivers/pinctrl/pinctrl-ab8500.c b/drivers/pinctrl/pinctrl-ab8500.c
new file mode 100644
index 0000000..3b471d8
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8500.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset)		(offset)
+
+#define AB8500_PIN_T10		ABX500_GPIO(1)
+#define AB8500_PIN_T9		ABX500_GPIO(2)
+#define AB8500_PIN_U9		ABX500_GPIO(3)
+#define AB8500_PIN_W2		ABX500_GPIO(4)
+/* hole */
+#define AB8500_PIN_Y18		ABX500_GPIO(6)
+#define AB8500_PIN_AA20		ABX500_GPIO(7)
+#define AB8500_PIN_W18		ABX500_GPIO(8)
+#define AB8500_PIN_AA19		ABX500_GPIO(9)
+#define AB8500_PIN_U17		ABX500_GPIO(10)
+#define AB8500_PIN_AA18		ABX500_GPIO(11)
+#define AB8500_PIN_U16		ABX500_GPIO(12)
+#define AB8500_PIN_W17		ABX500_GPIO(13)
+#define AB8500_PIN_F14		ABX500_GPIO(14)
+#define AB8500_PIN_B17		ABX500_GPIO(15)
+#define AB8500_PIN_F15		ABX500_GPIO(16)
+#define AB8500_PIN_P5		ABX500_GPIO(17)
+#define AB8500_PIN_R5		ABX500_GPIO(18)
+#define AB8500_PIN_U5		ABX500_GPIO(19)
+#define AB8500_PIN_T5		ABX500_GPIO(20)
+#define AB8500_PIN_H19		ABX500_GPIO(21)
+#define AB8500_PIN_G20		ABX500_GPIO(22)
+#define AB8500_PIN_G19		ABX500_GPIO(23)
+#define AB8500_PIN_T14		ABX500_GPIO(24)
+#define AB8500_PIN_R16		ABX500_GPIO(25)
+#define AB8500_PIN_M16		ABX500_GPIO(26)
+#define AB8500_PIN_J6		ABX500_GPIO(27)
+#define AB8500_PIN_K6		ABX500_GPIO(28)
+#define AB8500_PIN_G6		ABX500_GPIO(29)
+#define AB8500_PIN_H6		ABX500_GPIO(30)
+#define AB8500_PIN_F5		ABX500_GPIO(31)
+#define AB8500_PIN_G5		ABX500_GPIO(32)
+/* hole */
+#define AB8500_PIN_R17		ABX500_GPIO(34)
+#define AB8500_PIN_W15		ABX500_GPIO(35)
+#define AB8500_PIN_A17		ABX500_GPIO(36)
+#define AB8500_PIN_E15		ABX500_GPIO(37)
+#define AB8500_PIN_C17		ABX500_GPIO(38)
+#define AB8500_PIN_E16		ABX500_GPIO(39)
+#define AB8500_PIN_T19		ABX500_GPIO(40)
+#define AB8500_PIN_U19		ABX500_GPIO(41)
+#define AB8500_PIN_U2		ABX500_GPIO(42)
+
+/* indicates the highest GPIO number */
+#define AB8500_GPIO_MAX_NUMBER	42
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8500_pins[] = {
+	PINCTRL_PIN(AB8500_PIN_T10, "GPIO1_T10"),
+	PINCTRL_PIN(AB8500_PIN_T9, "GPIO2_T9"),
+	PINCTRL_PIN(AB8500_PIN_U9, "GPIO3_U9"),
+	PINCTRL_PIN(AB8500_PIN_W2, "GPIO4_W2"),
+	/* hole */
+	PINCTRL_PIN(AB8500_PIN_Y18, "GPIO6_Y18"),
+	PINCTRL_PIN(AB8500_PIN_AA20, "GPIO7_AA20"),
+	PINCTRL_PIN(AB8500_PIN_W18, "GPIO8_W18"),
+	PINCTRL_PIN(AB8500_PIN_AA19, "GPIO9_AA19"),
+	PINCTRL_PIN(AB8500_PIN_U17, "GPIO10_U17"),
+	PINCTRL_PIN(AB8500_PIN_AA18, "GPIO11_AA18"),
+	PINCTRL_PIN(AB8500_PIN_U16, "GPIO12_U16"),
+	PINCTRL_PIN(AB8500_PIN_W17, "GPIO13_W17"),
+	PINCTRL_PIN(AB8500_PIN_F14, "GPIO14_F14"),
+	PINCTRL_PIN(AB8500_PIN_B17, "GPIO15_B17"),
+	PINCTRL_PIN(AB8500_PIN_F15, "GPIO16_F15"),
+	PINCTRL_PIN(AB8500_PIN_P5, "GPIO17_P5"),
+	PINCTRL_PIN(AB8500_PIN_R5, "GPIO18_R5"),
+	PINCTRL_PIN(AB8500_PIN_U5, "GPIO19_U5"),
+	PINCTRL_PIN(AB8500_PIN_T5, "GPIO20_T5"),
+	PINCTRL_PIN(AB8500_PIN_H19, "GPIO21_H19"),
+	PINCTRL_PIN(AB8500_PIN_G20, "GPIO22_G20"),
+	PINCTRL_PIN(AB8500_PIN_G19, "GPIO23_G19"),
+	PINCTRL_PIN(AB8500_PIN_T14, "GPIO24_T14"),
+	PINCTRL_PIN(AB8500_PIN_R16, "GPIO25_R16"),
+	PINCTRL_PIN(AB8500_PIN_M16, "GPIO26_M16"),
+	PINCTRL_PIN(AB8500_PIN_J6, "GPIO27_J6"),
+	PINCTRL_PIN(AB8500_PIN_K6, "GPIO28_K6"),
+	PINCTRL_PIN(AB8500_PIN_G6, "GPIO29_G6"),
+	PINCTRL_PIN(AB8500_PIN_H6, "GPIO30_H6"),
+	PINCTRL_PIN(AB8500_PIN_F5, "GPIO31_F5"),
+	PINCTRL_PIN(AB8500_PIN_G5, "GPIO32_G5"),
+	/* hole */
+	PINCTRL_PIN(AB8500_PIN_R17, "GPIO34_R17"),
+	PINCTRL_PIN(AB8500_PIN_W15, "GPIO35_W15"),
+	PINCTRL_PIN(AB8500_PIN_A17, "GPIO36_A17"),
+	PINCTRL_PIN(AB8500_PIN_E15, "GPIO37_E15"),
+	PINCTRL_PIN(AB8500_PIN_C17, "GPIO38_C17"),
+	PINCTRL_PIN(AB8500_PIN_E16, "GPIO39_E16"),
+	PINCTRL_PIN(AB8500_PIN_T19, "GPIO40_T19"),
+	PINCTRL_PIN(AB8500_PIN_U19, "GPIO41_U19"),
+	PINCTRL_PIN(AB8500_PIN_U2, "GPIO42_U2"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8500_pinranges[] = {
+	ABX500_PINRANGE(1, 4, ABX500_ALT_A),
+	ABX500_PINRANGE(6, 4, ABX500_ALT_A),
+	ABX500_PINRANGE(10, 4, ABX500_DEFAULT),
+	ABX500_PINRANGE(14, 12, ABX500_ALT_A),
+	ABX500_PINRANGE(26, 1, ABX500_DEFAULT),
+	ABX500_PINRANGE(27, 6, ABX500_ALT_A),
+	ABX500_PINRANGE(34, 1, ABX500_ALT_A),
+	ABX500_PINRANGE(35, 1, ABX500_DEFAULT),
+	ABX500_PINRANGE(36, 7, ABX500_ALT_A),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8500_PIN_T10 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8500_PIN_T9 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8500_PIN_U9 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB8500_PIN_W2 };
+static const unsigned ycbcr0123_d_1_pins[] = { AB8500_PIN_Y18, AB8500_PIN_AA20,
+					AB8500_PIN_W18, AB8500_PIN_AA19};
+static const unsigned gpio10_d_1_pins[] = { AB8500_PIN_U17 };
+static const unsigned gpio11_d_1_pins[] = { AB8500_PIN_AA18 };
+static const unsigned gpio12_d_1_pins[] = { AB8500_PIN_U16 };
+static const unsigned gpio13_d_1_pins[] = { AB8500_PIN_W17 };
+static const unsigned pwmout1_d_1_pins[] = { AB8500_PIN_F14 };
+static const unsigned pwmout2_d_1_pins[] = { AB8500_PIN_B17 };
+static const unsigned pwmout3_d_1_pins[] = { AB8500_PIN_F15 };
+
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB8500_PIN_P5, AB8500_PIN_R5,
+					AB8500_PIN_U5, AB8500_PIN_T5 };
+/* USBUICC */
+static const unsigned usbuicc_d_1_pins[] = { AB8500_PIN_H19, AB8500_PIN_G20,
+					AB8500_PIN_G19 };
+static const unsigned sysclkreq7_d_1_pins[] = { AB8500_PIN_T14 };
+static const unsigned sysclkreq8_d_1_pins[] = { AB8500_PIN_R16 };
+static const unsigned gpio26_d_1_pins[] = { AB8500_PIN_M16 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB8500_PIN_J6, AB8500_PIN_K6 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB8500_PIN_G6, AB8500_PIN_H6 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB8500_PIN_F5, AB8500_PIN_G5 };
+static const unsigned extcpena_d_1_pins[] = { AB8500_PIN_R17 };
+static const unsigned gpio35_d_1_pins[] = { AB8500_PIN_W15 };
+/* APE SPI */
+static const unsigned apespi_d_1_pins[] = { AB8500_PIN_A17, AB8500_PIN_E15,
+					AB8500_PIN_C17, AB8500_PIN_E16};
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB8500_PIN_T19, AB8500_PIN_U19 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB8500_PIN_U2 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8500_PIN_T10 };
+static const unsigned gpio2_a_1_pins[] = { AB8500_PIN_T9 };
+static const unsigned gpio3_a_1_pins[] = { AB8500_PIN_U9 };
+static const unsigned gpio4_a_1_pins[] = { AB8500_PIN_W2 };
+static const unsigned gpio6_a_1_pins[] = { AB8500_PIN_Y18 };
+static const unsigned gpio7_a_1_pins[] = { AB8500_PIN_AA20 };
+static const unsigned gpio8_a_1_pins[] = { AB8500_PIN_W18 };
+static const unsigned gpio9_a_1_pins[] = { AB8500_PIN_AA19 };
+/* YCbCr4 YCbCr5 YCbCr6 YCbCr7*/
+static const unsigned ycbcr4567_a_1_pins[] = { AB8500_PIN_U17, AB8500_PIN_AA18,
+					AB8500_PIN_U16, AB8500_PIN_W17};
+static const unsigned gpio14_a_1_pins[] = { AB8500_PIN_F14 };
+static const unsigned gpio15_a_1_pins[] = { AB8500_PIN_B17 };
+static const unsigned gpio16_a_1_pins[] = { AB8500_PIN_F15 };
+static const unsigned gpio17_a_1_pins[] = { AB8500_PIN_P5 };
+static const unsigned gpio18_a_1_pins[] = { AB8500_PIN_R5 };
+static const unsigned gpio19_a_1_pins[] = { AB8500_PIN_U5 };
+static const unsigned gpio20_a_1_pins[] = { AB8500_PIN_T5 };
+static const unsigned gpio21_a_1_pins[] = { AB8500_PIN_H19 };
+static const unsigned gpio22_a_1_pins[] = { AB8500_PIN_G20 };
+static const unsigned gpio23_a_1_pins[] = { AB8500_PIN_G19 };
+static const unsigned gpio24_a_1_pins[] = { AB8500_PIN_T14 };
+static const unsigned gpio25_a_1_pins[] = { AB8500_PIN_R16 };
+static const unsigned gpio27_a_1_pins[] = { AB8500_PIN_J6 };
+static const unsigned gpio28_a_1_pins[] = { AB8500_PIN_K6 };
+static const unsigned gpio29_a_1_pins[] = { AB8500_PIN_G6 };
+static const unsigned gpio30_a_1_pins[] = { AB8500_PIN_H6 };
+static const unsigned gpio31_a_1_pins[] = { AB8500_PIN_F5 };
+static const unsigned gpio32_a_1_pins[] = { AB8500_PIN_G5 };
+static const unsigned gpio34_a_1_pins[] = { AB8500_PIN_R17 };
+static const unsigned gpio36_a_1_pins[] = { AB8500_PIN_A17 };
+static const unsigned gpio37_a_1_pins[] = { AB8500_PIN_E15 };
+static const unsigned gpio38_a_1_pins[] = { AB8500_PIN_C17 };
+static const unsigned gpio39_a_1_pins[] = { AB8500_PIN_E16 };
+static const unsigned gpio40_a_1_pins[] = { AB8500_PIN_T19 };
+static const unsigned gpio41_a_1_pins[] = { AB8500_PIN_U19 };
+static const unsigned gpio42_a_1_pins[] = { AB8500_PIN_U2 };
+
+/* Altfunction B colum */
+static const unsigned hiqclkena_b_1_pins[] = { AB8500_PIN_U17 };
+static const unsigned usbuiccpd_b_1_pins[] = { AB8500_PIN_AA18 };
+static const unsigned i2ctrig1_b_1_pins[] = { AB8500_PIN_U16 };
+static const unsigned i2ctrig2_b_1_pins[] = { AB8500_PIN_W17 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB8500_PIN_W17 };
+
+
+#define AB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,		\
+			.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8500_groups[] = {
+	/* default column */
+	AB8500_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(ycbcr0123_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio12_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(usbuicc_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq7_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq8_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio26_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(gpio35_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(apespi_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+	AB8500_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+	/* Altfunction A column */
+	AB8500_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio6_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio7_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio8_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio9_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(ycbcr4567_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio21_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio22_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio23_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio24_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio25_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio36_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio37_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio38_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio39_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+	AB8500_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+	/* Altfunction B column */
+	AB8500_PIN_GROUP(hiqclkena_b_1, ABX500_ALT_B),
+	AB8500_PIN_GROUP(usbuiccpd_b_1, ABX500_ALT_B),
+	AB8500_PIN_GROUP(i2ctrig1_b_1, ABX500_ALT_B),
+	AB8500_PIN_GROUP(i2ctrig2_b_1, ABX500_ALT_B),
+	/* Altfunction C column */
+	AB8500_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8500_FUNC_GROUPS(a, b...)	   \
+static const char * const a##_groups[] = { b };
+
+AB8500_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+		"sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1",
+		"sysclkreq7_d_1", "sysclkreq8_d_1");
+AB8500_FUNC_GROUPS(ycbcr, "ycbcr0123_d_1", "ycbcr4567_a_1");
+AB8500_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+		"gpio6_a_1", "gpio7_a_1", "gpio8_a_1", "gpio9_a_1",
+		"gpio10_d_1", "gpio11_d_1", "gpio12_d_1", "gpio13_d_1",
+		"gpio14_a_1", "gpio15_a_1", "gpio16_a_1", "gpio17_a_1",
+		"gpio18_a_1", "gpio19_a_1", "gpio20_a_1", "gpio21_a_1",
+		"gpio22_a_1", "gpio23_a_1", "gpio24_a_1", "gpio25_a_1",
+		"gpio26_d_1", "gpio27_a_1", "gpio28_a_1", "gpio29_a_1",
+		"gpio30_a_1", "gpio31_a_1", "gpio32_a_1", "gpio34_a_1",
+		"gpio35_d_1", "gpio36_a_1", "gpio37_a_1", "gpio38_a_1",
+		"gpio39_a_1", "gpio40_a_1", "gpio41_a_1", "gpio42_a_1");
+AB8500_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB8500_FUNC_GROUPS(adi1, "adi1_d_1");
+AB8500_FUNC_GROUPS(usbuicc, "usbuicc_d_1", "usbuiccpd_b_1");
+AB8500_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB8500_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB8500_FUNC_GROUPS(apespi, "apespi_d_1");
+AB8500_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB8500_FUNC_GROUPS(hiqclkena, "hiqclkena_b_1");
+AB8500_FUNC_GROUPS(i2ctrig, "i2ctrig1_b_1", "i2ctrig2_b_1");
+AB8500_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct abx500_function ab8500_functions[] = {
+	FUNCTION(sysclkreq),
+	FUNCTION(ycbcr),
+	FUNCTION(gpio),
+	FUNCTION(pwmout),
+	FUNCTION(adi1),
+	FUNCTION(usbuicc),
+	FUNCTION(dmic),
+	FUNCTION(extcpena),
+	FUNCTION(apespi),
+	FUNCTION(modsclsda),
+	FUNCTION(hiqclkena),
+	FUNCTION(i2ctrig),
+	FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB8500 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ *	ALTERNATE_FUNCTIONS(13,     4,      3,      4, 0, 1 ,2),
+ *	means that pin AB8500_PIN_W17 (pin 13) supports 4 mux (default/ALT_A,
+ *	ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to
+ *	select the mux.  ALTA, ALTB and ALTC val indicates values to write in
+ *	ALTERNATFUNC register. We need to specifies these values as SOC
+ *	designers didn't apply the same logic on how to select mux in the
+ *	ABx500 family.
+ *
+ *	As this pins supports at least ALT_B mux, default mux is
+ *	selected by writing 1 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ *	default	|       1       |          0          |          0
+ *	alt_A	|       0       |          0          |          0
+ *	alt_B	|       0       |          0          |          1
+ *	alt_C	|       0       |          1          |          0
+ *
+ *	ALTERNATE_FUNCTIONS(8,      7, UNUSED, UNUSED),
+ *	means that pin AB8500_PIN_W18 (pin 8) supports 2 mux, so only GPIOSEL
+ *	register is used to select the mux. As this pins doesn't support at
+ *	least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=7 | alternatfunc bit2=  | alternatfunc bit1=
+ *	default	|       0       |          0          |          0
+ *	alt_A	|       1       |          0          |          0
+ */
+
+struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
+	ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+	ALTERNATE_FUNCTIONS(1,	    0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(3,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+	ALTERNATE_FUNCTIONS(4,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+	/* bit 4 reserved */
+	ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+	ALTERNATE_FUNCTIONS(6,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO6, altA controlled by bit 5*/
+	ALTERNATE_FUNCTIONS(7,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO7, altA controlled by bit 6*/
+	ALTERNATE_FUNCTIONS(8,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO8, altA controlled by bit 7*/
+
+	ALTERNATE_FUNCTIONS(9,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO9, altA controlled by bit 0*/
+	ALTERNATE_FUNCTIONS(10,     1,      0, UNUSED, 0, 1, 0), /* GPIO10, altA and altB controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(11,     2,      1, UNUSED, 0, 1, 0), /* GPIO11, altA and altB controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(12,     3,      2, UNUSED, 0, 1, 0), /* GPIO12, altA and altB controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(13,     4,      3,      4, 0, 1, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+	ALTERNATE_FUNCTIONS(14,     5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(15,     6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(16,     7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+	/*
+	 * pins 17 to 20 are special case, only bit 0 is used to select
+	 * alternate function for these 4 pins.
+	 * bits 1 to 3 are reserved
+	 */
+	ALTERNATE_FUNCTIONS(17,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(18,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(19,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(20,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(21,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO21, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(22,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO22, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(23,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO23, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(24,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO24, altA controlled by bit 7 */
+
+	ALTERNATE_FUNCTIONS(25,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO25, altA controlled by bit 0 */
+	/* pin 26 special case, no alternate function, bit 1 reserved */
+	ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO26 */
+	ALTERNATE_FUNCTIONS(27,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(28,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(29,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(30,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(31,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(32,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+
+	ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+	ALTERNATE_FUNCTIONS(34,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+	/* pin 35 special case, no alternate function, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO35 */
+	ALTERNATE_FUNCTIONS(36,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO36, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(37,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO37, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(38,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO38, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(39,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO39, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(40,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7 */
+
+	ALTERNATE_FUNCTIONS(41,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(42,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+};
+
+/*
+ * Only some GPIOs are interrupt capable, and they are
+ * organized in discontiguous clusters:
+ *
+ *	GPIO6 to GPIO13
+ *	GPIO24 and GPIO25
+ *	GPIO36 to GPIO41
+ */
+struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
+	GPIO_IRQ_CLUSTER(6,  13, AB8500_INT_GPIO6R),
+	GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
+	GPIO_IRQ_CLUSTER(36, 41, AB8500_INT_GPIO36R),
+};
+
+static struct abx500_pinctrl_soc_data ab8500_soc = {
+	.gpio_ranges = ab8500_pinranges,
+	.gpio_num_ranges = ARRAY_SIZE(ab8500_pinranges),
+	.pins = ab8500_pins,
+	.npins = ARRAY_SIZE(ab8500_pins),
+	.functions = ab8500_functions,
+	.nfunctions = ARRAY_SIZE(ab8500_functions),
+	.groups = ab8500_groups,
+	.ngroups = ARRAY_SIZE(ab8500_groups),
+	.alternate_functions = ab8500_alternate_functions,
+	.gpio_irq_cluster = ab8500_gpio_irq_cluster,
+	.ngpio_irq_cluster = ARRAY_SIZE(ab8500_gpio_irq_cluster),
+	.irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+	.irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+	.irq_gpio_factor = 1,
+};
+
+void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+	*soc = &ab8500_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-ab8505.c b/drivers/pinctrl/pinctrl-ab8505.c
new file mode 100644
index 0000000..3a4238e
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8505.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset)	(offset)
+
+#define AB8505_PIN_N4		ABX500_GPIO(1)
+#define AB8505_PIN_R5		ABX500_GPIO(2)
+#define AB8505_PIN_P5		ABX500_GPIO(3)
+/* hole */
+#define AB8505_PIN_B16		ABX500_GPIO(10)
+#define AB8505_PIN_B17		ABX500_GPIO(11)
+/* hole */
+#define AB8505_PIN_D17		ABX500_GPIO(13)
+#define AB8505_PIN_C16		ABX500_GPIO(14)
+/* hole */
+#define AB8505_PIN_P2		ABX500_GPIO(17)
+#define AB8505_PIN_N3		ABX500_GPIO(18)
+#define AB8505_PIN_T1		ABX500_GPIO(19)
+#define AB8505_PIN_P3		ABX500_GPIO(20)
+/* hole */
+#define AB8505_PIN_H14		ABX500_GPIO(34)
+/* hole */
+#define AB8505_PIN_J15		ABX500_GPIO(40)
+#define AB8505_PIN_J14		ABX500_GPIO(41)
+/* hole */
+#define AB8505_PIN_L4		ABX500_GPIO(50)
+/* hole */
+#define AB8505_PIN_D16		ABX500_GPIO(52)
+#define AB8505_PIN_D15		ABX500_GPIO(53)
+
+/* indicates the higher GPIO number */
+#define AB8505_GPIO_MAX_NUMBER	53
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8505_pins[] = {
+	PINCTRL_PIN(AB8505_PIN_N4, "GPIO1_N4"),
+	PINCTRL_PIN(AB8505_PIN_R5, "GPIO2_R5"),
+	PINCTRL_PIN(AB8505_PIN_P5, "GPIO3_P5"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_B16, "GPIO10_B16"),
+	PINCTRL_PIN(AB8505_PIN_B17, "GPIO11_B17"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_D17, "GPIO13_D17"),
+	PINCTRL_PIN(AB8505_PIN_C16, "GPIO14_C16"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_P2, "GPIO17_P2"),
+	PINCTRL_PIN(AB8505_PIN_N3, "GPIO18_N3"),
+	PINCTRL_PIN(AB8505_PIN_T1, "GPIO19_T1"),
+	PINCTRL_PIN(AB8505_PIN_P3, "GPIO20_P3"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_H14, "GPIO34_H14"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_J15, "GPIO40_J15"),
+	PINCTRL_PIN(AB8505_PIN_J14, "GPIO41_J14"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_L4, "GPIO50_L4"),
+/* hole */
+	PINCTRL_PIN(AB8505_PIN_D16, "GPIO52_D16"),
+	PINCTRL_PIN(AB8505_PIN_D15, "GPIO53_D15"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8505_pinranges[] = {
+	ABX500_PINRANGE(1, 3, ABX500_ALT_A),
+	ABX500_PINRANGE(10, 2, ABX500_DEFAULT),
+	ABX500_PINRANGE(13, 1, ABX500_DEFAULT),
+	ABX500_PINRANGE(14, 1, ABX500_ALT_A),
+	ABX500_PINRANGE(17, 4, ABX500_ALT_A),
+	ABX500_PINRANGE(34, 1, ABX500_ALT_A),
+	ABX500_PINRANGE(40, 2, ABX500_ALT_A),
+	ABX500_PINRANGE(50, 1, ABX500_DEFAULT),
+	ABX500_PINRANGE(52, 2, ABX500_ALT_A),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8505_PIN_N4 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8505_PIN_R5 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8505_PIN_P5 };
+static const unsigned gpio10_d_1_pins[] = { AB8505_PIN_B16 };
+static const unsigned gpio11_d_1_pins[] = { AB8505_PIN_B17 };
+static const unsigned gpio13_d_1_pins[] = { AB8505_PIN_D17 };
+static const unsigned pwmout1_d_1_pins[] = { AB8505_PIN_C16 };
+/* audio data interface 2*/
+static const unsigned adi2_d_1_pins[] = { AB8505_PIN_P2, AB8505_PIN_N3,
+					AB8505_PIN_T1, AB8505_PIN_P3 };
+static const unsigned extcpena_d_1_pins[] = { AB8505_PIN_H14 };
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB8505_PIN_J15, AB8505_PIN_J14 };
+static const unsigned gpio50_d_1_pins[] = { AB8505_PIN_L4 };
+static const unsigned resethw_d_1_pins[] = { AB8505_PIN_D16 };
+static const unsigned service_d_1_pins[] = { AB8505_PIN_D15 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8505_PIN_N4 };
+static const unsigned gpio2_a_1_pins[] = { AB8505_PIN_R5 };
+static const unsigned gpio3_a_1_pins[] = { AB8505_PIN_P5 };
+static const unsigned hiqclkena_a_1_pins[] = { AB8505_PIN_B16 };
+static const unsigned pdmclk_a_1_pins[] = { AB8505_PIN_B17 };
+static const unsigned uarttxdata_a_1_pins[] = { AB8505_PIN_D17 };
+static const unsigned gpio14_a_1_pins[] = { AB8505_PIN_C16 };
+static const unsigned gpio17_a_1_pins[] = { AB8505_PIN_P2 };
+static const unsigned gpio18_a_1_pins[] = { AB8505_PIN_N3 };
+static const unsigned gpio19_a_1_pins[] = { AB8505_PIN_T1 };
+static const unsigned gpio20_a_1_pins[] = { AB8505_PIN_P3 };
+static const unsigned gpio34_a_1_pins[] = { AB8505_PIN_H14 };
+static const unsigned gpio40_a_1_pins[] = { AB8505_PIN_J15 };
+static const unsigned gpio41_a_1_pins[] = { AB8505_PIN_J14 };
+static const unsigned uartrxdata_a_1_pins[] = { AB8505_PIN_J14 };
+static const unsigned gpio50_a_1_pins[] = { AB8505_PIN_L4 };
+static const unsigned gpio52_a_1_pins[] = { AB8505_PIN_D16 };
+static const unsigned gpio53_a_1_pins[] = { AB8505_PIN_D15 };
+
+/* Altfunction B colum */
+static const unsigned pdmdata_b_1_pins[] = { AB8505_PIN_B16 };
+static const unsigned extvibrapwm1_b_1_pins[] = { AB8505_PIN_D17 };
+static const unsigned extvibrapwm2_b_1_pins[] = { AB8505_PIN_L4 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB8505_PIN_D17 };
+
+#define AB8505_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,		\
+			.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8505_groups[] = {
+	AB8505_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(adi2_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(gpio50_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(resethw_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(service_d_1, ABX500_DEFAULT),
+	AB8505_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(hiqclkena_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(pdmclk_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(uarttxdata_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(uartrxdata_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio52_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(gpio53_a_1, ABX500_ALT_A),
+	AB8505_PIN_GROUP(pdmdata_b_1, ABX500_ALT_B),
+	AB8505_PIN_GROUP(extvibrapwm1_b_1, ABX500_ALT_B),
+	AB8505_PIN_GROUP(extvibrapwm2_b_1, ABX500_ALT_B),
+	AB8505_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8505_FUNC_GROUPS(a, b...)	   \
+static const char * const a##_groups[] = { b };
+
+AB8505_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+		"sysclkreq4_d_1");
+AB8505_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1",
+		"gpio10_d_1", "gpio11_d_1", "gpio13_d_1", "gpio14_a_1",
+		"gpio17_a_1", "gpio18_a_1", "gpio19_a_1", "gpio20_a_1",
+		"gpio34_a_1", "gpio40_a_1", "gpio41_a_1", "gpio50_d_1",
+		"gpio52_a_1", "gpio53_a_1");
+AB8505_FUNC_GROUPS(pwmout, "pwmout1_d_1");
+AB8505_FUNC_GROUPS(adi2, "adi2_d_1");
+AB8505_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB8505_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB8505_FUNC_GROUPS(resethw, "resethw_d_1");
+AB8505_FUNC_GROUPS(service, "service_d_1");
+AB8505_FUNC_GROUPS(hiqclkena, "hiqclkena_a_1");
+AB8505_FUNC_GROUPS(pdm, "pdmclk_a_1", "pdmdata_b_1");
+AB8505_FUNC_GROUPS(uartdata, "uarttxdata_a_1", "uartrxdata_a_1");
+AB8505_FUNC_GROUPS(extvibra, "extvibrapwm1_b_1", "extvibrapwm2_b_1");
+AB8505_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct abx500_function ab8505_functions[] = {
+	FUNCTION(sysclkreq),
+	FUNCTION(gpio),
+	FUNCTION(pwmout),
+	FUNCTION(adi2),
+	FUNCTION(extcpena),
+	FUNCTION(modsclsda),
+	FUNCTION(resethw),
+	FUNCTION(service),
+	FUNCTION(hiqclkena),
+	FUNCTION(pdm),
+	FUNCTION(uartdata),
+	FUNCTION(extvibra),
+	FUNCTION(extvibra),
+	FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB8505 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ *	ALTERNATE_FUNCTIONS(13,     4,      3,      4, 1, 0, 2),
+ *	means that pin AB8505_PIN_D18 (pin 13) supports 4 mux (default/ALT_A,
+ *	ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to
+ *	select the mux. ALTA, ALTB and ALTC val indicates values to write in
+ *	ALTERNATFUNC register. We need to specifies these values as SOC
+ *	designers didn't apply the same logic on how to select mux in the
+ *	ABx500 family.
+ *
+ *	As this pins supports at least ALT_B mux, default mux is
+ *	selected by writing 1 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ *	default	|       1       |          0          |          0
+ *	alt_A	|       0       |          0          |          1
+ *	alt_B	|       0       |          0          |          0
+ *	alt_C	|       0       |          1          |          0
+ *
+ *	ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED),
+ *	means that pin AB9540_PIN_R4 (pin 1) supports 2 mux, so only GPIOSEL
+ *	register is used to select the mux. As this pins doesn't support at
+ *	least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=0 | alternatfunc bit2=  | alternatfunc bit1=
+ *	default	|       0       |          0          |          0
+ *	alt_A	|       1       |          0          |          0
+ */
+
+struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
+	ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+	ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(3,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+	ALTERNATE_FUNCTIONS(4, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO4, bit 3 reserved */
+	ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5, bit 4 reserved */
+	ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6, bit 5 reserved */
+	ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7, bit 6 reserved */
+	ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8, bit 7 reserved */
+
+	ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9, bit 0 reserved */
+	ALTERNATE_FUNCTIONS(10,      1,      0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(11,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reseved */
+	ALTERNATE_FUNCTIONS(13,      4,      3,      4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+	ALTERNATE_FUNCTIONS(14,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(15, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 6 reserved */
+	ALTERNATE_FUNCTIONS(16, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 7 reserved  */
+	/*
+	 * pins 17 to 20 are special case, only bit 0 is used to select
+	 * alternate function for these 4 pins.
+	 * bits 1 to 3 are reserved
+	 */
+	ALTERNATE_FUNCTIONS(17,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(18,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(19,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(20,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(21, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO21, bit 4 reserved */
+	ALTERNATE_FUNCTIONS(22, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO22, bit 5 reserved */
+	ALTERNATE_FUNCTIONS(23, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO23, bit 6 reserved */
+	ALTERNATE_FUNCTIONS(24, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO24, bit 7 reserved */
+
+	ALTERNATE_FUNCTIONS(25, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO25, bit 0 reserved */
+	ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26, bit 1 reserved */
+	ALTERNATE_FUNCTIONS(27, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO27, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(28, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO28, bit 3 reserved */
+	ALTERNATE_FUNCTIONS(29, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO29, bit 4 reserved */
+	ALTERNATE_FUNCTIONS(30, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO30, bit 5 reserved */
+	ALTERNATE_FUNCTIONS(31, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO31, bit 6 reserved */
+	ALTERNATE_FUNCTIONS(32, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO32, bit 7 reserved */
+
+	ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33, bit 0 reserved */
+	ALTERNATE_FUNCTIONS(34,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(40,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7*/
+
+	ALTERNATE_FUNCTIONS(41,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(42, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO42, bit 1 reserved */
+	ALTERNATE_FUNCTIONS(43, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO43, bit 2 reserved */
+	ALTERNATE_FUNCTIONS(44, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO44, bit 3 reserved */
+	ALTERNATE_FUNCTIONS(45, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO45, bit 4 reserved */
+	ALTERNATE_FUNCTIONS(46, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO46, bit 5 reserved */
+	ALTERNATE_FUNCTIONS(47, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO47, bit 6 reserved */
+	ALTERNATE_FUNCTIONS(48, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO48, bit 7 reserved */
+
+	ALTERNATE_FUNCTIONS(49, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49, bit 0 reserved */
+	ALTERNATE_FUNCTIONS(50,	     1,      2, UNUSED, 1, 0, 0), /* GPIO50, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(51, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49, bit 0 reserved */
+	ALTERNATE_FUNCTIONS(52,	     3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(53,	     4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */
+};
+
+/*
+ * For AB8505 Only some GPIOs are interrupt capable, and they are
+ * organized in discontiguous clusters:
+ *
+ *	GPIO10 to GPIO11
+ *	GPIO13
+ *	GPIO40 and GPIO41
+ *	GPIO50
+ *	GPIO52 to GPIO53
+ */
+struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = {
+	GPIO_IRQ_CLUSTER(10, 11, AB8500_INT_GPIO10R),
+	GPIO_IRQ_CLUSTER(13, 13, AB8500_INT_GPIO13R),
+	GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
+	GPIO_IRQ_CLUSTER(50, 50, AB9540_INT_GPIO50R),
+	GPIO_IRQ_CLUSTER(52, 53, AB9540_INT_GPIO52R),
+};
+
+static struct abx500_pinctrl_soc_data ab8505_soc = {
+	.gpio_ranges = ab8505_pinranges,
+	.gpio_num_ranges = ARRAY_SIZE(ab8505_pinranges),
+	.pins = ab8505_pins,
+	.npins = ARRAY_SIZE(ab8505_pins),
+	.functions = ab8505_functions,
+	.nfunctions = ARRAY_SIZE(ab8505_functions),
+	.groups = ab8505_groups,
+	.ngroups = ARRAY_SIZE(ab8505_groups),
+	.alternate_functions = ab8505_alternate_functions,
+	.gpio_irq_cluster = ab8505_gpio_irq_cluster,
+	.ngpio_irq_cluster = ARRAY_SIZE(ab8505_gpio_irq_cluster),
+	.irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+	.irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+	.irq_gpio_factor = 1,
+};
+
+void
+abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc)
+{
+	*soc = &ab8505_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-ab8540.c b/drivers/pinctrl/pinctrl-ab8540.c
new file mode 100644
index 0000000..8ee1e8d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8540.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset)		(offset)
+
+#define AB8540_PIN_J16		ABX500_GPIO(1)
+#define AB8540_PIN_D17		ABX500_GPIO(2)
+#define AB8540_PIN_C12		ABX500_GPIO(3)
+#define AB8540_PIN_G12		ABX500_GPIO(4)
+/* hole */
+#define AB8540_PIN_D16		ABX500_GPIO(14)
+#define AB8540_PIN_F15		ABX500_GPIO(15)
+#define AB8540_PIN_J8		ABX500_GPIO(16)
+#define AB8540_PIN_K16		ABX500_GPIO(17)
+#define AB8540_PIN_G15		ABX500_GPIO(18)
+#define AB8540_PIN_F17		ABX500_GPIO(19)
+#define AB8540_PIN_E17		ABX500_GPIO(20)
+/* hole */
+#define AB8540_PIN_AA16		ABX500_GPIO(27)
+#define AB8540_PIN_W18		ABX500_GPIO(28)
+#define AB8540_PIN_Y15		ABX500_GPIO(29)
+#define AB8540_PIN_W16		ABX500_GPIO(30)
+#define AB8540_PIN_V15		ABX500_GPIO(31)
+#define AB8540_PIN_W17		ABX500_GPIO(32)
+/* hole */
+#define AB8540_PIN_D12		ABX500_GPIO(42)
+#define AB8540_PIN_P4		ABX500_GPIO(43)
+#define AB8540_PIN_AB1		ABX500_GPIO(44)
+#define AB8540_PIN_K7		ABX500_GPIO(45)
+#define AB8540_PIN_L7		ABX500_GPIO(46)
+#define AB8540_PIN_G10		ABX500_GPIO(47)
+#define AB8540_PIN_K12		ABX500_GPIO(48)
+/* hole */
+#define AB8540_PIN_N8		ABX500_GPIO(51)
+#define AB8540_PIN_P12		ABX500_GPIO(52)
+#define AB8540_PIN_K8		ABX500_GPIO(53)
+#define AB8540_PIN_J11		ABX500_GPIO(54)
+#define AB8540_PIN_AC2		ABX500_GPIO(55)
+#define AB8540_PIN_AB2		ABX500_GPIO(56)
+
+/* indicates the highest GPIO number */
+#define AB8540_GPIO_MAX_NUMBER	56
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8540_pins[] = {
+	PINCTRL_PIN(AB8540_PIN_J16, "GPIO1_J16"),
+	PINCTRL_PIN(AB8540_PIN_D17, "GPIO2_D17"),
+	PINCTRL_PIN(AB8540_PIN_C12, "GPIO3_C12"),
+	PINCTRL_PIN(AB8540_PIN_G12, "GPIO4_G12"),
+	/* hole */
+	PINCTRL_PIN(AB8540_PIN_D16, "GPIO14_D16"),
+	PINCTRL_PIN(AB8540_PIN_F15, "GPIO15_F15"),
+	PINCTRL_PIN(AB8540_PIN_J8, "GPIO16_J8"),
+	PINCTRL_PIN(AB8540_PIN_K16, "GPIO17_K16"),
+	PINCTRL_PIN(AB8540_PIN_G15, "GPIO18_G15"),
+	PINCTRL_PIN(AB8540_PIN_F17, "GPIO19_F17"),
+	PINCTRL_PIN(AB8540_PIN_E17, "GPIO20_E17"),
+	/* hole */
+	PINCTRL_PIN(AB8540_PIN_AA16, "GPIO27_AA16"),
+	PINCTRL_PIN(AB8540_PIN_W18, "GPIO28_W18"),
+	PINCTRL_PIN(AB8540_PIN_Y15, "GPIO29_Y15"),
+	PINCTRL_PIN(AB8540_PIN_W16, "GPIO30_W16"),
+	PINCTRL_PIN(AB8540_PIN_V15, "GPIO31_V15"),
+	PINCTRL_PIN(AB8540_PIN_W17, "GPIO32_W17"),
+	/* hole */
+	PINCTRL_PIN(AB8540_PIN_D12, "GPIO42_D12"),
+	PINCTRL_PIN(AB8540_PIN_P4, "GPIO43_P4"),
+	PINCTRL_PIN(AB8540_PIN_AB1, "GPIO44_AB1"),
+	PINCTRL_PIN(AB8540_PIN_K7, "GPIO45_K7"),
+	PINCTRL_PIN(AB8540_PIN_L7, "GPIO46_L7"),
+	PINCTRL_PIN(AB8540_PIN_G10, "GPIO47_G10"),
+	PINCTRL_PIN(AB8540_PIN_K12, "GPIO48_K12"),
+	/* hole */
+	PINCTRL_PIN(AB8540_PIN_N8, "GPIO51_N8"),
+	PINCTRL_PIN(AB8540_PIN_P12, "GPIO52_P12"),
+	PINCTRL_PIN(AB8540_PIN_K8, "GPIO53_K8"),
+	PINCTRL_PIN(AB8540_PIN_J11, "GPIO54_J11"),
+	PINCTRL_PIN(AB8540_PIN_AC2, "GPIO55_AC2"),
+	PINCTRL_PIN(AB8540_PIN_AB2, "GPIO56_AB2"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8540_pinranges[] = {
+	ABX500_PINRANGE(1, 4, ABX500_ALT_A),
+	ABX500_PINRANGE(14, 7, ABX500_ALT_A),
+	ABX500_PINRANGE(27, 6, ABX500_ALT_A),
+	ABX500_PINRANGE(42, 7, ABX500_ALT_A),
+	ABX500_PINRANGE(51, 6, ABX500_ALT_A),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8540_PIN_J16 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8540_PIN_D17 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8540_PIN_C12 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB8540_PIN_G12 };
+static const unsigned pwmout1_d_1_pins[] = { AB8540_PIN_D16 };
+static const unsigned pwmout2_d_1_pins[] = { AB8540_PIN_F15 };
+static const unsigned pwmout3_d_1_pins[] = { AB8540_PIN_J8 };
+
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB8540_PIN_K16, AB8540_PIN_G15,
+					AB8540_PIN_F17, AB8540_PIN_E17 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB8540_PIN_AA16, AB8540_PIN_W18 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB8540_PIN_Y15, AB8540_PIN_W16 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB8540_PIN_V15, AB8540_PIN_W17 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB8540_PIN_D12 };
+static const unsigned batremn_d_1_pins[] = { AB8540_PIN_P4 };
+static const unsigned service_d_1_pins[] = { AB8540_PIN_AB1 };
+static const unsigned pwrctrl0_d_1_pins[] = { AB8540_PIN_K7 };
+static const unsigned pwrctrl1_d_1_pins[] = { AB8540_PIN_L7 };
+static const unsigned pwmextvibra1_d_1_pins[] = { AB8540_PIN_G10 };
+static const unsigned pwmextvibra2_d_1_pins[] = { AB8540_PIN_K12 };
+static const unsigned gpio1_vbat_d_1_pins[] = { AB8540_PIN_N8 };
+static const unsigned gpio2_vbat_d_1_pins[] = { AB8540_PIN_P12 };
+static const unsigned gpio3_vbat_d_1_pins[] = { AB8540_PIN_K8 };
+static const unsigned gpio4_vbat_d_1_pins[] = { AB8540_PIN_J11 };
+static const unsigned pdmclkdat_d_1_pins[] = { AB8540_PIN_AC2, AB8540_PIN_AB2 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8540_PIN_J16 };
+static const unsigned gpio2_a_1_pins[] = { AB8540_PIN_D17 };
+static const unsigned gpio3_a_1_pins[] = { AB8540_PIN_C12 };
+static const unsigned gpio4_a_1_pins[] = { AB8540_PIN_G12 };
+static const unsigned gpio14_a_1_pins[] = { AB8540_PIN_D16 };
+static const unsigned gpio15_a_1_pins[] = { AB8540_PIN_F15 };
+static const unsigned gpio16_a_1_pins[] = { AB8540_PIN_J8 };
+static const unsigned gpio17_a_1_pins[] = { AB8540_PIN_K16 };
+static const unsigned gpio18_a_1_pins[] = { AB8540_PIN_G15 };
+static const unsigned gpio19_a_1_pins[] = { AB8540_PIN_F17 };
+static const unsigned gpio20_a_1_pins[] = { AB8540_PIN_E17 };
+static const unsigned gpio27_a_1_pins[] = { AB8540_PIN_AA16 };
+static const unsigned gpio28_a_1_pins[] = { AB8540_PIN_W18 };
+static const unsigned gpio29_a_1_pins[] = { AB8540_PIN_Y15 };
+static const unsigned gpio30_a_1_pins[] = { AB8540_PIN_W16 };
+static const unsigned gpio31_a_1_pins[] = { AB8540_PIN_V15 };
+static const unsigned gpio32_a_1_pins[] = { AB8540_PIN_W17 };
+static const unsigned gpio42_a_1_pins[] = { AB8540_PIN_D12 };
+static const unsigned gpio43_a_1_pins[] = { AB8540_PIN_P4 };
+static const unsigned gpio44_a_1_pins[] = { AB8540_PIN_AB1 };
+static const unsigned gpio45_a_1_pins[] = { AB8540_PIN_K7 };
+static const unsigned gpio46_a_1_pins[] = { AB8540_PIN_L7 };
+static const unsigned gpio47_a_1_pins[] = { AB8540_PIN_G10 };
+static const unsigned gpio48_a_1_pins[] = { AB8540_PIN_K12 };
+static const unsigned gpio51_a_1_pins[] = { AB8540_PIN_N8 };
+static const unsigned gpio52_a_1_pins[] = { AB8540_PIN_P12 };
+static const unsigned gpio53_a_1_pins[] = { AB8540_PIN_K8 };
+static const unsigned gpio54_a_1_pins[] = { AB8540_PIN_J11 };
+static const unsigned gpio55_a_1_pins[] = { AB8540_PIN_AC2 };
+static const unsigned gpio56_a_1_pins[] = { AB8540_PIN_AB2 };
+
+#define AB8540_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,		\
+			.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8540_groups[] = {
+	/* default column */
+	AB8540_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(batremn_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(service_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwrctrl0_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwrctrl1_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwmextvibra1_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pwmextvibra2_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(gpio1_vbat_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(gpio2_vbat_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(gpio3_vbat_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(gpio4_vbat_d_1, ABX500_DEFAULT),
+	AB8540_PIN_GROUP(pdmclkdat_d_1, ABX500_DEFAULT),
+	/* Altfunction A column */
+	AB8540_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio43_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio44_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio45_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio46_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio47_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio48_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio51_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio52_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio53_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio54_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio55_a_1, ABX500_ALT_A),
+	AB8540_PIN_GROUP(gpio56_a_1, ABX500_ALT_A),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8540_FUNC_GROUPS(a, b...)	   \
+static const char * const a##_groups[] = { b };
+
+AB8540_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+		"sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1");
+AB8540_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+		"gpio14_a_1", "gpio15_a_1", "gpio16_a_1", "gpio17_a_1",
+		"gpio18_a_1", "gpio19_a_1", "gpio20_a_1", "gpio27_a_1",
+		"gpio28_a_1", "gpio29_a_1", "gpio30_a_1", "gpio31_a_1",
+		"gpio32_a_1", "gpio42_a_1", "gpio43_a_1", "gpio44_a_1",
+		"gpio45_a_1", "gpio46_a_1", "gpio47_a_1", "gpio48_a_1",
+		"gpio51_a_1", "gpio52_a_1", "gpio53_a_1", "gpio54_a_1",
+		"gpio55_a_1", "gpio56_a_1");
+AB8540_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB8540_FUNC_GROUPS(adi1, "adi1_d_1");
+AB8540_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB8540_FUNC_GROUPS(batremn, "batremn_d_1");
+AB8540_FUNC_GROUPS(service, "service_d_1");
+AB8540_FUNC_GROUPS(pwrctrl, "pwrctrl0_d_1", "pwrctrl1_d_1");
+AB8540_FUNC_GROUPS(pwmextvibra, "pwmextvibra1_d_1", "pwmextvibra2_d_1");
+AB8540_FUNC_GROUPS(gpio_vbat, "gpio1_vbat_d_1", "gpio2_vbat_d_1",
+		"gpio3_vbat_d_1", "gpio4_vbat_d_1");
+AB8540_FUNC_GROUPS(pdm, "pdmclkdat_d_1");
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct abx500_function ab8540_functions[] = {
+	FUNCTION(sysclkreq),
+	FUNCTION(gpio),
+	FUNCTION(pwmout),
+	FUNCTION(adi1),
+	FUNCTION(dmic),
+	FUNCTION(batremn),
+	FUNCTION(service),
+	FUNCTION(pwrctrl),
+	FUNCTION(pwmextvibra),
+	FUNCTION(gpio_vbat),
+	FUNCTION(pdm),
+};
+
+/*
+ * this table translates what's is in the AB8540 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ * AB8540 only supports DEFAULT and ALTA functions, so ALTERNATFUNC
+ * registers is not used
+ *
+ */
+
+struct alternate_functions ab8540_alternate_functions[AB8540_GPIO_MAX_NUMBER + 1] = {
+	/* GPIOSEL1 - bit 4-7 reserved */
+	ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+	ALTERNATE_FUNCTIONS(1,	    0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(3,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+	ALTERNATE_FUNCTIONS(4,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+	ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+	ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6 */
+	ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7 */
+	ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8 */
+	/* GPIOSEL2 - bit 0-4 reserved */
+	ALTERNATE_FUNCTIONS(9,  UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9 */
+	ALTERNATE_FUNCTIONS(10, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO10 */
+	ALTERNATE_FUNCTIONS(11, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO11 */
+	ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12 */
+	ALTERNATE_FUNCTIONS(13, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO13 */
+	ALTERNATE_FUNCTIONS(14,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(15,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(16,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+	/* GPIOSEL3 - bit 4-7 reserved */
+	ALTERNATE_FUNCTIONS(17,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(18,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(19,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(20,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(21, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO21 */
+	ALTERNATE_FUNCTIONS(22, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO22 */
+	ALTERNATE_FUNCTIONS(23, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO23 */
+	ALTERNATE_FUNCTIONS(24, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO24 */
+	/* GPIOSEL4 - bit 0-1 reserved */
+	ALTERNATE_FUNCTIONS(25, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO25 */
+	ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26 */
+	ALTERNATE_FUNCTIONS(27,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(28,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(29,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(30,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(31,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(32,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+	/* GPIOSEL5 - bit 0-7 reserved */
+	ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+	ALTERNATE_FUNCTIONS(34, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO34 */
+	ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35 */
+	ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36 */
+	ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37 */
+	ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38 */
+	ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39 */
+	ALTERNATE_FUNCTIONS(40, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO40 */
+	/* GPIOSEL6 - bit 0 reserved */
+	ALTERNATE_FUNCTIONS(41, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO41 */
+	ALTERNATE_FUNCTIONS(42,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(43,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO43, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(44,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO44, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(45,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO45, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(46,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO46, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(47,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO47, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(48,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO48, altA controlled by bit 7 */
+	/* GPIOSEL7 - bit 0-1 reserved */
+	ALTERNATE_FUNCTIONS(49, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49 */
+	ALTERNATE_FUNCTIONS(50, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO50 */
+	ALTERNATE_FUNCTIONS(51,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO51, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(52,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(53,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(54,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO54, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(55,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO55, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(56,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO56, altA controlled by bit 7 */
+};
+
+static struct pullud ab8540_pullud = {
+	.first_pin = 51,	/* GPIO1_VBAT */
+	.last_pin = 54,		/* GPIO4_VBAT */
+};
+
+/*
+ * For AB8540 Only some GPIOs are interrupt capable:
+ *	GPIO43 to GPIO44
+ *	GPIO51 to GPIO54
+ */
+struct abx500_gpio_irq_cluster ab8540_gpio_irq_cluster[] = {
+	GPIO_IRQ_CLUSTER(43, 43, AB8540_INT_GPIO43F),
+	GPIO_IRQ_CLUSTER(44, 44, AB8540_INT_GPIO44F),
+	GPIO_IRQ_CLUSTER(51, 54, AB9540_INT_GPIO51R),
+};
+
+static struct abx500_pinctrl_soc_data ab8540_soc = {
+	.gpio_ranges = ab8540_pinranges,
+	.gpio_num_ranges = ARRAY_SIZE(ab8540_pinranges),
+	.pins = ab8540_pins,
+	.npins = ARRAY_SIZE(ab8540_pins),
+	.functions = ab8540_functions,
+	.nfunctions = ARRAY_SIZE(ab8540_functions),
+	.groups = ab8540_groups,
+	.ngroups = ARRAY_SIZE(ab8540_groups),
+	.alternate_functions = ab8540_alternate_functions,
+	.pullud = &ab8540_pullud,
+	.gpio_irq_cluster = ab8540_gpio_irq_cluster,
+	.ngpio_irq_cluster = ARRAY_SIZE(ab8540_gpio_irq_cluster),
+	.irq_gpio_rising_offset = AB8540_INT_GPIO43R,
+	.irq_gpio_falling_offset = AB8540_INT_GPIO43F,
+	.irq_gpio_factor = 2,
+};
+
+void
+abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc)
+{
+	*soc = &ab8540_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-ab9540.c b/drivers/pinctrl/pinctrl-ab9540.c
new file mode 100644
index 0000000..7610bd0
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab9540.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset)		(offset)
+
+#define AB9540_PIN_R4		ABX500_GPIO(1)
+#define AB9540_PIN_V3		ABX500_GPIO(2)
+#define AB9540_PIN_T4		ABX500_GPIO(3)
+#define AB9540_PIN_T5		ABX500_GPIO(4)
+/* hole */
+#define AB9540_PIN_B18		ABX500_GPIO(10)
+#define AB9540_PIN_C18		ABX500_GPIO(11)
+/* hole */
+#define AB9540_PIN_D18		ABX500_GPIO(13)
+#define AB9540_PIN_B19		ABX500_GPIO(14)
+#define AB9540_PIN_C19		ABX500_GPIO(15)
+#define AB9540_PIN_D19		ABX500_GPIO(16)
+#define AB9540_PIN_R3		ABX500_GPIO(17)
+#define AB9540_PIN_T2		ABX500_GPIO(18)
+#define AB9540_PIN_U2		ABX500_GPIO(19)
+#define AB9540_PIN_V2		ABX500_GPIO(20)
+#define AB9540_PIN_N17		ABX500_GPIO(21)
+#define AB9540_PIN_N16		ABX500_GPIO(22)
+#define AB9540_PIN_M19		ABX500_GPIO(23)
+#define AB9540_PIN_T3		ABX500_GPIO(24)
+#define AB9540_PIN_W2		ABX500_GPIO(25)
+/* hole */
+#define AB9540_PIN_H4		ABX500_GPIO(27)
+#define AB9540_PIN_F1		ABX500_GPIO(28)
+#define AB9540_PIN_F4		ABX500_GPIO(29)
+#define AB9540_PIN_F2		ABX500_GPIO(30)
+#define AB9540_PIN_E4		ABX500_GPIO(31)
+#define AB9540_PIN_F3		ABX500_GPIO(32)
+/* hole */
+#define AB9540_PIN_J13		ABX500_GPIO(34)
+/* hole */
+#define AB9540_PIN_L17		ABX500_GPIO(40)
+#define AB9540_PIN_L16		ABX500_GPIO(41)
+#define AB9540_PIN_W3		ABX500_GPIO(42)
+#define AB9540_PIN_N4		ABX500_GPIO(50)
+#define AB9540_PIN_G12		ABX500_GPIO(51)
+#define AB9540_PIN_E17		ABX500_GPIO(52)
+#define AB9540_PIN_D11		ABX500_GPIO(53)
+#define AB9540_PIN_M18		ABX500_GPIO(54)
+
+/* indicates the highest GPIO number */
+#define AB9540_GPIO_MAX_NUMBER	54
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab9540_pins[] = {
+	PINCTRL_PIN(AB9540_PIN_R4, "GPIO1_R4"),
+	PINCTRL_PIN(AB9540_PIN_V3, "GPIO2_V3"),
+	PINCTRL_PIN(AB9540_PIN_T4, "GPIO3_T4"),
+	PINCTRL_PIN(AB9540_PIN_T5, "GPIO4_T5"),
+	/* hole */
+	PINCTRL_PIN(AB9540_PIN_B18, "GPIO10_B18"),
+	PINCTRL_PIN(AB9540_PIN_C18, "GPIO11_C18"),
+	/* hole */
+	PINCTRL_PIN(AB9540_PIN_D18, "GPIO13_D18"),
+	PINCTRL_PIN(AB9540_PIN_B19, "GPIO14_B19"),
+	PINCTRL_PIN(AB9540_PIN_C19, "GPIO15_C19"),
+	PINCTRL_PIN(AB9540_PIN_D19, "GPIO16_D19"),
+	PINCTRL_PIN(AB9540_PIN_R3, "GPIO17_R3"),
+	PINCTRL_PIN(AB9540_PIN_T2, "GPIO18_T2"),
+	PINCTRL_PIN(AB9540_PIN_U2, "GPIO19_U2"),
+	PINCTRL_PIN(AB9540_PIN_V2, "GPIO20_V2"),
+	PINCTRL_PIN(AB9540_PIN_N17, "GPIO21_N17"),
+	PINCTRL_PIN(AB9540_PIN_N16, "GPIO22_N16"),
+	PINCTRL_PIN(AB9540_PIN_M19, "GPIO23_M19"),
+	PINCTRL_PIN(AB9540_PIN_T3, "GPIO24_T3"),
+	PINCTRL_PIN(AB9540_PIN_W2, "GPIO25_W2"),
+	/* hole */
+	PINCTRL_PIN(AB9540_PIN_H4, "GPIO27_H4"),
+	PINCTRL_PIN(AB9540_PIN_F1, "GPIO28_F1"),
+	PINCTRL_PIN(AB9540_PIN_F4, "GPIO29_F4"),
+	PINCTRL_PIN(AB9540_PIN_F2, "GPIO30_F2"),
+	PINCTRL_PIN(AB9540_PIN_E4, "GPIO31_E4"),
+	PINCTRL_PIN(AB9540_PIN_F3, "GPIO32_F3"),
+	/* hole */
+	PINCTRL_PIN(AB9540_PIN_J13, "GPIO34_J13"),
+	/* hole */
+	PINCTRL_PIN(AB9540_PIN_L17, "GPIO40_L17"),
+	PINCTRL_PIN(AB9540_PIN_L16, "GPIO41_L16"),
+	PINCTRL_PIN(AB9540_PIN_W3, "GPIO42_W3"),
+	PINCTRL_PIN(AB9540_PIN_N4, "GPIO50_N4"),
+	PINCTRL_PIN(AB9540_PIN_G12, "GPIO51_G12"),
+	PINCTRL_PIN(AB9540_PIN_E17, "GPIO52_E17"),
+	PINCTRL_PIN(AB9540_PIN_D11, "GPIO53_D11"),
+	PINCTRL_PIN(AB9540_PIN_M18, "GPIO60_M18"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab9540_pinranges[] = {
+	ABX500_PINRANGE(1, 4, ABX500_ALT_A),
+	ABX500_PINRANGE(10, 2, ABX500_DEFAULT),
+	ABX500_PINRANGE(13, 1, ABX500_DEFAULT),
+	ABX500_PINRANGE(14, 12, ABX500_ALT_A),
+	ABX500_PINRANGE(27, 6, ABX500_ALT_A),
+	ABX500_PINRANGE(34, 1, ABX500_ALT_A),
+	ABX500_PINRANGE(40, 3, ABX500_ALT_A),
+	ABX500_PINRANGE(50, 1, ABX500_DEFAULT),
+	ABX500_PINRANGE(51, 3, ABX500_ALT_A),
+	ABX500_PINRANGE(54, 1, ABX500_DEFAULT),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB9540_PIN_R4 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB9540_PIN_V3 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB9540_PIN_T4 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB9540_PIN_T5 };
+static const unsigned gpio10_d_1_pins[] = { AB9540_PIN_B18 };
+static const unsigned gpio11_d_1_pins[] = { AB9540_PIN_C18 };
+static const unsigned gpio13_d_1_pins[] = { AB9540_PIN_D18 };
+static const unsigned pwmout1_d_1_pins[] = { AB9540_PIN_B19 };
+static const unsigned pwmout2_d_1_pins[] = { AB9540_PIN_C19 };
+static const unsigned pwmout3_d_1_pins[] = { AB9540_PIN_D19 };
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB9540_PIN_R3, AB9540_PIN_T2,
+					AB9540_PIN_U2, AB9540_PIN_V2 };
+/* USBUICC */
+static const unsigned usbuicc_d_1_pins[] = { AB9540_PIN_N17, AB9540_PIN_N16,
+					AB9540_PIN_M19 };
+static const unsigned sysclkreq7_d_1_pins[] = { AB9540_PIN_T3 };
+static const unsigned sysclkreq8_d_1_pins[] = { AB9540_PIN_W2 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB9540_PIN_H4, AB9540_PIN_F1 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB9540_PIN_F4, AB9540_PIN_F2 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB9540_PIN_E4, AB9540_PIN_F3 };
+static const unsigned extcpena_d_1_pins[] = { AB9540_PIN_J13 };
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB9540_PIN_L17, AB9540_PIN_L16 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB9540_PIN_W3 };
+static const unsigned gpio50_d_1_pins[] = { AB9540_PIN_N4 };
+static const unsigned batremn_d_1_pins[] = { AB9540_PIN_G12 };
+static const unsigned resethw_d_1_pins[] = { AB9540_PIN_E17 };
+static const unsigned service_d_1_pins[] = { AB9540_PIN_D11 };
+static const unsigned gpio60_d_1_pins[] = { AB9540_PIN_M18 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB9540_PIN_R4 };
+static const unsigned gpio2_a_1_pins[] = { AB9540_PIN_V3 };
+static const unsigned gpio3_a_1_pins[] = { AB9540_PIN_T4 };
+static const unsigned gpio4_a_1_pins[] = { AB9540_PIN_T5 };
+static const unsigned hiqclkena_a_1_pins[] = { AB9540_PIN_B18 };
+static const unsigned pdmclk_a_1_pins[] = { AB9540_PIN_C18 };
+static const unsigned uartdata_a_1_pins[] = { AB9540_PIN_D18, AB9540_PIN_N4 };
+static const unsigned gpio14_a_1_pins[] = { AB9540_PIN_B19 };
+static const unsigned gpio15_a_1_pins[] = { AB9540_PIN_C19 };
+static const unsigned gpio16_a_1_pins[] = { AB9540_PIN_D19 };
+static const unsigned gpio17_a_1_pins[] = { AB9540_PIN_R3 };
+static const unsigned gpio18_a_1_pins[] = { AB9540_PIN_T2 };
+static const unsigned gpio19_a_1_pins[] = { AB9540_PIN_U2 };
+static const unsigned gpio20_a_1_pins[] = { AB9540_PIN_V2 };
+static const unsigned gpio21_a_1_pins[] = { AB9540_PIN_N17 };
+static const unsigned gpio22_a_1_pins[] = { AB9540_PIN_N16 };
+static const unsigned gpio23_a_1_pins[] = { AB9540_PIN_M19 };
+static const unsigned gpio24_a_1_pins[] = { AB9540_PIN_T3 };
+static const unsigned gpio25_a_1_pins[] = { AB9540_PIN_W2 };
+static const unsigned gpio27_a_1_pins[] = { AB9540_PIN_H4 };
+static const unsigned gpio28_a_1_pins[] = { AB9540_PIN_F1 };
+static const unsigned gpio29_a_1_pins[] = { AB9540_PIN_F4 };
+static const unsigned gpio30_a_1_pins[] = { AB9540_PIN_F2 };
+static const unsigned gpio31_a_1_pins[] = { AB9540_PIN_E4 };
+static const unsigned gpio32_a_1_pins[] = { AB9540_PIN_F3 };
+static const unsigned gpio34_a_1_pins[] = { AB9540_PIN_J13 };
+static const unsigned gpio40_a_1_pins[] = { AB9540_PIN_L17 };
+static const unsigned gpio41_a_1_pins[] = { AB9540_PIN_L16 };
+static const unsigned gpio42_a_1_pins[] = { AB9540_PIN_W3 };
+static const unsigned gpio51_a_1_pins[] = { AB9540_PIN_G12 };
+static const unsigned gpio52_a_1_pins[] = { AB9540_PIN_E17 };
+static const unsigned gpio53_a_1_pins[] = { AB9540_PIN_D11 };
+static const unsigned usbuiccpd_a_1_pins[] = { AB9540_PIN_M18 };
+
+/* Altfunction B colum */
+static const unsigned pdmdata_b_1_pins[] = { AB9540_PIN_B18 };
+static const unsigned pwmextvibra1_b_1_pins[] = { AB9540_PIN_D18 };
+static const unsigned pwmextvibra2_b_1_pins[] = { AB9540_PIN_N4 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB9540_PIN_D18 };
+
+#define AB9540_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,		\
+			.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab9540_groups[] = {
+	/* default column */
+	AB9540_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(usbuicc_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(sysclkreq7_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(sysclkreq8_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(gpio50_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(batremn_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(resethw_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(service_d_1, ABX500_DEFAULT),
+	AB9540_PIN_GROUP(gpio60_d_1, ABX500_DEFAULT),
+
+	/* Altfunction A column */
+	AB9540_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(hiqclkena_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(pdmclk_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(uartdata_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio21_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio22_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio23_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio24_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio25_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio51_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio52_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(gpio53_a_1, ABX500_ALT_A),
+	AB9540_PIN_GROUP(usbuiccpd_a_1, ABX500_ALT_A),
+
+	/* Altfunction B column */
+	AB9540_PIN_GROUP(pdmdata_b_1, ABX500_ALT_B),
+	AB9540_PIN_GROUP(pwmextvibra1_b_1, ABX500_ALT_B),
+	AB9540_PIN_GROUP(pwmextvibra2_b_1, ABX500_ALT_B),
+
+	/* Altfunction C column */
+	AB9540_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB9540_FUNC_GROUPS(a, b...)	   \
+static const char * const a##_groups[] = { b };
+
+AB9540_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+		"sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1",
+		"sysclkreq7_d_1", "sysclkreq8_d_1");
+AB9540_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+		"gpio10_d_1", "gpio11_d_1", "gpio13_d_1", "gpio14_a_1",
+		"gpio15_a_1", "gpio16_a_1", "gpio17_a_1", "gpio18_a_1",
+		"gpio19_a_1", "gpio20_a_1", "gpio21_a_1", "gpio22_a_1",
+		"gpio23_a_1", "gpio24_a_1", "gpio25_a_1", "gpio27_a_1",
+		"gpio28_a_1", "gpio29_a_1", "gpio30_a_1", "gpio31_a_1",
+		"gpio32_a_1", "gpio34_a_1", "gpio40_a_1", "gpio41_a_1",
+		"gpio42_a_1", "gpio50_d_1", "gpio51_a_1", "gpio52_a_1",
+		"gpio53_a_1", "gpio60_d_1");
+AB9540_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB9540_FUNC_GROUPS(adi1, "adi1_d_1");
+AB9540_FUNC_GROUPS(usbuicc, "usbuicc_d_1", "usbuiccpd_a_1");
+AB9540_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB9540_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB9540_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB9540_FUNC_GROUPS(batremn, "batremn_d_1");
+AB9540_FUNC_GROUPS(resethw, "resethw_d_1");
+AB9540_FUNC_GROUPS(service, "service_d_1");
+AB9540_FUNC_GROUPS(hiqclkena, "hiqclkena_a_1");
+AB9540_FUNC_GROUPS(pdm, "pdmdata_b_1", "pdmclk_a_1");
+AB9540_FUNC_GROUPS(uartdata, "uartdata_a_1");
+AB9540_FUNC_GROUPS(pwmextvibra, "pwmextvibra1_b_1", "pwmextvibra2_b_1");
+AB9540_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct abx500_function ab9540_functions[] = {
+	FUNCTION(sysclkreq),
+	FUNCTION(gpio),
+	FUNCTION(pwmout),
+	FUNCTION(adi1),
+	FUNCTION(usbuicc),
+	FUNCTION(dmic),
+	FUNCTION(extcpena),
+	FUNCTION(modsclsda),
+	FUNCTION(batremn),
+	FUNCTION(resethw),
+	FUNCTION(service),
+	FUNCTION(hiqclkena),
+	FUNCTION(pdm),
+	FUNCTION(uartdata),
+	FUNCTION(pwmextvibra),
+	FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB9540 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ *	ALTERNATE_FUNCTIONS(13,     4,      3,      4, 1, 0, 2),
+ *	means that pin AB9540_PIN_D18 (pin 13) supports 4 mux (default/ALT_A,
+ *	ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to
+ *	select the mux. ALTA, ALTB and ALTC val indicates values to write in
+ *	ALTERNATFUNC register. We need to specifies these values as SOC
+ *	designers didn't apply the same logic on how to select mux in the
+ *	ABx500 family.
+ *
+ *	As this pins supports at least ALT_B mux, default mux is
+ *	selected by writing 1 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ *	default	|       1       |          0          |          0
+ *	alt_A	|       0       |          0          |          1
+ *	alt_B	|       0       |          0          |          0
+ *	alt_C	|       0       |          1          |          0
+ *
+ *	ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED),
+ *	means that pin AB9540_PIN_R4 (pin 1) supports 2 mux, so only GPIOSEL
+ *	register is used to select the mux. As this pins doesn't support at
+ *	least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ *		| GPIOSEL bit=0 | alternatfunc bit2=  | alternatfunc bit1=
+ *	default	|       0       |          0          |          0
+ *	alt_A	|       1       |          0          |          0
+ */
+
+struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1] = {
+	/* GPIOSEL1 - bits 4-7 are reserved */
+	ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+	ALTERNATE_FUNCTIONS(1,	    0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(3,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+	ALTERNATE_FUNCTIONS(4,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+	ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+	ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6 */
+	ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7 */
+	ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8 */
+	/* GPIOSEL2 - bits 0 and 3 are reserved */
+	ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9 */
+	ALTERNATE_FUNCTIONS(10,      1,      0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(11,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12 */
+	ALTERNATE_FUNCTIONS(13,      4,      3,      4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+	ALTERNATE_FUNCTIONS(14,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(15,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(16,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+	/* GPIOSEL3 - bit 1-3 reserved
+	 * pins 17 to 20 are special case, only bit 0 is used to select
+	 * alternate function for these 4 pins.
+	 * bits 1 to 3 are reserved
+	 */
+	ALTERNATE_FUNCTIONS(17,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(18,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(19,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(20,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(21,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO21, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(22,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO22, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(23,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO23, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(24,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO24, altA controlled by bit 7 */
+	/* GPIOSEL4 - bit 1 reserved */
+	ALTERNATE_FUNCTIONS(25,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO25, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26 */
+	ALTERNATE_FUNCTIONS(27,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(28,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(29,      4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(30,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+	ALTERNATE_FUNCTIONS(31,      6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+	ALTERNATE_FUNCTIONS(32,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+	/* GPIOSEL5 - bit 0, 2-6 are reserved */
+	ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+	ALTERNATE_FUNCTIONS(34,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35 */
+	ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36 */
+	ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37 */
+	ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38 */
+	ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39 */
+	ALTERNATE_FUNCTIONS(40,      7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7 */
+	/* GPIOSEL6 - bit 2-7 are reserved */
+	ALTERNATE_FUNCTIONS(41,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+	ALTERNATE_FUNCTIONS(42,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(43, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO43 */
+	ALTERNATE_FUNCTIONS(44, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO44 */
+	ALTERNATE_FUNCTIONS(45, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO45 */
+	ALTERNATE_FUNCTIONS(46, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO46 */
+	ALTERNATE_FUNCTIONS(47, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO47 */
+	ALTERNATE_FUNCTIONS(48, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO48 */
+	/*
+	 * GPIOSEL7 - bit 0 and 6-7 are reserved
+	 * special case with GPIO60, wich is located at offset 5 of gpiosel7
+	 * don't know why it has been called GPIO60 in AB9540 datasheet,
+	 * GPIO54 would be logical..., so at SOC point of view we consider
+	 * GPIO60 = GPIO54
+	 */
+	ALTERNATE_FUNCTIONS(49,      0, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49 */
+	ALTERNATE_FUNCTIONS(50,      1,	     2, UNUSED, 1, 0, 0), /* GPIO50, altA and altB controlled by bit 1 */
+	ALTERNATE_FUNCTIONS(51,	     2, UNUSED, UNUSED, 0, 0, 0), /* GPIO51, altA controlled by bit 2 */
+	ALTERNATE_FUNCTIONS(52,      3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */
+	ALTERNATE_FUNCTIONS(53,	     4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */
+	ALTERNATE_FUNCTIONS(54,	     5, UNUSED, UNUSED, 0, 0, 0), /* GPIO54 = GPIO60, altA controlled by bit 5 */
+};
+
+struct abx500_gpio_irq_cluster ab9540_gpio_irq_cluster[] = {
+	GPIO_IRQ_CLUSTER(10, 13, AB8500_INT_GPIO10R),
+	GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
+	GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
+	GPIO_IRQ_CLUSTER(50, 54, AB9540_INT_GPIO50R),
+};
+
+static struct abx500_pinctrl_soc_data ab9540_soc = {
+	.gpio_ranges = ab9540_pinranges,
+	.gpio_num_ranges = ARRAY_SIZE(ab9540_pinranges),
+	.pins = ab9540_pins,
+	.npins = ARRAY_SIZE(ab9540_pins),
+	.functions = ab9540_functions,
+	.nfunctions = ARRAY_SIZE(ab9540_functions),
+	.groups = ab9540_groups,
+	.ngroups = ARRAY_SIZE(ab9540_groups),
+	.alternate_functions = ab9540alternate_functions,
+	.gpio_irq_cluster = ab9540_gpio_irq_cluster,
+	.ngpio_irq_cluster = ARRAY_SIZE(ab9540_gpio_irq_cluster),
+	.irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+	.irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+	.irq_gpio_factor = 1,
+};
+
+void
+abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc)
+{
+	*soc = &ab9540_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
new file mode 100644
index 0000000..caecdd3
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2013
+ *
+ * Author: Patrice Chotard <patrice.chotard@st.com>
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "pinctrl-abx500.h"
+
+/*
+ * The AB9540 and AB8540 GPIO support are extended versions
+ * of the AB8500 GPIO support.
+ * The AB9540 supports an additional (7th) register so that
+ * more GPIO may be configured and used.
+ * The AB8540 supports 4 new gpios (GPIOx_VBAT) that have
+ * internal pull-up and pull-down capabilities.
+ */
+
+/*
+ * GPIO registers offset
+ * Bank: 0x10
+ */
+#define AB8500_GPIO_SEL1_REG	0x00
+#define AB8500_GPIO_SEL2_REG	0x01
+#define AB8500_GPIO_SEL3_REG	0x02
+#define AB8500_GPIO_SEL4_REG	0x03
+#define AB8500_GPIO_SEL5_REG	0x04
+#define AB8500_GPIO_SEL6_REG	0x05
+#define AB9540_GPIO_SEL7_REG	0x06
+
+#define AB8500_GPIO_DIR1_REG	0x10
+#define AB8500_GPIO_DIR2_REG	0x11
+#define AB8500_GPIO_DIR3_REG	0x12
+#define AB8500_GPIO_DIR4_REG	0x13
+#define AB8500_GPIO_DIR5_REG	0x14
+#define AB8500_GPIO_DIR6_REG	0x15
+#define AB9540_GPIO_DIR7_REG	0x16
+
+#define AB8500_GPIO_OUT1_REG	0x20
+#define AB8500_GPIO_OUT2_REG	0x21
+#define AB8500_GPIO_OUT3_REG	0x22
+#define AB8500_GPIO_OUT4_REG	0x23
+#define AB8500_GPIO_OUT5_REG	0x24
+#define AB8500_GPIO_OUT6_REG	0x25
+#define AB9540_GPIO_OUT7_REG	0x26
+
+#define AB8500_GPIO_PUD1_REG	0x30
+#define AB8500_GPIO_PUD2_REG	0x31
+#define AB8500_GPIO_PUD3_REG	0x32
+#define AB8500_GPIO_PUD4_REG	0x33
+#define AB8500_GPIO_PUD5_REG	0x34
+#define AB8500_GPIO_PUD6_REG	0x35
+#define AB9540_GPIO_PUD7_REG	0x36
+
+#define AB8500_GPIO_IN1_REG	0x40
+#define AB8500_GPIO_IN2_REG	0x41
+#define AB8500_GPIO_IN3_REG	0x42
+#define AB8500_GPIO_IN4_REG	0x43
+#define AB8500_GPIO_IN5_REG	0x44
+#define AB8500_GPIO_IN6_REG	0x45
+#define AB9540_GPIO_IN7_REG	0x46
+#define AB8540_GPIO_VINSEL_REG	0x47
+#define AB8540_GPIO_PULL_UPDOWN_REG	0x48
+#define AB8500_GPIO_ALTFUN_REG	0x50
+#define AB8540_GPIO_PULL_UPDOWN_MASK	0x03
+#define AB8540_GPIO_VINSEL_MASK	0x03
+#define AB8540_GPIOX_VBAT_START	51
+#define AB8540_GPIOX_VBAT_END	54
+
+struct abx500_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctldev;
+	struct abx500_pinctrl_soc_data *soc;
+	struct gpio_chip chip;
+	struct ab8500 *parent;
+	struct mutex lock;
+	struct abx500_gpio_irq_cluster *irq_cluster;
+	int irq_cluster_size;
+};
+
+/**
+ * to_abx500_pinctrl() - get the pointer to abx500_pinctrl
+ * @chip:	Member of the structure abx500_pinctrl
+ */
+static inline struct abx500_pinctrl *to_abx500_pinctrl(struct gpio_chip *chip)
+{
+	return container_of(chip, struct abx500_pinctrl, chip);
+}
+
+static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
+			       unsigned offset, bool *bit)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 pos = offset % 8;
+	u8 val;
+	int ret;
+
+	reg += offset / 8;
+	ret = abx500_get_register_interruptible(pct->dev,
+						AB8500_MISC, reg, &val);
+
+	*bit = !!(val & BIT(pos));
+
+	if (ret < 0)
+		dev_err(pct->dev,
+			"%s read reg =%x, offset=%x failed\n",
+			__func__, reg, offset);
+
+	return ret;
+}
+
+static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
+				unsigned offset, int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 pos = offset % 8;
+	int ret;
+
+	reg += offset / 8;
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+				AB8500_MISC, reg, BIT(pos), val << pos);
+	if (ret < 0)
+		dev_err(pct->dev, "%s write failed\n", __func__);
+
+	return ret;
+}
+
+/**
+ * abx500_gpio_get() - Get the particular GPIO value
+ * @chip:	Gpio device
+ * @offset:	GPIO number to read
+ */
+static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	bool bit;
+	int ret;
+
+	ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
+				  offset, &bit);
+	if (ret < 0) {
+		dev_err(pct->dev, "%s failed\n", __func__);
+		return ret;
+	}
+
+	return bit;
+}
+
+static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int ret;
+
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+	if (ret < 0)
+		dev_err(pct->dev, "%s write failed\n", __func__);
+}
+
+static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
+				     int offset, enum abx500_gpio_pull_updown val)
+{
+	u8 pos;
+	int ret;
+	struct pullud *pullud;
+
+	if (!pct->soc->pullud) {
+		dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
+				__func__);
+		ret = -EPERM;
+		goto out;
+	}
+
+	pullud = pct->soc->pullud;
+
+	if ((offset < pullud->first_pin)
+		|| (offset > pullud->last_pin)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pos = offset << 1;
+
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+			AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
+			AB8540_GPIO_PULL_UPDOWN_MASK << pos, val << pos);
+
+out:
+	if (ret < 0)
+		dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static int abx500_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset,
+					int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct pullud *pullud = pct->soc->pullud;
+	unsigned gpio;
+	int ret;
+
+	/* set direction as output */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable pull down */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
+	if (ret < 0)
+		return ret;
+
+	/* if supported, disable both pull down and pull up */
+	gpio = offset + 1;
+	if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
+		ret = abx500_config_pull_updown(pct,
+				gpio,
+				ABX500_GPIO_PULL_NONE);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* set the output as 1 or 0 */
+	return abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+}
+
+static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	/* set the register as input */
+	return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
+}
+
+static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	/* The AB8500 GPIO numbers are off by one */
+	int gpio = offset + 1;
+	int hwirq;
+	int i;
+
+	for (i = 0; i < pct->irq_cluster_size; i++) {
+		struct abx500_gpio_irq_cluster *cluster =
+			&pct->irq_cluster[i];
+
+		if (gpio >= cluster->start && gpio <= cluster->end) {
+			/*
+			 * The ABx500 GPIO's associated IRQs are clustered together
+			 * throughout the interrupt numbers at irregular intervals.
+			 * To solve this quandry, we have placed the read-in values
+			 * into the cluster information table.
+			 */
+			hwirq = gpio - cluster->start + cluster->to_irq;
+			return irq_create_mapping(pct->parent->domain, hwirq);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+			   unsigned gpio, int alt_setting)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct alternate_functions af = pct->soc->alternate_functions[gpio];
+	int ret;
+	int val;
+	unsigned offset;
+
+	const char *modes[] = {
+		[ABX500_DEFAULT]	= "default",
+		[ABX500_ALT_A]		= "altA",
+		[ABX500_ALT_B]		= "altB",
+		[ABX500_ALT_C]		= "altC",
+	};
+
+	/* sanity check */
+	if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) ||
+	    ((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) ||
+	    ((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) {
+		dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio,
+				modes[alt_setting]);
+		return -EINVAL;
+	}
+
+	/* on ABx5xx, there is no GPIO0, so adjust the offset */
+	offset = gpio - 1;
+
+	switch (alt_setting) {
+	case ABX500_DEFAULT:
+		/*
+		 * for ABx5xx family, default mode is always selected by
+		 * writing 0 to GPIOSELx register, except for pins which
+		 * support at least ALT_B mode, default mode is selected
+		 * by writing 1 to GPIOSELx register
+		 */
+		val = 0;
+		if (af.alt_bit1 != UNUSED)
+			val++;
+
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					   offset, val);
+		break;
+
+	case ABX500_ALT_A:
+		/*
+		 * for ABx5xx family, alt_a mode is always selected by
+		 * writing 1 to GPIOSELx register, except for pins which
+		 * support at least ALT_B mode, alt_a mode is selected
+		 * by writing 0 to GPIOSELx register and 0 in ALTFUNC
+		 * register
+		 */
+		if (af.alt_bit1 != UNUSED) {
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					offset, 0);
+			ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit1,
+					!!(af.alta_val && BIT(0)));
+			if (af.alt_bit2 != UNUSED)
+				ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit2,
+					!!(af.alta_val && BIT(1)));
+		} else
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					offset, 1);
+		break;
+
+	case ABX500_ALT_B:
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+				offset, 0);
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit1, !!(af.altb_val && BIT(0)));
+		if (af.alt_bit2 != UNUSED)
+			ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit2,
+					!!(af.altb_val && BIT(1)));
+		break;
+
+	case ABX500_ALT_C:
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+				offset, 0);
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit2, !!(af.altc_val && BIT(0)));
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit2, !!(af.altc_val && BIT(1)));
+		break;
+
+	default:
+		dev_dbg(pct->dev, "unknow alt_setting %d\n", alt_setting);
+
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+			  unsigned gpio)
+{
+	u8 mode;
+	bool bit_mode;
+	bool alt_bit1;
+	bool alt_bit2;
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct alternate_functions af = pct->soc->alternate_functions[gpio];
+	/* on ABx5xx, there is no GPIO0, so adjust the offset */
+	unsigned offset = gpio - 1;
+
+	/*
+	 * if gpiosel_bit is set to unused,
+	 * it means no GPIO or special case
+	 */
+	if (af.gpiosel_bit == UNUSED)
+		return ABX500_DEFAULT;
+
+	/* read GpioSelx register */
+	abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
+			af.gpiosel_bit, &bit_mode);
+	mode = bit_mode;
+
+	/* sanity check */
+	if ((af.alt_bit1 < UNUSED) || (af.alt_bit1 > 7) ||
+	    (af.alt_bit2 < UNUSED) || (af.alt_bit2 > 7)) {
+		dev_err(pct->dev,
+			"alt_bitX value not in correct range (-1 to 7)\n");
+		return -EINVAL;
+	}
+
+	/* if alt_bit2 is used, alt_bit1 must be used too */
+	if ((af.alt_bit2 != UNUSED) && (af.alt_bit1 == UNUSED)) {
+		dev_err(pct->dev,
+			"if alt_bit2 is used, alt_bit1 can't be unused\n");
+		return -EINVAL;
+	}
+
+	/* check if pin use AlternateFunction register */
+	if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED))
+		return mode;
+	/*
+	 * if pin GPIOSEL bit is set and pin supports alternate function,
+	 * it means DEFAULT mode
+	 */
+	if (mode)
+		return ABX500_DEFAULT;
+
+	/*
+	 * pin use the AlternatFunction register
+	 * read alt_bit1 value
+	 */
+	abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+			    af.alt_bit1, &alt_bit1);
+
+	if (af.alt_bit2 != UNUSED)
+		/* read alt_bit2 value */
+		abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
+				&alt_bit2);
+	else
+		alt_bit2 = 0;
+
+	mode = (alt_bit2 << 1) + alt_bit1;
+	if (mode == af.alta_val)
+		return ABX500_ALT_A;
+	else if (mode == af.altb_val)
+		return ABX500_ALT_B;
+	else
+		return ABX500_ALT_C;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void abx500_gpio_dbg_show_one(struct seq_file *s,
+				     struct pinctrl_dev *pctldev,
+				     struct gpio_chip *chip,
+				     unsigned offset, unsigned gpio)
+{
+	const char *label = gpiochip_is_requested(chip, offset - 1);
+	u8 gpio_offset = offset - 1;
+	int mode = -1;
+	bool is_out;
+	bool pull;
+
+	const char *modes[] = {
+		[ABX500_DEFAULT]	= "default",
+		[ABX500_ALT_A]		= "altA",
+		[ABX500_ALT_B]		= "altB",
+		[ABX500_ALT_C]		= "altC",
+	};
+
+	abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
+	abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
+
+	if (pctldev)
+		mode = abx500_get_mode(pctldev, chip, offset);
+
+	seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
+		   gpio, label ?: "(none)",
+		   is_out ? "out" : "in ",
+		   is_out ?
+		   (chip->get
+		   ? (chip->get(chip, offset) ? "hi" : "lo")
+		   : "?  ")
+		   : (pull ? "pull up" : "pull down"),
+		   (mode < 0) ? "unknown" : modes[mode]);
+}
+
+static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	unsigned i;
+	unsigned gpio = chip->base;
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct pinctrl_dev *pctldev = pct->pctldev;
+
+	for (i = 0; i < chip->ngpio; i++, gpio++) {
+		/* On AB8500, there is no GPIO0, the first is the GPIO 1 */
+		abx500_gpio_dbg_show_one(s, pctldev, chip, i + 1, gpio);
+		seq_printf(s, "\n");
+	}
+}
+
+#else
+static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
+					    struct pinctrl_dev *pctldev,
+					    struct gpio_chip *chip,
+					    unsigned offset, unsigned gpio)
+{
+}
+#define abx500_gpio_dbg_show	NULL
+#endif
+
+int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	return pinctrl_request_gpio(gpio);
+}
+
+void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	pinctrl_free_gpio(gpio);
+}
+
+static struct gpio_chip abx500gpio_chip = {
+	.label			= "abx500-gpio",
+	.owner			= THIS_MODULE,
+	.request		= abx500_gpio_request,
+	.free			= abx500_gpio_free,
+	.direction_input	= abx500_gpio_direction_input,
+	.get			= abx500_gpio_get,
+	.direction_output	= abx500_gpio_direction_output,
+	.set			= abx500_gpio_set,
+	.to_irq			= abx500_gpio_to_irq,
+	.dbg_show		= abx500_gpio_dbg_show,
+};
+
+static int abx500_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->nfunctions;
+}
+
+static const char *abx500_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					 unsigned function)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->functions[function].name;
+}
+
+static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				      unsigned function,
+				      const char * const **groups,
+				      unsigned * const num_groups)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pct->soc->functions[function].groups;
+	*num_groups = pct->soc->functions[function].ngroups;
+
+	return 0;
+}
+
+static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+			     unsigned group)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = &pct->chip;
+	const struct abx500_pingroup *g;
+	int i;
+	int ret = 0;
+
+	g = &pct->soc->groups[group];
+	if (g->altsetting < 0)
+		return -EINVAL;
+
+	dev_dbg(pct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+	for (i = 0; i < g->npins; i++) {
+		dev_dbg(pct->dev, "setting pin %d to altsetting %d\n",
+			g->pins[i], g->altsetting);
+
+		ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
+	}
+
+	return ret;
+}
+
+static void abx500_pmx_disable(struct pinctrl_dev *pctldev,
+			       unsigned function, unsigned group)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	const struct abx500_pingroup *g;
+
+	g = &pct->soc->groups[group];
+	if (g->altsetting < 0)
+		return;
+
+	/* FIXME: poke out the mux, set the pin to some default state? */
+	dev_dbg(pct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
+			       struct pinctrl_gpio_range *range,
+			       unsigned offset)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	const struct abx500_pinrange *p;
+	int ret;
+	int i;
+
+	/*
+	 * Different ranges have different ways to enable GPIO function on a
+	 * pin, so refer back to our local range type, where we handily define
+	 * what altfunc enables GPIO for a certain pin.
+	 */
+	for (i = 0; i < pct->soc->gpio_num_ranges; i++) {
+		p = &pct->soc->gpio_ranges[i];
+		if ((offset >= p->offset) &&
+		    (offset < (p->offset + p->npins)))
+		  break;
+	}
+
+	if (i == pct->soc->gpio_num_ranges) {
+		dev_err(pct->dev, "%s failed to locate range\n", __func__);
+		return -ENODEV;
+	}
+
+	dev_dbg(pct->dev, "enable GPIO by altfunc %d at gpio %d\n",
+		p->altfunc, offset);
+
+	ret = abx500_set_mode(pct->pctldev, &pct->chip,
+			      offset, p->altfunc);
+	if (ret < 0) {
+		dev_err(pct->dev, "%s setting altfunc failed\n", __func__);
+		return ret;
+	}
+
+	return ret;
+}
+
+static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
+				     struct pinctrl_gpio_range *range,
+				     unsigned offset)
+{
+}
+
+static struct pinmux_ops abx500_pinmux_ops = {
+	.get_functions_count = abx500_pmx_get_funcs_cnt,
+	.get_function_name = abx500_pmx_get_func_name,
+	.get_function_groups = abx500_pmx_get_func_groups,
+	.enable = abx500_pmx_enable,
+	.disable = abx500_pmx_disable,
+	.gpio_request_enable = abx500_gpio_request_enable,
+	.gpio_disable_free = abx500_gpio_disable_free,
+};
+
+static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->ngroups;
+}
+
+static const char *abx500_get_group_name(struct pinctrl_dev *pctldev,
+					 unsigned selector)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->groups[selector].name;
+}
+
+static int abx500_get_group_pins(struct pinctrl_dev *pctldev,
+				 unsigned selector,
+				 const unsigned **pins,
+				 unsigned *num_pins)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = pct->soc->groups[selector].pins;
+	*num_pins = pct->soc->groups[selector].npins;
+
+	return 0;
+}
+
+static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
+				struct seq_file *s, unsigned offset)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = &pct->chip;
+
+	abx500_gpio_dbg_show_one(s, pctldev, chip, offset,
+				 chip->base + offset - 1);
+}
+
+static struct pinctrl_ops abx500_pinctrl_ops = {
+	.get_groups_count = abx500_get_groups_cnt,
+	.get_group_name = abx500_get_group_name,
+	.get_group_pins = abx500_get_group_pins,
+	.pin_dbg_show = abx500_pin_dbg_show,
+};
+
+int abx500_pin_config_get(struct pinctrl_dev *pctldev,
+			  unsigned pin,
+			  unsigned long *config)
+{
+	return -ENOSYS;
+}
+
+int abx500_pin_config_set(struct pinctrl_dev *pctldev,
+			  unsigned pin,
+			  unsigned long config)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct pullud *pullud = pct->soc->pullud;
+	struct gpio_chip *chip = &pct->chip;
+	unsigned offset;
+	int ret;
+	enum pin_config_param param = pinconf_to_config_param(config);
+	enum pin_config_param argument = pinconf_to_config_argument(config);
+
+	dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+		pin, config, (param == PIN_CONFIG_OUTPUT) ? "output " : "input",
+		(param == PIN_CONFIG_OUTPUT) ? (argument ? "high" : "low") :
+		(argument ? "pull up" : "pull down"));
+
+	/* on ABx500, there is no GPIO0, so adjust the offset */
+	offset = pin - 1;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		/*
+		 * if argument = 1 set the pull down
+		 * else clear the pull down
+		 */
+		ret = abx500_gpio_direction_input(chip, offset);
+		/*
+		 * Some chips only support pull down, while some actually
+		 * support both pull up and pull down. Such chips have
+		 * a "pullud" range specified for the pins that support
+		 * both features. If the pin is not within that range, we
+		 * fall back to the old bit set that only support pull down.
+		 */
+		if (pullud &&
+		    pin >= pullud->first_pin &&
+		    pin <= pullud->last_pin)
+			ret = abx500_config_pull_updown(pct,
+				pin,
+				argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
+		else
+			/* Chip only supports pull down */
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
+				offset, argument ? 0 : 1);
+		break;
+
+	case PIN_CONFIG_OUTPUT:
+		ret = abx500_gpio_direction_output(chip, offset, argument);
+
+		break;
+
+	default:
+		dev_err(chip->dev, "illegal configuration requested\n");
+
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static struct pinconf_ops abx500_pinconf_ops = {
+	.pin_config_get = abx500_pin_config_get,
+	.pin_config_set = abx500_pin_config_set,
+};
+
+static struct pinctrl_desc abx500_pinctrl_desc = {
+	.name = "pinctrl-abx500",
+	.pctlops = &abx500_pinctrl_ops,
+	.pmxops = &abx500_pinmux_ops,
+	.confops = &abx500_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+static int abx500_get_gpio_num(struct abx500_pinctrl_soc_data *soc)
+{
+	unsigned int lowest = 0;
+	unsigned int highest = 0;
+	unsigned int npins = 0;
+	int i;
+
+	/*
+	 * Compute number of GPIOs from the last SoC gpio range descriptors
+	 * These ranges may include "holes" but the GPIO number space shall
+	 * still be homogeneous, so we need to detect and account for any
+	 * such holes so that these are included in the number of GPIO pins.
+	 */
+	for (i = 0; i < soc->gpio_num_ranges; i++) {
+		unsigned gstart;
+		unsigned gend;
+		const struct abx500_pinrange *p;
+
+		p = &soc->gpio_ranges[i];
+		gstart = p->offset;
+		gend = p->offset + p->npins - 1;
+
+		if (i == 0) {
+			/* First iteration, set start values */
+			lowest = gstart;
+			highest = gend;
+		} else {
+			if (gstart < lowest)
+				lowest = gstart;
+			if (gend > highest)
+				highest = gend;
+		}
+	}
+	/* this gives the absolute number of pins */
+	npins = highest - lowest + 1;
+	return npins;
+}
+
+static const struct of_device_id abx500_gpio_match[] = {
+	{ .compatible = "stericsson,ab8500-gpio", .data = (void *)PINCTRL_AB8500, },
+	{ .compatible = "stericsson,ab8505-gpio", .data = (void *)PINCTRL_AB8505, },
+	{ .compatible = "stericsson,ab8540-gpio", .data = (void *)PINCTRL_AB8540, },
+	{ .compatible = "stericsson,ab9540-gpio", .data = (void *)PINCTRL_AB9540, },
+};
+
+static int abx500_gpio_probe(struct platform_device *pdev)
+{
+	struct ab8500_platform_data *abx500_pdata =
+				dev_get_platdata(pdev->dev.parent);
+	struct abx500_gpio_platform_data *pdata = NULL;
+	struct device_node *np = pdev->dev.of_node;
+	struct abx500_pinctrl *pct;
+	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	unsigned int id = -1;
+	int ret, err;
+	int i;
+
+	if (abx500_pdata)
+		pdata = abx500_pdata->gpio;
+	if (!pdata) {
+		if (np) {
+			const struct of_device_id *match;
+
+			match = of_match_device(abx500_gpio_match, &pdev->dev);
+			if (!match)
+				return -ENODEV;
+			id = (unsigned long)match->data;
+		} else {
+			dev_err(&pdev->dev, "gpio dt and platform data missing\n");
+			return -ENODEV;
+		}
+	}
+
+	if (platid)
+		id = platid->driver_data;
+
+	pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl),
+				   GFP_KERNEL);
+	if (pct == NULL) {
+		dev_err(&pdev->dev,
+			"failed to allocate memory for pct\n");
+		return -ENOMEM;
+	}
+
+	pct->dev = &pdev->dev;
+	pct->parent = dev_get_drvdata(pdev->dev.parent);
+	pct->chip = abx500gpio_chip;
+	pct->chip.dev = &pdev->dev;
+	pct->chip.base = pdata->gpio_base;
+	pct->chip.base = (np) ? -1 : pdata->gpio_base;
+
+	/* initialize the lock */
+	mutex_init(&pct->lock);
+
+	/* Poke in other ASIC variants here */
+	switch (id) {
+	case PINCTRL_AB8500:
+		abx500_pinctrl_ab8500_init(&pct->soc);
+		break;
+	case PINCTRL_AB8540:
+		abx500_pinctrl_ab8540_init(&pct->soc);
+		break;
+	case PINCTRL_AB9540:
+		abx500_pinctrl_ab9540_init(&pct->soc);
+		break;
+	case PINCTRL_AB8505:
+		abx500_pinctrl_ab8505_init(&pct->soc);
+		break;
+	default:
+		dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n",
+				(int) platid->driver_data);
+		mutex_destroy(&pct->lock);
+		return -EINVAL;
+	}
+
+	if (!pct->soc) {
+		dev_err(&pdev->dev, "Invalid SOC data\n");
+		mutex_destroy(&pct->lock);
+		return -EINVAL;
+	}
+
+	pct->chip.ngpio = abx500_get_gpio_num(pct->soc);
+	pct->irq_cluster = pct->soc->gpio_irq_cluster;
+	pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
+
+	ret = gpiochip_add(&pct->chip);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
+		mutex_destroy(&pct->lock);
+		return ret;
+	}
+	dev_info(&pdev->dev, "added gpiochip\n");
+
+	abx500_pinctrl_desc.pins = pct->soc->pins;
+	abx500_pinctrl_desc.npins = pct->soc->npins;
+	pct->pctldev = pinctrl_register(&abx500_pinctrl_desc, &pdev->dev, pct);
+	if (!pct->pctldev) {
+		dev_err(&pdev->dev,
+			"could not register abx500 pinctrl driver\n");
+		ret = -EINVAL;
+		goto out_rem_chip;
+	}
+	dev_info(&pdev->dev, "registered pin controller\n");
+
+	/* We will handle a range of GPIO pins */
+	for (i = 0; i < pct->soc->gpio_num_ranges; i++) {
+		const struct abx500_pinrange *p = &pct->soc->gpio_ranges[i];
+
+		ret = gpiochip_add_pin_range(&pct->chip,
+					dev_name(&pdev->dev),
+					p->offset - 1, p->offset, p->npins);
+		if (ret < 0)
+			goto out_rem_chip;
+	}
+
+	platform_set_drvdata(pdev, pct);
+	dev_info(&pdev->dev, "initialized abx500 pinctrl driver\n");
+
+	return 0;
+
+out_rem_chip:
+	err = gpiochip_remove(&pct->chip);
+	if (err)
+		dev_info(&pdev->dev, "failed to remove gpiochip\n");
+
+	mutex_destroy(&pct->lock);
+	return ret;
+}
+
+/**
+ * abx500_gpio_remove() - remove Ab8500-gpio driver
+ * @pdev:	Platform device registered
+ */
+static int abx500_gpio_remove(struct platform_device *pdev)
+{
+	struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&pct->chip);
+	if (ret < 0) {
+		dev_err(pct->dev, "unable to remove gpiochip: %d\n",
+			ret);
+		return ret;
+	}
+
+	mutex_destroy(&pct->lock);
+
+	return 0;
+}
+
+static const struct platform_device_id abx500_pinctrl_id[] = {
+	{ "pinctrl-ab8500", PINCTRL_AB8500 },
+	{ "pinctrl-ab8540", PINCTRL_AB8540 },
+	{ "pinctrl-ab9540", PINCTRL_AB9540 },
+	{ "pinctrl-ab8505", PINCTRL_AB8505 },
+	{ },
+};
+
+static struct platform_driver abx500_gpio_driver = {
+	.driver = {
+		.name = "abx500-gpio",
+		.owner = THIS_MODULE,
+		.of_match_table = abx500_gpio_match,
+	},
+	.probe = abx500_gpio_probe,
+	.remove = abx500_gpio_remove,
+	.id_table = abx500_pinctrl_id,
+};
+
+static int __init abx500_gpio_init(void)
+{
+	return platform_driver_register(&abx500_gpio_driver);
+}
+core_initcall(abx500_gpio_init);
+
+MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>");
+MODULE_DESCRIPTION("Driver allows to use AxB5xx unused pins to be used as GPIO");
+MODULE_ALIAS("platform:abx500-gpio");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-abx500.h b/drivers/pinctrl/pinctrl-abx500.h
new file mode 100644
index 0000000..eeca8f9
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.h
@@ -0,0 +1,234 @@
+#ifndef PINCTRL_PINCTRL_ABx5O0_H
+#define PINCTRL_PINCTRL_ABx500_H
+
+/* Package definitions */
+#define PINCTRL_AB8500	0
+#define PINCTRL_AB8540	1
+#define PINCTRL_AB9540	2
+#define PINCTRL_AB8505	3
+
+/* pins alternate function */
+enum abx500_pin_func {
+	ABX500_DEFAULT,
+	ABX500_ALT_A,
+	ABX500_ALT_B,
+	ABX500_ALT_C,
+};
+
+/**
+ * struct abx500_function - ABx500 pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct abx500_function {
+	const char *name;
+	const char * const *groups;
+	unsigned ngroups;
+};
+
+/**
+ * struct abx500_pingroup - describes a ABx500 pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ *	from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ *	configure them to be used by a function
+ */
+struct abx500_pingroup {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned npins;
+	int altsetting;
+};
+
+#define ALTERNATE_FUNCTIONS(pin, sel_bit, alt1, alt2, alta, altb, altc)	\
+{									\
+	.pin_number = pin,						\
+	.gpiosel_bit = sel_bit,						\
+	.alt_bit1 = alt1,						\
+	.alt_bit2 = alt2,						\
+	.alta_val = alta,						\
+	.altb_val = altb,						\
+	.altc_val = altc,						\
+}
+
+#define UNUSED -1
+/**
+ * struct alternate_functions
+ * @pin_number:		The pin number
+ * @gpiosel_bit:	Control bit in GPIOSEL register,
+ * @alt_bit1:		First AlternateFunction bit used to select the
+ *			alternate function
+ * @alt_bit2:		Second AlternateFunction bit used to select the
+ *			alternate function
+ *
+ *			these 3 following fields are necessary due to none
+ *			coherency on how to select the altA, altB and altC
+ *			function between the ABx500 SOC family when using
+ *			alternatfunc register.
+ * @alta_val:		value to write in alternatfunc to select altA function
+ * @altb_val:		value to write in alternatfunc to select altB function
+ * @altc_val:		value to write in alternatfunc to select altC function
+ */
+struct alternate_functions {
+	unsigned pin_number;
+	s8 gpiosel_bit;
+	s8 alt_bit1;
+	s8 alt_bit2;
+	u8 alta_val;
+	u8 altb_val;
+	u8 altc_val;
+};
+
+/**
+ * struct pullud - specific pull up/down feature
+ * @first_pin:		The pin number of the first pins which support
+ *			specific pull up/down
+ * @last_pin:		The pin number of the last pins
+ */
+struct pullud {
+	unsigned first_pin;
+	unsigned last_pin;
+};
+
+#define GPIO_IRQ_CLUSTER(a, b, c)	\
+{					\
+	.start = a,			\
+	.end = b,			\
+	.to_irq = c,			\
+}
+
+/**
+ * struct abx500_gpio_irq_cluster - indicates GPIOs which are interrupt
+ *			capable
+ * @start:		The pin number of the first pin interrupt capable
+ * @end:		The pin number of the last pin interrupt capable
+ * @to_irq:		The ABx500 GPIO's associated IRQs are clustered
+ *                      together throughout the interrupt numbers at irregular
+ *                      intervals. To solve this quandary, we will place the
+ *                      read-in values into the cluster information table
+ */
+
+struct abx500_gpio_irq_cluster {
+	int start;
+	int end;
+	int to_irq;
+};
+
+/**
+ * struct abx500_pinrange - map pin numbers to GPIO offsets
+ * @offset:		offset into the GPIO local numberspace, incidentally
+ *			identical to the offset into the local pin numberspace
+ * @npins:		number of pins to map from both offsets
+ * @altfunc:		altfunc setting to be used to enable GPIO on a pin in
+ *			this range (may vary)
+ */
+struct abx500_pinrange {
+	unsigned int offset;
+	unsigned int npins;
+	int altfunc;
+};
+
+#define ABX500_PINRANGE(a, b, c) { .offset = a, .npins = b, .altfunc = c }
+
+/**
+ * struct abx500_pinctrl_soc_data - ABx500 pin controller per-SoC configuration
+ * @gpio_ranges:	An array of GPIO ranges for this SoC
+ * @gpio_num_ranges:	The number of GPIO ranges for this SoC
+ * @pins:		An array describing all pins the pin controller affects.
+ *			All pins which are also GPIOs must be listed first within the
+ *			array, and be numbered identically to the GPIO controller's
+ *			numbering.
+ * @npins:		The number of entries in @pins.
+ * @functions:		The functions supported on this SoC.
+ * @nfunction:		The number of entries in @functions.
+ * @groups:		An array describing all pin groups the pin SoC supports.
+ * @ngroups:		The number of entries in @groups.
+ * @alternate_functions: array describing pins which supports alternate and
+ *			how to set it.
+ * @pullud:		array describing pins which supports pull up/down
+ *			specific registers.
+ * @gpio_irq_cluster:	An array of GPIO interrupt capable for this SoC
+ * @ngpio_irq_cluster:	The number of GPIO inetrrupt capable for this SoC
+ * @irq_gpio_rising_offset: Interrupt offset used as base to compute specific
+ *			setting strategy of the rising interrupt line
+ * @irq_gpio_falling_offset: Interrupt offset used as base to compute specific
+ *			setting strategy of the falling interrupt line
+ * @irq_gpio_factor:	Factor used to compute specific setting strategy of
+ *			the interrupt line
+ */
+
+struct abx500_pinctrl_soc_data {
+	const struct abx500_pinrange *gpio_ranges;
+	unsigned gpio_num_ranges;
+	const struct pinctrl_pin_desc *pins;
+	unsigned npins;
+	const struct abx500_function *functions;
+	unsigned nfunctions;
+	const struct abx500_pingroup *groups;
+	unsigned ngroups;
+	struct alternate_functions *alternate_functions;
+	struct pullud *pullud;
+	struct abx500_gpio_irq_cluster *gpio_irq_cluster;
+	unsigned ngpio_irq_cluster;
+	int irq_gpio_rising_offset;
+	int irq_gpio_falling_offset;
+	int irq_gpio_factor;
+};
+
+#ifdef CONFIG_PINCTRL_AB8500
+
+void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8540
+
+void abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB9540
+
+void abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8505
+
+void abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_ABx500_H */
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index 8ed20e8..4a0d54a 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -170,7 +170,7 @@
 static const unsigned pins_ntr8k[] = {GPIO5};
 static const unsigned pins_hrst[] = {GPIO6};
 static const unsigned pins_mdio[] = {GPIO7, GPIO8};
-static const unsigned pins_bled[] = {GPIO7, GPIO10, GPIO11,
+static const unsigned pins_bled[] = {GPIO9, GPIO10, GPIO11,
 					GPIO12, GPIO13, GPIO14};
 static const unsigned pins_asc0[] = {GPIO32, GPIO33};
 static const unsigned pins_spi[] = {GPIO34, GPIO35, GPIO36};
@@ -315,6 +315,37 @@
 static void falcon_pinconf_dbg_show(struct pinctrl_dev *pctrldev,
 			struct seq_file *s, unsigned offset)
 {
+	unsigned long config;
+	struct pin_desc *desc;
+
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+	int port = PORT(offset);
+
+	seq_printf(s, " (port %d) mux %d -- ", port,
+		pad_r32(info->membase[port], LTQ_PADC_MUX(PORT_PIN(offset))));
+
+	config = LTQ_PINCONF_PACK(LTQ_PINCONF_PARAM_PULL, 0);
+	if (!falcon_pinconf_get(pctrldev, offset, &config))
+		seq_printf(s, "pull %d ",
+			(int)LTQ_PINCONF_UNPACK_ARG(config));
+
+	config = LTQ_PINCONF_PACK(LTQ_PINCONF_PARAM_DRIVE_CURRENT, 0);
+	if (!falcon_pinconf_get(pctrldev, offset, &config))
+		seq_printf(s, "drive-current %d ",
+			(int)LTQ_PINCONF_UNPACK_ARG(config));
+
+	config = LTQ_PINCONF_PACK(LTQ_PINCONF_PARAM_SLEW_RATE, 0);
+	if (!falcon_pinconf_get(pctrldev, offset, &config))
+		seq_printf(s, "slew-rate %d ",
+			(int)LTQ_PINCONF_UNPACK_ARG(config));
+
+	desc = pin_desc_get(pctrldev, offset);
+	if (desc) {
+		if (desc->gpio_owner)
+			seq_printf(s, " owner: %s", desc->gpio_owner);
+	} else {
+		seq_printf(s, " not registered");
+	}
 }
 
 static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
@@ -360,6 +391,8 @@
 static struct ltq_pinmux_info falcon_info = {
 	.desc		= &falcon_pctrl_desc,
 	.apply_mux	= falcon_mux_apply,
+	.params		= falcon_cfg_params,
+	.num_params	= ARRAY_SIZE(falcon_cfg_params),
 };
 
 
@@ -398,6 +431,9 @@
 		u32 avail;
 		int pins;
 
+		if (!of_device_is_available(np))
+			continue;
+
 		if (!ppdev) {
 			dev_err(&pdev->dev, "failed to find pad pdev\n");
 			continue;
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index 15f501d..a703846 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -64,11 +64,13 @@
 	seq_printf(s, " %s", dev_name(pctldev->dev));
 }
 
-static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+static void ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 				struct device_node *np,
 				struct pinctrl_map **map)
 {
 	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+	struct property *pins = of_find_property(np, "lantiq,pins", NULL);
+	struct property *groups = of_find_property(np, "lantiq,groups", NULL);
 	unsigned long configs[3];
 	unsigned num_configs = 0;
 	struct property *prop;
@@ -76,8 +78,20 @@
 	const char *function;
 	int ret, i;
 
+	if (!pins && !groups) {
+		dev_err(pctldev->dev, "%s defines neither pins nor groups\n",
+			np->name);
+		return;
+	}
+
+	if (pins && groups) {
+		dev_err(pctldev->dev, "%s defines both pins and groups\n",
+			np->name);
+		return;
+	}
+
 	ret = of_property_read_string(np, "lantiq,function", &function);
-	if (!ret) {
+	if (groups && !ret) {
 		of_property_for_each_string(np, "lantiq,groups", prop, group) {
 			(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
 			(*map)->name = function;
@@ -85,11 +99,6 @@
 			(*map)->data.mux.function = function;
 			(*map)++;
 		}
-		if (of_find_property(np, "lantiq,pins", NULL))
-			dev_err(pctldev->dev,
-				"%s mixes pins and groups settings\n",
-				np->name);
-		return 0;
 	}
 
 	for (i = 0; i < info->num_params; i++) {
@@ -103,7 +112,7 @@
 	}
 
 	if (!num_configs)
-		return -EINVAL;
+		return;
 
 	of_property_for_each_string(np, "lantiq,pins", prop, pin) {
 		(*map)->data.configs.configs = kmemdup(configs,
@@ -115,7 +124,16 @@
 		(*map)->data.configs.num_configs = num_configs;
 		(*map)++;
 	}
-	return 0;
+	of_property_for_each_string(np, "lantiq,groups", prop, group) {
+		(*map)->data.configs.configs = kmemdup(configs,
+					num_configs * sizeof(unsigned long),
+					GFP_KERNEL);
+		(*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+		(*map)->name = group;
+		(*map)->data.configs.group_or_pin = group;
+		(*map)->data.configs.num_configs = num_configs;
+		(*map)++;
+	}
 }
 
 static int ltq_pinctrl_dt_subnode_size(struct device_node *np)
@@ -135,23 +153,19 @@
 {
 	struct pinctrl_map *tmp;
 	struct device_node *np;
-	int ret;
+	int max_maps = 0;
 
-	*num_maps = 0;
 	for_each_child_of_node(np_config, np)
-		*num_maps += ltq_pinctrl_dt_subnode_size(np);
-	*map = kzalloc(*num_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
+		max_maps += ltq_pinctrl_dt_subnode_size(np);
+	*map = kzalloc(max_maps * sizeof(struct pinctrl_map) * 2, GFP_KERNEL);
 	if (!*map)
 		return -ENOMEM;
 	tmp = *map;
 
-	for_each_child_of_node(np_config, np) {
-		ret = ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
-		if (ret < 0) {
-			ltq_pinctrl_dt_free_map(pctldev, *map, *num_maps);
-			return ret;
-		}
-	}
+	for_each_child_of_node(np_config, np)
+		ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
+	*num_maps = ((int)(tmp - *map));
+
 	return 0;
 }
 
@@ -280,7 +294,7 @@
 				unsigned pin)
 {
 	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-	int mfp = match_mfp(info, pin + (range->id * 32));
+	int mfp = match_mfp(info, pin);
 	int pin_func;
 
 	if (mfp < 0) {
diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h
index 4419d32..6d07f02 100644
--- a/drivers/pinctrl/pinctrl-lantiq.h
+++ b/drivers/pinctrl/pinctrl-lantiq.h
@@ -34,6 +34,7 @@
 	LTQ_PINCONF_PARAM_OPEN_DRAIN,
 	LTQ_PINCONF_PARAM_DRIVE_CURRENT,
 	LTQ_PINCONF_PARAM_SLEW_RATE,
+	LTQ_PINCONF_PARAM_OUTPUT,
 };
 
 struct ltq_cfg_param {
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 5767b18..de9e851 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -25,6 +25,8 @@
 #include <linux/irqdomain.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/pinconf.h>
@@ -32,8 +34,8 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/pinctrl-nomadik.h>
 #include <asm/mach/irq.h>
-#include <mach/irqs.h>
 #include "pinctrl-nomadik.h"
+#include "core.h"
 
 /*
  * The GPIO module in the Nomadik family of Systems-on-Chip is an
@@ -216,7 +218,7 @@
 	u32 falling = nmk_chip->fimsc & BIT(offset);
 	u32 rising = nmk_chip->rimsc & BIT(offset);
 	int gpio = nmk_chip->chip.base + offset;
-	int irq = NOMADIK_GPIO_TO_IRQ(gpio);
+	int irq = irq_find_mapping(nmk_chip->domain, offset);
 	struct irq_data *d = irq_get_irq_data(irq);
 
 	if (!rising && !falling)
@@ -1341,8 +1343,7 @@
 
 		if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
 			dev_err(&dev->dev, "gpio-bank property not found\n");
-			ret = -EINVAL;
-			goto out;
+			return -EINVAL;
 		}
 
 		pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
@@ -1350,41 +1351,29 @@
 	}
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENOENT;
-		goto out;
-	}
+	if (!res)
+		return -ENOENT;
 
 	irq = platform_get_irq(dev, 0);
-	if (irq < 0) {
-		ret = irq;
-		goto out;
-	}
+	if (irq < 0)
+		return irq;
 
 	secondary_irq = platform_get_irq(dev, 1);
-	if (secondary_irq >= 0 && !pdata->get_secondary_status) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (secondary_irq >= 0 && !pdata->get_secondary_status)
+		return -EINVAL;
 
 	base = devm_request_and_ioremap(&dev->dev, res);
-	if (!base) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!base)
+		return -ENOMEM;
 
 	clk = devm_clk_get(&dev->dev, NULL);
-	if (IS_ERR(clk)) {
-		ret = PTR_ERR(clk);
-		goto out;
-	}
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
 	clk_prepare(clk);
 
 	nmk_chip = devm_kzalloc(&dev->dev, sizeof(*nmk_chip), GFP_KERNEL);
-	if (!nmk_chip) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!nmk_chip)
+		return -ENOMEM;
 
 	/*
 	 * The virt address in nmk_chip->addr is in the nomadik register space,
@@ -1418,7 +1407,7 @@
 
 	ret = gpiochip_add(&nmk_chip->chip);
 	if (ret)
-		goto out;
+		return ret;
 
 	BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
 
@@ -1427,14 +1416,15 @@
 	platform_set_drvdata(dev, nmk_chip);
 
 	if (!np)
-		irq_start = NOMADIK_GPIO_TO_IRQ(pdata->first_gpio);
+		irq_start = pdata->first_irq;
 	nmk_chip->domain = irq_domain_add_simple(np,
 				NMK_GPIO_PER_CHIP, irq_start,
 				&nmk_gpio_irq_simple_ops, nmk_chip);
 	if (!nmk_chip->domain) {
 		dev_err(&dev->dev, "failed to create irqdomain\n");
-		ret = -ENOSYS;
-		goto out;
+		/* Just do this, no matter if it fails */
+		ret = gpiochip_remove(&nmk_chip->chip);
+		return -ENOSYS;
 	}
 
 	nmk_gpio_init_irq(nmk_chip);
@@ -1442,12 +1432,6 @@
 	dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
 
 	return 0;
-
-out:
-	dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
-		  pdata->first_gpio, pdata->first_gpio+31);
-
-	return ret;
 }
 
 static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev)
@@ -1508,11 +1492,285 @@
 	nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset);
 }
 
+static void nmk_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map *map, unsigned num_maps)
+{
+	int i;
+
+	for (i = 0; i < num_maps; i++)
+		if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+			kfree(map[i].data.configs.configs);
+	kfree(map);
+}
+
+static int nmk_dt_reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, unsigned reserve)
+{
+	unsigned old_num = *reserved_maps;
+	unsigned new_num = *num_maps + reserve;
+	struct pinctrl_map *new_map;
+
+	if (old_num >= new_num)
+		return 0;
+
+	new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+	*map = new_map;
+	*reserved_maps = new_num;
+
+	return 0;
+}
+
+static int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, const char *group,
+		const char *function)
+{
+	if (*num_maps == *reserved_maps)
+		return -ENOSPC;
+
+	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+	(*map)[*num_maps].data.mux.group = group;
+	(*map)[*num_maps].data.mux.function = function;
+	(*num_maps)++;
+
+	return 0;
+}
+
+static int nmk_dt_add_map_configs(struct pinctrl_map **map,
+		unsigned *reserved_maps,
+		unsigned *num_maps, const char *group,
+		unsigned long *configs, unsigned num_configs)
+{
+	unsigned long *dup_configs;
+
+	if (*num_maps == *reserved_maps)
+		return -ENOSPC;
+
+	dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+			      GFP_KERNEL);
+	if (!dup_configs)
+		return -ENOMEM;
+
+	(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN;
+
+	(*map)[*num_maps].data.configs.group_or_pin = group;
+	(*map)[*num_maps].data.configs.configs = dup_configs;
+	(*map)[*num_maps].data.configs.num_configs = num_configs;
+	(*num_maps)++;
+
+	return 0;
+}
+
+#define NMK_CONFIG_PIN(x,y) { .property = x, .config = y, }
+#define NMK_CONFIG_PIN_ARRAY(x,y) { .property = x, .choice = y, \
+	.size = ARRAY_SIZE(y), }
+
+static const unsigned long nmk_pin_input_modes[] = {
+	PIN_INPUT_NOPULL,
+	PIN_INPUT_PULLUP,
+	PIN_INPUT_PULLDOWN,
+};
+
+static const unsigned long nmk_pin_output_modes[] = {
+	PIN_OUTPUT_LOW,
+	PIN_OUTPUT_HIGH,
+	PIN_DIR_OUTPUT,
+};
+
+static const unsigned long nmk_pin_sleep_modes[] = {
+	PIN_SLEEPMODE_DISABLED,
+	PIN_SLEEPMODE_ENABLED,
+};
+
+static const unsigned long nmk_pin_sleep_input_modes[] = {
+	PIN_SLPM_INPUT_NOPULL,
+	PIN_SLPM_INPUT_PULLUP,
+	PIN_SLPM_INPUT_PULLDOWN,
+	PIN_SLPM_DIR_INPUT,
+};
+
+static const unsigned long nmk_pin_sleep_output_modes[] = {
+	PIN_SLPM_OUTPUT_LOW,
+	PIN_SLPM_OUTPUT_HIGH,
+	PIN_SLPM_DIR_OUTPUT,
+};
+
+static const unsigned long nmk_pin_sleep_wakeup_modes[] = {
+	PIN_SLPM_WAKEUP_DISABLE,
+	PIN_SLPM_WAKEUP_ENABLE,
+};
+
+static const unsigned long nmk_pin_gpio_modes[] = {
+	PIN_GPIOMODE_DISABLED,
+	PIN_GPIOMODE_ENABLED,
+};
+
+static const unsigned long nmk_pin_sleep_pdis_modes[] = {
+	PIN_SLPM_PDIS_DISABLED,
+	PIN_SLPM_PDIS_ENABLED,
+};
+
+struct nmk_cfg_param {
+	const char *property;
+	unsigned long config;
+	const unsigned long *choice;
+	int size;
+};
+
+static const struct nmk_cfg_param nmk_cfg_params[] = {
+	NMK_CONFIG_PIN_ARRAY("ste,input",		nmk_pin_input_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,output",		nmk_pin_output_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,sleep",		nmk_pin_sleep_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,sleep-input",		nmk_pin_sleep_input_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,sleep-output",	nmk_pin_sleep_output_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,sleep-wakeup",	nmk_pin_sleep_wakeup_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,gpio",		nmk_pin_gpio_modes),
+	NMK_CONFIG_PIN_ARRAY("ste,sleep-pull-disable",	nmk_pin_sleep_pdis_modes),
+};
+
+static int nmk_dt_pin_config(int index, int val, unsigned long *config)
+{
+	int ret = 0;
+
+	if (nmk_cfg_params[index].choice == NULL)
+		*config = nmk_cfg_params[index].config;
+	else {
+		/* test if out of range */
+		if  (val < nmk_cfg_params[index].size) {
+			*config = nmk_cfg_params[index].config |
+				nmk_cfg_params[index].choice[val];
+		}
+	}
+	return ret;
+}
+
+static const char *nmk_find_pin_name(struct pinctrl_dev *pctldev, const char *pin_name)
+{
+	int i, pin_number;
+	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+	if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1)
+		for (i = 0; i < npct->soc->npins; i++)
+			if (npct->soc->pins[i].number == pin_number)
+				return npct->soc->pins[i].name;
+	return NULL;
+}
+
+static bool nmk_pinctrl_dt_get_config(struct device_node *np,
+		unsigned long *configs)
+{
+	bool has_config = 0;
+	unsigned long cfg = 0;
+	int i, val, ret;
+
+	for (i = 0; i < ARRAY_SIZE(nmk_cfg_params); i++) {
+		ret = of_property_read_u32(np,
+				nmk_cfg_params[i].property, &val);
+		if (ret != -EINVAL) {
+			if (nmk_dt_pin_config(i, val, &cfg) == 0) {
+				*configs |= cfg;
+				has_config = 1;
+			}
+		}
+	}
+
+	return has_config;
+}
+
+int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+		struct device_node *np,
+		struct pinctrl_map **map,
+		unsigned *reserved_maps,
+		unsigned *num_maps)
+{
+	int ret;
+	const char *function = NULL;
+	unsigned long configs = 0;
+	bool has_config = 0;
+	unsigned reserve = 0;
+	struct property *prop;
+	const char *group, *gpio_name;
+	struct device_node *np_config;
+
+	ret = of_property_read_string(np, "ste,function", &function);
+	if (ret >= 0)
+		reserve = 1;
+
+	has_config = nmk_pinctrl_dt_get_config(np, &configs);
+
+	np_config = of_parse_phandle(np, "ste,config", 0);
+	if (np_config)
+		has_config |= nmk_pinctrl_dt_get_config(np_config, &configs);
+
+	ret = of_property_count_strings(np, "ste,pins");
+	if (ret < 0)
+		goto exit;
+
+	if (has_config)
+		reserve++;
+
+	reserve *= ret;
+
+	ret = nmk_dt_reserve_map(map, reserved_maps, num_maps, reserve);
+	if (ret < 0)
+		goto exit;
+
+	of_property_for_each_string(np, "ste,pins", prop, group) {
+		if (function) {
+			ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps,
+					  group, function);
+			if (ret < 0)
+				goto exit;
+		}
+		if (has_config) {
+			gpio_name = nmk_find_pin_name(pctldev, group);
+
+			ret = nmk_dt_add_map_configs(map, reserved_maps, num_maps,
+					      gpio_name, &configs, 1);
+			if (ret < 0)
+				goto exit;
+		}
+
+	}
+exit:
+	return ret;
+}
+
+int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				 struct device_node *np_config,
+				 struct pinctrl_map **map, unsigned *num_maps)
+{
+	unsigned reserved_maps;
+	struct device_node *np;
+	int ret;
+
+	reserved_maps = 0;
+	*map = NULL;
+	*num_maps = 0;
+
+	for_each_child_of_node(np_config, np) {
+		ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map,
+				&reserved_maps, num_maps);
+		if (ret < 0) {
+			nmk_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static struct pinctrl_ops nmk_pinctrl_ops = {
 	.get_groups_count = nmk_get_groups_cnt,
 	.get_group_name = nmk_get_group_name,
 	.get_group_pins = nmk_get_group_pins,
 	.pin_dbg_show = nmk_pin_dbg_show,
+	.dt_node_to_map = nmk_pinctrl_dt_node_to_map,
+	.dt_free_map = nmk_pinctrl_dt_free_map,
 };
 
 static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
@@ -1846,16 +2104,39 @@
 
 static const struct of_device_id nmk_pinctrl_match[] = {
 	{
-		.compatible = "stericsson,nmk_pinctrl",
+		.compatible = "stericsson,nmk-pinctrl",
 		.data = (void *)PINCTRL_NMK_DB8500,
 	},
 	{},
 };
 
+static int nmk_pinctrl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct nmk_pinctrl *npct;
+
+	npct = platform_get_drvdata(pdev);
+	if (!npct)
+		return -EINVAL;
+
+	return pinctrl_force_sleep(npct->pctl);
+}
+
+static int nmk_pinctrl_resume(struct platform_device *pdev)
+{
+	struct nmk_pinctrl *npct;
+
+	npct = platform_get_drvdata(pdev);
+	if (!npct)
+		return -EINVAL;
+
+	return pinctrl_force_default(npct->pctl);
+}
+
 static int nmk_pinctrl_probe(struct platform_device *pdev)
 {
 	const struct platform_device_id *platid = platform_get_device_id(pdev);
 	struct device_node *np = pdev->dev.of_node;
+	struct device_node *prcm_np;
 	struct nmk_pinctrl *npct;
 	struct resource *res;
 	unsigned int version = 0;
@@ -1884,21 +2165,26 @@
 	if (version == PINCTRL_NMK_DB8540)
 		nmk_pinctrl_db8540_init(&npct->soc);
 
+	if (np) {
+		prcm_np = of_parse_phandle(np, "prcm", 0);
+		if (prcm_np)
+			npct->prcm_base = of_iomap(prcm_np, 0);
+	}
+
+	/* Allow platform passed information to over-write DT. */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res) {
+	if (res)
 		npct->prcm_base = devm_ioremap(&pdev->dev, res->start,
 					       resource_size(res));
-		if (!npct->prcm_base) {
-			dev_err(&pdev->dev,
-				"failed to ioremap PRCM registers\n");
-			return -ENOMEM;
+	if (!npct->prcm_base) {
+		if (version == PINCTRL_NMK_STN8815) {
+			dev_info(&pdev->dev,
+				 "No PRCM base, "
+				 "assuming no ALT-Cx control is available\n");
+		} else {
+			dev_err(&pdev->dev, "missing PRCM base address\n");
+			return -EINVAL;
 		}
-	} else if (version == PINCTRL_NMK_STN8815) {
-		dev_info(&pdev->dev,
-			 "No PRCM base, assume no ALT-Cx control is available\n");
-	} else {
-		dev_err(&pdev->dev, "missing PRCM base address\n");
-		return -EINVAL;
 	}
 
 	/*
@@ -1963,6 +2249,10 @@
 	},
 	.probe = nmk_pinctrl_probe,
 	.id_table = nmk_pinctrl_id,
+#ifdef CONFIG_PM
+	.suspend = nmk_pinctrl_suspend,
+	.resume = nmk_pinctrl_resume,
+#endif
 };
 
 static int __init nmk_gpio_init(void)
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index fd7b24c..5c20ed0 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -716,7 +716,6 @@
 	}
 	ctrldesc->pins = pindesc;
 	ctrldesc->npins = drvdata->ctrl->nr_pins;
-	ctrldesc->npins = drvdata->ctrl->nr_pins;
 
 	/* dynamically populate the pin number and pin name for pindesc */
 	for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
new file mode 100644
index 0000000..80b11e3
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -0,0 +1,1505 @@
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun4i_a10_pins[] = {
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* RTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* CTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* DTR */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* DSR */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* DCD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* RING */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x2, "uart0")),		/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x2, "uart0")),		/* RX */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart0")),		/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart0")),		/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+};
+
+static const struct sunxi_desc_pin sun5i_a13_pins[] = {
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* RX */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out"),
+		SUNXI_FUNCTION(0x4, "uart1")),		/* RX */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
+		SUNXI_FUNCTION(0x0, "gpio_in"),
+		SUNXI_FUNCTION(0x1, "gpio_out")),
+};
+
+static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
+	.pins = sun4i_a10_pins,
+	.npins = ARRAY_SIZE(sun4i_a10_pins),
+};
+
+static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = {
+	.pins = sun5i_a13_pins,
+	.npins = ARRAY_SIZE(sun5i_a13_pins),
+};
+
+static struct sunxi_pinctrl_group *
+sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
+{
+	int i;
+
+	for (i = 0; i < pctl->ngroups; i++) {
+		struct sunxi_pinctrl_group *grp = pctl->groups + i;
+
+		if (!strcmp(grp->name, group))
+			return grp;
+	}
+
+	return NULL;
+}
+
+static struct sunxi_pinctrl_function *
+sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl,
+				    const char *name)
+{
+	struct sunxi_pinctrl_function *func = pctl->functions;
+	int i;
+
+	for (i = 0; i < pctl->nfunctions; i++) {
+		if (!func[i].name)
+			break;
+
+		if (!strcmp(func[i].name, name))
+			return func + i;
+	}
+
+	return NULL;
+}
+
+static struct sunxi_desc_function *
+sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
+					 const char *pin_name,
+					 const char *func_name)
+{
+	int i;
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+
+		if (!strcmp(pin->pin.name, pin_name)) {
+			struct sunxi_desc_function *func = pin->functions;
+
+			while (func->name) {
+				if (!strcmp(func->name, func_name))
+					return func;
+
+				func++;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->ngroups;
+}
+
+static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+					      unsigned group)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->groups[group].name;
+}
+
+static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+				      unsigned group,
+				      const unsigned **pins,
+				      unsigned *num_pins)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = (unsigned *)&pctl->groups[group].pin;
+	*num_pins = 1;
+
+	return 0;
+}
+
+static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				      struct device_node *node,
+				      struct pinctrl_map **map,
+				      unsigned *num_maps)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	unsigned long *pinconfig;
+	struct property *prop;
+	const char *function;
+	const char *group;
+	int ret, nmaps, i = 0;
+	u32 val;
+
+	*map = NULL;
+	*num_maps = 0;
+
+	ret = of_property_read_string(node, "allwinner,function", &function);
+	if (ret) {
+		dev_err(pctl->dev,
+			"missing allwinner,function property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
+	if (nmaps < 0) {
+		dev_err(pctl->dev,
+			"missing allwinner,pins property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+	of_property_for_each_string(node, "allwinner,pins", prop, group) {
+		struct sunxi_pinctrl_group *grp =
+			sunxi_pinctrl_find_group_by_name(pctl, group);
+		int j = 0, configlen = 0;
+
+		if (!grp) {
+			dev_err(pctl->dev, "unknown pin %s", group);
+			continue;
+		}
+
+		if (!sunxi_pinctrl_desc_find_function_by_name(pctl,
+							      grp->name,
+							      function)) {
+			dev_err(pctl->dev, "unsupported function %s on pin %s",
+				function, group);
+			continue;
+		}
+
+		(*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
+		(*map)[i].data.mux.group = group;
+		(*map)[i].data.mux.function = function;
+
+		i++;
+
+		(*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+		(*map)[i].data.configs.group_or_pin = group;
+
+		if (of_find_property(node, "allwinner,drive", NULL))
+			configlen++;
+		if (of_find_property(node, "allwinner,pull", NULL))
+			configlen++;
+
+		pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
+
+		if (!of_property_read_u32(node, "allwinner,drive", &val)) {
+			u16 strength = (val + 1) * 10;
+			pinconfig[j++] =
+				pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
+							 strength);
+		}
+
+		if (!of_property_read_u32(node, "allwinner,pull", &val)) {
+			enum pin_config_param pull = PIN_CONFIG_END;
+			if (val == 1)
+				pull = PIN_CONFIG_BIAS_PULL_UP;
+			else if (val == 2)
+				pull = PIN_CONFIG_BIAS_PULL_DOWN;
+			pinconfig[j++] = pinconf_to_config_packed(pull, 0);
+		}
+
+		(*map)[i].data.configs.configs = pinconfig;
+		(*map)[i].data.configs.num_configs = configlen;
+
+		i++;
+	}
+
+	*num_maps = nmaps;
+
+	return 0;
+}
+
+static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
+				    struct pinctrl_map *map,
+				    unsigned num_maps)
+{
+	int i;
+
+	for (i = 0; i < num_maps; i++) {
+		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+			kfree(map[i].data.configs.configs);
+	}
+
+	kfree(map);
+}
+
+static struct pinctrl_ops sunxi_pctrl_ops = {
+	.dt_node_to_map		= sunxi_pctrl_dt_node_to_map,
+	.dt_free_map		= sunxi_pctrl_dt_free_map,
+	.get_groups_count	= sunxi_pctrl_get_groups_count,
+	.get_group_name		= sunxi_pctrl_get_group_name,
+	.get_group_pins		= sunxi_pctrl_get_group_pins,
+};
+
+static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
+				 unsigned group,
+				 unsigned long *config)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*config = pctl->groups[group].config;
+
+	return 0;
+}
+
+static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
+				 unsigned group,
+				 unsigned long config)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct sunxi_pinctrl_group *g = &pctl->groups[group];
+	u32 val, mask;
+	u16 strength;
+	u8 dlevel;
+
+	switch (pinconf_to_config_param(config)) {
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		strength = pinconf_to_config_argument(config);
+		if (strength > 40)
+			return -EINVAL;
+		/*
+		 * We convert from mA to what the register expects:
+		 *   0: 10mA
+		 *   1: 20mA
+		 *   2: 30mA
+		 *   3: 40mA
+		 */
+		dlevel = strength / 10 - 1;
+		val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
+	        mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
+		writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
+			pctl->membase + sunxi_dlevel_reg(g->pin));
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		val = readl(pctl->membase + sunxi_pull_reg(g->pin));
+		mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
+		writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
+			pctl->membase + sunxi_pull_reg(g->pin));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		val = readl(pctl->membase + sunxi_pull_reg(g->pin));
+		mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
+		writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
+			pctl->membase + sunxi_pull_reg(g->pin));
+		break;
+	default:
+		break;
+	}
+
+	/* cache the config value */
+	g->config = config;
+
+	return 0;
+}
+
+static struct pinconf_ops sunxi_pconf_ops = {
+	.pin_config_group_get	= sunxi_pconf_group_get,
+	.pin_config_group_set	= sunxi_pconf_group_set,
+};
+
+static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->nfunctions;
+}
+
+static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					   unsigned function)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctl->functions[function].name;
+}
+
+static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				     unsigned function,
+				     const char * const **groups,
+				     unsigned * const num_groups)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pctl->functions[function].groups;
+	*num_groups = pctl->functions[function].ngroups;
+
+	return 0;
+}
+
+static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
+				 unsigned pin,
+				 u8 config)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	u32 val = readl(pctl->membase + sunxi_mux_reg(pin));
+	u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
+	writel((val & ~mask) | config << sunxi_mux_offset(pin),
+		pctl->membase + sunxi_mux_reg(pin));
+}
+
+static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
+			    unsigned function,
+			    unsigned group)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct sunxi_pinctrl_group *g = pctl->groups + group;
+	struct sunxi_pinctrl_function *func = pctl->functions + function;
+	struct sunxi_desc_function *desc =
+		sunxi_pinctrl_desc_find_function_by_name(pctl,
+							 g->name,
+							 func->name);
+
+	if (!desc)
+		return -EINVAL;
+
+	sunxi_pmx_set(pctldev, g->pin, desc->muxval);
+
+	return 0;
+}
+
+static int
+sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+			struct pinctrl_gpio_range *range,
+			unsigned offset,
+			bool input)
+{
+	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct sunxi_desc_function *desc;
+	char pin_name[SUNXI_PIN_NAME_MAX_LEN];
+	const char *func;
+	u8 bank, pin;
+	int ret;
+
+	bank = (offset) / PINS_PER_BANK;
+	pin = (offset) % PINS_PER_BANK;
+
+	ret = sprintf(pin_name, "P%c%d", 'A' + bank, pin);
+	if (!ret)
+		goto error;
+
+	if (input)
+		func = "gpio_in";
+	else
+		func = "gpio_out";
+
+	desc = sunxi_pinctrl_desc_find_function_by_name(pctl,
+							pin_name,
+							func);
+	if (!desc) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	sunxi_pmx_set(pctldev, offset, desc->muxval);
+
+	ret = 0;
+
+error:
+	return ret;
+}
+
+static struct pinmux_ops sunxi_pmx_ops = {
+	.get_functions_count	= sunxi_pmx_get_funcs_cnt,
+	.get_function_name	= sunxi_pmx_get_func_name,
+	.get_function_groups	= sunxi_pmx_get_func_groups,
+	.enable			= sunxi_pmx_enable,
+	.gpio_set_direction	= sunxi_pmx_gpio_set_direction,
+};
+
+static struct pinctrl_desc sunxi_pctrl_desc = {
+	.confops	= &sunxi_pconf_ops,
+	.pctlops	= &sunxi_pctrl_ops,
+	.pmxops		= &sunxi_pmx_ops,
+};
+
+static int sunxi_pinctrl_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void sunxi_pinctrl_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	pinctrl_free_gpio(chip->base + offset);
+}
+
+static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
+					unsigned offset)
+{
+	return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+
+	u32 reg = sunxi_data_reg(offset);
+	u8 index = sunxi_data_offset(offset);
+	u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+
+	return val;
+}
+
+static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
+static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
+				unsigned offset, int value)
+{
+	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+	u32 reg = sunxi_data_reg(offset);
+	u8 index = sunxi_data_offset(offset);
+
+	writel((value & DATA_PINS_MASK) << index, pctl->membase + reg);
+}
+
+static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
+				const struct of_phandle_args *gpiospec,
+				u32 *flags)
+{
+	int pin, base;
+
+	base = PINS_PER_BANK * gpiospec->args[0];
+	pin = base + gpiospec->args[1];
+
+	if (pin > (gc->base + gc->ngpio))
+		return -EINVAL;
+
+	if (flags)
+		*flags = gpiospec->args[2];
+
+	return pin;
+}
+
+static struct gpio_chip sunxi_pinctrl_gpio_chip = {
+	.owner			= THIS_MODULE,
+	.request		= sunxi_pinctrl_gpio_request,
+	.free			= sunxi_pinctrl_gpio_free,
+	.direction_input	= sunxi_pinctrl_gpio_direction_input,
+	.direction_output	= sunxi_pinctrl_gpio_direction_output,
+	.get			= sunxi_pinctrl_gpio_get,
+	.set			= sunxi_pinctrl_gpio_set,
+	.of_xlate		= sunxi_pinctrl_gpio_of_xlate,
+	.of_gpio_n_cells	= 3,
+	.can_sleep		= 0,
+};
+
+static struct of_device_id sunxi_pinctrl_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data },
+	{ .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sunxi_pinctrl_match);
+
+static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
+					const char *name)
+{
+	struct sunxi_pinctrl_function *func = pctl->functions;
+
+	while (func->name) {
+		/* function already there */
+		if (strcmp(func->name, name) == 0) {
+			func->ngroups++;
+			return -EEXIST;
+		}
+		func++;
+	}
+
+	func->name = name;
+	func->ngroups = 1;
+
+	pctl->nfunctions++;
+
+	return 0;
+}
+
+static int sunxi_pinctrl_build_state(struct platform_device *pdev)
+{
+	struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
+	int i;
+
+	pctl->ngroups = pctl->desc->npins;
+
+	/* Allocate groups */
+	pctl->groups = devm_kzalloc(&pdev->dev,
+				    pctl->ngroups * sizeof(*pctl->groups),
+				    GFP_KERNEL);
+	if (!pctl->groups)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+		struct sunxi_pinctrl_group *group = pctl->groups + i;
+
+		group->name = pin->pin.name;
+		group->pin = pin->pin.number;
+	}
+
+	/*
+	 * We suppose that we won't have any more functions than pins,
+	 * we'll reallocate that later anyway
+	 */
+	pctl->functions = devm_kzalloc(&pdev->dev,
+				pctl->desc->npins * sizeof(*pctl->functions),
+				GFP_KERNEL);
+	if (!pctl->functions)
+		return -ENOMEM;
+
+	/* Count functions and their associated groups */
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+		struct sunxi_desc_function *func = pin->functions;
+
+		while (func->name) {
+			sunxi_pinctrl_add_function(pctl, func->name);
+			func++;
+		}
+	}
+
+	pctl->functions = krealloc(pctl->functions,
+				pctl->nfunctions * sizeof(*pctl->functions),
+				GFP_KERNEL);
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+		struct sunxi_desc_function *func = pin->functions;
+
+		while (func->name) {
+			struct sunxi_pinctrl_function *func_item;
+			const char **func_grp;
+
+			func_item = sunxi_pinctrl_find_function_by_name(pctl,
+									func->name);
+			if (!func_item)
+				return -EINVAL;
+
+			if (!func_item->groups) {
+				func_item->groups =
+					devm_kzalloc(&pdev->dev,
+						     func_item->ngroups * sizeof(*func_item->groups),
+						     GFP_KERNEL);
+				if (!func_item->groups)
+					return -ENOMEM;
+			}
+
+			func_grp = func_item->groups;
+			while (*func_grp)
+				func_grp++;
+
+			*func_grp = pin->pin.name;
+			func++;
+		}
+	}
+
+	return 0;
+}
+
+static int sunxi_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	const struct of_device_id *device;
+	struct pinctrl_pin_desc *pins;
+	struct sunxi_pinctrl *pctl;
+	int i, ret, last_pin;
+
+	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+	if (!pctl)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, pctl);
+
+	pctl->membase = of_iomap(node, 0);
+	if (!pctl->membase)
+		return -ENOMEM;
+
+	device = of_match_device(sunxi_pinctrl_match, &pdev->dev);
+	if (!device)
+		return -ENODEV;
+
+	pctl->desc = (struct sunxi_pinctrl_desc *)device->data;
+
+	ret = sunxi_pinctrl_build_state(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
+		return ret;
+	}
+
+	pins = devm_kzalloc(&pdev->dev,
+			    pctl->desc->npins * sizeof(*pins),
+			    GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl->desc->npins; i++)
+		pins[i] = pctl->desc->pins[i].pin;
+
+	sunxi_pctrl_desc.name = dev_name(&pdev->dev);
+	sunxi_pctrl_desc.owner = THIS_MODULE;
+	sunxi_pctrl_desc.pins = pins;
+	sunxi_pctrl_desc.npins = pctl->desc->npins;
+	pctl->dev = &pdev->dev;
+	pctl->pctl_dev = pinctrl_register(&sunxi_pctrl_desc,
+					  &pdev->dev, pctl);
+	if (!pctl->pctl_dev) {
+		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+		return -EINVAL;
+	}
+
+	pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
+	if (!pctl->chip) {
+		ret = -ENOMEM;
+		goto pinctrl_error;
+	}
+
+	last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
+	pctl->chip = &sunxi_pinctrl_gpio_chip;
+	pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK);
+	pctl->chip->label = dev_name(&pdev->dev);
+	pctl->chip->dev = &pdev->dev;
+	pctl->chip->base = 0;
+
+	ret = gpiochip_add(pctl->chip);
+	if (ret)
+		goto pinctrl_error;
+
+	for (i = 0; i < pctl->desc->npins; i++) {
+		const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+
+		ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
+					     pin->pin.number,
+					     pin->pin.number, 1);
+		if (ret)
+			goto gpiochip_error;
+	}
+
+	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
+
+	return 0;
+
+gpiochip_error:
+	ret = gpiochip_remove(pctl->chip);
+pinctrl_error:
+	pinctrl_unregister(pctl->pctl_dev);
+	return ret;
+}
+
+static struct platform_driver sunxi_pinctrl_driver = {
+	.probe = sunxi_pinctrl_probe,
+	.driver = {
+		.name = "sunxi-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = sunxi_pinctrl_match,
+	},
+};
+module_platform_driver(sunxi_pinctrl_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("Allwinner A1X pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
new file mode 100644
index 0000000..e921621
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -0,0 +1,478 @@
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINCTRL_SUNXI_H
+#define __PINCTRL_SUNXI_H
+
+#include <linux/kernel.h>
+
+#define PA_BASE	0
+#define PB_BASE	32
+#define PC_BASE	64
+#define PD_BASE	96
+#define PE_BASE	128
+#define PF_BASE	160
+#define PG_BASE	192
+#define PH_BASE	224
+#define PI_BASE	256
+
+#define SUNXI_PINCTRL_PIN_PA0	PINCTRL_PIN(PA_BASE + 0, "PA0")
+#define SUNXI_PINCTRL_PIN_PA1	PINCTRL_PIN(PA_BASE + 1, "PA1")
+#define SUNXI_PINCTRL_PIN_PA2	PINCTRL_PIN(PA_BASE + 2, "PA2")
+#define SUNXI_PINCTRL_PIN_PA3	PINCTRL_PIN(PA_BASE + 3, "PA3")
+#define SUNXI_PINCTRL_PIN_PA4	PINCTRL_PIN(PA_BASE + 4, "PA4")
+#define SUNXI_PINCTRL_PIN_PA5	PINCTRL_PIN(PA_BASE + 5, "PA5")
+#define SUNXI_PINCTRL_PIN_PA6	PINCTRL_PIN(PA_BASE + 6, "PA6")
+#define SUNXI_PINCTRL_PIN_PA7	PINCTRL_PIN(PA_BASE + 7, "PA7")
+#define SUNXI_PINCTRL_PIN_PA8	PINCTRL_PIN(PA_BASE + 8, "PA8")
+#define SUNXI_PINCTRL_PIN_PA9	PINCTRL_PIN(PA_BASE + 9, "PA9")
+#define SUNXI_PINCTRL_PIN_PA10	PINCTRL_PIN(PA_BASE + 10, "PA10")
+#define SUNXI_PINCTRL_PIN_PA11	PINCTRL_PIN(PA_BASE + 11, "PA11")
+#define SUNXI_PINCTRL_PIN_PA12	PINCTRL_PIN(PA_BASE + 12, "PA12")
+#define SUNXI_PINCTRL_PIN_PA13	PINCTRL_PIN(PA_BASE + 13, "PA13")
+#define SUNXI_PINCTRL_PIN_PA14	PINCTRL_PIN(PA_BASE + 14, "PA14")
+#define SUNXI_PINCTRL_PIN_PA15	PINCTRL_PIN(PA_BASE + 15, "PA15")
+#define SUNXI_PINCTRL_PIN_PA16	PINCTRL_PIN(PA_BASE + 16, "PA16")
+#define SUNXI_PINCTRL_PIN_PA17	PINCTRL_PIN(PA_BASE + 17, "PA17")
+#define SUNXI_PINCTRL_PIN_PA18	PINCTRL_PIN(PA_BASE + 18, "PA18")
+#define SUNXI_PINCTRL_PIN_PA19	PINCTRL_PIN(PA_BASE + 19, "PA19")
+#define SUNXI_PINCTRL_PIN_PA20	PINCTRL_PIN(PA_BASE + 20, "PA20")
+#define SUNXI_PINCTRL_PIN_PA21	PINCTRL_PIN(PA_BASE + 21, "PA21")
+#define SUNXI_PINCTRL_PIN_PA22	PINCTRL_PIN(PA_BASE + 22, "PA22")
+#define SUNXI_PINCTRL_PIN_PA23	PINCTRL_PIN(PA_BASE + 23, "PA23")
+#define SUNXI_PINCTRL_PIN_PA24	PINCTRL_PIN(PA_BASE + 24, "PA24")
+#define SUNXI_PINCTRL_PIN_PA25	PINCTRL_PIN(PA_BASE + 25, "PA25")
+#define SUNXI_PINCTRL_PIN_PA26	PINCTRL_PIN(PA_BASE + 26, "PA26")
+#define SUNXI_PINCTRL_PIN_PA27	PINCTRL_PIN(PA_BASE + 27, "PA27")
+#define SUNXI_PINCTRL_PIN_PA28	PINCTRL_PIN(PA_BASE + 28, "PA28")
+#define SUNXI_PINCTRL_PIN_PA29	PINCTRL_PIN(PA_BASE + 29, "PA29")
+#define SUNXI_PINCTRL_PIN_PA30	PINCTRL_PIN(PA_BASE + 30, "PA30")
+#define SUNXI_PINCTRL_PIN_PA31	PINCTRL_PIN(PA_BASE + 31, "PA31")
+
+#define SUNXI_PINCTRL_PIN_PB0	PINCTRL_PIN(PB_BASE + 0, "PB0")
+#define SUNXI_PINCTRL_PIN_PB1	PINCTRL_PIN(PB_BASE + 1, "PB1")
+#define SUNXI_PINCTRL_PIN_PB2	PINCTRL_PIN(PB_BASE + 2, "PB2")
+#define SUNXI_PINCTRL_PIN_PB3	PINCTRL_PIN(PB_BASE + 3, "PB3")
+#define SUNXI_PINCTRL_PIN_PB4	PINCTRL_PIN(PB_BASE + 4, "PB4")
+#define SUNXI_PINCTRL_PIN_PB5	PINCTRL_PIN(PB_BASE + 5, "PB5")
+#define SUNXI_PINCTRL_PIN_PB6	PINCTRL_PIN(PB_BASE + 6, "PB6")
+#define SUNXI_PINCTRL_PIN_PB7	PINCTRL_PIN(PB_BASE + 7, "PB7")
+#define SUNXI_PINCTRL_PIN_PB8	PINCTRL_PIN(PB_BASE + 8, "PB8")
+#define SUNXI_PINCTRL_PIN_PB9	PINCTRL_PIN(PB_BASE + 9, "PB9")
+#define SUNXI_PINCTRL_PIN_PB10	PINCTRL_PIN(PB_BASE + 10, "PB10")
+#define SUNXI_PINCTRL_PIN_PB11	PINCTRL_PIN(PB_BASE + 11, "PB11")
+#define SUNXI_PINCTRL_PIN_PB12	PINCTRL_PIN(PB_BASE + 12, "PB12")
+#define SUNXI_PINCTRL_PIN_PB13	PINCTRL_PIN(PB_BASE + 13, "PB13")
+#define SUNXI_PINCTRL_PIN_PB14	PINCTRL_PIN(PB_BASE + 14, "PB14")
+#define SUNXI_PINCTRL_PIN_PB15	PINCTRL_PIN(PB_BASE + 15, "PB15")
+#define SUNXI_PINCTRL_PIN_PB16	PINCTRL_PIN(PB_BASE + 16, "PB16")
+#define SUNXI_PINCTRL_PIN_PB17	PINCTRL_PIN(PB_BASE + 17, "PB17")
+#define SUNXI_PINCTRL_PIN_PB18	PINCTRL_PIN(PB_BASE + 18, "PB18")
+#define SUNXI_PINCTRL_PIN_PB19	PINCTRL_PIN(PB_BASE + 19, "PB19")
+#define SUNXI_PINCTRL_PIN_PB20	PINCTRL_PIN(PB_BASE + 20, "PB20")
+#define SUNXI_PINCTRL_PIN_PB21	PINCTRL_PIN(PB_BASE + 21, "PB21")
+#define SUNXI_PINCTRL_PIN_PB22	PINCTRL_PIN(PB_BASE + 22, "PB22")
+#define SUNXI_PINCTRL_PIN_PB23	PINCTRL_PIN(PB_BASE + 23, "PB23")
+#define SUNXI_PINCTRL_PIN_PB24	PINCTRL_PIN(PB_BASE + 24, "PB24")
+#define SUNXI_PINCTRL_PIN_PB25	PINCTRL_PIN(PB_BASE + 25, "PB25")
+#define SUNXI_PINCTRL_PIN_PB26	PINCTRL_PIN(PB_BASE + 26, "PB26")
+#define SUNXI_PINCTRL_PIN_PB27	PINCTRL_PIN(PB_BASE + 27, "PB27")
+#define SUNXI_PINCTRL_PIN_PB28	PINCTRL_PIN(PB_BASE + 28, "PB28")
+#define SUNXI_PINCTRL_PIN_PB29	PINCTRL_PIN(PB_BASE + 29, "PB29")
+#define SUNXI_PINCTRL_PIN_PB30	PINCTRL_PIN(PB_BASE + 30, "PB30")
+#define SUNXI_PINCTRL_PIN_PB31	PINCTRL_PIN(PB_BASE + 31, "PB31")
+
+#define SUNXI_PINCTRL_PIN_PC0	PINCTRL_PIN(PC_BASE + 0, "PC0")
+#define SUNXI_PINCTRL_PIN_PC1	PINCTRL_PIN(PC_BASE + 1, "PC1")
+#define SUNXI_PINCTRL_PIN_PC2	PINCTRL_PIN(PC_BASE + 2, "PC2")
+#define SUNXI_PINCTRL_PIN_PC3	PINCTRL_PIN(PC_BASE + 3, "PC3")
+#define SUNXI_PINCTRL_PIN_PC4	PINCTRL_PIN(PC_BASE + 4, "PC4")
+#define SUNXI_PINCTRL_PIN_PC5	PINCTRL_PIN(PC_BASE + 5, "PC5")
+#define SUNXI_PINCTRL_PIN_PC6	PINCTRL_PIN(PC_BASE + 6, "PC6")
+#define SUNXI_PINCTRL_PIN_PC7	PINCTRL_PIN(PC_BASE + 7, "PC7")
+#define SUNXI_PINCTRL_PIN_PC8	PINCTRL_PIN(PC_BASE + 8, "PC8")
+#define SUNXI_PINCTRL_PIN_PC9	PINCTRL_PIN(PC_BASE + 9, "PC9")
+#define SUNXI_PINCTRL_PIN_PC10	PINCTRL_PIN(PC_BASE + 10, "PC10")
+#define SUNXI_PINCTRL_PIN_PC11	PINCTRL_PIN(PC_BASE + 11, "PC11")
+#define SUNXI_PINCTRL_PIN_PC12	PINCTRL_PIN(PC_BASE + 12, "PC12")
+#define SUNXI_PINCTRL_PIN_PC13	PINCTRL_PIN(PC_BASE + 13, "PC13")
+#define SUNXI_PINCTRL_PIN_PC14	PINCTRL_PIN(PC_BASE + 14, "PC14")
+#define SUNXI_PINCTRL_PIN_PC15	PINCTRL_PIN(PC_BASE + 15, "PC15")
+#define SUNXI_PINCTRL_PIN_PC16	PINCTRL_PIN(PC_BASE + 16, "PC16")
+#define SUNXI_PINCTRL_PIN_PC17	PINCTRL_PIN(PC_BASE + 17, "PC17")
+#define SUNXI_PINCTRL_PIN_PC18	PINCTRL_PIN(PC_BASE + 18, "PC18")
+#define SUNXI_PINCTRL_PIN_PC19	PINCTRL_PIN(PC_BASE + 19, "PC19")
+#define SUNXI_PINCTRL_PIN_PC20	PINCTRL_PIN(PC_BASE + 20, "PC20")
+#define SUNXI_PINCTRL_PIN_PC21	PINCTRL_PIN(PC_BASE + 21, "PC21")
+#define SUNXI_PINCTRL_PIN_PC22	PINCTRL_PIN(PC_BASE + 22, "PC22")
+#define SUNXI_PINCTRL_PIN_PC23	PINCTRL_PIN(PC_BASE + 23, "PC23")
+#define SUNXI_PINCTRL_PIN_PC24	PINCTRL_PIN(PC_BASE + 24, "PC24")
+#define SUNXI_PINCTRL_PIN_PC25	PINCTRL_PIN(PC_BASE + 25, "PC25")
+#define SUNXI_PINCTRL_PIN_PC26	PINCTRL_PIN(PC_BASE + 26, "PC26")
+#define SUNXI_PINCTRL_PIN_PC27	PINCTRL_PIN(PC_BASE + 27, "PC27")
+#define SUNXI_PINCTRL_PIN_PC28	PINCTRL_PIN(PC_BASE + 28, "PC28")
+#define SUNXI_PINCTRL_PIN_PC29	PINCTRL_PIN(PC_BASE + 29, "PC29")
+#define SUNXI_PINCTRL_PIN_PC30	PINCTRL_PIN(PC_BASE + 30, "PC30")
+#define SUNXI_PINCTRL_PIN_PC31	PINCTRL_PIN(PC_BASE + 31, "PC31")
+
+#define SUNXI_PINCTRL_PIN_PD0	PINCTRL_PIN(PD_BASE + 0, "PD0")
+#define SUNXI_PINCTRL_PIN_PD1	PINCTRL_PIN(PD_BASE + 1, "PD1")
+#define SUNXI_PINCTRL_PIN_PD2	PINCTRL_PIN(PD_BASE + 2, "PD2")
+#define SUNXI_PINCTRL_PIN_PD3	PINCTRL_PIN(PD_BASE + 3, "PD3")
+#define SUNXI_PINCTRL_PIN_PD4	PINCTRL_PIN(PD_BASE + 4, "PD4")
+#define SUNXI_PINCTRL_PIN_PD5	PINCTRL_PIN(PD_BASE + 5, "PD5")
+#define SUNXI_PINCTRL_PIN_PD6	PINCTRL_PIN(PD_BASE + 6, "PD6")
+#define SUNXI_PINCTRL_PIN_PD7	PINCTRL_PIN(PD_BASE + 7, "PD7")
+#define SUNXI_PINCTRL_PIN_PD8	PINCTRL_PIN(PD_BASE + 8, "PD8")
+#define SUNXI_PINCTRL_PIN_PD9	PINCTRL_PIN(PD_BASE + 9, "PD9")
+#define SUNXI_PINCTRL_PIN_PD10	PINCTRL_PIN(PD_BASE + 10, "PD10")
+#define SUNXI_PINCTRL_PIN_PD11	PINCTRL_PIN(PD_BASE + 11, "PD11")
+#define SUNXI_PINCTRL_PIN_PD12	PINCTRL_PIN(PD_BASE + 12, "PD12")
+#define SUNXI_PINCTRL_PIN_PD13	PINCTRL_PIN(PD_BASE + 13, "PD13")
+#define SUNXI_PINCTRL_PIN_PD14	PINCTRL_PIN(PD_BASE + 14, "PD14")
+#define SUNXI_PINCTRL_PIN_PD15	PINCTRL_PIN(PD_BASE + 15, "PD15")
+#define SUNXI_PINCTRL_PIN_PD16	PINCTRL_PIN(PD_BASE + 16, "PD16")
+#define SUNXI_PINCTRL_PIN_PD17	PINCTRL_PIN(PD_BASE + 17, "PD17")
+#define SUNXI_PINCTRL_PIN_PD18	PINCTRL_PIN(PD_BASE + 18, "PD18")
+#define SUNXI_PINCTRL_PIN_PD19	PINCTRL_PIN(PD_BASE + 19, "PD19")
+#define SUNXI_PINCTRL_PIN_PD20	PINCTRL_PIN(PD_BASE + 20, "PD20")
+#define SUNXI_PINCTRL_PIN_PD21	PINCTRL_PIN(PD_BASE + 21, "PD21")
+#define SUNXI_PINCTRL_PIN_PD22	PINCTRL_PIN(PD_BASE + 22, "PD22")
+#define SUNXI_PINCTRL_PIN_PD23	PINCTRL_PIN(PD_BASE + 23, "PD23")
+#define SUNXI_PINCTRL_PIN_PD24	PINCTRL_PIN(PD_BASE + 24, "PD24")
+#define SUNXI_PINCTRL_PIN_PD25	PINCTRL_PIN(PD_BASE + 25, "PD25")
+#define SUNXI_PINCTRL_PIN_PD26	PINCTRL_PIN(PD_BASE + 26, "PD26")
+#define SUNXI_PINCTRL_PIN_PD27	PINCTRL_PIN(PD_BASE + 27, "PD27")
+#define SUNXI_PINCTRL_PIN_PD28	PINCTRL_PIN(PD_BASE + 28, "PD28")
+#define SUNXI_PINCTRL_PIN_PD29	PINCTRL_PIN(PD_BASE + 29, "PD29")
+#define SUNXI_PINCTRL_PIN_PD30	PINCTRL_PIN(PD_BASE + 30, "PD30")
+#define SUNXI_PINCTRL_PIN_PD31	PINCTRL_PIN(PD_BASE + 31, "PD31")
+
+#define SUNXI_PINCTRL_PIN_PE0	PINCTRL_PIN(PE_BASE + 0, "PE0")
+#define SUNXI_PINCTRL_PIN_PE1	PINCTRL_PIN(PE_BASE + 1, "PE1")
+#define SUNXI_PINCTRL_PIN_PE2	PINCTRL_PIN(PE_BASE + 2, "PE2")
+#define SUNXI_PINCTRL_PIN_PE3	PINCTRL_PIN(PE_BASE + 3, "PE3")
+#define SUNXI_PINCTRL_PIN_PE4	PINCTRL_PIN(PE_BASE + 4, "PE4")
+#define SUNXI_PINCTRL_PIN_PE5	PINCTRL_PIN(PE_BASE + 5, "PE5")
+#define SUNXI_PINCTRL_PIN_PE6	PINCTRL_PIN(PE_BASE + 6, "PE6")
+#define SUNXI_PINCTRL_PIN_PE7	PINCTRL_PIN(PE_BASE + 7, "PE7")
+#define SUNXI_PINCTRL_PIN_PE8	PINCTRL_PIN(PE_BASE + 8, "PE8")
+#define SUNXI_PINCTRL_PIN_PE9	PINCTRL_PIN(PE_BASE + 9, "PE9")
+#define SUNXI_PINCTRL_PIN_PE10	PINCTRL_PIN(PE_BASE + 10, "PE10")
+#define SUNXI_PINCTRL_PIN_PE11	PINCTRL_PIN(PE_BASE + 11, "PE11")
+#define SUNXI_PINCTRL_PIN_PE12	PINCTRL_PIN(PE_BASE + 12, "PE12")
+#define SUNXI_PINCTRL_PIN_PE13	PINCTRL_PIN(PE_BASE + 13, "PE13")
+#define SUNXI_PINCTRL_PIN_PE14	PINCTRL_PIN(PE_BASE + 14, "PE14")
+#define SUNXI_PINCTRL_PIN_PE15	PINCTRL_PIN(PE_BASE + 15, "PE15")
+#define SUNXI_PINCTRL_PIN_PE16	PINCTRL_PIN(PE_BASE + 16, "PE16")
+#define SUNXI_PINCTRL_PIN_PE17	PINCTRL_PIN(PE_BASE + 17, "PE17")
+#define SUNXI_PINCTRL_PIN_PE18	PINCTRL_PIN(PE_BASE + 18, "PE18")
+#define SUNXI_PINCTRL_PIN_PE19	PINCTRL_PIN(PE_BASE + 19, "PE19")
+#define SUNXI_PINCTRL_PIN_PE20	PINCTRL_PIN(PE_BASE + 20, "PE20")
+#define SUNXI_PINCTRL_PIN_PE21	PINCTRL_PIN(PE_BASE + 21, "PE21")
+#define SUNXI_PINCTRL_PIN_PE22	PINCTRL_PIN(PE_BASE + 22, "PE22")
+#define SUNXI_PINCTRL_PIN_PE23	PINCTRL_PIN(PE_BASE + 23, "PE23")
+#define SUNXI_PINCTRL_PIN_PE24	PINCTRL_PIN(PE_BASE + 24, "PE24")
+#define SUNXI_PINCTRL_PIN_PE25	PINCTRL_PIN(PE_BASE + 25, "PE25")
+#define SUNXI_PINCTRL_PIN_PE26	PINCTRL_PIN(PE_BASE + 26, "PE26")
+#define SUNXI_PINCTRL_PIN_PE27	PINCTRL_PIN(PE_BASE + 27, "PE27")
+#define SUNXI_PINCTRL_PIN_PE28	PINCTRL_PIN(PE_BASE + 28, "PE28")
+#define SUNXI_PINCTRL_PIN_PE29	PINCTRL_PIN(PE_BASE + 29, "PE29")
+#define SUNXI_PINCTRL_PIN_PE30	PINCTRL_PIN(PE_BASE + 30, "PE30")
+#define SUNXI_PINCTRL_PIN_PE31	PINCTRL_PIN(PE_BASE + 31, "PE31")
+
+#define SUNXI_PINCTRL_PIN_PF0	PINCTRL_PIN(PF_BASE + 0, "PF0")
+#define SUNXI_PINCTRL_PIN_PF1	PINCTRL_PIN(PF_BASE + 1, "PF1")
+#define SUNXI_PINCTRL_PIN_PF2	PINCTRL_PIN(PF_BASE + 2, "PF2")
+#define SUNXI_PINCTRL_PIN_PF3	PINCTRL_PIN(PF_BASE + 3, "PF3")
+#define SUNXI_PINCTRL_PIN_PF4	PINCTRL_PIN(PF_BASE + 4, "PF4")
+#define SUNXI_PINCTRL_PIN_PF5	PINCTRL_PIN(PF_BASE + 5, "PF5")
+#define SUNXI_PINCTRL_PIN_PF6	PINCTRL_PIN(PF_BASE + 6, "PF6")
+#define SUNXI_PINCTRL_PIN_PF7	PINCTRL_PIN(PF_BASE + 7, "PF7")
+#define SUNXI_PINCTRL_PIN_PF8	PINCTRL_PIN(PF_BASE + 8, "PF8")
+#define SUNXI_PINCTRL_PIN_PF9	PINCTRL_PIN(PF_BASE + 9, "PF9")
+#define SUNXI_PINCTRL_PIN_PF10	PINCTRL_PIN(PF_BASE + 10, "PF10")
+#define SUNXI_PINCTRL_PIN_PF11	PINCTRL_PIN(PF_BASE + 11, "PF11")
+#define SUNXI_PINCTRL_PIN_PF12	PINCTRL_PIN(PF_BASE + 12, "PF12")
+#define SUNXI_PINCTRL_PIN_PF13	PINCTRL_PIN(PF_BASE + 13, "PF13")
+#define SUNXI_PINCTRL_PIN_PF14	PINCTRL_PIN(PF_BASE + 14, "PF14")
+#define SUNXI_PINCTRL_PIN_PF15	PINCTRL_PIN(PF_BASE + 15, "PF15")
+#define SUNXI_PINCTRL_PIN_PF16	PINCTRL_PIN(PF_BASE + 16, "PF16")
+#define SUNXI_PINCTRL_PIN_PF17	PINCTRL_PIN(PF_BASE + 17, "PF17")
+#define SUNXI_PINCTRL_PIN_PF18	PINCTRL_PIN(PF_BASE + 18, "PF18")
+#define SUNXI_PINCTRL_PIN_PF19	PINCTRL_PIN(PF_BASE + 19, "PF19")
+#define SUNXI_PINCTRL_PIN_PF20	PINCTRL_PIN(PF_BASE + 20, "PF20")
+#define SUNXI_PINCTRL_PIN_PF21	PINCTRL_PIN(PF_BASE + 21, "PF21")
+#define SUNXI_PINCTRL_PIN_PF22	PINCTRL_PIN(PF_BASE + 22, "PF22")
+#define SUNXI_PINCTRL_PIN_PF23	PINCTRL_PIN(PF_BASE + 23, "PF23")
+#define SUNXI_PINCTRL_PIN_PF24	PINCTRL_PIN(PF_BASE + 24, "PF24")
+#define SUNXI_PINCTRL_PIN_PF25	PINCTRL_PIN(PF_BASE + 25, "PF25")
+#define SUNXI_PINCTRL_PIN_PF26	PINCTRL_PIN(PF_BASE + 26, "PF26")
+#define SUNXI_PINCTRL_PIN_PF27	PINCTRL_PIN(PF_BASE + 27, "PF27")
+#define SUNXI_PINCTRL_PIN_PF28	PINCTRL_PIN(PF_BASE + 28, "PF28")
+#define SUNXI_PINCTRL_PIN_PF29	PINCTRL_PIN(PF_BASE + 29, "PF29")
+#define SUNXI_PINCTRL_PIN_PF30	PINCTRL_PIN(PF_BASE + 30, "PF30")
+#define SUNXI_PINCTRL_PIN_PF31	PINCTRL_PIN(PF_BASE + 31, "PF31")
+
+#define SUNXI_PINCTRL_PIN_PG0	PINCTRL_PIN(PG_BASE + 0, "PG0")
+#define SUNXI_PINCTRL_PIN_PG1	PINCTRL_PIN(PG_BASE + 1, "PG1")
+#define SUNXI_PINCTRL_PIN_PG2	PINCTRL_PIN(PG_BASE + 2, "PG2")
+#define SUNXI_PINCTRL_PIN_PG3	PINCTRL_PIN(PG_BASE + 3, "PG3")
+#define SUNXI_PINCTRL_PIN_PG4	PINCTRL_PIN(PG_BASE + 4, "PG4")
+#define SUNXI_PINCTRL_PIN_PG5	PINCTRL_PIN(PG_BASE + 5, "PG5")
+#define SUNXI_PINCTRL_PIN_PG6	PINCTRL_PIN(PG_BASE + 6, "PG6")
+#define SUNXI_PINCTRL_PIN_PG7	PINCTRL_PIN(PG_BASE + 7, "PG7")
+#define SUNXI_PINCTRL_PIN_PG8	PINCTRL_PIN(PG_BASE + 8, "PG8")
+#define SUNXI_PINCTRL_PIN_PG9	PINCTRL_PIN(PG_BASE + 9, "PG9")
+#define SUNXI_PINCTRL_PIN_PG10	PINCTRL_PIN(PG_BASE + 10, "PG10")
+#define SUNXI_PINCTRL_PIN_PG11	PINCTRL_PIN(PG_BASE + 11, "PG11")
+#define SUNXI_PINCTRL_PIN_PG12	PINCTRL_PIN(PG_BASE + 12, "PG12")
+#define SUNXI_PINCTRL_PIN_PG13	PINCTRL_PIN(PG_BASE + 13, "PG13")
+#define SUNXI_PINCTRL_PIN_PG14	PINCTRL_PIN(PG_BASE + 14, "PG14")
+#define SUNXI_PINCTRL_PIN_PG15	PINCTRL_PIN(PG_BASE + 15, "PG15")
+#define SUNXI_PINCTRL_PIN_PG16	PINCTRL_PIN(PG_BASE + 16, "PG16")
+#define SUNXI_PINCTRL_PIN_PG17	PINCTRL_PIN(PG_BASE + 17, "PG17")
+#define SUNXI_PINCTRL_PIN_PG18	PINCTRL_PIN(PG_BASE + 18, "PG18")
+#define SUNXI_PINCTRL_PIN_PG19	PINCTRL_PIN(PG_BASE + 19, "PG19")
+#define SUNXI_PINCTRL_PIN_PG20	PINCTRL_PIN(PG_BASE + 20, "PG20")
+#define SUNXI_PINCTRL_PIN_PG21	PINCTRL_PIN(PG_BASE + 21, "PG21")
+#define SUNXI_PINCTRL_PIN_PG22	PINCTRL_PIN(PG_BASE + 22, "PG22")
+#define SUNXI_PINCTRL_PIN_PG23	PINCTRL_PIN(PG_BASE + 23, "PG23")
+#define SUNXI_PINCTRL_PIN_PG24	PINCTRL_PIN(PG_BASE + 24, "PG24")
+#define SUNXI_PINCTRL_PIN_PG25	PINCTRL_PIN(PG_BASE + 25, "PG25")
+#define SUNXI_PINCTRL_PIN_PG26	PINCTRL_PIN(PG_BASE + 26, "PG26")
+#define SUNXI_PINCTRL_PIN_PG27	PINCTRL_PIN(PG_BASE + 27, "PG27")
+#define SUNXI_PINCTRL_PIN_PG28	PINCTRL_PIN(PG_BASE + 28, "PG28")
+#define SUNXI_PINCTRL_PIN_PG29	PINCTRL_PIN(PG_BASE + 29, "PG29")
+#define SUNXI_PINCTRL_PIN_PG30	PINCTRL_PIN(PG_BASE + 30, "PG30")
+#define SUNXI_PINCTRL_PIN_PG31	PINCTRL_PIN(PG_BASE + 31, "PG31")
+
+#define SUNXI_PINCTRL_PIN_PH0	PINCTRL_PIN(PH_BASE + 0, "PH0")
+#define SUNXI_PINCTRL_PIN_PH1	PINCTRL_PIN(PH_BASE + 1, "PH1")
+#define SUNXI_PINCTRL_PIN_PH2	PINCTRL_PIN(PH_BASE + 2, "PH2")
+#define SUNXI_PINCTRL_PIN_PH3	PINCTRL_PIN(PH_BASE + 3, "PH3")
+#define SUNXI_PINCTRL_PIN_PH4	PINCTRL_PIN(PH_BASE + 4, "PH4")
+#define SUNXI_PINCTRL_PIN_PH5	PINCTRL_PIN(PH_BASE + 5, "PH5")
+#define SUNXI_PINCTRL_PIN_PH6	PINCTRL_PIN(PH_BASE + 6, "PH6")
+#define SUNXI_PINCTRL_PIN_PH7	PINCTRL_PIN(PH_BASE + 7, "PH7")
+#define SUNXI_PINCTRL_PIN_PH8	PINCTRL_PIN(PH_BASE + 8, "PH8")
+#define SUNXI_PINCTRL_PIN_PH9	PINCTRL_PIN(PH_BASE + 9, "PH9")
+#define SUNXI_PINCTRL_PIN_PH10	PINCTRL_PIN(PH_BASE + 10, "PH10")
+#define SUNXI_PINCTRL_PIN_PH11	PINCTRL_PIN(PH_BASE + 11, "PH11")
+#define SUNXI_PINCTRL_PIN_PH12	PINCTRL_PIN(PH_BASE + 12, "PH12")
+#define SUNXI_PINCTRL_PIN_PH13	PINCTRL_PIN(PH_BASE + 13, "PH13")
+#define SUNXI_PINCTRL_PIN_PH14	PINCTRL_PIN(PH_BASE + 14, "PH14")
+#define SUNXI_PINCTRL_PIN_PH15	PINCTRL_PIN(PH_BASE + 15, "PH15")
+#define SUNXI_PINCTRL_PIN_PH16	PINCTRL_PIN(PH_BASE + 16, "PH16")
+#define SUNXI_PINCTRL_PIN_PH17	PINCTRL_PIN(PH_BASE + 17, "PH17")
+#define SUNXI_PINCTRL_PIN_PH18	PINCTRL_PIN(PH_BASE + 18, "PH18")
+#define SUNXI_PINCTRL_PIN_PH19	PINCTRL_PIN(PH_BASE + 19, "PH19")
+#define SUNXI_PINCTRL_PIN_PH20	PINCTRL_PIN(PH_BASE + 20, "PH20")
+#define SUNXI_PINCTRL_PIN_PH21	PINCTRL_PIN(PH_BASE + 21, "PH21")
+#define SUNXI_PINCTRL_PIN_PH22	PINCTRL_PIN(PH_BASE + 22, "PH22")
+#define SUNXI_PINCTRL_PIN_PH23	PINCTRL_PIN(PH_BASE + 23, "PH23")
+#define SUNXI_PINCTRL_PIN_PH24	PINCTRL_PIN(PH_BASE + 24, "PH24")
+#define SUNXI_PINCTRL_PIN_PH25	PINCTRL_PIN(PH_BASE + 25, "PH25")
+#define SUNXI_PINCTRL_PIN_PH26	PINCTRL_PIN(PH_BASE + 26, "PH26")
+#define SUNXI_PINCTRL_PIN_PH27	PINCTRL_PIN(PH_BASE + 27, "PH27")
+#define SUNXI_PINCTRL_PIN_PH28	PINCTRL_PIN(PH_BASE + 28, "PH28")
+#define SUNXI_PINCTRL_PIN_PH29	PINCTRL_PIN(PH_BASE + 29, "PH29")
+#define SUNXI_PINCTRL_PIN_PH30	PINCTRL_PIN(PH_BASE + 30, "PH30")
+#define SUNXI_PINCTRL_PIN_PH31	PINCTRL_PIN(PH_BASE + 31, "PH31")
+
+#define SUNXI_PINCTRL_PIN_PI0	PINCTRL_PIN(PI_BASE + 0, "PI0")
+#define SUNXI_PINCTRL_PIN_PI1	PINCTRL_PIN(PI_BASE + 1, "PI1")
+#define SUNXI_PINCTRL_PIN_PI2	PINCTRL_PIN(PI_BASE + 2, "PI2")
+#define SUNXI_PINCTRL_PIN_PI3	PINCTRL_PIN(PI_BASE + 3, "PI3")
+#define SUNXI_PINCTRL_PIN_PI4	PINCTRL_PIN(PI_BASE + 4, "PI4")
+#define SUNXI_PINCTRL_PIN_PI5	PINCTRL_PIN(PI_BASE + 5, "PI5")
+#define SUNXI_PINCTRL_PIN_PI6	PINCTRL_PIN(PI_BASE + 6, "PI6")
+#define SUNXI_PINCTRL_PIN_PI7	PINCTRL_PIN(PI_BASE + 7, "PI7")
+#define SUNXI_PINCTRL_PIN_PI8	PINCTRL_PIN(PI_BASE + 8, "PI8")
+#define SUNXI_PINCTRL_PIN_PI9	PINCTRL_PIN(PI_BASE + 9, "PI9")
+#define SUNXI_PINCTRL_PIN_PI10	PINCTRL_PIN(PI_BASE + 10, "PI10")
+#define SUNXI_PINCTRL_PIN_PI11	PINCTRL_PIN(PI_BASE + 11, "PI11")
+#define SUNXI_PINCTRL_PIN_PI12	PINCTRL_PIN(PI_BASE + 12, "PI12")
+#define SUNXI_PINCTRL_PIN_PI13	PINCTRL_PIN(PI_BASE + 13, "PI13")
+#define SUNXI_PINCTRL_PIN_PI14	PINCTRL_PIN(PI_BASE + 14, "PI14")
+#define SUNXI_PINCTRL_PIN_PI15	PINCTRL_PIN(PI_BASE + 15, "PI15")
+#define SUNXI_PINCTRL_PIN_PI16	PINCTRL_PIN(PI_BASE + 16, "PI16")
+#define SUNXI_PINCTRL_PIN_PI17	PINCTRL_PIN(PI_BASE + 17, "PI17")
+#define SUNXI_PINCTRL_PIN_PI18	PINCTRL_PIN(PI_BASE + 18, "PI18")
+#define SUNXI_PINCTRL_PIN_PI19	PINCTRL_PIN(PI_BASE + 19, "PI19")
+#define SUNXI_PINCTRL_PIN_PI20	PINCTRL_PIN(PI_BASE + 20, "PI20")
+#define SUNXI_PINCTRL_PIN_PI21	PINCTRL_PIN(PI_BASE + 21, "PI21")
+#define SUNXI_PINCTRL_PIN_PI22	PINCTRL_PIN(PI_BASE + 22, "PI22")
+#define SUNXI_PINCTRL_PIN_PI23	PINCTRL_PIN(PI_BASE + 23, "PI23")
+#define SUNXI_PINCTRL_PIN_PI24	PINCTRL_PIN(PI_BASE + 24, "PI24")
+#define SUNXI_PINCTRL_PIN_PI25	PINCTRL_PIN(PI_BASE + 25, "PI25")
+#define SUNXI_PINCTRL_PIN_PI26	PINCTRL_PIN(PI_BASE + 26, "PI26")
+#define SUNXI_PINCTRL_PIN_PI27	PINCTRL_PIN(PI_BASE + 27, "PI27")
+#define SUNXI_PINCTRL_PIN_PI28	PINCTRL_PIN(PI_BASE + 28, "PI28")
+#define SUNXI_PINCTRL_PIN_PI29	PINCTRL_PIN(PI_BASE + 29, "PI29")
+#define SUNXI_PINCTRL_PIN_PI30	PINCTRL_PIN(PI_BASE + 30, "PI30")
+#define SUNXI_PINCTRL_PIN_PI31	PINCTRL_PIN(PI_BASE + 31, "PI31")
+
+#define SUNXI_PIN_NAME_MAX_LEN	5
+
+#define BANK_MEM_SIZE		0x24
+#define MUX_REGS_OFFSET		0x0
+#define DATA_REGS_OFFSET	0x10
+#define DLEVEL_REGS_OFFSET	0x14
+#define PULL_REGS_OFFSET	0x1c
+
+#define PINS_PER_BANK		32
+#define MUX_PINS_PER_REG	8
+#define MUX_PINS_BITS		4
+#define MUX_PINS_MASK		0x0f
+#define DATA_PINS_PER_REG	32
+#define DATA_PINS_BITS		1
+#define DATA_PINS_MASK		0x01
+#define DLEVEL_PINS_PER_REG	16
+#define DLEVEL_PINS_BITS	2
+#define DLEVEL_PINS_MASK	0x03
+#define PULL_PINS_PER_REG	16
+#define PULL_PINS_BITS		2
+#define PULL_PINS_MASK		0x03
+
+struct sunxi_desc_function {
+	const char	*name;
+	u8		muxval;
+};
+
+struct sunxi_desc_pin {
+	struct pinctrl_pin_desc		pin;
+	struct sunxi_desc_function	*functions;
+};
+
+struct sunxi_pinctrl_desc {
+	const struct sunxi_desc_pin	*pins;
+	int				npins;
+	struct pinctrl_gpio_range	*ranges;
+	int				nranges;
+};
+
+struct sunxi_pinctrl_function {
+	const char	*name;
+	const char	**groups;
+	unsigned	ngroups;
+};
+
+struct sunxi_pinctrl_group {
+	const char	*name;
+	unsigned long	config;
+	unsigned	pin;
+};
+
+struct sunxi_pinctrl {
+	void __iomem			*membase;
+	struct gpio_chip		*chip;
+	struct sunxi_pinctrl_desc	*desc;
+	struct device			*dev;
+	struct sunxi_pinctrl_function	*functions;
+	unsigned			nfunctions;
+	struct sunxi_pinctrl_group	*groups;
+	unsigned			ngroups;
+	struct pinctrl_dev		*pctl_dev;
+};
+
+#define SUNXI_PIN(_pin, ...)					\
+	{							\
+		.pin = _pin,					\
+		.functions = (struct sunxi_desc_function[]){	\
+			__VA_ARGS__, { } },			\
+	}
+
+#define SUNXI_FUNCTION(_val, _name)				\
+	{							\
+		.name = _name,					\
+		.muxval = _val,					\
+	}
+
+/*
+ * The sunXi PIO registers are organized as is:
+ * 0x00 - 0x0c	Muxing values.
+ *		8 pins per register, each pin having a 4bits value
+ * 0x10		Pin values
+ *		32 bits per register, each pin corresponding to one bit
+ * 0x14 - 0x18	Drive level
+ *		16 pins per register, each pin having a 2bits value
+ * 0x1c - 0x20	Pull-Up values
+ *		16 pins per register, each pin having a 2bits value
+ *
+ * This is for the first bank. Each bank will have the same layout,
+ * with an offset being a multiple of 0x24.
+ *
+ * The following functions calculate from the pin number the register
+ * and the bit offset that we should access.
+ */
+static inline u32 sunxi_mux_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += MUX_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_mux_offset(u16 pin)
+{
+	u32 pin_num = pin % MUX_PINS_PER_REG;
+	return pin_num * MUX_PINS_BITS;
+}
+
+static inline u32 sunxi_data_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += DATA_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_data_offset(u16 pin)
+{
+	u32 pin_num = pin % DATA_PINS_PER_REG;
+	return pin_num * DATA_PINS_BITS;
+}
+
+static inline u32 sunxi_dlevel_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += DLEVEL_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_dlevel_offset(u16 pin)
+{
+	u32 pin_num = pin % DLEVEL_PINS_PER_REG;
+	return pin_num * DLEVEL_PINS_BITS;
+}
+
+static inline u32 sunxi_pull_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += PULL_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_pull_offset(u16 pin)
+{
+	u32 pin_num = pin % PULL_PINS_PER_REG;
+	return pin_num * PULL_PINS_BITS;
+}
+
+#endif /* __PINCTRL_SUNXI_H */
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index ae1e4bb..f195d77 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -201,6 +201,7 @@
 	{"nvidia,open-drain",		TEGRA_PINCONF_PARAM_OPEN_DRAIN},
 	{"nvidia,lock",			TEGRA_PINCONF_PARAM_LOCK},
 	{"nvidia,io-reset",		TEGRA_PINCONF_PARAM_IORESET},
+	{"nvidia,rcv-sel",		TEGRA_PINCONF_PARAM_RCV_SEL},
 	{"nvidia,high-speed-mode",	TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE},
 	{"nvidia,schmitt",		TEGRA_PINCONF_PARAM_SCHMITT},
 	{"nvidia,low-power-mode",	TEGRA_PINCONF_PARAM_LOW_POWER_MODE},
@@ -208,6 +209,7 @@
 	{"nvidia,pull-up-strength",	TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH},
 	{"nvidia,slew-rate-falling",	TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
 	{"nvidia,slew-rate-rising",	TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
+	{"nvidia,drive-type",		TEGRA_PINCONF_PARAM_DRIVE_TYPE},
 };
 
 static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
@@ -450,6 +452,12 @@
 		*bit = g->ioreset_bit;
 		*width = 1;
 		break;
+	case TEGRA_PINCONF_PARAM_RCV_SEL:
+		*bank = g->rcv_sel_bank;
+		*reg = g->rcv_sel_reg;
+		*bit = g->rcv_sel_bit;
+		*width = 1;
+		break;
 	case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE:
 		*bank = g->drv_bank;
 		*reg = g->drv_reg;
@@ -492,6 +500,12 @@
 		*bit = g->slwr_bit;
 		*width = g->slwr_width;
 		break;
+	case TEGRA_PINCONF_PARAM_DRIVE_TYPE:
+		*bank = g->drvtype_bank;
+		*reg = g->drvtype_reg;
+		*bit = g->drvtype_bit;
+		*width = 2;
+		break;
 	default:
 		dev_err(pmx->dev, "Invalid config param %04x\n", param);
 		return -ENOTSUPP;
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 62e3809..817f706 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -30,6 +30,8 @@
 	/* argument: Boolean */
 	TEGRA_PINCONF_PARAM_IORESET,
 	/* argument: Boolean */
+	TEGRA_PINCONF_PARAM_RCV_SEL,
+	/* argument: Boolean */
 	TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE,
 	/* argument: Boolean */
 	TEGRA_PINCONF_PARAM_SCHMITT,
@@ -43,6 +45,8 @@
 	TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING,
 	/* argument: Integer, range is HW-dependant */
 	TEGRA_PINCONF_PARAM_SLEW_RATE_RISING,
+	/* argument: Integer, range is HW-dependant */
+	TEGRA_PINCONF_PARAM_DRIVE_TYPE,
 };
 
 enum tegra_pinconf_pull {
@@ -95,6 +99,9 @@
  * @ioreset_reg:	IO reset register offset. -1 if unsupported.
  * @ioreset_bank:	IO reset register bank. 0 if unsupported.
  * @ioreset_bit:	IO reset register bit. 0 if unsupported.
+ * @rcv_sel_reg:	Receiver select offset. -1 if unsupported.
+ * @rcv_sel_bank:	Receiver select bank. 0 if unsupported.
+ * @rcv_sel_bit:	Receiver select bit. 0 if unsupported.
  * @drv_reg:		Drive fields register offset. -1 if unsupported.
  *			This register contains the hsm, schmitt, lpmd, drvdn,
  *			drvup, slwr, and slwf parameters.
@@ -110,6 +117,9 @@
  * @slwr_width:		Slew Rising field width. 0 if unsupported.
  * @slwf_bit:		Slew Falling register bit. 0 if unsupported.
  * @slwf_width:		Slew Falling field width. 0 if unsupported.
+ * @drvtype_reg:	Drive type fields register offset. -1 if unsupported.
+ * @drvtype_bank:	Drive type fields register bank. 0 if unsupported.
+ * @drvtype_bit:	Drive type register bit. 0 if unsupported.
  *
  * A representation of a group of pins (possibly just one pin) in the Tegra
  * pin controller. Each group allows some parameter or parameters to be
@@ -131,15 +141,19 @@
 	s16 odrain_reg;
 	s16 lock_reg;
 	s16 ioreset_reg;
+	s16 rcv_sel_reg;
 	s16 drv_reg;
+	s16 drvtype_reg;
 	u32 mux_bank:2;
 	u32 pupd_bank:2;
 	u32 tri_bank:2;
 	u32 einput_bank:2;
 	u32 odrain_bank:2;
 	u32 ioreset_bank:2;
+	u32 rcv_sel_bank:2;
 	u32 lock_bank:2;
 	u32 drv_bank:2;
+	u32 drvtype_bank:2;
 	u32 mux_bit:5;
 	u32 pupd_bit:5;
 	u32 tri_bit:5;
@@ -147,6 +161,7 @@
 	u32 odrain_bit:5;
 	u32 lock_bit:5;
 	u32 ioreset_bit:5;
+	u32 rcv_sel_bit:5;
 	u32 hsm_bit:5;
 	u32 schmitt_bit:5;
 	u32 lpmd_bit:5;
@@ -154,6 +169,7 @@
 	u32 drvup_bit:5;
 	u32 slwr_bit:5;
 	u32 slwf_bit:5;
+	u32 drvtype_bit:5;
 	u32 drvdn_width:6;
 	u32 drvup_width:6;
 	u32 slwr_width:6;
diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/pinctrl-tegra114.c
new file mode 100644
index 0000000..622c485
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra114.c
@@ -0,0 +1,2769 @@
+/*
+ * Pinctrl data and driver for the NVIDIA Tegra114 pinmux
+ *
+ * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Arthur:  Pritesh Raithatha <praithatha@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-tegra.h"
+
+/*
+ * Most pins affected by the pinmux can also be GPIOs. Define these first.
+ * These must match how the GPIO driver names/numbers its pins.
+ */
+#define _GPIO(offset)				(offset)
+
+#define TEGRA_PIN_CLK_32K_OUT_PA0		_GPIO(0)
+#define TEGRA_PIN_UART3_CTS_N_PA1		_GPIO(1)
+#define TEGRA_PIN_DAP2_FS_PA2			_GPIO(2)
+#define TEGRA_PIN_DAP2_SCLK_PA3			_GPIO(3)
+#define TEGRA_PIN_DAP2_DIN_PA4			_GPIO(4)
+#define TEGRA_PIN_DAP2_DOUT_PA5			_GPIO(5)
+#define TEGRA_PIN_SDMMC3_CLK_PA6		_GPIO(6)
+#define TEGRA_PIN_SDMMC3_CMD_PA7		_GPIO(7)
+#define TEGRA_PIN_GMI_A17_PB0			_GPIO(8)
+#define TEGRA_PIN_GMI_A18_PB1			_GPIO(9)
+#define TEGRA_PIN_SDMMC3_DAT3_PB4		_GPIO(12)
+#define TEGRA_PIN_SDMMC3_DAT2_PB5		_GPIO(13)
+#define TEGRA_PIN_SDMMC3_DAT1_PB6		_GPIO(14)
+#define TEGRA_PIN_SDMMC3_DAT0_PB7		_GPIO(15)
+#define TEGRA_PIN_UART3_RTS_N_PC0		_GPIO(16)
+#define TEGRA_PIN_UART2_TXD_PC2			_GPIO(18)
+#define TEGRA_PIN_UART2_RXD_PC3			_GPIO(19)
+#define TEGRA_PIN_GEN1_I2C_SCL_PC4		_GPIO(20)
+#define TEGRA_PIN_GEN1_I2C_SDA_PC5		_GPIO(21)
+#define TEGRA_PIN_GMI_WP_N_PC7			_GPIO(23)
+#define TEGRA_PIN_GMI_AD0_PG0			_GPIO(48)
+#define TEGRA_PIN_GMI_AD1_PG1			_GPIO(49)
+#define TEGRA_PIN_GMI_AD2_PG2			_GPIO(50)
+#define TEGRA_PIN_GMI_AD3_PG3			_GPIO(51)
+#define TEGRA_PIN_GMI_AD4_PG4			_GPIO(52)
+#define TEGRA_PIN_GMI_AD5_PG5			_GPIO(53)
+#define TEGRA_PIN_GMI_AD6_PG6			_GPIO(54)
+#define TEGRA_PIN_GMI_AD7_PG7			_GPIO(55)
+#define TEGRA_PIN_GMI_AD8_PH0			_GPIO(56)
+#define TEGRA_PIN_GMI_AD9_PH1			_GPIO(57)
+#define TEGRA_PIN_GMI_AD10_PH2			_GPIO(58)
+#define TEGRA_PIN_GMI_AD11_PH3			_GPIO(59)
+#define TEGRA_PIN_GMI_AD12_PH4			_GPIO(60)
+#define TEGRA_PIN_GMI_AD13_PH5			_GPIO(61)
+#define TEGRA_PIN_GMI_AD14_PH6			_GPIO(62)
+#define TEGRA_PIN_GMI_AD15_PH7			_GPIO(63)
+#define TEGRA_PIN_GMI_WR_N_PI0			_GPIO(64)
+#define TEGRA_PIN_GMI_OE_N_PI1			_GPIO(65)
+#define TEGRA_PIN_GMI_CS6_N_PI3			_GPIO(67)
+#define TEGRA_PIN_GMI_RST_N_PI4			_GPIO(68)
+#define TEGRA_PIN_GMI_IORDY_PI5			_GPIO(69)
+#define TEGRA_PIN_GMI_CS7_N_PI6			_GPIO(70)
+#define TEGRA_PIN_GMI_WAIT_PI7			_GPIO(71)
+#define TEGRA_PIN_GMI_CS0_N_PJ0			_GPIO(72)
+#define TEGRA_PIN_GMI_CS1_N_PJ2			_GPIO(74)
+#define TEGRA_PIN_GMI_DQS_P_PJ3			_GPIO(75)
+#define TEGRA_PIN_UART2_CTS_N_PJ5		_GPIO(77)
+#define TEGRA_PIN_UART2_RTS_N_PJ6		_GPIO(78)
+#define TEGRA_PIN_GMI_A16_PJ7			_GPIO(79)
+#define TEGRA_PIN_GMI_ADV_N_PK0			_GPIO(80)
+#define TEGRA_PIN_GMI_CLK_PK1			_GPIO(81)
+#define TEGRA_PIN_GMI_CS4_N_PK2			_GPIO(82)
+#define TEGRA_PIN_GMI_CS2_N_PK3			_GPIO(83)
+#define TEGRA_PIN_GMI_CS3_N_PK4			_GPIO(84)
+#define TEGRA_PIN_SPDIF_OUT_PK5			_GPIO(85)
+#define TEGRA_PIN_SPDIF_IN_PK6			_GPIO(86)
+#define TEGRA_PIN_GMI_A19_PK7			_GPIO(87)
+#define TEGRA_PIN_DAP1_FS_PN0			_GPIO(104)
+#define TEGRA_PIN_DAP1_DIN_PN1			_GPIO(105)
+#define TEGRA_PIN_DAP1_DOUT_PN2			_GPIO(106)
+#define TEGRA_PIN_DAP1_SCLK_PN3			_GPIO(107)
+#define TEGRA_PIN_USB_VBUS_EN0_PN4		_GPIO(108)
+#define TEGRA_PIN_USB_VBUS_EN1_PN5		_GPIO(109)
+#define TEGRA_PIN_HDMI_INT_PN7			_GPIO(111)
+#define TEGRA_PIN_ULPI_DATA7_PO0		_GPIO(112)
+#define TEGRA_PIN_ULPI_DATA0_PO1		_GPIO(113)
+#define TEGRA_PIN_ULPI_DATA1_PO2		_GPIO(114)
+#define TEGRA_PIN_ULPI_DATA2_PO3		_GPIO(115)
+#define TEGRA_PIN_ULPI_DATA3_PO4		_GPIO(116)
+#define TEGRA_PIN_ULPI_DATA4_PO5		_GPIO(117)
+#define TEGRA_PIN_ULPI_DATA5_PO6		_GPIO(118)
+#define TEGRA_PIN_ULPI_DATA6_PO7		_GPIO(119)
+#define TEGRA_PIN_DAP3_FS_PP0			_GPIO(120)
+#define TEGRA_PIN_DAP3_DIN_PP1			_GPIO(121)
+#define TEGRA_PIN_DAP3_DOUT_PP2			_GPIO(122)
+#define TEGRA_PIN_DAP3_SCLK_PP3			_GPIO(123)
+#define TEGRA_PIN_DAP4_FS_PP4			_GPIO(124)
+#define TEGRA_PIN_DAP4_DIN_PP5			_GPIO(125)
+#define TEGRA_PIN_DAP4_DOUT_PP6			_GPIO(126)
+#define TEGRA_PIN_DAP4_SCLK_PP7			_GPIO(127)
+#define TEGRA_PIN_KB_COL0_PQ0			_GPIO(128)
+#define TEGRA_PIN_KB_COL1_PQ1			_GPIO(129)
+#define TEGRA_PIN_KB_COL2_PQ2			_GPIO(130)
+#define TEGRA_PIN_KB_COL3_PQ3			_GPIO(131)
+#define TEGRA_PIN_KB_COL4_PQ4			_GPIO(132)
+#define TEGRA_PIN_KB_COL5_PQ5			_GPIO(133)
+#define TEGRA_PIN_KB_COL6_PQ6			_GPIO(134)
+#define TEGRA_PIN_KB_COL7_PQ7			_GPIO(135)
+#define TEGRA_PIN_KB_ROW0_PR0			_GPIO(136)
+#define TEGRA_PIN_KB_ROW1_PR1			_GPIO(137)
+#define TEGRA_PIN_KB_ROW2_PR2			_GPIO(138)
+#define TEGRA_PIN_KB_ROW3_PR3			_GPIO(139)
+#define TEGRA_PIN_KB_ROW4_PR4			_GPIO(140)
+#define TEGRA_PIN_KB_ROW5_PR5			_GPIO(141)
+#define TEGRA_PIN_KB_ROW6_PR6			_GPIO(142)
+#define TEGRA_PIN_KB_ROW7_PR7			_GPIO(143)
+#define TEGRA_PIN_KB_ROW8_PS0			_GPIO(144)
+#define TEGRA_PIN_KB_ROW9_PS1			_GPIO(145)
+#define TEGRA_PIN_KB_ROW10_PS2			_GPIO(146)
+#define TEGRA_PIN_GEN2_I2C_SCL_PT5		_GPIO(157)
+#define TEGRA_PIN_GEN2_I2C_SDA_PT6		_GPIO(158)
+#define TEGRA_PIN_SDMMC4_CMD_PT7		_GPIO(159)
+#define TEGRA_PIN_PU0				_GPIO(160)
+#define TEGRA_PIN_PU1				_GPIO(161)
+#define TEGRA_PIN_PU2				_GPIO(162)
+#define TEGRA_PIN_PU3				_GPIO(163)
+#define TEGRA_PIN_PU4				_GPIO(164)
+#define TEGRA_PIN_PU5				_GPIO(165)
+#define TEGRA_PIN_PU6				_GPIO(166)
+#define TEGRA_PIN_PV0				_GPIO(168)
+#define TEGRA_PIN_PV1				_GPIO(169)
+#define TEGRA_PIN_SDMMC3_CD_N_PV2		_GPIO(170)
+#define TEGRA_PIN_SDMMC1_WP_N_PV3		_GPIO(171)
+#define TEGRA_PIN_DDC_SCL_PV4			_GPIO(172)
+#define TEGRA_PIN_DDC_SDA_PV5			_GPIO(173)
+#define TEGRA_PIN_GPIO_W2_AUD_PW2		_GPIO(178)
+#define TEGRA_PIN_GPIO_W3_AUD_PW3		_GPIO(179)
+#define TEGRA_PIN_CLK1_OUT_PW4			_GPIO(180)
+#define TEGRA_PIN_CLK2_OUT_PW5			_GPIO(181)
+#define TEGRA_PIN_UART3_TXD_PW6			_GPIO(182)
+#define TEGRA_PIN_UART3_RXD_PW7			_GPIO(183)
+#define TEGRA_PIN_DVFS_PWM_PX0			_GPIO(184)
+#define TEGRA_PIN_GPIO_X1_AUD_PX1		_GPIO(185)
+#define TEGRA_PIN_DVFS_CLK_PX2			_GPIO(186)
+#define TEGRA_PIN_GPIO_X3_AUD_PX3		_GPIO(187)
+#define TEGRA_PIN_GPIO_X4_AUD_PX4		_GPIO(188)
+#define TEGRA_PIN_GPIO_X5_AUD_PX5		_GPIO(189)
+#define TEGRA_PIN_GPIO_X6_AUD_PX6		_GPIO(190)
+#define TEGRA_PIN_GPIO_X7_AUD_PX7		_GPIO(191)
+#define TEGRA_PIN_ULPI_CLK_PY0			_GPIO(192)
+#define TEGRA_PIN_ULPI_DIR_PY1			_GPIO(193)
+#define TEGRA_PIN_ULPI_NXT_PY2			_GPIO(194)
+#define TEGRA_PIN_ULPI_STP_PY3			_GPIO(195)
+#define TEGRA_PIN_SDMMC1_DAT3_PY4		_GPIO(196)
+#define TEGRA_PIN_SDMMC1_DAT2_PY5		_GPIO(197)
+#define TEGRA_PIN_SDMMC1_DAT1_PY6		_GPIO(198)
+#define TEGRA_PIN_SDMMC1_DAT0_PY7		_GPIO(199)
+#define TEGRA_PIN_SDMMC1_CLK_PZ0		_GPIO(200)
+#define TEGRA_PIN_SDMMC1_CMD_PZ1		_GPIO(201)
+#define TEGRA_PIN_SYS_CLK_REQ_PZ5		_GPIO(205)
+#define TEGRA_PIN_PWR_I2C_SCL_PZ6		_GPIO(206)
+#define TEGRA_PIN_PWR_I2C_SDA_PZ7		_GPIO(207)
+#define TEGRA_PIN_SDMMC4_DAT0_PAA0		_GPIO(208)
+#define TEGRA_PIN_SDMMC4_DAT1_PAA1		_GPIO(209)
+#define TEGRA_PIN_SDMMC4_DAT2_PAA2		_GPIO(210)
+#define TEGRA_PIN_SDMMC4_DAT3_PAA3		_GPIO(211)
+#define TEGRA_PIN_SDMMC4_DAT4_PAA4		_GPIO(212)
+#define TEGRA_PIN_SDMMC4_DAT5_PAA5		_GPIO(213)
+#define TEGRA_PIN_SDMMC4_DAT6_PAA6		_GPIO(214)
+#define TEGRA_PIN_SDMMC4_DAT7_PAA7		_GPIO(215)
+#define TEGRA_PIN_PBB0				_GPIO(216)
+#define TEGRA_PIN_CAM_I2C_SCL_PBB1		_GPIO(217)
+#define TEGRA_PIN_CAM_I2C_SDA_PBB2		_GPIO(218)
+#define TEGRA_PIN_PBB3				_GPIO(219)
+#define TEGRA_PIN_PBB4				_GPIO(220)
+#define TEGRA_PIN_PBB5				_GPIO(221)
+#define TEGRA_PIN_PBB6				_GPIO(222)
+#define TEGRA_PIN_PBB7				_GPIO(223)
+#define TEGRA_PIN_CAM_MCLK_PCC0			_GPIO(224)
+#define TEGRA_PIN_PCC1				_GPIO(225)
+#define TEGRA_PIN_PCC2				_GPIO(226)
+#define TEGRA_PIN_SDMMC4_CLK_PCC4		_GPIO(228)
+#define TEGRA_PIN_CLK2_REQ_PCC5			_GPIO(229)
+#define TEGRA_PIN_CLK3_OUT_PEE0			_GPIO(240)
+#define TEGRA_PIN_CLK3_REQ_PEE1			_GPIO(241)
+#define TEGRA_PIN_CLK1_REQ_PEE2			_GPIO(242)
+#define TEGRA_PIN_HDMI_CEC_PEE3			_GPIO(243)
+#define TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4	_GPIO(244)
+#define TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5		_GPIO(245)
+
+/* All non-GPIO pins follow */
+#define NUM_GPIOS	(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
+#define _PIN(offset)	(NUM_GPIOS + (offset))
+
+/* Non-GPIO pins */
+#define TEGRA_PIN_CORE_PWR_REQ			_PIN(0)
+#define TEGRA_PIN_CPU_PWR_REQ			_PIN(1)
+#define TEGRA_PIN_PWR_INT_N			_PIN(2)
+#define TEGRA_PIN_RESET_OUT_N			_PIN(3)
+#define TEGRA_PIN_OWR				_PIN(4)
+
+static const struct pinctrl_pin_desc  tegra114_pins[] = {
+	PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_SCLK_PA3, "DAP2_SCLK PA3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_DIN_PA4, "DAP2_DIN PA4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP2_DOUT_PA5, "DAP2_DOUT PA5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_PA6, "SDMMC3_CLK PA6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CMD_PA7, "SDMMC3_CMD PA7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A17_PB0, "GMI_A17 PB0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A18_PB1, "GMI_A18 PB1"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT3_PB4, "SDMMC3_DAT3 PB4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT2_PB5, "SDMMC3_DAT2 PB5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT1_PB6, "SDMMC3_DAT1 PB6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT0_PB7, "SDMMC3_DAT0 PB7"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_RTS_N_PC0, "UART3_RTS_N PC0"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_TXD_PC2, "UART2_TXD PC2"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_RXD_PC3, "UART2_RXD PC3"),
+	PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SCL_PC4, "GEN1_I2C_SCL PC4"),
+	PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SDA_PC5, "GEN1_I2C_SDA PC5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WP_N_PC7, "GMI_WP_N PC7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD0_PG0, "GMI_AD0 PG0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD1_PG1, "GMI_AD1 PG1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD2_PG2, "GMI_AD2 PG2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD3_PG3, "GMI_AD3 PG3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD4_PG4, "GMI_AD4 PG4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD5_PG5, "GMI_AD5 PG5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD6_PG6, "GMI_AD6 PG6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD7_PG7, "GMI_AD7 PG7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD8_PH0, "GMI_AD8 PH0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD9_PH1, "GMI_AD9 PH1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD10_PH2, "GMI_AD10 PH2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD11_PH3, "GMI_AD11 PH3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD12_PH4, "GMI_AD12 PH4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD13_PH5, "GMI_AD13 PH5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD14_PH6, "GMI_AD14 PH6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_AD15_PH7, "GMI_AD15 PH7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WR_N_PI0, "GMI_WR_N PI0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_OE_N_PI1, "GMI_OE_N PI1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS6_N_PI3, "GMI_CS6_N PI3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_RST_N_PI4, "GMI_RST_N PI4"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_IORDY_PI5, "GMI_IORDY PI5"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS7_N_PI6, "GMI_CS7_N PI6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_WAIT_PI7, "GMI_WAIT PI7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS0_N_PJ0, "GMI_CS0_N PJ0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS1_N_PJ2, "GMI_CS1_N PJ2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_DQS_P_PJ3, "GMI_DQS_P PJ3"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_CTS_N_PJ5, "UART2_CTS_N PJ5"),
+	PINCTRL_PIN(TEGRA_PIN_UART2_RTS_N_PJ6, "UART2_RTS_N PJ6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A16_PJ7, "GMI_A16 PJ7"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_ADV_N_PK0, "GMI_ADV_N PK0"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CLK_PK1, "GMI_CLK PK1"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS4_N_PK2, "GMI_CS4_N PK2"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS2_N_PK3, "GMI_CS2_N PK3"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_CS3_N_PK4, "GMI_CS3_N PK4"),
+	PINCTRL_PIN(TEGRA_PIN_SPDIF_OUT_PK5, "SPDIF_OUT PK5"),
+	PINCTRL_PIN(TEGRA_PIN_SPDIF_IN_PK6, "SPDIF_IN PK6"),
+	PINCTRL_PIN(TEGRA_PIN_GMI_A19_PK7, "GMI_A19 PK7"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_FS_PN0, "DAP1_FS PN0"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_DIN_PN1, "DAP1_DIN PN1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_DOUT_PN2, "DAP1_DOUT PN2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP1_SCLK_PN3, "DAP1_SCLK PN3"),
+	PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN0_PN4, "USB_VBUS_EN0 PN4"),
+	PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN1_PN5, "USB_VBUS_EN1 PN5"),
+	PINCTRL_PIN(TEGRA_PIN_HDMI_INT_PN7, "HDMI_INT PN7"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA7_PO0, "ULPI_DATA7 PO0"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA0_PO1, "ULPI_DATA0 PO1"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA1_PO2, "ULPI_DATA1 PO2"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA2_PO3, "ULPI_DATA2 PO3"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA3_PO4, "ULPI_DATA3 PO4"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA4_PO5, "ULPI_DATA4 PO5"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA5_PO6, "ULPI_DATA5 PO6"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DATA6_PO7, "ULPI_DATA6 PO7"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_FS_PP0, "DAP3_FS PP0"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_DIN_PP1, "DAP3_DIN PP1"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_DOUT_PP2, "DAP3_DOUT PP2"),
+	PINCTRL_PIN(TEGRA_PIN_DAP3_SCLK_PP3, "DAP3_SCLK PP3"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_FS_PP4, "DAP4_FS PP4"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_DIN_PP5, "DAP4_DIN PP5"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_DOUT_PP6, "DAP4_DOUT PP6"),
+	PINCTRL_PIN(TEGRA_PIN_DAP4_SCLK_PP7, "DAP4_SCLK PP7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL0_PQ0, "KB_COL0 PQ0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL1_PQ1, "KB_COL1 PQ1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL2_PQ2, "KB_COL2 PQ2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL3_PQ3, "KB_COL3 PQ3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL4_PQ4, "KB_COL4 PQ4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL5_PQ5, "KB_COL5 PQ5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL6_PQ6, "KB_COL6 PQ6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_COL7_PQ7, "KB_COL7 PQ7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW0_PR0, "KB_ROW0 PR0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW1_PR1, "KB_ROW1 PR1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW2_PR2, "KB_ROW2 PR2"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW3_PR3, "KB_ROW3 PR3"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW4_PR4, "KB_ROW4 PR4"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW5_PR5, "KB_ROW5 PR5"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW6_PR6, "KB_ROW6 PR6"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW7_PR7, "KB_ROW7 PR7"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
+	PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
+	PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
+	PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_CMD_PT7, "SDMMC4_CMD PT7"),
+	PINCTRL_PIN(TEGRA_PIN_PU0, "PU0"),
+	PINCTRL_PIN(TEGRA_PIN_PU1, "PU1"),
+	PINCTRL_PIN(TEGRA_PIN_PU2, "PU2"),
+	PINCTRL_PIN(TEGRA_PIN_PU3, "PU3"),
+	PINCTRL_PIN(TEGRA_PIN_PU4, "PU4"),
+	PINCTRL_PIN(TEGRA_PIN_PU5, "PU5"),
+	PINCTRL_PIN(TEGRA_PIN_PU6, "PU6"),
+	PINCTRL_PIN(TEGRA_PIN_PV0, "PV0"),
+	PINCTRL_PIN(TEGRA_PIN_PV1, "PV1"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CD_N_PV2, "SDMMC3_CD_N PV2"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_WP_N_PV3, "SDMMC1_WP_N PV3"),
+	PINCTRL_PIN(TEGRA_PIN_DDC_SCL_PV4, "DDC_SCL PV4"),
+	PINCTRL_PIN(TEGRA_PIN_DDC_SDA_PV5, "DDC_SDA PV5"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_W2_AUD_PW2, "GPIO_W2_AUD PW2"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_W3_AUD_PW3, "GPIO_W3_AUD PW3"),
+	PINCTRL_PIN(TEGRA_PIN_CLK1_OUT_PW4, "CLK1_OUT PW4"),
+	PINCTRL_PIN(TEGRA_PIN_CLK2_OUT_PW5, "CLK2_OUT PW5"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_TXD_PW6, "UART3_TXD PW6"),
+	PINCTRL_PIN(TEGRA_PIN_UART3_RXD_PW7, "UART3_RXD PW7"),
+	PINCTRL_PIN(TEGRA_PIN_DVFS_PWM_PX0, "DVFS_PWM PX0"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_X1_AUD_PX1, "GPIO_X1_AUD PX1"),
+	PINCTRL_PIN(TEGRA_PIN_DVFS_CLK_PX2, "DVFS_CLK PX2"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_X3_AUD_PX3, "GPIO_X3_AUD PX3"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_X4_AUD_PX4, "GPIO_X4_AUD PX4"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_X5_AUD_PX5, "GPIO_X5_AUD PX5"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_X6_AUD_PX6, "GPIO_X6_AUD PX6"),
+	PINCTRL_PIN(TEGRA_PIN_GPIO_X7_AUD_PX7, "GPIO_X7_AUD PX7"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_CLK_PY0, "ULPI_CLK PY0"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_DIR_PY1, "ULPI_DIR PY1"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_NXT_PY2, "ULPI_NXT PY2"),
+	PINCTRL_PIN(TEGRA_PIN_ULPI_STP_PY3, "ULPI_STP PY3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT3_PY4, "SDMMC1_DAT3 PY4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT2_PY5, "SDMMC1_DAT2 PY5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT1_PY6, "SDMMC1_DAT1 PY6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT0_PY7, "SDMMC1_DAT0 PY7"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_CLK_PZ0, "SDMMC1_CLK PZ0"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC1_CMD_PZ1, "SDMMC1_CMD PZ1"),
+	PINCTRL_PIN(TEGRA_PIN_SYS_CLK_REQ_PZ5, "SYS_CLK_REQ PZ5"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SCL_PZ6, "PWR_I2C_SCL PZ6"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SDA_PZ7, "PWR_I2C_SDA PZ7"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT0_PAA0, "SDMMC4_DAT0 PAA0"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT1_PAA1, "SDMMC4_DAT1 PAA1"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT2_PAA2, "SDMMC4_DAT2 PAA2"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT3_PAA3, "SDMMC4_DAT3 PAA3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT4_PAA4, "SDMMC4_DAT4 PAA4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT5_PAA5, "SDMMC4_DAT5 PAA5"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT6_PAA6, "SDMMC4_DAT6 PAA6"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT7_PAA7, "SDMMC4_DAT7 PAA7"),
+	PINCTRL_PIN(TEGRA_PIN_PBB0, "PBB0"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SCL_PBB1, "CAM_I2C_SCL PBB1"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SDA_PBB2, "CAM_I2C_SDA PBB2"),
+	PINCTRL_PIN(TEGRA_PIN_PBB3, "PBB3"),
+	PINCTRL_PIN(TEGRA_PIN_PBB4, "PBB4"),
+	PINCTRL_PIN(TEGRA_PIN_PBB5, "PBB5"),
+	PINCTRL_PIN(TEGRA_PIN_PBB6, "PBB6"),
+	PINCTRL_PIN(TEGRA_PIN_PBB7, "PBB7"),
+	PINCTRL_PIN(TEGRA_PIN_CAM_MCLK_PCC0, "CAM_MCLK PCC0"),
+	PINCTRL_PIN(TEGRA_PIN_PCC1, "PCC1"),
+	PINCTRL_PIN(TEGRA_PIN_PCC2, "PCC2"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC4_CLK_PCC4, "SDMMC4_CLK PCC4"),
+	PINCTRL_PIN(TEGRA_PIN_CLK2_REQ_PCC5, "CLK2_REQ PCC5"),
+	PINCTRL_PIN(TEGRA_PIN_CLK3_OUT_PEE0, "CLK3_OUT PEE0"),
+	PINCTRL_PIN(TEGRA_PIN_CLK3_REQ_PEE1, "CLK3_REQ PEE1"),
+	PINCTRL_PIN(TEGRA_PIN_CLK1_REQ_PEE2, "CLK1_REQ PEE2"),
+	PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PEE3, "HDMI_CEC PEE3"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4, "SDMMC3_CLK_LB_OUT PEE4"),
+	PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
+	PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
+	PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
+	PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
+	PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+	PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
+};
+
+static const unsigned clk_32k_out_pa0_pins[] = {
+	TEGRA_PIN_CLK_32K_OUT_PA0,
+};
+
+static const unsigned uart3_cts_n_pa1_pins[] = {
+	TEGRA_PIN_UART3_CTS_N_PA1,
+};
+
+static const unsigned dap2_fs_pa2_pins[] = {
+	TEGRA_PIN_DAP2_FS_PA2,
+};
+
+static const unsigned dap2_sclk_pa3_pins[] = {
+	TEGRA_PIN_DAP2_SCLK_PA3,
+};
+
+static const unsigned dap2_din_pa4_pins[] = {
+	TEGRA_PIN_DAP2_DIN_PA4,
+};
+
+static const unsigned dap2_dout_pa5_pins[] = {
+	TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned sdmmc3_clk_pa6_pins[] = {
+	TEGRA_PIN_SDMMC3_CLK_PA6,
+};
+
+static const unsigned sdmmc3_cmd_pa7_pins[] = {
+	TEGRA_PIN_SDMMC3_CMD_PA7,
+};
+
+static const unsigned gmi_a17_pb0_pins[] = {
+	TEGRA_PIN_GMI_A17_PB0,
+};
+
+static const unsigned gmi_a18_pb1_pins[] = {
+	TEGRA_PIN_GMI_A18_PB1,
+};
+
+static const unsigned sdmmc3_dat3_pb4_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT3_PB4,
+};
+
+static const unsigned sdmmc3_dat2_pb5_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT2_PB5,
+};
+
+static const unsigned sdmmc3_dat1_pb6_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT1_PB6,
+};
+
+static const unsigned sdmmc3_dat0_pb7_pins[] = {
+	TEGRA_PIN_SDMMC3_DAT0_PB7,
+};
+
+static const unsigned uart3_rts_n_pc0_pins[] = {
+	TEGRA_PIN_UART3_RTS_N_PC0,
+};
+
+static const unsigned uart2_txd_pc2_pins[] = {
+	TEGRA_PIN_UART2_TXD_PC2,
+};
+
+static const unsigned uart2_rxd_pc3_pins[] = {
+	TEGRA_PIN_UART2_RXD_PC3,
+};
+
+static const unsigned gen1_i2c_scl_pc4_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SCL_PC4,
+};
+
+static const unsigned gen1_i2c_sda_pc5_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SDA_PC5,
+};
+
+static const unsigned gmi_wp_n_pc7_pins[] = {
+	TEGRA_PIN_GMI_WP_N_PC7,
+};
+
+static const unsigned gmi_ad0_pg0_pins[] = {
+	TEGRA_PIN_GMI_AD0_PG0,
+};
+
+static const unsigned gmi_ad1_pg1_pins[] = {
+	TEGRA_PIN_GMI_AD1_PG1,
+};
+
+static const unsigned gmi_ad2_pg2_pins[] = {
+	TEGRA_PIN_GMI_AD2_PG2,
+};
+
+static const unsigned gmi_ad3_pg3_pins[] = {
+	TEGRA_PIN_GMI_AD3_PG3,
+};
+
+static const unsigned gmi_ad4_pg4_pins[] = {
+	TEGRA_PIN_GMI_AD4_PG4,
+};
+
+static const unsigned gmi_ad5_pg5_pins[] = {
+	TEGRA_PIN_GMI_AD5_PG5,
+};
+
+static const unsigned gmi_ad6_pg6_pins[] = {
+	TEGRA_PIN_GMI_AD6_PG6,
+};
+
+static const unsigned gmi_ad7_pg7_pins[] = {
+	TEGRA_PIN_GMI_AD7_PG7,
+};
+
+static const unsigned gmi_ad8_ph0_pins[] = {
+	TEGRA_PIN_GMI_AD8_PH0,
+};
+
+static const unsigned gmi_ad9_ph1_pins[] = {
+	TEGRA_PIN_GMI_AD9_PH1,
+};
+
+static const unsigned gmi_ad10_ph2_pins[] = {
+	TEGRA_PIN_GMI_AD10_PH2,
+};
+
+static const unsigned gmi_ad11_ph3_pins[] = {
+	TEGRA_PIN_GMI_AD11_PH3,
+};
+
+static const unsigned gmi_ad12_ph4_pins[] = {
+	TEGRA_PIN_GMI_AD12_PH4,
+};
+
+static const unsigned gmi_ad13_ph5_pins[] = {
+	TEGRA_PIN_GMI_AD13_PH5,
+};
+
+static const unsigned gmi_ad14_ph6_pins[] = {
+	TEGRA_PIN_GMI_AD14_PH6,
+};
+
+static const unsigned gmi_ad15_ph7_pins[] = {
+	TEGRA_PIN_GMI_AD15_PH7,
+};
+
+static const unsigned gmi_wr_n_pi0_pins[] = {
+	TEGRA_PIN_GMI_WR_N_PI0,
+};
+
+static const unsigned gmi_oe_n_pi1_pins[] = {
+	TEGRA_PIN_GMI_OE_N_PI1,
+};
+
+static const unsigned gmi_cs6_n_pi3_pins[] = {
+	TEGRA_PIN_GMI_CS6_N_PI3,
+};
+
+static const unsigned gmi_rst_n_pi4_pins[] = {
+	TEGRA_PIN_GMI_RST_N_PI4,
+};
+
+static const unsigned gmi_iordy_pi5_pins[] = {
+	TEGRA_PIN_GMI_IORDY_PI5,
+};
+
+static const unsigned gmi_cs7_n_pi6_pins[] = {
+	TEGRA_PIN_GMI_CS7_N_PI6,
+};
+
+static const unsigned gmi_wait_pi7_pins[] = {
+	TEGRA_PIN_GMI_WAIT_PI7,
+};
+
+static const unsigned gmi_cs0_n_pj0_pins[] = {
+	TEGRA_PIN_GMI_CS0_N_PJ0,
+};
+
+static const unsigned gmi_cs1_n_pj2_pins[] = {
+	TEGRA_PIN_GMI_CS1_N_PJ2,
+};
+
+static const unsigned gmi_dqs_p_pj3_pins[] = {
+	TEGRA_PIN_GMI_DQS_P_PJ3,
+};
+
+static const unsigned uart2_cts_n_pj5_pins[] = {
+	TEGRA_PIN_UART2_CTS_N_PJ5,
+};
+
+static const unsigned uart2_rts_n_pj6_pins[] = {
+	TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned gmi_a16_pj7_pins[] = {
+	TEGRA_PIN_GMI_A16_PJ7,
+};
+
+static const unsigned gmi_adv_n_pk0_pins[] = {
+	TEGRA_PIN_GMI_ADV_N_PK0,
+};
+
+static const unsigned gmi_clk_pk1_pins[] = {
+	TEGRA_PIN_GMI_CLK_PK1,
+};
+
+static const unsigned gmi_cs4_n_pk2_pins[] = {
+	TEGRA_PIN_GMI_CS4_N_PK2,
+};
+
+static const unsigned gmi_cs2_n_pk3_pins[] = {
+	TEGRA_PIN_GMI_CS2_N_PK3,
+};
+
+static const unsigned gmi_cs3_n_pk4_pins[] = {
+	TEGRA_PIN_GMI_CS3_N_PK4,
+};
+
+static const unsigned spdif_out_pk5_pins[] = {
+	TEGRA_PIN_SPDIF_OUT_PK5,
+};
+
+static const unsigned spdif_in_pk6_pins[] = {
+	TEGRA_PIN_SPDIF_IN_PK6,
+};
+
+static const unsigned gmi_a19_pk7_pins[] = {
+	TEGRA_PIN_GMI_A19_PK7,
+};
+
+static const unsigned dap1_fs_pn0_pins[] = {
+	TEGRA_PIN_DAP1_FS_PN0,
+};
+
+static const unsigned dap1_din_pn1_pins[] = {
+	TEGRA_PIN_DAP1_DIN_PN1,
+};
+
+static const unsigned dap1_dout_pn2_pins[] = {
+	TEGRA_PIN_DAP1_DOUT_PN2,
+};
+
+static const unsigned dap1_sclk_pn3_pins[] = {
+	TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned usb_vbus_en0_pn4_pins[] = {
+	TEGRA_PIN_USB_VBUS_EN0_PN4,
+};
+
+static const unsigned usb_vbus_en1_pn5_pins[] = {
+	TEGRA_PIN_USB_VBUS_EN1_PN5,
+};
+
+static const unsigned hdmi_int_pn7_pins[] = {
+	TEGRA_PIN_HDMI_INT_PN7,
+};
+
+static const unsigned ulpi_data7_po0_pins[] = {
+	TEGRA_PIN_ULPI_DATA7_PO0,
+};
+
+static const unsigned ulpi_data0_po1_pins[] = {
+	TEGRA_PIN_ULPI_DATA0_PO1,
+};
+
+static const unsigned ulpi_data1_po2_pins[] = {
+	TEGRA_PIN_ULPI_DATA1_PO2,
+};
+
+static const unsigned ulpi_data2_po3_pins[] = {
+	TEGRA_PIN_ULPI_DATA2_PO3,
+};
+
+static const unsigned ulpi_data3_po4_pins[] = {
+	TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned ulpi_data4_po5_pins[] = {
+	TEGRA_PIN_ULPI_DATA4_PO5,
+};
+
+static const unsigned ulpi_data5_po6_pins[] = {
+	TEGRA_PIN_ULPI_DATA5_PO6,
+};
+
+static const unsigned ulpi_data6_po7_pins[] = {
+	TEGRA_PIN_ULPI_DATA6_PO7,
+};
+
+static const unsigned dap3_fs_pp0_pins[] = {
+	TEGRA_PIN_DAP3_FS_PP0,
+};
+
+static const unsigned dap3_din_pp1_pins[] = {
+	TEGRA_PIN_DAP3_DIN_PP1,
+};
+
+static const unsigned dap3_dout_pp2_pins[] = {
+	TEGRA_PIN_DAP3_DOUT_PP2,
+};
+
+static const unsigned dap3_sclk_pp3_pins[] = {
+	TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned dap4_fs_pp4_pins[] = {
+	TEGRA_PIN_DAP4_FS_PP4,
+};
+
+static const unsigned dap4_din_pp5_pins[] = {
+	TEGRA_PIN_DAP4_DIN_PP5,
+};
+
+static const unsigned dap4_dout_pp6_pins[] = {
+	TEGRA_PIN_DAP4_DOUT_PP6,
+};
+
+static const unsigned dap4_sclk_pp7_pins[] = {
+	TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned kb_col0_pq0_pins[] = {
+	TEGRA_PIN_KB_COL0_PQ0,
+};
+
+static const unsigned kb_col1_pq1_pins[] = {
+	TEGRA_PIN_KB_COL1_PQ1,
+};
+
+static const unsigned kb_col2_pq2_pins[] = {
+	TEGRA_PIN_KB_COL2_PQ2,
+};
+
+static const unsigned kb_col3_pq3_pins[] = {
+	TEGRA_PIN_KB_COL3_PQ3,
+};
+
+static const unsigned kb_col4_pq4_pins[] = {
+	TEGRA_PIN_KB_COL4_PQ4,
+};
+
+static const unsigned kb_col5_pq5_pins[] = {
+	TEGRA_PIN_KB_COL5_PQ5,
+};
+
+static const unsigned kb_col6_pq6_pins[] = {
+	TEGRA_PIN_KB_COL6_PQ6,
+};
+
+static const unsigned kb_col7_pq7_pins[] = {
+	TEGRA_PIN_KB_COL7_PQ7,
+};
+
+static const unsigned kb_row0_pr0_pins[] = {
+	TEGRA_PIN_KB_ROW0_PR0,
+};
+
+static const unsigned kb_row1_pr1_pins[] = {
+	TEGRA_PIN_KB_ROW1_PR1,
+};
+
+static const unsigned kb_row2_pr2_pins[] = {
+	TEGRA_PIN_KB_ROW2_PR2,
+};
+
+static const unsigned kb_row3_pr3_pins[] = {
+	TEGRA_PIN_KB_ROW3_PR3,
+};
+
+static const unsigned kb_row4_pr4_pins[] = {
+	TEGRA_PIN_KB_ROW4_PR4,
+};
+
+static const unsigned kb_row5_pr5_pins[] = {
+	TEGRA_PIN_KB_ROW5_PR5,
+};
+
+static const unsigned kb_row6_pr6_pins[] = {
+	TEGRA_PIN_KB_ROW6_PR6,
+};
+
+static const unsigned kb_row7_pr7_pins[] = {
+	TEGRA_PIN_KB_ROW7_PR7,
+};
+
+static const unsigned kb_row8_ps0_pins[] = {
+	TEGRA_PIN_KB_ROW8_PS0,
+};
+
+static const unsigned kb_row9_ps1_pins[] = {
+	TEGRA_PIN_KB_ROW9_PS1,
+};
+
+static const unsigned kb_row10_ps2_pins[] = {
+	TEGRA_PIN_KB_ROW10_PS2,
+};
+
+static const unsigned gen2_i2c_scl_pt5_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SCL_PT5,
+};
+
+static const unsigned gen2_i2c_sda_pt6_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned sdmmc4_cmd_pt7_pins[] = {
+	TEGRA_PIN_SDMMC4_CMD_PT7,
+};
+
+static const unsigned pu0_pins[] = {
+	TEGRA_PIN_PU0,
+};
+
+static const unsigned pu1_pins[] = {
+	TEGRA_PIN_PU1,
+};
+
+static const unsigned pu2_pins[] = {
+	TEGRA_PIN_PU2,
+};
+
+static const unsigned pu3_pins[] = {
+	TEGRA_PIN_PU3,
+};
+
+static const unsigned pu4_pins[] = {
+	TEGRA_PIN_PU4,
+};
+
+static const unsigned pu5_pins[] = {
+	TEGRA_PIN_PU5,
+};
+
+static const unsigned pu6_pins[] = {
+	TEGRA_PIN_PU6,
+};
+
+static const unsigned pv0_pins[] = {
+	TEGRA_PIN_PV0,
+};
+
+static const unsigned pv1_pins[] = {
+	TEGRA_PIN_PV1,
+};
+
+static const unsigned sdmmc3_cd_n_pv2_pins[] = {
+	TEGRA_PIN_SDMMC3_CD_N_PV2,
+};
+
+static const unsigned sdmmc1_wp_n_pv3_pins[] = {
+	TEGRA_PIN_SDMMC1_WP_N_PV3,
+};
+
+static const unsigned ddc_scl_pv4_pins[] = {
+	TEGRA_PIN_DDC_SCL_PV4,
+};
+
+static const unsigned ddc_sda_pv5_pins[] = {
+	TEGRA_PIN_DDC_SDA_PV5,
+};
+
+static const unsigned gpio_w2_aud_pw2_pins[] = {
+	TEGRA_PIN_GPIO_W2_AUD_PW2,
+};
+
+static const unsigned gpio_w3_aud_pw3_pins[] = {
+	TEGRA_PIN_GPIO_W3_AUD_PW3,
+};
+
+static const unsigned clk1_out_pw4_pins[] = {
+	TEGRA_PIN_CLK1_OUT_PW4,
+};
+
+static const unsigned clk2_out_pw5_pins[] = {
+	TEGRA_PIN_CLK2_OUT_PW5,
+};
+
+static const unsigned uart3_txd_pw6_pins[] = {
+	TEGRA_PIN_UART3_TXD_PW6,
+};
+
+static const unsigned uart3_rxd_pw7_pins[] = {
+	TEGRA_PIN_UART3_RXD_PW7,
+};
+
+static const unsigned dvfs_pwm_px0_pins[] = {
+	TEGRA_PIN_DVFS_PWM_PX0,
+};
+
+static const unsigned gpio_x1_aud_px1_pins[] = {
+	TEGRA_PIN_GPIO_X1_AUD_PX1,
+};
+
+static const unsigned dvfs_clk_px2_pins[] = {
+	TEGRA_PIN_DVFS_CLK_PX2,
+};
+
+static const unsigned gpio_x3_aud_px3_pins[] = {
+	TEGRA_PIN_GPIO_X3_AUD_PX3,
+};
+
+static const unsigned gpio_x4_aud_px4_pins[] = {
+	TEGRA_PIN_GPIO_X4_AUD_PX4,
+};
+
+static const unsigned gpio_x5_aud_px5_pins[] = {
+	TEGRA_PIN_GPIO_X5_AUD_PX5,
+};
+
+static const unsigned gpio_x6_aud_px6_pins[] = {
+	TEGRA_PIN_GPIO_X6_AUD_PX6,
+};
+
+static const unsigned gpio_x7_aud_px7_pins[] = {
+	TEGRA_PIN_GPIO_X7_AUD_PX7,
+};
+
+static const unsigned ulpi_clk_py0_pins[] = {
+	TEGRA_PIN_ULPI_CLK_PY0,
+};
+
+static const unsigned ulpi_dir_py1_pins[] = {
+	TEGRA_PIN_ULPI_DIR_PY1,
+};
+
+static const unsigned ulpi_nxt_py2_pins[] = {
+	TEGRA_PIN_ULPI_NXT_PY2,
+};
+
+static const unsigned ulpi_stp_py3_pins[] = {
+	TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned sdmmc1_dat3_py4_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT3_PY4,
+};
+
+static const unsigned sdmmc1_dat2_py5_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT2_PY5,
+};
+
+static const unsigned sdmmc1_dat1_py6_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT1_PY6,
+};
+
+static const unsigned sdmmc1_dat0_py7_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT0_PY7,
+};
+
+static const unsigned sdmmc1_clk_pz0_pins[] = {
+	TEGRA_PIN_SDMMC1_CLK_PZ0,
+};
+
+static const unsigned sdmmc1_cmd_pz1_pins[] = {
+	TEGRA_PIN_SDMMC1_CMD_PZ1,
+};
+
+static const unsigned sys_clk_req_pz5_pins[] = {
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+};
+
+static const unsigned pwr_i2c_scl_pz6_pins[] = {
+	TEGRA_PIN_PWR_I2C_SCL_PZ6,
+};
+
+static const unsigned pwr_i2c_sda_pz7_pins[] = {
+	TEGRA_PIN_PWR_I2C_SDA_PZ7,
+};
+
+static const unsigned sdmmc4_dat0_paa0_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT0_PAA0,
+};
+
+static const unsigned sdmmc4_dat1_paa1_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT1_PAA1,
+};
+
+static const unsigned sdmmc4_dat2_paa2_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT2_PAA2,
+};
+
+static const unsigned sdmmc4_dat3_paa3_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT3_PAA3,
+};
+
+static const unsigned sdmmc4_dat4_paa4_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT4_PAA4,
+};
+
+static const unsigned sdmmc4_dat5_paa5_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT5_PAA5,
+};
+
+static const unsigned sdmmc4_dat6_paa6_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT6_PAA6,
+};
+
+static const unsigned sdmmc4_dat7_paa7_pins[] = {
+	TEGRA_PIN_SDMMC4_DAT7_PAA7,
+};
+
+static const unsigned pbb0_pins[] = {
+	TEGRA_PIN_PBB0,
+};
+
+static const unsigned cam_i2c_scl_pbb1_pins[] = {
+	TEGRA_PIN_CAM_I2C_SCL_PBB1,
+};
+
+static const unsigned cam_i2c_sda_pbb2_pins[] = {
+	TEGRA_PIN_CAM_I2C_SDA_PBB2,
+};
+
+static const unsigned pbb3_pins[] = {
+	TEGRA_PIN_PBB3,
+};
+
+static const unsigned pbb4_pins[] = {
+	TEGRA_PIN_PBB4,
+};
+
+static const unsigned pbb5_pins[] = {
+	TEGRA_PIN_PBB5,
+};
+
+static const unsigned pbb6_pins[] = {
+	TEGRA_PIN_PBB6,
+};
+
+static const unsigned pbb7_pins[] = {
+	TEGRA_PIN_PBB7,
+};
+
+static const unsigned cam_mclk_pcc0_pins[] = {
+	TEGRA_PIN_CAM_MCLK_PCC0,
+};
+
+static const unsigned pcc1_pins[] = {
+	TEGRA_PIN_PCC1,
+};
+
+static const unsigned pcc2_pins[] = {
+	TEGRA_PIN_PCC2,
+};
+
+static const unsigned sdmmc4_clk_pcc4_pins[] = {
+	TEGRA_PIN_SDMMC4_CLK_PCC4,
+};
+
+static const unsigned clk2_req_pcc5_pins[] = {
+	TEGRA_PIN_CLK2_REQ_PCC5,
+};
+
+static const unsigned clk3_out_pee0_pins[] = {
+	TEGRA_PIN_CLK3_OUT_PEE0,
+};
+
+static const unsigned clk3_req_pee1_pins[] = {
+	TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned clk1_req_pee2_pins[] = {
+	TEGRA_PIN_CLK1_REQ_PEE2,
+};
+
+static const unsigned hdmi_cec_pee3_pins[] = {
+	TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
+static const unsigned sdmmc3_clk_lb_out_pee4_pins[] = {
+	TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4,
+};
+
+static const unsigned sdmmc3_clk_lb_in_pee5_pins[] = {
+	TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
+};
+
+static const unsigned core_pwr_req_pins[] = {
+	TEGRA_PIN_CORE_PWR_REQ,
+};
+
+static const unsigned cpu_pwr_req_pins[] = {
+	TEGRA_PIN_CPU_PWR_REQ,
+};
+
+static const unsigned owr_pins[] = {
+	TEGRA_PIN_OWR,
+};
+
+static const unsigned pwr_int_n_pins[] = {
+	TEGRA_PIN_PWR_INT_N,
+};
+
+static const unsigned reset_out_n_pins[] = {
+	TEGRA_PIN_RESET_OUT_N,
+};
+
+static const unsigned drive_ao1_pins[] = {
+	TEGRA_PIN_KB_ROW0_PR0,
+	TEGRA_PIN_KB_ROW1_PR1,
+	TEGRA_PIN_KB_ROW2_PR2,
+	TEGRA_PIN_KB_ROW3_PR3,
+	TEGRA_PIN_KB_ROW4_PR4,
+	TEGRA_PIN_KB_ROW5_PR5,
+	TEGRA_PIN_KB_ROW6_PR6,
+	TEGRA_PIN_KB_ROW7_PR7,
+	TEGRA_PIN_PWR_I2C_SCL_PZ6,
+	TEGRA_PIN_PWR_I2C_SDA_PZ7,
+};
+
+static const unsigned drive_ao2_pins[] = {
+	TEGRA_PIN_CLK_32K_OUT_PA0,
+	TEGRA_PIN_KB_COL0_PQ0,
+	TEGRA_PIN_KB_COL1_PQ1,
+	TEGRA_PIN_KB_COL2_PQ2,
+	TEGRA_PIN_KB_COL3_PQ3,
+	TEGRA_PIN_KB_COL4_PQ4,
+	TEGRA_PIN_KB_COL5_PQ5,
+	TEGRA_PIN_KB_COL6_PQ6,
+	TEGRA_PIN_KB_COL7_PQ7,
+	TEGRA_PIN_KB_ROW8_PS0,
+	TEGRA_PIN_KB_ROW9_PS1,
+	TEGRA_PIN_KB_ROW10_PS2,
+	TEGRA_PIN_SYS_CLK_REQ_PZ5,
+	TEGRA_PIN_CORE_PWR_REQ,
+	TEGRA_PIN_CPU_PWR_REQ,
+	TEGRA_PIN_RESET_OUT_N,
+};
+
+static const unsigned drive_at1_pins[] = {
+	TEGRA_PIN_GMI_AD8_PH0,
+	TEGRA_PIN_GMI_AD9_PH1,
+	TEGRA_PIN_GMI_AD10_PH2,
+	TEGRA_PIN_GMI_AD11_PH3,
+	TEGRA_PIN_GMI_AD12_PH4,
+	TEGRA_PIN_GMI_AD13_PH5,
+	TEGRA_PIN_GMI_AD14_PH6,
+	TEGRA_PIN_GMI_AD15_PH7,
+
+	TEGRA_PIN_GMI_IORDY_PI5,
+	TEGRA_PIN_GMI_CS7_N_PI6,
+};
+
+static const unsigned drive_at2_pins[] = {
+	TEGRA_PIN_GMI_AD0_PG0,
+	TEGRA_PIN_GMI_AD1_PG1,
+	TEGRA_PIN_GMI_AD2_PG2,
+	TEGRA_PIN_GMI_AD3_PG3,
+	TEGRA_PIN_GMI_AD4_PG4,
+	TEGRA_PIN_GMI_AD5_PG5,
+	TEGRA_PIN_GMI_AD6_PG6,
+	TEGRA_PIN_GMI_AD7_PG7,
+
+	TEGRA_PIN_GMI_WR_N_PI0,
+	TEGRA_PIN_GMI_OE_N_PI1,
+	TEGRA_PIN_GMI_CS6_N_PI3,
+	TEGRA_PIN_GMI_RST_N_PI4,
+	TEGRA_PIN_GMI_WAIT_PI7,
+
+	TEGRA_PIN_GMI_DQS_P_PJ3,
+
+	TEGRA_PIN_GMI_ADV_N_PK0,
+	TEGRA_PIN_GMI_CLK_PK1,
+	TEGRA_PIN_GMI_CS4_N_PK2,
+	TEGRA_PIN_GMI_CS2_N_PK3,
+	TEGRA_PIN_GMI_CS3_N_PK4,
+};
+
+static const unsigned drive_at3_pins[] = {
+	TEGRA_PIN_GMI_WP_N_PC7,
+	TEGRA_PIN_GMI_CS0_N_PJ0,
+};
+
+static const unsigned drive_at4_pins[] = {
+	TEGRA_PIN_GMI_A17_PB0,
+	TEGRA_PIN_GMI_A18_PB1,
+	TEGRA_PIN_GMI_CS1_N_PJ2,
+	TEGRA_PIN_GMI_A16_PJ7,
+	TEGRA_PIN_GMI_A19_PK7,
+};
+
+static const unsigned drive_at5_pins[] = {
+	TEGRA_PIN_GEN2_I2C_SCL_PT5,
+	TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned drive_cdev1_pins[] = {
+	TEGRA_PIN_CLK1_OUT_PW4,
+	TEGRA_PIN_CLK1_REQ_PEE2,
+};
+
+static const unsigned drive_cdev2_pins[] = {
+	TEGRA_PIN_CLK2_OUT_PW5,
+	TEGRA_PIN_CLK2_REQ_PCC5,
+	TEGRA_PIN_SDMMC1_WP_N_PV3,
+};
+
+static const unsigned drive_dap1_pins[] = {
+	TEGRA_PIN_DAP1_FS_PN0,
+	TEGRA_PIN_DAP1_DIN_PN1,
+	TEGRA_PIN_DAP1_DOUT_PN2,
+	TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned drive_dap2_pins[] = {
+	TEGRA_PIN_DAP2_FS_PA2,
+	TEGRA_PIN_DAP2_SCLK_PA3,
+	TEGRA_PIN_DAP2_DIN_PA4,
+	TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned drive_dap3_pins[] = {
+	TEGRA_PIN_DAP3_FS_PP0,
+	TEGRA_PIN_DAP3_DIN_PP1,
+	TEGRA_PIN_DAP3_DOUT_PP2,
+	TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned drive_dap4_pins[] = {
+	TEGRA_PIN_DAP4_FS_PP4,
+	TEGRA_PIN_DAP4_DIN_PP5,
+	TEGRA_PIN_DAP4_DOUT_PP6,
+	TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned drive_dbg_pins[] = {
+	TEGRA_PIN_GEN1_I2C_SCL_PC4,
+	TEGRA_PIN_GEN1_I2C_SDA_PC5,
+	TEGRA_PIN_PU0,
+	TEGRA_PIN_PU1,
+	TEGRA_PIN_PU2,
+	TEGRA_PIN_PU3,
+	TEGRA_PIN_PU4,
+	TEGRA_PIN_PU5,
+	TEGRA_PIN_PU6,
+};
+
+static const unsigned drive_sdio3_pins[] = {
+	TEGRA_PIN_SDMMC3_CLK_PA6,
+	TEGRA_PIN_SDMMC3_CMD_PA7,
+	TEGRA_PIN_SDMMC3_DAT3_PB4,
+	TEGRA_PIN_SDMMC3_DAT2_PB5,
+	TEGRA_PIN_SDMMC3_DAT1_PB6,
+	TEGRA_PIN_SDMMC3_DAT0_PB7,
+	TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4,
+	TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
+};
+
+static const unsigned drive_spi_pins[] = {
+	TEGRA_PIN_DVFS_PWM_PX0,
+	TEGRA_PIN_GPIO_X1_AUD_PX1,
+	TEGRA_PIN_DVFS_CLK_PX2,
+	TEGRA_PIN_GPIO_X3_AUD_PX3,
+	TEGRA_PIN_GPIO_X4_AUD_PX4,
+	TEGRA_PIN_GPIO_X5_AUD_PX5,
+	TEGRA_PIN_GPIO_X6_AUD_PX6,
+	TEGRA_PIN_GPIO_X7_AUD_PX7,
+	TEGRA_PIN_GPIO_W2_AUD_PW2,
+	TEGRA_PIN_GPIO_W3_AUD_PW3,
+};
+
+static const unsigned drive_uaa_pins[] = {
+	TEGRA_PIN_ULPI_DATA0_PO1,
+	TEGRA_PIN_ULPI_DATA1_PO2,
+	TEGRA_PIN_ULPI_DATA2_PO3,
+	TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned drive_uab_pins[] = {
+	TEGRA_PIN_ULPI_DATA7_PO0,
+	TEGRA_PIN_ULPI_DATA4_PO5,
+	TEGRA_PIN_ULPI_DATA5_PO6,
+	TEGRA_PIN_ULPI_DATA6_PO7,
+	TEGRA_PIN_PV0,
+	TEGRA_PIN_PV1,
+};
+
+static const unsigned drive_uart2_pins[] = {
+	TEGRA_PIN_UART2_TXD_PC2,
+	TEGRA_PIN_UART2_RXD_PC3,
+	TEGRA_PIN_UART2_CTS_N_PJ5,
+	TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned drive_uart3_pins[] = {
+	TEGRA_PIN_UART3_CTS_N_PA1,
+	TEGRA_PIN_UART3_RTS_N_PC0,
+	TEGRA_PIN_UART3_TXD_PW6,
+	TEGRA_PIN_UART3_RXD_PW7,
+};
+
+static const unsigned drive_sdio1_pins[] = {
+	TEGRA_PIN_SDMMC1_DAT3_PY4,
+	TEGRA_PIN_SDMMC1_DAT2_PY5,
+	TEGRA_PIN_SDMMC1_DAT1_PY6,
+	TEGRA_PIN_SDMMC1_DAT0_PY7,
+	TEGRA_PIN_SDMMC1_CLK_PZ0,
+	TEGRA_PIN_SDMMC1_CMD_PZ1,
+};
+
+static const unsigned drive_ddc_pins[] = {
+	TEGRA_PIN_DDC_SCL_PV4,
+	TEGRA_PIN_DDC_SDA_PV5,
+};
+
+static const unsigned drive_gma_pins[] = {
+	TEGRA_PIN_SDMMC4_CLK_PCC4,
+	TEGRA_PIN_SDMMC4_CMD_PT7,
+	TEGRA_PIN_SDMMC4_DAT0_PAA0,
+	TEGRA_PIN_SDMMC4_DAT1_PAA1,
+	TEGRA_PIN_SDMMC4_DAT2_PAA2,
+	TEGRA_PIN_SDMMC4_DAT3_PAA3,
+	TEGRA_PIN_SDMMC4_DAT4_PAA4,
+	TEGRA_PIN_SDMMC4_DAT5_PAA5,
+	TEGRA_PIN_SDMMC4_DAT6_PAA6,
+	TEGRA_PIN_SDMMC4_DAT7_PAA7,
+};
+
+static const unsigned drive_gme_pins[] = {
+	TEGRA_PIN_PBB0,
+	TEGRA_PIN_CAM_I2C_SCL_PBB1,
+	TEGRA_PIN_CAM_I2C_SDA_PBB2,
+	TEGRA_PIN_PBB3,
+	TEGRA_PIN_PCC2,
+};
+
+static const unsigned drive_gmf_pins[] = {
+	TEGRA_PIN_PBB4,
+	TEGRA_PIN_PBB5,
+	TEGRA_PIN_PBB6,
+	TEGRA_PIN_PBB7,
+};
+
+static const unsigned drive_gmg_pins[] = {
+	TEGRA_PIN_CAM_MCLK_PCC0,
+};
+
+static const unsigned drive_gmh_pins[] = {
+	TEGRA_PIN_PCC1,
+};
+
+static const unsigned drive_owr_pins[] = {
+	TEGRA_PIN_SDMMC3_CD_N_PV2,
+};
+
+static const unsigned drive_uda_pins[] = {
+	TEGRA_PIN_ULPI_CLK_PY0,
+	TEGRA_PIN_ULPI_DIR_PY1,
+	TEGRA_PIN_ULPI_NXT_PY2,
+	TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned drive_dev3_pins[] = {
+	TEGRA_PIN_CLK3_OUT_PEE0,
+	TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+enum tegra_mux {
+	TEGRA_MUX_BLINK,
+	TEGRA_MUX_CEC,
+	TEGRA_MUX_CLDVFS,
+	TEGRA_MUX_CLK12,
+	TEGRA_MUX_CPU,
+	TEGRA_MUX_DAP,
+	TEGRA_MUX_DAP1,
+	TEGRA_MUX_DAP2,
+	TEGRA_MUX_DEV3,
+	TEGRA_MUX_DISPLAYA,
+	TEGRA_MUX_DISPLAYA_ALT,
+	TEGRA_MUX_DISPLAYB,
+	TEGRA_MUX_DTV,
+	TEGRA_MUX_EMC_DLL,
+	TEGRA_MUX_EXTPERIPH1,
+	TEGRA_MUX_EXTPERIPH2,
+	TEGRA_MUX_EXTPERIPH3,
+	TEGRA_MUX_GMI,
+	TEGRA_MUX_GMI_ALT,
+	TEGRA_MUX_HDA,
+	TEGRA_MUX_HSI,
+	TEGRA_MUX_I2C1,
+	TEGRA_MUX_I2C2,
+	TEGRA_MUX_I2C3,
+	TEGRA_MUX_I2C4,
+	TEGRA_MUX_I2CPWR,
+	TEGRA_MUX_I2S0,
+	TEGRA_MUX_I2S1,
+	TEGRA_MUX_I2S2,
+	TEGRA_MUX_I2S3,
+	TEGRA_MUX_I2S4,
+	TEGRA_MUX_IRDA,
+	TEGRA_MUX_KBC,
+	TEGRA_MUX_NAND,
+	TEGRA_MUX_NAND_ALT,
+	TEGRA_MUX_OWR,
+	TEGRA_MUX_PMI,
+	TEGRA_MUX_PWM0,
+	TEGRA_MUX_PWM1,
+	TEGRA_MUX_PWM2,
+	TEGRA_MUX_PWM3,
+	TEGRA_MUX_PWRON,
+	TEGRA_MUX_RESET_OUT_N,
+	TEGRA_MUX_RSVD1,
+	TEGRA_MUX_RSVD2,
+	TEGRA_MUX_RSVD3,
+	TEGRA_MUX_RSVD4,
+	TEGRA_MUX_SDMMC1,
+	TEGRA_MUX_SDMMC2,
+	TEGRA_MUX_SDMMC3,
+	TEGRA_MUX_SDMMC4,
+	TEGRA_MUX_SOC,
+	TEGRA_MUX_SPDIF,
+	TEGRA_MUX_SPI1,
+	TEGRA_MUX_SPI2,
+	TEGRA_MUX_SPI3,
+	TEGRA_MUX_SPI4,
+	TEGRA_MUX_SPI5,
+	TEGRA_MUX_SPI6,
+	TEGRA_MUX_SYSCLK,
+	TEGRA_MUX_TRACE,
+	TEGRA_MUX_UARTA,
+	TEGRA_MUX_UARTB,
+	TEGRA_MUX_UARTC,
+	TEGRA_MUX_UARTD,
+	TEGRA_MUX_ULPI,
+	TEGRA_MUX_USB,
+	TEGRA_MUX_VGP1,
+	TEGRA_MUX_VGP2,
+	TEGRA_MUX_VGP3,
+	TEGRA_MUX_VGP4,
+	TEGRA_MUX_VGP5,
+	TEGRA_MUX_VGP6,
+	TEGRA_MUX_VI,
+	TEGRA_MUX_VI_ALT1,
+	TEGRA_MUX_VI_ALT3,
+};
+
+static const char * const blink_groups[] = {
+	"clk_32k_out_pa0",
+};
+
+static const char * const cec_groups[] = {
+	"hdmi_cec_pee3",
+};
+
+static const char * const cldvfs_groups[] = {
+	"gmi_ad9_ph1",
+	"gmi_ad10_ph2",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"dvfs_pwm_px0",
+	"dvfs_clk_px2",
+};
+
+static const char * const clk12_groups[] = {
+	"sdmmc1_wp_n_pv3",
+	"sdmmc1_clk_pz0",
+};
+
+static const char * const cpu_groups[] = {
+	"cpu_pwr_req",
+};
+
+static const char * const dap_groups[] = {
+	"clk1_req_pee2",
+	"clk2_req_pcc5",
+};
+
+static const char * const dap1_groups[] = {
+	"clk1_req_pee2",
+};
+
+static const char * const dap2_groups[] = {
+	"clk1_out_pw4",
+	"gpio_x4_aud_px4",
+};
+
+static const char * const dev3_groups[] = {
+	"clk3_req_pee1",
+};
+
+static const char * const displaya_groups[] = {
+	"dap3_fs_pp0",
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_sclk_pp3",
+	"uart3_rts_n_pc0",
+	"pu3",
+	"pu4",
+	"pu5",
+	"pbb3",
+	"pbb4",
+	"pbb5",
+	"pbb6",
+	"kb_row3_pr3",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+	"kb_row6_pr6",
+	"kb_col3_pq3",
+	"sdmmc3_dat2_pb5",
+};
+
+static const char * const displaya_alt_groups[] = {
+	"kb_row6_pr6",
+};
+
+static const char * const displayb_groups[] = {
+	"dap3_fs_pp0",
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_sclk_pp3",
+	"pu3",
+	"pu4",
+	"pu5",
+	"pu6",
+	"pbb3",
+	"pbb4",
+	"pbb5",
+	"pbb6",
+	"kb_row3_pr3",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+	"kb_row6_pr6",
+	"sdmmc3_dat3_pb4",
+};
+
+static const char * const dtv_groups[] = {
+	"uart3_cts_n_pa1",
+	"uart3_rts_n_pc0",
+	"dap4_fs_pp4",
+	"dap4_dout_pp6",
+	"gmi_wait_pi7",
+	"gmi_ad8_ph0",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+};
+
+static const char * const emc_dll_groups[] = {
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+};
+
+static const char * const extperiph1_groups[] = {
+	"clk1_out_pw4",
+};
+
+static const char * const extperiph2_groups[] = {
+	"clk2_out_pw5",
+};
+
+static const char * const extperiph3_groups[] = {
+	"clk3_out_pee0",
+};
+
+static const char * const gmi_groups[] = {
+	"gmi_wp_n_pc7",
+
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_ad8_ph0",
+	"gmi_ad9_ph1",
+	"gmi_ad10_ph2",
+	"gmi_ad11_ph3",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_wr_n_pi0",
+	"gmi_oe_n_pi1",
+	"gmi_cs6_n_pi3",
+	"gmi_rst_n_pi4",
+	"gmi_iordy_pi5",
+	"gmi_cs7_n_pi6",
+	"gmi_wait_pi7",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+	"gmi_dqs_p_pj3",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs4_n_pk2",
+	"gmi_cs2_n_pk3",
+	"gmi_cs3_n_pk4",
+	"gmi_a16_pj7",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_a19_pk7",
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc4_dat7_paa7",
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+	"dap1_fs_pn0",
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_sclk_pn3",
+};
+
+static const char * const gmi_alt_groups[] = {
+	"gmi_wp_n_pc7",
+	"gmi_cs3_n_pk4",
+	"gmi_a16_pj7",
+};
+
+static const char * const hda_groups[] = {
+	"dap1_fs_pn0",
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_sclk_pn3",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+};
+
+static const char * const hsi_groups[] = {
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+};
+
+static const char * const i2c1_groups[] = {
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"gpio_w2_aud_pw2",
+	"gpio_w3_aud_pw3",
+};
+
+static const char * const i2c2_groups[] = {
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+};
+
+static const char * const i2c3_groups[] = {
+	"cam_i2c_scl_pbb1",
+	"cam_i2c_sda_pbb2",
+};
+
+static const char * const i2c4_groups[] = {
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+};
+
+static const char * const i2cpwr_groups[] = {
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+};
+
+static const char * const i2s0_groups[] = {
+	"dap1_fs_pn0",
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_sclk_pn3",
+};
+
+static const char * const i2s1_groups[] = {
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+};
+
+static const char * const i2s2_groups[] = {
+	"dap3_fs_pp0",
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_sclk_pp3",
+};
+
+static const char * const i2s3_groups[] = {
+	"dap4_fs_pp4",
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_sclk_pp7",
+};
+
+static const char * const i2s4_groups[] = {
+	"pcc1",
+	"pbb0",
+	"pbb7",
+	"pcc2",
+};
+
+static const char * const irda_groups[] = {
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+};
+
+static const char * const kbc_groups[] = {
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row2_pr2",
+	"kb_row3_pr3",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+	"kb_row6_pr6",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+	"kb_row10_ps2",
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+	"kb_col2_pq2",
+	"kb_col3_pq3",
+	"kb_col4_pq4",
+	"kb_col5_pq5",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+};
+
+static const char * const nand_groups[] = {
+	"gmi_wp_n_pc7",
+	"gmi_wait_pi7",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+	"gmi_cs2_n_pk3",
+	"gmi_cs3_n_pk4",
+	"gmi_cs4_n_pk2",
+	"gmi_cs6_n_pi3",
+	"gmi_cs7_n_pi6",
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_ad8_ph0",
+	"gmi_ad9_ph1",
+	"gmi_ad10_ph2",
+	"gmi_ad11_ph3",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_wr_n_pi0",
+	"gmi_oe_n_pi1",
+	"gmi_dqs_p_pj3",
+	"gmi_rst_n_pi4",
+};
+
+static const char * const nand_alt_groups[] = {
+	"gmi_cs6_n_pi3",
+	"gmi_cs7_n_pi6",
+	"gmi_rst_n_pi4",
+};
+
+static const char * const owr_groups[] = {
+	"pu0",
+	"kb_col4_pq4",
+	"owr",
+	"sdmmc3_cd_n_pv2",
+};
+
+static const char * const pmi_groups[] = {
+	"pwr_int_n",
+};
+
+static const char * const pwm0_groups[] = {
+	"sdmmc1_dat2_py5",
+	"uart3_rts_n_pc0",
+	"pu3",
+	"gmi_ad8_ph0",
+	"sdmmc3_dat3_pb4",
+};
+
+static const char * const pwm1_groups[] = {
+	"sdmmc1_dat1_py6",
+	"pu4",
+	"gmi_ad9_ph1",
+	"sdmmc3_dat2_pb5",
+};
+
+static const char * const pwm2_groups[] = {
+	"pu5",
+	"gmi_ad10_ph2",
+	"kb_col3_pq3",
+	"sdmmc3_dat1_pb6",
+};
+
+static const char * const pwm3_groups[] = {
+	"pu6",
+	"gmi_ad11_ph3",
+	"sdmmc3_cmd_pa7",
+};
+
+static const char * const pwron_groups[] = {
+	"core_pwr_req",
+};
+
+static const char * const reset_out_n_groups[] = {
+	"reset_out_n",
+};
+
+static const char * const rsvd1_groups[] = {
+	"pv1",
+	"hdmi_int_pn7",
+	"pu1",
+	"pu2",
+	"gmi_wp_n_pc7",
+	"gmi_adv_n_pk0",
+	"gmi_cs0_n_pj0",
+	"gmi_cs1_n_pj2",
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_wr_n_pi0",
+	"gmi_oe_n_pi1",
+	"gpio_x4_aud_px4",
+	"gpio_x5_aud_px5",
+	"gpio_x7_aud_px7",
+
+	"reset_out_n",
+};
+
+static const char * const rsvd2_groups[] = {
+	"pv0",
+	"pv1",
+	"sdmmc1_dat0_py7",
+	"clk2_out_pw5",
+	"clk2_req_pcc5",
+	"hdmi_int_pn7",
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+	"uart3_txd_pw6",
+	"uart3_rxd_pw7",
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"dap4_fs_pp4",
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_sclk_pp7",
+	"clk3_out_pee0",
+	"clk3_req_pee1",
+	"gmi_iordy_pi5",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+	"sdmmc4_dat7_paa7",
+	"pcc1",
+	"pbb7",
+	"pcc2",
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row2_pr2",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+	"kb_row10_ps2",
+	"kb_col1_pq1",
+	"kb_col2_pq2",
+	"kb_col5_pq5",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"sys_clk_req_pz5",
+	"core_pwr_req",
+	"cpu_pwr_req",
+	"pwr_int_n",
+	"owr",
+	"spdif_out_pk5",
+	"gpio_x1_aud_px1",
+	"sdmmc3_clk_pa6",
+	"sdmmc3_dat0_pb7",
+	"gpio_w2_aud_pw2",
+	"usb_vbus_en0_pn4",
+	"usb_vbus_en1_pn5",
+	"sdmmc3_clk_lb_out_pee4",
+	"sdmmc3_clk_lb_in_pee5",
+	"reset_out_n",
+};
+
+static const char * const rsvd3_groups[] = {
+	"pv0",
+	"pv1",
+	"sdmmc1_clk_pz0",
+	"clk2_out_pw5",
+	"clk2_req_pcc5",
+	"hdmi_int_pn7",
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+	"uart2_rts_n_pj6",
+	"uart2_cts_n_pj5",
+	"uart3_txd_pw6",
+	"uart3_rxd_pw7",
+	"pu0",
+	"pu1",
+	"pu2",
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"dap4_din_pp5",
+	"dap4_sclk_pp7",
+	"clk3_out_pee0",
+	"clk3_req_pee1",
+	"pcc1",
+	"cam_i2c_scl_pbb1",
+	"cam_i2c_sda_pbb2",
+	"pbb7",
+	"pcc2",
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row2_pr2",
+	"kb_row3_pr3",
+	"kb_row9_ps1",
+	"kb_row10_ps2",
+	"clk_32k_out_pa0",
+	"sys_clk_req_pz5",
+	"core_pwr_req",
+	"cpu_pwr_req",
+	"pwr_int_n",
+	"owr",
+	"clk1_req_pee2",
+	"clk1_out_pw4",
+	"spdif_out_pk5",
+	"spdif_in_pk6",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+	"dvfs_pwm_px0",
+	"gpio_x1_aud_px1",
+	"gpio_x3_aud_px3",
+	"dvfs_clk_px2",
+	"sdmmc3_clk_pa6",
+	"sdmmc3_dat0_pb7",
+	"hdmi_cec_pee3",
+	"sdmmc3_cd_n_pv2",
+	"usb_vbus_en0_pn4",
+	"usb_vbus_en1_pn5",
+	"sdmmc3_clk_lb_out_pee4",
+	"sdmmc3_clk_lb_in_pee5",
+	"reset_out_n",
+};
+
+static const char * const rsvd4_groups[] = {
+	"pv0",
+	"pv1",
+	"sdmmc1_clk_pz0",
+	"clk2_out_pw5",
+	"clk2_req_pcc5",
+	"hdmi_int_pn7",
+	"ddc_scl_pv4",
+	"ddc_sda_pv5",
+	"pu0",
+	"pu1",
+	"pu2",
+	"gen1_i2c_scl_pc4",
+	"gen1_i2c_sda_pc5",
+	"dap4_fs_pp4",
+	"dap4_din_pp5",
+	"dap4_dout_pp6",
+	"dap4_sclk_pp7",
+	"clk3_out_pee0",
+	"clk3_req_pee1",
+	"gmi_ad0_pg0",
+	"gmi_ad1_pg1",
+	"gmi_ad2_pg2",
+	"gmi_ad3_pg3",
+	"gmi_ad4_pg4",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_rst_n_pi4",
+	"gen2_i2c_scl_pt5",
+	"gen2_i2c_sda_pt6",
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc4_dat7_paa7",
+	"cam_mclk_pcc0",
+	"pcc1",
+	"cam_i2c_scl_pbb1",
+	"cam_i2c_sda_pbb2",
+	"pbb3",
+	"pbb4",
+	"pbb5",
+	"pbb6",
+	"pbb7",
+	"pcc2",
+	"pwr_i2c_scl_pz6",
+	"pwr_i2c_sda_pz7",
+	"kb_row0_pr0",
+	"kb_row1_pr1",
+	"kb_row2_pr2",
+	"kb_col2_pq2",
+	"kb_col5_pq5",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"clk_32k_out_pa0",
+	"sys_clk_req_pz5",
+	"core_pwr_req",
+	"cpu_pwr_req",
+	"pwr_int_n",
+	"owr",
+	"dap1_fs_pn0",
+	"dap1_din_pn1",
+	"dap1_dout_pn2",
+	"dap1_sclk_pn3",
+	"clk1_req_pee2",
+	"clk1_out_pw4",
+	"spdif_in_pk6",
+	"spdif_out_pk5",
+	"dap2_fs_pa2",
+	"dap2_sclk_pa3",
+	"dap2_din_pa4",
+	"dap2_dout_pa5",
+	"dvfs_pwm_px0",
+	"gpio_x1_aud_px1",
+	"gpio_x3_aud_px3",
+	"dvfs_clk_px2",
+	"gpio_x5_aud_px5",
+	"gpio_x6_aud_px6",
+	"gpio_x7_aud_px7",
+	"sdmmc3_cd_n_pv2",
+	"usb_vbus_en0_pn4",
+	"usb_vbus_en1_pn5",
+	"sdmmc3_clk_lb_in_pee5",
+	"sdmmc3_clk_lb_out_pee4",
+};
+
+static const char * const sdmmc1_groups[] = {
+
+	"sdmmc1_clk_pz0",
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat3_py4",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat0_py7",
+	"uart3_cts_n_pa1",
+	"kb_col5_pq5",
+	"sdmmc1_wp_n_pv3",
+};
+
+static const char * const sdmmc2_groups[] = {
+	"gmi_iordy_pi5",
+	"gmi_clk_pk1",
+	"gmi_cs2_n_pk3",
+	"gmi_cs3_n_pk4",
+	"gmi_cs7_n_pi6",
+	"gmi_ad12_ph4",
+	"gmi_ad13_ph5",
+	"gmi_ad14_ph6",
+	"gmi_ad15_ph7",
+	"gmi_dqs_p_pj3",
+};
+
+static const char * const sdmmc3_groups[] = {
+	"kb_col4_pq4",
+	"sdmmc3_clk_pa6",
+	"sdmmc3_cmd_pa7",
+	"sdmmc3_dat0_pb7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc3_dat2_pb5",
+	"sdmmc3_dat3_pb4",
+	"hdmi_cec_pee3",
+	"sdmmc3_cd_n_pv2",
+	"sdmmc3_clk_lb_in_pee5",
+	"sdmmc3_clk_lb_out_pee4",
+};
+
+static const char * const sdmmc4_groups[] = {
+	"sdmmc4_clk_pcc4",
+	"sdmmc4_cmd_pt7",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc4_dat7_paa7",
+};
+
+static const char * const soc_groups[] = {
+	"gmi_cs1_n_pj2",
+	"gmi_oe_n_pi1",
+	"clk_32k_out_pa0",
+	"hdmi_cec_pee3",
+};
+
+static const char * const spdif_groups[] = {
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat3_py4",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+	"spdif_in_pk6",
+	"spdif_out_pk5",
+};
+
+static const char * const spi1_groups[] = {
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+	"gpio_x3_aud_px3",
+	"gpio_x4_aud_px4",
+	"gpio_x5_aud_px5",
+	"gpio_x6_aud_px6",
+	"gpio_x7_aud_px7",
+	"gpio_w3_aud_pw3",
+};
+
+static const char * const spi2_groups[] = {
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+	"kb_row4_pr4",
+	"kb_row5_pr5",
+	"kb_col0_pq0",
+	"kb_col1_pq1",
+	"kb_col2_pq2",
+	"kb_col6_pq6",
+	"kb_col7_pq7",
+	"gpio_x4_aud_px4",
+	"gpio_x5_aud_px5",
+	"gpio_x6_aud_px6",
+	"gpio_x7_aud_px7",
+	"gpio_w2_aud_pw2",
+	"gpio_w3_aud_pw3",
+};
+
+static const char * const spi3_groups[] = {
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"sdmmc4_dat0_paa0",
+	"sdmmc4_dat1_paa1",
+	"sdmmc4_dat2_paa2",
+	"sdmmc4_dat3_paa3",
+	"sdmmc4_dat4_paa4",
+	"sdmmc4_dat5_paa5",
+	"sdmmc4_dat6_paa6",
+	"sdmmc3_clk_pa6",
+	"sdmmc3_cmd_pa7",
+	"sdmmc3_dat0_pb7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc3_dat2_pb5",
+	"sdmmc3_dat3_pb4",
+};
+
+static const char * const spi4_groups[] = {
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat3_py4",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat0_py7",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+	"uart2_rts_n_pj6",
+	"uart2_cts_n_pj5",
+	"uart3_txd_pw6",
+	"uart3_rxd_pw7",
+	"uart3_cts_n_pa1",
+	"gmi_wait_pi7",
+	"gmi_cs6_n_pi3",
+	"gmi_ad5_pg5",
+	"gmi_ad6_pg6",
+	"gmi_ad7_pg7",
+	"gmi_a19_pk7",
+	"gmi_wr_n_pi0",
+	"sdmmc1_wp_n_pv3",
+};
+
+static const char * const spi5_groups[] = {
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+	"dap3_fs_pp0",
+	"dap3_din_pp1",
+	"dap3_dout_pp2",
+	"dap3_sclk_pp3",
+};
+
+static const char * const spi6_groups[] = {
+	"dvfs_pwm_px0",
+	"gpio_x1_aud_px1",
+	"gpio_x3_aud_px3",
+	"dvfs_clk_px2",
+	"gpio_x6_aud_px6",
+	"gpio_w2_aud_pw2",
+	"gpio_w3_aud_pw3",
+};
+
+static const char * const sysclk_groups[] = {
+	"sys_clk_req_pz5",
+};
+
+static const char * const trace_groups[] = {
+	"gmi_iordy_pi5",
+	"gmi_adv_n_pk0",
+	"gmi_clk_pk1",
+	"gmi_cs2_n_pk3",
+	"gmi_cs4_n_pk2",
+	"gmi_a16_pj7",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_a19_pk7",
+	"gmi_dqs_p_pj3",
+};
+
+static const char * const uarta_groups[] = {
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+	"sdmmc1_cmd_pz1",
+	"sdmmc1_dat3_py4",
+	"sdmmc1_dat2_py5",
+	"sdmmc1_dat1_py6",
+	"sdmmc1_dat0_py7",
+	"uart2_rxd_pc3",
+	"uart2_txd_pc2",
+	"uart2_rts_n_pj6",
+	"uart2_cts_n_pj5",
+	"pu0",
+	"pu1",
+	"pu2",
+	"pu3",
+	"pu4",
+	"pu5",
+	"pu6",
+	"kb_row7_pr7",
+	"kb_row8_ps0",
+	"kb_row9_ps1",
+	"kb_row10_ps2",
+	"kb_col3_pq3",
+	"kb_col4_pq4",
+	"sdmmc3_cmd_pa7",
+	"sdmmc3_dat1_pb6",
+	"sdmmc1_wp_n_pv3",
+};
+
+static const char * const uartb_groups[] = {
+	"uart2_rts_n_pj6",
+	"uart2_cts_n_pj5",
+};
+
+static const char * const uartc_groups[] = {
+	"uart3_txd_pw6",
+	"uart3_rxd_pw7",
+	"uart3_cts_n_pa1",
+	"uart3_rts_n_pc0",
+};
+
+static const char * const uartd_groups[] = {
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+	"gmi_a16_pj7",
+	"gmi_a17_pb0",
+	"gmi_a18_pb1",
+	"gmi_a19_pk7",
+};
+
+static const char * const ulpi_groups[] = {
+	"ulpi_data0_po1",
+	"ulpi_data1_po2",
+	"ulpi_data2_po3",
+	"ulpi_data3_po4",
+	"ulpi_data4_po5",
+	"ulpi_data5_po6",
+	"ulpi_data6_po7",
+	"ulpi_data7_po0",
+	"ulpi_clk_py0",
+	"ulpi_dir_py1",
+	"ulpi_nxt_py2",
+	"ulpi_stp_py3",
+};
+
+static const char * const usb_groups[] = {
+	"pv0",
+	"pu6",
+	"gmi_cs0_n_pj0",
+	"gmi_cs4_n_pk2",
+	"gmi_ad11_ph3",
+	"kb_col0_pq0",
+	"spdif_in_pk6",
+	"usb_vbus_en0_pn4",
+	"usb_vbus_en1_pn5",
+};
+
+static const char * const vgp1_groups[] = {
+	"cam_i2c_scl_pbb1",
+};
+
+static const char * const vgp2_groups[] = {
+	"cam_i2c_sda_pbb2",
+};
+
+static const char * const vgp3_groups[] = {
+	"pbb3",
+};
+
+static const char * const vgp4_groups[] = {
+	"pbb4",
+};
+
+static const char * const vgp5_groups[] = {
+	"pbb5",
+};
+
+static const char * const vgp6_groups[] = {
+	"pbb6",
+};
+
+static const char * const vi_groups[] = {
+	"cam_mclk_pcc0",
+	"pbb0",
+};
+
+static const char * const vi_alt1_groups[] = {
+	"cam_mclk_pcc0",
+	"pbb0",
+};
+
+static const char * const vi_alt3_groups[] = {
+	"cam_mclk_pcc0",
+	"pbb0",
+};
+
+#define FUNCTION(fname)					\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+static const struct tegra_function  tegra114_functions[] = {
+	FUNCTION(blink),
+	FUNCTION(cec),
+	FUNCTION(cldvfs),
+	FUNCTION(clk12),
+	FUNCTION(cpu),
+	FUNCTION(dap),
+	FUNCTION(dap1),
+	FUNCTION(dap2),
+	FUNCTION(dev3),
+	FUNCTION(displaya),
+	FUNCTION(displaya_alt),
+	FUNCTION(displayb),
+	FUNCTION(dtv),
+	FUNCTION(emc_dll),
+	FUNCTION(extperiph1),
+	FUNCTION(extperiph2),
+	FUNCTION(extperiph3),
+	FUNCTION(gmi),
+	FUNCTION(gmi_alt),
+	FUNCTION(hda),
+	FUNCTION(hsi),
+	FUNCTION(i2c1),
+	FUNCTION(i2c2),
+	FUNCTION(i2c3),
+	FUNCTION(i2c4),
+	FUNCTION(i2cpwr),
+	FUNCTION(i2s0),
+	FUNCTION(i2s1),
+	FUNCTION(i2s2),
+	FUNCTION(i2s3),
+	FUNCTION(i2s4),
+	FUNCTION(irda),
+	FUNCTION(kbc),
+	FUNCTION(nand),
+	FUNCTION(nand_alt),
+	FUNCTION(owr),
+	FUNCTION(pmi),
+	FUNCTION(pwm0),
+	FUNCTION(pwm1),
+	FUNCTION(pwm2),
+	FUNCTION(pwm3),
+	FUNCTION(pwron),
+	FUNCTION(reset_out_n),
+	FUNCTION(rsvd1),
+	FUNCTION(rsvd2),
+	FUNCTION(rsvd3),
+	FUNCTION(rsvd4),
+	FUNCTION(sdmmc1),
+	FUNCTION(sdmmc2),
+	FUNCTION(sdmmc3),
+	FUNCTION(sdmmc4),
+	FUNCTION(soc),
+	FUNCTION(spdif),
+	FUNCTION(spi1),
+	FUNCTION(spi2),
+	FUNCTION(spi3),
+	FUNCTION(spi4),
+	FUNCTION(spi5),
+	FUNCTION(spi6),
+	FUNCTION(sysclk),
+	FUNCTION(trace),
+	FUNCTION(uarta),
+	FUNCTION(uartb),
+	FUNCTION(uartc),
+	FUNCTION(uartd),
+	FUNCTION(ulpi),
+	FUNCTION(usb),
+	FUNCTION(vgp1),
+	FUNCTION(vgp2),
+	FUNCTION(vgp3),
+	FUNCTION(vgp4),
+	FUNCTION(vgp5),
+	FUNCTION(vgp6),
+	FUNCTION(vi),
+	FUNCTION(vi_alt1),
+	FUNCTION(vi_alt3),
+};
+
+#define DRV_PINGROUP_REG_START			0x868	/* bank 0 */
+#define PINGROUP_REG_START			0x3000	/* bank 1 */
+
+#define PINGROUP_REG_Y(r)			((r) - PINGROUP_REG_START)
+#define PINGROUP_REG_N(r)			-1
+
+#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel)	\
+	{								\
+		.name = #pg_name,					\
+		.pins = pg_name##_pins,					\
+		.npins = ARRAY_SIZE(pg_name##_pins),			\
+		.funcs = {						\
+			TEGRA_MUX_##f0,					\
+			TEGRA_MUX_##f1,					\
+			TEGRA_MUX_##f2,					\
+			TEGRA_MUX_##f3,					\
+		},							\
+		.func_safe = TEGRA_MUX_##f_safe,			\
+		.mux_reg = PINGROUP_REG_Y(r),				\
+		.mux_bank = 1,						\
+		.mux_bit = 0,						\
+		.pupd_reg = PINGROUP_REG_Y(r),				\
+		.pupd_bank = 1,						\
+		.pupd_bit = 2,						\
+		.tri_reg = PINGROUP_REG_Y(r),				\
+		.tri_bank = 1,						\
+		.tri_bit = 4,						\
+		.einput_reg = PINGROUP_REG_Y(r),			\
+		.einput_bank = 1,					\
+		.einput_bit = 5,					\
+		.odrain_reg = PINGROUP_REG_##od(r),			\
+		.odrain_bank = 1,					\
+		.odrain_bit = 6,					\
+		.lock_reg = PINGROUP_REG_Y(r),				\
+		.lock_bank = 1,						\
+		.lock_bit = 7,						\
+		.ioreset_reg = PINGROUP_REG_##ior(r),			\
+		.ioreset_bank = 1,					\
+		.ioreset_bit = 8,					\
+		.rcv_sel_reg = PINGROUP_REG_##rcv_sel(r),		\
+		.rcv_sel_bank = 1,					\
+		.rcv_sel_bit = 9,					\
+		.drv_reg = -1,						\
+		.drvtype_reg = -1,					\
+	}
+
+#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_START)
+#define DRV_PINGROUP_DVRTYPE_N(r) -1
+
+#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b,		\
+			drvdn_b, drvdn_w, drvup_b, drvup_w,		\
+			slwr_b, slwr_w, slwf_b, slwf_w,			\
+			drvtype)					\
+	{								\
+		.name = "drive_" #pg_name,				\
+		.pins = drive_##pg_name##_pins,				\
+		.npins = ARRAY_SIZE(drive_##pg_name##_pins),		\
+		.mux_reg = -1,						\
+		.pupd_reg = -1,						\
+		.tri_reg = -1,						\
+		.einput_reg = -1,					\
+		.odrain_reg = -1,					\
+		.lock_reg = -1,						\
+		.ioreset_reg = -1,					\
+		.rcv_sel_reg = -1,					\
+		.drv_reg = DRV_PINGROUP_DVRTYPE_Y(r),			\
+		.drv_bank = 0,						\
+		.hsm_bit = hsm_b,					\
+		.schmitt_bit = schmitt_b,				\
+		.lpmd_bit = lpmd_b,					\
+		.drvdn_bit = drvdn_b,					\
+		.drvdn_width = drvdn_w,					\
+		.drvup_bit = drvup_b,					\
+		.drvup_width = drvup_w,					\
+		.slwr_bit = slwr_b,					\
+		.slwr_width = slwr_w,					\
+		.slwf_bit = slwf_b,					\
+		.slwf_width = slwf_w,					\
+		.drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r),	\
+		.drvtype_bank = 0,					\
+		.drvtype_bit = 6,					\
+	}
+
+static const struct tegra_pingroup tegra114_groups[] = {
+	/*       pg_name,                f0,         f1,         f2,           f3,          safe,     r,      od, ior, rcv_sel */
+	/* FIXME: Fill in correct data in safe column */
+	PINGROUP(ulpi_data0_po1,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x3000,  N,  N,  N),
+	PINGROUP(ulpi_data1_po2,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x3004,  N,  N,  N),
+	PINGROUP(ulpi_data2_po3,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x3008,  N,  N,  N),
+	PINGROUP(ulpi_data3_po4,         SPI3,       HSI,        UARTA,        ULPI,        ULPI,     0x300c,  N,  N,  N),
+	PINGROUP(ulpi_data4_po5,         SPI2,       HSI,        UARTA,        ULPI,        ULPI,     0x3010,  N,  N,  N),
+	PINGROUP(ulpi_data5_po6,         SPI2,       HSI,        UARTA,        ULPI,        ULPI,     0x3014,  N,  N,  N),
+	PINGROUP(ulpi_data6_po7,         SPI2,       HSI,        UARTA,        ULPI,        ULPI,     0x3018,  N,  N,  N),
+	PINGROUP(ulpi_data7_po0,         SPI2,       HSI,        UARTA,        ULPI,        ULPI,     0x301c,  N,  N,  N),
+	PINGROUP(ulpi_clk_py0,           SPI1,       SPI5,       UARTD,        ULPI,        ULPI,     0x3020,  N,  N,  N),
+	PINGROUP(ulpi_dir_py1,           SPI1,       SPI5,       UARTD,        ULPI,        ULPI,     0x3024,  N,  N,  N),
+	PINGROUP(ulpi_nxt_py2,           SPI1,       SPI5,       UARTD,        ULPI,        ULPI,     0x3028,  N,  N,  N),
+	PINGROUP(ulpi_stp_py3,           SPI1,       SPI5,       UARTD,        ULPI,        ULPI,     0x302c,  N,  N,  N),
+	PINGROUP(dap3_fs_pp0,            I2S2,       SPI5,       DISPLAYA,     DISPLAYB,    I2S2,     0x3030,  N,  N,  N),
+	PINGROUP(dap3_din_pp1,           I2S2,       SPI5,       DISPLAYA,     DISPLAYB,    I2S2,     0x3034,  N,  N,  N),
+	PINGROUP(dap3_dout_pp2,          I2S2,       SPI5,       DISPLAYA,     DISPLAYB,    I2S2,     0x3038,  N,  N,  N),
+	PINGROUP(dap3_sclk_pp3,          I2S2,       SPI5,       DISPLAYA,     DISPLAYB,    I2S2,     0x303c,  N,  N,  N),
+	PINGROUP(pv0,                    USB,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3040,  N,  N,  N),
+	PINGROUP(pv1,                    RSVD1,      RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3044,  N,  N,  N),
+	PINGROUP(sdmmc1_clk_pz0,         SDMMC1,     CLK12,      RSVD3,        RSVD4,       RSVD4,    0x3048,  N,  N,  N),
+	PINGROUP(sdmmc1_cmd_pz1,         SDMMC1,     SPDIF,      SPI4,         UARTA,       SDMMC1,   0x304c,  N,  N,  N),
+	PINGROUP(sdmmc1_dat3_py4,        SDMMC1,     SPDIF,      SPI4,         UARTA,       SDMMC1,   0x3050,  N,  N,  N),
+	PINGROUP(sdmmc1_dat2_py5,        SDMMC1,     PWM0,       SPI4,         UARTA,       SDMMC1,   0x3054,  N,  N,  N),
+	PINGROUP(sdmmc1_dat1_py6,        SDMMC1,     PWM1,       SPI4,         UARTA,       SDMMC1,   0x3058,  N,  N,  N),
+	PINGROUP(sdmmc1_dat0_py7,        SDMMC1,     RSVD2,      SPI4,         UARTA,       RSVD2,    0x305c,  N,  N,  N),
+	PINGROUP(clk2_out_pw5,           EXTPERIPH2, RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3068,  N,  N,  N),
+	PINGROUP(clk2_req_pcc5,          DAP,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x306c,  N,  N,  N),
+	PINGROUP(hdmi_int_pn7,           RSVD1,      RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3110,  N,  N,  Y),
+	PINGROUP(ddc_scl_pv4,            I2C4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3114,  N,  N,  Y),
+	PINGROUP(ddc_sda_pv5,            I2C4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3118,  N,  N,  Y),
+	PINGROUP(uart2_rxd_pc3,          IRDA,       SPDIF,      UARTA,        SPI4,        IRDA,     0x3164,  N,  N,  N),
+	PINGROUP(uart2_txd_pc2,          IRDA,       SPDIF,      UARTA,        SPI4,        IRDA,     0x3168,  N,  N,  N),
+	PINGROUP(uart2_rts_n_pj6,        UARTA,      UARTB,      RSVD3,        SPI4,        RSVD3,    0x316c,  N,  N,  N),
+	PINGROUP(uart2_cts_n_pj5,        UARTA,      UARTB,      RSVD3,        SPI4,        RSVD3,    0x3170,  N,  N,  N),
+	PINGROUP(uart3_txd_pw6,          UARTC,      RSVD2,      RSVD3,        SPI4,        RSVD3,    0x3174,  N,  N,  N),
+	PINGROUP(uart3_rxd_pw7,          UARTC,      RSVD2,      RSVD3,        SPI4,        RSVD3,    0x3178,  N,  N,  N),
+	PINGROUP(uart3_cts_n_pa1,        UARTC,      SDMMC1,     DTV,          SPI4,        UARTC,    0x317c,  N,  N,  N),
+	PINGROUP(uart3_rts_n_pc0,        UARTC,      PWM0,       DTV,          DISPLAYA,    UARTC,    0x3180,  N,  N,  N),
+	PINGROUP(pu0,                    OWR,        UARTA,      RSVD3,        RSVD4,       RSVD4,    0x3184,  N,  N,  N),
+	PINGROUP(pu1,                    RSVD1,      UARTA,      RSVD3,        RSVD4,       RSVD4,    0x3188,  N,  N,  N),
+	PINGROUP(pu2,                    RSVD1,      UARTA,      RSVD3,        RSVD4,       RSVD4,    0x318c,  N,  N,  N),
+	PINGROUP(pu3,                    PWM0,       UARTA,      DISPLAYA,     DISPLAYB,    PWM0,     0x3190,  N,  N,  N),
+	PINGROUP(pu4,                    PWM1,       UARTA,      DISPLAYA,     DISPLAYB,    PWM1,     0x3194,  N,  N,  N),
+	PINGROUP(pu5,                    PWM2,       UARTA,      DISPLAYA,     DISPLAYB,    PWM2,     0x3198,  N,  N,  N),
+	PINGROUP(pu6,                    PWM3,       UARTA,      USB,          DISPLAYB,    PWM3,     0x319c,  N,  N,  N),
+	PINGROUP(gen1_i2c_sda_pc5,       I2C1,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x31a0,  Y,  N,  N),
+	PINGROUP(gen1_i2c_scl_pc4,       I2C1,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x31a4,  Y,  N,  N),
+	PINGROUP(dap4_fs_pp4,            I2S3,       RSVD2,      DTV,          RSVD4,       RSVD4,    0x31a8,  N,  N,  N),
+	PINGROUP(dap4_din_pp5,           I2S3,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x31ac,  N,  N,  N),
+	PINGROUP(dap4_dout_pp6,          I2S3,       RSVD2,      DTV,          RSVD4,       RSVD4,    0x31b0,  N,  N,  N),
+	PINGROUP(dap4_sclk_pp7,          I2S3,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x31b4,  N,  N,  N),
+	PINGROUP(clk3_out_pee0,          EXTPERIPH3, RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x31b8,  N,  N,  N),
+	PINGROUP(clk3_req_pee1,          DEV3,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x31bc,  N,  N,  N),
+	PINGROUP(gmi_wp_n_pc7,           RSVD1,      NAND,       GMI,          GMI_ALT,     RSVD1,    0x31c0,  N,  N,  N),
+	PINGROUP(gmi_iordy_pi5,          SDMMC2,     RSVD2,      GMI,          TRACE,       RSVD2,    0x31c4,  N,  N,  N),
+	PINGROUP(gmi_wait_pi7,           SPI4,       NAND,       GMI,          DTV,         NAND,     0x31c8,  N,  N,  N),
+	PINGROUP(gmi_adv_n_pk0,          RSVD1,      NAND,       GMI,          TRACE,       RSVD1,    0x31cc,  N,  N,  N),
+	PINGROUP(gmi_clk_pk1,            SDMMC2,     NAND,       GMI,          TRACE,       GMI,      0x31d0,  N,  N,  N),
+	PINGROUP(gmi_cs0_n_pj0,          RSVD1,      NAND,       GMI,          USB,         RSVD1,    0x31d4,  N,  N,  N),
+	PINGROUP(gmi_cs1_n_pj2,          RSVD1,      NAND,       GMI,          SOC,         RSVD1,    0x31d8,  N,  N,  N),
+	PINGROUP(gmi_cs2_n_pk3,          SDMMC2,     NAND,       GMI,          TRACE,       GMI,      0x31dc,  N,  N,  N),
+	PINGROUP(gmi_cs3_n_pk4,          SDMMC2,     NAND,       GMI,          GMI_ALT,     GMI,      0x31e0,  N,  N,  N),
+	PINGROUP(gmi_cs4_n_pk2,          USB,        NAND,       GMI,          TRACE,       GMI,      0x31e4,  N,  N,  N),
+	PINGROUP(gmi_cs6_n_pi3,          NAND,       NAND_ALT,   GMI,          SPI4,        NAND,     0x31e8,  N,  N,  N),
+	PINGROUP(gmi_cs7_n_pi6,          NAND,       NAND_ALT,   GMI,          SDMMC2,      NAND,     0x31ec,  N,  N,  N),
+	PINGROUP(gmi_ad0_pg0,            RSVD1,      NAND,       GMI,          RSVD4,       RSVD4,    0x31f0,  N,  N,  N),
+	PINGROUP(gmi_ad1_pg1,            RSVD1,      NAND,       GMI,          RSVD4,       RSVD4,    0x31f4,  N,  N,  N),
+	PINGROUP(gmi_ad2_pg2,            RSVD1,      NAND,       GMI,          RSVD4,       RSVD4,    0x31f8,  N,  N,  N),
+	PINGROUP(gmi_ad3_pg3,            RSVD1,      NAND,       GMI,          RSVD4,       RSVD4,    0x31fc,  N,  N,  N),
+	PINGROUP(gmi_ad4_pg4,            RSVD1,      NAND,       GMI,          RSVD4,       RSVD4,    0x3200,  N,  N,  N),
+	PINGROUP(gmi_ad5_pg5,            RSVD1,      NAND,       GMI,          SPI4,        RSVD1,    0x3204,  N,  N,  N),
+	PINGROUP(gmi_ad6_pg6,            RSVD1,      NAND,       GMI,          SPI4,        RSVD1,    0x3208,  N,  N,  N),
+	PINGROUP(gmi_ad7_pg7,            RSVD1,      NAND,       GMI,          SPI4,        RSVD1,    0x320c,  N,  N,  N),
+	PINGROUP(gmi_ad8_ph0,            PWM0,       NAND,       GMI,          DTV,         GMI,      0x3210,  N,  N,  N),
+	PINGROUP(gmi_ad9_ph1,            PWM1,       NAND,       GMI,          CLDVFS,      GMI,      0x3214,  N,  N,  N),
+	PINGROUP(gmi_ad10_ph2,           PWM2,       NAND,       GMI,          CLDVFS,      GMI,      0x3218,  N,  N,  N),
+	PINGROUP(gmi_ad11_ph3,           PWM3,       NAND,       GMI,          USB,         GMI,      0x321c,  N,  N,  N),
+	PINGROUP(gmi_ad12_ph4,           SDMMC2,     NAND,       GMI,          RSVD4,       RSVD4,    0x3220,  N,  N,  N),
+	PINGROUP(gmi_ad13_ph5,           SDMMC2,     NAND,       GMI,          RSVD4,       RSVD4,    0x3224,  N,  N,  N),
+	PINGROUP(gmi_ad14_ph6,           SDMMC2,     NAND,       GMI,          DTV,         GMI,      0x3228,  N,  N,  N),
+	PINGROUP(gmi_ad15_ph7,           SDMMC2,     NAND,       GMI,          DTV,         GMI,      0x322c,  N,  N,  N),
+	PINGROUP(gmi_a16_pj7,            UARTD,      TRACE,      GMI,          GMI_ALT,     GMI,      0x3230,  N,  N,  N),
+	PINGROUP(gmi_a17_pb0,            UARTD,      RSVD2,      GMI,          TRACE,       RSVD2,    0x3234,  N,  N,  N),
+	PINGROUP(gmi_a18_pb1,            UARTD,      RSVD2,      GMI,          TRACE,       RSVD2,    0x3238,  N,  N,  N),
+	PINGROUP(gmi_a19_pk7,            UARTD,      SPI4,       GMI,          TRACE,       GMI,      0x323c,  N,  N,  N),
+	PINGROUP(gmi_wr_n_pi0,           RSVD1,      NAND,       GMI,          SPI4,        RSVD1,    0x3240,  N,  N,  N),
+	PINGROUP(gmi_oe_n_pi1,           RSVD1,      NAND,       GMI,          SOC,         RSVD1,    0x3244,  N,  N,  N),
+	PINGROUP(gmi_dqs_p_pj3,          SDMMC2,     NAND,       GMI,          TRACE,       NAND,     0x3248,  N,  N,  N),
+	PINGROUP(gmi_rst_n_pi4,          NAND,       NAND_ALT,   GMI,          RSVD4,       RSVD4,    0x324c,  N,  N,  N),
+	PINGROUP(gen2_i2c_scl_pt5,       I2C2,       RSVD2,      GMI,          RSVD4,       RSVD4,    0x3250,  Y,  N,  N),
+	PINGROUP(gen2_i2c_sda_pt6,       I2C2,       RSVD2,      GMI,          RSVD4,       RSVD4,    0x3254,  Y,  N,  N),
+	PINGROUP(sdmmc4_clk_pcc4,        SDMMC4,     RSVD2,      GMI,          RSVD4,       RSVD4,    0x3258,  N,  Y,  N),
+	PINGROUP(sdmmc4_cmd_pt7,         SDMMC4,     RSVD2,      GMI,          RSVD4,       RSVD4,    0x325c,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat0_paa0,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x3260,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat1_paa1,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x3264,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat2_paa2,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x3268,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat3_paa3,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x326c,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat4_paa4,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x3270,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat5_paa5,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x3274,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat6_paa6,       SDMMC4,     SPI3,       GMI,          RSVD4,       RSVD4,    0x3278,  N,  Y,  N),
+	PINGROUP(sdmmc4_dat7_paa7,       SDMMC4,     RSVD2,      GMI,          RSVD4,       RSVD4,    0x327c,  N,  Y,  N),
+	PINGROUP(cam_mclk_pcc0,          VI,         VI_ALT1,    VI_ALT3,      RSVD4,       RSVD4,    0x3284,  N,  N,  N),
+	PINGROUP(pcc1,                   I2S4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3288,  N,  N,  N),
+	PINGROUP(pbb0,                   I2S4,       VI,         VI_ALT1,      VI_ALT3,     I2S4,     0x328c,  N,  N,  N),
+	PINGROUP(cam_i2c_scl_pbb1,       VGP1,       I2C3,       RSVD3,        RSVD4,       RSVD4,    0x3290,  Y,  N,  N),
+	PINGROUP(cam_i2c_sda_pbb2,       VGP2,       I2C3,       RSVD3,        RSVD4,       RSVD4,    0x3294,  Y,  N,  N),
+	PINGROUP(pbb3,                   VGP3,       DISPLAYA,   DISPLAYB,     RSVD4,       RSVD4,    0x3298,  N,  N,  N),
+	PINGROUP(pbb4,                   VGP4,       DISPLAYA,   DISPLAYB,     RSVD4,       RSVD4,    0x329c,  N,  N,  N),
+	PINGROUP(pbb5,                   VGP5,       DISPLAYA,   DISPLAYB,     RSVD4,       RSVD4,    0x32a0,  N,  N,  N),
+	PINGROUP(pbb6,                   VGP6,       DISPLAYA,   DISPLAYB,     RSVD4,       RSVD4,    0x32a4,  N,  N,  N),
+	PINGROUP(pbb7,                   I2S4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32a8,  N,  N,  N),
+	PINGROUP(pcc2,                   I2S4,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32ac,  N,  N,  N),
+	PINGROUP(pwr_i2c_scl_pz6,        I2CPWR,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32b4,  Y,  N,  N),
+	PINGROUP(pwr_i2c_sda_pz7,        I2CPWR,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32b8,  Y,  N,  N),
+	PINGROUP(kb_row0_pr0,            KBC,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32bc,  N,  N,  N),
+	PINGROUP(kb_row1_pr1,            KBC,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32c0,  N,  N,  N),
+	PINGROUP(kb_row2_pr2,            KBC,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x32c4,  N,  N,  N),
+	PINGROUP(kb_row3_pr3,            KBC,        DISPLAYA,   RSVD3,        DISPLAYB,    RSVD3,    0x32c8,  N,  N,  N),
+	PINGROUP(kb_row4_pr4,            KBC,        DISPLAYA,   SPI2,         DISPLAYB,    KBC,      0x32cc,  N,  N,  N),
+	PINGROUP(kb_row5_pr5,            KBC,        DISPLAYA,   SPI2,         DISPLAYB,    KBC,      0x32d0,  N,  N,  N),
+	PINGROUP(kb_row6_pr6,            KBC,        DISPLAYA,   DISPLAYA_ALT, DISPLAYB,    KBC,      0x32d4,  N,  N,  N),
+	PINGROUP(kb_row7_pr7,            KBC,        RSVD2,      CLDVFS,       UARTA,       RSVD2,    0x32d8,  N,  N,  N),
+	PINGROUP(kb_row8_ps0,            KBC,        RSVD2,      CLDVFS,       UARTA,       RSVD2,    0x32dc,  N,  N,  N),
+	PINGROUP(kb_row9_ps1,            KBC,        RSVD2,      RSVD3,        UARTA,       RSVD3,    0x32e0,  N,  N,  N),
+	PINGROUP(kb_row10_ps2,           KBC,        RSVD2,      RSVD3,        UARTA,       RSVD3,    0x32e4,  N,  N,  N),
+	PINGROUP(kb_col0_pq0,            KBC,        USB,        SPI2,         EMC_DLL,     KBC,      0x32fc,  N,  N,  N),
+	PINGROUP(kb_col1_pq1,            KBC,        RSVD2,      SPI2,         EMC_DLL,     RSVD2,    0x3300,  N,  N,  N),
+	PINGROUP(kb_col2_pq2,            KBC,        RSVD2,      SPI2,         RSVD4,       RSVD2,    0x3304,  N,  N,  N),
+	PINGROUP(kb_col3_pq3,            KBC,        DISPLAYA,   PWM2,         UARTA,       KBC,      0x3308,  N,  N,  N),
+	PINGROUP(kb_col4_pq4,            KBC,        OWR,        SDMMC3,       UARTA,       KBC,      0x330c,  N,  N,  N),
+	PINGROUP(kb_col5_pq5,            KBC,        RSVD2,      SDMMC1,       RSVD4,       RSVD4,    0x3310,  N,  N,  N),
+	PINGROUP(kb_col6_pq6,            KBC,        RSVD2,      SPI2,         RSVD4,       RSVD4,    0x3314,  N,  N,  N),
+	PINGROUP(kb_col7_pq7,            KBC,        RSVD2,      SPI2,         RSVD4,       RSVD4,    0x3318,  N,  N,  N),
+	PINGROUP(clk_32k_out_pa0,        BLINK,      SOC,        RSVD3,        RSVD4,       RSVD4,    0x331c,  N,  N,  N),
+	PINGROUP(sys_clk_req_pz5,        SYSCLK,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3320,  N,  N,  N),
+	PINGROUP(core_pwr_req,           PWRON,      RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3324,  N,  N,  N),
+	PINGROUP(cpu_pwr_req,            CPU,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3328,  N,  N,  N),
+	PINGROUP(pwr_int_n,              PMI,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x332c,  N,  N,  N),
+	PINGROUP(owr,                    OWR,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3334,  N,  N,  Y),
+	PINGROUP(dap1_fs_pn0,            I2S0,       HDA,        GMI,          RSVD4,       RSVD4,    0x3338,  N,  N,  N),
+	PINGROUP(dap1_din_pn1,           I2S0,       HDA,        GMI,          RSVD4,       RSVD4,    0x333c,  N,  N,  N),
+	PINGROUP(dap1_dout_pn2,          I2S0,       HDA,        GMI,          RSVD4,       RSVD4,    0x3340,  N,  N,  N),
+	PINGROUP(dap1_sclk_pn3,          I2S0,       HDA,        GMI,          RSVD4,       RSVD4,    0x3344,  N,  N,  N),
+	PINGROUP(clk1_req_pee2,          DAP,        DAP1,       RSVD3,        RSVD4,       RSVD4,    0x3348,  N,  N,  N),
+	PINGROUP(clk1_out_pw4,           EXTPERIPH1, DAP2,       RSVD3,        RSVD4,       RSVD4,    0x334c,  N,  N,  N),
+	PINGROUP(spdif_in_pk6,           SPDIF,      USB,        RSVD3,        RSVD4,       RSVD4,    0x3350,  N,  N,  N),
+	PINGROUP(spdif_out_pk5,          SPDIF,      RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3354,  N,  N,  N),
+	PINGROUP(dap2_fs_pa2,            I2S1,       HDA,        RSVD3,        RSVD4,       RSVD4,    0x3358,  N,  N,  N),
+	PINGROUP(dap2_din_pa4,           I2S1,       HDA,        RSVD3,        RSVD4,       RSVD4,    0x335c,  N,  N,  N),
+	PINGROUP(dap2_dout_pa5,          I2S1,       HDA,        RSVD3,        RSVD4,       RSVD4,    0x3360,  N,  N,  N),
+	PINGROUP(dap2_sclk_pa3,          I2S1,       HDA,        RSVD3,        RSVD4,       RSVD4,    0x3364,  N,  N,  N),
+	PINGROUP(dvfs_pwm_px0,           SPI6,       CLDVFS,     RSVD3,        RSVD4,       RSVD4,    0x3368,  N,  N,  N),
+	PINGROUP(gpio_x1_aud_px1,        SPI6,       RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x336c,  N,  N,  N),
+	PINGROUP(gpio_x3_aud_px3,        SPI6,       SPI1,       RSVD3,        RSVD4,       RSVD4,    0x3370,  N,  N,  N),
+	PINGROUP(dvfs_clk_px2,           SPI6,       CLDVFS,     RSVD3,        RSVD4,       RSVD4,    0x3374,  N,  N,  N),
+	PINGROUP(gpio_x4_aud_px4,        RSVD1,      SPI1,       SPI2,         DAP2,        RSVD1,    0x3378,  N,  N,  N),
+	PINGROUP(gpio_x5_aud_px5,        RSVD1,      SPI1,       SPI2,         RSVD4,       RSVD1,    0x337c,  N,  N,  N),
+	PINGROUP(gpio_x6_aud_px6,        SPI6,       SPI1,       SPI2,         RSVD4,       RSVD4,    0x3380,  N,  N,  N),
+	PINGROUP(gpio_x7_aud_px7,        RSVD1,      SPI1,       SPI2,         RSVD4,       RSVD4,    0x3384,  N,  N,  N),
+	PINGROUP(sdmmc3_clk_pa6,         SDMMC3,     RSVD2,      RSVD3,        SPI3,        RSVD3,    0x3390,  N,  N,  N),
+	PINGROUP(sdmmc3_cmd_pa7,         SDMMC3,     PWM3,       UARTA,        SPI3,        SDMMC3,   0x3394,  N,  N,  N),
+	PINGROUP(sdmmc3_dat0_pb7,        SDMMC3,     RSVD2,      RSVD3,        SPI3,        RSVD3,    0x3398,  N,  N,  N),
+	PINGROUP(sdmmc3_dat1_pb6,        SDMMC3,     PWM2,       UARTA,        SPI3,        SDMMC3,   0x339c,  N,  N,  N),
+	PINGROUP(sdmmc3_dat2_pb5,        SDMMC3,     PWM1,       DISPLAYA,     SPI3,        SDMMC3,   0x33a0,  N,  N,  N),
+	PINGROUP(sdmmc3_dat3_pb4,        SDMMC3,     PWM0,       DISPLAYB,     SPI3,        SDMMC3,   0x33a4,  N,  N,  N),
+	PINGROUP(hdmi_cec_pee3,          CEC,        SDMMC3,     RSVD3,        SOC,         RSVD3,    0x33e0,  Y,  N,  N),
+	PINGROUP(sdmmc1_wp_n_pv3,        SDMMC1,     CLK12,      SPI4,         UARTA,       SDMMC1,   0x33e4,  N,  N,  N),
+	PINGROUP(sdmmc3_cd_n_pv2,        SDMMC3,     OWR,        RSVD3,        RSVD4,       RSVD4,    0x33e8,  N,  N,  N),
+	PINGROUP(gpio_w2_aud_pw2,        SPI6,       RSVD2,      SPI2,         I2C1,        RSVD2,    0x33ec,  N,  N,  N),
+	PINGROUP(gpio_w3_aud_pw3,        SPI6,       SPI1,       SPI2,         I2C1,        SPI6,     0x33f0,  N,  N,  N),
+	PINGROUP(usb_vbus_en0_pn4,       USB,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x33f4,  Y,  N,  N),
+	PINGROUP(usb_vbus_en1_pn5,       USB,        RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x33f8,  Y,  N,  N),
+	PINGROUP(sdmmc3_clk_lb_in_pee5,  SDMMC3,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x33fc,  N,  N,  N),
+	PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3,     RSVD2,      RSVD3,        RSVD4,       RSVD4,    0x3400,  N,  N,  N),
+	PINGROUP(reset_out_n,            RSVD1,      RSVD2,      RSVD3,        RESET_OUT_N, RSVD3,    0x3408,  N,  N,  N),
+
+	/* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */
+	DRV_PINGROUP(ao1,   0x868,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(ao2,   0x86c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(at1,   0x870,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+	DRV_PINGROUP(at2,   0x874,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+	DRV_PINGROUP(at3,   0x878,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+	DRV_PINGROUP(at4,   0x87c,  2,  3,  4,  12,  7,  20,  7,  28,  2,  30,  2,  Y),
+	DRV_PINGROUP(at5,   0x880,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(cdev1, 0x884,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(cdev2, 0x888,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(dap1,  0x890,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(dap2,  0x894,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(dap3,  0x898,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(dap4,  0x89c,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(dbg,   0x8a0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(sdio3, 0x8b0,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(spi,   0x8b4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(uaa,   0x8b8,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(uab,   0x8bc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(uart2, 0x8c0,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(uart3, 0x8c4,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(sdio1, 0x8ec,  2,  3, -1,  12,  7,  20,  7,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(ddc,   0x8fc,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(gma,   0x900,  2,  3,  4,  14,  5,  20,  5,  28,  2,  30,  2,  Y),
+	DRV_PINGROUP(gme,   0x910,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(gmf,   0x914,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(gmg,   0x918,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(gmh,   0x91c,  2,  3,  4,  14,  5,  19,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(owr,   0x920,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+	DRV_PINGROUP(uda,   0x924,  2,  3,  4,  12,  5,  20,  5,  28,  2,  30,  2,  N),
+};
+
+static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
+	.ngpios = NUM_GPIOS,
+	.pins = tegra114_pins,
+	.npins = ARRAY_SIZE(tegra114_pins),
+	.functions = tegra114_functions,
+	.nfunctions = ARRAY_SIZE(tegra114_functions),
+	.groups = tegra114_groups,
+	.ngroups = ARRAY_SIZE(tegra114_groups),
+};
+
+static int tegra114_pinctrl_probe(struct platform_device *pdev)
+{
+	return tegra_pinctrl_probe(pdev, &tegra114_pinctrl);
+}
+
+static struct of_device_id tegra114_pinctrl_of_match[] = {
+	{ .compatible = "nvidia,tegra114-pinmux", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra114_pinctrl_of_match);
+
+static struct platform_driver tegra114_pinctrl_driver = {
+	.driver = {
+		.name = "tegra114-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = tegra114_pinctrl_of_match,
+	},
+	.probe = tegra114_pinctrl_probe,
+	.remove = tegra_pinctrl_remove,
+};
+module_platform_driver(tegra114_pinctrl_driver);
+
+MODULE_ALIAS("platform:tegra114-pinctrl");
+MODULE_AUTHOR("Pritesh Raithatha <praithatha@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra114 pincontrol driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index e848189..fcfb7d0 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -2624,7 +2624,9 @@
 		.odrain_reg = -1,				\
 		.lock_reg = -1,					\
 		.ioreset_reg = -1,				\
+		.rcv_sel_reg = -1,				\
 		.drv_reg = -1,					\
+		.drvtype_reg = -1,				\
 	}
 
 /* Pin groups with only pull up and pull down control */
@@ -2642,7 +2644,9 @@
 		.odrain_reg = -1,				\
 		.lock_reg = -1,					\
 		.ioreset_reg = -1,				\
+		.rcv_sel_reg = -1,				\
 		.drv_reg = -1,					\
+		.drvtype_reg = -1,				\
 	}
 
 /* Pin groups for drive strength registers (configurable version) */
@@ -2660,6 +2664,7 @@
 		.odrain_reg = -1,				\
 		.lock_reg = -1,					\
 		.ioreset_reg = -1,				\
+		.rcv_sel_reg = -1,				\
 		.drv_reg = ((r) - PINGROUP_REG_A),		\
 		.drv_bank = 3,					\
 		.hsm_bit = hsm_b,				\
@@ -2673,6 +2678,7 @@
 		.slwr_width = slwr_w,				\
 		.slwf_bit = slwf_b,				\
 		.slwf_width = slwf_w,				\
+		.drvtype_reg = -1,				\
 	}
 
 /* Pin groups for drive strength registers (simple version) */
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 9ad87ea..2300deb 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -3384,7 +3384,9 @@
 		.ioreset_reg = PINGROUP_REG_##ior(r),		\
 		.ioreset_bank = 1,				\
 		.ioreset_bit = 8,				\
+		.rcv_sel_reg = -1,				\
 		.drv_reg = -1,					\
+		.drvtype_reg = -1,				\
 	}
 
 #define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b,	\
@@ -3401,6 +3403,7 @@
 		.odrain_reg = -1,				\
 		.lock_reg = -1,					\
 		.ioreset_reg = -1,				\
+		.rcv_sel_reg = -1,				\
 		.drv_reg = ((r) - DRV_PINGROUP_REG_A),		\
 		.drv_bank = 0,					\
 		.hsm_bit = hsm_b,				\
@@ -3414,6 +3417,7 @@
 		.slwr_width = slwr_w,				\
 		.slwf_bit = slwf_b,				\
 		.slwf_width = slwf_w,				\
+		.drvtype_reg = -1,				\
 	}
 
 static const struct tegra_pingroup tegra30_groups[] = {
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index 5f0eb04..53cb6a3 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -441,17 +441,17 @@
 		if (port == PORT3)
 			reg = GPIO3_OD;
 		else
-			reg = GPIO_OD(port);
+			reg = GPIO_OD(pin);
 		*config = LTQ_PINCONF_PACK(param,
-			!!gpio_getbit(info->membase[0], reg, PORT_PIN(port)));
+			!gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
 		break;
 
 	case LTQ_PINCONF_PARAM_PULL:
 		if (port == PORT3)
 			reg = GPIO3_PUDEN;
 		else
-			reg = GPIO_PUDEN(port);
-		if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port))) {
+			reg = GPIO_PUDEN(pin);
+		if (!gpio_getbit(info->membase[0], reg, PORT_PIN(pin))) {
 			*config = LTQ_PINCONF_PACK(param, 0);
 			break;
 		}
@@ -459,13 +459,18 @@
 		if (port == PORT3)
 			reg = GPIO3_PUDSEL;
 		else
-			reg = GPIO_PUDSEL(port);
-		if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port)))
+			reg = GPIO_PUDSEL(pin);
+		if (!gpio_getbit(info->membase[0], reg, PORT_PIN(pin)))
 			*config = LTQ_PINCONF_PACK(param, 2);
 		else
 			*config = LTQ_PINCONF_PACK(param, 1);
 		break;
 
+	case LTQ_PINCONF_PARAM_OUTPUT:
+		reg = GPIO_DIR(pin);
+		*config = LTQ_PINCONF_PACK(param,
+			gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
+		break;
 	default:
 		dev_err(pctldev->dev, "Invalid config param %04x\n", param);
 		return -ENOTSUPP;
@@ -488,33 +493,44 @@
 		if (port == PORT3)
 			reg = GPIO3_OD;
 		else
-			reg = GPIO_OD(port);
-		gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+			reg = GPIO_OD(pin);
+		if (arg == 0)
+			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+		else
+			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
 		break;
 
 	case LTQ_PINCONF_PARAM_PULL:
 		if (port == PORT3)
 			reg = GPIO3_PUDEN;
 		else
-			reg = GPIO_PUDEN(port);
+			reg = GPIO_PUDEN(pin);
 		if (arg == 0) {
-			gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
+			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
 			break;
 		}
-		gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+		gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
 
 		if (port == PORT3)
 			reg = GPIO3_PUDSEL;
 		else
-			reg = GPIO_PUDSEL(port);
+			reg = GPIO_PUDSEL(pin);
 		if (arg == 1)
-			gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
+			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
 		else if (arg == 2)
-			gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
 		else
 			dev_err(pctldev->dev, "Invalid pull value %d\n", arg);
 		break;
 
+	case LTQ_PINCONF_PARAM_OUTPUT:
+		reg = GPIO_DIR(pin);
+		if (arg == 0)
+			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
+		else
+			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+		break;
+
 	default:
 		dev_err(pctldev->dev, "Invalid config param %04x\n", param);
 		return -ENOTSUPP;
@@ -522,9 +538,24 @@
 	return 0;
 }
 
+int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
+			unsigned selector,
+			unsigned long config)
+{
+	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+	int i, ret = 0;
+
+	for (i = 0; i < info->grps[selector].npins && !ret; i++)
+		ret = xway_pinconf_set(pctldev,
+				info->grps[selector].pins[i], config);
+
+	return ret;
+}
+
 static struct pinconf_ops xway_pinconf_ops = {
 	.pin_config_get	= xway_pinconf_get,
 	.pin_config_set	= xway_pinconf_set,
+	.pin_config_group_set = xway_pinconf_group_set,
 };
 
 static struct pinctrl_desc xway_pctrl_desc = {
@@ -558,6 +589,7 @@
 static const struct ltq_cfg_param xway_cfg_params[] = {
 	{"lantiq,pull",		LTQ_PINCONF_PARAM_PULL},
 	{"lantiq,open-drain",	LTQ_PINCONF_PARAM_OPEN_DRAIN},
+	{"lantiq,output",	LTQ_PINCONF_PARAM_OUTPUT},
 };
 
 static struct ltq_pinmux_info xway_info = {
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index fcde4e5..d9f9a0d 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1910,7 +1910,7 @@
 	return result;
 }
 
-static int asus_acpi_remove(struct acpi_device *device, int type)
+static int asus_acpi_remove(struct acpi_device *device)
 {
 	struct asus_laptop *asus = acpi_driver_data(device);
 
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index c87ff16..36e5e6c 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -432,7 +432,7 @@
 	return error;
 }
 
-static int cmpc_accel_remove_v4(struct acpi_device *acpi, int type)
+static int cmpc_accel_remove_v4(struct acpi_device *acpi)
 {
 	struct input_dev *inputdev;
 	struct cmpc_accel *accel;
@@ -668,7 +668,7 @@
 	return error;
 }
 
-static int cmpc_accel_remove(struct acpi_device *acpi, int type)
+static int cmpc_accel_remove(struct acpi_device *acpi)
 {
 	struct input_dev *inputdev;
 	struct cmpc_accel *accel;
@@ -753,7 +753,7 @@
 					   cmpc_tablet_idev_init);
 }
 
-static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
+static int cmpc_tablet_remove(struct acpi_device *acpi)
 {
 	return cmpc_remove_acpi_notify_device(acpi);
 }
@@ -1000,7 +1000,7 @@
 	return retval;
 }
 
-static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
+static int cmpc_ipml_remove(struct acpi_device *acpi)
 {
 	struct ipml200_dev *ipml;
 
@@ -1079,7 +1079,7 @@
 					   cmpc_keys_idev_init);
 }
 
-static int cmpc_keys_remove(struct acpi_device *acpi, int type)
+static int cmpc_keys_remove(struct acpi_device *acpi)
 {
 	return cmpc_remove_acpi_notify_device(acpi);
 }
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 528e949..5d26e70 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1007,7 +1007,7 @@
 
 static void eeepc_set_fan_pwm(int value)
 {
-	value = SENSORS_LIMIT(value, 0, 255);
+	value = clamp_val(value, 0, 255);
 	value = value * 100 / 255;
 	ec_write(EEEPC_EC_FAN_PWM, value);
 }
@@ -1501,7 +1501,7 @@
 	return result;
 }
 
-static int eeepc_acpi_remove(struct acpi_device *device, int type)
+static int eeepc_acpi_remove(struct acpi_device *device)
 {
 	struct eeepc_laptop *eeepc = acpi_driver_data(device);
 
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index c4c1a54..1c9386e 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -733,7 +733,7 @@
 	return result;
 }
 
-static int acpi_fujitsu_remove(struct acpi_device *device, int type)
+static int acpi_fujitsu_remove(struct acpi_device *device)
 {
 	struct fujitsu_t *fujitsu = acpi_driver_data(device);
 	struct input_dev *input = fujitsu->input;
@@ -938,7 +938,7 @@
 	return result;
 }
 
-static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
+static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
 {
 	struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
 	struct input_dev *input = fujitsu_hotkey->input;
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 174ca01..570926c 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -431,7 +431,7 @@
 	return 0;
 }
 
-static int acpi_fujitsu_remove(struct acpi_device *adev, int type)
+static int acpi_fujitsu_remove(struct acpi_device *adev)
 {
 	free_irq(fujitsu.irq, fujitsu_interrupt);
 	release_region(fujitsu.io_base, fujitsu.io_length);
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 18d74f2..e64a7a8 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -337,7 +337,7 @@
 	return ret;
 }
 
-static int lis3lv02d_remove(struct acpi_device *device, int type)
+static int lis3lv02d_remove(struct acpi_device *device)
 {
 	if (!device)
 		return -EINVAL;
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 64bfb30..17f00b8 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -834,7 +834,7 @@
 	return ret;
 }
 
-static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
+static int ideapad_acpi_remove(struct acpi_device *adevice)
 {
 	struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
 	int i;
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 3271ac8..d6cfc15 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -200,7 +200,7 @@
 
 }
 
-static int intel_menlow_memory_remove(struct acpi_device *device, int type)
+static int intel_menlow_memory_remove(struct acpi_device *device)
 {
 	struct thermal_cooling_device *cdev = acpi_driver_data(device);
 
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 8e8caa7..4add9a3 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -176,7 +176,7 @@
 /* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
 
 static int acpi_pcc_hotkey_add(struct acpi_device *device);
-static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
+static int acpi_pcc_hotkey_remove(struct acpi_device *device);
 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id pcc_device_ids[] = {
@@ -663,7 +663,7 @@
 	return 0;
 }
 
-static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
+static int acpi_pcc_hotkey_remove(struct acpi_device *device)
 {
 	struct pcc_acpi *pcc = acpi_driver_data(device);
 
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index b8ad71f..ceb41ef 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -2740,7 +2740,7 @@
 	return result;
 }
 
-static int sony_nc_remove(struct acpi_device *device, int type)
+static int sony_nc_remove(struct acpi_device *device)
 {
 	struct sony_nc_value *item;
 
@@ -4111,7 +4111,7 @@
  *  ACPI driver
  *
  *****************/
-static int sony_pic_remove(struct acpi_device *device, int type)
+static int sony_pic_remove(struct acpi_device *device)
 {
 	struct sony_pic_ioport *io, *tmp_io;
 	struct sony_pic_irq *irq, *tmp_irq;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index f946ca7..ebcb461 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -4877,8 +4877,7 @@
 static void light_exit(void)
 {
 	led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
-	if (work_pending(&tpacpi_led_thinklight.work))
-		flush_workqueue(tpacpi_wq);
+	flush_workqueue(tpacpi_wq);
 }
 
 static int light_read(struct seq_file *m)
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index d727bfe..4ab618c 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -157,7 +157,7 @@
 	return -ENODEV;
 }
 
-static int acpi_topstar_remove(struct acpi_device *device, int type)
+static int acpi_topstar_remove(struct acpi_device *device)
 {
 	struct topstar_hkey *tps_hkey = acpi_driver_data(device);
 
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index c272789..904476b 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -1118,7 +1118,7 @@
 	return 0;
 }
 
-static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
+static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
 {
 	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
 
@@ -1250,7 +1250,7 @@
 	return 0;
 
 error:
-	toshiba_acpi_remove(acpi_dev, 0);
+	toshiba_acpi_remove(acpi_dev);
 	return ret;
 }
 
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index e95be0b..74dd01a 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -32,7 +32,7 @@
 
 
 static int toshiba_bt_rfkill_add(struct acpi_device *device);
-static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
+static int toshiba_bt_rfkill_remove(struct acpi_device *device);
 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id bt_device_ids[] = {
@@ -122,7 +122,7 @@
 	return result;
 }
 
-static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type)
+static int toshiba_bt_rfkill_remove(struct acpi_device *device)
 {
 	/* clean up */
 	return 0;
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 42a4dcc..e4ac38a 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -92,7 +92,7 @@
 MODULE_PARM_DESC(debug_dump_wdg,
 		 "Dump available WMI interfaces [0/1]");
 
-static int acpi_wmi_remove(struct acpi_device *device, int type);
+static int acpi_wmi_remove(struct acpi_device *device);
 static int acpi_wmi_add(struct acpi_device *device);
 static void acpi_wmi_notify(struct acpi_device *device, u32 event);
 
@@ -917,7 +917,7 @@
 	}
 }
 
-static int acpi_wmi_remove(struct acpi_device *device, int type)
+static int acpi_wmi_remove(struct acpi_device *device)
 {
 	acpi_remove_address_space_handler(device->handle,
 				ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
index 16d340c..4b1377b 100644
--- a/drivers/platform/x86/xo15-ebook.c
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -150,7 +150,7 @@
 	return error;
 }
 
-static int ebook_switch_remove(struct acpi_device *device, int type)
+static int ebook_switch_remove(struct acpi_device *device)
 {
 	struct ebook_switch *button = acpi_driver_data(device);
 
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 72e822e..8813fc0 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -90,7 +90,7 @@
 	pnp_dbg(&dev->dev, "set resources\n");
 
 	handle = DEVICE_ACPI_HANDLE(&dev->dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+	if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
 		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 		return -ENODEV;
 	}
@@ -123,7 +123,7 @@
 	dev_dbg(&dev->dev, "disable resources\n");
 
 	handle = DEVICE_ACPI_HANDLE(&dev->dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+	if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
 		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 		return 0;
 	}
@@ -145,7 +145,7 @@
 	acpi_handle handle;
 
 	handle = DEVICE_ACPI_HANDLE(&dev->dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+	if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
 		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 		return false;
 	}
@@ -160,7 +160,7 @@
 	int error = 0;
 
 	handle = DEVICE_ACPI_HANDLE(&dev->dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+	if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
 		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 		return 0;
 	}
@@ -197,7 +197,7 @@
 	acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
 	int error = 0;
 
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+	if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
 		dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
 		return -ENODEV;
 	}
diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig
index b986d9f..50c3dd0 100644
--- a/drivers/pnp/pnpbios/Kconfig
+++ b/drivers/pnp/pnpbios/Kconfig
@@ -2,8 +2,8 @@
 # Plug and Play BIOS configuration
 #
 config PNPBIOS
-	bool "Plug and Play BIOS support (EXPERIMENTAL)"
-	depends on ISA && X86 && EXPERIMENTAL
+	bool "Plug and Play BIOS support"
+	depends on ISA && X86
 	default n
 	---help---
 	  Linux uses the PNPBIOS as defined in "Plug and Play BIOS
diff --git a/drivers/power/88pm860x_battery.c b/drivers/power/88pm860x_battery.c
index 8bc80b0..d338c1c 100644
--- a/drivers/power/88pm860x_battery.c
+++ b/drivers/power/88pm860x_battery.c
@@ -915,15 +915,13 @@
 	info->irq_cc = platform_get_irq(pdev, 0);
 	if (info->irq_cc <= 0) {
 		dev_err(&pdev->dev, "No IRQ resource!\n");
-		ret = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	info->irq_batt = platform_get_irq(pdev, 1);
 	if (info->irq_batt <= 0) {
 		dev_err(&pdev->dev, "No IRQ resource!\n");
-		ret = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	info->chip = chip;
@@ -957,7 +955,7 @@
 
 	ret = power_supply_register(&pdev->dev, &info->battery);
 	if (ret)
-		goto out;
+		return ret;
 	info->battery.dev->parent = &pdev->dev;
 
 	ret = request_threaded_irq(info->irq_cc, NULL,
@@ -984,8 +982,6 @@
 	free_irq(info->irq_cc, info);
 out_reg:
 	power_supply_unregister(&info->battery);
-out:
-	kfree(info);
 	return ret;
 }
 
@@ -993,10 +989,9 @@
 {
 	struct pm860x_battery_info *info = platform_get_drvdata(pdev);
 
-	power_supply_unregister(&info->battery);
 	free_irq(info->irq_batt, info);
 	free_irq(info->irq_cc, info);
-	kfree(info);
+	power_supply_unregister(&info->battery);
 	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 9f45e2f..9e00c38 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -346,6 +346,20 @@
 	help
 	  Say Y to include support for AB8500 battery management.
 
+config BATTERY_GOLDFISH
+	tristate "Goldfish battery driver"
+	depends on GENERIC_HARDIRQS
+	help
+	  Say Y to enable support for the battery and AC power in the
+	  Goldfish emulator.
+
+config CHARGER_PM2301
+	bool "PM2301 Battery Charger Driver"
+	depends on AB8500_BM
+	help
+	  Say Y to include support for PM2301 charger driver.
+	  Depends on AB8500 battery management core.
+
 source "drivers/power/reset/Kconfig"
 
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 22c8913..3f66436 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_BATTERY_DS2780)	+= ds2780_battery.o
 obj-$(CONFIG_BATTERY_DS2781)	+= ds2781_battery.o
 obj-$(CONFIG_BATTERY_DS2782)	+= ds2782_battery.o
+obj-$(CONFIG_BATTERY_GOLDFISH)	+= goldfish_battery.o
 obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)	+= tosa_battery.o
@@ -38,7 +39,7 @@
 obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)	+= intel_mid_battery.o
 obj-$(CONFIG_BATTERY_RX51)	+= rx51_battery.o
-obj-$(CONFIG_AB8500_BM)		+= ab8500_bmdata.o ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
+obj-$(CONFIG_AB8500_BM)		+= ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
 obj-$(CONFIG_CHARGER_ISP1704)	+= isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)	+= max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)	+= twl4030_charger.o
@@ -46,6 +47,7 @@
 obj-$(CONFIG_CHARGER_LP8788)	+= lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO)	+= gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)	+= charger-manager.o
+obj-$(CONFIG_CHARGER_PM2301)	+= pm2301_charger.o
 obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
index f034ae4..7a96c06 100644
--- a/drivers/power/ab8500_bmdata.c
+++ b/drivers/power/ab8500_bmdata.c
@@ -182,206 +182,206 @@
 };
 
 static struct abx500_battery_type bat_type_thermistor[] = {
-[BATTERY_UNKNOWN] = {
-	/* First element always represent the UNKNOWN battery */
-	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
-	.resis_high = 0,
-	.resis_low = 0,
-	.battery_resistance = 300,
-	.charge_full_design = 612,
-	.nominal_voltage = 3700,
-	.termination_vol = 4050,
-	.termination_curr = 200,
-	.recharge_vol = 3990,
-	.normal_cur_lvl = 400,
-	.normal_vol_lvl = 4100,
-	.maint_a_cur_lvl = 400,
-	.maint_a_vol_lvl = 4050,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 400,
-	.maint_b_vol_lvl = 4000,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
-	.r_to_t_tbl = temp_tbl,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
-	.v_to_cap_tbl = cap_tbl,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
-	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
-	.resis_high = 53407,
-	.resis_low = 12500,
-	.battery_resistance = 300,
-	.charge_full_design = 900,
-	.nominal_voltage = 3600,
-	.termination_vol = 4150,
-	.termination_curr = 80,
-	.recharge_vol = 4130,
-	.normal_cur_lvl = 700,
-	.normal_vol_lvl = 4200,
-	.maint_a_cur_lvl = 600,
-	.maint_a_vol_lvl = 4150,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 600,
-	.maint_b_vol_lvl = 4100,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
-	.r_to_t_tbl = temp_tbl_A_thermistor,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
-	.v_to_cap_tbl = cap_tbl_A_thermistor,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
+	[BATTERY_UNKNOWN] = {
+		/* First element always represent the UNKNOWN battery */
+		.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+		.resis_high = 0,
+		.resis_low = 0,
+		.battery_resistance = 300,
+		.charge_full_design = 612,
+		.nominal_voltage = 3700,
+		.termination_vol = 4050,
+		.termination_curr = 200,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 400,
+		.normal_vol_lvl = 4100,
+		.maint_a_cur_lvl = 400,
+		.maint_a_vol_lvl = 4050,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 400,
+		.maint_b_vol_lvl = 4000,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+		.r_to_t_tbl = temp_tbl,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+		.v_to_cap_tbl = cap_tbl,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
+	},
+	{
+		.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+		.resis_high = 53407,
+		.resis_low = 12500,
+		.battery_resistance = 300,
+		.charge_full_design = 900,
+		.nominal_voltage = 3600,
+		.termination_vol = 4150,
+		.termination_curr = 80,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 700,
+		.normal_vol_lvl = 4200,
+		.maint_a_cur_lvl = 600,
+		.maint_a_vol_lvl = 4150,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 600,
+		.maint_b_vol_lvl = 4100,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
+		.r_to_t_tbl = temp_tbl_A_thermistor,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
+		.v_to_cap_tbl = cap_tbl_A_thermistor,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
 
-},
-{
-	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
-	.resis_high = 200000,
-	.resis_low = 82869,
-	.battery_resistance = 300,
-	.charge_full_design = 900,
-	.nominal_voltage = 3600,
-	.termination_vol = 4150,
-	.termination_curr = 80,
-	.recharge_vol = 4130,
-	.normal_cur_lvl = 700,
-	.normal_vol_lvl = 4200,
-	.maint_a_cur_lvl = 600,
-	.maint_a_vol_lvl = 4150,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 600,
-	.maint_b_vol_lvl = 4100,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
-	.r_to_t_tbl = temp_tbl_B_thermistor,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
-	.v_to_cap_tbl = cap_tbl_B_thermistor,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
-},
+	},
+	{
+		.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+		.resis_high = 200000,
+		.resis_low = 82869,
+		.battery_resistance = 300,
+		.charge_full_design = 900,
+		.nominal_voltage = 3600,
+		.termination_vol = 4150,
+		.termination_curr = 80,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 700,
+		.normal_vol_lvl = 4200,
+		.maint_a_cur_lvl = 600,
+		.maint_a_vol_lvl = 4150,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 600,
+		.maint_b_vol_lvl = 4100,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
+		.r_to_t_tbl = temp_tbl_B_thermistor,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
+		.v_to_cap_tbl = cap_tbl_B_thermistor,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
+	},
 };
 
 static struct abx500_battery_type bat_type_ext_thermistor[] = {
-[BATTERY_UNKNOWN] = {
-	/* First element always represent the UNKNOWN battery */
-	.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
-	.resis_high = 0,
-	.resis_low = 0,
-	.battery_resistance = 300,
-	.charge_full_design = 612,
-	.nominal_voltage = 3700,
-	.termination_vol = 4050,
-	.termination_curr = 200,
-	.recharge_vol = 3990,
-	.normal_cur_lvl = 400,
-	.normal_vol_lvl = 4100,
-	.maint_a_cur_lvl = 400,
-	.maint_a_vol_lvl = 4050,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 400,
-	.maint_b_vol_lvl = 4000,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
-	.r_to_t_tbl = temp_tbl,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
-	.v_to_cap_tbl = cap_tbl,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
-},
+	[BATTERY_UNKNOWN] = {
+		/* First element always represent the UNKNOWN battery */
+		.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+		.resis_high = 0,
+		.resis_low = 0,
+		.battery_resistance = 300,
+		.charge_full_design = 612,
+		.nominal_voltage = 3700,
+		.termination_vol = 4050,
+		.termination_curr = 200,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 400,
+		.normal_vol_lvl = 4100,
+		.maint_a_cur_lvl = 400,
+		.maint_a_vol_lvl = 4050,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 400,
+		.maint_b_vol_lvl = 4000,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+		.r_to_t_tbl = temp_tbl,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+		.v_to_cap_tbl = cap_tbl,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
+	},
 /*
  * These are the batteries that doesn't have an internal NTC resistor to measure
  * its temperature. The temperature in this case is measure with a NTC placed
  * near the battery but on the PCB.
  */
-{
-	.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
-	.resis_high = 76000,
-	.resis_low = 53000,
-	.battery_resistance = 300,
-	.charge_full_design = 900,
-	.nominal_voltage = 3700,
-	.termination_vol = 4150,
-	.termination_curr = 100,
-	.recharge_vol = 4130,
-	.normal_cur_lvl = 700,
-	.normal_vol_lvl = 4200,
-	.maint_a_cur_lvl = 600,
-	.maint_a_vol_lvl = 4150,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 600,
-	.maint_b_vol_lvl = 4100,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
-	.r_to_t_tbl = temp_tbl,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
-	.v_to_cap_tbl = cap_tbl,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
-	.name = POWER_SUPPLY_TECHNOLOGY_LION,
-	.resis_high = 30000,
-	.resis_low = 10000,
-	.battery_resistance = 300,
-	.charge_full_design = 950,
-	.nominal_voltage = 3700,
-	.termination_vol = 4150,
-	.termination_curr = 100,
-	.recharge_vol = 4130,
-	.normal_cur_lvl = 700,
-	.normal_vol_lvl = 4200,
-	.maint_a_cur_lvl = 600,
-	.maint_a_vol_lvl = 4150,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 600,
-	.maint_b_vol_lvl = 4100,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
-	.r_to_t_tbl = temp_tbl,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
-	.v_to_cap_tbl = cap_tbl,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
-	.name = POWER_SUPPLY_TECHNOLOGY_LION,
-	.resis_high = 95000,
-	.resis_low = 76001,
-	.battery_resistance = 300,
-	.charge_full_design = 950,
-	.nominal_voltage = 3700,
-	.termination_vol = 4150,
-	.termination_curr = 100,
-	.recharge_vol = 4130,
-	.normal_cur_lvl = 700,
-	.normal_vol_lvl = 4200,
-	.maint_a_cur_lvl = 600,
-	.maint_a_vol_lvl = 4150,
-	.maint_a_chg_timer_h = 60,
-	.maint_b_cur_lvl = 600,
-	.maint_b_vol_lvl = 4100,
-	.maint_b_chg_timer_h = 200,
-	.low_high_cur_lvl = 300,
-	.low_high_vol_lvl = 4000,
-	.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
-	.r_to_t_tbl = temp_tbl,
-	.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
-	.v_to_cap_tbl = cap_tbl,
-	.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
-	.batres_tbl = temp_to_batres_tbl_thermistor,
-},
+	{
+		.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+		.resis_high = 76000,
+		.resis_low = 53000,
+		.battery_resistance = 300,
+		.charge_full_design = 900,
+		.nominal_voltage = 3700,
+		.termination_vol = 4150,
+		.termination_curr = 100,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 700,
+		.normal_vol_lvl = 4200,
+		.maint_a_cur_lvl = 600,
+		.maint_a_vol_lvl = 4150,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 600,
+		.maint_b_vol_lvl = 4100,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+		.r_to_t_tbl = temp_tbl,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+		.v_to_cap_tbl = cap_tbl,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
+	},
+	{
+		.name = POWER_SUPPLY_TECHNOLOGY_LION,
+		.resis_high = 30000,
+		.resis_low = 10000,
+		.battery_resistance = 300,
+		.charge_full_design = 950,
+		.nominal_voltage = 3700,
+		.termination_vol = 4150,
+		.termination_curr = 100,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 700,
+		.normal_vol_lvl = 4200,
+		.maint_a_cur_lvl = 600,
+		.maint_a_vol_lvl = 4150,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 600,
+		.maint_b_vol_lvl = 4100,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+		.r_to_t_tbl = temp_tbl,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+		.v_to_cap_tbl = cap_tbl,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
+	},
+	{
+		.name = POWER_SUPPLY_TECHNOLOGY_LION,
+		.resis_high = 95000,
+		.resis_low = 76001,
+		.battery_resistance = 300,
+		.charge_full_design = 950,
+		.nominal_voltage = 3700,
+		.termination_vol = 4150,
+		.termination_curr = 100,
+		.recharge_cap = 95,
+		.normal_cur_lvl = 700,
+		.normal_vol_lvl = 4200,
+		.maint_a_cur_lvl = 600,
+		.maint_a_vol_lvl = 4150,
+		.maint_a_chg_timer_h = 60,
+		.maint_b_cur_lvl = 600,
+		.maint_b_vol_lvl = 4100,
+		.maint_b_chg_timer_h = 200,
+		.low_high_cur_lvl = 300,
+		.low_high_vol_lvl = 4000,
+		.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+		.r_to_t_tbl = temp_tbl,
+		.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+		.v_to_cap_tbl = cap_tbl,
+		.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+		.batres_tbl = temp_to_batres_tbl_thermistor,
+	},
 };
 
 static const struct abx500_bm_capacity_levels cap_levels = {
@@ -405,8 +405,8 @@
 	.lowbat_threshold = 3100,
 	.battok_falling_th_sel0 = 2860,
 	.battok_raising_th_sel1 = 2860,
+	.maint_thres = 95,
 	.user_cap_limit = 15,
-	.maint_thres = 97,
 };
 
 static const struct abx500_maxim_parameters maxi_params = {
@@ -424,96 +424,84 @@
 };
 
 struct abx500_bm_data ab8500_bm_data = {
-	.temp_under		= 3,
-	.temp_low		= 8,
-	.temp_high		= 43,
-	.temp_over		= 48,
-	.main_safety_tmr_h	= 4,
-	.temp_interval_chg	= 20,
-	.temp_interval_nochg	= 120,
-	.usb_safety_tmr_h	= 4,
-	.bkup_bat_v		= BUP_VCH_SEL_2P6V,
-	.bkup_bat_i		= BUP_ICH_SEL_150UA,
-	.no_maintenance		= false,
-	.adc_therm		= ABx500_ADC_THERM_BATCTRL,
-	.chg_unknown_bat	= false,
-	.enable_overshoot	= false,
-	.fg_res			= 100,
-	.cap_levels		= &cap_levels,
-	.bat_type		= bat_type_thermistor,
-	.n_btypes		= 3,
-	.batt_id		= 0,
-	.interval_charging	= 5,
-	.interval_not_charging	= 120,
-	.temp_hysteresis	= 3,
-	.gnd_lift_resistance	= 34,
-	.maxi			= &maxi_params,
-	.chg_params		= &chg,
-	.fg_params		= &fg,
+	.temp_under             = 3,
+	.temp_low               = 8,
+	.temp_high              = 43,
+	.temp_over              = 48,
+	.main_safety_tmr_h      = 4,
+	.temp_interval_chg      = 20,
+	.temp_interval_nochg    = 120,
+	.usb_safety_tmr_h       = 4,
+	.bkup_bat_v             = BUP_VCH_SEL_2P6V,
+	.bkup_bat_i             = BUP_ICH_SEL_150UA,
+	.no_maintenance         = false,
+	.capacity_scaling       = false,
+	.adc_therm              = ABx500_ADC_THERM_BATCTRL,
+	.chg_unknown_bat        = false,
+	.enable_overshoot       = false,
+	.fg_res                 = 100,
+	.cap_levels             = &cap_levels,
+	.bat_type               = bat_type_thermistor,
+	.n_btypes               = 3,
+	.batt_id                = 0,
+	.interval_charging      = 5,
+	.interval_not_charging  = 120,
+	.temp_hysteresis        = 3,
+	.gnd_lift_resistance    = 34,
+	.maxi                   = &maxi_params,
+	.chg_params             = &chg,
+	.fg_params              = &fg,
 };
 
-int bmdevs_of_probe(struct device *dev, struct device_node *np,
-		    struct abx500_bm_data **battery)
+int ab8500_bm_of_probe(struct device *dev,
+		       struct device_node *np,
+		       struct abx500_bm_data *bm)
 {
-	struct	abx500_battery_type *btype;
-	struct  device_node *np_bat_supply;
-	struct	abx500_bm_data *bat;
+	struct batres_vs_temp *tmp_batres_tbl;
+	struct device_node *battery_node;
 	const char *btech;
-	char bat_tech[8];
-	int i, thermistor;
-
-	*battery = &ab8500_bm_data;
+	int i;
 
 	/* get phandle to 'battery-info' node */
-	np_bat_supply = of_parse_phandle(np, "battery", 0);
-	if (!np_bat_supply) {
-		dev_err(dev, "missing property battery\n");
+	battery_node = of_parse_phandle(np, "battery", 0);
+	if (!battery_node) {
+		dev_err(dev, "battery node or reference missing\n");
 		return -EINVAL;
 	}
-	if (of_property_read_bool(np_bat_supply,
-			"thermistor-on-batctrl"))
-		thermistor = NTC_INTERNAL;
-	else
-		thermistor = NTC_EXTERNAL;
 
-	bat = *battery;
-	if (thermistor == NTC_EXTERNAL) {
-		bat->n_btypes  = 4;
-		bat->bat_type  = bat_type_ext_thermistor;
-		bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
-	}
-	btech = of_get_property(np_bat_supply,
-		"stericsson,battery-type", NULL);
+	btech = of_get_property(battery_node, "stericsson,battery-type", NULL);
 	if (!btech) {
 		dev_warn(dev, "missing property battery-name/type\n");
-		strcpy(bat_tech, "UNKNOWN");
-	} else {
-		strcpy(bat_tech, btech);
+		return -EINVAL;
 	}
 
-	if (strncmp(bat_tech, "LION", 4) == 0) {
-		bat->no_maintenance  = true;
-		bat->chg_unknown_bat = true;
-		bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
-		bat->bat_type[BATTERY_UNKNOWN].termination_vol    = 4150;
-		bat->bat_type[BATTERY_UNKNOWN].recharge_vol	  = 4130;
-		bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl	  = 520;
-		bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl	  = 4200;
+	if (strncmp(btech, "LION", 4) == 0) {
+		bm->no_maintenance  = true;
+		bm->chg_unknown_bat = true;
+		bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
+		bm->bat_type[BATTERY_UNKNOWN].termination_vol    = 4150;
+		bm->bat_type[BATTERY_UNKNOWN].recharge_cap       = 95;
+		bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl     = 520;
+		bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl     = 4200;
 	}
+
+	if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) {
+		if (strncmp(btech, "LION", 4) == 0)
+			tmp_batres_tbl = temp_to_batres_tbl_9100;
+		else
+			tmp_batres_tbl = temp_to_batres_tbl_thermistor;
+	} else {
+		bm->n_btypes   = 4;
+		bm->bat_type   = bat_type_ext_thermistor;
+		bm->adc_therm  = ABx500_ADC_THERM_BATTEMP;
+		tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor;
+	}
+
 	/* select the battery resolution table */
-	for (i = 0; i < bat->n_btypes; ++i) {
-		btype = (bat->bat_type + i);
-		if (thermistor == NTC_EXTERNAL) {
-			btype->batres_tbl =
-				temp_to_batres_tbl_ext_thermistor;
-		} else if (strncmp(bat_tech, "LION", 4) == 0) {
-			btype->batres_tbl =
-				temp_to_batres_tbl_9100;
-		} else {
-			btype->batres_tbl =
-				temp_to_batres_tbl_thermistor;
-		}
-	}
-	of_node_put(np_bat_supply);
+	for (i = 0; i < bm->n_btypes; ++i)
+		bm->bat_type[i].batres_tbl = tmp_batres_tbl;
+
+	of_node_put(battery_node);
+
 	return 0;
 }
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 20e2a7d..0768906 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -39,6 +39,9 @@
 #define BTEMP_BATCTRL_CURR_SRC_7UA	7
 #define BTEMP_BATCTRL_CURR_SRC_20UA	20
 
+#define BTEMP_BATCTRL_CURR_SRC_16UA	16
+#define BTEMP_BATCTRL_CURR_SRC_18UA	18
+
 #define to_ab8500_btemp_device_info(x) container_of((x), \
 	struct ab8500_btemp, btemp_psy);
 
@@ -78,12 +81,13 @@
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
  * @fg:			Pointer to the struct fg
- * @bat:		Pointer to the abx500_bm platform data
+ * @bm:           	Platform specific battery management information
  * @btemp_psy:		Structure for BTEMP specific battery properties
  * @events:		Structure for information about events triggered
  * @btemp_ranges:	Battery temperature range structure
  * @btemp_wq:		Work queue for measuring the temperature periodically
  * @btemp_periodic_work:	Work for measuring the temperature periodically
+ * @initialized:	True if battery id read.
  */
 struct ab8500_btemp {
 	struct device *dev;
@@ -94,12 +98,13 @@
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
 	struct ab8500_fg *fg;
-	struct abx500_bm_data *bat;
+	struct abx500_bm_data *bm;
 	struct power_supply btemp_psy;
 	struct ab8500_btemp_events events;
 	struct ab8500_btemp_ranges btemp_ranges;
 	struct workqueue_struct *btemp_wq;
 	struct delayed_work btemp_periodic_work;
+	bool initialized;
 };
 
 /* BTEMP power supply properties */
@@ -147,13 +152,13 @@
 		return (450000 * (v_batctrl)) / (1800 - v_batctrl);
 	}
 
-	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL) {
+	if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) {
 		/*
 		 * If the battery has internal NTC, we use the current
 		 * source to calculate the resistance, 7uA or 20uA
 		 */
 		rbs = (v_batctrl * 1000
-		       - di->bat->gnd_lift_resistance * inst_curr)
+		       - di->bm->gnd_lift_resistance * inst_curr)
 		      / di->curr_source;
 	} else {
 		/*
@@ -209,11 +214,19 @@
 		return 0;
 
 	/* Only do this for batteries with internal NTC */
-	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
-		if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
-			curr = BAT_CTRL_7U_ENA;
-		else
-			curr = BAT_CTRL_20U_ENA;
+	if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
+
+		if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+			if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_16UA)
+				curr = BAT_CTRL_16U_ENA;
+			else
+				curr = BAT_CTRL_18U_ENA;
+		} else {
+			if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
+				curr = BAT_CTRL_7U_ENA;
+			else
+				curr = BAT_CTRL_20U_ENA;
+		}
 
 		dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source);
 
@@ -241,14 +254,25 @@
 				__func__);
 			goto disable_curr_source;
 		}
-	} else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
+	} else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
 		dev_dbg(di->dev, "Disable BATCTRL curr source\n");
 
-		/* Write 0 to the curr bits */
-		ret = abx500_mask_and_set_register_interruptible(di->dev,
-			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
-			BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
-			~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+		if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+			/* Write 0 to the curr bits */
+			ret = abx500_mask_and_set_register_interruptible(
+				di->dev,
+				AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+				BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA,
+				~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA));
+		} else {
+			/* Write 0 to the curr bits */
+			ret = abx500_mask_and_set_register_interruptible(
+				di->dev,
+				AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+				BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
+				~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+		}
+
 		if (ret) {
 			dev_err(di->dev, "%s failed disabling current source\n",
 				__func__);
@@ -290,11 +314,20 @@
 	 * if we got an error above
 	 */
 disable_curr_source:
-	/* Write 0 to the curr bits */
-	ret = abx500_mask_and_set_register_interruptible(di->dev,
+	if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+		/* Write 0 to the curr bits */
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+			BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA,
+			~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA));
+	} else {
+		/* Write 0 to the curr bits */
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
 			AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
 			BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
 			~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+	}
+
 	if (ret) {
 		dev_err(di->dev, "%s failed disabling current source\n",
 			__func__);
@@ -372,13 +405,10 @@
 		return ret;
 	}
 
-	/*
-	 * Since there is no interrupt when current measurement is done,
-	 * loop for over 250ms (250ms is one sample conversion time
-	 * with 32.768 Khz RTC clock). Note that a stop time must be set
-	 * since the ab8500_btemp_read_batctrl_voltage call can block and
-	 * take an unknown amount of time to complete.
-	 */
+	do {
+		msleep(20);
+	} while (!ab8500_fg_inst_curr_started(di->fg));
+
 	i = 0;
 
 	do {
@@ -457,9 +487,9 @@
 	int rbat, rntc, vntc;
 	u8 id;
 
-	id = di->bat->batt_id;
+	id = di->bm->batt_id;
 
-	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL &&
+	if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
 			id != BATTERY_UNKNOWN) {
 
 		rbat = ab8500_btemp_get_batctrl_res(di);
@@ -474,8 +504,8 @@
 		}
 
 		temp = ab8500_btemp_res_to_temp(di,
-			di->bat->bat_type[id].r_to_t_tbl,
-			di->bat->bat_type[id].n_temp_tbl_elements, rbat);
+			di->bm->bat_type[id].r_to_t_tbl,
+			di->bm->bat_type[id].n_temp_tbl_elements, rbat);
 	} else {
 		vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL);
 		if (vntc < 0) {
@@ -491,8 +521,8 @@
 		rntc = 230000 * vntc / (VTVOUT_V - vntc);
 
 		temp = ab8500_btemp_res_to_temp(di,
-			di->bat->bat_type[id].r_to_t_tbl,
-			di->bat->bat_type[id].n_temp_tbl_elements, rntc);
+			di->bm->bat_type[id].r_to_t_tbl,
+			di->bm->bat_type[id].n_temp_tbl_elements, rntc);
 		prev = temp;
 	}
 	dev_dbg(di->dev, "Battery temperature is %d\n", temp);
@@ -511,9 +541,12 @@
 {
 	int res;
 	u8 i;
+	if (is_ab9540(di->parent) || is_ab8505(di->parent))
+		di->curr_source = BTEMP_BATCTRL_CURR_SRC_16UA;
+	else
+		di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
 
-	di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
-	di->bat->batt_id = BATTERY_UNKNOWN;
+	di->bm->batt_id = BATTERY_UNKNOWN;
 
 	res =  ab8500_btemp_get_batctrl_res(di);
 	if (res < 0) {
@@ -522,23 +555,23 @@
 	}
 
 	/* BATTERY_UNKNOWN is defined on position 0, skip it! */
-	for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) {
-		if ((res <= di->bat->bat_type[i].resis_high) &&
-			(res >= di->bat->bat_type[i].resis_low)) {
+	for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) {
+		if ((res <= di->bm->bat_type[i].resis_high) &&
+			(res >= di->bm->bat_type[i].resis_low)) {
 			dev_dbg(di->dev, "Battery detected on %s"
 				" low %d < res %d < high: %d"
 				" index: %d\n",
-				di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL ?
+				di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ?
 				"BATCTRL" : "BATTEMP",
-				di->bat->bat_type[i].resis_low, res,
-				di->bat->bat_type[i].resis_high, i);
+				di->bm->bat_type[i].resis_low, res,
+				di->bm->bat_type[i].resis_high, i);
 
-			di->bat->batt_id = i;
+			di->bm->batt_id = i;
 			break;
 		}
 	}
 
-	if (di->bat->batt_id == BATTERY_UNKNOWN) {
+	if (di->bm->batt_id == BATTERY_UNKNOWN) {
 		dev_warn(di->dev, "Battery identified as unknown"
 			", resistance %d Ohm\n", res);
 		return -ENXIO;
@@ -548,13 +581,18 @@
 	 * We only have to change current source if the
 	 * detected type is Type 1, else we use the 7uA source
 	 */
-	if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL &&
-			di->bat->batt_id == 1) {
-		dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
-		di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
+	if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
+			di->bm->batt_id == 1) {
+		if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+			dev_dbg(di->dev, "Set BATCTRL current source to 16uA\n");
+			di->curr_source = BTEMP_BATCTRL_CURR_SRC_16UA;
+		} else {
+			dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
+			di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
+		}
 	}
 
-	return di->bat->batt_id;
+	return di->bm->batt_id;
 }
 
 /**
@@ -569,6 +607,13 @@
 	struct ab8500_btemp *di = container_of(work,
 		struct ab8500_btemp, btemp_periodic_work.work);
 
+	if (!di->initialized) {
+		di->initialized = true;
+		/* Identify the battery */
+		if (ab8500_btemp_id(di) < 0)
+			dev_warn(di->dev, "failed to identify the battery\n");
+	}
+
 	di->bat_temp = ab8500_btemp_measure_temp(di);
 
 	if (di->bat_temp != di->prev_bat_temp) {
@@ -577,9 +622,9 @@
 	}
 
 	if (di->events.ac_conn || di->events.usb_conn)
-		interval = di->bat->temp_interval_chg;
+		interval = di->bm->temp_interval_chg;
 	else
-		interval = di->bat->temp_interval_nochg;
+		interval = di->bm->temp_interval_nochg;
 
 	/* Schedule a new measurement */
 	queue_delayed_work(di->btemp_wq,
@@ -616,9 +661,9 @@
 {
 	struct ab8500_btemp *di = _di;
 
-	if (is_ab8500_2p0_or_earlier(di->parent)) {
+	if (is_ab8500_3p3_or_earlier(di->parent)) {
 		dev_dbg(di->dev, "Ignore false btemp low irq"
-			" for ABB cut 1.0, 1.1 and 2.0\n");
+			" for ABB cut 1.0, 1.1, 2.0 and 3.3\n");
 	} else {
 		dev_crit(di->dev, "Battery temperature lower than -10deg c\n");
 
@@ -732,30 +777,30 @@
 	int temp = 0;
 
 	/*
-	 * The BTEMP events are not reliabe on AB8500 cut2.0
+	 * The BTEMP events are not reliabe on AB8500 cut3.3
 	 * and prior versions
 	 */
-	if (is_ab8500_2p0_or_earlier(di->parent)) {
+	if (is_ab8500_3p3_or_earlier(di->parent)) {
 		temp = di->bat_temp * 10;
 	} else {
 		if (di->events.btemp_low) {
 			if (temp > di->btemp_ranges.btemp_low_limit)
-				temp = di->btemp_ranges.btemp_low_limit;
+				temp = di->btemp_ranges.btemp_low_limit * 10;
 			else
 				temp = di->bat_temp * 10;
 		} else if (di->events.btemp_high) {
 			if (temp < di->btemp_ranges.btemp_high_limit)
-				temp = di->btemp_ranges.btemp_high_limit;
+				temp = di->btemp_ranges.btemp_high_limit * 10;
 			else
 				temp = di->bat_temp * 10;
 		} else if (di->events.btemp_lowmed) {
 			if (temp > di->btemp_ranges.btemp_med_limit)
-				temp = di->btemp_ranges.btemp_med_limit;
+				temp = di->btemp_ranges.btemp_med_limit * 10;
 			else
 				temp = di->bat_temp * 10;
 		} else if (di->events.btemp_medhigh) {
 			if (temp < di->btemp_ranges.btemp_med_limit)
-				temp = di->btemp_ranges.btemp_med_limit;
+				temp = di->btemp_ranges.btemp_med_limit * 10;
 			else
 				temp = di->bat_temp * 10;
 		} else
@@ -806,7 +851,7 @@
 			val->intval = 1;
 		break;
 	case POWER_SUPPLY_PROP_TECHNOLOGY:
-		val->intval = di->bat->bat_type[di->bat->batt_id].name;
+		val->intval = di->bm->bat_type[di->bm->batt_id].name;
 		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		val->intval = ab8500_btemp_get_temp(di);
@@ -967,6 +1012,7 @@
 static int ab8500_btemp_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct abx500_bm_data *plat = pdev->dev.platform_data;
 	struct ab8500_btemp *di;
 	int irq, i, ret = 0;
 	u8 val;
@@ -976,21 +1022,19 @@
 		dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
 		return -ENOMEM;
 	}
-	di->bat = pdev->mfd_cell->platform_data;
-	if (!di->bat) {
-		if (np) {
-			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
-			if (ret) {
-				dev_err(&pdev->dev,
-					"failed to get battery information\n");
-				return ret;
-			}
-		} else {
-			dev_err(&pdev->dev, "missing dt node for ab8500_btemp\n");
-			return -EINVAL;
+
+	if (!plat) {
+		dev_err(&pdev->dev, "no battery management data supplied\n");
+		return -EINVAL;
+	}
+	di->bm = plat;
+
+	if (np) {
+		ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get battery information\n");
+			return ret;
 		}
-	} else {
-		dev_info(&pdev->dev, "falling back to legacy platform data\n");
 	}
 
 	/* get parent data */
@@ -998,6 +1042,8 @@
 	di->parent = dev_get_drvdata(pdev->dev.parent);
 	di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
+	di->initialized = false;
+
 	/* BTEMP supply */
 	di->btemp_psy.name = "ab8500_btemp";
 	di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
@@ -1022,10 +1068,6 @@
 	INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
 		ab8500_btemp_periodic_work);
 
-	/* Identify the battery */
-	if (ab8500_btemp_id(di) < 0)
-		dev_warn(di->dev, "failed to identify the battery\n");
-
 	/* Set BTEMP thermal limits. Low and Med are fixed */
 	di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
 	di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
@@ -1123,7 +1165,7 @@
 	platform_driver_unregister(&ab8500_btemp_driver);
 }
 
-subsys_initcall_sync(ab8500_btemp_init);
+device_initcall(ab8500_btemp_init);
 module_exit(ab8500_btemp_exit);
 
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 3be9c0e..24b30b7 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -31,6 +31,7 @@
 #include <linux/mfd/abx500/ab8500-gpadc.h>
 #include <linux/mfd/abx500/ux500_chargalg.h>
 #include <linux/usb/otg.h>
+#include <linux/mutex.h>
 
 /* Charger constants */
 #define NO_PW_CONN			0
@@ -54,6 +55,7 @@
 
 #define MAIN_CH_INPUT_CURR_SHIFT	4
 #define VBUS_IN_CURR_LIM_SHIFT		4
+#define AUTO_VBUS_IN_CURR_LIM_SHIFT	4
 
 #define LED_INDICATOR_PWM_ENA		0x01
 #define LED_INDICATOR_PWM_DIS		0x00
@@ -68,6 +70,11 @@
 #define MAIN_CH_NOK			0x01
 #define VBUS_DET			0x80
 
+#define MAIN_CH_STATUS2_MAINCHGDROP		0x80
+#define MAIN_CH_STATUS2_MAINCHARGERDETDBNC	0x40
+#define USB_CH_VBUSDROP				0x40
+#define USB_CH_VBUSDETDBNC			0x01
+
 /* UsbLineStatus register bit masks */
 #define AB8500_USB_LINK_STATUS		0x78
 #define AB8500_STD_HOST_SUSP		0x18
@@ -79,6 +86,17 @@
 /* Lowest charger voltage is 3.39V -> 0x4E */
 #define LOW_VOLT_REG			0x4E
 
+/* Step up/down delay in us */
+#define STEP_UDELAY			1000
+
+#define CHARGER_STATUS_POLL 10 /* in ms */
+
+#define CHG_WD_INTERVAL			(60 * HZ)
+
+#define AB8500_SW_CONTROL_FALLBACK	0x03
+/* Wait for enumeration before charing in us */
+#define WAIT_ACA_RID_ENUMERATION	(5 * 1000)
+
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
 	USB_STAT_NOT_CONFIGURED,
@@ -97,6 +115,13 @@
 	USB_STAT_HM_IDGND,
 	USB_STAT_RESERVED,
 	USB_STAT_NOT_VALID_LINK,
+	USB_STAT_PHY_EN,
+	USB_STAT_SUP_NO_IDGND_VBUS,
+	USB_STAT_SUP_IDGND_VBUS,
+	USB_STAT_CHARGER_LINE_1,
+	USB_STAT_CARKIT_1,
+	USB_STAT_CARKIT_2,
+	USB_STAT_ACA_DOCK_CHARGER,
 };
 
 enum ab8500_usb_state {
@@ -149,6 +174,7 @@
 	int charger_voltage;
 	int cv_active;
 	bool wd_expired;
+	int charger_current;
 };
 
 struct ab8500_charger_event_flags {
@@ -159,12 +185,14 @@
 	bool usbchargernotok;
 	bool chgwdexp;
 	bool vbus_collapse;
+	bool vbus_drop_end;
 };
 
 struct ab8500_charger_usb_state {
-	bool usb_changed;
 	int usb_current;
+	int usb_current_tmp;
 	enum ab8500_usb_state state;
+	enum ab8500_usb_state state_tmp;
 	spinlock_t usb_lock;
 };
 
@@ -182,11 +210,17 @@
  *			charger is enabled
  * @vbat		Battery voltage
  * @old_vbat		Previously measured battery voltage
+ * @usb_device_is_unrecognised	USB device is unrecognised by the hardware
  * @autopower		Indicate if we should have automatic pwron after pwrloss
  * @autopower_cfg	platform specific power config support for "pwron after pwrloss"
+ * @invalid_charger_detect_state State when forcing AB to use invalid charger
+ * @is_usb_host:	Indicate if last detected USB type is host
+ * @is_aca_rid:		Incicate if accessory is ACA type
+ * @current_stepping_sessions:
+ *			Counter for current stepping sessions
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
- * @bat:		Pointer to the abx500_bm platform data
+ * @bm:           	Platform specific battery management information
  * @flags:		Structure for information about events triggered
  * @usb_state:		Structure for usb stack information
  * @ac_chg:		AC charger power supply
@@ -195,19 +229,28 @@
  * @usb:		Structure that holds the USB charger properties
  * @regu:		Pointer to the struct regulator
  * @charger_wq:		Work queue for the IRQs and checking HW state
+ * @usb_ipt_crnt_lock:	Lock to protect VBUS input current setting from mutuals
+ * @pm_lock:		Lock to prevent system to suspend
  * @check_vbat_work	Work for checking vbat threshold to adjust vbus current
  * @check_hw_failure_work:	Work for checking HW state
  * @check_usbchgnotok_work:	Work for checking USB charger not ok status
  * @kick_wd_work:		Work for kicking the charger watchdog in case
  *				of ABB rev 1.* due to the watchog logic bug
+ * @ac_charger_attached_work:	Work for checking if AC charger is still
+ *				connected
+ * @usb_charger_attached_work:	Work for checking if USB charger is still
+ *				connected
  * @ac_work:			Work for checking AC charger connection
  * @detect_usb_type_work:	Work for detecting the USB type connected
  * @usb_link_status_work:	Work for checking the new USB link status
  * @usb_state_changed_work:	Work for checking USB state
+ * @attach_work:		Work for detecting USB type
+ * @vbus_drop_end_work:		Work for detecting VBUS drop end
  * @check_main_thermal_prot_work:
  *				Work for checking Main thermal status
  * @check_usb_thermal_prot_work:
  *				Work for checking USB thermal status
+ * @charger_attached_mutex:	For controlling the wakelock
  */
 struct ab8500_charger {
 	struct device *dev;
@@ -219,11 +262,16 @@
 	bool vddadc_en_usb;
 	int vbat;
 	int old_vbat;
+	bool usb_device_is_unrecognised;
 	bool autopower;
 	bool autopower_cfg;
+	int invalid_charger_detect_state;
+	bool is_usb_host;
+	int is_aca_rid;
+	atomic_t current_stepping_sessions;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_bm_data *bat;
+	struct abx500_bm_data *bm;
 	struct ab8500_charger_event_flags flags;
 	struct ab8500_charger_usb_state usb_state;
 	struct ux500_charger ac_chg;
@@ -232,18 +280,24 @@
 	struct ab8500_charger_info usb;
 	struct regulator *regu;
 	struct workqueue_struct *charger_wq;
+	struct mutex usb_ipt_crnt_lock;
 	struct delayed_work check_vbat_work;
 	struct delayed_work check_hw_failure_work;
 	struct delayed_work check_usbchgnotok_work;
 	struct delayed_work kick_wd_work;
+	struct delayed_work usb_state_changed_work;
+	struct delayed_work attach_work;
+	struct delayed_work ac_charger_attached_work;
+	struct delayed_work usb_charger_attached_work;
+	struct delayed_work vbus_drop_end_work;
 	struct work_struct ac_work;
 	struct work_struct detect_usb_type_work;
 	struct work_struct usb_link_status_work;
-	struct work_struct usb_state_changed_work;
 	struct work_struct check_main_thermal_prot_work;
 	struct work_struct check_usb_thermal_prot_work;
 	struct usb_phy *usb_phy;
 	struct notifier_block nb;
+	struct mutex charger_attached_mutex;
 };
 
 /* AC properties */
@@ -267,50 +321,65 @@
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 };
 
-/**
- * ab8500_power_loss_handling - set how we handle powerloss.
- * @di:		pointer to the ab8500_charger structure
- *
- * Magic nummbers are from STE HW department.
+/*
+ * Function for enabling and disabling sw fallback mode
+ * should always be disabled when no charger is connected.
  */
-static void ab8500_power_loss_handling(struct ab8500_charger *di)
+static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di,
+		bool fallback)
 {
+	u8 val;
 	u8 reg;
+	u8 bank;
+	u8 bit;
 	int ret;
 
-	dev_dbg(di->dev, "Autopower : %d\n", di->autopower);
+	dev_dbg(di->dev, "SW Fallback: %d\n", fallback);
 
-	/* read the autopower register */
-	ret = abx500_get_register_interruptible(di->dev, 0x15, 0x00, &reg);
-	if (ret) {
-		dev_err(di->dev, "%d write failed\n", __LINE__);
+	if (is_ab8500(di->parent)) {
+		bank = 0x15;
+		reg = 0x0;
+		bit = 3;
+	} else {
+		bank = AB8500_SYS_CTRL1_BLOCK;
+		reg = AB8500_SW_CONTROL_FALLBACK;
+		bit = 0;
+	}
+
+	/* read the register containing fallback bit */
+	ret = abx500_get_register_interruptible(di->dev, bank, reg, &val);
+	if (ret < 0) {
+		dev_err(di->dev, "%d read failed\n", __LINE__);
 		return;
 	}
 
-	/* enable the OPT emulation registers */
-	ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
-	if (ret) {
-		dev_err(di->dev, "%d write failed\n", __LINE__);
-		return;
+	if (is_ab8500(di->parent)) {
+		/* enable the OPT emulation registers */
+		ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
+		if (ret) {
+			dev_err(di->dev, "%d write failed\n", __LINE__);
+			goto disable_otp;
+		}
 	}
 
-	if (di->autopower)
-		reg |= 0x8;
+	if (fallback)
+		val |= (1 << bit);
 	else
-		reg &= ~0x8;
+		val &= ~(1 << bit);
 
-	/* write back the changed value to autopower reg */
-	ret = abx500_set_register_interruptible(di->dev, 0x15, 0x00, reg);
+	/* write back the changed fallback bit value to register */
+	ret = abx500_set_register_interruptible(di->dev, bank, reg, val);
 	if (ret) {
 		dev_err(di->dev, "%d write failed\n", __LINE__);
-		return;
 	}
 
-	/* disable the set OTP registers again */
-	ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
-	if (ret) {
-		dev_err(di->dev, "%d write failed\n", __LINE__);
-		return;
+disable_otp:
+	if (is_ab8500(di->parent)) {
+		/* disable the set OTP registers again */
+		ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
+		if (ret) {
+			dev_err(di->dev, "%d write failed\n", __LINE__);
+		}
 	}
 }
 
@@ -329,12 +398,12 @@
 		    !di->ac.charger_connected &&
 		    di->autopower) {
 			di->autopower = false;
-			ab8500_power_loss_handling(di);
+			ab8500_enable_disable_sw_fallback(di, false);
 		} else if (!di->autopower &&
 			   (di->ac.charger_connected ||
 			    di->usb.charger_connected)) {
 			di->autopower = true;
-			ab8500_power_loss_handling(di);
+			ab8500_enable_disable_sw_fallback(di, true);
 		}
 	}
 	power_supply_changed(psy);
@@ -347,6 +416,19 @@
 		dev_dbg(di->dev, "USB connected:%i\n", connected);
 		di->usb.charger_connected = connected;
 		sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present");
+
+		if (connected) {
+			mutex_lock(&di->charger_attached_mutex);
+			mutex_unlock(&di->charger_attached_mutex);
+
+			queue_delayed_work(di->charger_wq,
+					   &di->usb_charger_attached_work,
+					   HZ);
+		} else {
+			cancel_delayed_work_sync(&di->usb_charger_attached_work);
+			mutex_lock(&di->charger_attached_mutex);
+			mutex_unlock(&di->charger_attached_mutex);
+		}
 	}
 }
 
@@ -500,6 +582,7 @@
 /**
  * ab8500_charger_detect_chargers() - Detect the connected chargers
  * @di:		pointer to the ab8500_charger structure
+ * @probe:	if probe, don't delay and wait for HW
  *
  * Returns the type of charger connected.
  * For USB it will not mean we can actually charge from it
@@ -513,7 +596,7 @@
  * USB_PW_CONN  if the USB power supply is connected
  * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
  */
-static int ab8500_charger_detect_chargers(struct ab8500_charger *di)
+static int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool probe)
 {
 	int result = NO_PW_CONN;
 	int ret;
@@ -531,13 +614,25 @@
 		result = AC_PW_CONN;
 
 	/* Check for USB charger */
+
+	if (!probe) {
+		/*
+		 * AB8500 says VBUS_DET_DBNC1 & VBUS_DET_DBNC100
+		 * when disconnecting ACA even though no
+		 * charger was connected. Try waiting a little
+		 * longer than the 100 ms of VBUS_DET_DBNC100...
+		 */
+		msleep(110);
+	}
 	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
 		AB8500_CH_USBCH_STAT1_REG, &val);
 	if (ret < 0) {
 		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
 		return ret;
 	}
-
+	dev_dbg(di->dev,
+		"%s AB8500_CH_USBCH_STAT1_REG %x\n", __func__,
+		val);
 	if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100))
 		result |= USB_PW_CONN;
 
@@ -554,31 +649,53 @@
  * Returns error code in case of failure else 0 on success
  */
 static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
-	enum ab8500_charger_link_status link_status)
+		enum ab8500_charger_link_status link_status)
 {
 	int ret = 0;
 
+	di->usb_device_is_unrecognised = false;
+
+	/*
+	 * Platform only supports USB 2.0.
+	 * This means that charging current from USB source
+	 * is maximum 500 mA. Every occurence of USB_STAT_*_HOST_*
+	 * should set USB_CH_IP_CUR_LVL_0P5.
+	 */
+
 	switch (link_status) {
 	case USB_STAT_STD_HOST_NC:
 	case USB_STAT_STD_HOST_C_NS:
 	case USB_STAT_STD_HOST_C_S:
 		dev_dbg(di->dev, "USB Type - Standard host is "
 			"detected through USB driver\n");
-		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09;
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		di->is_usb_host = true;
+		di->is_aca_rid = 0;
 		break;
 	case USB_STAT_HOST_CHG_HS_CHIRP:
 		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		di->is_usb_host = true;
+		di->is_aca_rid = 0;
 		break;
 	case USB_STAT_HOST_CHG_HS:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		di->is_usb_host = true;
+		di->is_aca_rid = 0;
+		break;
 	case USB_STAT_ACA_RID_C_HS:
 		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9;
+		di->is_usb_host = false;
+		di->is_aca_rid = 0;
 		break;
 	case USB_STAT_ACA_RID_A:
 		/*
 		 * Dedicated charger level minus maximum current accessory
-		 * can consume (300mA). Closest level is 1100mA
+		 * can consume (900mA). Closest level is 500mA
 		 */
-		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P1;
+		dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n");
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		di->is_usb_host = false;
+		di->is_aca_rid = 1;
 		break;
 	case USB_STAT_ACA_RID_B:
 		/*
@@ -586,34 +703,68 @@
 		 * 100mA for potential accessory). Closest level is 1300mA
 		 */
 		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P3;
+		dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+				di->max_usb_in_curr);
+		di->is_usb_host = false;
+		di->is_aca_rid = 1;
+		break;
+	case USB_STAT_HOST_CHG_NM:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		di->is_usb_host = true;
+		di->is_aca_rid = 0;
 		break;
 	case USB_STAT_DEDICATED_CHG:
-	case USB_STAT_HOST_CHG_NM:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+		di->is_usb_host = false;
+		di->is_aca_rid = 0;
+		break;
 	case USB_STAT_ACA_RID_C_HS_CHIRP:
 	case USB_STAT_ACA_RID_C_NM:
 		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+		di->is_usb_host = false;
+		di->is_aca_rid = 1;
 		break;
-	case USB_STAT_RESERVED:
-		/*
-		 * This state is used to indicate that VBUS has dropped below
-		 * the detection level 4 times in a row. This is due to the
-		 * charger output current is set to high making the charger
-		 * voltage collapse. This have to be propagated through to
-		 * chargalg. This is done using the property
-		 * POWER_SUPPLY_PROP_CURRENT_AVG = 1
-		 */
-		di->flags.vbus_collapse = true;
-		dev_dbg(di->dev, "USB Type - USB_STAT_RESERVED "
-			"VBUS has collapsed\n");
-		ret = -1;
-		break;
-	case USB_STAT_HM_IDGND:
 	case USB_STAT_NOT_CONFIGURED:
-	case USB_STAT_NOT_VALID_LINK:
+		if (di->vbus_detected) {
+			di->usb_device_is_unrecognised = true;
+			dev_dbg(di->dev, "USB Type - Legacy charger.\n");
+			di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+			break;
+		}
+	case USB_STAT_HM_IDGND:
 		dev_err(di->dev, "USB Type - Charging not allowed\n");
 		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
 		ret = -ENXIO;
 		break;
+	case USB_STAT_RESERVED:
+		if (is_ab8500(di->parent)) {
+			di->flags.vbus_collapse = true;
+			dev_err(di->dev, "USB Type - USB_STAT_RESERVED "
+						"VBUS has collapsed\n");
+			ret = -ENXIO;
+			break;
+		}
+		if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+			dev_dbg(di->dev, "USB Type - Charging not allowed\n");
+			di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+			dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
+					link_status, di->max_usb_in_curr);
+			ret = -ENXIO;
+			break;
+		}
+		break;
+	case USB_STAT_CARKIT_1:
+	case USB_STAT_CARKIT_2:
+	case USB_STAT_ACA_DOCK_CHARGER:
+	case USB_STAT_CHARGER_LINE_1:
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+				di->max_usb_in_curr);
+	case USB_STAT_NOT_VALID_LINK:
+		dev_err(di->dev, "USB Type invalid - try charging anyway\n");
+		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+		break;
+
 	default:
 		dev_err(di->dev, "USB Type - Unknown\n");
 		di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
@@ -645,8 +796,14 @@
 		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
 		return ret;
 	}
-	ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
-		AB8500_USB_LINE_STAT_REG, &val);
+	if (is_ab8500(di->parent)) {
+		ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+				AB8500_USB_LINE_STAT_REG, &val);
+	} else {
+		if (is_ab9540(di->parent) || is_ab8505(di->parent))
+			ret = abx500_get_register_interruptible(di->dev,
+				AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
+	}
 	if (ret < 0) {
 		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
 		return ret;
@@ -682,16 +839,25 @@
 		ret = abx500_get_register_interruptible(di->dev,
 			AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG,
 			&val);
+		dev_dbg(di->dev, "%s AB8500_IT_SOURCE21_REG %x\n",
+			__func__, val);
 		if (ret < 0) {
 			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
 			return ret;
 		}
-		ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
-			AB8500_USB_LINE_STAT_REG, &val);
+
+		if (is_ab8500(di->parent))
+			ret = abx500_get_register_interruptible(di->dev,
+				AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
+		else
+			ret = abx500_get_register_interruptible(di->dev,
+				AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
 		if (ret < 0) {
 			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
 			return ret;
 		}
+		dev_dbg(di->dev, "%s AB8500_USB_LINE_STAT_REG %x\n", __func__,
+			val);
 		/*
 		 * Until the IT source register is read the UsbLineStatus
 		 * register is not updated, hence doing the same
@@ -936,6 +1102,144 @@
 }
 
 /**
+ * ab8500_charger_set_current() - set charger current
+ * @di:		pointer to the ab8500_charger structure
+ * @ich:	charger current, in mA
+ * @reg:	select what charger register to set
+ *
+ * Set charger current.
+ * There is no state machine in the AB to step up/down the charger
+ * current to avoid dips and spikes on MAIN, VBUS and VBAT when
+ * charging is started. Instead we need to implement
+ * this charger current step-up/down here.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_current(struct ab8500_charger *di,
+	int ich, int reg)
+{
+	int ret = 0;
+	int auto_curr_index, curr_index, prev_curr_index, shift_value, i;
+	u8 reg_value;
+	u32 step_udelay;
+	bool no_stepping = false;
+
+	atomic_inc(&di->current_stepping_sessions);
+
+	ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+		reg, &reg_value);
+	if (ret < 0) {
+		dev_err(di->dev, "%s read failed\n", __func__);
+		goto exit_set_current;
+	}
+
+	switch (reg) {
+	case AB8500_MCH_IPT_CURLVL_REG:
+		shift_value = MAIN_CH_INPUT_CURR_SHIFT;
+		prev_curr_index = (reg_value >> shift_value);
+		curr_index = ab8500_current_to_regval(ich);
+		step_udelay = STEP_UDELAY;
+		if (!di->ac.charger_connected)
+			no_stepping = true;
+		break;
+	case AB8500_USBCH_IPT_CRNTLVL_REG:
+		shift_value = VBUS_IN_CURR_LIM_SHIFT;
+		prev_curr_index = (reg_value >> shift_value);
+		curr_index = ab8500_vbus_in_curr_to_regval(ich);
+		step_udelay = STEP_UDELAY * 100;
+
+		ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+					AB8500_CH_USBCH_STAT2_REG, &reg_value);
+		if (ret < 0) {
+			dev_err(di->dev, "%s read failed\n", __func__);
+			goto exit_set_current;
+		}
+		auto_curr_index =
+			reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT;
+
+		dev_dbg(di->dev, "%s Auto VBUS curr is %d mA\n",
+			__func__,
+			ab8500_charger_vbus_in_curr_map[auto_curr_index]);
+
+		prev_curr_index = min(prev_curr_index, auto_curr_index);
+
+		if (!di->usb.charger_connected)
+			no_stepping = true;
+		break;
+	case AB8500_CH_OPT_CRNTLVL_REG:
+		shift_value = 0;
+		prev_curr_index = (reg_value >> shift_value);
+		curr_index = ab8500_current_to_regval(ich);
+		step_udelay = STEP_UDELAY;
+		if (curr_index && (curr_index - prev_curr_index) > 1)
+			step_udelay *= 100;
+
+		if (!di->usb.charger_connected && !di->ac.charger_connected)
+			no_stepping = true;
+
+		break;
+	default:
+		dev_err(di->dev, "%s current register not valid\n", __func__);
+		ret = -ENXIO;
+		goto exit_set_current;
+	}
+
+	if (curr_index < 0) {
+		dev_err(di->dev, "requested current limit out-of-range\n");
+		ret = -ENXIO;
+		goto exit_set_current;
+	}
+
+	/* only update current if it's been changed */
+	if (prev_curr_index == curr_index) {
+		dev_dbg(di->dev, "%s current not changed for reg: 0x%02x\n",
+			__func__, reg);
+		ret = 0;
+		goto exit_set_current;
+	}
+
+	dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n",
+		__func__, ich, reg);
+
+	if (no_stepping) {
+		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+					reg, (u8)curr_index << shift_value);
+		if (ret)
+			dev_err(di->dev, "%s write failed\n", __func__);
+	} else if (prev_curr_index > curr_index) {
+		for (i = prev_curr_index - 1; i >= curr_index; i--) {
+			dev_dbg(di->dev, "curr change_1 to: %x for 0x%02x\n",
+				(u8) i << shift_value, reg);
+			ret = abx500_set_register_interruptible(di->dev,
+				AB8500_CHARGER, reg, (u8)i << shift_value);
+			if (ret) {
+				dev_err(di->dev, "%s write failed\n", __func__);
+				goto exit_set_current;
+			}
+			if (i != curr_index)
+				usleep_range(step_udelay, step_udelay * 2);
+		}
+	} else {
+		for (i = prev_curr_index + 1; i <= curr_index; i++) {
+			dev_dbg(di->dev, "curr change_2 to: %x for 0x%02x\n",
+				(u8)i << shift_value, reg);
+			ret = abx500_set_register_interruptible(di->dev,
+				AB8500_CHARGER, reg, (u8)i << shift_value);
+			if (ret) {
+				dev_err(di->dev, "%s write failed\n", __func__);
+				goto exit_set_current;
+			}
+			if (i != curr_index)
+				usleep_range(step_udelay, step_udelay * 2);
+		}
+	}
+
+exit_set_current:
+	atomic_dec(&di->current_stepping_sessions);
+
+	return ret;
+}
+
+/**
  * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit
  * @di:		pointer to the ab8500_charger structure
  * @ich_in:	charger input current limit
@@ -946,12 +1250,11 @@
 static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
 		int ich_in)
 {
-	int ret;
-	int input_curr_index;
 	int min_value;
+	int ret;
 
 	/* We should always use to lowest current limit */
-	min_value = min(di->bat->chg_params->usb_curr_max, ich_in);
+	min_value = min(di->bm->chg_params->usb_curr_max, ich_in);
 
 	switch (min_value) {
 	case 100:
@@ -966,22 +1269,47 @@
 		break;
 	}
 
-	input_curr_index = ab8500_vbus_in_curr_to_regval(min_value);
-	if (input_curr_index < 0) {
-		dev_err(di->dev, "VBUS input current limit too high\n");
-		return -ENXIO;
-	}
+	dev_info(di->dev, "VBUS input current limit set to %d mA\n", min_value);
 
-	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
-		AB8500_USBCH_IPT_CRNTLVL_REG,
-		input_curr_index << VBUS_IN_CURR_LIM_SHIFT);
-	if (ret)
-		dev_err(di->dev, "%s write failed\n", __func__);
+	mutex_lock(&di->usb_ipt_crnt_lock);
+	ret = ab8500_charger_set_current(di, min_value,
+		AB8500_USBCH_IPT_CRNTLVL_REG);
+	mutex_unlock(&di->usb_ipt_crnt_lock);
 
 	return ret;
 }
 
 /**
+ * ab8500_charger_set_main_in_curr() - set main charger input current
+ * @di:		pointer to the ab8500_charger structure
+ * @ich_in:	input charger current, in mA
+ *
+ * Set main charger input current.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di,
+	int ich_in)
+{
+	return ab8500_charger_set_current(di, ich_in,
+		AB8500_MCH_IPT_CURLVL_REG);
+}
+
+/**
+ * ab8500_charger_set_output_curr() - set charger output current
+ * @di:		pointer to the ab8500_charger structure
+ * @ich_out:	output charger current, in mA
+ *
+ * Set charger output current.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_output_curr(struct ab8500_charger *di,
+	int ich_out)
+{
+	return ab8500_charger_set_current(di, ich_out,
+		AB8500_CH_OPT_CRNTLVL_REG);
+}
+
+/**
  * ab8500_charger_led_en() - turn on/off chargign led
  * @di:		pointer to the ab8500_charger structure
  * @on:		flag to turn on/off the chargign led
@@ -1074,7 +1402,7 @@
 		volt_index = ab8500_voltage_to_regval(vset);
 		curr_index = ab8500_current_to_regval(iset);
 		input_curr_index = ab8500_current_to_regval(
-			di->bat->chg_params->ac_curr_max);
+			di->bm->chg_params->ac_curr_max);
 		if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) {
 			dev_err(di->dev,
 				"Charger voltage or current too high, "
@@ -1090,23 +1418,24 @@
 			return ret;
 		}
 		/* MainChInputCurr: current that can be drawn from the charger*/
-		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
-			AB8500_MCH_IPT_CURLVL_REG,
-			input_curr_index << MAIN_CH_INPUT_CURR_SHIFT);
+		ret = ab8500_charger_set_main_in_curr(di,
+			di->bm->chg_params->ac_curr_max);
 		if (ret) {
-			dev_err(di->dev, "%s write failed\n", __func__);
+			dev_err(di->dev, "%s Failed to set MainChInputCurr\n",
+				__func__);
 			return ret;
 		}
 		/* ChOutputCurentLevel: protected output current */
-		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
-			AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+		ret = ab8500_charger_set_output_curr(di, iset);
 		if (ret) {
-			dev_err(di->dev, "%s write failed\n", __func__);
+			dev_err(di->dev, "%s "
+				"Failed to set ChOutputCurentLevel\n",
+				__func__);
 			return ret;
 		}
 
 		/* Check if VBAT overshoot control should be enabled */
-		if (!di->bat->enable_overshoot)
+		if (!di->bm->enable_overshoot)
 			overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N;
 
 		/* Enable Main Charger */
@@ -1158,12 +1487,11 @@
 				return ret;
 			}
 
-			ret = abx500_set_register_interruptible(di->dev,
-				AB8500_CHARGER,
-				AB8500_CH_OPT_CRNTLVL_REG, CH_OP_CUR_LVL_0P1);
+			ret = ab8500_charger_set_output_curr(di, 0);
 			if (ret) {
-				dev_err(di->dev,
-					"%s write failed\n", __func__);
+				dev_err(di->dev, "%s "
+					"Failed to set ChOutputCurentLevel\n",
+					__func__);
 				return ret;
 			}
 		} else {
@@ -1259,24 +1587,13 @@
 			dev_err(di->dev, "%s write failed\n", __func__);
 			return ret;
 		}
-		/* USBChInputCurr: current that can be drawn from the usb */
-		ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
-		if (ret) {
-			dev_err(di->dev, "setting USBChInputCurr failed\n");
-			return ret;
-		}
-		/* ChOutputCurentLevel: protected output current */
-		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
-			AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
-		if (ret) {
-			dev_err(di->dev, "%s write failed\n", __func__);
-			return ret;
-		}
 		/* Check if VBAT overshoot control should be enabled */
-		if (!di->bat->enable_overshoot)
+		if (!di->bm->enable_overshoot)
 			overshoot = USB_CHG_NO_OVERSHOOT_ENA_N;
 
 		/* Enable USB Charger */
+		dev_dbg(di->dev,
+			"Enabling USB with write to AB8500_USBCH_CTRL1_REG\n");
 		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
 			AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot);
 		if (ret) {
@@ -1289,11 +1606,29 @@
 		if (ret < 0)
 			dev_err(di->dev, "failed to enable LED\n");
 
+		di->usb.charger_online = 1;
+
+		/* USBChInputCurr: current that can be drawn from the usb */
+		ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+		if (ret) {
+			dev_err(di->dev, "setting USBChInputCurr failed\n");
+			return ret;
+		}
+
+		/* ChOutputCurentLevel: protected output current */
+		ret = ab8500_charger_set_output_curr(di, ich_out);
+		if (ret) {
+			dev_err(di->dev, "%s "
+				"Failed to set ChOutputCurentLevel\n",
+				__func__);
+			return ret;
+		}
+
 		queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ);
 
-		di->usb.charger_online = 1;
 	} else {
 		/* Disable USB charging */
+		dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
 		ret = abx500_set_register_interruptible(di->dev,
 			AB8500_CHARGER,
 			AB8500_USBCH_CTRL1_REG, 0);
@@ -1306,7 +1641,21 @@
 		ret = ab8500_charger_led_en(di, false);
 		if (ret < 0)
 			dev_err(di->dev, "failed to disable LED\n");
+		/* USBChInputCurr: current that can be drawn from the usb */
+		ret = ab8500_charger_set_vbus_in_curr(di, 0);
+		if (ret) {
+			dev_err(di->dev, "setting USBChInputCurr failed\n");
+			return ret;
+		}
 
+		/* ChOutputCurentLevel: protected output current */
+		ret = ab8500_charger_set_output_curr(di, 0);
+		if (ret) {
+			dev_err(di->dev, "%s "
+				"Failed to reset ChOutputCurentLevel\n",
+				__func__);
+			return ret;
+		}
 		di->usb.charger_online = 0;
 		di->usb.wd_expired = false;
 
@@ -1366,7 +1715,6 @@
 		int ich_out)
 {
 	int ret;
-	int curr_index;
 	struct ab8500_charger *di;
 
 	if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
@@ -1376,18 +1724,11 @@
 	else
 		return -ENXIO;
 
-	curr_index = ab8500_current_to_regval(ich_out);
-	if (curr_index < 0) {
-		dev_err(di->dev,
-			"Charger current too high, "
-			"charging not started\n");
-		return -ENXIO;
-	}
-
-	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
-		AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+	ret = ab8500_charger_set_output_curr(di, ich_out);
 	if (ret) {
-		dev_err(di->dev, "%s write failed\n", __func__);
+		dev_err(di->dev, "%s "
+			"Failed to set ChOutputCurentLevel\n",
+			__func__);
 		return ret;
 	}
 
@@ -1597,7 +1938,7 @@
 	 * synchronously, we have the check if the main charger is
 	 * connected by reading the status register
 	 */
-	ret = ab8500_charger_detect_chargers(di);
+	ret = ab8500_charger_detect_chargers(di, false);
 	if (ret < 0)
 		return;
 
@@ -1612,6 +1953,84 @@
 	sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present");
 }
 
+static void ab8500_charger_usb_attached_work(struct work_struct *work)
+{
+	struct ab8500_charger *di = container_of(work,
+						 struct ab8500_charger,
+						 usb_charger_attached_work.work);
+	int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC);
+	int ret, i;
+	u8 statval;
+
+	for (i = 0; i < 10; i++) {
+		ret = abx500_get_register_interruptible(di->dev,
+							AB8500_CHARGER,
+							AB8500_CH_USBCH_STAT1_REG,
+							&statval);
+		if (ret < 0) {
+			dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+			goto reschedule;
+		}
+		if ((statval & usbch) != usbch)
+			goto reschedule;
+
+		msleep(CHARGER_STATUS_POLL);
+	}
+
+	ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0);
+
+	mutex_lock(&di->charger_attached_mutex);
+	mutex_unlock(&di->charger_attached_mutex);
+
+	return;
+
+reschedule:
+	queue_delayed_work(di->charger_wq,
+			   &di->usb_charger_attached_work,
+			   HZ);
+}
+
+static void ab8500_charger_ac_attached_work(struct work_struct *work)
+{
+
+	struct ab8500_charger *di = container_of(work,
+						 struct ab8500_charger,
+						 ac_charger_attached_work.work);
+	int mainch = (MAIN_CH_STATUS2_MAINCHGDROP |
+		      MAIN_CH_STATUS2_MAINCHARGERDETDBNC);
+	int ret, i;
+	u8 statval;
+
+	for (i = 0; i < 10; i++) {
+		ret = abx500_get_register_interruptible(di->dev,
+							AB8500_CHARGER,
+							AB8500_CH_STATUS2_REG,
+							&statval);
+		if (ret < 0) {
+			dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+			goto reschedule;
+		}
+
+		if ((statval & mainch) != mainch)
+			goto reschedule;
+
+		msleep(CHARGER_STATUS_POLL);
+	}
+
+	ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0);
+	queue_work(di->charger_wq, &di->ac_work);
+
+	mutex_lock(&di->charger_attached_mutex);
+	mutex_unlock(&di->charger_attached_mutex);
+
+	return;
+
+reschedule:
+	queue_delayed_work(di->charger_wq,
+			   &di->ac_charger_attached_work,
+			   HZ);
+}
+
 /**
  * ab8500_charger_detect_usb_type_work() - work to detect USB type
  * @work:	Pointer to the work_struct structure
@@ -1630,16 +2049,18 @@
 	 * synchronously, we have the check if is
 	 * connected by reading the status register
 	 */
-	ret = ab8500_charger_detect_chargers(di);
+	ret = ab8500_charger_detect_chargers(di, false);
 	if (ret < 0)
 		return;
 
 	if (!(ret & USB_PW_CONN)) {
-		di->vbus_detected = 0;
+		dev_dbg(di->dev, "%s di->vbus_detected = false\n", __func__);
+		di->vbus_detected = false;
 		ab8500_charger_set_usb_connected(di, false);
 		ab8500_power_supply_changed(di, &di->usb_chg.psy);
 	} else {
-		di->vbus_detected = 1;
+		dev_dbg(di->dev, "%s di->vbus_detected = true\n", __func__);
+		di->vbus_detected = true;
 
 		if (is_ab8500_1p1_or_earlier(di->parent)) {
 			ret = ab8500_charger_detect_usb_type(di);
@@ -1649,7 +2070,8 @@
 							    &di->usb_chg.psy);
 			}
 		} else {
-			/* For ABB cut2.0 and onwards we have an IRQ,
+			/*
+			 * For ABB cut2.0 and onwards we have an IRQ,
 			 * USB_LINK_STATUS that will be triggered when the USB
 			 * link status changes. The exception is USB connected
 			 * during startup. Then we don't get a
@@ -1670,6 +2092,29 @@
 }
 
 /**
+ * ab8500_charger_usb_link_attach_work() - work to detect USB type
+ * @work:	pointer to the work_struct structure
+ *
+ * Detect the type of USB plugged
+ */
+static void ab8500_charger_usb_link_attach_work(struct work_struct *work)
+{
+	struct ab8500_charger *di =
+		container_of(work, struct ab8500_charger, attach_work.work);
+	int ret;
+
+	/* Update maximum input current if USB enumeration is not detected */
+	if (!di->usb.charger_online) {
+		ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+		if (ret)
+			return;
+	}
+
+	ab8500_charger_set_usb_connected(di, true);
+	ab8500_power_supply_changed(di, &di->usb_chg.psy);
+}
+
+/**
  * ab8500_charger_usb_link_status_work() - work to detect USB type
  * @work:	pointer to the work_struct structure
  *
@@ -1677,7 +2122,9 @@
  */
 static void ab8500_charger_usb_link_status_work(struct work_struct *work)
 {
+	int detected_chargers;
 	int ret;
+	u8 val;
 
 	struct ab8500_charger *di = container_of(work,
 		struct ab8500_charger, usb_link_status_work);
@@ -1687,31 +2134,95 @@
 	 * synchronously, we have the check if  is
 	 * connected by reading the status register
 	 */
-	ret = ab8500_charger_detect_chargers(di);
-	if (ret < 0)
+	detected_chargers = ab8500_charger_detect_chargers(di, false);
+	if (detected_chargers < 0)
 		return;
 
-	if (!(ret & USB_PW_CONN)) {
-		di->vbus_detected = 0;
+	/*
+	 * Some chargers that breaks the USB spec is
+	 * identified as invalid by AB8500 and it refuse
+	 * to start the charging process. but by jumping
+	 * thru a few hoops it can be forced to start.
+	 */
+	ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+			AB8500_USB_LINE_STAT_REG, &val);
+	if (ret >= 0)
+		dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val);
+	else
+		dev_dbg(di->dev, "Error reading USB link status\n");
+
+	if (detected_chargers & USB_PW_CONN) {
+		if (((val & AB8500_USB_LINK_STATUS) >> 3) == USB_STAT_NOT_VALID_LINK &&
+				di->invalid_charger_detect_state == 0) {
+			dev_dbg(di->dev, "Invalid charger detected, state= 0\n");
+			/*Enable charger*/
+			abx500_mask_and_set_register_interruptible(di->dev,
+					AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 0x01, 0x01);
+			/*Enable charger detection*/
+			abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB,
+					AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x01);
+			di->invalid_charger_detect_state = 1;
+			/*exit and wait for new link status interrupt.*/
+			return;
+
+		}
+		if (di->invalid_charger_detect_state == 1) {
+			dev_dbg(di->dev, "Invalid charger detected, state= 1\n");
+			/*Stop charger detection*/
+			abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB,
+					AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x00);
+			/*Check link status*/
+			ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+					AB8500_USB_LINE_STAT_REG, &val);
+			dev_dbg(di->dev, "USB link status= 0x%02x\n",
+					(val & AB8500_USB_LINK_STATUS) >> 3);
+			di->invalid_charger_detect_state = 2;
+		}
+	} else {
+		di->invalid_charger_detect_state = 0;
+	}
+
+	if (!(detected_chargers & USB_PW_CONN)) {
+		di->vbus_detected = false;
 		ab8500_charger_set_usb_connected(di, false);
 		ab8500_power_supply_changed(di, &di->usb_chg.psy);
-	} else {
-		di->vbus_detected = 1;
-		ret = ab8500_charger_read_usb_type(di);
-		if (!ret) {
-			/* Update maximum input current */
-			ret = ab8500_charger_set_vbus_in_curr(di,
-					di->max_usb_in_curr);
-			if (ret)
-				return;
+		return;
+	}
 
-			ab8500_charger_set_usb_connected(di, true);
-			ab8500_power_supply_changed(di, &di->usb_chg.psy);
-		} else if (ret == -ENXIO) {
+	dev_dbg(di->dev,"%s di->vbus_detected = true\n",__func__);
+	di->vbus_detected = true;
+	ret = ab8500_charger_read_usb_type(di);
+	if (ret) {
+		if (ret == -ENXIO) {
 			/* No valid charger type detected */
 			ab8500_charger_set_usb_connected(di, false);
 			ab8500_power_supply_changed(di, &di->usb_chg.psy);
 		}
+		return;
+	}
+
+	if (di->usb_device_is_unrecognised) {
+		dev_dbg(di->dev,
+			"Potential Legacy Charger device. "
+			"Delay work for %d msec for USB enum "
+			"to finish",
+			WAIT_ACA_RID_ENUMERATION);
+		queue_delayed_work(di->charger_wq,
+				   &di->attach_work,
+				   msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION));
+	} else if (di->is_aca_rid == 1) {
+		/* Only wait once */
+		di->is_aca_rid++;
+		dev_dbg(di->dev,
+			"%s Wait %d msec for USB enum to finish",
+			__func__, WAIT_ACA_RID_ENUMERATION);
+		queue_delayed_work(di->charger_wq,
+				   &di->attach_work,
+				   msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION));
+	} else {
+		queue_delayed_work(di->charger_wq,
+				   &di->attach_work,
+				   0);
 	}
 }
 
@@ -1721,24 +2232,20 @@
 	unsigned long flags;
 
 	struct ab8500_charger *di = container_of(work,
-		struct ab8500_charger, usb_state_changed_work);
+		struct ab8500_charger, usb_state_changed_work.work);
 
-	if (!di->vbus_detected)
+	if (!di->vbus_detected)	{
+		dev_dbg(di->dev,
+			"%s !di->vbus_detected\n",
+			__func__);
 		return;
+	}
 
 	spin_lock_irqsave(&di->usb_state.usb_lock, flags);
-	di->usb_state.usb_changed = false;
+	di->usb_state.state = di->usb_state.state_tmp;
+	di->usb_state.usb_current = di->usb_state.usb_current_tmp;
 	spin_unlock_irqrestore(&di->usb_state.usb_lock, flags);
 
-	/*
-	 * wait for some time until you get updates from the usb stack
-	 * and negotiations are completed
-	 */
-	msleep(250);
-
-	if (di->usb_state.usb_changed)
-		return;
-
 	dev_dbg(di->dev, "%s USB state: 0x%02x mA: %d\n",
 		__func__, di->usb_state.state, di->usb_state.usb_current);
 
@@ -1892,6 +2399,10 @@
 	dev_dbg(di->dev, "Main charger unplugged\n");
 	queue_work(di->charger_wq, &di->ac_work);
 
+	cancel_delayed_work_sync(&di->ac_charger_attached_work);
+	mutex_lock(&di->charger_attached_mutex);
+	mutex_unlock(&di->charger_attached_mutex);
+
 	return IRQ_HANDLED;
 }
 
@@ -1909,6 +2420,11 @@
 	dev_dbg(di->dev, "Main charger plugged\n");
 	queue_work(di->charger_wq, &di->ac_work);
 
+	mutex_lock(&di->charger_attached_mutex);
+	mutex_unlock(&di->charger_attached_mutex);
+	queue_delayed_work(di->charger_wq,
+			   &di->ac_charger_attached_work,
+			   HZ);
 	return IRQ_HANDLED;
 }
 
@@ -1971,6 +2487,21 @@
 	return IRQ_HANDLED;
 }
 
+static void ab8500_charger_vbus_drop_end_work(struct work_struct *work)
+{
+	struct ab8500_charger *di = container_of(work,
+		struct ab8500_charger, vbus_drop_end_work.work);
+
+	di->flags.vbus_drop_end = false;
+
+	/* Reset the drop counter */
+	abx500_set_register_interruptible(di->dev,
+				  AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01);
+
+	if (di->usb.charger_connected)
+		ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+}
+
 /**
  * ab8500_charger_vbusdetf_handler() - VBUS falling detected
  * @irq:       interrupt number
@@ -1982,6 +2513,7 @@
 {
 	struct ab8500_charger *di = _di;
 
+	di->vbus_detected = false;
 	dev_dbg(di->dev, "VBUS falling detected\n");
 	queue_work(di->charger_wq, &di->detect_usb_type_work);
 
@@ -2001,6 +2533,7 @@
 
 	di->vbus_detected = true;
 	dev_dbg(di->dev, "VBUS rising detected\n");
+
 	queue_work(di->charger_wq, &di->detect_usb_type_work);
 
 	return IRQ_HANDLED;
@@ -2109,6 +2642,25 @@
 }
 
 /**
+ * ab8500_charger_vbuschdropend_handler() - VBUS drop removed
+ * @irq:       interrupt number
+ * @_di:       pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_vbuschdropend_handler(int irq, void *_di)
+{
+	struct ab8500_charger *di = _di;
+
+	dev_dbg(di->dev, "VBUS charger drop ended\n");
+	di->flags.vbus_drop_end = true;
+	queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work,
+			   round_jiffies(30 * HZ));
+
+	return IRQ_HANDLED;
+}
+
+/**
  * ab8500_charger_vbusovv_handler() - VBUS overvoltage detected
  * @irq:       interrupt number
  * @_di:       pointer to the ab8500_charger structure
@@ -2148,6 +2700,7 @@
 	union power_supply_propval *val)
 {
 	struct ab8500_charger *di;
+	int ret;
 
 	di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy));
 
@@ -2169,7 +2722,10 @@
 		val->intval = di->ac.charger_connected;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		di->ac.charger_voltage = ab8500_charger_get_ac_voltage(di);
+		ret = ab8500_charger_get_ac_voltage(di);
+		if (ret >= 0)
+			di->ac.charger_voltage = ret;
+		/* On error, use previous value */
 		val->intval = di->ac.charger_voltage * 1000;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
@@ -2181,7 +2737,10 @@
 		val->intval = di->ac.cv_active;
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
-		val->intval = ab8500_charger_get_ac_current(di) * 1000;
+		ret = ab8500_charger_get_ac_current(di);
+		if (ret >= 0)
+			di->ac.charger_current = ret;
+		val->intval = di->ac.charger_current * 1000;
 		break;
 	default:
 		return -EINVAL;
@@ -2208,6 +2767,7 @@
 	union power_supply_propval *val)
 {
 	struct ab8500_charger *di;
+	int ret;
 
 	di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy));
 
@@ -2231,7 +2791,9 @@
 		val->intval = di->usb.charger_connected;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		di->usb.charger_voltage = ab8500_charger_get_vbus_voltage(di);
+		ret = ab8500_charger_get_vbus_voltage(di);
+		if (ret >= 0)
+			di->usb.charger_voltage = ret;
 		val->intval = di->usb.charger_voltage * 1000;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
@@ -2243,7 +2805,10 @@
 		val->intval = di->usb.cv_active;
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
-		val->intval = ab8500_charger_get_usb_current(di) * 1000;
+		ret = ab8500_charger_get_usb_current(di);
+		if (ret >= 0)
+			di->usb.charger_current = ret;
+		val->intval = di->usb.charger_current * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_AVG:
 		/*
@@ -2293,13 +2858,23 @@
 		}
 	}
 
-	/* VBUS OVV set to 6.3V and enable automatic current limitiation */
-	ret = abx500_set_register_interruptible(di->dev,
-		AB8500_CHARGER,
-		AB8500_USBCH_CTRL2_REG,
-		VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
+	if (is_ab9540_2p0(di->parent) || is_ab8505_2p0(di->parent))
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_CHARGER,
+			AB8500_USBCH_CTRL2_REG,
+			VBUS_AUTO_IN_CURR_LIM_ENA,
+			VBUS_AUTO_IN_CURR_LIM_ENA);
+	else
+		/*
+		 * VBUS OVV set to 6.3V and enable automatic current limitation
+		 */
+		ret = abx500_set_register_interruptible(di->dev,
+			AB8500_CHARGER,
+			AB8500_USBCH_CTRL2_REG,
+			VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
 	if (ret) {
-		dev_err(di->dev, "failed to set VBUS OVV\n");
+		dev_err(di->dev,
+			"failed to set automatic current limitation\n");
 		goto out;
 	}
 
@@ -2355,12 +2930,26 @@
 		goto out;
 	}
 
+	/* Set charger watchdog timeout */
+	ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+		AB8500_CH_WD_TIMER_REG, WD_TIMER);
+	if (ret) {
+		dev_err(di->dev, "failed to set charger watchdog timeout\n");
+		goto out;
+	}
+
+	ret = ab8500_charger_led_en(di, false);
+	if (ret < 0) {
+		dev_err(di->dev, "failed to disable LED\n");
+		goto out;
+	}
+
 	/* Backup battery voltage and current */
 	ret = abx500_set_register_interruptible(di->dev,
 		AB8500_RTC,
 		AB8500_RTC_BACKUP_CHG_REG,
-		di->bat->bkup_bat_v |
-		di->bat->bkup_bat_i);
+		di->bm->bkup_bat_v |
+		di->bm->bkup_bat_i);
 	if (ret) {
 		dev_err(di->dev, "failed to setup backup battery charging\n");
 		goto out;
@@ -2394,6 +2983,7 @@
 	{"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler},
 	{"VBUS_OVV", ab8500_charger_vbusovv_handler},
 	{"CH_WD_EXP", ab8500_charger_chwdexp_handler},
+	{"VBUS_CH_DROP_END", ab8500_charger_vbuschdropend_handler},
 };
 
 static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
@@ -2404,6 +2994,9 @@
 	enum ab8500_usb_state bm_usb_state;
 	unsigned mA = *((unsigned *)power);
 
+	if (!di)
+		return NOTIFY_DONE;
+
 	if (event != USB_EVENT_VBUS) {
 		dev_dbg(di->dev, "not a standard host, returning\n");
 		return NOTIFY_DONE;
@@ -2427,13 +3020,15 @@
 		__func__, bm_usb_state, mA);
 
 	spin_lock(&di->usb_state.usb_lock);
-	di->usb_state.usb_changed = true;
+	di->usb_state.state_tmp = bm_usb_state;
+	di->usb_state.usb_current_tmp = mA;
 	spin_unlock(&di->usb_state.usb_lock);
 
-	di->usb_state.state = bm_usb_state;
-	di->usb_state.usb_current = mA;
-
-	queue_work(di->charger_wq, &di->usb_state_changed_work);
+	/*
+	 * wait for some time until you get updates from the usb stack
+	 * and negotiations are completed
+	 */
+	queue_delayed_work(di->charger_wq, &di->usb_state_changed_work, HZ/2);
 
 	return NOTIFY_OK;
 }
@@ -2473,6 +3068,9 @@
 			&di->check_hw_failure_work, 0);
 	}
 
+	if (di->flags.vbus_drop_end)
+		queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 0);
+
 	return 0;
 }
 
@@ -2485,6 +3083,23 @@
 	if (delayed_work_pending(&di->check_hw_failure_work))
 		cancel_delayed_work(&di->check_hw_failure_work);
 
+	if (delayed_work_pending(&di->vbus_drop_end_work))
+		cancel_delayed_work(&di->vbus_drop_end_work);
+
+	flush_delayed_work(&di->attach_work);
+	flush_delayed_work(&di->usb_charger_attached_work);
+	flush_delayed_work(&di->ac_charger_attached_work);
+	flush_delayed_work(&di->check_usbchgnotok_work);
+	flush_delayed_work(&di->check_vbat_work);
+	flush_delayed_work(&di->kick_wd_work);
+
+	flush_work(&di->usb_link_status_work);
+	flush_work(&di->ac_work);
+	flush_work(&di->detect_usb_type_work);
+
+	if (atomic_read(&di->current_stepping_sessions))
+		return -EAGAIN;
+
 	return 0;
 }
 #else
@@ -2509,9 +3124,6 @@
 		free_irq(irq, di);
 	}
 
-	/* disable the regulator */
-	regulator_put(di->regu);
-
 	/* Backup battery voltage and current disable */
 	ret = abx500_mask_and_set_register_interruptible(di->dev,
 		AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
@@ -2525,8 +3137,12 @@
 	destroy_workqueue(di->charger_wq);
 
 	flush_scheduled_work();
-	power_supply_unregister(&di->usb_chg.psy);
-	power_supply_unregister(&di->ac_chg.psy);
+	if(di->usb_chg.enabled)
+		power_supply_unregister(&di->usb_chg.psy);
+#if !defined(CONFIG_CHARGER_PM2301)
+	if(di->ac_chg.enabled)
+		power_supply_unregister(&di->ac_chg.psy);
+#endif
 	platform_set_drvdata(pdev, NULL);
 
 	return 0;
@@ -2541,32 +3157,31 @@
 static int ab8500_charger_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct abx500_bm_data *plat = pdev->dev.platform_data;
 	struct ab8500_charger *di;
-	int irq, i, charger_status, ret = 0;
+	int irq, i, charger_status, ret = 0, ch_stat;
 
 	di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
 	if (!di) {
 		dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__);
 		return -ENOMEM;
 	}
-	di->bat = pdev->mfd_cell->platform_data;
-	if (!di->bat) {
-		if (np) {
-			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
-			if (ret) {
-				dev_err(&pdev->dev,
-					"failed to get battery information\n");
-				return ret;
-			}
-			di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
-		} else {
-			dev_err(&pdev->dev, "missing dt node for ab8500_charger\n");
-			return -EINVAL;
-		}
-	} else {
-		dev_info(&pdev->dev, "falling back to legacy platform data\n");
-		di->autopower_cfg = false;
+
+	if (!plat) {
+		dev_err(&pdev->dev, "no battery management data supplied\n");
+		return -EINVAL;
 	}
+	di->bm = plat;
+
+	if (np) {
+		ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get battery information\n");
+			return ret;
+		}
+		di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
+	} else
+		di->autopower_cfg = false;
 
 	/* get parent data */
 	di->dev = &pdev->dev;
@@ -2575,8 +3190,10 @@
 
 	/* initialize lock */
 	spin_lock_init(&di->usb_state.usb_lock);
+	mutex_init(&di->usb_ipt_crnt_lock);
 
 	di->autopower = false;
+	di->invalid_charger_detect_state = 0;
 
 	/* AC supply */
 	/* power_supply base class */
@@ -2595,6 +3212,9 @@
 		ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
 	di->ac_chg.max_out_curr = ab8500_charger_current_map[
 		ARRAY_SIZE(ab8500_charger_current_map) - 1];
+	di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
+	di->ac_chg.enabled = di->bm->ac_enabled;
+	di->ac_chg.external = false;
 
 	/* USB supply */
 	/* power_supply base class */
@@ -2613,7 +3233,9 @@
 		ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
 	di->usb_chg.max_out_curr = ab8500_charger_current_map[
 		ARRAY_SIZE(ab8500_charger_current_map) - 1];
-
+	di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
+	di->usb_chg.enabled = di->bm->usb_enabled;
+	di->usb_chg.external = false;
 
 	/* Create a work queue for the charger */
 	di->charger_wq =
@@ -2623,12 +3245,19 @@
 		return -ENOMEM;
 	}
 
+	mutex_init(&di->charger_attached_mutex);
+
 	/* Init work for HW failure check */
 	INIT_DEFERRABLE_WORK(&di->check_hw_failure_work,
 		ab8500_charger_check_hw_failure_work);
 	INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work,
 		ab8500_charger_check_usbchargernotok_work);
 
+	INIT_DELAYED_WORK(&di->ac_charger_attached_work,
+			  ab8500_charger_ac_attached_work);
+	INIT_DELAYED_WORK(&di->usb_charger_attached_work,
+			  ab8500_charger_usb_attached_work);
+
 	/*
 	 * For ABB revision 1.0 and 1.1 there is a bug in the watchdog
 	 * logic. That means we have to continously kick the charger
@@ -2644,6 +3273,15 @@
 	INIT_DEFERRABLE_WORK(&di->check_vbat_work,
 		ab8500_charger_check_vbat_work);
 
+	INIT_DELAYED_WORK(&di->attach_work,
+		ab8500_charger_usb_link_attach_work);
+
+	INIT_DELAYED_WORK(&di->usb_state_changed_work,
+		ab8500_charger_usb_state_changed_work);
+
+	INIT_DELAYED_WORK(&di->vbus_drop_end_work,
+		ab8500_charger_vbus_drop_end_work);
+
 	/* Init work for charger detection */
 	INIT_WORK(&di->usb_link_status_work,
 		ab8500_charger_usb_link_status_work);
@@ -2651,9 +3289,6 @@
 	INIT_WORK(&di->detect_usb_type_work,
 		ab8500_charger_detect_usb_type_work);
 
-	INIT_WORK(&di->usb_state_changed_work,
-		ab8500_charger_usb_state_changed_work);
-
 	/* Init work for checking HW status */
 	INIT_WORK(&di->check_main_thermal_prot_work,
 		ab8500_charger_check_main_thermal_prot_work);
@@ -2665,7 +3300,7 @@
 	 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
 	 * interrupts during charging
 	 */
-	di->regu = regulator_get(di->dev, "vddadc");
+	di->regu = devm_regulator_get(di->dev, "vddadc");
 	if (IS_ERR(di->regu)) {
 		ret = PTR_ERR(di->regu);
 		dev_err(di->dev, "failed to get vddadc regulator\n");
@@ -2677,21 +3312,25 @@
 	ret = ab8500_charger_init_hw_registers(di);
 	if (ret) {
 		dev_err(di->dev, "failed to initialize ABB registers\n");
-		goto free_regulator;
+		goto free_charger_wq;
 	}
 
 	/* Register AC charger class */
-	ret = power_supply_register(di->dev, &di->ac_chg.psy);
-	if (ret) {
-		dev_err(di->dev, "failed to register AC charger\n");
-		goto free_regulator;
+	if(di->ac_chg.enabled) {
+		ret = power_supply_register(di->dev, &di->ac_chg.psy);
+		if (ret) {
+			dev_err(di->dev, "failed to register AC charger\n");
+			goto free_charger_wq;
+		}
 	}
 
 	/* Register USB charger class */
-	ret = power_supply_register(di->dev, &di->usb_chg.psy);
-	if (ret) {
-		dev_err(di->dev, "failed to register USB charger\n");
-		goto free_ac;
+	if(di->usb_chg.enabled) {
+		ret = power_supply_register(di->dev, &di->usb_chg.psy);
+		if (ret) {
+			dev_err(di->dev, "failed to register USB charger\n");
+			goto free_ac;
+		}
 	}
 
 	di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
@@ -2708,7 +3347,7 @@
 	}
 
 	/* Identify the connected charger types during startup */
-	charger_status = ab8500_charger_detect_chargers(di);
+	charger_status = ab8500_charger_detect_chargers(di, true);
 	if (charger_status & AC_PW_CONN) {
 		di->ac.charger_connected = 1;
 		di->ac_conn = true;
@@ -2717,7 +3356,6 @@
 	}
 
 	if (charger_status & USB_PW_CONN) {
-		dev_dbg(di->dev, "VBUS Detect during startup\n");
 		di->vbus_detected = true;
 		di->vbus_detected_start = true;
 		queue_work(di->charger_wq,
@@ -2742,6 +3380,23 @@
 
 	platform_set_drvdata(pdev, di);
 
+	mutex_lock(&di->charger_attached_mutex);
+
+	ch_stat = ab8500_charger_detect_chargers(di, false);
+
+	if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) {
+		queue_delayed_work(di->charger_wq,
+				   &di->ac_charger_attached_work,
+				   HZ);
+	}
+	if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) {
+		queue_delayed_work(di->charger_wq,
+				   &di->usb_charger_attached_work,
+				   HZ);
+	}
+
+	mutex_unlock(&di->charger_attached_mutex);
+
 	return ret;
 
 free_irq:
@@ -2755,11 +3410,11 @@
 put_usb_phy:
 	usb_put_phy(di->usb_phy);
 free_usb:
-	power_supply_unregister(&di->usb_chg.psy);
+	if(di->usb_chg.enabled)
+		power_supply_unregister(&di->usb_chg.psy);
 free_ac:
-	power_supply_unregister(&di->ac_chg.psy);
-free_regulator:
-	regulator_put(di->regu);
+	if(di->ac_chg.enabled)
+		power_supply_unregister(&di->ac_chg.psy);
 free_charger_wq:
 	destroy_workqueue(di->charger_wq);
 	return ret;
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index b3bf178..25dae4c 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -32,6 +32,7 @@
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/kernel.h>
 
 #define MILLI_TO_MICRO			1000
 #define FG_LSB_IN_MA			1627
@@ -42,7 +43,7 @@
 
 #define NBR_AVG_SAMPLES			20
 
-#define LOW_BAT_CHECK_INTERVAL		(2 * HZ)
+#define LOW_BAT_CHECK_INTERVAL		(HZ / 16) /* 62.5 ms */
 
 #define VALID_CAPACITY_SEC		(45 * 60) /* 45 minutes */
 #define BATT_OK_MIN			2360 /* mV */
@@ -113,6 +114,13 @@
 	int sum;
 };
 
+struct ab8500_fg_cap_scaling {
+	bool enable;
+	int cap_to_scale[2];
+	int disable_cap_level;
+	int scaled_cap;
+};
+
 struct ab8500_fg_battery_capacity {
 	int max_mah_design;
 	int max_mah;
@@ -123,6 +131,7 @@
 	int prev_percent;
 	int prev_level;
 	int user_mah;
+	struct ab8500_fg_cap_scaling cap_scale;
 };
 
 struct ab8500_fg_flags {
@@ -160,6 +169,8 @@
  * @recovery_cnt:	Counter for recovery mode
  * @high_curr_cnt:	Counter for high current mode
  * @init_cnt:		Counter for init mode
+ * @low_bat_cnt		Counter for number of consecutive low battery measures
+ * @nbr_cceoc_irq_cnt	Counter for number of CCEOC irqs received since enabled
  * @recovery_needed:	Indicate if recovery is needed
  * @high_curr_mode:	Indicate if we're in high current mode
  * @init_capacity:	Indicate if initial capacity measuring should be done
@@ -167,13 +178,14 @@
  * @calib_state		State during offset calibration
  * @discharge_state:	Current discharge state
  * @charge_state:	Current charge state
+ * @ab8500_fg_started	Completion struct used for the instant current start
  * @ab8500_fg_complete	Completion struct used for the instant current reading
  * @flags:		Structure for information about events triggered
  * @bat_cap:		Structure for battery capacity specific parameters
  * @avg_cap:		Average capacity filter
  * @parent:		Pointer to the struct ab8500
  * @gpadc:		Pointer to the struct gpadc
- * @bat:		Pointer to the abx500_bm platform data
+ * @bm:           	Platform specific battery management information
  * @fg_psy:		Structure that holds the FG specific battery properties
  * @fg_wq:		Work queue for running the FG algorithm
  * @fg_periodic_work:	Work to run the FG algorithm periodically
@@ -199,6 +211,8 @@
 	int recovery_cnt;
 	int high_curr_cnt;
 	int init_cnt;
+	int low_bat_cnt;
+	int nbr_cceoc_irq_cnt;
 	bool recovery_needed;
 	bool high_curr_mode;
 	bool init_capacity;
@@ -206,13 +220,14 @@
 	enum ab8500_fg_calibration_state calib_state;
 	enum ab8500_fg_discharge_state discharge_state;
 	enum ab8500_fg_charge_state charge_state;
+	struct completion ab8500_fg_started;
 	struct completion ab8500_fg_complete;
 	struct ab8500_fg_flags flags;
 	struct ab8500_fg_battery_capacity bat_cap;
 	struct ab8500_fg_avg_cap avg_cap;
 	struct ab8500 *parent;
 	struct ab8500_gpadc *gpadc;
-	struct abx500_bm_data *bat;
+	struct abx500_bm_data *bm;
 	struct power_supply fg_psy;
 	struct workqueue_struct *fg_wq;
 	struct delayed_work fg_periodic_work;
@@ -355,7 +370,7 @@
 	/*
 	 * We want to know if we're in low current mode
 	 */
-	if (curr > -di->bat->fg_params->high_curr_threshold)
+	if (curr > -di->bm->fg_params->high_curr_threshold)
 		return true;
 	else
 		return false;
@@ -484,8 +499,9 @@
 		di->flags.fg_enabled = true;
 	} else {
 		/* Clear any pending read requests */
-		ret = abx500_set_register_interruptible(di->dev,
-			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0);
+		ret = abx500_mask_and_set_register_interruptible(di->dev,
+			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+			(RESET_ACCU | READ_REQ), 0);
 		if (ret)
 			goto cc_err;
 
@@ -523,13 +539,14 @@
  * Note: This is part "one" and has to be called before
  * ab8500_fg_inst_curr_finalize()
  */
- int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
+int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
 {
 	u8 reg_val;
 	int ret;
 
 	mutex_lock(&di->cc_lock);
 
+	di->nbr_cceoc_irq_cnt = 0;
 	ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
 		AB8500_RTC_CC_CONF_REG, &reg_val);
 	if (ret < 0)
@@ -557,6 +574,7 @@
 	}
 
 	/* Return and WFI */
+	INIT_COMPLETION(di->ab8500_fg_started);
 	INIT_COMPLETION(di->ab8500_fg_complete);
 	enable_irq(di->irq);
 
@@ -568,6 +586,17 @@
 }
 
 /**
+ * ab8500_fg_inst_curr_started() - check if fg conversion has started
+ * @di:         pointer to the ab8500_fg structure
+ *
+ * Returns 1 if conversion started, 0 if still waiting
+ */
+int ab8500_fg_inst_curr_started(struct ab8500_fg *di)
+{
+	return completion_done(&di->ab8500_fg_started);
+}
+
+/**
  * ab8500_fg_inst_curr_done() - check if fg conversion is done
  * @di:         pointer to the ab8500_fg structure
  *
@@ -595,13 +624,15 @@
 	int timeout;
 
 	if (!completion_done(&di->ab8500_fg_complete)) {
-		timeout = wait_for_completion_timeout(&di->ab8500_fg_complete,
+		timeout = wait_for_completion_timeout(
+			&di->ab8500_fg_complete,
 			INS_CURR_TIMEOUT);
 		dev_dbg(di->dev, "Finalize time: %d ms\n",
 			((INS_CURR_TIMEOUT - timeout) * 1000) / HZ);
 		if (!timeout) {
 			ret = -ETIME;
 			disable_irq(di->irq);
+			di->nbr_cceoc_irq_cnt = 0;
 			dev_err(di->dev, "completion timed out [%d]\n",
 				__LINE__);
 			goto fail;
@@ -609,6 +640,7 @@
 	}
 
 	disable_irq(di->irq);
+	di->nbr_cceoc_irq_cnt = 0;
 
 	ret = abx500_mask_and_set_register_interruptible(di->dev,
 			AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
@@ -647,7 +679,7 @@
 	 * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
 	 */
 	val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) /
-		(1000 * di->bat->fg_res);
+		(1000 * di->bm->fg_res);
 
 	if (di->turn_off_fg) {
 		dev_dbg(di->dev, "%s Disable FG\n", __func__);
@@ -683,6 +715,7 @@
 int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
 {
 	int ret;
+	int timeout;
 	int res = 0;
 
 	ret = ab8500_fg_inst_curr_start(di);
@@ -691,13 +724,33 @@
 		return 0;
 	}
 
+	/* Wait for CC to actually start */
+	if (!completion_done(&di->ab8500_fg_started)) {
+		timeout = wait_for_completion_timeout(
+			&di->ab8500_fg_started,
+			INS_CURR_TIMEOUT);
+		dev_dbg(di->dev, "Start time: %d ms\n",
+			((INS_CURR_TIMEOUT - timeout) * 1000) / HZ);
+		if (!timeout) {
+			ret = -ETIME;
+			dev_err(di->dev, "completion timed out [%d]\n",
+				__LINE__);
+			goto fail;
+		}
+	}
+
 	ret = ab8500_fg_inst_curr_finalize(di, &res);
 	if (ret) {
 		dev_err(di->dev, "Failed to finalize fg_inst\n");
 		return 0;
 	}
 
+	dev_dbg(di->dev, "%s instant current: %d", __func__, res);
 	return res;
+fail:
+	disable_irq(di->irq);
+	mutex_unlock(&di->cc_lock);
+	return ret;
 }
 
 /**
@@ -750,19 +803,16 @@
 	 * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
 	 */
 	di->accu_charge = (val * QLSB_NANO_AMP_HOURS_X10) /
-		(100 * di->bat->fg_res);
+		(100 * di->bm->fg_res);
 
 	/*
 	 * Convert to unit value in mA
-	 * Full scale input voltage is
-	 * 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA
-	 * Given a 250ms conversion cycle time the LSB corresponds
-	 * to 112.9 nAh. Convert to current by dividing by the conversion
+	 * by dividing by the conversion
 	 * time in hours (= samples / (3600 * 4)h)
-	 * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+	 * and multiply with 1000
 	 */
 	di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) /
-		(1000 * di->bat->fg_res * (di->fg_samples / 4));
+		(1000 * di->bm->fg_res * (di->fg_samples / 4));
 
 	di->flags.conv_done = true;
 
@@ -770,6 +820,8 @@
 
 	queue_work(di->fg_wq, &di->fg_work);
 
+	dev_dbg(di->dev, "fg_res: %d, fg_samples: %d, gasg: %d, accu_charge: %d \n",
+				di->bm->fg_res, di->fg_samples, val, di->accu_charge);
 	return;
 exit:
 	dev_err(di->dev,
@@ -814,8 +866,8 @@
 	struct abx500_v_to_cap *tbl;
 	int cap = 0;
 
-	tbl = di->bat->bat_type[di->bat->batt_id].v_to_cap_tbl,
-	tbl_size = di->bat->bat_type[di->bat->batt_id].n_v_cap_tbl_elements;
+	tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl,
+	tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements;
 
 	for (i = 0; i < tbl_size; ++i) {
 		if (voltage > tbl[i].voltage)
@@ -866,8 +918,8 @@
 	struct batres_vs_temp *tbl;
 	int resist = 0;
 
-	tbl = di->bat->bat_type[di->bat->batt_id].batres_tbl;
-	tbl_size = di->bat->bat_type[di->bat->batt_id].n_batres_tbl_elements;
+	tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl;
+	tbl_size = di->bm->bat_type[di->bm->batt_id].n_batres_tbl_elements;
 
 	for (i = 0; i < tbl_size; ++i) {
 		if (di->bat_temp / 10 > tbl[i].temp)
@@ -888,11 +940,11 @@
 
 	dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d"
 	    " fg resistance %d, total: %d (mOhm)\n",
-		__func__, di->bat_temp, resist, di->bat->fg_res / 10,
-		(di->bat->fg_res / 10) + resist);
+		__func__, di->bat_temp, resist, di->bm->fg_res / 10,
+		(di->bm->fg_res / 10) + resist);
 
 	/* fg_res variable is in 0.1mOhm */
-	resist += di->bat->fg_res / 10;
+	resist += di->bm->fg_res / 10;
 
 	return resist;
 }
@@ -915,7 +967,7 @@
 	do {
 		vbat += ab8500_fg_bat_voltage(di);
 		i++;
-		msleep(5);
+		usleep_range(5000, 6000);
 	} while (!ab8500_fg_inst_curr_done(di));
 
 	ab8500_fg_inst_curr_finalize(di, &di->inst_curr);
@@ -1108,16 +1160,16 @@
 {
 	int ret, percent;
 
-	percent = di->bat_cap.permille / 10;
+	percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
 
-	if (percent <= di->bat->cap_levels->critical ||
+	if (percent <= di->bm->cap_levels->critical ||
 		di->flags.low_bat)
 		ret = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
-	else if (percent <= di->bat->cap_levels->low)
+	else if (percent <= di->bm->cap_levels->low)
 		ret = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
-	else if (percent <= di->bat->cap_levels->normal)
+	else if (percent <= di->bm->cap_levels->normal)
 		ret = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
-	else if (percent <= di->bat->cap_levels->high)
+	else if (percent <= di->bm->cap_levels->high)
 		ret = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
 	else
 		ret = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
@@ -1126,6 +1178,99 @@
 }
 
 /**
+ * ab8500_fg_calculate_scaled_capacity() - Capacity scaling
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * Calculates the capacity to be shown to upper layers. Scales the capacity
+ * to have 100% as a reference from the actual capacity upon removal of charger
+ * when charging is in maintenance mode.
+ */
+static int ab8500_fg_calculate_scaled_capacity(struct ab8500_fg *di)
+{
+	struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale;
+	int capacity = di->bat_cap.prev_percent;
+
+	if (!cs->enable)
+		return capacity;
+
+	/*
+	 * As long as we are in fully charge mode scale the capacity
+	 * to show 100%.
+	 */
+	if (di->flags.fully_charged) {
+		cs->cap_to_scale[0] = 100;
+		cs->cap_to_scale[1] =
+			max(capacity, di->bm->fg_params->maint_thres);
+		dev_dbg(di->dev, "Scale cap with %d/%d\n",
+			 cs->cap_to_scale[0], cs->cap_to_scale[1]);
+	}
+
+	/* Calculates the scaled capacity. */
+	if ((cs->cap_to_scale[0] != cs->cap_to_scale[1])
+					&& (cs->cap_to_scale[1] > 0))
+		capacity = min(100,
+				 DIV_ROUND_CLOSEST(di->bat_cap.prev_percent *
+						 cs->cap_to_scale[0],
+						 cs->cap_to_scale[1]));
+
+	if (di->flags.charging) {
+		if (capacity < cs->disable_cap_level) {
+			cs->disable_cap_level = capacity;
+			dev_dbg(di->dev, "Cap to stop scale lowered %d%%\n",
+				cs->disable_cap_level);
+		} else if (!di->flags.fully_charged) {
+			if (di->bat_cap.prev_percent >=
+			    cs->disable_cap_level) {
+				dev_dbg(di->dev, "Disabling scaled capacity\n");
+				cs->enable = false;
+				capacity = di->bat_cap.prev_percent;
+			} else {
+				dev_dbg(di->dev,
+					"Waiting in cap to level %d%%\n",
+					cs->disable_cap_level);
+				capacity = cs->disable_cap_level;
+			}
+		}
+	}
+
+	return capacity;
+}
+
+/**
+ * ab8500_fg_update_cap_scalers() - Capacity scaling
+ * @di:		pointer to the ab8500_fg structure
+ *
+ * To be called when state change from charge<->discharge to update
+ * the capacity scalers.
+ */
+static void ab8500_fg_update_cap_scalers(struct ab8500_fg *di)
+{
+	struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale;
+
+	if (!cs->enable)
+		return;
+	if (di->flags.charging) {
+		di->bat_cap.cap_scale.disable_cap_level =
+			di->bat_cap.cap_scale.scaled_cap;
+		dev_dbg(di->dev, "Cap to stop scale at charge %d%%\n",
+				di->bat_cap.cap_scale.disable_cap_level);
+	} else {
+		if (cs->scaled_cap != 100) {
+			cs->cap_to_scale[0] = cs->scaled_cap;
+			cs->cap_to_scale[1] = di->bat_cap.prev_percent;
+		} else {
+			cs->cap_to_scale[0] = 100;
+			cs->cap_to_scale[1] =
+				max(di->bat_cap.prev_percent,
+				    di->bm->fg_params->maint_thres);
+		}
+
+		dev_dbg(di->dev, "Cap to scale at discharge %d/%d\n",
+				cs->cap_to_scale[0], cs->cap_to_scale[1]);
+	}
+}
+
+/**
  * ab8500_fg_check_capacity_limits() - Check if capacity has changed
  * @di:		pointer to the ab8500_fg structure
  * @init:	capacity is allowed to go up in init mode
@@ -1136,6 +1281,7 @@
 static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
 {
 	bool changed = false;
+	int percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
 
 	di->bat_cap.level = ab8500_fg_capacity_level(di);
 
@@ -1167,33 +1313,41 @@
 		dev_dbg(di->dev, "Battery low, set capacity to 0\n");
 		di->bat_cap.prev_percent = 0;
 		di->bat_cap.permille = 0;
+		percent = 0;
 		di->bat_cap.prev_mah = 0;
 		di->bat_cap.mah = 0;
 		changed = true;
 	} else if (di->flags.fully_charged) {
 		/*
 		 * We report 100% if algorithm reported fully charged
-		 * unless capacity drops too much
+		 * and show 100% during maintenance charging (scaling).
 		 */
 		if (di->flags.force_full) {
-			di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+			di->bat_cap.prev_percent = percent;
 			di->bat_cap.prev_mah = di->bat_cap.mah;
-		} else if (!di->flags.force_full &&
-			di->bat_cap.prev_percent !=
-			(di->bat_cap.permille) / 10 &&
-			(di->bat_cap.permille / 10) <
-			di->bat->fg_params->maint_thres) {
+
+			changed = true;
+
+			if (!di->bat_cap.cap_scale.enable &&
+						di->bm->capacity_scaling) {
+				di->bat_cap.cap_scale.enable = true;
+				di->bat_cap.cap_scale.cap_to_scale[0] = 100;
+				di->bat_cap.cap_scale.cap_to_scale[1] =
+						di->bat_cap.prev_percent;
+				di->bat_cap.cap_scale.disable_cap_level = 100;
+			}
+		} else if (di->bat_cap.prev_percent != percent) {
 			dev_dbg(di->dev,
 				"battery reported full "
 				"but capacity dropping: %d\n",
-				di->bat_cap.permille / 10);
-			di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+				percent);
+			di->bat_cap.prev_percent = percent;
 			di->bat_cap.prev_mah = di->bat_cap.mah;
 
 			changed = true;
 		}
-	} else if (di->bat_cap.prev_percent != di->bat_cap.permille / 10) {
-		if (di->bat_cap.permille / 10 == 0) {
+	} else if (di->bat_cap.prev_percent != percent) {
+		if (percent == 0) {
 			/*
 			 * We will not report 0% unless we've got
 			 * the LOW_BAT IRQ, no matter what the FG
@@ -1203,11 +1357,11 @@
 			di->bat_cap.permille = 1;
 			di->bat_cap.prev_mah = 1;
 			di->bat_cap.mah = 1;
+			percent = 1;
 
 			changed = true;
 		} else if (!(!di->flags.charging &&
-			(di->bat_cap.permille / 10) >
-			di->bat_cap.prev_percent) || init) {
+			percent > di->bat_cap.prev_percent) || init) {
 			/*
 			 * We do not allow reported capacity to go up
 			 * unless we're charging or if we're in init
@@ -1215,9 +1369,9 @@
 			dev_dbg(di->dev,
 				"capacity changed from %d to %d (%d)\n",
 				di->bat_cap.prev_percent,
-				di->bat_cap.permille / 10,
+				percent,
 				di->bat_cap.permille);
-			di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+			di->bat_cap.prev_percent = percent;
 			di->bat_cap.prev_mah = di->bat_cap.mah;
 
 			changed = true;
@@ -1225,12 +1379,20 @@
 			dev_dbg(di->dev, "capacity not allowed to go up since "
 				"no charger is connected: %d to %d (%d)\n",
 				di->bat_cap.prev_percent,
-				di->bat_cap.permille / 10,
+				percent,
 				di->bat_cap.permille);
 		}
 	}
 
 	if (changed) {
+		if (di->bm->capacity_scaling) {
+			di->bat_cap.cap_scale.scaled_cap =
+				ab8500_fg_calculate_scaled_capacity(di);
+
+			dev_info(di->dev, "capacity=%d (%d)\n",
+				di->bat_cap.prev_percent,
+				di->bat_cap.cap_scale.scaled_cap);
+		}
 		power_supply_changed(&di->fg_psy);
 		if (di->flags.fully_charged && di->flags.force_full) {
 			dev_dbg(di->dev, "Battery full, notifying.\n");
@@ -1284,7 +1446,7 @@
 	switch (di->charge_state) {
 	case AB8500_FG_CHARGE_INIT:
 		di->fg_samples = SEC_TO_SAMPLE(
-			di->bat->fg_params->accu_charging);
+			di->bm->fg_params->accu_charging);
 
 		ab8500_fg_coulomb_counter(di, true);
 		ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_READOUT);
@@ -1296,7 +1458,7 @@
 		 * Read the FG and calculate the new capacity
 		 */
 		mutex_lock(&di->cc_lock);
-		if (!di->flags.conv_done) {
+		if (!di->flags.conv_done && !di->flags.force_full) {
 			/* Wasn't the CC IRQ that got us here */
 			mutex_unlock(&di->cc_lock);
 			dev_dbg(di->dev, "%s CC conv not done\n",
@@ -1346,8 +1508,8 @@
 	cap_permille = ab8500_fg_convert_mah_to_permille(di,
 		di->bat_cap.user_mah);
 
-	lower = di->bat_cap.permille - di->bat->fg_params->user_cap_limit * 10;
-	upper = di->bat_cap.permille + di->bat->fg_params->user_cap_limit * 10;
+	lower = di->bat_cap.permille - di->bm->fg_params->user_cap_limit * 10;
+	upper = di->bat_cap.permille + di->bm->fg_params->user_cap_limit * 10;
 
 	if (lower < 0)
 		lower = 0;
@@ -1387,7 +1549,7 @@
 	case AB8500_FG_DISCHARGE_INIT:
 		/* We use the FG IRQ to work on */
 		di->init_cnt = 0;
-		di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer);
+		di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
 		ab8500_fg_coulomb_counter(di, true);
 		ab8500_fg_discharge_state_to(di,
 			AB8500_FG_DISCHARGE_INITMEASURING);
@@ -1400,18 +1562,17 @@
 		 * samples to get an initial capacity.
 		 * Then go to READOUT
 		 */
-		sleep_time = di->bat->fg_params->init_timer;
+		sleep_time = di->bm->fg_params->init_timer;
 
 		/* Discard the first [x] seconds */
-		if (di->init_cnt >
-			di->bat->fg_params->init_discard_time) {
+		if (di->init_cnt > di->bm->fg_params->init_discard_time) {
 			ab8500_fg_calc_cap_discharge_voltage(di, true);
 
 			ab8500_fg_check_capacity_limits(di, true);
 		}
 
 		di->init_cnt += sleep_time;
-		if (di->init_cnt > di->bat->fg_params->init_total_time)
+		if (di->init_cnt > di->bm->fg_params->init_total_time)
 			ab8500_fg_discharge_state_to(di,
 				AB8500_FG_DISCHARGE_READOUT_INIT);
 
@@ -1426,7 +1587,7 @@
 		/* Intentional fallthrough */
 
 	case AB8500_FG_DISCHARGE_RECOVERY:
-		sleep_time = di->bat->fg_params->recovery_sleep_timer;
+		sleep_time = di->bm->fg_params->recovery_sleep_timer;
 
 		/*
 		 * We should check the power consumption
@@ -1438,9 +1599,9 @@
 
 		if (ab8500_fg_is_low_curr(di, di->inst_curr)) {
 			if (di->recovery_cnt >
-				di->bat->fg_params->recovery_total_time) {
+				di->bm->fg_params->recovery_total_time) {
 				di->fg_samples = SEC_TO_SAMPLE(
-					di->bat->fg_params->accu_high_curr);
+					di->bm->fg_params->accu_high_curr);
 				ab8500_fg_coulomb_counter(di, true);
 				ab8500_fg_discharge_state_to(di,
 					AB8500_FG_DISCHARGE_READOUT);
@@ -1453,7 +1614,7 @@
 			di->recovery_cnt += sleep_time;
 		} else {
 			di->fg_samples = SEC_TO_SAMPLE(
-				di->bat->fg_params->accu_high_curr);
+				di->bm->fg_params->accu_high_curr);
 			ab8500_fg_coulomb_counter(di, true);
 			ab8500_fg_discharge_state_to(di,
 				AB8500_FG_DISCHARGE_READOUT);
@@ -1462,7 +1623,7 @@
 
 	case AB8500_FG_DISCHARGE_READOUT_INIT:
 		di->fg_samples = SEC_TO_SAMPLE(
-			di->bat->fg_params->accu_high_curr);
+			di->bm->fg_params->accu_high_curr);
 		ab8500_fg_coulomb_counter(di, true);
 		ab8500_fg_discharge_state_to(di,
 				AB8500_FG_DISCHARGE_READOUT);
@@ -1480,7 +1641,7 @@
 
 			if (di->recovery_needed) {
 				ab8500_fg_discharge_state_to(di,
-					AB8500_FG_DISCHARGE_RECOVERY);
+					AB8500_FG_DISCHARGE_INIT_RECOVERY);
 
 				queue_delayed_work(di->fg_wq,
 					&di->fg_periodic_work, 0);
@@ -1509,9 +1670,9 @@
 			}
 
 			di->high_curr_cnt +=
-				di->bat->fg_params->accu_high_curr;
+				di->bm->fg_params->accu_high_curr;
 			if (di->high_curr_cnt >
-				di->bat->fg_params->high_curr_time)
+				di->bm->fg_params->high_curr_time)
 				di->recovery_needed = true;
 
 			ab8500_fg_calc_cap_discharge_fg(di);
@@ -1523,12 +1684,10 @@
 
 	case AB8500_FG_DISCHARGE_WAKEUP:
 		ab8500_fg_coulomb_counter(di, true);
-		di->inst_curr = ab8500_fg_inst_curr_blocking(di);
-
 		ab8500_fg_calc_cap_discharge_voltage(di, true);
 
 		di->fg_samples = SEC_TO_SAMPLE(
-			di->bat->fg_params->accu_high_curr);
+			di->bm->fg_params->accu_high_curr);
 		ab8500_fg_coulomb_counter(di, true);
 		ab8500_fg_discharge_state_to(di,
 				AB8500_FG_DISCHARGE_READOUT);
@@ -1641,8 +1800,6 @@
 		fg_periodic_work.work);
 
 	if (di->init_capacity) {
-		/* A dummy read that will return 0 */
-		di->inst_curr = ab8500_fg_inst_curr_blocking(di);
 		/* Get an initial capacity calculation */
 		ab8500_fg_calc_cap_discharge_voltage(di, true);
 		ab8500_fg_check_capacity_limits(di, true);
@@ -1684,24 +1841,26 @@
 	 * If we have had a battery over-voltage situation,
 	 * check ovv-bit to see if it should be reset.
 	 */
-	if (di->flags.bat_ovv) {
-		ret = abx500_get_register_interruptible(di->dev,
-			AB8500_CHARGER, AB8500_CH_STAT_REG,
-			&reg_value);
-		if (ret < 0) {
-			dev_err(di->dev, "%s ab8500 read failed\n", __func__);
-			return;
+	ret = abx500_get_register_interruptible(di->dev,
+		AB8500_CHARGER, AB8500_CH_STAT_REG,
+		&reg_value);
+	if (ret < 0) {
+		dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+		return;
+	}
+	if ((reg_value & BATT_OVV) == BATT_OVV) {
+		if (!di->flags.bat_ovv) {
+			dev_dbg(di->dev, "Battery OVV\n");
+			di->flags.bat_ovv = true;
+			power_supply_changed(&di->fg_psy);
 		}
-		if ((reg_value & BATT_OVV) != BATT_OVV) {
+		/* Not yet recovered from ovv, reschedule this test */
+		queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work,
+				   HZ);
+		} else {
 			dev_dbg(di->dev, "Battery recovered from OVV\n");
 			di->flags.bat_ovv = false;
 			power_supply_changed(&di->fg_psy);
-			return;
-		}
-
-		/* Not yet recovered from ovv, reschedule this test */
-		queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work,
-				   round_jiffies(HZ));
 	}
 }
 
@@ -1721,26 +1880,30 @@
 	vbat = ab8500_fg_bat_voltage(di);
 
 	/* Check if LOW_BAT still fulfilled */
-	if (vbat < di->bat->fg_params->lowbat_threshold) {
-		di->flags.low_bat = true;
-		dev_warn(di->dev, "Battery voltage still LOW\n");
-
-		/*
-		 * We need to re-schedule this check to be able to detect
-		 * if the voltage increases again during charging
-		 */
-		queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
-			round_jiffies(LOW_BAT_CHECK_INTERVAL));
+	if (vbat < di->bm->fg_params->lowbat_threshold) {
+		/* Is it time to shut down? */
+		if (di->low_bat_cnt < 1) {
+			di->flags.low_bat = true;
+			dev_warn(di->dev, "Shut down pending...\n");
+		} else {
+			/*
+			* Else we need to re-schedule this check to be able to detect
+			* if the voltage increases again during charging or
+			* due to decreasing load.
+			*/
+			di->low_bat_cnt--;
+			dev_warn(di->dev, "Battery voltage still LOW\n");
+			queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
+				round_jiffies(LOW_BAT_CHECK_INTERVAL));
+		}
 	} else {
-		di->flags.low_bat = false;
+		di->flags.low_bat_delay = false;
+		di->low_bat_cnt = 10;
 		dev_warn(di->dev, "Battery voltage OK again\n");
 	}
 
 	/* This is needed to dispatch LOW_BAT */
 	ab8500_fg_check_capacity_limits(di, false);
-
-	/* Set this flag to check if LOW_BAT IRQ still occurs */
-	di->flags.low_bat_delay = false;
 }
 
 /**
@@ -1779,8 +1942,8 @@
 	int ret;
 	int new_val;
 
-	sel0 = di->bat->fg_params->battok_falling_th_sel0;
-	sel1 = di->bat->fg_params->battok_raising_th_sel1;
+	sel0 = di->bm->fg_params->battok_falling_th_sel0;
+	sel1 = di->bm->fg_params->battok_raising_th_sel1;
 
 	cbp_sel0 = ab8500_fg_battok_calc(di, sel0);
 	cbp_sel1 = ab8500_fg_battok_calc(di, sel1);
@@ -1828,7 +1991,13 @@
 static irqreturn_t ab8500_fg_cc_data_end_handler(int irq, void *_di)
 {
 	struct ab8500_fg *di = _di;
-	complete(&di->ab8500_fg_complete);
+	if (!di->nbr_cceoc_irq_cnt) {
+		di->nbr_cceoc_irq_cnt++;
+		complete(&di->ab8500_fg_started);
+	} else {
+		di->nbr_cceoc_irq_cnt = 0;
+		complete(&di->ab8500_fg_complete);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -1875,8 +2044,6 @@
 	struct ab8500_fg *di = _di;
 
 	dev_dbg(di->dev, "Battery OVV\n");
-	di->flags.bat_ovv = true;
-	power_supply_changed(&di->fg_psy);
 
 	/* Schedule a new HW failure check */
 	queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, 0);
@@ -1895,6 +2062,7 @@
 {
 	struct ab8500_fg *di = _di;
 
+	/* Initiate handling in ab8500_fg_low_bat_work() if not already initiated. */
 	if (!di->flags.low_bat_delay) {
 		dev_warn(di->dev, "Battery voltage is below LOW threshold\n");
 		di->flags.low_bat_delay = true;
@@ -1963,7 +2131,7 @@
 				di->bat_cap.max_mah);
 		break;
 	case POWER_SUPPLY_PROP_ENERGY_NOW:
-		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+		if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
 				di->flags.batt_id_received)
 			val->intval = ab8500_fg_convert_mah_to_uwh(di,
 					di->bat_cap.max_mah);
@@ -1978,21 +2146,23 @@
 		val->intval = di->bat_cap.max_mah;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
-		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+		if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
 				di->flags.batt_id_received)
 			val->intval = di->bat_cap.max_mah;
 		else
 			val->intval = di->bat_cap.prev_mah;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
-		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+		if (di->bm->capacity_scaling)
+			val->intval = di->bat_cap.cap_scale.scaled_cap;
+		else if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
 				di->flags.batt_id_received)
 			val->intval = 100;
 		else
 			val->intval = di->bat_cap.prev_percent;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
-		if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+		if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
 				di->flags.batt_id_received)
 			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
 		else
@@ -2049,6 +2219,8 @@
 						break;
 					di->flags.charging = false;
 					di->flags.fully_charged = false;
+					if (di->bm->capacity_scaling)
+						ab8500_fg_update_cap_scalers(di);
 					queue_work(di->fg_wq, &di->fg_work);
 					break;
 				case POWER_SUPPLY_STATUS_FULL:
@@ -2061,10 +2233,13 @@
 					queue_work(di->fg_wq, &di->fg_work);
 					break;
 				case POWER_SUPPLY_STATUS_CHARGING:
-					if (di->flags.charging)
+					if (di->flags.charging &&
+						!di->flags.fully_charged)
 						break;
 					di->flags.charging = true;
 					di->flags.fully_charged = false;
+					if (di->bm->capacity_scaling)
+						ab8500_fg_update_cap_scalers(di);
 					queue_work(di->fg_wq, &di->fg_work);
 					break;
 				};
@@ -2075,10 +2250,11 @@
 		case POWER_SUPPLY_PROP_TECHNOLOGY:
 			switch (ext->type) {
 			case POWER_SUPPLY_TYPE_BATTERY:
-				if (!di->flags.batt_id_received) {
+				if (!di->flags.batt_id_received &&
+				    di->bm->batt_id != BATTERY_UNKNOWN) {
 					const struct abx500_battery_type *b;
 
-					b = &(di->bat->bat_type[di->bat->batt_id]);
+					b = &(di->bm->bat_type[di->bm->batt_id]);
 
 					di->flags.batt_id_received = true;
 
@@ -2104,8 +2280,8 @@
 		case POWER_SUPPLY_PROP_TEMP:
 			switch (ext->type) {
 			case POWER_SUPPLY_TYPE_BATTERY:
-			    if (di->flags.batt_id_received)
-				di->bat_temp = ret.intval;
+				if (di->flags.batt_id_received)
+					di->bat_temp = ret.intval;
 				break;
 			default:
 				break;
@@ -2155,7 +2331,7 @@
 		AB8500_SYS_CTRL2_BLOCK,
 		AB8500_LOW_BAT_REG,
 		ab8500_volt_to_regval(
-			di->bat->fg_params->lowbat_threshold) << 1 |
+			di->bm->fg_params->lowbat_threshold) << 1 |
 		LOW_BAT_ENABLE);
 	if (ret) {
 		dev_err(di->dev, "%s write failed\n", __func__);
@@ -2395,6 +2571,11 @@
 	struct ab8500_fg *di = platform_get_drvdata(pdev);
 
 	flush_delayed_work(&di->fg_periodic_work);
+	flush_work(&di->fg_work);
+	flush_work(&di->fg_acc_cur_work);
+	flush_delayed_work(&di->fg_reinit_work);
+	flush_delayed_work(&di->fg_low_bat_work);
+	flush_delayed_work(&di->fg_check_hw_failure_work);
 
 	/*
 	 * If the FG is enabled we will disable it before going to suspend
@@ -2448,6 +2629,7 @@
 static int ab8500_fg_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct abx500_bm_data *plat = pdev->dev.platform_data;
 	struct ab8500_fg *di;
 	int i, irq;
 	int ret = 0;
@@ -2457,21 +2639,19 @@
 		dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
 		return -ENOMEM;
 	}
-	di->bat = pdev->mfd_cell->platform_data;
-	if (!di->bat) {
-		if (np) {
-			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
-			if (ret) {
-				dev_err(&pdev->dev,
-					"failed to get battery information\n");
-				return ret;
-			}
-		} else {
-			dev_err(&pdev->dev, "missing dt node for ab8500_fg\n");
-			return -EINVAL;
+
+	if (!plat) {
+		dev_err(&pdev->dev, "no battery management data supplied\n");
+		return -EINVAL;
+	}
+	di->bm = plat;
+
+	if (np) {
+		ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get battery information\n");
+			return ret;
 		}
-	} else {
-		dev_info(&pdev->dev, "falling back to legacy platform data\n");
 	}
 
 	mutex_init(&di->cc_lock);
@@ -2491,11 +2671,11 @@
 	di->fg_psy.external_power_changed = ab8500_fg_external_power_changed;
 
 	di->bat_cap.max_mah_design = MILLI_TO_MICRO *
-		di->bat->bat_type[di->bat->batt_id].charge_full_design;
+		di->bm->bat_type[di->bm->batt_id].charge_full_design;
 
 	di->bat_cap.max_mah = di->bat_cap.max_mah_design;
 
-	di->vbat_nom = di->bat->bat_type[di->bat->batt_id].nominal_voltage;
+	di->vbat_nom = di->bm->bat_type[di->bm->batt_id].nominal_voltage;
 
 	di->init_capacity = true;
 
@@ -2531,6 +2711,12 @@
 	INIT_DEFERRABLE_WORK(&di->fg_check_hw_failure_work,
 		ab8500_fg_check_hw_failure_work);
 
+	/* Reset battery low voltage flag */
+	di->flags.low_bat = false;
+
+	/* Initialize low battery counter */
+	di->low_bat_cnt = 10;
+
 	/* Initialize OVV, and other registers */
 	ret = ab8500_fg_init_hw_registers(di);
 	if (ret) {
@@ -2549,10 +2735,14 @@
 		goto free_inst_curr_wq;
 	}
 
-	di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer);
+	di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
 	ab8500_fg_coulomb_counter(di, true);
 
-	/* Initialize completion used to notify completion of inst current */
+	/*
+	 * Initialize completion used to notify completion and start
+	 * of inst current
+	 */
+	init_completion(&di->ab8500_fg_started);
 	init_completion(&di->ab8500_fg_complete);
 
 	/* Register interrupts */
@@ -2572,6 +2762,7 @@
 	}
 	di->irq = platform_get_irq_byname(pdev, "CCEOC");
 	disable_irq(di->irq);
+	di->nbr_cceoc_irq_cnt = 0;
 
 	platform_set_drvdata(pdev, di);
 
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 2970891..f043c08 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -33,9 +33,6 @@
 /* End-of-charge criteria counter */
 #define EOC_COND_CNT			10
 
-/* Recharge criteria counter */
-#define RCH_COND_CNT			3
-
 #define to_abx500_chargalg_device_info(x) container_of((x), \
 	struct abx500_chargalg, chargalg_psy);
 
@@ -196,7 +193,6 @@
  * @dev:		pointer to the structure device
  * @charge_status:	battery operating status
  * @eoc_cnt:		counter used to determine end-of_charge
- * @rch_cnt:		counter used to determine start of recharge
  * @maintenance_chg:	indicate if maintenance charge is active
  * @t_hyst_norm		temperature hysteresis when the temperature has been
  *			over or under normal limits
@@ -207,7 +203,7 @@
  * @chg_info:		information about connected charger types
  * @batt_data:		data of the battery
  * @susp_status:	current charger suspension status
- * @bat:		pointer to the abx500_bm platform data
+ * @bm:           	Platform specific battery management information
  * @chargalg_psy:	structure that holds the battery properties exposed by
  *			the charging algorithm
  * @events:		structure for information about events triggered
@@ -223,7 +219,6 @@
 	struct device *dev;
 	int charge_status;
 	int eoc_cnt;
-	int rch_cnt;
 	bool maintenance_chg;
 	int t_hyst_norm;
 	int t_hyst_lowhigh;
@@ -232,7 +227,7 @@
 	struct abx500_chargalg_charger_info chg_info;
 	struct abx500_chargalg_battery_data batt_data;
 	struct abx500_chargalg_suspension_status susp_status;
-	struct abx500_bm_data *bat;
+	struct abx500_bm_data *bm;
 	struct power_supply chargalg_psy;
 	struct ux500_charger *ac_chg;
 	struct ux500_charger *usb_chg;
@@ -367,13 +362,13 @@
 	case AC_CHG:
 		timer_expiration =
 		round_jiffies(jiffies +
-			(di->bat->main_safety_tmr_h * 3600 * HZ));
+			(di->bm->main_safety_tmr_h * 3600 * HZ));
 		break;
 
 	case USB_CHG:
 		timer_expiration =
 		round_jiffies(jiffies +
-			(di->bat->usb_safety_tmr_h * 3600 * HZ));
+			(di->bm->usb_safety_tmr_h * 3600 * HZ));
 		break;
 
 	default:
@@ -450,8 +445,18 @@
 {
 	/* Check if charger exists and kick watchdog if charging */
 	if (di->ac_chg && di->ac_chg->ops.kick_wd &&
-			di->chg_info.online_chg & AC_CHG)
+	    di->chg_info.online_chg & AC_CHG) {
+		/*
+		 * If AB charger watchdog expired, pm2xxx charging
+		 * gets disabled. To be safe, kick both AB charger watchdog
+		 * and pm2xxx watchdog.
+		 */
+		if (di->ac_chg->external &&
+		    di->usb_chg && di->usb_chg->ops.kick_wd)
+			di->usb_chg->ops.kick_wd(di->usb_chg);
+
 		return di->ac_chg->ops.kick_wd(di->ac_chg);
+	}
 	else if (di->usb_chg && di->usb_chg->ops.kick_wd &&
 			di->chg_info.online_chg & USB_CHG)
 		return di->usb_chg->ops.kick_wd(di->usb_chg);
@@ -608,6 +613,8 @@
 static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
 	int vset, int iset)
 {
+	bool start_chargalg_wd = true;
+
 	switch (di->chg_info.charger_type) {
 	case AC_CHG:
 		dev_dbg(di->dev,
@@ -625,8 +632,12 @@
 
 	default:
 		dev_err(di->dev, "Unknown charger to charge from\n");
+		start_chargalg_wd = false;
 		break;
 	}
+
+	if (start_chargalg_wd && !delayed_work_pending(&di->chargalg_wd_work))
+		queue_delayed_work(di->chargalg_wq, &di->chargalg_wd_work, 0);
 }
 
 /**
@@ -638,32 +649,32 @@
  */
 static void abx500_chargalg_check_temp(struct abx500_chargalg *di)
 {
-	if (di->batt_data.temp > (di->bat->temp_low + di->t_hyst_norm) &&
-		di->batt_data.temp < (di->bat->temp_high - di->t_hyst_norm)) {
+	if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) &&
+		di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) {
 		/* Temp OK! */
 		di->events.btemp_underover = false;
 		di->events.btemp_lowhigh = false;
 		di->t_hyst_norm = 0;
 		di->t_hyst_lowhigh = 0;
 	} else {
-		if (((di->batt_data.temp >= di->bat->temp_high) &&
+		if (((di->batt_data.temp >= di->bm->temp_high) &&
 			(di->batt_data.temp <
-				(di->bat->temp_over - di->t_hyst_lowhigh))) ||
+				(di->bm->temp_over - di->t_hyst_lowhigh))) ||
 			((di->batt_data.temp >
-				(di->bat->temp_under + di->t_hyst_lowhigh)) &&
-			(di->batt_data.temp <= di->bat->temp_low))) {
+				(di->bm->temp_under + di->t_hyst_lowhigh)) &&
+			(di->batt_data.temp <= di->bm->temp_low))) {
 			/* TEMP minor!!!!! */
 			di->events.btemp_underover = false;
 			di->events.btemp_lowhigh = true;
-			di->t_hyst_norm = di->bat->temp_hysteresis;
+			di->t_hyst_norm = di->bm->temp_hysteresis;
 			di->t_hyst_lowhigh = 0;
-		} else if (di->batt_data.temp <= di->bat->temp_under ||
-			di->batt_data.temp >= di->bat->temp_over) {
+		} else if (di->batt_data.temp <= di->bm->temp_under ||
+			di->batt_data.temp >= di->bm->temp_over) {
 			/* TEMP major!!!!! */
 			di->events.btemp_underover = true;
 			di->events.btemp_lowhigh = false;
 			di->t_hyst_norm = 0;
-			di->t_hyst_lowhigh = di->bat->temp_hysteresis;
+			di->t_hyst_lowhigh = di->bm->temp_hysteresis;
 		} else {
 		/* Within hysteresis */
 		dev_dbg(di->dev, "Within hysteresis limit temp: %d "
@@ -682,12 +693,12 @@
  */
 static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di)
 {
-	if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max)
+	if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max)
 		di->chg_info.usb_chg_ok = false;
 	else
 		di->chg_info.usb_chg_ok = true;
 
-	if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max)
+	if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max)
 		di->chg_info.ac_chg_ok = false;
 	else
 		di->chg_info.ac_chg_ok = true;
@@ -707,10 +718,10 @@
 	if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
 		di->charge_state == STATE_NORMAL &&
 		!di->maintenance_chg && (di->batt_data.volt >=
-		di->bat->bat_type[di->bat->batt_id].termination_vol ||
+		di->bm->bat_type[di->bm->batt_id].termination_vol ||
 		di->events.usb_cv_active || di->events.ac_cv_active) &&
 		di->batt_data.avg_curr <
-		di->bat->bat_type[di->bat->batt_id].termination_curr &&
+		di->bm->bat_type[di->bm->batt_id].termination_curr &&
 		di->batt_data.avg_curr > 0) {
 		if (++di->eoc_cnt >= EOC_COND_CNT) {
 			di->eoc_cnt = 0;
@@ -733,12 +744,12 @@
 static void init_maxim_chg_curr(struct abx500_chargalg *di)
 {
 	di->ccm.original_iset =
-		di->bat->bat_type[di->bat->batt_id].normal_cur_lvl;
+		di->bm->bat_type[di->bm->batt_id].normal_cur_lvl;
 	di->ccm.current_iset =
-		di->bat->bat_type[di->bat->batt_id].normal_cur_lvl;
-	di->ccm.test_delta_i = di->bat->maxi->charger_curr_step;
-	di->ccm.max_current = di->bat->maxi->chg_curr;
-	di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+		di->bm->bat_type[di->bm->batt_id].normal_cur_lvl;
+	di->ccm.test_delta_i = di->bm->maxi->charger_curr_step;
+	di->ccm.max_current = di->bm->maxi->chg_curr;
+	di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
 	di->ccm.level = 0;
 }
 
@@ -755,7 +766,7 @@
 {
 	int delta_i;
 
-	if (!di->bat->maxi->ena_maxi)
+	if (!di->bm->maxi->ena_maxi)
 		return MAXIM_RET_NOACTION;
 
 	delta_i = di->ccm.original_iset - di->batt_data.inst_curr;
@@ -766,7 +777,7 @@
 		if (di->ccm.wait_cnt == 0) {
 			dev_dbg(di->dev, "lowering current\n");
 			di->ccm.wait_cnt++;
-			di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+			di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
 			di->ccm.max_current =
 				di->ccm.current_iset - di->ccm.test_delta_i;
 			di->ccm.current_iset = di->ccm.max_current;
@@ -791,7 +802,7 @@
 		if (di->ccm.current_iset == di->ccm.original_iset)
 			return MAXIM_RET_NOACTION;
 
-		di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+		di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
 		di->ccm.current_iset = di->ccm.original_iset;
 		di->ccm.level = 0;
 
@@ -803,7 +814,7 @@
 		di->ccm.max_current) {
 		if (di->ccm.condition_cnt-- == 0) {
 			/* Increse the iset with cco.test_delta_i */
-			di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+			di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
 			di->ccm.current_iset += di->ccm.test_delta_i;
 			di->ccm.level++;
 			dev_dbg(di->dev, " Maximization needed, increase"
@@ -818,7 +829,7 @@
 			return MAXIM_RET_NOACTION;
 		}
 	}  else {
-		di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+		di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
 		return MAXIM_RET_NOACTION;
 	}
 }
@@ -838,7 +849,7 @@
 		break;
 	case MAXIM_RET_IBAT_TOO_HIGH:
 		result = abx500_chargalg_update_chg_curr(di,
-			di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+			di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
 		if (result)
 			dev_err(di->dev, "failed to set chg curr\n");
 		break;
@@ -858,6 +869,7 @@
 	union power_supply_propval ret;
 	int i, j;
 	bool psy_found = false;
+	bool capacity_updated = false;
 
 	psy = (struct power_supply *)data;
 	ext = dev_get_drvdata(dev);
@@ -870,6 +882,16 @@
 	if (!psy_found)
 		return 0;
 
+	/*
+	 *  If external is not registering 'POWER_SUPPLY_PROP_CAPACITY' to its
+	 * property because of handling that sysfs entry on its own, this is
+	 * the place to get the battery capacity.
+	 */
+	if (!ext->get_property(ext, POWER_SUPPLY_PROP_CAPACITY, &ret)) {
+		di->batt_data.percent = ret.intval;
+		capacity_updated = true;
+	}
+
 	/* Go through all properties for the psy */
 	for (j = 0; j < ext->num_properties; j++) {
 		enum power_supply_property prop;
@@ -1154,7 +1176,8 @@
 			}
 			break;
 		case POWER_SUPPLY_PROP_CAPACITY:
-			di->batt_data.percent = ret.intval;
+			if (!capacity_updated)
+				di->batt_data.percent = ret.intval;
 			break;
 		default:
 			break;
@@ -1210,7 +1233,7 @@
 	 * this way
 	 */
 	if (!charger_status ||
-		(di->events.batt_unknown && !di->bat->chg_unknown_bat)) {
+		(di->events.batt_unknown && !di->bm->chg_unknown_bat)) {
 		if (di->charge_state != STATE_HANDHELD) {
 			di->events.safety_timer_expired = false;
 			abx500_chargalg_state_to(di, STATE_HANDHELD_INIT);
@@ -1394,8 +1417,8 @@
 
 	case STATE_NORMAL_INIT:
 		abx500_chargalg_start_charging(di,
-			di->bat->bat_type[di->bat->batt_id].normal_vol_lvl,
-			di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+			di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
+			di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
 		abx500_chargalg_state_to(di, STATE_NORMAL);
 		abx500_chargalg_start_safety_timer(di);
 		abx500_chargalg_stop_maintenance_timer(di);
@@ -1411,7 +1434,7 @@
 		handle_maxim_chg_curr(di);
 		if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
 			di->maintenance_chg) {
-			if (di->bat->no_maintenance)
+			if (di->bm->no_maintenance)
 				abx500_chargalg_state_to(di,
 					STATE_WAIT_FOR_RECHARGE_INIT);
 			else
@@ -1424,28 +1447,25 @@
 	case STATE_WAIT_FOR_RECHARGE_INIT:
 		abx500_chargalg_hold_charging(di);
 		abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE);
-		di->rch_cnt = RCH_COND_CNT;
 		/* Intentional fallthrough */
 
 	case STATE_WAIT_FOR_RECHARGE:
-		if (di->batt_data.volt <=
-			di->bat->bat_type[di->bat->batt_id].recharge_vol) {
-			if (di->rch_cnt-- == 0)
-				abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
-		} else
-			di->rch_cnt = RCH_COND_CNT;
+		if (di->batt_data.percent <=
+		    di->bm->bat_type[di->bm->batt_id].
+		    recharge_cap)
+			abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
 		break;
 
 	case STATE_MAINTENANCE_A_INIT:
 		abx500_chargalg_stop_safety_timer(di);
 		abx500_chargalg_start_maintenance_timer(di,
-			di->bat->bat_type[
-				di->bat->batt_id].maint_a_chg_timer_h);
+			di->bm->bat_type[
+				di->bm->batt_id].maint_a_chg_timer_h);
 		abx500_chargalg_start_charging(di,
-			di->bat->bat_type[
-				di->bat->batt_id].maint_a_vol_lvl,
-			di->bat->bat_type[
-				di->bat->batt_id].maint_a_cur_lvl);
+			di->bm->bat_type[
+				di->bm->batt_id].maint_a_vol_lvl,
+			di->bm->bat_type[
+				di->bm->batt_id].maint_a_cur_lvl);
 		abx500_chargalg_state_to(di, STATE_MAINTENANCE_A);
 		power_supply_changed(&di->chargalg_psy);
 		/* Intentional fallthrough*/
@@ -1459,13 +1479,13 @@
 
 	case STATE_MAINTENANCE_B_INIT:
 		abx500_chargalg_start_maintenance_timer(di,
-			di->bat->bat_type[
-				di->bat->batt_id].maint_b_chg_timer_h);
+			di->bm->bat_type[
+				di->bm->batt_id].maint_b_chg_timer_h);
 		abx500_chargalg_start_charging(di,
-			di->bat->bat_type[
-				di->bat->batt_id].maint_b_vol_lvl,
-			di->bat->bat_type[
-				di->bat->batt_id].maint_b_cur_lvl);
+			di->bm->bat_type[
+				di->bm->batt_id].maint_b_vol_lvl,
+			di->bm->bat_type[
+				di->bm->batt_id].maint_b_cur_lvl);
 		abx500_chargalg_state_to(di, STATE_MAINTENANCE_B);
 		power_supply_changed(&di->chargalg_psy);
 		/* Intentional fallthrough*/
@@ -1479,10 +1499,10 @@
 
 	case STATE_TEMP_LOWHIGH_INIT:
 		abx500_chargalg_start_charging(di,
-			di->bat->bat_type[
-				di->bat->batt_id].low_high_vol_lvl,
-			di->bat->bat_type[
-				di->bat->batt_id].low_high_cur_lvl);
+			di->bm->bat_type[
+				di->bm->batt_id].low_high_vol_lvl,
+			di->bm->bat_type[
+				di->bm->batt_id].low_high_cur_lvl);
 		abx500_chargalg_stop_maintenance_timer(di);
 		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
 		abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH);
@@ -1543,11 +1563,11 @@
 	if (di->chg_info.conn_chg)
 		queue_delayed_work(di->chargalg_wq,
 			&di->chargalg_periodic_work,
-			di->bat->interval_charging * HZ);
+			di->bm->interval_charging * HZ);
 	else
 		queue_delayed_work(di->chargalg_wq,
 			&di->chargalg_periodic_work,
-			di->bat->interval_not_charging * HZ);
+			di->bm->interval_not_charging * HZ);
 }
 
 /**
@@ -1614,10 +1634,13 @@
 		if (di->events.batt_ovv) {
 			val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
 		} else if (di->events.btemp_underover) {
-			if (di->batt_data.temp <= di->bat->temp_under)
+			if (di->batt_data.temp <= di->bm->temp_under)
 				val->intval = POWER_SUPPLY_HEALTH_COLD;
 			else
 				val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		} else if (di->charge_state == STATE_SAFETY_TIMER_EXPIRED ||
+			   di->charge_state == STATE_SAFETY_TIMER_EXPIRED_INIT) {
+			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
 		} else {
 			val->intval = POWER_SUPPLY_HEALTH_GOOD;
 		}
@@ -1631,6 +1654,25 @@
 /* Exposure to the sysfs interface */
 
 /**
+ * abx500_chargalg_sysfs_show() - sysfs show operations
+ * @kobj:      pointer to the struct kobject
+ * @attr:      pointer to the struct attribute
+ * @buf:       buffer that holds the parameter to send to userspace
+ *
+ * Returns a buffer to be displayed in user space
+ */
+static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
+					  struct attribute *attr, char *buf)
+{
+	struct abx500_chargalg *di = container_of(kobj,
+               struct abx500_chargalg, chargalg_kobject);
+
+	return sprintf(buf, "%d\n",
+		       di->susp_status.ac_suspended &&
+		       di->susp_status.usb_suspended);
+}
+
+/**
  * abx500_chargalg_sysfs_charger() - sysfs store operations
  * @kobj:      pointer to the struct kobject
  * @attr:      pointer to the struct attribute
@@ -1698,7 +1740,7 @@
 static struct attribute abx500_chargalg_en_charger = \
 {
 	.name = "chargalg",
-	.mode = S_IWUGO,
+	.mode = S_IRUGO | S_IWUSR,
 };
 
 static struct attribute *abx500_chargalg_chg[] = {
@@ -1707,6 +1749,7 @@
 };
 
 static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
+	.show = abx500_chargalg_sysfs_show,
 	.store = abx500_chargalg_sysfs_charger,
 };
 
@@ -1806,6 +1849,7 @@
 static int abx500_chargalg_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct abx500_bm_data *plat = pdev->dev.platform_data;
 	struct abx500_chargalg *di;
 	int ret = 0;
 
@@ -1814,21 +1858,19 @@
 		dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
 		return -ENOMEM;
 	}
-	di->bat = pdev->mfd_cell->platform_data;
-	if (!di->bat) {
-		if (np) {
-			ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
-			if (ret) {
-				dev_err(&pdev->dev,
-					"failed to get battery information\n");
-				return ret;
-			}
-		} else {
-			dev_err(&pdev->dev, "missing dt node for ab8500_chargalg\n");
-			return -EINVAL;
+
+	if (!plat) {
+		dev_err(&pdev->dev, "no battery management data supplied\n");
+		return -EINVAL;
+	}
+	di->bm = plat;
+
+	if (np) {
+		ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to get battery information\n");
+			return ret;
 		}
-	} else {
-		dev_info(&pdev->dev, "falling back to legacy platform data\n");
 	}
 
 	/* get device struct */
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c
index ee842b3..ca91396 100644
--- a/drivers/power/bq2415x_charger.c
+++ b/drivers/power/bq2415x_charger.c
@@ -28,7 +28,6 @@
  * http://www.ti.com/product/bq24155
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/param.h>
@@ -734,12 +733,10 @@
 	int charger = 0;
 	int boost = 0;
 
-	if (mode == BQ2415X_MODE_HOST_CHARGER ||
-		mode == BQ2415X_MODE_DEDICATED_CHARGER)
-			charger = 1;
-
 	if (mode == BQ2415X_MODE_BOOST)
 		boost = 1;
+	else if (mode != BQ2415X_MODE_OFF)
+		charger = 1;
 
 	if (!charger)
 		ret = bq2415x_exec_command(bq, BQ2415X_CHARGER_DISABLE);
@@ -751,6 +748,10 @@
 		return ret;
 
 	switch (mode) {
+	case BQ2415X_MODE_OFF:
+		dev_dbg(bq->dev, "changing mode to: Offline\n");
+		ret = bq2415x_set_current_limit(bq, 100);
+		break;
 	case BQ2415X_MODE_NONE:
 		dev_dbg(bq->dev, "changing mode to: N/A\n");
 		ret = bq2415x_set_current_limit(bq, 100);
@@ -843,7 +844,7 @@
 	dev_err(bq->dev, "%s\n", msg);
 	if (bq->automode > 0)
 		bq->automode = 0;
-	bq2415x_set_mode(bq, BQ2415X_MODE_NONE);
+	bq2415x_set_mode(bq, BQ2415X_MODE_OFF);
 	bq2415x_set_autotimer(bq, 0);
 }
 
@@ -1136,6 +1137,10 @@
 			return -ENOSYS;
 		bq->automode = 1;
 		mode = bq->reported_mode;
+	} else if (strncmp(buf, "off", 3) == 0) {
+		if (bq->automode > 0)
+			bq->automode = 0;
+		mode = BQ2415X_MODE_OFF;
 	} else if (strncmp(buf, "none", 4) == 0) {
 		if (bq->automode > 0)
 			bq->automode = 0;
@@ -1183,6 +1188,9 @@
 		ret += sprintf(buf+ret, "auto (");
 
 	switch (bq->mode) {
+	case BQ2415X_MODE_OFF:
+		ret += sprintf(buf+ret, "off");
+		break;
 	case BQ2415X_MODE_NONE:
 		ret += sprintf(buf+ret, "none");
 		break;
@@ -1217,6 +1225,8 @@
 		return -EINVAL;
 
 	switch (bq->reported_mode) {
+	case BQ2415X_MODE_OFF:
+		return sprintf(buf, "off\n");
 	case BQ2415X_MODE_NONE:
 		return sprintf(buf, "none\n");
 	case BQ2415X_MODE_HOST_CHARGER:
@@ -1523,7 +1533,7 @@
 		goto error_1;
 	}
 
-	bq = kzalloc(sizeof(*bq), GFP_KERNEL);
+	bq = devm_kzalloc(&client->dev, sizeof(*bq), GFP_KERNEL);
 	if (!bq) {
 		dev_err(&client->dev, "failed to allocate device data\n");
 		ret = -ENOMEM;
@@ -1536,8 +1546,8 @@
 	bq->dev = &client->dev;
 	bq->chip = id->driver_data;
 	bq->name = name;
-	bq->mode = BQ2415X_MODE_NONE;
-	bq->reported_mode = BQ2415X_MODE_NONE;
+	bq->mode = BQ2415X_MODE_OFF;
+	bq->reported_mode = BQ2415X_MODE_OFF;
 	bq->autotimer = 0;
 	bq->automode = 0;
 
@@ -1549,19 +1559,19 @@
 	ret = bq2415x_power_supply_init(bq);
 	if (ret) {
 		dev_err(bq->dev, "failed to register power supply: %d\n", ret);
-		goto error_3;
+		goto error_2;
 	}
 
 	ret = bq2415x_sysfs_init(bq);
 	if (ret) {
 		dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret);
-		goto error_4;
+		goto error_3;
 	}
 
 	ret = bq2415x_set_defaults(bq);
 	if (ret) {
 		dev_err(bq->dev, "failed to set default values: %d\n", ret);
-		goto error_5;
+		goto error_4;
 	}
 
 	if (bq->init_data.set_mode_hook) {
@@ -1585,12 +1595,10 @@
 	dev_info(bq->dev, "driver registered\n");
 	return 0;
 
-error_5:
-	bq2415x_sysfs_exit(bq);
 error_4:
-	bq2415x_power_supply_exit(bq);
+	bq2415x_sysfs_exit(bq);
 error_3:
-	kfree(bq);
+	bq2415x_power_supply_exit(bq);
 error_2:
 	kfree(name);
 error_1:
@@ -1622,7 +1630,6 @@
 	dev_info(bq->dev, "driver unregistered\n");
 
 	kfree(bq->name);
-	kfree(bq);
 
 	return 0;
 }
@@ -1652,18 +1659,7 @@
 	.remove = bq2415x_remove,
 	.id_table = bq2415x_i2c_id_table,
 };
-
-static int __init bq2415x_init(void)
-{
-	return i2c_add_driver(&bq2415x_driver);
-}
-module_init(bq2415x_init);
-
-static void __exit bq2415x_exit(void)
-{
-	i2c_del_driver(&bq2415x_driver);
-}
-module_exit(bq2415x_exit);
+module_i2c_driver(bq2415x_driver);
 
 MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
 MODULE_DESCRIPTION("bq2415x charger driver");
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 36b34ef..8ccf5d7 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -299,7 +299,7 @@
 }
 
 /*
- * Return the battery temperature in tenths of degree Celsius
+ * Return the battery temperature in tenths of degree Kelvin
  * Or < 0 if something fails.
  */
 static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
@@ -312,10 +312,8 @@
 		return temp;
 	}
 
-	if (bq27xxx_is_chip_version_higher(di))
-		temp -= 2731;
-	else
-		temp = ((temp * 5) - 5463) / 2;
+	if (!bq27xxx_is_chip_version_higher(di))
+		temp = 5 * temp / 2;
 
 	return temp;
 }
@@ -448,7 +446,6 @@
 		cache.temperature = bq27x00_battery_read_temperature(di);
 		if (!is_bq27425)
 			cache.cycle_count = bq27x00_battery_read_cyct(di);
-		cache.cycle_count = bq27x00_battery_read_cyct(di);
 		cache.power_avg =
 			bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG);
 
@@ -642,6 +639,8 @@
 		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		ret = bq27x00_simple_value(di->cache.temperature, val);
+		if (ret == 0)
+			val->intval -= 2731;
 		break;
 	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
 		ret = bq27x00_simple_value(di->cache.time_to_empty, val);
@@ -696,7 +695,6 @@
 	int ret;
 
 	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
-	di->chip = BQ27425;
 	if (di->chip == BQ27425) {
 		di->bat.properties = bq27425_battery_props;
 		di->bat.num_properties = ARRAY_SIZE(bq27425_battery_props);
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 6ba047f..8acc3f8 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -669,15 +669,21 @@
 	WARN(cm_wq == NULL, "charger-manager: workqueue not initialized"
 			    ". try it later. %s\n", __func__);
 
+	/*
+	 * Use mod_delayed_work() iff the next polling interval should
+	 * occur before the currently scheduled one.  If @cm_monitor_work
+	 * isn't active, the end result is the same, so no need to worry
+	 * about stale @next_polling.
+	 */
 	_next_polling = jiffies + polling_jiffy;
 
-	if (!delayed_work_pending(&cm_monitor_work) ||
-	    (delayed_work_pending(&cm_monitor_work) &&
-	     time_after(next_polling, _next_polling))) {
-		next_polling = jiffies + polling_jiffy;
+	if (time_before(_next_polling, next_polling)) {
 		mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy);
+		next_polling = _next_polling;
+	} else {
+		if (queue_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy))
+			next_polling = _next_polling;
 	}
-
 out:
 	mutex_unlock(&cm_list_mtx);
 }
@@ -751,8 +757,7 @@
 	if (cm_suspended)
 		device_set_wakeup_capable(cm->dev, true);
 
-	if (!delayed_work_pending(&cm_monitor_work) &&
-	    is_polling_required(cm) && cm->desc->polling_interval_ms)
+	if (is_polling_required(cm) && cm->desc->polling_interval_ms)
 		schedule_work(&setup_polling);
 	uevent_notify(cm, default_event_names[type]);
 }
@@ -1170,8 +1175,7 @@
 	 * when charger cable is attached.
 	 */
 	if (cable->attached && is_polling_required(cable->cm)) {
-		if (work_pending(&setup_polling))
-			cancel_work_sync(&setup_polling);
+		cancel_work_sync(&setup_polling);
 		schedule_work(&setup_polling);
 	}
 
@@ -1215,6 +1219,55 @@
 	return ret;
 }
 
+/**
+ * charger_manager_register_extcon - Register extcon device to recevie state
+ *				     of charger cable.
+ * @cm: the Charger Manager representing the battery.
+ *
+ * This function support EXTCON(External Connector) subsystem to detect the
+ * state of charger cables for enabling or disabling charger(regulator) and
+ * select the charger cable for charging among a number of external cable
+ * according to policy of H/W board.
+ */
+static int charger_manager_register_extcon(struct charger_manager *cm)
+{
+	struct charger_desc *desc = cm->desc;
+	struct charger_regulator *charger;
+	int ret = 0;
+	int i;
+	int j;
+
+	for (i = 0; i < desc->num_charger_regulators; i++) {
+		charger = &desc->charger_regulators[i];
+
+		charger->consumer = regulator_get(cm->dev,
+					charger->regulator_name);
+		if (charger->consumer == NULL) {
+			dev_err(cm->dev, "Cannot find charger(%s)n",
+					charger->regulator_name);
+			ret = -EINVAL;
+			goto err;
+		}
+		charger->cm = cm;
+
+		for (j = 0; j < charger->num_cables; j++) {
+			struct charger_cable *cable = &charger->cables[j];
+
+			ret = charger_extcon_init(cm, cable);
+			if (ret < 0) {
+				dev_err(cm->dev, "Cannot initialize charger(%s)n",
+						charger->regulator_name);
+				goto err;
+			}
+			cable->charger = charger;
+			cable->cm = cm;
+		}
+	}
+
+err:
+	return ret;
+}
+
 /* help function of sysfs node to control charger(regulator) */
 static ssize_t charger_name_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -1274,7 +1327,7 @@
 
 	for (i = 0; i < desc->num_charger_regulators; i++) {
 		if (&desc->charger_regulators[i] != charger &&
-			      !desc->charger_regulators[i].externally_control) {
+			!desc->charger_regulators[i].externally_control) {
 			/*
 			 * At least, one charger is controlled by
 			 * charger-manager
@@ -1303,13 +1356,107 @@
 	return count;
 }
 
+/**
+ * charger_manager_register_sysfs - Register sysfs entry for each charger
+ * @cm: the Charger Manager representing the battery.
+ *
+ * This function add sysfs entry for charger(regulator) to control charger from
+ * user-space. If some development board use one more chargers for charging
+ * but only need one charger on specific case which is dependent on user
+ * scenario or hardware restrictions, the user enter 1 or 0(zero) to '/sys/
+ * class/power_supply/battery/charger.[index]/externally_control'. For example,
+ * if user enter 1 to 'sys/class/power_supply/battery/charger.[index]/
+ * externally_control, this charger isn't controlled from charger-manager and
+ * always stay off state of regulator.
+ */
+static int charger_manager_register_sysfs(struct charger_manager *cm)
+{
+	struct charger_desc *desc = cm->desc;
+	struct charger_regulator *charger;
+	int chargers_externally_control = 1;
+	char buf[11];
+	char *str;
+	int ret = 0;
+	int i;
+
+	/* Create sysfs entry to control charger(regulator) */
+	for (i = 0; i < desc->num_charger_regulators; i++) {
+		charger = &desc->charger_regulators[i];
+
+		snprintf(buf, 10, "charger.%d", i);
+		str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
+		if (!str) {
+			dev_err(cm->dev, "Cannot allocate memory: %s\n",
+					charger->regulator_name);
+			ret = -ENOMEM;
+			goto err;
+		}
+		strcpy(str, buf);
+
+		charger->attrs[0] = &charger->attr_name.attr;
+		charger->attrs[1] = &charger->attr_state.attr;
+		charger->attrs[2] = &charger->attr_externally_control.attr;
+		charger->attrs[3] = NULL;
+		charger->attr_g.name = str;
+		charger->attr_g.attrs = charger->attrs;
+
+		sysfs_attr_init(&charger->attr_name.attr);
+		charger->attr_name.attr.name = "name";
+		charger->attr_name.attr.mode = 0444;
+		charger->attr_name.show = charger_name_show;
+
+		sysfs_attr_init(&charger->attr_state.attr);
+		charger->attr_state.attr.name = "state";
+		charger->attr_state.attr.mode = 0444;
+		charger->attr_state.show = charger_state_show;
+
+		sysfs_attr_init(&charger->attr_externally_control.attr);
+		charger->attr_externally_control.attr.name
+				= "externally_control";
+		charger->attr_externally_control.attr.mode = 0644;
+		charger->attr_externally_control.show
+				= charger_externally_control_show;
+		charger->attr_externally_control.store
+				= charger_externally_control_store;
+
+		if (!desc->charger_regulators[i].externally_control ||
+				!chargers_externally_control)
+			chargers_externally_control = 0;
+
+		dev_info(cm->dev, "'%s' regulator's externally_control"
+				"is %d\n", charger->regulator_name,
+				charger->externally_control);
+
+		ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
+					&charger->attr_g);
+		if (ret < 0) {
+			dev_err(cm->dev, "Cannot create sysfs entry"
+					"of %s regulator\n",
+					charger->regulator_name);
+			ret = -EINVAL;
+			goto err;
+		}
+	}
+
+	if (chargers_externally_control) {
+		dev_err(cm->dev, "Cannot register regulator because "
+				"charger-manager must need at least "
+				"one charger for charging battery\n");
+
+		ret = -EINVAL;
+		goto err;
+	}
+
+err:
+	return ret;
+}
+
 static int charger_manager_probe(struct platform_device *pdev)
 {
 	struct charger_desc *desc = dev_get_platdata(&pdev->dev);
 	struct charger_manager *cm;
 	int ret = 0, i = 0;
 	int j = 0;
-	int chargers_externally_control = 1;
 	union power_supply_propval val;
 
 	if (g_desc && !rtc_dev && g_desc->rtc_name) {
@@ -1440,11 +1587,10 @@
 
 	memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default));
 
-	if (!desc->psy_name) {
+	if (!desc->psy_name)
 		strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX);
-	} else {
+	else
 		strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
-	}
 	cm->charger_psy.name = cm->psy_name_buf;
 
 	/* Allocate for psy properties because they may vary */
@@ -1496,105 +1642,19 @@
 		goto err_register;
 	}
 
-	for (i = 0 ; i < desc->num_charger_regulators ; i++) {
-		struct charger_regulator *charger
-					= &desc->charger_regulators[i];
-		char buf[11];
-		char *str;
-
-		charger->consumer = regulator_get(&pdev->dev,
-					charger->regulator_name);
-		if (charger->consumer == NULL) {
-			dev_err(&pdev->dev, "Cannot find charger(%s)n",
-						charger->regulator_name);
-			ret = -EINVAL;
-			goto err_chg_get;
-		}
-		charger->cm = cm;
-
-		for (j = 0 ; j < charger->num_cables ; j++) {
-			struct charger_cable *cable = &charger->cables[j];
-
-			ret = charger_extcon_init(cm, cable);
-			if (ret < 0) {
-				dev_err(&pdev->dev, "Cannot find charger(%s)n",
-						charger->regulator_name);
-				goto err_extcon;
-			}
-			cable->charger = charger;
-			cable->cm = cm;
-		}
-
-		/* Create sysfs entry to control charger(regulator) */
-		snprintf(buf, 10, "charger.%d", i);
-		str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
-		if (!str) {
-			for (i--; i >= 0; i--) {
-				charger = &desc->charger_regulators[i];
-				kfree(charger->attr_g.name);
-			}
-			ret = -ENOMEM;
-
-			goto err_extcon;
-		}
-		strcpy(str, buf);
-
-		charger->attrs[0] = &charger->attr_name.attr;
-		charger->attrs[1] = &charger->attr_state.attr;
-		charger->attrs[2] = &charger->attr_externally_control.attr;
-		charger->attrs[3] = NULL;
-		charger->attr_g.name = str;
-		charger->attr_g.attrs = charger->attrs;
-
-		sysfs_attr_init(&charger->attr_name.attr);
-		charger->attr_name.attr.name = "name";
-		charger->attr_name.attr.mode = 0444;
-		charger->attr_name.show = charger_name_show;
-
-		sysfs_attr_init(&charger->attr_state.attr);
-		charger->attr_state.attr.name = "state";
-		charger->attr_state.attr.mode = 0444;
-		charger->attr_state.show = charger_state_show;
-
-		sysfs_attr_init(&charger->attr_externally_control.attr);
-		charger->attr_externally_control.attr.name
-				= "externally_control";
-		charger->attr_externally_control.attr.mode = 0644;
-		charger->attr_externally_control.show
-				= charger_externally_control_show;
-		charger->attr_externally_control.store
-				= charger_externally_control_store;
-
-		if (!desc->charger_regulators[i].externally_control ||
-				!chargers_externally_control) {
-			chargers_externally_control = 0;
-		}
-		dev_info(&pdev->dev, "'%s' regulator's externally_control"
-				"is %d\n", charger->regulator_name,
-				charger->externally_control);
-
-		ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
-				&charger->attr_g);
-		if (ret < 0) {
-			dev_info(&pdev->dev, "Cannot create sysfs entry"
-					"of %s regulator\n",
-					charger->regulator_name);
-		}
+	/* Register extcon device for charger cable */
+	ret = charger_manager_register_extcon(cm);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Cannot initialize extcon device\n");
+		goto err_reg_extcon;
 	}
 
-	if (chargers_externally_control) {
-		dev_err(&pdev->dev, "Cannot register regulator because "
-				"charger-manager must need at least "
-				"one charger for charging battery\n");
-
-		ret = -EINVAL;
-		goto err_chg_enable;
-	}
-
-	ret = try_charger_enable(cm, true);
-	if (ret) {
-		dev_err(&pdev->dev, "Cannot enable charger regulators\n");
-		goto err_chg_enable;
+	/* Register sysfs entry for charger(regulator) */
+	ret = charger_manager_register_sysfs(cm);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Cannot initialize sysfs entry of regulator\n");
+		goto err_reg_sysfs;
 	}
 
 	/* Add to the list */
@@ -1613,27 +1673,28 @@
 
 	return 0;
 
-err_chg_enable:
+err_reg_sysfs:
 	for (i = 0; i < desc->num_charger_regulators; i++) {
 		struct charger_regulator *charger;
 
 		charger = &desc->charger_regulators[i];
 		sysfs_remove_group(&cm->charger_psy.dev->kobj,
 				&charger->attr_g);
+
 		kfree(charger->attr_g.name);
 	}
-err_extcon:
-	for (i = 0 ; i < desc->num_charger_regulators ; i++) {
-		struct charger_regulator *charger
-				= &desc->charger_regulators[i];
-		for (j = 0 ; j < charger->num_cables ; j++) {
+err_reg_extcon:
+	for (i = 0; i < desc->num_charger_regulators; i++) {
+		struct charger_regulator *charger;
+
+		charger = &desc->charger_regulators[i];
+		for (j = 0; j < charger->num_cables; j++) {
 			struct charger_cable *cable = &charger->cables[j];
 			extcon_unregister_interest(&cable->extcon_dev);
 		}
-	}
-err_chg_get:
-	for (i = 0 ; i < desc->num_charger_regulators ; i++)
+
 		regulator_put(desc->charger_regulators[i].consumer);
+	}
 
 	power_supply_unregister(&cm->charger_psy);
 err_register:
@@ -1661,10 +1722,8 @@
 	list_del(&cm->entry);
 	mutex_unlock(&cm_list_mtx);
 
-	if (work_pending(&setup_polling))
-		cancel_work_sync(&setup_polling);
-	if (delayed_work_pending(&cm_monitor_work))
-		cancel_delayed_work_sync(&cm_monitor_work);
+	cancel_work_sync(&setup_polling);
+	cancel_delayed_work_sync(&cm_monitor_work);
 
 	for (i = 0 ; i < desc->num_charger_regulators ; i++) {
 		struct charger_regulator *charger
@@ -1733,8 +1792,7 @@
 		cm_suspended = true;
 	}
 
-	if (delayed_work_pending(&cm->fullbatt_vchk_work))
-		cancel_delayed_work(&cm->fullbatt_vchk_work);
+	cancel_delayed_work(&cm->fullbatt_vchk_work);
 	cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm);
 	cm->status_save_batt = is_batt_present(cm);
 
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
index 94762e6..e8c5a39 100644
--- a/drivers/power/da9030_battery.c
+++ b/drivers/power/da9030_battery.c
@@ -22,6 +22,7 @@
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/notifier.h>
 
 #define DA9030_FAULT_LOG		0x0a
 #define DA9030_FAULT_LOG_OVER_TEMP	(1 << 7)
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c
index 3c5c2e4..08193fe 100644
--- a/drivers/power/da9052-battery.c
+++ b/drivers/power/da9052-battery.c
@@ -337,7 +337,7 @@
 	if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1])
 		return DA9052_VC_TBL_REF_SZ - 1;
 
-	for (i = 0; i < DA9052_VC_TBL_REF_SZ; i++) {
+	for (i = 0; i < DA9052_VC_TBL_REF_SZ - 1; i++) {
 		if ((adc_temp > vc_tbl_ref[i]) &&
 		    (adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])))
 				return i;
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index 2fa9b6b..e7301b3 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -7,6 +7,8 @@
  *
  * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
  *
+ * UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru>
+ *
  * 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.
@@ -19,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/swab.h>
 #include <linux/i2c.h>
+#include <linux/delay.h>
 #include <linux/idr.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
@@ -40,6 +43,8 @@
 
 #define DS2786_CURRENT_UNITS	25
 
+#define DS278x_DELAY		1000
+
 struct ds278x_info;
 
 struct ds278x_battery_ops {
@@ -54,8 +59,11 @@
 	struct i2c_client	*client;
 	struct power_supply	battery;
 	struct ds278x_battery_ops  *ops;
+	struct delayed_work	bat_work;
 	int			id;
 	int                     rsns;
+	int			capacity;
+	int			status;		/* State Of Charge */
 };
 
 static DEFINE_IDR(battery_id);
@@ -220,6 +228,8 @@
 	if (err)
 		return err;
 
+	info->capacity = capacity;
+
 	if (capacity == 100)
 		*status = POWER_SUPPLY_STATUS_FULL;
 	else if (current_uA == 0)
@@ -267,6 +277,27 @@
 	return ret;
 }
 
+static void ds278x_bat_update(struct ds278x_info *info)
+{
+	int old_status = info->status;
+	int old_capacity = info->capacity;
+
+	ds278x_get_status(info, &info->status);
+
+	if ((old_status != info->status) || (old_capacity != info->capacity))
+		power_supply_changed(&info->battery);
+}
+
+static void ds278x_bat_work(struct work_struct *work)
+{
+	struct ds278x_info *info;
+
+	info = container_of(work, struct ds278x_info, bat_work.work);
+	ds278x_bat_update(info);
+
+	schedule_delayed_work(&info->bat_work, DS278x_DELAY);
+}
+
 static enum power_supply_property ds278x_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CAPACITY,
@@ -295,10 +326,39 @@
 	idr_remove(&battery_id, info->id);
 	mutex_unlock(&battery_lock);
 
+	cancel_delayed_work(&info->bat_work);
+
 	kfree(info);
 	return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int ds278x_suspend(struct i2c_client *client,
+		pm_message_t state)
+{
+	struct ds278x_info *info = i2c_get_clientdata(client);
+
+	cancel_delayed_work(&info->bat_work);
+	return 0;
+}
+
+static int ds278x_resume(struct i2c_client *client)
+{
+	struct ds278x_info *info = i2c_get_clientdata(client);
+
+	schedule_delayed_work(&info->bat_work, DS278x_DELAY);
+	return 0;
+}
+
+#else
+
+#define ds278x_suspend NULL
+#define ds278x_resume NULL
+
+#endif /* CONFIG_PM */
+
+
 enum ds278x_num_id {
 	DS2782 = 0,
 	DS2786,
@@ -368,10 +428,17 @@
 	info->ops  = &ds278x_ops[id->driver_data];
 	ds278x_power_supply_init(&info->battery);
 
+	info->capacity = 100;
+	info->status = POWER_SUPPLY_STATUS_FULL;
+
+	INIT_DELAYED_WORK(&info->bat_work, ds278x_bat_work);
+
 	ret = power_supply_register(&client->dev, &info->battery);
 	if (ret) {
 		dev_err(&client->dev, "failed to register battery\n");
 		goto fail_register;
+	} else {
+		schedule_delayed_work(&info->bat_work, DS278x_DELAY);
 	}
 
 	return 0;
@@ -401,6 +468,8 @@
 	},
 	.probe		= ds278x_battery_probe,
 	.remove		= ds278x_battery_remove,
+	.suspend	= ds278x_suspend,
+	.resume		= ds278x_resume,
 	.id_table	= ds278x_id,
 };
 module_i2c_driver(ds278x_battery_driver);
diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c
index 32ce17e..836816b 100644
--- a/drivers/power/generic-adc-battery.c
+++ b/drivers/power/generic-adc-battery.c
@@ -263,9 +263,6 @@
 	psy->external_power_changed = gab_ext_power_changed;
 	adc_bat->pdata = pdata;
 
-	/* calculate the total number of channels */
-	chan = ARRAY_SIZE(gab_chan_name);
-
 	/*
 	 * copying the static properties and allocating extra memory for holding
 	 * the extra configurable properties received from platform data.
@@ -291,6 +288,7 @@
 						gab_chan_name[chan]);
 		if (IS_ERR(adc_bat->channel[chan])) {
 			ret = PTR_ERR(adc_bat->channel[chan]);
+			adc_bat->channel[chan] = NULL;
 		} else {
 			/* copying properties for supported channels only */
 			memcpy(properties + sizeof(*(psy->properties)) * index,
@@ -344,8 +342,10 @@
 gpio_req_fail:
 	power_supply_unregister(psy);
 err_reg_fail:
-	for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++)
-		iio_channel_release(adc_bat->channel[chan]);
+	for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
+		if (adc_bat->channel[chan])
+			iio_channel_release(adc_bat->channel[chan]);
+	}
 second_mem_fail:
 	kfree(psy->properties);
 first_mem_fail:
@@ -365,8 +365,10 @@
 		gpio_free(pdata->gpio_charge_finished);
 	}
 
-	for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++)
-		iio_channel_release(adc_bat->channel[chan]);
+	for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
+		if (adc_bat->channel[chan])
+			iio_channel_release(adc_bat->channel[chan]);
+	}
 
 	kfree(adc_bat->psy.properties);
 	cancel_delayed_work(&adc_bat->bat_work);
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c
new file mode 100644
index 0000000..c10f460
--- /dev/null
+++ b/drivers/power/goldfish_battery.c
@@ -0,0 +1,236 @@
+/*
+ * Power supply driver for the goldfish emulator
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+struct goldfish_battery_data {
+	void __iomem *reg_base;
+	int irq;
+	spinlock_t lock;
+
+	struct power_supply battery;
+	struct power_supply ac;
+};
+
+#define GOLDFISH_BATTERY_READ(data, addr) \
+	(readl(data->reg_base + addr))
+#define GOLDFISH_BATTERY_WRITE(data, addr, x) \
+	(writel(x, data->reg_base + addr))
+
+/*
+ * Temporary variable used between goldfish_battery_probe() and
+ * goldfish_battery_open().
+ */
+static struct goldfish_battery_data *battery_data;
+
+enum {
+	/* status register */
+	BATTERY_INT_STATUS	    = 0x00,
+	/* set this to enable IRQ */
+	BATTERY_INT_ENABLE	    = 0x04,
+
+	BATTERY_AC_ONLINE       = 0x08,
+	BATTERY_STATUS          = 0x0C,
+	BATTERY_HEALTH          = 0x10,
+	BATTERY_PRESENT         = 0x14,
+	BATTERY_CAPACITY        = 0x18,
+
+	BATTERY_STATUS_CHANGED	= 1U << 0,
+	AC_STATUS_CHANGED	= 1U << 1,
+	BATTERY_INT_MASK        = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
+};
+
+
+static int goldfish_ac_get_property(struct power_supply *psy,
+			enum power_supply_property psp,
+			union power_supply_propval *val)
+{
+	struct goldfish_battery_data *data = container_of(psy,
+		struct goldfish_battery_data, ac);
+	int ret = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int goldfish_battery_get_property(struct power_supply *psy,
+				 enum power_supply_property psp,
+				 union power_supply_propval *val)
+{
+	struct goldfish_battery_data *data = container_of(psy,
+		struct goldfish_battery_data, battery);
+	int ret = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static enum power_supply_property goldfish_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property goldfish_ac_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
+{
+	unsigned long irq_flags;
+	struct goldfish_battery_data *data = dev_id;
+	uint32_t status;
+
+	spin_lock_irqsave(&data->lock, irq_flags);
+
+	/* read status flags, which will clear the interrupt */
+	status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
+	status &= BATTERY_INT_MASK;
+
+	if (status & BATTERY_STATUS_CHANGED)
+		power_supply_changed(&data->battery);
+	if (status & AC_STATUS_CHANGED)
+		power_supply_changed(&data->ac);
+
+	spin_unlock_irqrestore(&data->lock, irq_flags);
+	return status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+
+static int goldfish_battery_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *r;
+	struct goldfish_battery_data *data;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&data->lock);
+
+	data->battery.properties = goldfish_battery_props;
+	data->battery.num_properties = ARRAY_SIZE(goldfish_battery_props);
+	data->battery.get_property = goldfish_battery_get_property;
+	data->battery.name = "battery";
+	data->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+
+	data->ac.properties = goldfish_ac_props;
+	data->ac.num_properties = ARRAY_SIZE(goldfish_ac_props);
+	data->ac.get_property = goldfish_ac_get_property;
+	data->ac.name = "ac";
+	data->ac.type = POWER_SUPPLY_TYPE_MAINS;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "platform_get_resource failed\n");
+		return -ENODEV;
+	}
+
+	data->reg_base = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1);
+	if (data->reg_base == NULL) {
+		dev_err(&pdev->dev, "unable to remap MMIO\n");
+		return -ENOMEM;
+	}
+
+	data->irq = platform_get_irq(pdev, 0);
+	if (data->irq < 0) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		return -ENODEV;
+	}
+
+	ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt,
+						IRQF_SHARED, pdev->name, data);
+	if (ret)
+		return ret;
+
+	ret = power_supply_register(&pdev->dev, &data->ac);
+	if (ret)
+		return ret;
+
+	ret = power_supply_register(&pdev->dev, &data->battery);
+	if (ret) {
+		power_supply_unregister(&data->ac);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, data);
+	battery_data = data;
+
+	GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
+	return 0;
+}
+
+static int goldfish_battery_remove(struct platform_device *pdev)
+{
+	struct goldfish_battery_data *data = platform_get_drvdata(pdev);
+
+	power_supply_unregister(&data->battery);
+	power_supply_unregister(&data->ac);
+	battery_data = NULL;
+	return 0;
+}
+
+static struct platform_driver goldfish_battery_device = {
+	.probe		= goldfish_battery_probe,
+	.remove		= goldfish_battery_remove,
+	.driver = {
+		.name = "goldfish-battery"
+	}
+};
+module_platform_driver(goldfish_battery_device);
+
+MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c
index 4ee71a9..5ef41b8 100644
--- a/drivers/power/lp8727_charger.c
+++ b/drivers/power/lp8727_charger.c
@@ -367,28 +367,28 @@
 			return -EINVAL;
 
 		if (pdata->get_batt_present)
-			val->intval = pchg->pdata->get_batt_present();
+			val->intval = pdata->get_batt_present();
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		if (!pdata)
 			return -EINVAL;
 
 		if (pdata->get_batt_level)
-			val->intval = pchg->pdata->get_batt_level();
+			val->intval = pdata->get_batt_level();
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
 		if (!pdata)
 			return -EINVAL;
 
 		if (pdata->get_batt_capacity)
-			val->intval = pchg->pdata->get_batt_capacity();
+			val->intval = pdata->get_batt_capacity();
 		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		if (!pdata)
 			return -EINVAL;
 
 		if (pdata->get_batt_temp)
-			val->intval = pchg->pdata->get_batt_temp();
+			val->intval = pdata->get_batt_temp();
 		break;
 	default:
 		break;
diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c
index 22b6407c..e33d6b2 100644
--- a/drivers/power/lp8788-charger.c
+++ b/drivers/power/lp8788-charger.c
@@ -367,7 +367,8 @@
 	return addr >= LP8788_CHG_START && addr <= LP8788_CHG_END;
 }
 
-static int lp8788_update_charger_params(struct lp8788_charger *pchg)
+static int lp8788_update_charger_params(struct platform_device *pdev,
+					struct lp8788_charger *pchg)
 {
 	struct lp8788 *lp = pchg->lp;
 	struct lp8788_charger_platform_data *pdata = pchg->pdata;
@@ -376,7 +377,7 @@
 	int ret;
 
 	if (!pdata || !pdata->chg_params) {
-		dev_info(lp->dev, "skip updating charger parameters\n");
+		dev_info(&pdev->dev, "skip updating charger parameters\n");
 		return 0;
 	}
 
@@ -537,7 +538,6 @@
 static int lp8788_irq_register(struct platform_device *pdev,
 				struct lp8788_charger *pchg)
 {
-	struct lp8788 *lp = pchg->lp;
 	const char *name[] = {
 		LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ
 	};
@@ -550,13 +550,13 @@
 	for (i = 0; i < ARRAY_SIZE(name); i++) {
 		ret = lp8788_set_irqs(pdev, pchg, name[i]);
 		if (ret) {
-			dev_warn(lp->dev, "irq setup failed: %s\n", name[i]);
+			dev_warn(&pdev->dev, "irq setup failed: %s\n", name[i]);
 			return ret;
 		}
 	}
 
 	if (pchg->num_irqs > LP8788_MAX_CHG_IRQS) {
-		dev_err(lp->dev, "invalid total number of irqs: %d\n",
+		dev_err(&pdev->dev, "invalid total number of irqs: %d\n",
 			pchg->num_irqs);
 		return -EINVAL;
 	}
@@ -690,9 +690,10 @@
 {
 	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
 	struct lp8788_charger *pchg;
+	struct device *dev = &pdev->dev;
 	int ret;
 
-	pchg = devm_kzalloc(lp->dev, sizeof(struct lp8788_charger), GFP_KERNEL);
+	pchg = devm_kzalloc(dev, sizeof(struct lp8788_charger), GFP_KERNEL);
 	if (!pchg)
 		return -ENOMEM;
 
@@ -700,7 +701,7 @@
 	pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL;
 	platform_set_drvdata(pdev, pchg);
 
-	ret = lp8788_update_charger_params(pchg);
+	ret = lp8788_update_charger_params(pdev, pchg);
 	if (ret)
 		return ret;
 
@@ -718,7 +719,7 @@
 
 	ret = lp8788_irq_register(pdev, pchg);
 	if (ret)
-		dev_warn(lp->dev, "failed to register charger irq: %d\n", ret);
+		dev_warn(dev, "failed to register charger irq: %d\n", ret);
 
 	return 0;
 }
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index 22cfe9c..74a0bd9 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -207,7 +207,7 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
 		return -EIO;
 
-	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
 
@@ -225,7 +225,6 @@
 	ret = power_supply_register(&client->dev, &chip->battery);
 	if (ret) {
 		dev_err(&client->dev, "failed: power supply register\n");
-		kfree(chip);
 		return ret;
 	}
 
@@ -244,7 +243,6 @@
 
 	power_supply_unregister(&chip->battery);
 	cancel_delayed_work(&chip->work);
-	kfree(chip);
 	return 0;
 }
 
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c
new file mode 100644
index 0000000..ed48d75
--- /dev/null
+++ b/drivers/power/pm2301_charger.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright 2012 ST Ericsson.
+ *
+ * Power supply driver for ST Ericsson pm2xxx_charger charger
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/mfd/abx500/ux500_chargalg.h>
+#include <linux/pm2301_charger.h>
+#include <linux/gpio.h>
+
+#include "pm2301_charger.h"
+
+#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
+		struct pm2xxx_charger, ac_chg)
+
+static int pm2xxx_interrupt_registers[] = {
+	PM2XXX_REG_INT1,
+	PM2XXX_REG_INT2,
+	PM2XXX_REG_INT3,
+	PM2XXX_REG_INT4,
+	PM2XXX_REG_INT5,
+	PM2XXX_REG_INT6,
+};
+
+static enum power_supply_property pm2xxx_charger_ac_props[] = {
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+};
+
+static int pm2xxx_charger_voltage_map[] = {
+	3500,
+	3525,
+	3550,
+	3575,
+	3600,
+	3625,
+	3650,
+	3675,
+	3700,
+	3725,
+	3750,
+	3775,
+	3800,
+	3825,
+	3850,
+	3875,
+	3900,
+	3925,
+	3950,
+	3975,
+	4000,
+	4025,
+	4050,
+	4075,
+	4100,
+	4125,
+	4150,
+	4175,
+	4200,
+	4225,
+	4250,
+	4275,
+	4300,
+};
+
+static int pm2xxx_charger_current_map[] = {
+	200,
+	200,
+	400,
+	600,
+	800,
+	1000,
+	1200,
+	1400,
+	1600,
+	1800,
+	2000,
+	2200,
+	2400,
+	2600,
+	2800,
+	3000,
+};
+
+static const struct i2c_device_id pm2xxx_ident[] = {
+	{ "pm2301", 0 },
+	{ }
+};
+
+static void set_lpn_pin(struct pm2xxx_charger *pm2)
+{
+	if (pm2->ac.charger_connected)
+		return;
+	gpio_set_value(pm2->lpn_pin, 1);
+
+	return;
+}
+
+static void clear_lpn_pin(struct pm2xxx_charger *pm2)
+{
+	if (pm2->ac.charger_connected)
+		return;
+	gpio_set_value(pm2->lpn_pin, 0);
+
+	return;
+}
+
+static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
+{
+	int ret;
+	/*
+	 * When AC adaptor is unplugged, the host
+	 * must put LPN high to be able to
+	 * communicate by I2C with PM2301
+	 * and receive I2C "acknowledge" from PM2301.
+	 */
+	mutex_lock(&pm2->lock);
+	set_lpn_pin(pm2);
+
+	ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
+				1, val);
+	if (ret < 0)
+		dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
+	else
+		ret = 0;
+	clear_lpn_pin(pm2);
+	mutex_unlock(&pm2->lock);
+
+	return ret;
+}
+
+static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
+{
+	int ret;
+	/*
+	 * When AC adaptor is unplugged, the host
+	 * must put LPN high to be able to
+	 * communicate by I2C with PM2301
+	 * and receive I2C "acknowledge" from PM2301.
+	 */
+	mutex_lock(&pm2->lock);
+	set_lpn_pin(pm2);
+
+	ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
+				1, &val);
+	if (ret < 0)
+		dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
+	else
+		ret = 0;
+	clear_lpn_pin(pm2);
+	mutex_unlock(&pm2->lock);
+
+	return ret;
+}
+
+static int pm2xxx_charging_enable_mngt(struct pm2xxx_charger *pm2)
+{
+	int ret;
+
+	/* Enable charging */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
+			(PM2XXX_CH_AUTO_RESUME_EN | PM2XXX_CHARGER_ENA));
+
+	return ret;
+}
+
+static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2)
+{
+	int ret;
+
+	/* Disable charging */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
+			(PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS));
+
+	return ret;
+}
+
+static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
+{
+	queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
+
+	return 0;
+}
+
+
+int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
+{
+	queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
+
+	return 0;
+}
+
+static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val)
+{
+	int ret = 0;
+
+	pm2->failure_input_ovv++;
+	if (pm2->failure_input_ovv < 4) {
+		ret = pm2xxx_charging_enable_mngt(pm2);
+		goto out;
+	} else {
+		pm2->failure_input_ovv = 0;
+		dev_err(pm2->dev, "Overvoltage detected\n");
+		pm2->flags.ovv = true;
+		power_supply_changed(&pm2->ac_chg.psy);
+	}
+
+out:
+	return ret;
+}
+
+static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
+{
+	dev_dbg(pm2->dev , "20 minutes watchdog occured\n");
+
+	pm2->ac.wd_expired = true;
+	power_supply_changed(&pm2->ac_chg.psy);
+
+	return 0;
+}
+
+static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
+{
+	switch (val) {
+	case PM2XXX_INT1_ITVBATLOWR:
+		dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
+		break;
+
+	case PM2XXX_INT1_ITVBATLOWF:
+		dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
+		break;
+
+	default:
+		dev_err(pm2->dev, "Unknown VBAT level\n");
+	}
+
+	return 0;
+}
+
+static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val)
+{
+	dev_dbg(pm2->dev, "battery disconnected\n");
+
+	return 0;
+}
+
+static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val)
+{
+	int ret;
+
+	ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val);
+
+	if (ret < 0) {
+		dev_err(pm2->dev, "Charger detection failed\n");
+		goto out;
+	}
+
+	*val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG);
+
+out:
+	return ret;
+}
+
+static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val)
+{
+
+	int ret;
+	u8 read_val;
+
+	/*
+	 * Since we can't be sure that the events are received
+	 * synchronously, we have the check if the main charger is
+	 * connected by reading the interrupt source register.
+	 */
+	ret = pm2xxx_charger_detection(pm2, &read_val);
+
+	if ((ret == 0) && read_val) {
+		pm2->ac.charger_connected = 1;
+		pm2->ac_conn = true;
+		queue_work(pm2->charger_wq, &pm2->ac_work);
+	}
+
+
+	return ret;
+}
+
+static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2,
+								int val)
+{
+	pm2->ac.charger_connected = 0;
+	queue_work(pm2->charger_wq, &pm2->ac_work);
+
+	return 0;
+}
+
+static int pm2_int_reg0(void *pm2_data, int val)
+{
+	struct pm2xxx_charger *pm2 = pm2_data;
+	int ret = 0;
+
+	if (val & (PM2XXX_INT1_ITVBATLOWR | PM2XXX_INT1_ITVBATLOWF)) {
+		ret = pm2xxx_charger_vbat_lsig_mngt(pm2, val &
+			(PM2XXX_INT1_ITVBATLOWR | PM2XXX_INT1_ITVBATLOWF));
+	}
+
+	if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
+		ret = pm2xxx_charger_bat_disc_mngt(pm2,
+				PM2XXX_INT1_ITVBATDISCONNECT);
+	}
+
+	return ret;
+}
+
+static int pm2_int_reg1(void *pm2_data, int val)
+{
+	struct pm2xxx_charger *pm2 = pm2_data;
+	int ret = 0;
+
+	if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) {
+		dev_dbg(pm2->dev , "Main charger plugged\n");
+		ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val &
+			(PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG));
+	}
+
+	if (val &
+		(PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) {
+		dev_dbg(pm2->dev , "Main charger unplugged\n");
+		ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val &
+						(PM2XXX_INT2_ITVPWR1UNPLUG |
+						PM2XXX_INT2_ITVPWR2UNPLUG));
+	}
+
+	return ret;
+}
+
+static int pm2_int_reg2(void *pm2_data, int val)
+{
+	struct pm2xxx_charger *pm2 = pm2_data;
+	int ret = 0;
+
+	if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD)
+		ret = pm2xxx_charger_wd_exp_mngt(pm2, val);
+
+	if (val & (PM2XXX_INT3_ITCHPRECHARGEWD |
+				PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) {
+		dev_dbg(pm2->dev,
+			"Watchdog occured for precharge, CC and CV charge\n");
+	}
+
+	return ret;
+}
+
+static int pm2_int_reg3(void *pm2_data, int val)
+{
+	struct pm2xxx_charger *pm2 = pm2_data;
+	int ret = 0;
+
+	if (val & (PM2XXX_INT4_ITCHARGINGON)) {
+		dev_dbg(pm2->dev ,
+			"chargind operation has started\n");
+	}
+
+	if (val & (PM2XXX_INT4_ITVRESUME)) {
+		dev_dbg(pm2->dev,
+			"battery discharged down to VResume threshold\n");
+	}
+
+	if (val & (PM2XXX_INT4_ITBATTFULL)) {
+		dev_dbg(pm2->dev , "battery fully detected\n");
+	}
+
+	if (val & (PM2XXX_INT4_ITCVPHASE)) {
+		dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n");
+	}
+
+	if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) {
+		pm2->failure_case = VPWR_OVV;
+		ret = pm2xxx_charger_ovv_mngt(pm2, val &
+			(PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV));
+		dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n");
+	}
+
+	if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD |
+				PM2XXX_INT4_S_ITBATTEMPHOT)) {
+		ret = pm2xxx_charger_batt_therm_mngt(pm2, val &
+			(PM2XXX_INT4_S_ITBATTEMPCOLD |
+			PM2XXX_INT4_S_ITBATTEMPHOT));
+		dev_dbg(pm2->dev, "BTEMP is too Low/High\n");
+	}
+
+	return ret;
+}
+
+static int pm2_int_reg4(void *pm2_data, int val)
+{
+	struct pm2xxx_charger *pm2 = pm2_data;
+	int ret = 0;
+
+	if (val & PM2XXX_INT5_ITVSYSTEMOVV) {
+		pm2->failure_case = VSYSTEM_OVV;
+		ret = pm2xxx_charger_ovv_mngt(pm2, val &
+						PM2XXX_INT5_ITVSYSTEMOVV);
+		dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n");
+	}
+
+	if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL |
+				PM2XXX_INT5_ITTHERMALWARNINGRISE |
+				PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
+				PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) {
+		dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n");
+		ret = pm2xxx_charger_die_therm_mngt(pm2, val &
+			(PM2XXX_INT5_ITTHERMALWARNINGFALL |
+			PM2XXX_INT5_ITTHERMALWARNINGRISE |
+			PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
+			PM2XXX_INT5_ITTHERMALSHUTDOWNRISE));
+	}
+
+	return ret;
+}
+
+static int pm2_int_reg5(void *pm2_data, int val)
+{
+	struct pm2xxx_charger *pm2 = pm2_data;
+	int ret = 0;
+
+
+	if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
+		dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
+	}
+
+	if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE |
+			PM2XXX_INT6_ITVPWR1VALIDRISE |
+			PM2XXX_INT6_ITVPWR2VALIDFALL |
+			PM2XXX_INT6_ITVPWR1VALIDFALL)) {
+		dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
+	}
+
+	return ret;
+}
+
+static irqreturn_t  pm2xxx_irq_int(int irq, void *data)
+{
+	struct pm2xxx_charger *pm2 = data;
+	struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
+	int i;
+
+	for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
+		 pm2xxx_reg_read(pm2,
+				pm2xxx_interrupt_registers[i],
+				&(interrupt->reg[i]));
+
+		if (interrupt->reg[i] > 0)
+			interrupt->handler[i](pm2, interrupt->reg[i]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2)
+{
+	int ret = 0;
+	u8 val;
+
+	if (pm2->ac.charger_connected && pm2->ac.charger_online) {
+
+		ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val);
+		if (ret < 0) {
+			dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+			goto out;
+		}
+
+		if (val & PM2XXX_INT4_S_ITCVPHASE)
+			ret = PM2XXX_CONST_VOLT;
+		else
+			ret = PM2XXX_CONST_CURR;
+	}
+out:
+	return ret;
+}
+
+static int pm2xxx_current_to_regval(int curr)
+{
+	int i;
+
+	if (curr < pm2xxx_charger_current_map[0])
+		return 0;
+
+	for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) {
+		if (curr < pm2xxx_charger_current_map[i])
+			return (i - 1);
+	}
+
+	i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1;
+	if (curr == pm2xxx_charger_current_map[i])
+		return i;
+	else
+		return -EINVAL;
+}
+
+static int pm2xxx_voltage_to_regval(int curr)
+{
+	int i;
+
+	if (curr < pm2xxx_charger_voltage_map[0])
+		return 0;
+
+	for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) {
+		if (curr < pm2xxx_charger_voltage_map[i])
+			return i - 1;
+	}
+
+	i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1;
+	if (curr == pm2xxx_charger_voltage_map[i])
+		return i;
+	else
+		return -EINVAL;
+}
+
+static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger,
+		int ich_out)
+{
+	int ret;
+	int curr_index;
+	struct pm2xxx_charger *pm2;
+	u8 val;
+
+	if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+		pm2 = to_pm2xxx_charger_ac_device_info(charger);
+	else
+		return -ENXIO;
+
+	curr_index = pm2xxx_current_to_regval(ich_out);
+	if (curr_index < 0) {
+		dev_err(pm2->dev,
+			"Charger current too high, charging not started\n");
+		return -ENXIO;
+	}
+
+	ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
+	if (ret >= 0) {
+		val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
+		val |= curr_index;
+		ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
+		if (ret < 0) {
+			dev_err(pm2->dev,
+				"%s write failed\n", __func__);
+		}
+	}
+	else
+		dev_err(pm2->dev, "%s read failed\n", __func__);
+
+	return ret;
+}
+
+static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
+	enum power_supply_property psp,
+	union power_supply_propval *val)
+{
+	struct pm2xxx_charger *pm2;
+
+	pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy));
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_HEALTH:
+		if (pm2->flags.mainextchnotok)
+			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		else if (pm2->ac.wd_expired)
+			val->intval = POWER_SUPPLY_HEALTH_DEAD;
+		else if (pm2->flags.main_thermal_prot)
+			val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		else
+			val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = pm2->ac.charger_online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = pm2->ac.charger_connected;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+		pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2);
+		val->intval = pm2->ac.cv_active;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
+{
+	int ret = 0;
+
+	/* enable CC and CV watchdog */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3,
+		(PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN));
+	if( ret < 0)
+		return ret;
+
+	/* enable precharge watchdog */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4,
+					PM2XXX_CH_WD_PRECH_PHASE_60MIN);
+
+	/* Disable auto timeout */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5,
+					PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN);
+
+	/*
+     * EOC current level = 100mA
+	 * Precharge current level = 100mA
+	 * CC current level = 1000mA
+	 */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6,
+		(PM2XXX_DIR_CH_CC_CURRENT_1000MA |
+		PM2XXX_CH_PRECH_CURRENT_100MA |
+		PM2XXX_CH_EOC_CURRENT_100MA));
+
+	/*
+     * recharge threshold = 3.8V
+	 * Precharge to CC threshold = 2.9V
+	 */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7,
+		(PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8));
+
+	/* float voltage charger level = 4.2V */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8,
+		PM2XXX_CH_VOLT_4_2);
+
+	/* Voltage drop between VBAT and VSYS in HW charging = 300mV */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9,
+		(PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS |
+		PM2XXX_CH_CC_REDUCED_CURRENT_IDENT |
+		PM2XXX_CH_CC_MODEDROP_DIS));
+
+	/* Input charger level of over voltage = 10V */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2,
+					PM2XXX_VPWR2_OVV_10);
+	ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1,
+					PM2XXX_VPWR1_OVV_10);
+
+	/* Input charger drop */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2,
+		(PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS |
+		PM2XXX_VPWR2_DROP_DIS));
+	ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1,
+		(PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS |
+		PM2XXX_VPWR1_DROP_DIS));
+
+	/* Disable battery low monitoring */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
+		PM2XXX_VBAT_LOW_MONITORING_ENA);
+
+	/* Disable LED */
+	ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG,
+		PM2XXX_LED_SELECT_DIS);
+
+	return ret;
+}
+
+static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
+	int enable, int vset, int iset)
+{
+	int ret;
+	int volt_index;
+	int curr_index;
+	u8 val;
+
+	struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);
+
+	if (enable) {
+		if (!pm2->ac.charger_connected) {
+			dev_dbg(pm2->dev, "AC charger not connected\n");
+			return -ENXIO;
+		}
+
+		dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
+		if (!pm2->vddadc_en_ac) {
+			regulator_enable(pm2->regu);
+			pm2->vddadc_en_ac = true;
+		}
+
+		ret = pm2xxx_charging_init(pm2);
+		if (ret < 0) {
+			dev_err(pm2->dev, "%s charging init failed\n",
+					__func__);
+			goto error_occured;
+		}
+
+		volt_index = pm2xxx_voltage_to_regval(vset);
+		curr_index = pm2xxx_current_to_regval(iset);
+
+		if (volt_index < 0 || curr_index < 0) {
+			dev_err(pm2->dev,
+				"Charger voltage or current too high, "
+				"charging not started\n");
+			return -ENXIO;
+		}
+
+		ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
+		if (ret < 0) {
+			dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+			goto error_occured;
+		}
+		val &= ~PM2XXX_CH_VOLT_MASK;
+		val |= volt_index;
+		ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
+		if (ret < 0) {
+			dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+			goto error_occured;
+		}
+
+		ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
+		if (ret < 0) {
+			dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+			goto error_occured;
+		}
+		val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
+		val |= curr_index;
+		ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
+		if (ret < 0) {
+			dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+			goto error_occured;
+		}
+
+		if (!pm2->bat->enable_overshoot) {
+			ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
+			if (ret < 0) {
+				dev_err(pm2->dev, "%s pm2xxx read failed\n",
+								__func__);
+				goto error_occured;
+			}
+			val |= PM2XXX_ANTI_OVERSHOOT_EN;
+			ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
+			if (ret < 0) {
+				dev_err(pm2->dev, "%s pm2xxx write failed\n",
+								__func__);
+				goto error_occured;
+			}
+		}
+
+		ret = pm2xxx_charging_enable_mngt(pm2);
+		if (ret < 0) {
+			dev_err(pm2->dev, "Failed to enable"
+						"pm2xxx ac charger\n");
+			goto error_occured;
+		}
+
+		pm2->ac.charger_online = 1;
+	} else {
+		pm2->ac.charger_online = 0;
+		pm2->ac.wd_expired = false;
+
+		/* Disable regulator if enabled */
+		if (pm2->vddadc_en_ac) {
+			regulator_disable(pm2->regu);
+			pm2->vddadc_en_ac = false;
+		}
+
+		ret = pm2xxx_charging_disable_mngt(pm2);
+		if (ret < 0) {
+			dev_err(pm2->dev, "failed to disable"
+						"pm2xxx ac charger\n");
+			goto error_occured;
+		}
+
+		dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
+	}
+	power_supply_changed(&pm2->ac_chg.psy);
+
+error_occured:
+	return ret;
+}
+
+static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger)
+{
+	int ret;
+	struct pm2xxx_charger *pm2;
+
+	if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+		pm2 = to_pm2xxx_charger_ac_device_info(charger);
+	else
+		return -ENXIO;
+
+	ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER);
+	if (ret)
+		dev_err(pm2->dev, "Failed to kick WD!\n");
+
+	return ret;
+}
+
+static void pm2xxx_charger_ac_work(struct work_struct *work)
+{
+	struct pm2xxx_charger *pm2 = container_of(work,
+		struct pm2xxx_charger, ac_work);
+
+
+	power_supply_changed(&pm2->ac_chg.psy);
+	sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
+};
+
+static void pm2xxx_charger_check_main_thermal_prot_work(
+	struct work_struct *work)
+{
+};
+
+static struct pm2xxx_interrupts pm2xxx_int = {
+	.handler[0] = pm2_int_reg0,
+	.handler[1] = pm2_int_reg1,
+	.handler[2] = pm2_int_reg2,
+	.handler[3] = pm2_int_reg3,
+	.handler[4] = pm2_int_reg4,
+	.handler[5] = pm2_int_reg5,
+};
+
+static struct pm2xxx_irq pm2xxx_charger_irq[] = {
+	{"PM2XXX_IRQ_INT", pm2xxx_irq_int},
+};
+
+static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client)
+{
+	return 0;
+}
+
+static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client,
+	pm_message_t state)
+{
+	return 0;
+}
+
+static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
+		const struct i2c_device_id *id)
+{
+	struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
+	struct pm2xxx_charger *pm2;
+	int ret = 0;
+	u8 val;
+
+	pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
+	if (!pm2) {
+		dev_err(pm2->dev, "pm2xxx_charger allocation failed\n");
+		return -ENOMEM;
+	}
+
+	/* get parent data */
+	pm2->dev = &i2c_client->dev;
+	pm2->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+
+	pm2->pm2_int = &pm2xxx_int;
+
+	/* get charger spcific platform data */
+	if (!pl_data->wall_charger) {
+		dev_err(pm2->dev, "no charger platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	pm2->pdata = pl_data->wall_charger;
+
+	/* get battery specific platform data */
+	if (!pl_data->battery) {
+		dev_err(pm2->dev, "no battery platform data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+
+	pm2->bat = pl_data->battery;
+
+	/*get lpn GPIO from platform data*/
+	if (!pm2->pdata->lpn_gpio) {
+		dev_err(pm2->dev, "no lpn gpio data supplied\n");
+		ret = -EINVAL;
+		goto free_device_info;
+	}
+	pm2->lpn_pin = pm2->pdata->lpn_gpio;
+
+	if (!i2c_check_functionality(i2c_client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA |
+			I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+		ret = -ENODEV;
+		dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
+		goto free_device_info;
+	}
+
+	pm2->config.pm2xxx_i2c = i2c_client;
+	pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
+	i2c_set_clientdata(i2c_client, pm2);
+
+	/* AC supply */
+	/* power_supply base class */
+	pm2->ac_chg.psy.name = pm2->pdata->label;
+	pm2->ac_chg.psy.type = POWER_SUPPLY_TYPE_MAINS;
+	pm2->ac_chg.psy.properties = pm2xxx_charger_ac_props;
+	pm2->ac_chg.psy.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
+	pm2->ac_chg.psy.get_property = pm2xxx_charger_ac_get_property;
+	pm2->ac_chg.psy.supplied_to = pm2->pdata->supplied_to;
+	pm2->ac_chg.psy.num_supplicants = pm2->pdata->num_supplicants;
+	/* pm2xxx_charger sub-class */
+	pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
+	pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
+	pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
+	pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
+		ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
+	pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
+		ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
+	pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
+	pm2->ac_chg.enabled = true;
+	pm2->ac_chg.external = true;
+
+	/* Create a work queue for the charger */
+	pm2->charger_wq =
+		create_singlethread_workqueue("pm2xxx_charger_wq");
+	if (pm2->charger_wq == NULL) {
+		dev_err(pm2->dev, "failed to create work queue\n");
+		goto free_device_info;
+	}
+
+	/* Init work for charger detection */
+	INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);
+
+	/* Init work for checking HW status */
+	INIT_WORK(&pm2->check_main_thermal_prot_work,
+		pm2xxx_charger_check_main_thermal_prot_work);
+
+	/*
+	 * VDD ADC supply needs to be enabled from this driver when there
+	 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
+	 * interrupts during charging
+	 */
+	pm2->regu = regulator_get(pm2->dev, "vddadc");
+	if (IS_ERR(pm2->regu)) {
+		ret = PTR_ERR(pm2->regu);
+		dev_err(pm2->dev, "failed to get vddadc regulator\n");
+		goto free_charger_wq;
+	}
+
+	/* Register AC charger class */
+	ret = power_supply_register(pm2->dev, &pm2->ac_chg.psy);
+	if (ret) {
+		dev_err(pm2->dev, "failed to register AC charger\n");
+		goto free_regulator;
+	}
+
+	/* Register interrupts */
+	ret = request_threaded_irq(pm2->pdata->irq_number, NULL,
+				pm2xxx_charger_irq[0].isr,
+				pm2->pdata->irq_type,
+				pm2xxx_charger_irq[0].name, pm2);
+
+	if (ret != 0) {
+		dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
+		pm2xxx_charger_irq[0].name, pm2->pdata->irq_number, ret);
+		goto unregister_pm2xxx_charger;
+	}
+
+	/*Initialize lock*/
+	mutex_init(&pm2->lock);
+
+	/*
+	 * Charger detection mechanism requires pulling up the LPN pin
+	 * while i2c communication if Charger is not connected
+	 * LPN pin of PM2301 is GPIO60 of AB9540
+	 */
+	ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
+	if (ret < 0) {
+		dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
+		goto unregister_pm2xxx_charger;
+	}
+	ret = gpio_direction_output(pm2->lpn_pin, 0);
+	if (ret < 0) {
+		dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
+		goto free_gpio;
+	}
+
+	ret = pm2xxx_charger_detection(pm2, &val);
+
+	if ((ret == 0) && val) {
+		pm2->ac.charger_connected = 1;
+		pm2->ac_conn = true;
+		power_supply_changed(&pm2->ac_chg.psy);
+		sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
+	}
+
+	return 0;
+
+free_gpio:
+	gpio_free(pm2->lpn_pin);
+unregister_pm2xxx_charger:
+	/* unregister power supply */
+	power_supply_unregister(&pm2->ac_chg.psy);
+free_regulator:
+	/* disable the regulator */
+	regulator_put(pm2->regu);
+free_charger_wq:
+	destroy_workqueue(pm2->charger_wq);
+free_device_info:
+	kfree(pm2);
+	return ret;
+}
+
+static int __devexit pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
+{
+	struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
+
+	/* Disable AC charging */
+	pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
+
+	/* Disable interrupts */
+	free_irq(pm2->pdata->irq_number, pm2);
+
+	/* Delete the work queue */
+	destroy_workqueue(pm2->charger_wq);
+
+	flush_scheduled_work();
+
+	/* disable the regulator */
+	regulator_put(pm2->regu);
+
+	power_supply_unregister(&pm2->ac_chg.psy);
+
+	/*Free GPIO60*/
+	gpio_free(pm2->lpn_pin);
+
+	kfree(pm2);
+
+	return 0;
+}
+
+static const struct i2c_device_id pm2xxx_id[] = {
+	{ "pm2301", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
+
+static struct i2c_driver pm2xxx_charger_driver = {
+	.probe = pm2xxx_wall_charger_probe,
+	.remove = __devexit_p(pm2xxx_wall_charger_remove),
+	.suspend = pm2xxx_wall_charger_suspend,
+	.resume = pm2xxx_wall_charger_resume,
+	.driver = {
+		.name = "pm2xxx-wall_charger",
+		.owner = THIS_MODULE,
+	},
+	.id_table = pm2xxx_id,
+};
+
+static int __init pm2xxx_charger_init(void)
+{
+	return i2c_add_driver(&pm2xxx_charger_driver);
+}
+
+static void __exit pm2xxx_charger_exit(void)
+{
+	i2c_del_driver(&pm2xxx_charger_driver);
+}
+
+subsys_initcall_sync(pm2xxx_charger_init);
+module_exit(pm2xxx_charger_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
+MODULE_ALIAS("platform:pm2xxx-charger");
+MODULE_DESCRIPTION("PM2xxx charger management driver");
+
diff --git a/drivers/power/pm2301_charger.h b/drivers/power/pm2301_charger.h
new file mode 100644
index 0000000..e6319cd
--- /dev/null
+++ b/drivers/power/pm2301_charger.h
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * PM2301 power supply interface
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef PM2301_CHARGER_H
+#define PM2301_CHARGER_H
+
+#define MAIN_WDOG_ENA			0x01
+#define MAIN_WDOG_KICK			0x02
+#define MAIN_WDOG_DIS			0x00
+#define CHARG_WD_KICK			0x01
+#define MAIN_CH_ENA			0x01
+#define MAIN_CH_NO_OVERSHOOT_ENA_N	0x02
+#define MAIN_CH_DET			0x01
+#define MAIN_CH_CV_ON			0x04
+#define OTP_ENABLE_WD			0x01
+
+#define MAIN_CH_INPUT_CURR_SHIFT	4
+
+#define LED_INDICATOR_PWM_ENA		0x01
+#define LED_INDICATOR_PWM_DIS		0x00
+#define LED_IND_CUR_5MA			0x04
+#define LED_INDICATOR_PWM_DUTY_252_256	0xBF
+
+/* HW failure constants */
+#define MAIN_CH_TH_PROT			0x02
+#define MAIN_CH_NOK			0x01
+
+/* Watchdog timeout constant */
+#define WD_TIMER			0x30 /* 4min */
+#define WD_KICK_INTERVAL		(30 * HZ)
+
+#define PM2XXX_NUM_INT_REG		0x6
+
+/* Constant voltage/current */
+#define PM2XXX_CONST_CURR		0x0
+#define PM2XXX_CONST_VOLT		0x1
+
+/* Lowest charger voltage is 3.39V -> 0x4E */
+#define LOW_VOLT_REG			0x4E
+
+#define PM2XXX_BATT_CTRL_REG1		0x00
+#define PM2XXX_BATT_CTRL_REG2		0x01
+#define PM2XXX_BATT_CTRL_REG3		0x02
+#define PM2XXX_BATT_CTRL_REG4		0x03
+#define PM2XXX_BATT_CTRL_REG5		0x04
+#define PM2XXX_BATT_CTRL_REG6		0x05
+#define PM2XXX_BATT_CTRL_REG7		0x06
+#define PM2XXX_BATT_CTRL_REG8		0x07
+#define PM2XXX_NTC_CTRL_REG1		0x08
+#define PM2XXX_NTC_CTRL_REG2		0x09
+#define PM2XXX_BATT_CTRL_REG9		0x0A
+#define PM2XXX_BATT_STAT_REG1		0x0B
+#define PM2XXX_INP_VOLT_VPWR2		0x11
+#define PM2XXX_INP_DROP_VPWR2		0x13
+#define PM2XXX_INP_VOLT_VPWR1		0x15
+#define PM2XXX_INP_DROP_VPWR1		0x17
+#define PM2XXX_INP_MODE_VPWR		0x18
+#define PM2XXX_BATT_WD_KICK		0x70
+#define PM2XXX_DEV_VER_STAT		0x0C
+#define PM2XXX_THERM_WARN_CTRL_REG	0x20
+#define PM2XXX_BATT_DISC_REG		0x21
+#define PM2XXX_BATT_LOW_LEV_COMP_REG	0x22
+#define PM2XXX_BATT_LOW_LEV_VAL_REG	0x23
+#define PM2XXX_I2C_PAD_CTRL_REG		0x24
+#define PM2XXX_SW_CTRL_REG		0x26
+#define PM2XXX_LED_CTRL_REG		0x28
+
+#define PM2XXX_REG_INT1			0x40
+#define PM2XXX_MASK_REG_INT1		0x50
+#define PM2XXX_SRCE_REG_INT1		0x60
+#define PM2XXX_REG_INT2			0x41
+#define PM2XXX_MASK_REG_INT2		0x51
+#define PM2XXX_SRCE_REG_INT2		0x61
+#define PM2XXX_REG_INT3			0x42
+#define PM2XXX_MASK_REG_INT3		0x52
+#define PM2XXX_SRCE_REG_INT3		0x62
+#define PM2XXX_REG_INT4			0x43
+#define PM2XXX_MASK_REG_INT4		0x53
+#define PM2XXX_SRCE_REG_INT4		0x63
+#define PM2XXX_REG_INT5			0x44
+#define PM2XXX_MASK_REG_INT5		0x54
+#define PM2XXX_SRCE_REG_INT5		0x64
+#define PM2XXX_REG_INT6			0x45
+#define PM2XXX_MASK_REG_INT6		0x55
+#define PM2XXX_SRCE_REG_INT6		0x65
+
+#define VPWR_OVV			0x0
+#define VSYSTEM_OVV			0x1
+
+/* control Reg 1 */
+#define PM2XXX_CH_RESUME_EN		0x1
+#define PM2XXX_CH_RESUME_DIS		0x0
+
+/* control Reg 2 */
+#define PM2XXX_CH_AUTO_RESUME_EN	0X2
+#define PM2XXX_CH_AUTO_RESUME_DIS	0X0
+#define PM2XXX_CHARGER_ENA		0x4
+#define PM2XXX_CHARGER_DIS		0x0
+
+/* control Reg 3 */
+#define PM2XXX_CH_WD_CC_PHASE_OFF	0x0
+#define PM2XXX_CH_WD_CC_PHASE_5MIN	0x1
+#define PM2XXX_CH_WD_CC_PHASE_10MIN	0x2
+#define PM2XXX_CH_WD_CC_PHASE_30MIN	0x3
+#define PM2XXX_CH_WD_CC_PHASE_60MIN	0x4
+#define PM2XXX_CH_WD_CC_PHASE_120MIN	0x5
+#define PM2XXX_CH_WD_CC_PHASE_240MIN	0x6
+#define PM2XXX_CH_WD_CC_PHASE_360MIN	0x7
+
+#define PM2XXX_CH_WD_CV_PHASE_OFF	(0x0<<3)
+#define PM2XXX_CH_WD_CV_PHASE_5MIN	(0x1<<3)
+#define PM2XXX_CH_WD_CV_PHASE_10MIN	(0x2<<3)
+#define PM2XXX_CH_WD_CV_PHASE_30MIN	(0x3<<3)
+#define PM2XXX_CH_WD_CV_PHASE_60MIN	(0x4<<3)
+#define PM2XXX_CH_WD_CV_PHASE_120MIN	(0x5<<3)
+#define PM2XXX_CH_WD_CV_PHASE_240MIN	(0x6<<3)
+#define PM2XXX_CH_WD_CV_PHASE_360MIN	(0x7<<3)
+
+/* control Reg 4 */
+#define PM2XXX_CH_WD_PRECH_PHASE_OFF	0x0
+#define PM2XXX_CH_WD_PRECH_PHASE_1MIN	0x1
+#define PM2XXX_CH_WD_PRECH_PHASE_5MIN	0x2
+#define PM2XXX_CH_WD_PRECH_PHASE_10MIN	0x3
+#define PM2XXX_CH_WD_PRECH_PHASE_30MIN	0x4
+#define PM2XXX_CH_WD_PRECH_PHASE_60MIN	0x5
+#define PM2XXX_CH_WD_PRECH_PHASE_120MIN	0x6
+#define PM2XXX_CH_WD_PRECH_PHASE_240MIN	0x7
+
+/* control Reg 5 */
+#define PM2XXX_CH_WD_AUTO_TIMEOUT_NONE	0x0
+#define PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN	0x1
+
+/* control Reg 6 */
+#define PM2XXX_DIR_CH_CC_CURRENT_MASK	0x0F
+#define PM2XXX_DIR_CH_CC_CURRENT_200MA	0x0
+#define PM2XXX_DIR_CH_CC_CURRENT_400MA	0x2
+#define PM2XXX_DIR_CH_CC_CURRENT_600MA	0x3
+#define PM2XXX_DIR_CH_CC_CURRENT_800MA	0x4
+#define PM2XXX_DIR_CH_CC_CURRENT_1000MA	0x5
+#define PM2XXX_DIR_CH_CC_CURRENT_1200MA	0x6
+#define PM2XXX_DIR_CH_CC_CURRENT_1400MA	0x7
+#define PM2XXX_DIR_CH_CC_CURRENT_1600MA	0x8
+#define PM2XXX_DIR_CH_CC_CURRENT_1800MA	0x9
+#define PM2XXX_DIR_CH_CC_CURRENT_2000MA	0xA
+#define PM2XXX_DIR_CH_CC_CURRENT_2200MA	0xB
+#define PM2XXX_DIR_CH_CC_CURRENT_2400MA	0xC
+#define PM2XXX_DIR_CH_CC_CURRENT_2600MA	0xD
+#define PM2XXX_DIR_CH_CC_CURRENT_2800MA	0xE
+#define PM2XXX_DIR_CH_CC_CURRENT_3000MA	0xF
+
+#define PM2XXX_CH_PRECH_CURRENT_MASK	0x30
+#define PM2XXX_CH_PRECH_CURRENT_25MA	(0x0<<4)
+#define PM2XXX_CH_PRECH_CURRENT_50MA	(0x1<<4)
+#define PM2XXX_CH_PRECH_CURRENT_75MA	(0x2<<4)
+#define PM2XXX_CH_PRECH_CURRENT_100MA	(0x3<<4)
+
+#define PM2XXX_CH_EOC_CURRENT_MASK	0xC0
+#define PM2XXX_CH_EOC_CURRENT_100MA	(0x0<<6)
+#define PM2XXX_CH_EOC_CURRENT_150MA	(0x1<<6)
+#define PM2XXX_CH_EOC_CURRENT_300MA	(0x2<<6)
+#define PM2XXX_CH_EOC_CURRENT_400MA	(0x3<<6)
+
+/* control Reg 7 */
+#define PM2XXX_CH_PRECH_VOL_2_5		0x0
+#define PM2XXX_CH_PRECH_VOL_2_7		0x1
+#define PM2XXX_CH_PRECH_VOL_2_9		0x2
+#define PM2XXX_CH_PRECH_VOL_3_1		0x3
+
+#define PM2XXX_CH_VRESUME_VOL_3_2	(0x0<<2)
+#define PM2XXX_CH_VRESUME_VOL_3_4	(0x1<<2)
+#define PM2XXX_CH_VRESUME_VOL_3_6	(0x2<<2)
+#define PM2XXX_CH_VRESUME_VOL_3_8	(0x3<<2)
+
+/* control Reg 8 */
+#define PM2XXX_CH_VOLT_MASK		0x3F
+#define PM2XXX_CH_VOLT_3_5		0x0
+#define PM2XXX_CH_VOLT_3_5225		0x1
+#define PM2XXX_CH_VOLT_3_6		0x4
+#define PM2XXX_CH_VOLT_3_7		0x8
+#define PM2XXX_CH_VOLT_4_0		0x14
+#define PM2XXX_CH_VOLT_4_175		0x1B
+#define PM2XXX_CH_VOLT_4_2		0x1C
+#define PM2XXX_CH_VOLT_4_275		0x1F
+#define PM2XXX_CH_VOLT_4_3		0x20
+
+/*NTC control register 1*/
+#define PM2XXX_BTEMP_HIGH_TH_45		0x0
+#define PM2XXX_BTEMP_HIGH_TH_50		0x1
+#define PM2XXX_BTEMP_HIGH_TH_55		0x2
+#define PM2XXX_BTEMP_HIGH_TH_60		0x3
+#define PM2XXX_BTEMP_HIGH_TH_65		0x4
+
+#define PM2XXX_BTEMP_LOW_TH_N5		(0x0<<3)
+#define PM2XXX_BTEMP_LOW_TH_0		(0x1<<3)
+#define PM2XXX_BTEMP_LOW_TH_5		(0x2<<3)
+#define PM2XXX_BTEMP_LOW_TH_10		(0x3<<3)
+
+/*NTC control register 2*/
+#define PM2XXX_NTC_BETA_COEFF_3477	0x0
+#define PM2XXX_NTC_BETA_COEFF_3964	0x1
+
+#define PM2XXX_NTC_RES_10K		(0x0<<2)
+#define PM2XXX_NTC_RES_47K		(0x1<<2)
+#define PM2XXX_NTC_RES_100K		(0x2<<2)
+#define PM2XXX_NTC_RES_NO_NTC		(0x3<<2)
+
+/* control Reg 9 */
+#define PM2XXX_CH_CC_MODEDROP_EN	1
+#define PM2XXX_CH_CC_MODEDROP_DIS	0
+
+#define PM2XXX_CH_CC_REDUCED_CURRENT_100MA	(0x0<<1)
+#define PM2XXX_CH_CC_REDUCED_CURRENT_200MA	(0x1<<1)
+#define PM2XXX_CH_CC_REDUCED_CURRENT_400MA	(0x2<<1)
+#define PM2XXX_CH_CC_REDUCED_CURRENT_IDENT	(0x3<<1)
+
+#define PM2XXX_CHARCHING_INFO_DIS	(0<<3)
+#define PM2XXX_CHARCHING_INFO_EN	(1<<3)
+
+#define PM2XXX_CH_150MV_DROP_300MV	(0<<4)
+#define PM2XXX_CH_150MV_DROP_150MV	(1<<4)
+
+
+/* charger status register */
+#define PM2XXX_CHG_STATUS_OFF		0x0
+#define PM2XXX_CHG_STATUS_ON		0x1
+#define PM2XXX_CHG_STATUS_FULL		0x2
+#define PM2XXX_CHG_STATUS_ERR		0x3
+#define PM2XXX_CHG_STATUS_WAIT		0x4
+#define PM2XXX_CHG_STATUS_NOBAT		0x5
+
+/* Input charger voltage VPWR2 */
+#define PM2XXX_VPWR2_OVV_6_0		0x0
+#define PM2XXX_VPWR2_OVV_6_3		0x1
+#define PM2XXX_VPWR2_OVV_10		0x2
+#define PM2XXX_VPWR2_OVV_NONE		0x3
+
+/* Input charger drop VPWR2 */
+#define PM2XXX_VPWR2_HW_OPT_EN		(0x1<<4)
+#define PM2XXX_VPWR2_HW_OPT_DIS		(0x0<<4)
+
+#define PM2XXX_VPWR2_VALID_EN		(0x1<<3)
+#define PM2XXX_VPWR2_VALID_DIS		(0x0<<3)
+
+#define PM2XXX_VPWR2_DROP_EN		(0x1<<2)
+#define PM2XXX_VPWR2_DROP_DIS		(0x0<<2)
+
+/* Input charger voltage VPWR1 */
+#define PM2XXX_VPWR1_OVV_6_0		0x0
+#define PM2XXX_VPWR1_OVV_6_3		0x1
+#define PM2XXX_VPWR1_OVV_10		0x2
+#define PM2XXX_VPWR1_OVV_NONE		0x3
+
+/* Input charger drop VPWR1 */
+#define PM2XXX_VPWR1_HW_OPT_EN		(0x1<<4)
+#define PM2XXX_VPWR1_HW_OPT_DIS		(0x0<<4)
+
+#define PM2XXX_VPWR1_VALID_EN		(0x1<<3)
+#define PM2XXX_VPWR1_VALID_DIS		(0x0<<3)
+
+#define PM2XXX_VPWR1_DROP_EN		(0x1<<2)
+#define PM2XXX_VPWR1_DROP_DIS		(0x0<<2)
+
+/* Battery low level comparator control register */
+#define PM2XXX_VBAT_LOW_MONITORING_DIS	0x0
+#define PM2XXX_VBAT_LOW_MONITORING_ENA	0x1
+
+/* Battery low level value control register */
+#define PM2XXX_VBAT_LOW_LEVEL_2_3	0x0
+#define PM2XXX_VBAT_LOW_LEVEL_2_4	0x1
+#define PM2XXX_VBAT_LOW_LEVEL_2_5	0x2
+#define PM2XXX_VBAT_LOW_LEVEL_2_6	0x3
+#define PM2XXX_VBAT_LOW_LEVEL_2_7	0x4
+#define PM2XXX_VBAT_LOW_LEVEL_2_8	0x5
+#define PM2XXX_VBAT_LOW_LEVEL_2_9	0x6
+#define PM2XXX_VBAT_LOW_LEVEL_3_0	0x7
+#define PM2XXX_VBAT_LOW_LEVEL_3_1	0x8
+#define PM2XXX_VBAT_LOW_LEVEL_3_2	0x9
+#define PM2XXX_VBAT_LOW_LEVEL_3_3	0xA
+#define PM2XXX_VBAT_LOW_LEVEL_3_4	0xB
+#define PM2XXX_VBAT_LOW_LEVEL_3_5	0xC
+#define PM2XXX_VBAT_LOW_LEVEL_3_6	0xD
+#define PM2XXX_VBAT_LOW_LEVEL_3_7	0xE
+#define PM2XXX_VBAT_LOW_LEVEL_3_8	0xF
+#define PM2XXX_VBAT_LOW_LEVEL_3_9	0x10
+#define PM2XXX_VBAT_LOW_LEVEL_4_0	0x11
+#define PM2XXX_VBAT_LOW_LEVEL_4_1	0x12
+#define PM2XXX_VBAT_LOW_LEVEL_4_2	0x13
+
+/* SW CTRL */
+#define PM2XXX_SWCTRL_HW		0x0
+#define PM2XXX_SWCTRL_SW		0x1
+
+
+/* LED Driver Control */
+#define PM2XXX_LED_CURRENT_MASK		0x0C
+#define PM2XXX_LED_CURRENT_2_5MA	(0X0<<2)
+#define PM2XXX_LED_CURRENT_1MA		(0X1<<2)
+#define PM2XXX_LED_CURRENT_5MA		(0X2<<2)
+#define PM2XXX_LED_CURRENT_10MA		(0X3<<2)
+
+#define PM2XXX_LED_SELECT_MASK		0x02
+#define PM2XXX_LED_SELECT_EN		(0X0<<1)
+#define PM2XXX_LED_SELECT_DIS		(0X1<<1)
+
+#define PM2XXX_ANTI_OVERSHOOT_MASK	0x01
+#define PM2XXX_ANTI_OVERSHOOT_DIS	0X0
+#define PM2XXX_ANTI_OVERSHOOT_EN	0X1
+
+enum pm2xxx_reg_int1 {
+	PM2XXX_INT1_ITVBATDISCONNECT	= 0x02,
+	PM2XXX_INT1_ITVBATLOWR		= 0x04,
+	PM2XXX_INT1_ITVBATLOWF		= 0x08,
+};
+
+enum pm2xxx_mask_reg_int1 {
+	PM2XXX_INT1_M_ITVBATDISCONNECT	= 0x02,
+	PM2XXX_INT1_M_ITVBATLOWR	= 0x04,
+	PM2XXX_INT1_M_ITVBATLOWF	= 0x08,
+};
+
+enum pm2xxx_source_reg_int1 {
+	PM2XXX_INT1_S_ITVBATDISCONNECT	= 0x02,
+	PM2XXX_INT1_S_ITVBATLOWR	= 0x04,
+	PM2XXX_INT1_S_ITVBATLOWF	= 0x08,
+};
+
+enum pm2xxx_reg_int2 {
+	PM2XXX_INT2_ITVPWR2PLUG		= 0x01,
+	PM2XXX_INT2_ITVPWR2UNPLUG	= 0x02,
+	PM2XXX_INT2_ITVPWR1PLUG		= 0x04,
+	PM2XXX_INT2_ITVPWR1UNPLUG	= 0x08,
+};
+
+enum pm2xxx_mask_reg_int2 {
+	PM2XXX_INT2_M_ITVPWR2PLUG	= 0x01,
+	PM2XXX_INT2_M_ITVPWR2UNPLUG	= 0x02,
+	PM2XXX_INT2_M_ITVPWR1PLUG	= 0x04,
+	PM2XXX_INT2_M_ITVPWR1UNPLUG	= 0x08,
+};
+
+enum pm2xxx_source_reg_int2 {
+	PM2XXX_INT2_S_ITVPWR2PLUG	= 0x03,
+	PM2XXX_INT2_S_ITVPWR1PLUG	= 0x0c,
+};
+
+enum pm2xxx_reg_int3 {
+	PM2XXX_INT3_ITCHPRECHARGEWD	= 0x01,
+	PM2XXX_INT3_ITCHCCWD		= 0x02,
+	PM2XXX_INT3_ITCHCVWD		= 0x04,
+	PM2XXX_INT3_ITAUTOTIMEOUTWD	= 0x08,
+};
+
+enum pm2xxx_mask_reg_int3 {
+	PM2XXX_INT3_M_ITCHPRECHARGEWD	= 0x01,
+	PM2XXX_INT3_M_ITCHCCWD		= 0x02,
+	PM2XXX_INT3_M_ITCHCVWD		= 0x04,
+	PM2XXX_INT3_M_ITAUTOTIMEOUTWD	= 0x08,
+};
+
+enum pm2xxx_source_reg_int3 {
+	PM2XXX_INT3_S_ITCHPRECHARGEWD	= 0x01,
+	PM2XXX_INT3_S_ITCHCCWD		= 0x02,
+	PM2XXX_INT3_S_ITCHCVWD		= 0x04,
+	PM2XXX_INT3_S_ITAUTOTIMEOUTWD	= 0x08,
+};
+
+enum pm2xxx_reg_int4 {
+	PM2XXX_INT4_ITBATTEMPCOLD	= 0x01,
+	PM2XXX_INT4_ITBATTEMPHOT	= 0x02,
+	PM2XXX_INT4_ITVPWR2OVV		= 0x04,
+	PM2XXX_INT4_ITVPWR1OVV		= 0x08,
+	PM2XXX_INT4_ITCHARGINGON	= 0x10,
+	PM2XXX_INT4_ITVRESUME		= 0x20,
+	PM2XXX_INT4_ITBATTFULL		= 0x40,
+	PM2XXX_INT4_ITCVPHASE		= 0x80,
+};
+
+enum pm2xxx_mask_reg_int4 {
+	PM2XXX_INT4_M_ITBATTEMPCOLD	= 0x01,
+	PM2XXX_INT4_M_ITBATTEMPHOT	= 0x02,
+	PM2XXX_INT4_M_ITVPWR2OVV	= 0x04,
+	PM2XXX_INT4_M_ITVPWR1OVV	= 0x08,
+	PM2XXX_INT4_M_ITCHARGINGON	= 0x10,
+	PM2XXX_INT4_M_ITVRESUME		= 0x20,
+	PM2XXX_INT4_M_ITBATTFULL	= 0x40,
+	PM2XXX_INT4_M_ITCVPHASE		= 0x80,
+};
+
+enum pm2xxx_source_reg_int4 {
+	PM2XXX_INT4_S_ITBATTEMPCOLD	= 0x01,
+	PM2XXX_INT4_S_ITBATTEMPHOT	= 0x02,
+	PM2XXX_INT4_S_ITVPWR2OVV	= 0x04,
+	PM2XXX_INT4_S_ITVPWR1OVV	= 0x08,
+	PM2XXX_INT4_S_ITCHARGINGON	= 0x10,
+	PM2XXX_INT4_S_ITVRESUME		= 0x20,
+	PM2XXX_INT4_S_ITBATTFULL	= 0x40,
+	PM2XXX_INT4_S_ITCVPHASE		= 0x80,
+};
+
+enum pm2xxx_reg_int5 {
+	PM2XXX_INT5_ITTHERMALSHUTDOWNRISE	= 0x01,
+	PM2XXX_INT5_ITTHERMALSHUTDOWNFALL	= 0x02,
+	PM2XXX_INT5_ITTHERMALWARNINGRISE	= 0x04,
+	PM2XXX_INT5_ITTHERMALWARNINGFALL	= 0x08,
+	PM2XXX_INT5_ITVSYSTEMOVV		= 0x10,
+};
+
+enum pm2xxx_mask_reg_int5 {
+	PM2XXX_INT5_M_ITTHERMALSHUTDOWNRISE	= 0x01,
+	PM2XXX_INT5_M_ITTHERMALSHUTDOWNFALL	= 0x02,
+	PM2XXX_INT5_M_ITTHERMALWARNINGRISE	= 0x04,
+	PM2XXX_INT5_M_ITTHERMALWARNINGFALL	= 0x08,
+	PM2XXX_INT5_M_ITVSYSTEMOVV		= 0x10,
+};
+
+enum pm2xxx_source_reg_int5 {
+	PM2XXX_INT5_S_ITTHERMALSHUTDOWNRISE	= 0x01,
+	PM2XXX_INT5_S_ITTHERMALSHUTDOWNFALL	= 0x02,
+	PM2XXX_INT5_S_ITTHERMALWARNINGRISE	= 0x04,
+	PM2XXX_INT5_S_ITTHERMALWARNINGFALL	= 0x08,
+	PM2XXX_INT5_S_ITVSYSTEMOVV		= 0x10,
+};
+
+enum pm2xxx_reg_int6 {
+	PM2XXX_INT6_ITVPWR2DROP		= 0x01,
+	PM2XXX_INT6_ITVPWR1DROP		= 0x02,
+	PM2XXX_INT6_ITVPWR2VALIDRISE	= 0x04,
+	PM2XXX_INT6_ITVPWR2VALIDFALL	= 0x08,
+	PM2XXX_INT6_ITVPWR1VALIDRISE	= 0x10,
+	PM2XXX_INT6_ITVPWR1VALIDFALL	= 0x20,
+};
+
+enum pm2xxx_mask_reg_int6 {
+	PM2XXX_INT6_M_ITVPWR2DROP	= 0x01,
+	PM2XXX_INT6_M_ITVPWR1DROP	= 0x02,
+	PM2XXX_INT6_M_ITVPWR2VALIDRISE	= 0x04,
+	PM2XXX_INT6_M_ITVPWR2VALIDFALL	= 0x08,
+	PM2XXX_INT6_M_ITVPWR1VALIDRISE	= 0x10,
+	PM2XXX_INT6_M_ITVPWR1VALIDFALL	= 0x20,
+};
+
+enum pm2xxx_source_reg_int6 {
+	PM2XXX_INT6_S_ITVPWR2DROP	= 0x01,
+	PM2XXX_INT6_S_ITVPWR1DROP	= 0x02,
+	PM2XXX_INT6_S_ITVPWR2VALIDRISE	= 0x04,
+	PM2XXX_INT6_S_ITVPWR2VALIDFALL	= 0x08,
+	PM2XXX_INT6_S_ITVPWR1VALIDRISE	= 0x10,
+	PM2XXX_INT6_S_ITVPWR1VALIDFALL	= 0x20,
+};
+
+struct pm2xxx_charger_info {
+	int charger_connected;
+	int charger_online;
+	int cv_active;
+	bool wd_expired;
+};
+
+struct pm2xxx_charger_event_flags {
+	bool mainextchnotok;
+	bool main_thermal_prot;
+	bool ovv;
+	bool chgwdexp;
+};
+
+struct pm2xxx_interrupts {
+	u8 reg[PM2XXX_NUM_INT_REG];
+	int (*handler[PM2XXX_NUM_INT_REG])(void *, int);
+};
+
+struct pm2xxx_config {
+	struct i2c_client *pm2xxx_i2c;
+	struct i2c_device_id *pm2xxx_id;
+};
+
+struct pm2xxx_irq {
+	char *name;
+	irqreturn_t (*isr)(int irq, void *data);
+};
+
+struct pm2xxx_charger {
+	struct device *dev;
+	u8 chip_id;
+	bool vddadc_en_ac;
+	struct pm2xxx_config config;
+	bool ac_conn;
+	unsigned int gpio_irq;
+	int vbat;
+	int old_vbat;
+	int failure_case;
+	int failure_input_ovv;
+	unsigned int lpn_pin;
+	struct pm2xxx_interrupts *pm2_int;
+	struct ab8500_gpadc *gpadc;
+	struct regulator *regu;
+	struct pm2xxx_bm_data *bat;
+	struct mutex lock;
+	struct ab8500 *parent;
+	struct pm2xxx_charger_info ac;
+	struct pm2xxx_charger_platform_data *pdata;
+	struct workqueue_struct *charger_wq;
+	struct delayed_work check_vbat_work;
+	struct work_struct ac_work;
+	struct work_struct check_main_thermal_prot_work;
+	struct ux500_charger ac_chg;
+	struct pm2xxx_charger_event_flags flags;
+};
+
+#endif /* PM2301_CHARGER_H */
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 40fa3b7..29178f7 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -55,7 +55,8 @@
 	};
 	static char *health_text[] = {
 		"Unknown", "Good", "Overheat", "Dead", "Over voltage",
-		"Unspecified failure", "Cold",
+		"Unspecified failure", "Cold", "Watchdog timer expire",
+		"Safety timer expire"
 	};
 	static char *technology_text[] = {
 		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 6461b48..1ae65b8 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -13,3 +13,20 @@
 	  This driver supports turning off your board via a GPIO line.
 	  If your board needs a GPIO high/low to power down, say Y and
 	  create a binding in your devicetree.
+
+config POWER_RESET_QNAP
+	bool "QNAP power-off driver"
+	depends on OF_GPIO && POWER_RESET && PLAT_ORION
+	help
+	  This driver supports turning off QNAP NAS devices by sending
+	  commands to the microcontroller which controls the main power.
+
+	  Say Y if you have a QNAP NAS.
+
+config POWER_RESET_RESTART
+	bool "Restart power-off driver"
+	depends on ARM
+	help
+	  Some boards don't actually have the ability to power off.
+	  Instead they restart, and u-boot holds the SoC until the
+	  user presses a key. u-boot then boots into Linux.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 751488a..0f317f5 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1 +1,3 @@
 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
+obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
+obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
\ No newline at end of file
diff --git a/drivers/power/reset/qnap-poweroff.c b/drivers/power/reset/qnap-poweroff.c
new file mode 100644
index 0000000..37f56f7
--- /dev/null
+++ b/drivers/power/reset/qnap-poweroff.c
@@ -0,0 +1,116 @@
+/*
+ * QNAP Turbo NAS Board power off
+ *
+ * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch>
+ *
+ * Based on the code from:
+ *
+ * Copyright (C) 2009  Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2008  Byron Bradley <byron.bbradley@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial_reg.h>
+#include <linux/kallsyms.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#define UART1_REG(x)	(base + ((UART_##x) << 2))
+
+static void __iomem *base;
+static unsigned long tclk;
+
+static void qnap_power_off(void)
+{
+	/* 19200 baud divisor */
+	const unsigned divisor = ((tclk + (8 * 19200)) / (16 * 19200));
+
+	pr_err("%s: triggering power-off...\n", __func__);
+
+	/* hijack UART1 and reset into sane state (19200,8n1) */
+	writel(0x83, UART1_REG(LCR));
+	writel(divisor & 0xff, UART1_REG(DLL));
+	writel((divisor >> 8) & 0xff, UART1_REG(DLM));
+	writel(0x03, UART1_REG(LCR));
+	writel(0x00, UART1_REG(IER));
+	writel(0x00, UART1_REG(FCR));
+	writel(0x00, UART1_REG(MCR));
+
+	/* send the power-off command 'A' to PIC */
+	writel('A', UART1_REG(TX));
+}
+
+static int qnap_power_off_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct clk *clk;
+	char symname[KSYM_NAME_LEN];
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Missing resource");
+		return -EINVAL;
+	}
+
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_err(&pdev->dev, "Unable to map resource");
+		return -EINVAL;
+	}
+
+	/* We need to know tclk in order to calculate the UART divisor */
+	clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Clk missing");
+		return PTR_ERR(clk);
+	}
+
+	tclk = clk_get_rate(clk);
+
+	/* Check that nothing else has already setup a handler */
+	if (pm_power_off) {
+		lookup_symbol_name((ulong)pm_power_off, symname);
+		dev_err(&pdev->dev,
+			"pm_power_off already claimed %p %s",
+			pm_power_off, symname);
+		return -EBUSY;
+	}
+	pm_power_off = qnap_power_off;
+
+	return 0;
+}
+
+static int qnap_power_off_remove(struct platform_device *pdev)
+{
+	pm_power_off = NULL;
+	return 0;
+}
+
+static const struct of_device_id qnap_power_off_of_match_table[] = {
+	{ .compatible = "qnap,power-off", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table);
+
+static struct platform_driver qnap_power_off_driver = {
+	.probe	= qnap_power_off_probe,
+	.remove	= qnap_power_off_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "qnap_power_off",
+		.of_match_table = of_match_ptr(qnap_power_off_of_match_table),
+	},
+};
+module_platform_driver(qnap_power_off_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
+MODULE_DESCRIPTION("QNAP Power off driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c
new file mode 100644
index 0000000..059cd15
--- /dev/null
+++ b/drivers/power/reset/restart-poweroff.c
@@ -0,0 +1,65 @@
+/*
+ * Power off by restarting and let u-boot keep hold of the machine
+ * until the user presses a button for example.
+ *
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * Copyright (C) 2012 Andrew Lunn
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <asm/system_misc.h>
+
+static void restart_poweroff_do_poweroff(void)
+{
+	arm_pm_restart('h', NULL);
+}
+
+static int restart_poweroff_probe(struct platform_device *pdev)
+{
+	/* If a pm_power_off function has already been added, leave it alone */
+	if (pm_power_off != NULL) {
+		dev_err(&pdev->dev,
+			"pm_power_off function already registered");
+		return -EBUSY;
+	}
+
+	pm_power_off = &restart_poweroff_do_poweroff;
+	return 0;
+}
+
+static int restart_poweroff_remove(struct platform_device *pdev)
+{
+	if (pm_power_off == &restart_poweroff_do_poweroff)
+		pm_power_off = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id of_restart_poweroff_match[] = {
+	{ .compatible = "restart-poweroff", },
+	{},
+};
+
+static struct platform_driver restart_poweroff_driver = {
+	.probe = restart_poweroff_probe,
+	.remove = restart_poweroff_remove,
+	.driver = {
+		.name = "poweroff-restart",
+		.owner = THIS_MODULE,
+		.of_match_table = of_restart_poweroff_match,
+	},
+};
+module_platform_driver(restart_poweroff_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch");
+MODULE_DESCRIPTION("restart poweroff driver");
+MODULE_LICENSE("GPLv2");
+MODULE_ALIAS("platform:poweroff-restart");
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 2b55711..c79ab84 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -30,8 +30,6 @@
 	unsigned int	*vol_table;
 	unsigned int	*vol_suspend;
 
-	int	update_reg;
-	int	update_bit;
 	int	slope_double;
 };
 
@@ -222,29 +220,6 @@
 	return ret;
 }
 
-static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
-{
-	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-	uint8_t val;
-	int ret;
-
-	val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
-
-	ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
-			      rdev->desc->vsel_mask, val);
-	if (ret)
-		return ret;
-	switch (info->desc.id) {
-	case PM8607_ID_BUCK1:
-	case PM8607_ID_BUCK3:
-		ret = pm860x_set_bits(info->i2c, info->update_reg,
-				      1 << info->update_bit,
-				      1 << info->update_bit);
-		break;
-	}
-	return ret;
-}
-
 static int pm8606_preg_enable(struct regulator_dev *rdev)
 {
 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
@@ -276,7 +251,7 @@
 
 static struct regulator_ops pm8607_regulator_ops = {
 	.list_voltage	= pm8607_list_voltage,
-	.set_voltage_sel = pm8607_set_voltage_sel,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
@@ -313,11 +288,11 @@
 		.n_voltages = ARRAY_SIZE(vreg##_table),			\
 		.vsel_reg = PM8607_##vreg,				\
 		.vsel_mask = ARRAY_SIZE(vreg##_table) - 1,		\
+		.apply_reg = PM8607_##ureg,				\
+		.apply_bit = (ubit),					\
 		.enable_reg = PM8607_##ereg,				\
 		.enable_mask = 1 << (ebit),				\
 	},								\
-	.update_reg	= PM8607_##ureg,				\
-	.update_bit	= (ubit),					\
 	.slope_double	= (0),						\
 	.vol_table	= (unsigned int *)&vreg##_table,		\
 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
@@ -343,9 +318,9 @@
 }
 
 static struct pm8607_regulator_info pm8607_regulator_info[] = {
-	PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
-	PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
-	PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
+	PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0),
+	PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1),
+	PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2),
 
 	PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
 	PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
@@ -372,7 +347,7 @@
 				    struct regulator_config *config)
 {
 	struct device_node *nproot, *np;
-	nproot = pdev->dev.parent->of_node;
+	nproot = of_node_get(pdev->dev.parent->of_node);
 	if (!nproot)
 		return -ENODEV;
 	nproot = of_find_node_by_name(nproot, "regulators");
@@ -388,6 +363,7 @@
 			break;
 		}
 	}
+	of_node_put(nproot);
 	return 0;
 }
 #else
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 551a22b..a5d97ea 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -91,6 +91,7 @@
 config REGULATOR_ARIZONA
 	tristate "Wolfson Arizona class devices"
 	depends on MFD_ARIZONA
+	depends on SND_SOC
 	help
 	  Support for the regulators found on Wolfson Arizona class
 	  devices.
@@ -277,6 +278,15 @@
 	help
 	  This driver supports LP8720/LP8725 PMIC
 
+config REGULATOR_LP8755
+	tristate "TI LP8755 High Performance PMU driver"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports LP8755 High Performance PMU driver. This
+	  chip contains six step-down DC/DC converters which can support
+	  9 mode multiphase configuration.
+
 config REGULATOR_LP8788
 	bool "TI LP8788 Power Regulators"
 	depends on MFD_LP8788
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index b802b0c..6e82503 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
 obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
 obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
+obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 8f39cac..0d4a8cc 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -31,12 +31,18 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 
+#define LDO_RAMP_UP_UNIT_IN_CYCLES      64 /* 64 cycles per step */
+#define LDO_RAMP_UP_FREQ_IN_MHZ         24 /* cycle based on 24M OSC */
+
 struct anatop_regulator {
 	const char *name;
 	u32 control_reg;
 	struct regmap *anatop;
 	int vol_bit_shift;
 	int vol_bit_width;
+	u32 delay_reg;
+	int delay_bit_shift;
+	int delay_bit_width;
 	int min_bit_val;
 	int min_voltage;
 	int max_voltage;
@@ -55,6 +61,32 @@
 	return regulator_set_voltage_sel_regmap(reg, selector);
 }
 
+static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
+	unsigned int old_sel,
+	unsigned int new_sel)
+{
+	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+	u32 val;
+	int ret = 0;
+
+	/* check whether need to care about LDO ramp up speed */
+	if (anatop_reg->delay_bit_width && new_sel > old_sel) {
+		/*
+		 * the delay for LDO ramp up time is
+		 * based on the register setting, we need
+		 * to calculate how many steps LDO need to
+		 * ramp up, and how much delay needed. (us)
+		 */
+		regmap_read(anatop_reg->anatop, anatop_reg->delay_reg, &val);
+		val = (val >> anatop_reg->delay_bit_shift) &
+			((1 << anatop_reg->delay_bit_width) - 1);
+		ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES <<
+			val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1;
+	}
+
+	return ret;
+}
+
 static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
 {
 	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
@@ -67,6 +99,7 @@
 
 static struct regulator_ops anatop_rops = {
 	.set_voltage_sel = anatop_regmap_set_voltage_sel,
+	.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
 	.get_voltage_sel = anatop_regmap_get_voltage_sel,
 	.list_voltage = regulator_list_voltage_linear,
 	.map_voltage = regulator_map_voltage_linear,
@@ -143,6 +176,14 @@
 		goto anatop_probe_end;
 	}
 
+	/* read LDO ramp up setting, only for core reg */
+	of_property_read_u32(np, "anatop-delay-reg-offset",
+			     &sreg->delay_reg);
+	of_property_read_u32(np, "anatop-delay-bit-width",
+			     &sreg->delay_bit_width);
+	of_property_read_u32(np, "anatop-delay-bit-shift",
+			     &sreg->delay_bit_shift);
+
 	rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
 			    + sreg->min_bit_val;
 	rdesc->min_uV = sreg->min_voltage;
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index a6d040c..e87536b 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -21,6 +21,8 @@
 #include <linux/regulator/machine.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
 
 #include <linux/mfd/arizona/core.h>
 #include <linux/mfd/arizona/pdata.h>
@@ -34,6 +36,8 @@
 
 	struct regulator_consumer_supply supply;
 	struct regulator_init_data init_data;
+
+	struct work_struct check_cp_work;
 };
 
 static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
@@ -72,9 +76,73 @@
 	return selector;
 }
 
+static void arizona_micsupp_check_cp(struct work_struct *work)
+{
+	struct arizona_micsupp *micsupp =
+		container_of(work, struct arizona_micsupp, check_cp_work);
+	struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
+	struct arizona *arizona = micsupp->arizona;
+	struct regmap *regmap = arizona->regmap;
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, &reg);
+	if (ret != 0) {
+		dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
+		return;
+	}
+
+	if (dapm) {
+		if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
+		    ARIZONA_CPMIC_ENA)
+			snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
+		else
+			snd_soc_dapm_disable_pin(dapm, "MICSUPP");
+
+		snd_soc_dapm_sync(dapm);
+	}
+}
+
+static int arizona_micsupp_enable(struct regulator_dev *rdev)
+{
+	struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = regulator_enable_regmap(rdev);
+
+	if (ret == 0)
+		schedule_work(&micsupp->check_cp_work);
+
+	return ret;
+}
+
+static int arizona_micsupp_disable(struct regulator_dev *rdev)
+{
+	struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = regulator_disable_regmap(rdev);
+	if (ret == 0)
+		schedule_work(&micsupp->check_cp_work);
+
+	return ret;
+}
+
+static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
+{
+	struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = regulator_set_bypass_regmap(rdev, ena);
+	if (ret == 0)
+		schedule_work(&micsupp->check_cp_work);
+
+	return ret;
+}
+
 static struct regulator_ops arizona_micsupp_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
+	.enable = arizona_micsupp_enable,
+	.disable = arizona_micsupp_disable,
 	.is_enabled = regulator_is_enabled_regmap,
 
 	.list_voltage = arizona_micsupp_list_voltage,
@@ -84,7 +152,7 @@
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 
 	.get_bypass = regulator_get_bypass_regmap,
-	.set_bypass = regulator_set_bypass_regmap,
+	.set_bypass = arizona_micsupp_set_bypass,
 };
 
 static const struct regulator_desc arizona_micsupp = {
@@ -109,7 +177,8 @@
 static const struct regulator_init_data arizona_micsupp_default = {
 	.constraints = {
 		.valid_ops_mask = REGULATOR_CHANGE_STATUS |
-				REGULATOR_CHANGE_VOLTAGE,
+				REGULATOR_CHANGE_VOLTAGE |
+				REGULATOR_CHANGE_BYPASS,
 		.min_uV = 1700000,
 		.max_uV = 3300000,
 	},
@@ -131,6 +200,7 @@
 	}
 
 	micsupp->arizona = arizona;
+	INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
 
 	/*
 	 * Since the chip usually supplies itself we provide some
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index 2f1341d..f0ba8c4 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -303,7 +303,7 @@
 		reg_data = pdata ? pdata->init_data[id] : NULL;
 
 		/* No need to register if there is no regulator data */
-		if (!ri->desc.name)
+		if (!reg_data)
 			continue;
 
 		reg = &regs[id];
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2785843..da9782b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -200,8 +200,8 @@
 	}
 
 	if (*min_uV > *max_uV) {
-		dev_err(regulator->dev, "Restricting voltage, %u-%uuV\n",
-			regulator->min_uV, regulator->max_uV);
+		rdev_err(rdev, "Restricting voltage, %u-%uuV\n",
+			*min_uV, *max_uV);
 		return -EINVAL;
 	}
 
@@ -2080,10 +2080,20 @@
  */
 int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
 {
+	int ret;
+
 	sel <<= ffs(rdev->desc->vsel_mask) - 1;
 
-	return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
 				  rdev->desc->vsel_mask, sel);
+	if (ret)
+		return ret;
+
+	if (rdev->desc->apply_bit)
+		ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+					 rdev->desc->apply_bit,
+					 rdev->desc->apply_bit);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
 
@@ -2229,8 +2239,11 @@
 			best_val = rdev->desc->ops->list_voltage(rdev, ret);
 			if (min_uV <= best_val && max_uV >= best_val) {
 				selector = ret;
-				ret = rdev->desc->ops->set_voltage_sel(rdev,
-								       ret);
+				if (old_selector == selector)
+					ret = 0;
+				else
+					ret = rdev->desc->ops->set_voltage_sel(
+								rdev, ret);
 			} else {
 				ret = -EINVAL;
 			}
@@ -2241,7 +2254,7 @@
 
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
 	if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
-	    rdev->desc->ops->set_voltage_time_sel) {
+	    old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
 
 		delay = rdev->desc->ops->set_voltage_time_sel(rdev,
 						old_selector, selector);
@@ -2294,6 +2307,7 @@
 {
 	struct regulator_dev *rdev = regulator->rdev;
 	int ret = 0;
+	int old_min_uV, old_max_uV;
 
 	mutex_lock(&rdev->mutex);
 
@@ -2315,18 +2329,29 @@
 	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
 	if (ret < 0)
 		goto out;
+	
+	/* restore original values in case of error */
+	old_min_uV = regulator->min_uV;
+	old_max_uV = regulator->max_uV;
 	regulator->min_uV = min_uV;
 	regulator->max_uV = max_uV;
 
 	ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
 	if (ret < 0)
-		goto out;
+		goto out2;
 
 	ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
-
+	if (ret < 0)
+		goto out2;
+	
 out:
 	mutex_unlock(&rdev->mutex);
 	return ret;
+out2:
+	regulator->min_uV = old_min_uV;
+	regulator->max_uV = old_max_uV;
+	mutex_unlock(&rdev->mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage);
 
@@ -3208,7 +3233,7 @@
 		if (status < 0)
 			return status;
 	}
-	if (ops->is_enabled) {
+	if (rdev->ena_gpio || ops->is_enabled) {
 		status = device_create_file(dev, &dev_attr_state);
 		if (status < 0)
 			return status;
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index d096309..96b569a 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -70,7 +70,6 @@
 	int step_uV;
 	int min_uV;
 	int max_uV;
-	unsigned char activate_bit;
 };
 
 struct da9052_regulator {
@@ -210,36 +209,6 @@
 	return sel;
 }
 
-static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
-					    unsigned int selector)
-{
-	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
-	struct da9052_regulator_info *info = regulator->info;
-	int id = rdev_get_id(rdev);
-	int ret;
-
-	ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
-				rdev->desc->vsel_mask, selector);
-	if (ret < 0)
-		return ret;
-
-	/* Some LDOs and DCDCs are DVC controlled which requires enabling of
-	 * the activate bit to implment the changes on the output.
-	 */
-	switch (id) {
-	case DA9052_ID_BUCK1:
-	case DA9052_ID_BUCK2:
-	case DA9052_ID_BUCK3:
-	case DA9052_ID_LDO2:
-	case DA9052_ID_LDO3:
-		ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
-					info->activate_bit, info->activate_bit);
-		break;
-	}
-
-	return ret;
-}
-
 static struct regulator_ops da9052_dcdc_ops = {
 	.get_current_limit = da9052_dcdc_get_current_limit,
 	.set_current_limit = da9052_dcdc_set_current_limit,
@@ -247,7 +216,7 @@
 	.list_voltage = da9052_list_voltage,
 	.map_voltage = da9052_map_voltage,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_sel = da9052_regulator_set_voltage_sel,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
@@ -257,7 +226,7 @@
 	.list_voltage = da9052_list_voltage,
 	.map_voltage = da9052_map_voltage,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_sel = da9052_regulator_set_voltage_sel,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
@@ -274,13 +243,14 @@
 		.owner = THIS_MODULE,\
 		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
 		.vsel_mask = (1 << (sbits)) - 1,\
+		.apply_reg = DA9052_SUPPLY_REG, \
+		.apply_bit = (abits), \
 		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
 		.enable_mask = 1 << (ebits),\
 	},\
 	.min_uV = (min) * 1000,\
 	.max_uV = (max) * 1000,\
 	.step_uV = (step) * 1000,\
-	.activate_bit = (abits),\
 }
 
 #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \
@@ -294,13 +264,14 @@
 		.owner = THIS_MODULE,\
 		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
 		.vsel_mask = (1 << (sbits)) - 1,\
+		.apply_reg = DA9052_SUPPLY_REG, \
+		.apply_bit = (abits), \
 		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
 		.enable_mask = 1 << (ebits),\
 	},\
 	.min_uV = (min) * 1000,\
 	.max_uV = (max) * 1000,\
 	.step_uV = (step) * 1000,\
-	.activate_bit = (abits),\
 }
 
 static struct da9052_regulator_info da9052_regulator_info[] = {
@@ -395,9 +366,9 @@
 		config.init_data = pdata->regulators[pdev->id];
 	} else {
 #ifdef CONFIG_OF
-		struct device_node *nproot = da9052->dev->of_node;
-		struct device_node *np;
+		struct device_node *nproot, *np;
 
+		nproot = of_node_get(da9052->dev->of_node);
 		if (!nproot)
 			return -ENODEV;
 
@@ -414,6 +385,7 @@
 				break;
 			}
 		}
+		of_node_put(nproot);
 #endif
 	}
 
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index 1a05ac6..3022109 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -58,7 +58,6 @@
 	int reg_b;
 	int sl_shift;
 	int v_mask;
-	int v_shift;
 };
 
 struct da9055_mode_reg {
@@ -388,7 +387,6 @@
 		.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
 		.sl_shift = 7,\
 		.v_mask = (1 << (vbits)) - 1,\
-		.v_shift = (vbits),\
 	},\
 }
 
@@ -417,7 +415,6 @@
 		.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
 		.sl_shift = 7,\
 		.v_mask = (1 << (vbits)) - 1,\
-		.v_shift = (vbits),\
 	},\
 	.mode = {\
 		.reg = DA9055_REG_BCORE_MODE,\
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index bae681c..9d39eb4 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -132,7 +132,7 @@
 	.list_voltage = gpio_regulator_list_voltage,
 };
 
-struct gpio_regulator_config *
+static struct gpio_regulator_config *
 of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
 {
 	struct gpio_regulator_config *config;
@@ -163,10 +163,7 @@
 	config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
 
 	/* Fetch GPIOs. */
-	for (i = 0; ; i++)
-		if (of_get_named_gpio(np, "gpios", i) < 0)
-			break;
-	config->nr_gpios = i;
+	config->nr_gpios = of_gpio_count(np);
 
 	config->gpios = devm_kzalloc(dev,
 				sizeof(struct gpio) * config->nr_gpios,
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 5f68ff1..9cb2c0f 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -73,8 +73,6 @@
 };
 
 #define BUCK_TARGET_VOL_MASK 0x3f
-#define BUCK_TARGET_VOL_MIN_IDX 0x01
-#define BUCK_TARGET_VOL_MAX_IDX 0x19
 
 #define LP3971_BUCK_RAMP_REG(x)	(buck_base_addr[x]+2)
 
@@ -140,7 +138,7 @@
 	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
 }
 
-static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
+static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
 {
 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
 	int ldo = rdev_get_id(dev) - LP3971_LDO1;
@@ -149,7 +147,7 @@
 	reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
 	val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
 
-	return dev->desc->volt_table[val];
+	return val;
 }
 
 static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -168,7 +166,7 @@
 	.is_enabled = lp3971_ldo_is_enabled,
 	.enable = lp3971_ldo_enable,
 	.disable = lp3971_ldo_disable,
-	.get_voltage = lp3971_ldo_get_voltage,
+	.get_voltage_sel = lp3971_ldo_get_voltage_sel,
 	.set_voltage_sel = lp3971_ldo_set_voltage_sel,
 };
 
@@ -201,24 +199,16 @@
 	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
 }
 
-static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
+static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
 	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
 	int buck = rdev_get_id(dev) - LP3971_DCDC1;
 	u16 reg;
-	int val;
 
 	reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
 	reg &= BUCK_TARGET_VOL_MASK;
 
-	if (reg <= BUCK_TARGET_VOL_MAX_IDX)
-		val = buck_voltage_map[reg];
-	else {
-		val = 0;
-		dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
-	}
-
-	return val;
+	return reg;
 }
 
 static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -249,7 +239,7 @@
 	.is_enabled = lp3971_dcdc_is_enabled,
 	.enable = lp3971_dcdc_enable,
 	.disable = lp3971_dcdc_disable,
-	.get_voltage = lp3971_dcdc_get_voltage,
+	.get_voltage_sel = lp3971_dcdc_get_voltage_sel,
 	.set_voltage_sel = lp3971_dcdc_set_voltage_sel,
 };
 
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 69c42c3..0baabcf 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -165,8 +165,6 @@
 #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
 #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
 #define LP3972_BUCK_VOL_MASK 0x1f
-#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00)
-#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f)
 
 static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
 	u16 *dest)
@@ -257,7 +255,7 @@
 				mask, 0);
 }
 
-static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
+static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev)
 {
 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
 	int ldo = rdev_get_id(dev) - LP3972_LDO1;
@@ -267,7 +265,7 @@
 	reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
 	val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
 
-	return dev->desc->volt_table[val];
+	return val;
 }
 
 static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -314,7 +312,7 @@
 	.is_enabled = lp3972_ldo_is_enabled,
 	.enable = lp3972_ldo_enable,
 	.disable = lp3972_ldo_disable,
-	.get_voltage = lp3972_ldo_get_voltage,
+	.get_voltage_sel = lp3972_ldo_get_voltage_sel,
 	.set_voltage_sel = lp3972_ldo_set_voltage_sel,
 };
 
@@ -353,24 +351,16 @@
 	return val;
 }
 
-static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
+static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
 	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
 	int buck = rdev_get_id(dev) - LP3972_DCDC1;
 	u16 reg;
-	int val;
 
 	reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
 	reg &= LP3972_BUCK_VOL_MASK;
-	if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
-		val = dev->desc->volt_table[reg];
-	else {
-		val = 0;
-		dev_warn(&dev->dev, "chip reported incorrect voltage value."
-				    " reg = %d\n", reg);
-	}
 
-	return val;
+	return reg;
 }
 
 static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -402,7 +392,7 @@
 	.is_enabled = lp3972_dcdc_is_enabled,
 	.enable = lp3972_dcdc_enable,
 	.disable = lp3972_dcdc_disable,
-	.get_voltage = lp3972_dcdc_get_voltage,
+	.get_voltage_sel = lp3972_dcdc_get_voltage_sel,
 	.set_voltage_sel = lp3972_dcdc_set_voltage_sel,
 };
 
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 9289ead..8e3c7ae 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -181,20 +181,6 @@
 	return regmap_update_bits(lp->regmap, addr, mask, data);
 }
 
-static int _rdev_to_offset(struct regulator_dev *rdev)
-{
-	enum lp872x_regulator_id id = rdev_get_id(rdev);
-
-	switch (id) {
-	case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
-		return id;
-	case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
-		return id - LP8725_ID_BASE;
-	default:
-		return -EINVAL;
-	}
-}
-
 static int lp872x_get_timestep_usec(struct lp872x *lp)
 {
 	enum lp872x_id chip = lp->chipid;
@@ -234,28 +220,20 @@
 static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
 {
 	struct lp872x *lp = rdev_get_drvdata(rdev);
-	enum lp872x_regulator_id regulator = rdev_get_id(rdev);
+	enum lp872x_regulator_id rid = rdev_get_id(rdev);
 	int time_step_us = lp872x_get_timestep_usec(lp);
-	int ret, offset;
+	int ret;
 	u8 addr, val;
 
 	if (time_step_us < 0)
 		return -EINVAL;
 
-	switch (regulator) {
-	case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
-	case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
-		offset = _rdev_to_offset(rdev);
-		if (offset < 0)
-			return -EINVAL;
-
-		addr = LP872X_LDO1_VOUT + offset;
+	switch (rid) {
+	case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
+		addr = LP872X_LDO1_VOUT + rid;
 		break;
-	case LP8720_ID_BUCK:
-		addr = LP8720_BUCK_VOUT1;
-		break;
-	case LP8725_ID_BUCK1:
-		addr = LP8725_BUCK1_VOUT1;
+	case LP8725_ID_LDO1 ... LP8725_ID_BUCK1:
+		addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE;
 		break;
 	case LP8725_ID_BUCK2:
 		addr = LP8725_BUCK2_VOUT1;
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
new file mode 100644
index 0000000..f0f6ea0
--- /dev/null
+++ b/drivers/regulator/lp8755.c
@@ -0,0 +1,566 @@
+/*
+ * LP8755 High Performance Power Management Unit : System Interface Driver
+ * (based on rev. 0.26)
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/platform_data/lp8755.h>
+
+#define LP8755_REG_BUCK0	0x00
+#define LP8755_REG_BUCK1	0x03
+#define LP8755_REG_BUCK2	0x04
+#define LP8755_REG_BUCK3	0x01
+#define LP8755_REG_BUCK4	0x05
+#define LP8755_REG_BUCK5	0x02
+#define LP8755_REG_MAX		0xFF
+
+#define LP8755_BUCK_EN_M	BIT(7)
+#define LP8755_BUCK_LINEAR_OUT_MAX	0x76
+#define LP8755_BUCK_VOUT_M	0x7F
+
+struct lp8755_mphase {
+	int nreg;
+	int buck_num[LP8755_BUCK_MAX];
+};
+
+struct lp8755_chip {
+	struct device *dev;
+	struct regmap *regmap;
+	struct lp8755_platform_data *pdata;
+
+	int irq;
+	unsigned int irqmask;
+
+	int mphase;
+	struct regulator_dev *rdev[LP8755_BUCK_MAX];
+};
+
+/**
+ *lp8755_read : read a single register value from lp8755.
+ *@pchip : device to read from
+ *@reg   : register to read from
+ *@val   : pointer to store read value
+ */
+static int lp8755_read(struct lp8755_chip *pchip, unsigned int reg,
+		       unsigned int *val)
+{
+	return regmap_read(pchip->regmap, reg, val);
+}
+
+/**
+ *lp8755_write : write a single register value to lp8755.
+ *@pchip : device to write to
+ *@reg   : register to write to
+ *@val   : value to be written
+ */
+static int lp8755_write(struct lp8755_chip *pchip, unsigned int reg,
+			unsigned int val)
+{
+	return regmap_write(pchip->regmap, reg, val);
+}
+
+/**
+ *lp8755_update_bits : set the values of bit fields in lp8755 register.
+ *@pchip : device to read from
+ *@reg   : register to update
+ *@mask  : bitmask to be changed
+ *@val   : value for bitmask
+ */
+static int lp8755_update_bits(struct lp8755_chip *pchip, unsigned int reg,
+			      unsigned int mask, unsigned int val)
+{
+	return regmap_update_bits(pchip->regmap, reg, mask, val);
+}
+
+static int lp8755_buck_enable_time(struct regulator_dev *rdev)
+{
+	int ret;
+	unsigned int regval;
+	enum lp8755_bucks id = rdev_get_id(rdev);
+	struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+	ret = lp8755_read(pchip, 0x12 + id, &regval);
+	if (ret < 0) {
+		dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+		return ret;
+	}
+	return (regval & 0xff) * 100;
+}
+
+static int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret;
+	unsigned int regbval = 0x0;
+	enum lp8755_bucks id = rdev_get_id(rdev);
+	struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* forced pwm mode */
+		regbval = (0x01 << id);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		/* enable automatic pwm/pfm mode */
+		ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x00);
+		if (ret < 0)
+			goto err_i2c;
+		break;
+	case REGULATOR_MODE_IDLE:
+		/* enable automatic pwm/pfm/lppfm mode */
+		ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x20);
+		if (ret < 0)
+			goto err_i2c;
+
+		ret = lp8755_update_bits(pchip, 0x10, 0x01, 0x01);
+		if (ret < 0)
+			goto err_i2c;
+		break;
+	default:
+		dev_err(pchip->dev, "Not supported buck mode %s\n", __func__);
+		/* forced pwm mode */
+		regbval = (0x01 << id);
+	}
+
+	ret = lp8755_update_bits(pchip, 0x06, 0x01 << id, regbval);
+	if (ret < 0)
+		goto err_i2c;
+	return ret;
+err_i2c:
+	dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+	return ret;
+}
+
+static unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev)
+{
+	int ret;
+	unsigned int regval;
+	enum lp8755_bucks id = rdev_get_id(rdev);
+	struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+	ret = lp8755_read(pchip, 0x06, &regval);
+	if (ret < 0)
+		goto err_i2c;
+
+	/* mode fast means forced pwm mode */
+	if (regval & (0x01 << id))
+		return REGULATOR_MODE_FAST;
+
+	ret = lp8755_read(pchip, 0x08 + id, &regval);
+	if (ret < 0)
+		goto err_i2c;
+
+	/* mode idle means automatic pwm/pfm/lppfm mode */
+	if (regval & 0x20)
+		return REGULATOR_MODE_IDLE;
+
+	/* mode normal means automatic pwm/pfm mode */
+	return REGULATOR_MODE_NORMAL;
+
+err_i2c:
+	dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+	return 0;
+}
+
+static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
+{
+	int ret;
+	unsigned int regval = 0x00;
+	enum lp8755_bucks id = rdev_get_id(rdev);
+	struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+	/* uV/us */
+	switch (ramp) {
+	case 0 ... 230:
+		regval = 0x07;
+		break;
+	case 231 ... 470:
+		regval = 0x06;
+		break;
+	case 471 ... 940:
+		regval = 0x05;
+		break;
+	case 941 ... 1900:
+		regval = 0x04;
+		break;
+	case 1901 ... 3800:
+		regval = 0x03;
+		break;
+	case 3801 ... 7500:
+		regval = 0x02;
+		break;
+	case 7501 ... 15000:
+		regval = 0x01;
+		break;
+	case 15001 ... 30000:
+		regval = 0x00;
+		break;
+	default:
+		dev_err(pchip->dev,
+			"Not supported ramp value %d %s\n", ramp, __func__);
+		return -EINVAL;
+	}
+
+	ret = lp8755_update_bits(pchip, 0x07 + id, 0x07, regval);
+	if (ret < 0)
+		goto err_i2c;
+	return ret;
+err_i2c:
+	dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+	return ret;
+}
+
+static struct regulator_ops lp8755_buck_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.enable_time = lp8755_buck_enable_time,
+	.set_mode = lp8755_buck_set_mode,
+	.get_mode = lp8755_buck_get_mode,
+	.set_ramp_delay = lp8755_buck_set_ramp,
+};
+
+#define lp8755_rail(_id) "lp8755_buck"#_id
+#define lp8755_buck_init(_id)\
+{\
+	.constraints = {\
+		.name = lp8755_rail(_id),\
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\
+		.min_uV = 500000,\
+		.max_uV = 1675000,\
+	},\
+}
+
+static struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = {
+	[LP8755_BUCK0] = lp8755_buck_init(0),
+	[LP8755_BUCK1] = lp8755_buck_init(1),
+	[LP8755_BUCK2] = lp8755_buck_init(2),
+	[LP8755_BUCK3] = lp8755_buck_init(3),
+	[LP8755_BUCK4] = lp8755_buck_init(4),
+	[LP8755_BUCK5] = lp8755_buck_init(5),
+};
+
+static const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = {
+	{ 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } },
+	{ 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3,
+	       LP8755_BUCK4, LP8755_BUCK5 } },
+	{ 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4,
+	       LP8755_BUCK5} },
+	{ 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} },
+	{ 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} },
+	{ 2, { LP8755_BUCK0, LP8755_BUCK5} },
+	{ 1, { LP8755_BUCK0} },
+	{ 2, { LP8755_BUCK0, LP8755_BUCK3} },
+	{ 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} },
+};
+
+static int lp8755_init_data(struct lp8755_chip *pchip)
+{
+	unsigned int regval;
+	int ret, icnt, buck_num;
+	struct lp8755_platform_data *pdata = pchip->pdata;
+
+	/* read back  muti-phase configuration */
+	ret = lp8755_read(pchip, 0x3D, &regval);
+	if (ret < 0)
+		goto out_i2c_error;
+	pchip->mphase = regval & 0x0F;
+
+	/* set default data based on multi-phase config */
+	for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
+		buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
+		pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num];
+	}
+	return ret;
+
+out_i2c_error:
+	dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+	return ret;
+}
+
+#define lp8755_buck_desc(_id)\
+{\
+	.name = lp8755_rail(_id),\
+	.id   = LP8755_BUCK##_id,\
+	.ops  = &lp8755_buck_ops,\
+	.n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\
+	.uV_step = 10000,\
+	.min_uV = 500000,\
+	.type = REGULATOR_VOLTAGE,\
+	.owner = THIS_MODULE,\
+	.enable_reg = LP8755_REG_BUCK##_id,\
+	.enable_mask = LP8755_BUCK_EN_M,\
+	.vsel_reg = LP8755_REG_BUCK##_id,\
+	.vsel_mask = LP8755_BUCK_VOUT_M,\
+}
+
+static struct regulator_desc lp8755_regulators[] = {
+	lp8755_buck_desc(0),
+	lp8755_buck_desc(1),
+	lp8755_buck_desc(2),
+	lp8755_buck_desc(3),
+	lp8755_buck_desc(4),
+	lp8755_buck_desc(5),
+};
+
+static int lp8755_regulator_init(struct lp8755_chip *pchip)
+{
+	int ret, icnt, buck_num;
+	struct lp8755_platform_data *pdata = pchip->pdata;
+	struct regulator_config rconfig = { };
+
+	rconfig.regmap = pchip->regmap;
+	rconfig.dev = pchip->dev;
+	rconfig.driver_data = pchip;
+
+	for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
+		buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
+		rconfig.init_data = pdata->buck_data[buck_num];
+		rconfig.of_node = pchip->dev->of_node;
+		pchip->rdev[buck_num] =
+		    regulator_register(&lp8755_regulators[buck_num], &rconfig);
+		if (IS_ERR(pchip->rdev[buck_num])) {
+			ret = PTR_ERR(pchip->rdev[buck_num]);
+			pchip->rdev[buck_num] = NULL;
+			dev_err(pchip->dev, "regulator init failed: buck %d\n",
+				buck_num);
+			goto err_buck;
+		}
+	}
+
+	return 0;
+
+err_buck:
+	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+		regulator_unregister(pchip->rdev[icnt]);
+	return ret;
+}
+
+static irqreturn_t lp8755_irq_handler(int irq, void *data)
+{
+	int ret, icnt;
+	unsigned int flag0, flag1;
+	struct lp8755_chip *pchip = data;
+
+	/* read flag0 register */
+	ret = lp8755_read(pchip, 0x0D, &flag0);
+	if (ret < 0)
+		goto err_i2c;
+	/* clear flag register to pull up int. pin */
+	ret = lp8755_write(pchip, 0x0D, 0x00);
+	if (ret < 0)
+		goto err_i2c;
+
+	/* sent power fault detection event to specific regulator */
+	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+		if ((flag0 & (0x4 << icnt))
+		    && (pchip->irqmask & (0x04 << icnt))
+		    && (pchip->rdev[icnt] != NULL))
+			regulator_notifier_call_chain(pchip->rdev[icnt],
+						      LP8755_EVENT_PWR_FAULT,
+						      NULL);
+
+	/* read flag1 register */
+	ret = lp8755_read(pchip, 0x0E, &flag1);
+	if (ret < 0)
+		goto err_i2c;
+	/* clear flag register to pull up int. pin */
+	ret = lp8755_write(pchip, 0x0E, 0x00);
+	if (ret < 0)
+		goto err_i2c;
+
+	/* send OCP event to all regualtor devices */
+	if ((flag1 & 0x01) && (pchip->irqmask & 0x01))
+		for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+			if (pchip->rdev[icnt] != NULL)
+				regulator_notifier_call_chain(pchip->rdev[icnt],
+							      LP8755_EVENT_OCP,
+							      NULL);
+
+	/* send OVP event to all regualtor devices */
+	if ((flag1 & 0x02) && (pchip->irqmask & 0x02))
+		for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+			if (pchip->rdev[icnt] != NULL)
+				regulator_notifier_call_chain(pchip->rdev[icnt],
+							      LP8755_EVENT_OVP,
+							      NULL);
+	return IRQ_HANDLED;
+
+err_i2c:
+	dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+	return IRQ_NONE;
+}
+
+static int lp8755_int_config(struct lp8755_chip *pchip)
+{
+	int ret;
+	unsigned int regval;
+
+	if (pchip->irq == 0) {
+		dev_warn(pchip->dev, "not use interrupt : %s\n", __func__);
+		return 0;
+	}
+
+	ret = lp8755_read(pchip, 0x0F, &regval);
+	if (ret < 0)
+		goto err_i2c;
+	pchip->irqmask = regval;
+	ret = request_threaded_irq(pchip->irq, NULL, lp8755_irq_handler,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   "lp8755-irq", pchip);
+	if (ret)
+		return ret;
+
+	return ret;
+
+err_i2c:
+	dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+	return ret;
+}
+
+static const struct regmap_config lp8755_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = LP8755_REG_MAX,
+};
+
+static int lp8755_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret, icnt;
+	struct lp8755_chip *pchip;
+	struct lp8755_platform_data *pdata = client->dev.platform_data;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "i2c functionality check fail.\n");
+		return -EOPNOTSUPP;
+	}
+
+	pchip = devm_kzalloc(&client->dev,
+			     sizeof(struct lp8755_chip), GFP_KERNEL);
+	if (!pchip)
+		return -ENOMEM;
+
+	pchip->dev = &client->dev;
+	pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap);
+	if (IS_ERR(pchip->regmap)) {
+		ret = PTR_ERR(pchip->regmap);
+		dev_err(&client->dev, "fail to allocate regmap %d\n", ret);
+		return ret;
+	}
+	i2c_set_clientdata(client, pchip);
+
+	if (pdata != NULL) {
+		pchip->pdata = pdata;
+		pchip->mphase = pdata->mphase;
+	} else {
+		pchip->pdata = devm_kzalloc(pchip->dev,
+					    sizeof(struct lp8755_platform_data),
+					    GFP_KERNEL);
+		if (!pchip->pdata)
+			return -ENOMEM;
+		ret = lp8755_init_data(pchip);
+		if (ret < 0) {
+			dev_err(&client->dev, "fail to initialize chip\n");
+			return ret;
+		}
+	}
+
+	ret = lp8755_regulator_init(pchip);
+	if (ret < 0) {
+		dev_err(&client->dev, "fail to initialize regulators\n");
+		goto err_regulator;
+	}
+
+	pchip->irq = client->irq;
+	ret = lp8755_int_config(pchip);
+	if (ret < 0) {
+		dev_err(&client->dev, "fail to irq config\n");
+		goto err_irq;
+	}
+
+	return ret;
+
+err_irq:
+	for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
+		regulator_unregister(pchip->rdev[icnt]);
+
+err_regulator:
+	/* output disable */
+	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+		lp8755_write(pchip, icnt, 0x00);
+
+	return ret;
+}
+
+static int lp8755_remove(struct i2c_client *client)
+{
+	int icnt;
+	struct lp8755_chip *pchip = i2c_get_clientdata(client);
+
+	for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
+		regulator_unregister(pchip->rdev[icnt]);
+
+	for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+		lp8755_write(pchip, icnt, 0x00);
+
+	if (pchip->irq != 0)
+		free_irq(pchip->irq, pchip);
+
+	return 0;
+}
+
+static const struct i2c_device_id lp8755_id[] = {
+	{LP8755_NAME, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp8755_id);
+
+static struct i2c_driver lp8755_i2c_driver = {
+	.driver = {
+		   .name = LP8755_NAME,
+		   },
+	.probe = lp8755_probe,
+	.remove = lp8755_remove,
+	.id_table = lp8755_id,
+};
+
+static int __init lp8755_init(void)
+{
+	return i2c_add_driver(&lp8755_i2c_driver);
+}
+
+subsys_initcall(lp8755_init);
+
+static void __exit lp8755_exit(void)
+{
+	i2c_del_driver(&lp8755_i2c_driver);
+}
+
+module_exit(lp8755_exit);
+
+MODULE_DESCRIPTION("Texas Instruments lp8755 driver");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
index aef3f2b..97891a7 100644
--- a/drivers/regulator/lp8788-buck.c
+++ b/drivers/regulator/lp8788-buck.c
@@ -103,16 +103,6 @@
 	1950000, 2000000,
 };
 
-static const u8 buck1_vout_addr[] = {
-	LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
-	LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
-};
-
-static const u8 buck2_vout_addr[] = {
-	LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
-	LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
-};
-
 static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
 {
 	struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
@@ -235,7 +225,7 @@
 			lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 			idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
 		}
-		addr = buck1_vout_addr[idx];
+		addr = LP8788_BUCK1_VOUT0 + idx;
 		break;
 	case BUCK2:
 		if (mode == EXTPIN) {
@@ -258,7 +248,7 @@
 			lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
 			idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
 		}
-		addr = buck2_vout_addr[idx];
+		addr = LP8788_BUCK2_VOUT0 + idx;
 		break;
 	default:
 		goto err;
@@ -429,7 +419,8 @@
 	},
 };
 
-static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
+static int lp8788_dvs_gpio_request(struct platform_device *pdev,
+				struct lp8788_buck *buck,
 				enum lp8788_buck_id id)
 {
 	struct lp8788_platform_data *pdata = buck->lp->pdata;
@@ -440,7 +431,7 @@
 	switch (id) {
 	case BUCK1:
 		gpio = pdata->buck1_dvs->gpio;
-		ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW,
+		ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW,
 					    b1_name);
 		if (ret)
 			return ret;
@@ -448,9 +439,9 @@
 		buck->dvs = pdata->buck1_dvs;
 		break;
 	case BUCK2:
-		for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
+		for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) {
 			gpio = pdata->buck2_dvs->gpio[i];
-			ret = devm_gpio_request_one(buck->lp->dev, gpio,
+			ret = devm_gpio_request_one(&pdev->dev, gpio,
 						    DVS_LOW, b2_name[i]);
 			if (ret)
 				return ret;
@@ -464,7 +455,8 @@
 	return 0;
 }
 
-static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+static int lp8788_init_dvs(struct platform_device *pdev,
+			struct lp8788_buck *buck, enum lp8788_buck_id id)
 {
 	struct lp8788_platform_data *pdata = buck->lp->pdata;
 	u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
@@ -472,7 +464,7 @@
 	u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
 
 	/* no dvs for buck3, 4 */
-	if (id == BUCK3 || id == BUCK4)
+	if (id > BUCK2)
 		return 0;
 
 	/* no dvs platform data, then dvs will be selected by I2C registers */
@@ -483,7 +475,7 @@
 		(id == BUCK2 && !pdata->buck2_dvs))
 		goto set_default_dvs_mode;
 
-	if (lp8788_dvs_gpio_request(buck, id))
+	if (lp8788_dvs_gpio_request(pdev, buck, id))
 		goto set_default_dvs_mode;
 
 	return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
@@ -503,17 +495,20 @@
 	struct regulator_dev *rdev;
 	int ret;
 
-	buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
+	if (id >= LP8788_NUM_BUCKS)
+		return -EINVAL;
+
+	buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
 	if (!buck)
 		return -ENOMEM;
 
 	buck->lp = lp;
 
-	ret = lp8788_init_dvs(buck, id);
+	ret = lp8788_init_dvs(pdev, buck, id);
 	if (ret)
 		return ret;
 
-	cfg.dev = lp->dev;
+	cfg.dev = pdev->dev.parent;
 	cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
 	cfg.driver_data = buck;
 	cfg.regmap = lp->regmap;
@@ -521,7 +516,7 @@
 	rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
 	if (IS_ERR(rdev)) {
 		ret = PTR_ERR(rdev);
-		dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
+		dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",
 				id + 1, ret);
 		return ret;
 	}
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index 3792741..cd5a14a 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -88,11 +88,6 @@
 #define ENABLE				GPIOF_OUT_INIT_HIGH
 #define DISABLE				GPIOF_OUT_INIT_LOW
 
-enum lp8788_enable_mode {
-	REGISTER,
-	EXTPIN,
-};
-
 enum lp8788_ldo_id {
 	DLDO1,
 	DLDO2,
@@ -189,114 +184,38 @@
 	ALDO10,
 };
 
-/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7
-   : can be enabled either by external pin or by i2c register */
-static enum lp8788_enable_mode
-lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id)
-{
-	int ret;
-	u8 val, mask;
-
-	ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val);
-	if (ret)
-		return ret;
-
-	switch (id) {
-	case DLDO7:
-		mask =  LP8788_EN_SEL_DLDO7_M;
-		break;
-	case DLDO9:
-	case DLDO11:
-		mask =  LP8788_EN_SEL_DLDO911_M;
-		break;
-	case ALDO1:
-		mask =  LP8788_EN_SEL_ALDO1_M;
-		break;
-	case ALDO2 ... ALDO4:
-		mask =  LP8788_EN_SEL_ALDO234_M;
-		break;
-	case ALDO5:
-		mask =  LP8788_EN_SEL_ALDO5_M;
-		break;
-	case ALDO7:
-		mask =  LP8788_EN_SEL_ALDO7_M;
-		break;
-	default:
-		return REGISTER;
-	}
-
-	return val & mask ? EXTPIN : REGISTER;
-}
-
-static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate)
-{
-	struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-
-	if (!pin)
-		return -EINVAL;
-
-	if (gpio_is_valid(pin->gpio))
-		gpio_set_value(pin->gpio, pinstate);
-
-	return 0;
-}
-
-static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo)
-{
-	struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-
-	if (!pin)
-		return -EINVAL;
-
-	return gpio_get_value(pin->gpio) ? 1 : 0;
-}
-
 static int lp8788_ldo_enable(struct regulator_dev *rdev)
 {
 	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-	enum lp8788_ldo_id id = rdev_get_id(rdev);
-	enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
 
-	switch (mode) {
-	case EXTPIN:
-		return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE);
-	case REGISTER:
+	if (ldo->en_pin) {
+		gpio_set_value(ldo->en_pin->gpio, ENABLE);
+		return 0;
+	} else {
 		return regulator_enable_regmap(rdev);
-	default:
-		return -EINVAL;
 	}
 }
 
 static int lp8788_ldo_disable(struct regulator_dev *rdev)
 {
 	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-	enum lp8788_ldo_id id = rdev_get_id(rdev);
-	enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
 
-	switch (mode) {
-	case EXTPIN:
-		return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE);
-	case REGISTER:
+	if (ldo->en_pin) {
+		gpio_set_value(ldo->en_pin->gpio, DISABLE);
+		return 0;
+	} else {
 		return regulator_disable_regmap(rdev);
-	default:
-		return -EINVAL;
 	}
 }
 
 static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
 {
 	struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-	enum lp8788_ldo_id id = rdev_get_id(rdev);
-	enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
 
-	switch (mode) {
-	case EXTPIN:
-		return lp8788_ldo_is_enabled_by_extern_pin(ldo);
-	case REGISTER:
+	if (ldo->en_pin)
+		return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
+	else
 		return regulator_is_enabled_regmap(rdev);
-	default:
-		return -EINVAL;
-	}
 }
 
 static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
@@ -616,10 +535,11 @@
 	},
 };
 
-static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
+static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
+				struct lp8788_ldo *ldo,
 				enum lp8788_ext_ldo_en_id id)
 {
-	struct device *dev = ldo->lp->dev;
+	struct device *dev = &pdev->dev;
 	struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
 	int ret, gpio, pinstate;
 	char *name[] = {
@@ -647,7 +567,8 @@
 	return ret;
 }
 
-static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
+static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
+					struct lp8788_ldo *ldo,
 					enum lp8788_ldo_id id)
 {
 	int ret;
@@ -693,9 +614,11 @@
 
 	ldo->en_pin = pdata->ldo_pin[enable_id];
 
-	ret = lp8788_gpio_request_ldo_en(ldo, enable_id);
-	if (ret)
+	ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
+	if (ret) {
+		ldo->en_pin = NULL;
 		goto set_default_ldo_enable_mode;
+	}
 
 	return ret;
 
@@ -712,16 +635,16 @@
 	struct regulator_dev *rdev;
 	int ret;
 
-	ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+	ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
 	if (!ldo)
 		return -ENOMEM;
 
 	ldo->lp = lp;
-	ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]);
+	ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]);
 	if (ret)
 		return ret;
 
-	cfg.dev = lp->dev;
+	cfg.dev = pdev->dev.parent;
 	cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
 	cfg.driver_data = ldo;
 	cfg.regmap = lp->regmap;
@@ -729,7 +652,7 @@
 	rdev = regulator_register(&lp8788_dldo_desc[id], &cfg);
 	if (IS_ERR(rdev)) {
 		ret = PTR_ERR(rdev);
-		dev_err(lp->dev, "DLDO%d regulator register err = %d\n",
+		dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n",
 				id + 1, ret);
 		return ret;
 	}
@@ -768,16 +691,16 @@
 	struct regulator_dev *rdev;
 	int ret;
 
-	ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+	ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
 	if (!ldo)
 		return -ENOMEM;
 
 	ldo->lp = lp;
-	ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]);
+	ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]);
 	if (ret)
 		return ret;
 
-	cfg.dev = lp->dev;
+	cfg.dev = pdev->dev.parent;
 	cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
 	cfg.driver_data = ldo;
 	cfg.regmap = lp->regmap;
@@ -785,7 +708,7 @@
 	rdev = regulator_register(&lp8788_aldo_desc[id], &cfg);
 	if (IS_ERR(rdev)) {
 		ret = PTR_ERR(rdev);
-		dev_err(lp->dev, "ALDO%d regulator register err = %d\n",
+		dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n",
 				id + 1, ret);
 		return ret;
 	}
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index cca18a3..e4586ee 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -75,13 +75,14 @@
 {
 	unsigned int val;
 	struct max77686_data *max77686 = rdev_get_drvdata(rdev);
+        int id = rdev_get_id(rdev);
 
-	if (rdev->desc->id == MAX77686_BUCK1)
+	if (id == MAX77686_BUCK1)
 		val = 0x1;
 	else
 		val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT;
 
-	max77686->opmode[rdev->desc->id] = val;
+	max77686->opmode[id] = val;
 	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 				  rdev->desc->enable_mask,
 				  val);
@@ -93,9 +94,10 @@
 {
 	struct max77686_data *max77686 = rdev_get_drvdata(rdev);
 	unsigned int val;
+        int id = rdev_get_id(rdev);
 
 	/* BUCK[5-9] doesn't support this feature */
-	if (rdev->desc->id >= MAX77686_BUCK5)
+	if (id >= MAX77686_BUCK5)
 		return 0;
 
 	switch (mode) {
@@ -111,7 +113,7 @@
 		return -EINVAL;
 	}
 
-	max77686->opmode[rdev->desc->id] = val;
+	max77686->opmode[id] = val;
 	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 				  rdev->desc->enable_mask,
 				  val);
@@ -140,7 +142,7 @@
 		return -EINVAL;
 	}
 
-	max77686->opmode[rdev->desc->id] = val;
+	max77686->opmode[rdev_get_id(rdev)] = val;
 	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 				  rdev->desc->enable_mask,
 				  val);
@@ -152,7 +154,7 @@
 
 	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
 				  rdev->desc->enable_mask,
-				  max77686->opmode[rdev->desc->id]);
+				  max77686->opmode[rdev_get_id(rdev)]);
 }
 
 static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
index d40cf7f..4568c15 100644
--- a/drivers/regulator/max8907-regulator.c
+++ b/drivers/regulator/max8907-regulator.c
@@ -224,11 +224,11 @@
 
 static int max8907_regulator_parse_dt(struct platform_device *pdev)
 {
-	struct device_node *np = pdev->dev.parent->of_node;
-	struct device_node *regulators;
+	struct device_node *np, *regulators;
 	int ret;
 
-	if (!pdev->dev.parent->of_node)
+	np = of_node_get(pdev->dev.parent->of_node);
+	if (!np)
 		return 0;
 
 	regulators = of_find_node_by_name(np, "regulators");
@@ -239,6 +239,7 @@
 
 	ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
 				 ARRAY_SIZE(max8907_matches));
+	of_node_put(regulators);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
 			ret);
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 446a854..0d5f64a 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -252,7 +252,7 @@
 {
 	struct device_node *nproot, *np;
 	int rcount;
-	nproot = pdev->dev.parent->of_node;
+	nproot = of_node_get(pdev->dev.parent->of_node);
 	if (!nproot)
 		return -ENODEV;
 	np = of_find_node_by_name(nproot, "regulators");
@@ -263,6 +263,7 @@
 
 	rcount = of_regulator_match(&pdev->dev, np,
 				&max8925_regulator_matches[ridx], 1);
+	of_node_put(np);
 	if (rcount < 0)
 		return -ENODEV;
 	config->init_data =	max8925_regulator_matches[ridx].init_data;
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 836908c..0ac7a87 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -54,6 +54,13 @@
 	u8 saved_states[MAX8997_REG_MAX];
 };
 
+static const unsigned int safeoutvolt[] = {
+	4850000,
+	4900000,
+	4950000,
+	3300000,
+};
+
 static inline void max8997_set_gpio(struct max8997_data *max8997)
 {
 	int set3 = (max8997->buck125_gpioindex) & 0x1;
@@ -130,29 +137,6 @@
 	[MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
 };
 
-static int max8997_list_voltage_safeout(struct regulator_dev *rdev,
-		unsigned int selector)
-{
-	int rid = rdev_get_id(rdev);
-
-	if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) {
-		switch (selector) {
-		case 0:
-			return 4850000;
-		case 1:
-			return 4900000;
-		case 2:
-			return 4950000;
-		case 3:
-			return 3300000;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	return -EINVAL;
-}
-
 static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
 		unsigned int selector)
 {
@@ -522,7 +506,7 @@
 	return ret;
 }
 
-static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev,
+static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev,
 						unsigned int old_selector,
 						unsigned int new_selector)
 {
@@ -720,49 +704,23 @@
 	return 0;
 }
 
-static const int safeoutvolt[] = {
-	3300000,
-	4850000,
-	4900000,
-	4950000,
-};
-
 /* For SAFEOUT1 and SAFEOUT2 */
-static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
-		int min_uV, int max_uV, unsigned *selector)
+static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev,
+					   unsigned selector)
 {
 	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
 	struct i2c_client *i2c = max8997->iodev->i2c;
 	int rid = rdev_get_id(rdev);
 	int reg, shift = 0, mask, ret;
-	int i = 0;
-	u8 val;
 
 	if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
 		return -EINVAL;
 
-	for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) {
-		if (min_uV <= safeoutvolt[i] &&
-				max_uV >= safeoutvolt[i])
-			break;
-	}
-
-	if (i >= ARRAY_SIZE(safeoutvolt))
-		return -EINVAL;
-
-	if (i == 0)
-		val = 0x3;
-	else
-		val = i - 1;
-
 	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
 	if (ret)
 		return ret;
 
-	ret = max8997_update_reg(i2c, reg, val << shift, mask << shift);
-	*selector = val;
-
-	return ret;
+	return max8997_update_reg(i2c, reg, selector << shift, mask << shift);
 }
 
 static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
@@ -799,7 +757,6 @@
 	.disable		= max8997_reg_disable,
 	.get_voltage_sel	= max8997_get_voltage_sel,
 	.set_voltage		= max8997_set_voltage_ldobuck,
-	.set_voltage_time_sel	= max8997_set_voltage_ldobuck_time_sel,
 	.set_suspend_disable	= max8997_reg_disable_suspend,
 };
 
@@ -810,7 +767,7 @@
 	.disable		= max8997_reg_disable,
 	.get_voltage_sel	= max8997_get_voltage_sel,
 	.set_voltage		= max8997_set_voltage_buck,
-	.set_voltage_time_sel	= max8997_set_voltage_ldobuck_time_sel,
+	.set_voltage_time_sel	= max8997_set_voltage_buck_time_sel,
 	.set_suspend_disable	= max8997_reg_disable_suspend,
 };
 
@@ -823,12 +780,12 @@
 };
 
 static struct regulator_ops max8997_safeout_ops = {
-	.list_voltage		= max8997_list_voltage_safeout,
+	.list_voltage		= regulator_list_voltage_table,
 	.is_enabled		= max8997_reg_is_enabled,
 	.enable			= max8997_reg_enable,
 	.disable		= max8997_reg_disable,
 	.get_voltage_sel	= max8997_get_voltage_sel,
-	.set_voltage		= max8997_set_voltage_safeout,
+	.set_voltage_sel	= max8997_set_voltage_safeout_sel,
 	.set_suspend_disable	= max8997_reg_disable_suspend,
 };
 
@@ -960,7 +917,7 @@
 	struct max8997_regulator_data *rdata;
 	unsigned int i, dvs_voltage_nr = 1, ret;
 
-	pmic_np = iodev->dev->of_node;
+	pmic_np = of_node_get(iodev->dev->of_node);
 	if (!pmic_np) {
 		dev_err(&pdev->dev, "could not find pmic sub-node\n");
 		return -ENODEV;
@@ -973,13 +930,12 @@
 	}
 
 	/* count the number of regulators to be supported in pmic */
-	pdata->num_regulators = 0;
-	for_each_child_of_node(regulators_np, reg_np)
-		pdata->num_regulators++;
+	pdata->num_regulators = of_get_child_count(regulators_np);
 
 	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
 				pdata->num_regulators, GFP_KERNEL);
 	if (!rdata) {
+		of_node_put(regulators_np);
 		dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
 		return -ENOMEM;
 	}
@@ -1002,6 +958,7 @@
 		rdata->reg_node = reg_np;
 		rdata++;
 	}
+	of_node_put(regulators_np);
 
 	if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL))
 		pdata->buck1_gpiodvs = true;
@@ -1233,13 +1190,15 @@
 		int id = pdata->regulators[i].id;
 
 		desc = reg_voltage_map[id];
-		if (desc)
+		if (desc) {
 			regulators[id].n_voltages =
 				(desc->max - desc->min) / desc->step + 1;
-		else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2)
-			regulators[id].n_voltages = 4;
-		else if (id == MAX8997_CHARGER_CV)
+		} else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) {
+			regulators[id].volt_table = safeoutvolt;
+			regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt);
+		} else if (id == MAX8997_CHARGER_CV) {
 			regulators[id].n_voltages = 16;
+		}
 
 		config.dev = max8997->dev;
 		config.init_data = pdata->regulators[i].initdata;
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 0a8dd1c..b588f07 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -311,25 +311,13 @@
 		dev_get_platdata(max8998->iodev->dev);
 	struct i2c_client *i2c = max8998->iodev->i2c;
 	int buck = rdev_get_id(rdev);
-	int reg, shift = 0, mask, ret;
-	int j, previous_sel;
+	int reg, shift = 0, mask, ret, j;
 	static u8 buck1_last_val;
 
 	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
 	if (ret)
 		return ret;
 
-	previous_sel = max8998_get_voltage_sel(rdev);
-
-	/* Check if voltage needs to be changed */
-	/* if previous_voltage equal new voltage, return */
-	if (previous_sel == selector) {
-		dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
-			regulator_list_voltage_linear(rdev, previous_sel),
-			regulator_list_voltage_linear(rdev, selector));
-		return ret;
-	}
-
 	switch (buck) {
 	case MAX8998_BUCK1:
 		dev_dbg(max8998->dev,
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 0d84b1f..9891aec 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -164,6 +164,14 @@
 	1350000, 1375000
 };
 
+/*
+ * Note: this table is used to derive SWxVSEL by index into
+ * the array. Offset the values by the index of 1100000uV
+ * to get the actual register value for that voltage selector
+ * if the HI bit is to be set as well.
+ */
+#define MC13892_SWxHI_SEL_OFFSET		20
+
 static const unsigned int mc13892_sw[] = {
 	600000,   625000,  650000,  675000,  700000,  725000,
 	750000,   775000,  800000,  825000,  850000,  875000,
@@ -239,7 +247,6 @@
 };
 
 static struct regulator_ops mc13892_gpo_regulator_ops;
-/* sw regulators need special care due to the "hi bit" */
 static struct regulator_ops mc13892_sw_regulator_ops;
 
 
@@ -396,7 +403,7 @@
 {
 	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
 	int ret, id = rdev_get_id(rdev);
-	unsigned int val;
+	unsigned int val, selector;
 
 	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
 
@@ -407,12 +414,28 @@
 	if (ret)
 		return ret;
 
-	val = (val & mc13892_regulators[id].vsel_mask)
-		>> mc13892_regulators[id].vsel_shift;
+	/*
+	 * Figure out if the HI bit is set inside the switcher mode register
+	 * since this means the selector value we return is at a different
+	 * offset into the selector table.
+	 *
+	 * According to the MC13892 documentation note 59 (Table 47) the SW1
+	 * buck switcher does not support output range programming therefore
+	 * the HI bit must always remain 0. So do not do anything strange if
+	 * our register is MC13892_SWITCHERS0.
+	 */
 
-	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+	selector = val & mc13892_regulators[id].vsel_mask;
 
-	return val;
+	if ((mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) &&
+	    (val & MC13892_SWITCHERS0_SWxHI)) {
+		selector += MC13892_SWxHI_SEL_OFFSET;
+	}
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: 0x%08x selector: %d\n",
+			__func__, id, val, selector);
+
+	return selector;
 }
 
 static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
@@ -425,18 +448,35 @@
 
 	volt = rdev->desc->volt_table[selector];
 	mask = mc13892_regulators[id].vsel_mask;
-	reg_value = selector << mc13892_regulators[id].vsel_shift;
+	reg_value = selector;
 
-	if (volt > 1375000) {
-		mask |= MC13892_SWITCHERS0_SWxHI;
-		reg_value |= MC13892_SWITCHERS0_SWxHI;
-	} else if (volt < 1100000) {
-		mask |= MC13892_SWITCHERS0_SWxHI;
-		reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+	/*
+	 * Don't mess with the HI bit or support HI voltage offsets for SW1.
+	 *
+	 * Since the get_voltage_sel callback has given a fudged value for
+	 * the selector offset, we need to back out that offset if HI is
+	 * to be set so we write the correct value to the register.
+	 *
+	 * The HI bit addition and selector offset handling COULD be more
+	 * complicated by shifting and masking off the voltage selector part
+	 * of the register then logical OR it back in, but since the selector
+	 * is at bits 4:0 there is very little point. This makes the whole
+	 * thing more readable and we do far less work.
+	 */
+
+	if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) {
+		if (volt > 1375000) {
+			reg_value -= MC13892_SWxHI_SEL_OFFSET;
+			reg_value |= MC13892_SWITCHERS0_SWxHI;
+			mask |= MC13892_SWITCHERS0_SWxHI;
+		} else if (volt < 1100000) {
+			reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+			mask |= MC13892_SWITCHERS0_SWxHI;
+		}
 	}
 
 	mc13xxx_lock(priv->mc13xxx);
-	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask,
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, mask,
 			      reg_value);
 	mc13xxx_unlock(priv->mc13xxx);
 
@@ -495,15 +535,18 @@
 	struct mc13xxx_regulator_init_data *mc13xxx_data;
 	struct regulator_config config = { };
 	int i, ret;
-	int num_regulators = 0;
+	int num_regulators = 0, num_parsed;
 	u32 val;
 
 	num_regulators = mc13xxx_get_num_regulators_dt(pdev);
+
 	if (num_regulators <= 0 && pdata)
 		num_regulators = pdata->num_regulators;
 	if (num_regulators <= 0)
 		return -EINVAL;
 
+	num_parsed = num_regulators;
+
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
 		num_regulators * sizeof(priv->regulators[0]),
 		GFP_KERNEL);
@@ -520,7 +563,7 @@
 	if (ret)
 		goto err_unlock;
 
-	/* enable switch auto mode */
+	/* enable switch auto mode (on 2.0A silicon only) */
 	if ((val & 0x0000FFFF) == 0x45d0) {
 		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
 			MC13892_SWITCHERS4_SW1MODE_M |
@@ -546,7 +589,39 @@
 		= mc13892_vcam_get_mode;
 
 	mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
-					ARRAY_SIZE(mc13892_regulators));
+					ARRAY_SIZE(mc13892_regulators),
+					&num_parsed);
+
+	/*
+	 * Perform a little sanity check on the regulator tree - if we found
+	 * a number of regulators from mc13xxx_get_num_regulators_dt and
+	 * then parsed a smaller number in mc13xxx_parse_regulators_dt then
+	 * there is a regulator defined in the regulators node which has
+	 * not matched any usable regulator in the driver. In this case,
+	 * there is one missing and what will happen is the first regulator
+	 * will get registered again.
+	 *
+	 * Fix this by basically making our number of registerable regulators
+	 * equal to the number of regulators we parsed. We are allocating
+	 * too much memory for priv, but this is unavoidable at this point.
+	 *
+	 * As an example of how this can happen, try making a typo in your
+	 * regulators node (vviohi {} instead of viohi {}) so that the name
+	 * does not match..
+	 *
+	 * The check will basically pass for platform data (non-DT) because
+	 * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed.
+	 *
+	 */
+	if (num_parsed != num_regulators) {
+		dev_warn(&pdev->dev,
+		"parsed %d != regulators %d - check your device tree!\n",
+			num_parsed, num_regulators);
+
+		num_regulators = num_parsed;
+		priv->num_regulators = num_regulators;
+	}
+
 	for (i = 0; i < num_regulators; i++) {
 		struct regulator_init_data *init_data;
 		struct regulator_desc *desc;
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 4ed89c6..23cf9f9 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -164,29 +164,30 @@
 #ifdef CONFIG_OF
 int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 {
-	struct device_node *parent, *child;
-	int num = 0;
+	struct device_node *parent;
+	int num;
 
 	of_node_get(pdev->dev.parent->of_node);
 	parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
 	if (!parent)
 		return -ENODEV;
 
-	for_each_child_of_node(parent, child)
-		num++;
-
+	num = of_get_child_count(parent);
+	of_node_put(parent);
 	return num;
 }
 EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
 
 struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
 	struct platform_device *pdev, struct mc13xxx_regulator *regulators,
-	int num_regulators)
+	int num_regulators, int *num_parsed)
 {
 	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
 	struct mc13xxx_regulator_init_data *data, *p;
 	struct device_node *parent, *child;
-	int i;
+	int i, parsed = 0;
+
+	*num_parsed = 0;
 
 	of_node_get(pdev->dev.parent->of_node);
 	parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
@@ -195,24 +196,32 @@
 
 	data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators,
 			    GFP_KERNEL);
-	if (!data)
+	if (!data) {
+		of_node_put(parent);
 		return NULL;
+	}
+
 	p = data;
 
 	for_each_child_of_node(parent, child) {
 		for (i = 0; i < num_regulators; i++) {
 			if (!of_node_cmp(child->name,
 					 regulators[i].desc.name)) {
+
 				p->id = i;
 				p->init_data = of_get_regulator_init_data(
 							&pdev->dev, child);
 				p->node = child;
 				p++;
+
+				parsed++;
 				break;
 			}
 		}
 	}
+	of_node_put(parent);
 
+	*num_parsed = parsed;
 	return data;
 }
 EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index 06c8903..007f833 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -39,7 +39,7 @@
 extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
 extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
 	struct platform_device *pdev, struct mc13xxx_regulator *regulators,
-	int num_regulators);
+	int num_regulators, int *num_parsed);
 #else
 static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 {
@@ -48,7 +48,7 @@
 
 static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
 	struct platform_device *pdev, struct mc13xxx_regulator *regulators,
-	int num_regulators)
+	int num_regulators, int *num_parsed)
 {
 	return NULL;
 }
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index c9e912f..cde13bb 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -527,6 +527,7 @@
 	u32 prop;
 	int idx, ret;
 
+	node = of_node_get(node);
 	regulators = of_find_node_by_name(node, "regulators");
 	if (!regulators) {
 		dev_info(dev, "regulator node not found\n");
@@ -535,6 +536,7 @@
 
 	ret = of_regulator_match(dev, regulators, palmas_matches,
 			PALMAS_NUM_REGS);
+	of_node_put(regulators);
 	if (ret < 0) {
 		dev_err(dev, "Error parsing regulator init data: %d\n", ret);
 		return;
@@ -566,11 +568,6 @@
 			pdata->reg_init[idx]->mode_sleep = prop;
 
 		ret = of_property_read_u32(palmas_matches[idx].of_node,
-				"ti,warm_reset", &prop);
-		if (!ret)
-			pdata->reg_init[idx]->warm_reset = prop;
-
-		ret = of_property_read_u32(palmas_matches[idx].of_node,
 				"ti,tstep", &prop);
 		if (!ret)
 			pdata->reg_init[idx]->tstep = prop;
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 33b65c9..8a83194 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -14,6 +14,7 @@
 #include <linux/bug.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -21,6 +22,9 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s5m8767.h>
+#include <linux/regulator/of_regulator.h>
+
+#define S5M8767_OPMODE_NORMAL_MODE 0x1
 
 struct s5m8767_info {
 	struct device *dev;
@@ -255,10 +259,8 @@
 	return sec_reg_update(s5m8767->iodev, reg, ~mask, mask);
 }
 
-static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
+static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
 {
-	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-	int reg_id = rdev_get_id(rdev);
 	int reg;
 
 	switch (reg_id) {
@@ -296,43 +298,18 @@
 		return -EINVAL;
 	}
 
-	*_reg = reg;
-
-	return 0;
+	return reg;
 }
 
-static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
-{
-	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-	int reg, mask, ret;
-	int reg_id = rdev_get_id(rdev);
-	unsigned int val;
-
-	ret = s5m8767_get_voltage_register(rdev, &reg);
-	if (ret)
-		return ret;
-
-	mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
-
-	ret = sec_reg_read(s5m8767->iodev, reg, &val);
-	if (ret)
-		return ret;
-
-	val &= mask;
-
-	return val;
-}
-
-static int s5m8767_convert_voltage_to_sel(
-		const struct sec_voltage_desc *desc,
-		int min_vol, int max_vol)
+static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc,
+					  int min_vol)
 {
 	int selector = 0;
 
 	if (desc == NULL)
 		return -EINVAL;
 
-	if (max_vol < desc->min || min_vol > desc->max)
+	if (min_vol > desc->max)
 		return -EINVAL;
 
 	if (min_vol < desc->min)
@@ -340,7 +317,7 @@
 
 	selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
 
-	if (desc->min + desc->step * selector > max_vol)
+	if (desc->min + desc->step * selector > desc->max)
 		return -EINVAL;
 
 	return selector;
@@ -373,15 +350,13 @@
 {
 	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
 	int reg_id = rdev_get_id(rdev);
-	int reg, mask, ret = 0, old_index, index = 0;
+	int old_index, index = 0;
 	u8 *buck234_vol = NULL;
 
 	switch (reg_id) {
 	case S5M8767_LDO1 ... S5M8767_LDO28:
-		mask = 0x3f;
 		break;
 	case S5M8767_BUCK1 ... S5M8767_BUCK6:
-		mask = 0xff;
 		if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
 			buck234_vol = &s5m8767->buck2_vol[0];
 		else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
@@ -392,7 +367,6 @@
 	case S5M8767_BUCK7 ... S5M8767_BUCK8:
 		return -EINVAL;
 	case S5M8767_BUCK9:
-		mask = 0xff;
 		break;
 	default:
 		return -EINVAL;
@@ -412,11 +386,7 @@
 		else
 			return s5m8767_set_low(s5m8767);
 	} else {
-		ret = s5m8767_get_voltage_register(rdev, &reg);
-		if (ret)
-			return ret;
-
-		return sec_reg_update(s5m8767->iodev, reg, selector, mask);
+		return regulator_set_voltage_sel_regmap(rdev, selector);
 	}
 }
 
@@ -441,7 +411,7 @@
 	.is_enabled		= s5m8767_reg_is_enabled,
 	.enable			= s5m8767_reg_enable,
 	.disable		= s5m8767_reg_disable,
-	.get_voltage_sel	= s5m8767_get_voltage_sel,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= s5m8767_set_voltage_sel,
 	.set_voltage_time_sel	= s5m8767_set_voltage_time_sel,
 };
@@ -508,10 +478,182 @@
 	s5m8767_regulator_desc(BUCK9),
 };
 
+#ifdef CONFIG_OF
+static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
+			struct sec_platform_data *pdata,
+			struct device_node *pmic_np)
+{
+	int i, gpio;
+
+	for (i = 0; i < 3; i++) {
+		gpio = of_get_named_gpio(pmic_np,
+					"s5m8767,pmic-buck-dvs-gpios", i);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+			return -EINVAL;
+		}
+		pdata->buck_gpios[i] = gpio;
+	}
+	return 0;
+}
+
+static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
+			struct sec_platform_data *pdata,
+			struct device_node *pmic_np)
+{
+	int i, gpio;
+
+	for (i = 0; i < 3; i++) {
+		gpio = of_get_named_gpio(pmic_np,
+					"s5m8767,pmic-buck-ds-gpios", i);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+			return -EINVAL;
+		}
+		pdata->buck_ds[i] = gpio;
+	}
+	return 0;
+}
+
+static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
+					struct sec_platform_data *pdata)
+{
+	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct device_node *pmic_np, *regulators_np, *reg_np;
+	struct sec_regulator_data *rdata;
+	struct sec_opmode_data *rmode;
+	unsigned int i, dvs_voltage_nr = 1, ret;
+
+	pmic_np = iodev->dev->of_node;
+	if (!pmic_np) {
+		dev_err(iodev->dev, "could not find pmic sub-node\n");
+		return -ENODEV;
+	}
+
+	regulators_np = of_find_node_by_name(pmic_np, "regulators");
+	if (!regulators_np) {
+		dev_err(iodev->dev, "could not find regulators sub-node\n");
+		return -EINVAL;
+	}
+
+	/* count the number of regulators to be supported in pmic */
+	pdata->num_regulators = of_get_child_count(regulators_np);
+
+	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
+				pdata->num_regulators, GFP_KERNEL);
+	if (!rdata) {
+		dev_err(iodev->dev,
+			"could not allocate memory for regulator data\n");
+		return -ENOMEM;
+	}
+
+	rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
+				pdata->num_regulators, GFP_KERNEL);
+	if (!rdata) {
+		dev_err(iodev->dev,
+			"could not allocate memory for regulator mode\n");
+		return -ENOMEM;
+	}
+
+	pdata->regulators = rdata;
+	pdata->opmode = rmode;
+	for_each_child_of_node(regulators_np, reg_np) {
+		for (i = 0; i < ARRAY_SIZE(regulators); i++)
+			if (!of_node_cmp(reg_np->name, regulators[i].name))
+				break;
+
+		if (i == ARRAY_SIZE(regulators)) {
+			dev_warn(iodev->dev,
+			"don't know how to configure regulator %s\n",
+			reg_np->name);
+			continue;
+		}
+
+		rdata->id = i;
+		rdata->initdata = of_get_regulator_init_data(
+						&pdev->dev, reg_np);
+		rdata->reg_node = reg_np;
+		rdata++;
+		rmode->id = i;
+		if (of_property_read_u32(reg_np, "op_mode",
+				&rmode->mode)) {
+			dev_warn(iodev->dev,
+				"no op_mode property property at %s\n",
+				reg_np->full_name);
+
+			rmode->mode = S5M8767_OPMODE_NORMAL_MODE;
+		}
+		rmode++;
+	}
+
+	if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL))
+		pdata->buck2_gpiodvs = true;
+
+	if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL))
+		pdata->buck3_gpiodvs = true;
+
+	if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL))
+		pdata->buck4_gpiodvs = true;
+
+	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+						pdata->buck4_gpiodvs) {
+		ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+		if (ret)
+			return -EINVAL;
+
+		if (of_property_read_u32(pmic_np,
+				"s5m8767,pmic-buck-default-dvs-idx",
+				&pdata->buck_default_idx)) {
+			pdata->buck_default_idx = 0;
+		} else {
+			if (pdata->buck_default_idx >= 8) {
+				pdata->buck_default_idx = 0;
+				dev_info(iodev->dev,
+				"invalid value for default dvs index, use 0\n");
+			}
+		}
+		dvs_voltage_nr = 8;
+	}
+
+	ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);
+	if (ret)
+		return -EINVAL;
+
+	if (of_property_read_u32_array(pmic_np,
+				"s5m8767,pmic-buck2-dvs-voltage",
+				pdata->buck2_voltage, dvs_voltage_nr)) {
+		dev_err(iodev->dev, "buck2 voltages not specified\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32_array(pmic_np,
+				"s5m8767,pmic-buck3-dvs-voltage",
+				pdata->buck3_voltage, dvs_voltage_nr)) {
+		dev_err(iodev->dev, "buck3 voltages not specified\n");
+		return -EINVAL;
+	}
+
+	if (of_property_read_u32_array(pmic_np,
+				"s5m8767,pmic-buck4-dvs-voltage",
+				pdata->buck4_voltage, dvs_voltage_nr)) {
+		dev_err(iodev->dev, "buck4 voltages not specified\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
+					struct sec_platform_data *pdata)
+{
+	return 0;
+}
+#endif /* CONFIG_OF */
+
 static int s5m8767_pmic_probe(struct platform_device *pdev)
 {
 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct sec_platform_data *pdata = iodev->pdata;
 	struct regulator_config config = { };
 	struct regulator_dev **rdev;
 	struct s5m8767_info *s5m8767;
@@ -522,6 +664,12 @@
 		return -ENODEV;
 	}
 
+	if (iodev->dev->of_node) {
+		ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata);
+		if (ret)
+			return ret;
+	}
+
 	if (pdata->buck2_gpiodvs) {
 		if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
 			dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
@@ -577,23 +725,17 @@
 	s5m8767->opmode = pdata->opmode;
 
 	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
-						pdata->buck2_init,
-						pdata->buck2_init +
-						buck_voltage_val2.step);
+						   pdata->buck2_init);
 
 	sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
 
 	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
-						pdata->buck3_init,
-						pdata->buck3_init +
-						buck_voltage_val2.step);
+						   pdata->buck3_init);
 
 	sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
 
 	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
-						pdata->buck4_init,
-						pdata->buck4_init +
-						buck_voltage_val2.step);
+						   pdata->buck4_init);
 
 	sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
 
@@ -602,27 +744,21 @@
 			s5m8767->buck2_vol[i] =
 				s5m8767_convert_voltage_to_sel(
 						&buck_voltage_val2,
-						pdata->buck2_voltage[i],
-						pdata->buck2_voltage[i] +
-						buck_voltage_val2.step);
+						pdata->buck2_voltage[i]);
 		}
 
 		if (s5m8767->buck3_gpiodvs) {
 			s5m8767->buck3_vol[i] =
 				s5m8767_convert_voltage_to_sel(
 						&buck_voltage_val2,
-						pdata->buck3_voltage[i],
-						pdata->buck3_voltage[i] +
-						buck_voltage_val2.step);
+						pdata->buck3_voltage[i]);
 		}
 
 		if (s5m8767->buck4_gpiodvs) {
 			s5m8767->buck4_vol[i] =
 				s5m8767_convert_voltage_to_sel(
 						&buck_voltage_val2,
-						pdata->buck4_voltage[i],
-						pdata->buck4_voltage[i] +
-						buck_voltage_val2.step);
+						pdata->buck4_voltage[i]);
 		}
 	}
 
@@ -760,11 +896,19 @@
 				(desc->max - desc->min) / desc->step + 1;
 			regulators[id].min_uV = desc->min;
 			regulators[id].uV_step = desc->step;
+			regulators[id].vsel_reg =
+				s5m8767_get_vsel_reg(id, s5m8767);
+			if (id < S5M8767_BUCK1)
+				regulators[id].vsel_mask = 0x3f;
+			else
+				regulators[id].vsel_mask = 0xff;
 		}
 
 		config.dev = s5m8767->dev;
 		config.init_data = pdata->regulators[i].initdata;
 		config.driver_data = s5m8767;
+		config.regmap = iodev->regmap;
+		config.of_node = pdata->regulators[i].reg_node;
 
 		rdev[i] = regulator_register(&regulators[id], &config);
 		if (IS_ERR(rdev[i])) {
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index ab21133..6e67be7 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -28,10 +28,13 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/regulator/tps51632-regulator.h>
 #include <linux/slab.h>
 
@@ -85,49 +88,8 @@
 	struct regulator_desc desc;
 	struct regulator_dev *rdev;
 	struct regmap *regmap;
-	bool enable_pwm_dvfs;
 };
 
-static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev)
-{
-	struct tps51632_chip *tps = rdev_get_drvdata(rdev);
-	unsigned int data;
-	int ret;
-	unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
-	int vsel;
-
-	if (tps->enable_pwm_dvfs)
-		reg = TPS51632_VOLTAGE_BASE_REG;
-
-	ret = regmap_read(tps->regmap, reg, &data);
-	if (ret < 0) {
-		dev_err(tps->dev, "reg read failed, err %d\n", ret);
-		return ret;
-	}
-
-	vsel = data & TPS51632_VOUT_MASK;
-	return vsel;
-}
-
-static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev,
-		unsigned selector)
-{
-	struct tps51632_chip *tps = rdev_get_drvdata(rdev);
-	int ret;
-	unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
-
-	if (tps->enable_pwm_dvfs)
-		reg = TPS51632_VOLTAGE_BASE_REG;
-
-	if (selector > TPS51632_MAX_VSEL)
-		return -EINVAL;
-
-	ret = regmap_write(tps->regmap, reg, selector);
-	if (ret < 0)
-		dev_err(tps->dev, "reg write failed, err %d\n", ret);
-	return ret;
-}
-
 static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
 		int ramp_delay)
 {
@@ -144,8 +106,8 @@
 }
 
 static struct regulator_ops tps51632_dcdc_ops = {
-	.get_voltage_sel	= tps51632_dcdc_get_voltage_sel,
-	.set_voltage_sel	= tps51632_dcdc_set_voltage_sel,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
 	.list_voltage		= regulator_list_voltage_linear,
 	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
 	.set_ramp_delay		= tps51632_dcdc_set_ramp_delay,
@@ -162,7 +124,6 @@
 		goto skip_pwm_config;
 
 	control |= TPS51632_DVFS_PWMEN;
-	tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs;
 	vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV);
 	ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel);
 	if (ret < 0) {
@@ -205,22 +166,96 @@
 	return ret;
 }
 
-static bool rd_wr_reg(struct device *dev, unsigned int reg)
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
 {
-	if ((reg >= 0x8) && (reg <= 0x10))
+	switch (reg) {
+	case TPS51632_OFFSET_REG:
+	case TPS51632_FAULT_REG:
+	case TPS51632_IMON_REG:
+		return true;
+	default:
 		return false;
-	return true;
+	}
+}
+
+static bool is_read_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case 0x08 ... 0x0F:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static bool is_write_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TPS51632_VOLTAGE_SELECT_REG:
+	case TPS51632_VOLTAGE_BASE_REG:
+	case TPS51632_VMAX_REG:
+	case TPS51632_DVFS_CONTROL_REG:
+	case TPS51632_POWER_STATE_REG:
+	case TPS51632_SLEW_REGS:
+		return true;
+	default:
+		return false;
+	}
 }
 
 static const struct regmap_config tps51632_regmap_config = {
 	.reg_bits		= 8,
 	.val_bits		= 8,
-	.writeable_reg		= rd_wr_reg,
-	.readable_reg		= rd_wr_reg,
+	.writeable_reg		= is_write_reg,
+	.readable_reg		= is_read_reg,
+	.volatile_reg		= is_volatile_reg,
 	.max_register		= TPS51632_MAX_REG - 1,
 	.cache_type		= REGCACHE_RBTREE,
 };
 
+#if defined(CONFIG_OF)
+static const struct of_device_id tps51632_of_match[] = {
+	{ .compatible = "ti,tps51632",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, tps51632_of_match);
+
+static struct tps51632_regulator_platform_data *
+	of_get_tps51632_platform_data(struct device *dev)
+{
+	struct tps51632_regulator_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "Memory alloc failed for platform data\n");
+		return NULL;
+	}
+
+	pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
+	if (!pdata->reg_init_data) {
+		dev_err(dev, "Not able to get OF regulator init data\n");
+		return NULL;
+	}
+
+	pdata->enable_pwm_dvfs =
+			of_property_read_bool(np, "ti,enable-pwm-dvfs");
+	pdata->dvfs_step_20mV = of_property_read_bool(np, "ti,dvfs-step-20mV");
+
+	pdata->base_voltage_uV = pdata->reg_init_data->constraints.min_uV ? :
+					TPS51632_MIN_VOLATGE;
+	pdata->max_voltage_uV = pdata->reg_init_data->constraints.max_uV ? :
+					TPS51632_MAX_VOLATGE;
+	return pdata;
+}
+#else
+static struct tps51632_regulator_platform_data *
+	of_get_tps51632_platform_data(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int tps51632_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
@@ -230,7 +265,19 @@
 	int ret;
 	struct regulator_config config = { };
 
+	if (client->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_device(of_match_ptr(tps51632_of_match),
+				&client->dev);
+		if (!match) {
+			dev_err(&client->dev, "Error: No device match found\n");
+			return -ENODEV;
+		}
+	}
+
 	pdata = client->dev.platform_data;
+	if (!pdata && client->dev.of_node)
+		pdata = of_get_tps51632_platform_data(&client->dev);
 	if (!pdata) {
 		dev_err(&client->dev, "No Platform data\n");
 		return -EINVAL;
@@ -269,6 +316,12 @@
 	tps->desc.type = REGULATOR_VOLTAGE;
 	tps->desc.owner = THIS_MODULE;
 
+	if (pdata->enable_pwm_dvfs)
+		tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG;
+	else
+		tps->desc.vsel_reg = TPS51632_VOLTAGE_SELECT_REG;
+	tps->desc.vsel_mask = TPS51632_VOUT_MASK;
+
 	tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config);
 	if (IS_ERR(tps->regmap)) {
 		ret = PTR_ERR(tps->regmap);
@@ -319,6 +372,7 @@
 	.driver = {
 		.name = "tps51632",
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(tps51632_of_match),
 	},
 	.probe = tps51632_probe,
 	.remove = tps51632_remove,
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 0233cfb..54aa2da 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -23,8 +23,10 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/tps6507x.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/mfd/tps6507x.h>
+#include <linux/regulator/of_regulator.h>
 
 /* DCDC's */
 #define TPS6507X_DCDC_1				0
@@ -356,6 +358,80 @@
 	.list_voltage = regulator_list_voltage_table,
 };
 
+#ifdef CONFIG_OF
+static struct of_regulator_match tps6507x_matches[] = {
+	{ .name = "VDCDC1"},
+	{ .name = "VDCDC2"},
+	{ .name = "VDCDC3"},
+	{ .name = "LDO1"},
+	{ .name = "LDO2"},
+};
+
+static struct tps6507x_board *tps6507x_parse_dt_reg_data(
+		struct platform_device *pdev,
+		struct of_regulator_match **tps6507x_reg_matches)
+{
+	struct tps6507x_board *tps_board;
+	struct device_node *np = pdev->dev.parent->of_node;
+	struct device_node *regulators;
+	struct of_regulator_match *matches;
+	static struct regulator_init_data *reg_data;
+	int idx = 0, count, ret;
+
+	tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
+					GFP_KERNEL);
+	if (!tps_board) {
+		dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+		return NULL;
+	}
+
+	regulators = of_find_node_by_name(np, "regulators");
+	if (!regulators) {
+		dev_err(&pdev->dev, "regulator node not found\n");
+		return NULL;
+	}
+
+	count = ARRAY_SIZE(tps6507x_matches);
+	matches = tps6507x_matches;
+
+	ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+			ret);
+		return NULL;
+	}
+
+	*tps6507x_reg_matches = matches;
+
+	reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
+					* TPS6507X_NUM_REGULATOR), GFP_KERNEL);
+	if (!reg_data) {
+		dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
+		return NULL;
+	}
+
+	tps_board->tps6507x_pmic_init_data = reg_data;
+
+	for (idx = 0; idx < count; idx++) {
+		if (!matches[idx].init_data || !matches[idx].of_node)
+			continue;
+
+		memcpy(&reg_data[idx], matches[idx].init_data,
+				sizeof(struct regulator_init_data));
+
+	}
+
+	return tps_board;
+}
+#else
+static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
+			struct platform_device *pdev,
+			struct of_regulator_match **tps6507x_reg_matches)
+{
+	*tps6507x_reg_matches = NULL;
+	return NULL;
+}
+#endif
 static int tps6507x_pmic_probe(struct platform_device *pdev)
 {
 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
@@ -365,8 +441,10 @@
 	struct regulator_dev *rdev;
 	struct tps6507x_pmic *tps;
 	struct tps6507x_board *tps_board;
+	struct of_regulator_match *tps6507x_reg_matches = NULL;
 	int i;
 	int error;
+	unsigned int prop;
 
 	/**
 	 * tps_board points to pmic related constants
@@ -374,6 +452,9 @@
 	 */
 
 	tps_board = dev_get_platdata(tps6507x_dev->dev);
+	if (!tps_board && tps6507x_dev->dev->of_node)
+		tps_board = tps6507x_parse_dt_reg_data(pdev,
+						&tps6507x_reg_matches);
 	if (!tps_board)
 		return -EINVAL;
 
@@ -415,6 +496,17 @@
 		config.init_data = init_data;
 		config.driver_data = tps;
 
+		if (tps6507x_reg_matches) {
+			error = of_property_read_u32(
+				tps6507x_reg_matches[i].of_node,
+					"ti,defdcdc_default", &prop);
+
+			if (!error)
+				tps->info[i]->defdcdc_default = prop;
+
+			config.of_node = tps6507x_reg_matches[i].of_node;
+		}
+
 		rdev = regulator_register(&tps->desc[i], &config);
 		if (IS_ERR(rdev)) {
 			dev_err(tps6507x_dev->dev,
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index 41c3917..c8e7045 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -19,11 +19,13 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/mfd/tps65090.h>
 
 struct tps65090_regulator {
@@ -67,8 +69,8 @@
 	tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops),
 	tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops),
 	tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops),
-	tps65090_REG_DESC(LDO1,  "vsys_l1", 0,    tps65090_ldo_ops),
-	tps65090_REG_DESC(LDO2,  "vsys_l2", 0,    tps65090_ldo_ops),
+	tps65090_REG_DESC(LDO1,  "vsys-l1", 0,    tps65090_ldo_ops),
+	tps65090_REG_DESC(LDO2,  "vsys-l2", 0,    tps65090_ldo_ops),
 };
 
 static inline bool is_dcdc(int id)
@@ -138,6 +140,92 @@
 	}
 }
 
+#ifdef CONFIG_OF
+static struct of_regulator_match tps65090_matches[] = {
+	{ .name = "dcdc1", },
+	{ .name = "dcdc2", },
+	{ .name = "dcdc3", },
+	{ .name = "fet1",  },
+	{ .name = "fet2",  },
+	{ .name = "fet3",  },
+	{ .name = "fet4",  },
+	{ .name = "fet5",  },
+	{ .name = "fet6",  },
+	{ .name = "fet7",  },
+	{ .name = "ldo1",  },
+	{ .name = "ldo2",  },
+};
+
+static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
+		struct platform_device *pdev,
+		struct of_regulator_match **tps65090_reg_matches)
+{
+	struct tps65090_platform_data *tps65090_pdata;
+	struct device_node *np = pdev->dev.parent->of_node;
+	struct device_node *regulators;
+	int idx = 0, ret;
+	struct tps65090_regulator_plat_data *reg_pdata;
+
+	tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
+				GFP_KERNEL);
+	if (!tps65090_pdata) {
+		dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
+				sizeof(*reg_pdata), GFP_KERNEL);
+	if (!reg_pdata) {
+		dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	regulators = of_find_node_by_name(np, "regulators");
+	if (!regulators) {
+		dev_err(&pdev->dev, "regulator node not found\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
+			ARRAY_SIZE(tps65090_matches));
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Error parsing regulator init data: %d\n", ret);
+		return ERR_PTR(ret);
+	}
+
+	*tps65090_reg_matches = tps65090_matches;
+	for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) {
+		struct regulator_init_data *ri_data;
+		struct tps65090_regulator_plat_data *rpdata;
+
+		rpdata = &reg_pdata[idx];
+		ri_data = tps65090_matches[idx].init_data;
+		if (!ri_data || !tps65090_matches[idx].of_node)
+			continue;
+
+		rpdata->reg_init_data = ri_data;
+		rpdata->enable_ext_control = of_property_read_bool(
+					tps65090_matches[idx].of_node,
+					"ti,enable-ext-control");
+		if (rpdata->enable_ext_control)
+			rpdata->gpio = of_get_named_gpio(np,
+					"dcdc-ext-control-gpios", 0);
+
+		tps65090_pdata->reg_pdata[idx] = rpdata;
+	}
+	return tps65090_pdata;
+}
+#else
+static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data(
+			struct platform_device *pdev,
+			struct of_regulator_match **tps65090_reg_matches)
+{
+	*tps65090_reg_matches = NULL;
+	return NULL;
+}
+#endif
+
 static int tps65090_regulator_probe(struct platform_device *pdev)
 {
 	struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
@@ -147,15 +235,19 @@
 	struct tps65090_regulator_plat_data *tps_pdata;
 	struct tps65090_regulator *pmic;
 	struct tps65090_platform_data *tps65090_pdata;
+	struct of_regulator_match *tps65090_reg_matches = NULL;
 	int num;
 	int ret;
 
 	dev_dbg(&pdev->dev, "Probing regulator\n");
 
 	tps65090_pdata = dev_get_platdata(pdev->dev.parent);
-	if (!tps65090_pdata) {
+	if (!tps65090_pdata && tps65090_mfd->dev->of_node)
+		tps65090_pdata = tps65090_parse_dt_reg_data(pdev,
+					&tps65090_reg_matches);
+	if (IS_ERR_OR_NULL(tps65090_pdata)) {
 		dev_err(&pdev->dev, "Platform data missing\n");
-		return -EINVAL;
+		return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL;
 	}
 
 	pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
@@ -192,13 +284,17 @@
 			}
 		}
 
-		config.dev = &pdev->dev;
+		config.dev = pdev->dev.parent;
 		config.driver_data = ri;
 		config.regmap = tps65090_mfd->rmap;
 		if (tps_pdata)
 			config.init_data = tps_pdata->reg_init_data;
 		else
 			config.init_data = NULL;
+		if (tps65090_reg_matches)
+			config.of_node = tps65090_reg_matches[num].of_node;
+		else
+			config.of_node = NULL;
 
 		rdev = regulator_register(ri->desc, &config);
 		if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index f86da67..e68382d 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -61,10 +61,6 @@
 
 	int enable_bit[2];
 	int enable_reg[2];
-
-	/* for DVM regulators */
-	int go_reg;
-	int go_bit;
 };
 
 static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
@@ -72,37 +68,10 @@
 	return rdev_get_dev(rdev)->parent;
 }
 
-static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-	struct device *parent = to_tps6586x_dev(rdev);
-	int ret, val, rid = rdev_get_id(rdev);
-	uint8_t mask;
-
-	val = selector << (ffs(rdev->desc->vsel_mask) - 1);
-	mask = rdev->desc->vsel_mask;
-
-	ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask);
-	if (ret)
-		return ret;
-
-	/* Update go bit for DVM regulators */
-	switch (rid) {
-	case TPS6586X_ID_LDO_2:
-	case TPS6586X_ID_LDO_4:
-	case TPS6586X_ID_SM_0:
-	case TPS6586X_ID_SM_1:
-		ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
-		break;
-	}
-	return ret;
-}
-
 static struct regulator_ops tps6586x_regulator_ops = {
 	.list_voltage = regulator_list_voltage_table,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_sel = tps6586x_set_voltage_sel,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
@@ -142,7 +111,7 @@
 };
 
 #define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits,	\
-			   ereg0, ebit0, ereg1, ebit1)			\
+			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\
 	.desc	= {							\
 		.supply_name = _pin_name,				\
 		.name	= "REG-" #_id,					\
@@ -156,29 +125,26 @@
 		.enable_mask = 1 << (ebit0),				\
 		.vsel_reg = TPS6586X_##vreg,				\
 		.vsel_mask = ((1 << (nbits)) - 1) << (shift),		\
+		.apply_reg = (goreg),				\
+		.apply_bit = (gobit),				\
 	},								\
 	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
 	.enable_bit[0]	= (ebit0),					\
 	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
 	.enable_bit[1]	= (ebit1),
 
-#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)			\
-	.go_reg = TPS6586X_##goreg,					\
-	.go_bit = (gobit),
-
 #define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits,		\
 		     ereg0, ebit0, ereg1, ebit1)			\
 {									\
 	TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,	\
-			   ereg0, ebit0, ereg1, ebit1)			\
+			   ereg0, ebit0, ereg1, ebit1, 0, 0)		\
 }
 
 #define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits,		\
 		     ereg0, ebit0, ereg1, ebit1, goreg, gobit)		\
 {									\
 	TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,	\
-			   ereg0, ebit0, ereg1, ebit1)			\
-	TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)			\
+			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\
 }
 
 #define TPS6586X_SYS_REGULATOR()					\
@@ -207,13 +173,13 @@
 	TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
 
 	TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
-					ENB, 3, VCC2, 6),
+					ENB, 3, TPS6586X_VCC2, BIT(6)),
 	TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
-					END, 3, VCC1, 6),
+					END, 3, TPS6586X_VCC1, BIT(6)),
 	TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1,
-					ENB, 1, VCC1, 2),
+					ENB, 1, TPS6586X_VCC1, BIT(2)),
 	TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0,
-					ENB, 0, VCC1, 0),
+					ENB, 0, TPS6586X_VCC1, BIT(0)),
 };
 
 /*
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index b0e4c0b..6ba6931 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -964,8 +964,7 @@
 {
 	struct tps65910_board *pmic_plat_data;
 	struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
-	struct device_node *np = pdev->dev.parent->of_node;
-	struct device_node *regulators;
+	struct device_node *np, *regulators;
 	struct of_regulator_match *matches;
 	unsigned int prop;
 	int idx = 0, ret, count;
@@ -978,6 +977,7 @@
 		return NULL;
 	}
 
+	np = of_node_get(pdev->dev.parent->of_node);
 	regulators = of_find_node_by_name(np, "regulators");
 	if (!regulators) {
 		dev_err(&pdev->dev, "regulator node not found\n");
@@ -994,11 +994,13 @@
 		matches = tps65911_matches;
 		break;
 	default:
+		of_node_put(regulators);
 		dev_err(&pdev->dev, "Invalid tps chip version\n");
 		return NULL;
 	}
 
 	ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+	of_node_put(regulators);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
 			ret);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 923a9da..5e44eaa 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -20,14 +20,24 @@
 config RTC_HCTOSYS
 	bool "Set system time from RTC on startup and resume"
 	default y
+	depends on !ALWAYS_USE_PERSISTENT_CLOCK
 	help
 	  If you say yes here, the system time (wall clock) will be set using
 	  the value read from a specified RTC device. This is useful to avoid
 	  unnecessary fsck runs at boot time, and to network better.
 
+config RTC_SYSTOHC
+	bool "Set the RTC time based on NTP synchronization"
+	default y
+	depends on !ALWAYS_USE_PERSISTENT_CLOCK
+	help
+	  If you say yes here, the system time (wall clock) will be stored
+	  in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
+	  minutes if userspace reports synchronized NTP status.
+
 config RTC_HCTOSYS_DEVICE
 	string "RTC used to set the system time"
-	depends on RTC_HCTOSYS = y
+	depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
 	default "rtc0"
 	help
 	  The RTC device that will be used to (re)initialize the system
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 4418ef3..ec2988b 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_RTC_LIB)		+= rtc-lib.o
 obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
+obj-$(CONFIG_RTC_SYSTOHC)	+= systohc.o
 obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
 rtc-core-y			:= class.o interface.o
 
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 5143629..26388f1 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -50,6 +50,10 @@
 	struct rtc_device	*rtc = to_rtc_device(dev);
 	struct rtc_time		tm;
 	struct timespec		delta, delta_delta;
+
+	if (has_persistent_clock())
+		return 0;
+
 	if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
 		return 0;
 
@@ -88,6 +92,9 @@
 	struct timespec		new_system, new_rtc;
 	struct timespec		sleep_time;
 
+	if (has_persistent_clock())
+		return 0;
+
 	rtc_hctosys_ret = -ENODEV;
 	if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
 		return 0;
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 10c1a34..81c5077 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -350,7 +350,9 @@
 	/* Enable the clockwatch on ST Variants */
 	if (vendor->clockwatch)
 		data |= RTC_CR_CWEN;
-	writel(data | RTC_CR_EN, ldata->base + RTC_CR);
+	else
+		data |= RTC_CR_EN;
+	writel(data, ldata->base + RTC_CR);
 
 	/*
 	 * On ST PL031 variants, the RTC reset value does not provide correct
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
new file mode 100644
index 0000000..bf3e242
--- /dev/null
+++ b/drivers/rtc/systohc.c
@@ -0,0 +1,44 @@
+/*
+ * 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 <linux/rtc.h>
+#include <linux/time.h>
+
+/**
+ * rtc_set_ntp_time - Save NTP synchronized time to the RTC
+ * @now: Current time of day
+ *
+ * Replacement for the NTP platform function update_persistent_clock
+ * that stores time for later retrieval by rtc_hctosys.
+ *
+ * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
+ * possible at all, and various other -errno for specific temporary failure
+ * cases.
+ *
+ * If temporary failure is indicated the caller should try again 'soon'
+ */
+int rtc_set_ntp_time(struct timespec now)
+{
+	struct rtc_device *rtc;
+	struct rtc_time tm;
+	int err = -ENODEV;
+
+	if (now.tv_nsec < (NSEC_PER_SEC >> 1))
+		rtc_time_to_tm(now.tv_sec, &tm);
+	else
+		rtc_time_to_tm(now.tv_sec + 1, &tm);
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc) {
+		/* rtc_hctosys exclusively uses UTC, so we call set_time here,
+		 * not set_mmss. */
+		if (rtc->ops && (rtc->ops->set_time || rtc->ops->set_mmss))
+			err = rtc_set_time(rtc, &tm);
+		rtc_class_close(rtc);
+	}
+
+	return err;
+}
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index dfda748..8b3f559 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -74,8 +74,8 @@
 	depends on CCW && NETDEVICES && IP_MULTICAST && QDIO
 	help
 	  This driver supports the IBM System z OSA Express adapters
-	  in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN
-	  interfaces in QDIO and HIPER mode.
+	  in QDIO mode (all media types), HiperSockets interfaces and z/VM
+	  virtual NICs for Guest LAN and VSWITCH.
 	
 	  For details please refer to the documentation provided by IBM at
 	  <http://www.ibm.com/developerworks/linux/linux390>
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 480fbea..d690b33 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -678,6 +678,7 @@
 	int performance_stats;
 	int rx_sg_cb;
 	enum qeth_ipa_isolation_modes isolation;
+	enum qeth_ipa_isolation_modes prev_isolation;
 	int sniffer;
 	enum qeth_cq cq;
 	char hsuid[9];
@@ -789,6 +790,7 @@
 	struct qeth_rx rx;
 	struct delayed_work buffer_reclaim_work;
 	int reclaim_index;
+	struct work_struct close_dev_work;
 };
 
 struct qeth_card_list_struct {
@@ -909,9 +911,6 @@
 int qeth_mdio_read(struct net_device *, int, int);
 int qeth_snmp_command(struct qeth_card *, char __user *);
 int qeth_query_oat_command(struct qeth_card *, char __user *);
-struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32);
-int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *,
-					unsigned long);
 int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
 	int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
 	void *reply_param);
@@ -928,12 +927,13 @@
 void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
 void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
 int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
-int qeth_set_access_ctrl_online(struct qeth_card *card);
+int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback);
 int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
 int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
 int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
 int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
 void qeth_trace_features(struct qeth_card *);
+void qeth_close_dev(struct qeth_card *);
 
 /* exports for OSN */
 int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 638a57f..0d8cdff 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -68,6 +68,27 @@
 		enum qeth_qdio_buffer_states newbufstate);
 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 
+static struct workqueue_struct *qeth_wq;
+
+static void qeth_close_dev_handler(struct work_struct *work)
+{
+	struct qeth_card *card;
+
+	card = container_of(work, struct qeth_card, close_dev_work);
+	QETH_CARD_TEXT(card, 2, "cldevhdl");
+	rtnl_lock();
+	dev_close(card->dev);
+	rtnl_unlock();
+	ccwgroup_set_offline(card->gdev);
+}
+
+void qeth_close_dev(struct qeth_card *card)
+{
+	QETH_CARD_TEXT(card, 2, "cldevsubm");
+	queue_work(qeth_wq, &card->close_dev_work);
+}
+EXPORT_SYMBOL_GPL(qeth_close_dev);
+
 static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
 	if (card->info.guestlan) {
@@ -542,11 +563,23 @@
 		} else {
 			switch (cmd->hdr.command) {
 			case IPA_CMD_STOPLAN:
-				dev_warn(&card->gdev->dev,
+				if (cmd->hdr.return_code ==
+						IPA_RC_VEPA_TO_VEB_TRANSITION) {
+					dev_err(&card->gdev->dev,
+					   "Interface %s is down because the "
+					   "adjacent port is no longer in "
+					   "reflective relay mode\n",
+					   QETH_CARD_IFNAME(card));
+					qeth_close_dev(card);
+				} else {
+					dev_warn(&card->gdev->dev,
 					   "The link for interface %s on CHPID"
 					   " 0x%X failed\n",
 					   QETH_CARD_IFNAME(card),
 					   card->info.chpid);
+					qeth_issue_ipa_msg(cmd,
+						cmd->hdr.return_code, card);
+				}
 				card->lan_online = 0;
 				if (card->dev && netif_carrier_ok(card->dev))
 					netif_carrier_off(card->dev);
@@ -1416,6 +1449,7 @@
 	/* init QDIO stuff */
 	qeth_init_qdio_info(card);
 	INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work);
+	INIT_WORK(&card->close_dev_work, qeth_close_dev_handler);
 	return 0;
 }
 
@@ -2868,7 +2902,7 @@
 }
 EXPORT_SYMBOL_GPL(qeth_send_startlan);
 
-int qeth_default_setadapterparms_cb(struct qeth_card *card,
+static int qeth_default_setadapterparms_cb(struct qeth_card *card,
 		struct qeth_reply *reply, unsigned long data)
 {
 	struct qeth_ipa_cmd *cmd;
@@ -2881,7 +2915,6 @@
 			cmd->data.setadapterparms.hdr.return_code;
 	return 0;
 }
-EXPORT_SYMBOL_GPL(qeth_default_setadapterparms_cb);
 
 static int qeth_query_setadapterparms_cb(struct qeth_card *card,
 		struct qeth_reply *reply, unsigned long data)
@@ -2901,7 +2934,7 @@
 	return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
 }
 
-struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
+static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
 		__u32 command, __u32 cmdlen)
 {
 	struct qeth_cmd_buffer *iob;
@@ -2917,7 +2950,6 @@
 
 	return iob;
 }
-EXPORT_SYMBOL_GPL(qeth_get_adapter_cmd);
 
 int qeth_query_setadapterparms(struct qeth_card *card)
 {
@@ -4059,6 +4091,7 @@
 {
 	struct qeth_ipa_cmd *cmd;
 	struct qeth_set_access_ctrl *access_ctrl_req;
+	int fallback = *(int *)reply->param;
 
 	QETH_CARD_TEXT(card, 4, "setaccb");
 
@@ -4068,12 +4101,14 @@
 	QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
 	QETH_DBF_TEXT_(SETUP, 2, "rc=%d",
 		cmd->data.setadapterparms.hdr.return_code);
+	if (cmd->data.setadapterparms.hdr.return_code !=
+						SET_ACCESS_CTRL_RC_SUCCESS)
+		QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
+				card->gdev->dev.kobj.name,
+				access_ctrl_req->subcmd_code,
+				cmd->data.setadapterparms.hdr.return_code);
 	switch (cmd->data.setadapterparms.hdr.return_code) {
 	case SET_ACCESS_CTRL_RC_SUCCESS:
-	case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
-	case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
-	{
-		card->options.isolation = access_ctrl_req->subcmd_code;
 		if (card->options.isolation == ISOLATION_MODE_NONE) {
 			dev_info(&card->gdev->dev,
 			    "QDIO data connection isolation is deactivated\n");
@@ -4081,72 +4116,64 @@
 			dev_info(&card->gdev->dev,
 			    "QDIO data connection isolation is activated\n");
 		}
-		QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n",
-			card->gdev->dev.kobj.name,
-			access_ctrl_req->subcmd_code,
-			cmd->data.setadapterparms.hdr.return_code);
 		break;
-	}
+	case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
+		QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already "
+				"deactivated\n", dev_name(&card->gdev->dev));
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
+		break;
+	case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
+		QETH_DBF_MESSAGE(2, "%s QDIO data connection isolation already"
+				" activated\n", dev_name(&card->gdev->dev));
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
+		break;
 	case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
-	{
-		QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
-			card->gdev->dev.kobj.name,
-			access_ctrl_req->subcmd_code,
-			cmd->data.setadapterparms.hdr.return_code);
 		dev_err(&card->gdev->dev, "Adapter does not "
 			"support QDIO data connection isolation\n");
-
-		/* ensure isolation mode is "none" */
-		card->options.isolation = ISOLATION_MODE_NONE;
 		break;
-	}
 	case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
-	{
-		QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
-			card->gdev->dev.kobj.name,
-			access_ctrl_req->subcmd_code,
-			cmd->data.setadapterparms.hdr.return_code);
 		dev_err(&card->gdev->dev,
 			"Adapter is dedicated. "
 			"QDIO data connection isolation not supported\n");
-
-		/* ensure isolation mode is "none" */
-		card->options.isolation = ISOLATION_MODE_NONE;
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
 		break;
-	}
 	case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
-	{
-		QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
-			card->gdev->dev.kobj.name,
-			access_ctrl_req->subcmd_code,
-			cmd->data.setadapterparms.hdr.return_code);
 		dev_err(&card->gdev->dev,
 			"TSO does not permit QDIO data connection isolation\n");
-
-		/* ensure isolation mode is "none" */
-		card->options.isolation = ISOLATION_MODE_NONE;
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
 		break;
-	}
+	case SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED:
+		dev_err(&card->gdev->dev, "The adjacent switch port does not "
+			"support reflective relay mode\n");
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
+		break;
+	case SET_ACCESS_CTRL_RC_REFLREL_FAILED:
+		dev_err(&card->gdev->dev, "The reflective relay mode cannot be "
+					"enabled at the adjacent switch port");
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
+		break;
+	case SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED:
+		dev_warn(&card->gdev->dev, "Turning off reflective relay mode "
+					"at the adjacent switch failed\n");
+		break;
 	default:
-	{
 		/* this should never happen */
-		QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d"
-			"==UNKNOWN\n",
-			card->gdev->dev.kobj.name,
-			access_ctrl_req->subcmd_code,
-			cmd->data.setadapterparms.hdr.return_code);
-
-		/* ensure isolation mode is "none" */
-		card->options.isolation = ISOLATION_MODE_NONE;
+		if (fallback)
+			card->options.isolation = card->options.prev_isolation;
 		break;
 	}
-	}
 	qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
 	return 0;
 }
 
 static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
-		enum qeth_ipa_isolation_modes isolation)
+		enum qeth_ipa_isolation_modes isolation, int fallback)
 {
 	int rc;
 	struct qeth_cmd_buffer *iob;
@@ -4166,12 +4193,12 @@
 	access_ctrl_req->subcmd_code = isolation;
 
 	rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb,
-			       NULL);
+			       &fallback);
 	QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc);
 	return rc;
 }
 
-int qeth_set_access_ctrl_online(struct qeth_card *card)
+int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback)
 {
 	int rc = 0;
 
@@ -4181,12 +4208,13 @@
 	     card->info.type == QETH_CARD_TYPE_OSX) &&
 	     qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
 		rc = qeth_setadpparms_set_access_ctrl(card,
-			card->options.isolation);
+			card->options.isolation, fallback);
 		if (rc) {
 			QETH_DBF_MESSAGE(3,
 				"IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
 				card->gdev->dev.kobj.name,
 				rc);
+			rc = -EOPNOTSUPP;
 		}
 	} else if (card->options.isolation != ISOLATION_MODE_NONE) {
 		card->options.isolation = ISOLATION_MODE_NONE;
@@ -4672,7 +4700,7 @@
 	init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
 	init_data.output_sbal_state_array = card->qdio.out_bufstates;
 	init_data.scan_threshold =
-		(card->info.type == QETH_CARD_TYPE_IQD) ? 8 : 32;
+		(card->info.type == QETH_CARD_TYPE_IQD) ? 1 : 32;
 
 	if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
 		QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
@@ -4765,14 +4793,14 @@
 
 int qeth_core_hardsetup_card(struct qeth_card *card)
 {
-	int retries = 0;
+	int retries = 3;
 	int rc;
 
 	QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
 	atomic_set(&card->force_alloc_skb, 0);
 	qeth_update_from_chp_desc(card);
 retry:
-	if (retries)
+	if (retries < 3)
 		QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
 			dev_name(&card->gdev->dev));
 	ccw_device_set_offline(CARD_DDEV(card));
@@ -4794,7 +4822,7 @@
 		return rc;
 	} else if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
-		if (++retries > 3)
+		if (--retries < 0)
 			goto out;
 		else
 			goto retry;
@@ -5094,13 +5122,81 @@
 	.groups = qeth_osn_attr_groups,
 };
 
+#define DBF_NAME_LEN	20
+
+struct qeth_dbf_entry {
+	char dbf_name[DBF_NAME_LEN];
+	debug_info_t *dbf_info;
+	struct list_head dbf_list;
+};
+
+static LIST_HEAD(qeth_dbf_list);
+static DEFINE_MUTEX(qeth_dbf_list_mutex);
+
+static debug_info_t *qeth_get_dbf_entry(char *name)
+{
+	struct qeth_dbf_entry *entry;
+	debug_info_t *rc = NULL;
+
+	mutex_lock(&qeth_dbf_list_mutex);
+	list_for_each_entry(entry, &qeth_dbf_list, dbf_list) {
+		if (strcmp(entry->dbf_name, name) == 0) {
+			rc = entry->dbf_info;
+			break;
+		}
+	}
+	mutex_unlock(&qeth_dbf_list_mutex);
+	return rc;
+}
+
+static int qeth_add_dbf_entry(struct qeth_card *card, char *name)
+{
+	struct qeth_dbf_entry *new_entry;
+
+	card->debug = debug_register(name, 2, 1, 8);
+	if (!card->debug) {
+		QETH_DBF_TEXT_(SETUP, 2, "%s", "qcdbf");
+		goto err;
+	}
+	if (debug_register_view(card->debug, &debug_hex_ascii_view))
+		goto err_dbg;
+	new_entry = kzalloc(sizeof(struct qeth_dbf_entry), GFP_KERNEL);
+	if (!new_entry)
+		goto err_dbg;
+	strncpy(new_entry->dbf_name, name, DBF_NAME_LEN);
+	new_entry->dbf_info = card->debug;
+	mutex_lock(&qeth_dbf_list_mutex);
+	list_add(&new_entry->dbf_list, &qeth_dbf_list);
+	mutex_unlock(&qeth_dbf_list_mutex);
+
+	return 0;
+
+err_dbg:
+	debug_unregister(card->debug);
+err:
+	return -ENOMEM;
+}
+
+static void qeth_clear_dbf_list(void)
+{
+	struct qeth_dbf_entry *entry, *tmp;
+
+	mutex_lock(&qeth_dbf_list_mutex);
+	list_for_each_entry_safe(entry, tmp, &qeth_dbf_list, dbf_list) {
+		list_del(&entry->dbf_list);
+		debug_unregister(entry->dbf_info);
+		kfree(entry);
+	}
+	mutex_unlock(&qeth_dbf_list_mutex);
+}
+
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
 	struct qeth_card *card;
 	struct device *dev;
 	int rc;
 	unsigned long flags;
-	char dbf_name[20];
+	char dbf_name[DBF_NAME_LEN];
 
 	QETH_DBF_TEXT(SETUP, 2, "probedev");
 
@@ -5119,13 +5215,12 @@
 
 	snprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s",
 		dev_name(&gdev->dev));
-	card->debug = debug_register(dbf_name, 2, 1, 8);
+	card->debug = qeth_get_dbf_entry(dbf_name);
 	if (!card->debug) {
-		QETH_DBF_TEXT_(SETUP, 2, "%s", "qcdbf");
-		rc = -ENOMEM;
-		goto err_card;
+		rc = qeth_add_dbf_entry(card, dbf_name);
+		if (rc)
+			goto err_card;
 	}
-	debug_register_view(card->debug, &debug_hex_ascii_view);
 
 	card->read.ccwdev  = gdev->cdev[0];
 	card->write.ccwdev = gdev->cdev[1];
@@ -5139,12 +5234,12 @@
 	rc = qeth_determine_card_type(card);
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-		goto err_dbf;
+		goto err_card;
 	}
 	rc = qeth_setup_card(card);
 	if (rc) {
 		QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-		goto err_dbf;
+		goto err_card;
 	}
 
 	if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -5157,7 +5252,7 @@
 	case QETH_CARD_TYPE_OSM:
 		rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
 		if (rc)
-			goto err_dbf;
+			goto err_card;
 		rc = card->discipline->setup(card->gdev);
 		if (rc)
 			goto err_disc;
@@ -5176,8 +5271,6 @@
 
 err_disc:
 	qeth_core_free_discipline(card);
-err_dbf:
-	debug_unregister(card->debug);
 err_card:
 	qeth_core_free_card(card);
 err_dev:
@@ -5197,7 +5290,6 @@
 		qeth_core_free_discipline(card);
 	}
 
-	debug_unregister(card->debug);
 	write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
 	list_del(&card->list);
 	write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
@@ -5444,17 +5536,14 @@
 		struct ethtool_drvinfo *info)
 {
 	struct qeth_card *card = dev->ml_priv;
-	if (card->options.layer2)
-		strcpy(info->driver, "qeth_l2");
-	else
-		strcpy(info->driver, "qeth_l3");
 
-	strcpy(info->version, "1.0");
-	strcpy(info->fw_version, card->info.mcl_level);
-	sprintf(info->bus_info, "%s/%s/%s",
-			CARD_RDEV_ID(card),
-			CARD_WDEV_ID(card),
-			CARD_DDEV_ID(card));
+	strlcpy(info->driver, card->options.layer2 ? "qeth_l2" : "qeth_l3",
+		sizeof(info->driver));
+	strlcpy(info->version, "1.0", sizeof(info->version));
+	strlcpy(info->fw_version, card->info.mcl_level,
+		sizeof(info->fw_version));
+	snprintf(info->bus_info, sizeof(info->bus_info), "%s/%s/%s",
+		 CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
 }
 EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo);
 
@@ -5554,9 +5643,12 @@
 
 	pr_info("loading core functions\n");
 	INIT_LIST_HEAD(&qeth_core_card_list.list);
+	INIT_LIST_HEAD(&qeth_dbf_list);
 	rwlock_init(&qeth_core_card_list.rwlock);
 	mutex_init(&qeth_mod_mutex);
 
+	qeth_wq = create_singlethread_workqueue("qeth_wq");
+
 	rc = qeth_register_dbf_views();
 	if (rc)
 		goto out_err;
@@ -5603,6 +5695,8 @@
 
 static void __exit qeth_core_exit(void)
 {
+	qeth_clear_dbf_list();
+	destroy_workqueue(qeth_wq);
 	ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
 	ccw_driver_unregister(&qeth_ccw_driver);
 	kmem_cache_destroy(qeth_qdio_outbuf_cache);
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index 5cebfdd..06c5578 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -204,6 +204,7 @@
 	{IPA_RC_INVALID_SETRTG_INDICATOR, "Invalid SETRTG indicator"},
 	{IPA_RC_MC_ADDR_ALREADY_DEFINED, "Multicast address already defined"},
 	{IPA_RC_LAN_OFFLINE,		"STRTLAN_LAN_DISABLED - LAN offline"},
+	{IPA_RC_VEPA_TO_VEB_TRANSITION,	"Adj. switch disabled port mode RR"},
 	{IPA_RC_INVALID_IP_VERSION2,	"Invalid IP version"},
 	{IPA_RC_ENOMEM,			"Memory problem"},
 	{IPA_RC_FFFF,			"Unknown Error"}
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 3690bbf..07085d5 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -177,6 +177,7 @@
 	IPA_RC_INVALID_SETRTG_INDICATOR	= 0xe012,
 	IPA_RC_MC_ADDR_ALREADY_DEFINED	= 0xe013,
 	IPA_RC_LAN_OFFLINE		= 0xe080,
+	IPA_RC_VEPA_TO_VEB_TRANSITION	= 0xe090,
 	IPA_RC_INVALID_IP_VERSION2	= 0xf001,
 	IPA_RC_ENOMEM			= 0xfffe,
 	IPA_RC_FFFF			= 0xffff
@@ -269,6 +270,9 @@
 	SET_ACCESS_CTRL_RC_ALREADY_ISOLATED	= 0x0010,
 	SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER	= 0x0014,
 	SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF	= 0x0018,
+	SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED	= 0x0022,
+	SET_ACCESS_CTRL_RC_REFLREL_FAILED	= 0x0024,
+	SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED	= 0x0028,
 };
 
 
@@ -386,6 +390,7 @@
 /* SET_ACCESS_CONTROL: same format for request and reply */
 struct qeth_set_access_ctrl {
 	__u32 subcmd_code;
+	__u8 reserved[8];
 } __attribute__((packed));
 
 struct qeth_query_oat {
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 9655dc0..425c0ec 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -513,10 +513,11 @@
 	rc = count;
 
 	/* defer IP assist if device is offline (until discipline->set_online)*/
+	card->options.prev_isolation = card->options.isolation;
 	card->options.isolation = isolation;
 	if (card->state == CARD_STATE_SOFTSETUP ||
 	    card->state == CARD_STATE_UP) {
-		int ipa_rc = qeth_set_access_ctrl_online(card);
+		int ipa_rc = qeth_set_access_ctrl_online(card, 1);
 		if (ipa_rc != 0)
 			rc = ipa_rc;
 	}
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 7319555..d690166 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1025,9 +1025,14 @@
 
 contin:
 	if ((card->info.type == QETH_CARD_TYPE_OSD) ||
-	    (card->info.type == QETH_CARD_TYPE_OSX))
+	    (card->info.type == QETH_CARD_TYPE_OSX)) {
 		/* configure isolation level */
-		qeth_set_access_ctrl_online(card);
+		rc = qeth_set_access_ctrl_online(card, 0);
+		if (rc) {
+			rc = -ENODEV;
+			goto out_remove;
+		}
+	}
 
 	if (card->info.type != QETH_CARD_TYPE_OSN &&
 	    card->info.type != QETH_CARD_TYPE_OSM)
@@ -1144,12 +1149,9 @@
 		dev_info(&card->gdev->dev,
 			"Device successfully recovered!\n");
 	else {
-		if (rtnl_trylock()) {
-			dev_close(card->dev);
-			rtnl_unlock();
-			dev_warn(&card->gdev->dev, "The qeth device driver "
+		qeth_close_dev(card);
+		dev_warn(&card->gdev->dev, "The qeth device driver "
 				"failed to recover an error on the device\n");
-		}
 	}
 	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
 	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 6e5eef0..091ca0efa 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1449,7 +1449,8 @@
 {
 	QETH_CARD_TEXT(card, 3, "strtipas");
 
-	qeth_set_access_ctrl_online(card);	/* go on*/
+	if (qeth_set_access_ctrl_online(card, 0))
+		return -EIO;
 	qeth_l3_start_ipa_arp_processing(card);	/* go on*/
 	qeth_l3_start_ipa_ip_fragmentation(card);	/* go on*/
 	qeth_l3_start_ipa_source_mac(card);	/* go on*/
@@ -1640,6 +1641,7 @@
 	}
 }
 
+/* called with rcu_read_lock */
 static void qeth_l3_add_vlan_mc(struct qeth_card *card)
 {
 	struct in_device *in_dev;
@@ -1652,19 +1654,14 @@
 	for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
 		struct net_device *netdev;
 
-		rcu_read_lock();
 		netdev = __vlan_find_dev_deep(card->dev, vid);
-		rcu_read_unlock();
 		if (netdev == NULL ||
 		    !(netdev->flags & IFF_UP))
 			continue;
-		in_dev = in_dev_get(netdev);
+		in_dev = __in_dev_get_rcu(netdev);
 		if (!in_dev)
 			continue;
-		rcu_read_lock();
 		qeth_l3_add_mc(card, in_dev);
-		rcu_read_unlock();
-		in_dev_put(in_dev);
 	}
 }
 
@@ -1673,14 +1670,14 @@
 	struct in_device *in4_dev;
 
 	QETH_CARD_TEXT(card, 4, "chkmcv4");
-	in4_dev = in_dev_get(card->dev);
-	if (in4_dev == NULL)
-		return;
 	rcu_read_lock();
+	in4_dev = __in_dev_get_rcu(card->dev);
+	if (in4_dev == NULL)
+		goto unlock;
 	qeth_l3_add_mc(card, in4_dev);
 	qeth_l3_add_vlan_mc(card);
+unlock:
 	rcu_read_unlock();
-	in_dev_put(in4_dev);
 }
 
 #ifdef CONFIG_QETH_IPV6
@@ -1705,6 +1702,7 @@
 	}
 }
 
+/* called with rcu_read_lock */
 static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
 {
 	struct inet6_dev *in_dev;
@@ -1741,10 +1739,12 @@
 	in6_dev = in6_dev_get(card->dev);
 	if (in6_dev == NULL)
 		return;
+	rcu_read_lock();
 	read_lock_bh(&in6_dev->lock);
 	qeth_l3_add_mc6(card, in6_dev);
 	qeth_l3_add_vlan_mc6(card);
 	read_unlock_bh(&in6_dev->lock);
+	rcu_read_unlock();
 	in6_dev_put(in6_dev);
 }
 #endif /* CONFIG_QETH_IPV6 */
@@ -1813,8 +1813,10 @@
 static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
 			unsigned short vid)
 {
+	rcu_read_lock();
 	qeth_l3_free_vlan_addresses4(card, vid);
 	qeth_l3_free_vlan_addresses6(card, vid);
+	rcu_read_unlock();
 }
 
 static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
@@ -3387,8 +3389,10 @@
 		QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
 	if (!card->options.sniffer) {
 		rc = qeth_l3_start_ipassists(card);
-		if (rc)
+		if (rc) {
 			QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+			goto out_remove;
+		}
 		rc = qeth_l3_setrouting_v4(card);
 		if (rc)
 			QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
@@ -3510,12 +3514,9 @@
 		dev_info(&card->gdev->dev,
 			"Device successfully recovered!\n");
 	else {
-		if (rtnl_trylock()) {
-			dev_close(card->dev);
-			rtnl_unlock();
-			dev_warn(&card->gdev->dev, "The qeth device driver "
+		qeth_close_dev(card);
+		dev_warn(&card->gdev->dev, "The qeth device driver "
 				"failed to recover an error on the device\n");
-		}
 	}
 	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
 	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2e188e1..e79884e9 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -297,9 +297,20 @@
 	help
 	  This selects a driver for the PPC4xx SPI Controller.
 
+config SPI_PXA2XX_PXADMA
+	bool "PXA2xx SSP legacy PXA DMA API support"
+	depends on SPI_PXA2XX && ARCH_PXA
+	help
+	  Enable PXA private legacy DMA API support. Note that this is
+	  deprecated in favor of generic DMA engine API.
+
+config SPI_PXA2XX_DMA
+	def_bool y
+	depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA
+
 config SPI_PXA2XX
 	tristate "PXA2xx SSP SPI master"
-	depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
+	depends on ARCH_PXA || PCI || ACPI
 	select PXA_SSP if ARCH_PXA
 	help
 	  This enables using a PXA2xx or Sodaville SSP port as a SPI master
@@ -307,7 +318,7 @@
 	  additional documentation can be found a Documentation/spi/pxa2xx.
 
 config SPI_PXA2XX_PCI
-	def_bool SPI_PXA2XX && X86_32 && PCI
+	def_tristate SPI_PXA2XX && PCI
 
 config SPI_RSPI
 	tristate "Renesas RSPI controller"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 64e970b..e53c309 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -47,7 +47,10 @@
 obj-$(CONFIG_SPI_ORION)			+= spi-orion.o
 obj-$(CONFIG_SPI_PL022)			+= spi-pl022.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
-obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx.o
+spi-pxa2xx-platform-objs		:= spi-pxa2xx.o
+spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA)	+= spi-pxa2xx-pxadma.o
+spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)	+= spi-pxa2xx-dma.o
+obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
 obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index 5e7314a..a537f8d 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -134,7 +134,7 @@
 	hw->tx = t->tx_buf;
 	hw->rx = t->rx_buf;
 	hw->count = 0;
-	hw->bytes_per_word = (t->bits_per_word ? : spi->bits_per_word) / 8;
+	hw->bytes_per_word = t->bits_per_word / 8;
 	hw->len = t->len / hw->bytes_per_word;
 
 	if (hw->irq >= 0) {
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 9a5d779..e504b76 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -24,17 +24,24 @@
 #include <linux/spi/spi_bitbang.h>
 #include <linux/bitops.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 
 #include <asm/mach-ath79/ar71xx_regs.h>
 #include <asm/mach-ath79/ath79_spi_platform.h>
 
 #define DRV_NAME	"ath79-spi"
 
+#define ATH79_SPI_RRW_DELAY_FACTOR	12000
+#define MHZ				(1000 * 1000)
+
 struct ath79_spi {
 	struct spi_bitbang	bitbang;
 	u32			ioc_base;
 	u32			reg_ctrl;
 	void __iomem		*base;
+	struct clk		*clk;
+	unsigned		rrw_delay;
 };
 
 static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
@@ -52,6 +59,12 @@
 	return spi_master_get_devdata(spi->master);
 }
 
+static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
+{
+	if (nsecs > sp->rrw_delay)
+		ndelay(nsecs - sp->rrw_delay);
+}
+
 static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
 {
 	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
@@ -83,15 +96,8 @@
 
 }
 
-static int ath79_spi_setup_cs(struct spi_device *spi)
+static void ath79_spi_enable(struct ath79_spi *sp)
 {
-	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-	struct ath79_spi_controller_data *cdata;
-
-	cdata = spi->controller_data;
-	if (spi->chip_select && !cdata)
-		return -EINVAL;
-
 	/* enable GPIO mode */
 	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
 
@@ -101,46 +107,50 @@
 
 	/* TODO: setup speed? */
 	ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
-
-	if (spi->chip_select) {
-		int status = 0;
-
-		status = gpio_request(cdata->gpio, dev_name(&spi->dev));
-		if (status)
-			return status;
-
-		status = gpio_direction_output(cdata->gpio,
-					       spi->mode & SPI_CS_HIGH);
-		if (status) {
-			gpio_free(cdata->gpio);
-			return status;
-		}
-	} else {
-		if (spi->mode & SPI_CS_HIGH)
-			sp->ioc_base |= AR71XX_SPI_IOC_CS0;
-		else
-			sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
-		ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
-	}
-
-	return 0;
 }
 
-static void ath79_spi_cleanup_cs(struct spi_device *spi)
+static void ath79_spi_disable(struct ath79_spi *sp)
 {
-	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-
-	if (spi->chip_select) {
-		struct ath79_spi_controller_data *cdata = spi->controller_data;
-		gpio_free(cdata->gpio);
-	}
-
 	/* restore CTRL register */
 	ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
 	/* disable GPIO mode */
 	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
 }
 
+static int ath79_spi_setup_cs(struct spi_device *spi)
+{
+	struct ath79_spi_controller_data *cdata;
+	int status;
+
+	cdata = spi->controller_data;
+	if (spi->chip_select && !cdata)
+		return -EINVAL;
+
+	status = 0;
+	if (spi->chip_select) {
+		unsigned long flags;
+
+		flags = GPIOF_DIR_OUT;
+		if (spi->mode & SPI_CS_HIGH)
+			flags |= GPIOF_INIT_HIGH;
+		else
+			flags |= GPIOF_INIT_LOW;
+
+		status = gpio_request_one(cdata->gpio, flags,
+					  dev_name(&spi->dev));
+	}
+
+	return status;
+}
+
+static void ath79_spi_cleanup_cs(struct spi_device *spi)
+{
+	if (spi->chip_select) {
+		struct ath79_spi_controller_data *cdata = spi->controller_data;
+		gpio_free(cdata->gpio);
+	}
+}
+
 static int ath79_spi_setup(struct spi_device *spi)
 {
 	int status = 0;
@@ -184,7 +194,11 @@
 
 		/* setup MSB (to slave) on trailing edge */
 		ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
+		ath79_spi_delay(sp, nsecs);
 		ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
+		ath79_spi_delay(sp, nsecs);
+		if (bits == 1)
+			ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
 
 		word <<= 1;
 	}
@@ -198,6 +212,7 @@
 	struct ath79_spi *sp;
 	struct ath79_spi_platform_data *pdata;
 	struct resource	*r;
+	unsigned long rate;
 	int ret;
 
 	master = spi_alloc_master(&pdev->dev, sizeof(*sp));
@@ -236,12 +251,39 @@
 		goto err_put_master;
 	}
 
+	sp->clk = clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(sp->clk)) {
+		ret = PTR_ERR(sp->clk);
+		goto err_unmap;
+	}
+
+	ret = clk_enable(sp->clk);
+	if (ret)
+		goto err_clk_put;
+
+	rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
+	if (!rate) {
+		ret = -EINVAL;
+		goto err_clk_disable;
+	}
+
+	sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
+	dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
+		sp->rrw_delay);
+
+	ath79_spi_enable(sp);
 	ret = spi_bitbang_start(&sp->bitbang);
 	if (ret)
-		goto err_unmap;
+		goto err_disable;
 
 	return 0;
 
+err_disable:
+	ath79_spi_disable(sp);
+err_clk_disable:
+	clk_disable(sp->clk);
+err_clk_put:
+	clk_put(sp->clk);
 err_unmap:
 	iounmap(sp->base);
 err_put_master:
@@ -256,6 +298,9 @@
 	struct ath79_spi *sp = platform_get_drvdata(pdev);
 
 	spi_bitbang_stop(&sp->bitbang);
+	ath79_spi_disable(sp);
+	clk_disable(sp->clk);
+	clk_put(sp->clk);
 	iounmap(sp->base);
 	platform_set_drvdata(pdev, NULL);
 	spi_master_put(sp->bitbang.master);
@@ -263,9 +308,15 @@
 	return 0;
 }
 
+static void ath79_spi_shutdown(struct platform_device *pdev)
+{
+	ath79_spi_remove(pdev);
+}
+
 static struct platform_driver ath79_spi_driver = {
 	.probe		= ath79_spi_probe,
 	.remove		= ath79_spi_remove,
+	.shutdown	= ath79_spi_shutdown,
 	.driver		= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index ab34497..656d137 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1088,7 +1088,7 @@
 	.suspend	= atmel_spi_suspend,
 	.resume		= atmel_spi_resume,
 	.probe		= atmel_spi_probe,
-	.remove		= __exit_p(atmel_spi_remove),
+	.remove		= atmel_spi_remove,
 };
 module_platform_driver(atmel_spi_driver);
 
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 4de66d1..44dd34b 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -717,7 +717,7 @@
 	}
 }
 
-static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
+static void au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
 {
 	u32 stat, cfg;
 
@@ -766,7 +766,7 @@
 }
 
 
-static int __init au1550_spi_probe(struct platform_device *pdev)
+static int au1550_spi_probe(struct platform_device *pdev)
 {
 	struct au1550_spi *hw;
 	struct spi_master *master;
@@ -968,7 +968,7 @@
 	return err;
 }
 
-static int __exit au1550_spi_remove(struct platform_device *pdev)
+static int au1550_spi_remove(struct platform_device *pdev)
 {
 	struct au1550_spi *hw = platform_get_drvdata(pdev);
 
@@ -997,7 +997,7 @@
 MODULE_ALIAS("platform:au1550-spi");
 
 static struct platform_driver au1550_spi_drv = {
-	.remove = __exit_p(au1550_spi_remove),
+	.remove = au1550_spi_remove,
 	.driver = {
 		.name = "au1550-spi",
 		.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index f44ab55..9578af7 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -37,6 +37,8 @@
 
 #define PFX		KBUILD_MODNAME
 
+#define BCM63XX_SPI_MAX_PREPEND		15
+
 struct bcm63xx_spi {
 	struct completion	done;
 
@@ -49,16 +51,10 @@
 	unsigned int		msg_type_shift;
 	unsigned int		msg_ctl_width;
 
-	/* Data buffers */
-	const unsigned char	*tx_ptr;
-	unsigned char		*rx_ptr;
-
 	/* data iomem */
 	u8 __iomem		*tx_io;
 	const u8 __iomem	*rx_io;
 
-	int			remaining_bytes;
-
 	struct clk		*clk;
 	struct platform_device	*pdev;
 };
@@ -175,24 +171,17 @@
 	return 0;
 }
 
-/* Fill the TX FIFO with as many bytes as possible */
-static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
-{
-	u8 size;
-
-	/* Fill the Tx FIFO with as many bytes as possible */
-	size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
-		bs->fifo_size;
-	memcpy_toio(bs->tx_io, bs->tx_ptr, size);
-	bs->remaining_bytes -= size;
-}
-
-static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
-					struct spi_transfer *t)
+static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
+				unsigned int num_transfers)
 {
 	struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
 	u16 msg_ctl;
 	u16 cmd;
+	u8 rx_tail;
+	unsigned int i, timeout = 0, prepend_len = 0, len = 0;
+	struct spi_transfer *t = first;
+	bool do_rx = false;
+	bool do_tx = false;
 
 	/* Disable the CMD_DONE interrupt */
 	bcm_spi_writeb(bs, 0, SPI_INT_MASK);
@@ -200,25 +189,45 @@
 	dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
 		t->tx_buf, t->rx_buf, t->len);
 
-	/* Transmitter is inhibited */
-	bs->tx_ptr = t->tx_buf;
-	bs->rx_ptr = t->rx_buf;
+	if (num_transfers > 1 && t->tx_buf && t->len <= BCM63XX_SPI_MAX_PREPEND)
+		prepend_len = t->len;
 
-	if (t->tx_buf) {
-		bs->remaining_bytes = t->len;
-		bcm63xx_spi_fill_tx_fifo(bs);
+	/* prepare the buffer */
+	for (i = 0; i < num_transfers; i++) {
+		if (t->tx_buf) {
+			do_tx = true;
+			memcpy_toio(bs->tx_io + len, t->tx_buf, t->len);
+
+			/* don't prepend more than one tx */
+			if (t != first)
+				prepend_len = 0;
+		}
+
+		if (t->rx_buf) {
+			do_rx = true;
+			/* prepend is half-duplex write only */
+			if (t == first)
+				prepend_len = 0;
+		}
+
+		len += t->len;
+
+		t = list_entry(t->transfer_list.next, struct spi_transfer,
+			       transfer_list);
 	}
 
+	len -= prepend_len;
+
 	init_completion(&bs->done);
 
 	/* Fill in the Message control register */
-	msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
+	msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
 
-	if (t->rx_buf && t->tx_buf)
+	if (do_rx && do_tx && prepend_len == 0)
 		msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
-	else if (t->rx_buf)
+	else if (do_rx)
 		msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
-	else if (t->tx_buf)
+	else if (do_tx)
 		msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
 
 	switch (bs->msg_ctl_width) {
@@ -232,14 +241,41 @@
 
 	/* Issue the transfer */
 	cmd = SPI_CMD_START_IMMEDIATE;
-	cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
+	cmd |= (prepend_len << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
 	cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
 	bcm_spi_writew(bs, cmd, SPI_CMD);
 
 	/* Enable the CMD_DONE interrupt */
 	bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
 
-	return t->len - bs->remaining_bytes;
+	timeout = wait_for_completion_timeout(&bs->done, HZ);
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	/* read out all data */
+	rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
+
+	if (do_rx && rx_tail != len)
+		return -EIO;
+
+	if (!rx_tail)
+		return 0;
+
+	len = 0;
+	t = first;
+	/* Read out all the data */
+	for (i = 0; i < num_transfers; i++) {
+		if (t->rx_buf)
+			memcpy_fromio(t->rx_buf, bs->rx_io + len, t->len);
+
+		if (t != first || prepend_len == 0)
+			len += t->len;
+
+		t = list_entry(t->transfer_list.next, struct spi_transfer,
+			       transfer_list);
+	}
+
+	return 0;
 }
 
 static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
@@ -264,41 +300,76 @@
 					struct spi_message *m)
 {
 	struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-	struct spi_transfer *t;
+	struct spi_transfer *t, *first = NULL;
 	struct spi_device *spi = m->spi;
 	int status = 0;
-	unsigned int timeout = 0;
+	unsigned int n_transfers = 0, total_len = 0;
+	bool can_use_prepend = false;
 
+	/*
+	 * This SPI controller does not support keeping CS active after a
+	 * transfer.
+	 * Work around this by merging as many transfers we can into one big
+	 * full-duplex transfers.
+	 */
 	list_for_each_entry(t, &m->transfers, transfer_list) {
-		unsigned int len = t->len;
-		u8 rx_tail;
-
 		status = bcm63xx_spi_check_transfer(spi, t);
 		if (status < 0)
 			goto exit;
 
-		/* configure adapter for a new transfer */
-		bcm63xx_spi_setup_transfer(spi, t);
+		if (!first)
+			first = t;
 
-		while (len) {
-			/* send the data */
-			len -= bcm63xx_txrx_bufs(spi, t);
+		n_transfers++;
+		total_len += t->len;
 
-			timeout = wait_for_completion_timeout(&bs->done, HZ);
-			if (!timeout) {
-				status = -ETIMEDOUT;
-				goto exit;
-			}
+		if (n_transfers == 2 && !first->rx_buf && !t->tx_buf &&
+		    first->len <= BCM63XX_SPI_MAX_PREPEND)
+			can_use_prepend = true;
+		else if (can_use_prepend && t->tx_buf)
+			can_use_prepend = false;
 
-			/* read out all data */
-			rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
-
-			/* Read out all the data */
-			if (rx_tail)
-				memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
+		/* we can only transfer one fifo worth of data */
+		if ((can_use_prepend &&
+		     total_len > (bs->fifo_size + BCM63XX_SPI_MAX_PREPEND)) ||
+		    (!can_use_prepend && total_len > bs->fifo_size)) {
+			dev_err(&spi->dev, "unable to do transfers larger than FIFO size (%i > %i)\n",
+				total_len, bs->fifo_size);
+			status = -EINVAL;
+			goto exit;
 		}
 
-		m->actual_length += t->len;
+		/* all combined transfers have to have the same speed */
+		if (t->speed_hz != first->speed_hz) {
+			dev_err(&spi->dev, "unable to change speed between transfers\n");
+			status = -EINVAL;
+			goto exit;
+		}
+
+		/* CS will be deasserted directly after transfer */
+		if (t->delay_usecs) {
+			dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
+			status = -EINVAL;
+			goto exit;
+		}
+
+		if (t->cs_change ||
+		    list_is_last(&t->transfer_list, &m->transfers)) {
+			/* configure adapter for a new transfer */
+			bcm63xx_spi_setup_transfer(spi, first);
+
+			/* send the data */
+			status = bcm63xx_txrx_bufs(spi, first, n_transfers);
+			if (status)
+				goto exit;
+
+			m->actual_length += total_len;
+
+			first = NULL;
+			n_transfers = 0;
+			total_len = 0;
+			can_use_prepend = false;
+		}
 	}
 exit:
 	m->status = status;
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index ac7ffca..39b0d17 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -416,8 +416,7 @@
 	drv_data->cs_change = transfer->cs_change;
 
 	/* Bits per word setup */
-	bits_per_word = transfer->bits_per_word ? :
-		message->spi->bits_per_word ? : 8;
+	bits_per_word = transfer->bits_per_word;
 	if (bits_per_word % 16 == 0)
 		drv_data->ops = &bfin_sport_transfer_ops_u16;
 	else
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index 0429d83..317f564 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -642,8 +642,7 @@
 	drv_data->cs_change = transfer->cs_change;
 
 	/* Bits per word setup */
-	bits_per_word = transfer->bits_per_word ? :
-		message->spi->bits_per_word ? : 8;
+	bits_per_word = transfer->bits_per_word;
 	if (bits_per_word % 16 == 0) {
 		drv_data->n_bytes = bits_per_word/8;
 		drv_data->len = (transfer->len) >> 1;
@@ -1274,7 +1273,7 @@
 	return 0;
 }
 
-static int __init bfin_spi_probe(struct platform_device *pdev)
+static int bfin_spi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct bfin5xx_spi_master *platform_info;
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index 8b3d8ef..a63d7da 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -69,7 +69,7 @@
 	unsigned		ns,
 	struct spi_transfer	*t
 ) {
-	unsigned		bits = t->bits_per_word ? : spi->bits_per_word;
+	unsigned		bits = t->bits_per_word;
 	unsigned		count = t->len;
 	const u8		*tx = t->tx_buf;
 	u8			*rx = t->rx_buf;
@@ -95,7 +95,7 @@
 	unsigned		ns,
 	struct spi_transfer	*t
 ) {
-	unsigned		bits = t->bits_per_word ? : spi->bits_per_word;
+	unsigned		bits = t->bits_per_word;
 	unsigned		count = t->len;
 	const u16		*tx = t->tx_buf;
 	u16			*rx = t->rx_buf;
@@ -121,7 +121,7 @@
 	unsigned		ns,
 	struct spi_transfer	*t
 ) {
-	unsigned		bits = t->bits_per_word ? : spi->bits_per_word;
+	unsigned		bits = t->bits_per_word;
 	unsigned		count = t->len;
 	const u32		*tx = t->tx_buf;
 	u32			*rx = t->rx_buf;
@@ -427,40 +427,41 @@
  */
 int spi_bitbang_start(struct spi_bitbang *bitbang)
 {
-	int	status;
+	struct spi_master *master = bitbang->master;
+	int status;
 
-	if (!bitbang->master || !bitbang->chipselect)
+	if (!master || !bitbang->chipselect)
 		return -EINVAL;
 
 	INIT_WORK(&bitbang->work, bitbang_work);
 	spin_lock_init(&bitbang->lock);
 	INIT_LIST_HEAD(&bitbang->queue);
 
-	if (!bitbang->master->mode_bits)
-		bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
+	if (!master->mode_bits)
+		master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
 
-	if (!bitbang->master->transfer)
-		bitbang->master->transfer = spi_bitbang_transfer;
+	if (!master->transfer)
+		master->transfer = spi_bitbang_transfer;
 	if (!bitbang->txrx_bufs) {
 		bitbang->use_dma = 0;
 		bitbang->txrx_bufs = spi_bitbang_bufs;
-		if (!bitbang->master->setup) {
+		if (!master->setup) {
 			if (!bitbang->setup_transfer)
 				bitbang->setup_transfer =
 					 spi_bitbang_setup_transfer;
-			bitbang->master->setup = spi_bitbang_setup;
-			bitbang->master->cleanup = spi_bitbang_cleanup;
+			master->setup = spi_bitbang_setup;
+			master->cleanup = spi_bitbang_cleanup;
 		}
-	} else if (!bitbang->master->setup)
+	} else if (!master->setup)
 		return -EINVAL;
-	if (bitbang->master->transfer == spi_bitbang_transfer &&
+	if (master->transfer == spi_bitbang_transfer &&
 			!bitbang->setup_transfer)
 		return -EINVAL;
 
 	/* this task is the only thing to touch the SPI bits */
 	bitbang->busy = 0;
 	bitbang->workqueue = create_singlethread_workqueue(
-			dev_name(bitbang->master->dev.parent));
+			dev_name(master->dev.parent));
 	if (bitbang->workqueue == NULL) {
 		status = -EBUSY;
 		goto err1;
@@ -469,7 +470,7 @@
 	/* driver may get busy before register() returns, especially
 	 * if someone registered boardinfo for devices
 	 */
-	status = spi_register_master(bitbang->master);
+	status = spi_register_master(master);
 	if (status < 0)
 		goto err2;
 
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 1366c46..a11cbf0 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -68,7 +68,7 @@
 				   struct spi_transfer *xfer)
 {
 	u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
-	u8 bpw = xfer->bits_per_word ? : spi->bits_per_word;
+	u8 bpw = xfer->bits_per_word;
 	struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
 
 	if (bpw != 8) {
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 58466b8..7b5cc9e 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -329,8 +329,7 @@
 		mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
 
 		mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
-		if ((t->bits_per_word ? t->bits_per_word :
-					spi->bits_per_word) == 8)
+		if (t->bits_per_word == 8)
 			mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
 					t->rx_buf);
 		else
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 13661e1..8234d22 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -28,6 +28,8 @@
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/edma.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/slab.h>
@@ -135,7 +137,7 @@
 	int			dma_rx_chnum;
 	int			dma_tx_chnum;
 
-	struct davinci_spi_platform_data *pdata;
+	struct davinci_spi_platform_data pdata;
 
 	void			(*get_rx)(u32 rx_data, struct davinci_spi *);
 	u32			(*get_tx)(struct davinci_spi *);
@@ -213,7 +215,7 @@
 	bool gpio_chipsel = false;
 
 	dspi = spi_master_get_devdata(spi->master);
-	pdata = dspi->pdata;
+	pdata = &dspi->pdata;
 
 	if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
 				pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
@@ -392,7 +394,7 @@
 	struct davinci_spi_platform_data *pdata;
 
 	dspi = spi_master_get_devdata(spi->master);
-	pdata = dspi->pdata;
+	pdata = &dspi->pdata;
 
 	/* if bits per word length is zero then set it default 8 */
 	if (!spi->bits_per_word)
@@ -534,7 +536,7 @@
 	struct scatterlist sg_rx, sg_tx;
 
 	dspi = spi_master_get_devdata(spi->master);
-	pdata = dspi->pdata;
+	pdata = &dspi->pdata;
 	spicfg = (struct davinci_spi_config *)spi->controller_data;
 	if (!spicfg)
 		spicfg = &davinci_spi_default_cfg;
@@ -700,6 +702,19 @@
 }
 
 /**
+ * dummy_thread_fn - dummy thread function
+ * @irq: IRQ number for this SPI Master
+ * @context_data: structure for SPI Master controller davinci_spi
+ *
+ * This is to satisfy the request_threaded_irq() API so that the irq
+ * handler is called in interrupt context.
+ */
+static irqreturn_t dummy_thread_fn(s32 irq, void *data)
+{
+	return IRQ_HANDLED;
+}
+
+/**
  * davinci_spi_irq - Interrupt handler for SPI Master Controller
  * @irq: IRQ number for this SPI Master
  * @context_data: structure for SPI Master controller davinci_spi
@@ -758,6 +773,70 @@
 	return r;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id davinci_spi_of_match[] = {
+	{
+		.compatible = "ti,dm644x-spi",
+	},
+	{
+		.compatible = "ti,da8xx-spi",
+		.data = (void *)SPI_VERSION_2,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, davini_spi_of_match);
+
+/**
+ * spi_davinci_get_pdata - Get platform data from DTS binding
+ * @pdev: ptr to platform data
+ * @dspi: ptr to driver data
+ *
+ * Parses and populates pdata in dspi from device tree bindings.
+ *
+ * NOTE: Not all platform data params are supported currently.
+ */
+static int spi_davinci_get_pdata(struct platform_device *pdev,
+			struct davinci_spi *dspi)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct davinci_spi_platform_data *pdata;
+	unsigned int num_cs, intr_line = 0;
+	const struct of_device_id *match;
+
+	pdata = &dspi->pdata;
+
+	pdata->version = SPI_VERSION_1;
+	match = of_match_device(of_match_ptr(davinci_spi_of_match),
+				&pdev->dev);
+	if (!match)
+		return -ENODEV;
+
+	/* match data has the SPI version number for SPI_VERSION_2 */
+	if (match->data == (void *)SPI_VERSION_2)
+		pdata->version = SPI_VERSION_2;
+
+	/*
+	 * default num_cs is 1 and all chipsel are internal to the chip
+	 * indicated by chip_sel being NULL. GPIO based CS is not
+	 * supported yet in DT bindings.
+	 */
+	num_cs = 1;
+	of_property_read_u32(node, "num-cs", &num_cs);
+	pdata->num_chipselect = num_cs;
+	of_property_read_u32(node, "ti,davinci-spi-intr-line", &intr_line);
+	pdata->intr_line = intr_line;
+	return 0;
+}
+#else
+#define davinci_spi_of_match NULL
+static struct davinci_spi_platform_data
+	*spi_davinci_get_pdata(struct platform_device *pdev,
+		struct davinci_spi *dspi)
+{
+	return -ENODEV;
+}
+#endif
+
 /**
  * davinci_spi_probe - probe function for SPI Master Controller
  * @pdev: platform_device structure which contains plateform specific data
@@ -780,12 +859,6 @@
 	int i = 0, ret = 0;
 	u32 spipc0;
 
-	pdata = pdev->dev.platform_data;
-	if (pdata == NULL) {
-		ret = -ENODEV;
-		goto err;
-	}
-
 	master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
 	if (master == NULL) {
 		ret = -ENOMEM;
@@ -800,6 +873,19 @@
 		goto free_master;
 	}
 
+	if (pdev->dev.platform_data) {
+		pdata = pdev->dev.platform_data;
+		dspi->pdata = *pdata;
+	} else {
+		/* update dspi pdata with that from the DT */
+		ret = spi_davinci_get_pdata(pdev, dspi);
+		if (ret < 0)
+			goto free_master;
+	}
+
+	/* pdata in dspi is now updated and point pdata to that */
+	pdata = &dspi->pdata;
+
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (r == NULL) {
 		ret = -ENOENT;
@@ -807,7 +893,6 @@
 	}
 
 	dspi->pbase = r->start;
-	dspi->pdata = pdata;
 
 	mem = request_mem_region(r->start, resource_size(r), pdev->name);
 	if (mem == NULL) {
@@ -827,8 +912,8 @@
 		goto unmap_io;
 	}
 
-	ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev),
-									dspi);
+	ret = request_threaded_irq(dspi->irq, davinci_spi_irq, dummy_thread_fn,
+				 0, dev_name(&pdev->dev), dspi);
 	if (ret)
 		goto unmap_io;
 
@@ -843,8 +928,9 @@
 		ret = -ENODEV;
 		goto put_master;
 	}
-	clk_enable(dspi->clk);
+	clk_prepare_enable(dspi->clk);
 
+	master->dev.of_node = pdev->dev.of_node;
 	master->bus_num = pdev->id;
 	master->num_chipselect = pdata->num_chipselect;
 	master->setup = davinci_spi_setup;
@@ -927,7 +1013,7 @@
 	dma_release_channel(dspi->dma_rx);
 	dma_release_channel(dspi->dma_tx);
 free_clk:
-	clk_disable(dspi->clk);
+	clk_disable_unprepare(dspi->clk);
 	clk_put(dspi->clk);
 put_master:
 	spi_master_put(master);
@@ -963,7 +1049,7 @@
 
 	spi_bitbang_stop(&dspi->bitbang);
 
-	clk_disable(dspi->clk);
+	clk_disable_unprepare(dspi->clk);
 	clk_put(dspi->clk);
 	spi_master_put(master);
 	free_irq(dspi->irq, dspi);
@@ -978,6 +1064,7 @@
 	.driver = {
 		.name = "spi_davinci",
 		.owner = THIS_MODULE,
+		.of_match_table = davinci_spi_of_match,
 	},
 	.probe = davinci_spi_probe,
 	.remove = davinci_spi_remove,
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index acb1e19..aecbff1 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -446,7 +446,7 @@
 	struct spi_message *msg = espi->current_msg;
 	struct spi_transfer *t = msg->state;
 
-	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+	return t->bits_per_word;
 }
 
 static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index 6a6f62e..c7a74f0 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -398,7 +398,7 @@
 	}
 
 	m->status = ret;
-	m->complete(m->context);
+	spi_finalize_current_message(master);
 
 	return 0;
 }
@@ -423,6 +423,7 @@
 
 	master->mode_bits = SPI_MODE_3;
 	master->num_chipselect = 1;
+	master->flags = SPI_MASTER_HALF_DUPLEX;
 	master->bus_num = -1;
 	master->setup = falcon_sflash_setup;
 	master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 1a7f635..086a9ee 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -947,12 +947,12 @@
 	struct device_node *np = dev->of_node;
 	struct fsl_spi_platform_data *pdata = dev->platform_data;
 	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-	unsigned int ngpios;
+	int ngpios;
 	int i = 0;
 	int ret;
 
 	ngpios = of_gpio_count(np);
-	if (!ngpios) {
+	if (ngpios <= 0) {
 		/*
 		 * SPI w/o chip-select line. One SPI device is still permitted
 		 * though.
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index c7cf0b7..9ddef55 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -365,9 +365,26 @@
 	if (!pdata)
 		return -ENOMEM;
 
-	pdata->sck = of_get_named_gpio(np, "gpio-sck", 0);
-	pdata->miso = of_get_named_gpio(np, "gpio-miso", 0);
-	pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0);
+	ret = of_get_named_gpio(np, "gpio-sck", 0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "gpio-sck property not found\n");
+		goto error_free;
+	}
+	pdata->sck = ret;
+
+	ret = of_get_named_gpio(np, "gpio-miso", 0);
+	if (ret < 0) {
+		dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
+		pdata->miso = SPI_GPIO_NO_MISO;
+	} else
+		pdata->miso = ret;
+
+	ret = of_get_named_gpio(np, "gpio-mosi", 0);
+	if (ret < 0) {
+		dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
+		pdata->mosi = SPI_GPIO_NO_MOSI;
+	} else
+		pdata->mosi = ret;
 
 	ret = of_property_read_u32(np, "num-chipselects", &tmp);
 	if (ret < 0) {
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 9049132..0befeeb 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -949,3 +949,4 @@
 MODULE_DESCRIPTION("SPI Master Controller driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index cb3a310..89480b2 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -438,6 +438,7 @@
 		master->num_chipselect = pdata->max_chipselect;
 	}
 
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
 	master->setup = mpc512x_psc_spi_setup;
 	master->transfer = mpc512x_psc_spi_transfer;
 	master->cleanup = mpc512x_psc_spi_cleanup;
@@ -522,17 +523,11 @@
 	regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
 
 	/* get PSC id (0..11, used by port_config) */
-	if (op->dev.platform_data == NULL) {
-		const u32 *psc_nump;
-
-		psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL);
-		if (!psc_nump || *psc_nump > 11) {
-			dev_err(&op->dev, "mpc512x_psc_spi: Device node %s "
-				"has invalid cell-index property\n",
-				op->dev.of_node->full_name);
-			return -EINVAL;
-		}
-		id = *psc_nump;
+	id = of_alias_get_id(op->dev.of_node, "spi");
+	if (id < 0) {
+		dev_err(&op->dev, "no alias id for %s\n",
+			op->dev.of_node->full_name);
+		return id;
 	}
 
 	return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index a3ede24..e3d8b31 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -241,6 +241,7 @@
 	INIT_COMPLETION(spi->c);
 
 	ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
+	ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
 	ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
 
 	if (*first)
@@ -256,8 +257,10 @@
 		if ((sg_count + 1 == sgs) && *last)
 			ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
 
-		if (ssp->devid == IMX23_SSP)
+		if (ssp->devid == IMX23_SSP) {
+			ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
 			ctrl0 |= min;
+		}
 
 		dma_xfer[sg_count].pio[0] = ctrl0;
 		dma_xfer[sg_count].pio[3] = min;
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 432e66e..cb2e284 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -54,7 +54,7 @@
 	unsigned int txc, rxc;
 	const u8 *txp;
 	u8 *rxp;
-	unsigned int gpio_cs_count;
+	int gpio_cs_count;
 	int *gpio_cs;
 };
 
@@ -74,7 +74,7 @@
 {
 	struct tiny_spi *hw = tiny_spi_to_hw(spi);
 
-	if (hw->gpio_cs_count) {
+	if (hw->gpio_cs_count > 0) {
 		gpio_set_value(hw->gpio_cs[spi->chip_select],
 			(spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
 	}
@@ -254,7 +254,7 @@
 	if (!np)
 		return 0;
 	hw->gpio_cs_count = of_gpio_count(np);
-	if (hw->gpio_cs_count) {
+	if (hw->gpio_cs_count > 0) {
 		hw->gpio_cs = devm_kzalloc(&pdev->dev,
 				hw->gpio_cs_count * sizeof(unsigned int),
 				GFP_KERNEL);
@@ -352,7 +352,7 @@
 			goto exit_gpio;
 		gpio_direction_output(hw->gpio_cs[i], 1);
 	}
-	hw->bitbang.master->num_chipselect = max(1U, hw->gpio_cs_count);
+	hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count);
 
 	/* register our spi controller */
 	err = spi_bitbang_start(&hw->bitbang);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 3aef7fa..78d29a1 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -481,7 +481,7 @@
 	return 0;
 }
 
-static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
+static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
 {
 	return 0;
 }
@@ -560,7 +560,7 @@
 	return status;
 }
 
-static int __exit omap1_spi100k_remove(struct platform_device *pdev)
+static int omap1_spi100k_remove(struct platform_device *pdev)
 {
 	struct spi_master       *master;
 	struct omap1_spi100k    *spi100k;
@@ -604,7 +604,7 @@
 		.name		= "omap1_spi100k",
 		.owner		= THIS_MODULE,
 	},
-	.remove		= __exit_p(omap1_spi100k_remove),
+	.remove		= omap1_spi100k_remove,
 };
 
 
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 0a94d9d..102b233 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -476,7 +476,7 @@
 	spi_master_put(uwire->bitbang.master);
 }
 
-static int __init uwire_probe(struct platform_device *pdev)
+static int uwire_probe(struct platform_device *pdev)
 {
 	struct spi_master	*master;
 	struct uwire_spi	*uwire;
@@ -536,7 +536,7 @@
 	return status;
 }
 
-static int __exit uwire_remove(struct platform_device *pdev)
+static int uwire_remove(struct platform_device *pdev)
 {
 	struct uwire_spi	*uwire = dev_get_drvdata(&pdev->dev);
 	int			status;
@@ -557,7 +557,7 @@
 		.name		= "omap_uwire",
 		.owner		= THIS_MODULE,
 	},
-	.remove		= __exit_p(uwire_remove),
+	.remove		= uwire_remove,
 	// suspend ... unuse ck
 	// resume ... use ck
 };
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index b610f52..69945b0 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -298,10 +298,10 @@
 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
 	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
-	complete(&mcspi_dma->dma_rx_completion);
-
 	/* We must disable the DMA RX request */
 	omap2_mcspi_set_dma_req(spi, 1, 0);
+
+	complete(&mcspi_dma->dma_rx_completion);
 }
 
 static void omap2_mcspi_tx_callback(void *data)
@@ -310,10 +310,10 @@
 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
 	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
-	complete(&mcspi_dma->dma_tx_completion);
-
 	/* We must disable the DMA TX request */
 	omap2_mcspi_set_dma_req(spi, 0, 0);
+
+	complete(&mcspi_dma->dma_tx_completion);
 }
 
 static void omap2_mcspi_tx_dma(struct spi_device *spi,
@@ -927,6 +927,7 @@
 
 	struct spi_device		*spi;
 	struct spi_transfer		*t = NULL;
+	struct spi_master		*master;
 	int				cs_active = 0;
 	struct omap2_mcspi_cs		*cs;
 	struct omap2_mcspi_device_config *cd;
@@ -935,6 +936,7 @@
 	u32				chconf;
 
 	spi = m->spi;
+	master = spi->master;
 	cs = spi->controller_state;
 	cd = spi->controller_data;
 
@@ -952,6 +954,14 @@
 			if (!t->speed_hz && !t->bits_per_word)
 				par_override = 0;
 		}
+		if (cd && cd->cs_per_word) {
+			chconf = mcspi->ctx.modulctrl;
+			chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
+			mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+			mcspi->ctx.modulctrl =
+				mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+		}
+
 
 		if (!cs_active) {
 			omap2_mcspi_force_cs(spi, 1);
@@ -1013,6 +1023,14 @@
 	if (cs_active)
 		omap2_mcspi_force_cs(spi, 0);
 
+	if (cd && cd->cs_per_word) {
+		chconf = mcspi->ctx.modulctrl;
+		chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
+		mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+		mcspi->ctx.modulctrl =
+			mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+	}
+
 	omap2_mcspi_set_enable(spi, 0);
 
 	m->status = status;
@@ -1020,7 +1038,7 @@
 }
 
 static int omap2_mcspi_transfer_one_message(struct spi_master *master,
-						struct spi_message *m)
+		struct spi_message *m)
 {
 	struct omap2_mcspi	*mcspi;
 	struct spi_transfer	*t;
@@ -1041,7 +1059,7 @@
 				|| (len && !(rx_buf || tx_buf))
 				|| (t->bits_per_word &&
 					(  t->bits_per_word < 4
-					|| t->bits_per_word > 32))) {
+					   || t->bits_per_word > 32))) {
 			dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
 					t->speed_hz,
 					len,
@@ -1052,8 +1070,8 @@
 		}
 		if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
 			dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
-				t->speed_hz,
-				OMAP2_MCSPI_MAX_FREQ >> 15);
+					t->speed_hz,
+					OMAP2_MCSPI_MAX_FREQ >> 15);
 			return -EINVAL;
 		}
 
@@ -1099,7 +1117,7 @@
 		return ret;
 
 	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
-				OMAP2_MCSPI_WAKEUPENABLE_WKEN);
+			OMAP2_MCSPI_WAKEUPENABLE_WKEN);
 	ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
 
 	omap2_mcspi_set_master_mode(master);
@@ -1228,7 +1246,7 @@
 
 		sprintf(dma_ch_name, "rx%d", i);
 		dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-							dma_ch_name);
+				dma_ch_name);
 		if (!dma_res) {
 			dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
 			status = -ENODEV;
@@ -1238,7 +1256,7 @@
 		mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
 		sprintf(dma_ch_name, "tx%d", i);
 		dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-							dma_ch_name);
+				dma_ch_name);
 		if (!dma_res) {
 			dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
 			status = -ENODEV;
@@ -1254,7 +1272,7 @@
 	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
 	if (IS_ERR(pinctrl))
 		dev_warn(&pdev->dev,
-			"pins are not configured from the driver\n");
+				"pins are not configured from the driver\n");
 
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index b7e7182..66a5f82 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -366,7 +366,7 @@
 	return 0;
 }
 
-static int __init orion_spi_reset(struct orion_spi *orion_spi)
+static int orion_spi_reset(struct orion_spi *orion_spi)
 {
 	/* Verify that the CS is deasserted */
 	orion_spi_set_cs(orion_spi, 0);
@@ -396,7 +396,7 @@
 	return 0;
 }
 
-static int __init orion_spi_probe(struct platform_device *pdev)
+static int orion_spi_probe(struct platform_device *pdev)
 {
 	struct spi_master *master;
 	struct orion_spi *spi;
@@ -479,7 +479,7 @@
 }
 
 
-static int __exit orion_spi_remove(struct platform_device *pdev)
+static int orion_spi_remove(struct platform_device *pdev)
 {
 	struct spi_master *master;
 	struct resource *r;
@@ -513,20 +513,11 @@
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(orion_spi_of_match_table),
 	},
-	.remove		= __exit_p(orion_spi_remove),
+	.probe		= orion_spi_probe,
+	.remove		= orion_spi_remove,
 };
 
-static int __init orion_spi_init(void)
-{
-	return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
-}
-module_init(orion_spi_init);
-
-static void __exit orion_spi_exit(void)
-{
-	platform_driver_unregister(&orion_spi_driver);
-}
-module_exit(orion_spi_exit);
+module_platform_driver(orion_spi_driver);
 
 MODULE_DESCRIPTION("Orion SPI driver");
 MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 7a85f22..357f183 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -389,7 +389,7 @@
 /*
  * platform_device layer stuff...
  */
-static int __init spi_ppc4xx_of_probe(struct platform_device *op)
+static int spi_ppc4xx_of_probe(struct platform_device *op)
 {
 	struct ppc4xx_spi *hw;
 	struct spi_master *master;
@@ -419,7 +419,7 @@
 	 * This includes both "null" gpio's and real ones.
 	 */
 	num_gpios = of_gpio_count(np);
-	if (num_gpios) {
+	if (num_gpios > 0) {
 		int i;
 
 		hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
@@ -471,7 +471,7 @@
 		SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
 
 	/* this many pins in all GPIO controllers */
-	bbp->master->num_chipselect = num_gpios;
+	bbp->master->num_chipselect = num_gpios > 0 ? num_gpios : 0;
 
 	/* Get the clock for the OPB */
 	opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
@@ -560,7 +560,7 @@
 	return ret;
 }
 
-static int __exit spi_ppc4xx_of_remove(struct platform_device *op)
+static int spi_ppc4xx_of_remove(struct platform_device *op)
 {
 	struct spi_master *master = dev_get_drvdata(&op->dev);
 	struct ppc4xx_spi *hw = spi_master_get_devdata(master);
@@ -583,7 +583,7 @@
 
 static struct platform_driver spi_ppc4xx_of_driver = {
 	.probe = spi_ppc4xx_of_probe,
-	.remove = __exit_p(spi_ppc4xx_of_remove),
+	.remove = spi_ppc4xx_of_remove,
 	.driver = {
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
new file mode 100644
index 0000000..c735c5a
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -0,0 +1,392 @@
+/*
+ * PXA2xx SPI DMA engine support.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.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.
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+#include "spi-pxa2xx.h"
+
+static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
+				     enum dma_data_direction dir)
+{
+	int i, nents, len = drv_data->len;
+	struct scatterlist *sg;
+	struct device *dmadev;
+	struct sg_table *sgt;
+	void *buf, *pbuf;
+
+	/*
+	 * Some DMA controllers have problems transferring buffers that are
+	 * not multiple of 4 bytes. So we truncate the transfer so that it
+	 * is suitable for such controllers, and handle the trailing bytes
+	 * manually after the DMA completes.
+	 *
+	 * REVISIT: It would be better if this information could be
+	 * retrieved directly from the DMA device in a similar way than
+	 * ->copy_align etc. is done.
+	 */
+	len = ALIGN(drv_data->len, 4);
+
+	if (dir == DMA_TO_DEVICE) {
+		dmadev = drv_data->tx_chan->device->dev;
+		sgt = &drv_data->tx_sgt;
+		buf = drv_data->tx;
+		drv_data->tx_map_len = len;
+	} else {
+		dmadev = drv_data->rx_chan->device->dev;
+		sgt = &drv_data->rx_sgt;
+		buf = drv_data->rx;
+		drv_data->rx_map_len = len;
+	}
+
+	nents = DIV_ROUND_UP(len, SZ_2K);
+	if (nents != sgt->nents) {
+		int ret;
+
+		sg_free_table(sgt);
+		ret = sg_alloc_table(sgt, nents, GFP_KERNEL);
+		if (ret)
+			return ret;
+	}
+
+	pbuf = buf;
+	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+		size_t bytes = min_t(size_t, len, SZ_2K);
+
+		if (buf)
+			sg_set_buf(sg, pbuf, bytes);
+		else
+			sg_set_buf(sg, drv_data->dummy, bytes);
+
+		pbuf += bytes;
+		len -= bytes;
+	}
+
+	nents = dma_map_sg(dmadev, sgt->sgl, sgt->nents, dir);
+	if (!nents)
+		return -ENOMEM;
+
+	return nents;
+}
+
+static void pxa2xx_spi_unmap_dma_buffer(struct driver_data *drv_data,
+					enum dma_data_direction dir)
+{
+	struct device *dmadev;
+	struct sg_table *sgt;
+
+	if (dir == DMA_TO_DEVICE) {
+		dmadev = drv_data->tx_chan->device->dev;
+		sgt = &drv_data->tx_sgt;
+	} else {
+		dmadev = drv_data->rx_chan->device->dev;
+		sgt = &drv_data->rx_sgt;
+	}
+
+	dma_unmap_sg(dmadev, sgt->sgl, sgt->nents, dir);
+}
+
+static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
+{
+	if (!drv_data->dma_mapped)
+		return;
+
+	pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_FROM_DEVICE);
+	pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
+
+	drv_data->dma_mapped = 0;
+}
+
+static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
+					     bool error)
+{
+	struct spi_message *msg = drv_data->cur_msg;
+
+	/*
+	 * It is possible that one CPU is handling ROR interrupt and other
+	 * just gets DMA completion. Calling pump_transfers() twice for the
+	 * same transfer leads to problems thus we prevent concurrent calls
+	 * by using ->dma_running.
+	 */
+	if (atomic_dec_and_test(&drv_data->dma_running)) {
+		void __iomem *reg = drv_data->ioaddr;
+
+		/*
+		 * If the other CPU is still handling the ROR interrupt we
+		 * might not know about the error yet. So we re-check the
+		 * ROR bit here before we clear the status register.
+		 */
+		if (!error) {
+			u32 status = read_SSSR(reg) & drv_data->mask_sr;
+			error = status & SSSR_ROR;
+		}
+
+		/* Clear status & disable interrupts */
+		write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+		write_SSSR_CS(drv_data, drv_data->clear_sr);
+		if (!pxa25x_ssp_comp(drv_data))
+			write_SSTO(0, reg);
+
+		if (!error) {
+			pxa2xx_spi_unmap_dma_buffers(drv_data);
+
+			/* Handle the last bytes of unaligned transfer */
+			drv_data->tx += drv_data->tx_map_len;
+			drv_data->write(drv_data);
+
+			drv_data->rx += drv_data->rx_map_len;
+			drv_data->read(drv_data);
+
+			msg->actual_length += drv_data->len;
+			msg->state = pxa2xx_spi_next_transfer(drv_data);
+		} else {
+			/* In case we got an error we disable the SSP now */
+			write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+
+			msg->state = ERROR_STATE;
+		}
+
+		tasklet_schedule(&drv_data->pump_transfers);
+	}
+}
+
+static void pxa2xx_spi_dma_callback(void *data)
+{
+	pxa2xx_spi_dma_transfer_complete(data, false);
+}
+
+static struct dma_async_tx_descriptor *
+pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
+			   enum dma_transfer_direction dir)
+{
+	struct pxa2xx_spi_master *pdata = drv_data->master_info;
+	struct chip_data *chip = drv_data->cur_chip;
+	enum dma_slave_buswidth width;
+	struct dma_slave_config cfg;
+	struct dma_chan *chan;
+	struct sg_table *sgt;
+	int nents, ret;
+
+	switch (drv_data->n_bytes) {
+	case 1:
+		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		break;
+	case 2:
+		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	default:
+		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	}
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.direction = dir;
+
+	if (dir == DMA_MEM_TO_DEV) {
+		cfg.dst_addr = drv_data->ssdr_physical;
+		cfg.dst_addr_width = width;
+		cfg.dst_maxburst = chip->dma_burst_size;
+		cfg.slave_id = pdata->tx_slave_id;
+
+		sgt = &drv_data->tx_sgt;
+		nents = drv_data->tx_nents;
+		chan = drv_data->tx_chan;
+	} else {
+		cfg.src_addr = drv_data->ssdr_physical;
+		cfg.src_addr_width = width;
+		cfg.src_maxburst = chip->dma_burst_size;
+		cfg.slave_id = pdata->rx_slave_id;
+
+		sgt = &drv_data->rx_sgt;
+		nents = drv_data->rx_nents;
+		chan = drv_data->rx_chan;
+	}
+
+	ret = dmaengine_slave_config(chan, &cfg);
+	if (ret) {
+		dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n");
+		return NULL;
+	}
+
+	return dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir,
+				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+}
+
+static bool pxa2xx_spi_dma_filter(struct dma_chan *chan, void *param)
+{
+	const struct pxa2xx_spi_master *pdata = param;
+
+	return chan->chan_id == pdata->tx_chan_id ||
+	       chan->chan_id == pdata->rx_chan_id;
+}
+
+bool pxa2xx_spi_dma_is_possible(size_t len)
+{
+	return len <= MAX_DMA_LEN;
+}
+
+int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
+{
+	const struct chip_data *chip = drv_data->cur_chip;
+	int ret;
+
+	if (!chip->enable_dma)
+		return 0;
+
+	/* Don't bother with DMA if we can't do even a single burst */
+	if (drv_data->len < chip->dma_burst_size)
+		return 0;
+
+	ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_TO_DEVICE);
+	if (ret <= 0) {
+		dev_warn(&drv_data->pdev->dev, "failed to DMA map TX\n");
+		return 0;
+	}
+
+	drv_data->tx_nents = ret;
+
+	ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_FROM_DEVICE);
+	if (ret <= 0) {
+		pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
+		dev_warn(&drv_data->pdev->dev, "failed to DMA map RX\n");
+		return 0;
+	}
+
+	drv_data->rx_nents = ret;
+	return 1;
+}
+
+irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
+{
+	u32 status;
+
+	status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr;
+	if (status & SSSR_ROR) {
+		dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
+
+		dmaengine_terminate_all(drv_data->rx_chan);
+		dmaengine_terminate_all(drv_data->tx_chan);
+
+		pxa2xx_spi_dma_transfer_complete(drv_data, true);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
+{
+	struct dma_async_tx_descriptor *tx_desc, *rx_desc;
+
+	tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV);
+	if (!tx_desc) {
+		dev_err(&drv_data->pdev->dev,
+			"failed to get DMA TX descriptor\n");
+		return -EBUSY;
+	}
+
+	rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM);
+	if (!rx_desc) {
+		dev_err(&drv_data->pdev->dev,
+			"failed to get DMA RX descriptor\n");
+		return -EBUSY;
+	}
+
+	/* We are ready when RX completes */
+	rx_desc->callback = pxa2xx_spi_dma_callback;
+	rx_desc->callback_param = drv_data;
+
+	dmaengine_submit(rx_desc);
+	dmaengine_submit(tx_desc);
+	return 0;
+}
+
+void pxa2xx_spi_dma_start(struct driver_data *drv_data)
+{
+	dma_async_issue_pending(drv_data->rx_chan);
+	dma_async_issue_pending(drv_data->tx_chan);
+
+	atomic_set(&drv_data->dma_running, 1);
+}
+
+int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
+{
+	struct pxa2xx_spi_master *pdata = drv_data->master_info;
+	dma_cap_mask_t mask;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	drv_data->dummy = devm_kzalloc(&drv_data->pdev->dev, SZ_2K, GFP_KERNEL);
+	if (!drv_data->dummy)
+		return -ENOMEM;
+
+	drv_data->tx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
+						pdata);
+	if (!drv_data->tx_chan)
+		return -ENODEV;
+
+	drv_data->rx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
+						pdata);
+	if (!drv_data->rx_chan) {
+		dma_release_channel(drv_data->tx_chan);
+		drv_data->tx_chan = NULL;
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+void pxa2xx_spi_dma_release(struct driver_data *drv_data)
+{
+	if (drv_data->rx_chan) {
+		dmaengine_terminate_all(drv_data->rx_chan);
+		dma_release_channel(drv_data->rx_chan);
+		sg_free_table(&drv_data->rx_sgt);
+		drv_data->rx_chan = NULL;
+	}
+	if (drv_data->tx_chan) {
+		dmaengine_terminate_all(drv_data->tx_chan);
+		dma_release_channel(drv_data->tx_chan);
+		sg_free_table(&drv_data->tx_sgt);
+		drv_data->tx_chan = NULL;
+	}
+}
+
+void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
+{
+}
+
+int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+					   struct spi_device *spi,
+					   u8 bits_per_word, u32 *burst_code,
+					   u32 *threshold)
+{
+	struct pxa2xx_spi_chip *chip_info = spi->controller_data;
+
+	/*
+	 * If the DMA burst size is given in chip_info we use that,
+	 * otherwise we use the default. Also we use the default FIFO
+	 * thresholds for now.
+	 */
+	*burst_code = chip_info ? chip_info->dma_burst_size : 16;
+	*threshold = SSCR1_RxTresh(RX_THRESH_DFLT)
+		   | SSCR1_TxTresh(TX_THRESH_DFLT);
+
+	return 0;
+}
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index cf95587..364964d 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -8,147 +8,58 @@
 #include <linux/module.h>
 #include <linux/spi/pxa2xx_spi.h>
 
-struct ce4100_info {
-	struct ssp_device ssp;
-	struct platform_device *spi_pdev;
-};
-
-static DEFINE_MUTEX(ssp_lock);
-static LIST_HEAD(ssp_list);
-
-struct ssp_device *pxa_ssp_request(int port, const char *label)
-{
-	struct ssp_device *ssp = NULL;
-
-	mutex_lock(&ssp_lock);
-
-	list_for_each_entry(ssp, &ssp_list, node) {
-		if (ssp->port_id == port && ssp->use_count == 0) {
-			ssp->use_count++;
-			ssp->label = label;
-			break;
-		}
-	}
-
-	mutex_unlock(&ssp_lock);
-
-	if (&ssp->node == &ssp_list)
-		return NULL;
-
-	return ssp;
-}
-EXPORT_SYMBOL_GPL(pxa_ssp_request);
-
-void pxa_ssp_free(struct ssp_device *ssp)
-{
-	mutex_lock(&ssp_lock);
-	if (ssp->use_count) {
-		ssp->use_count--;
-		ssp->label = NULL;
-	} else
-		dev_err(&ssp->pdev->dev, "device already free\n");
-	mutex_unlock(&ssp_lock);
-}
-EXPORT_SYMBOL_GPL(pxa_ssp_free);
-
 static int ce4100_spi_probe(struct pci_dev *dev,
 		const struct pci_device_id *ent)
 {
+	struct platform_device_info pi;
 	int ret;
-	resource_size_t phys_beg;
-	resource_size_t phys_len;
-	struct ce4100_info *spi_info;
 	struct platform_device *pdev;
 	struct pxa2xx_spi_master spi_pdata;
 	struct ssp_device *ssp;
 
-	ret = pci_enable_device(dev);
+	ret = pcim_enable_device(dev);
 	if (ret)
 		return ret;
 
-	phys_beg = pci_resource_start(dev, 0);
-	phys_len = pci_resource_len(dev, 0);
-
-	if (!request_mem_region(phys_beg, phys_len,
-				"CE4100 SPI")) {
-		dev_err(&dev->dev, "Can't request register space.\n");
-		ret = -EBUSY;
+	ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
+	if (!ret)
 		return ret;
-	}
 
-	pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
-	spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
-	if (!pdev || !spi_info ) {
-		ret = -ENOMEM;
-		goto err_nomem;
-	}
 	memset(&spi_pdata, 0, sizeof(spi_pdata));
 	spi_pdata.num_chipselect = dev->devfn;
 
-	ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
-	if (ret)
-		goto err_nomem;
-
-	pdev->dev.parent = &dev->dev;
-	pdev->dev.of_node = dev->dev.of_node;
-	ssp = &spi_info->ssp;
+	ssp = &spi_pdata.ssp;
 	ssp->phys_base = pci_resource_start(dev, 0);
-	ssp->mmio_base = ioremap(phys_beg, phys_len);
+	ssp->mmio_base = pcim_iomap_table(dev)[0];
 	if (!ssp->mmio_base) {
-		dev_err(&pdev->dev, "failed to ioremap() registers\n");
-		ret = -EIO;
-		goto err_nomem;
+		dev_err(&dev->dev, "failed to ioremap() registers\n");
+		return -EIO;
 	}
 	ssp->irq = dev->irq;
-	ssp->port_id = pdev->id;
+	ssp->port_id = dev->devfn;
 	ssp->type = PXA25x_SSP;
 
-	mutex_lock(&ssp_lock);
-	list_add(&ssp->node, &ssp_list);
-	mutex_unlock(&ssp_lock);
+	memset(&pi, 0, sizeof(pi));
+	pi.parent = &dev->dev;
+	pi.name = "pxa2xx-spi";
+	pi.id = ssp->port_id;
+	pi.data = &spi_pdata;
+	pi.size_data = sizeof(spi_pdata);
 
-	pci_set_drvdata(dev, spi_info);
+	pdev = platform_device_register_full(&pi);
+	if (!pdev)
+		return -ENOMEM;
 
-	ret = platform_device_add(pdev);
-	if (ret)
-		goto err_dev_add;
+	pci_set_drvdata(dev, pdev);
 
-	return ret;
-
-err_dev_add:
-	pci_set_drvdata(dev, NULL);
-	mutex_lock(&ssp_lock);
-	list_del(&ssp->node);
-	mutex_unlock(&ssp_lock);
-	iounmap(ssp->mmio_base);
-
-err_nomem:
-	release_mem_region(phys_beg, phys_len);
-	platform_device_put(pdev);
-	kfree(spi_info);
-	return ret;
+	return 0;
 }
 
 static void ce4100_spi_remove(struct pci_dev *dev)
 {
-	struct ce4100_info *spi_info;
-	struct ssp_device *ssp;
+	struct platform_device *pdev = pci_get_drvdata(dev);
 
-	spi_info = pci_get_drvdata(dev);
-	ssp = &spi_info->ssp;
-	platform_device_unregister(spi_info->spi_pdev);
-
-	iounmap(ssp->mmio_base);
-	release_mem_region(pci_resource_start(dev, 0),
-			pci_resource_len(dev, 0));
-
-	mutex_lock(&ssp_lock);
-	list_del(&ssp->node);
-	mutex_unlock(&ssp_lock);
-
-	pci_set_drvdata(dev, NULL);
-	pci_disable_device(dev);
-	kfree(spi_info);
+	platform_device_unregister(pdev);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = {
diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c
new file mode 100644
index 0000000..2916efc
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx-pxadma.c
@@ -0,0 +1,490 @@
+/*
+ * PXA2xx SPI private DMA support.
+ *
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+#include "spi-pxa2xx.h"
+
+#define DMA_INT_MASK		(DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL	(DCSR_NODESC | DMA_INT_MASK)
+
+bool pxa2xx_spi_dma_is_possible(size_t len)
+{
+	/* Try to map dma buffer and do a dma transfer if successful, but
+	 * only if the length is non-zero and less than MAX_DMA_LEN.
+	 *
+	 * Zero-length non-descriptor DMA is illegal on PXA2xx; force use
+	 * of PIO instead.  Care is needed above because the transfer may
+	 * have have been passed with buffers that are already dma mapped.
+	 * A zero-length transfer in PIO mode will not try to write/read
+	 * to/from the buffers
+	 *
+	 * REVISIT large transfers are exactly where we most want to be
+	 * using DMA.  If this happens much, split those transfers into
+	 * multiple DMA segments rather than forcing PIO.
+	 */
+	return len > 0 && len <= MAX_DMA_LEN;
+}
+
+int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
+{
+	struct spi_message *msg = drv_data->cur_msg;
+	struct device *dev = &msg->spi->dev;
+
+	if (!drv_data->cur_chip->enable_dma)
+		return 0;
+
+	if (msg->is_dma_mapped)
+		return  drv_data->rx_dma && drv_data->tx_dma;
+
+	if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
+		return 0;
+
+	/* Modify setup if rx buffer is null */
+	if (drv_data->rx == NULL) {
+		*drv_data->null_dma_buf = 0;
+		drv_data->rx = drv_data->null_dma_buf;
+		drv_data->rx_map_len = 4;
+	} else
+		drv_data->rx_map_len = drv_data->len;
+
+
+	/* Modify setup if tx buffer is null */
+	if (drv_data->tx == NULL) {
+		*drv_data->null_dma_buf = 0;
+		drv_data->tx = drv_data->null_dma_buf;
+		drv_data->tx_map_len = 4;
+	} else
+		drv_data->tx_map_len = drv_data->len;
+
+	/* Stream map the tx buffer. Always do DMA_TO_DEVICE first
+	 * so we flush the cache *before* invalidating it, in case
+	 * the tx and rx buffers overlap.
+	 */
+	drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
+					drv_data->tx_map_len, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, drv_data->tx_dma))
+		return 0;
+
+	/* Stream map the rx buffer */
+	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
+					drv_data->rx_map_len, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, drv_data->rx_dma)) {
+		dma_unmap_single(dev, drv_data->tx_dma,
+					drv_data->tx_map_len, DMA_TO_DEVICE);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
+{
+	struct device *dev;
+
+	if (!drv_data->dma_mapped)
+		return;
+
+	if (!drv_data->cur_msg->is_dma_mapped) {
+		dev = &drv_data->cur_msg->spi->dev;
+		dma_unmap_single(dev, drv_data->rx_dma,
+					drv_data->rx_map_len, DMA_FROM_DEVICE);
+		dma_unmap_single(dev, drv_data->tx_dma,
+					drv_data->tx_map_len, DMA_TO_DEVICE);
+	}
+
+	drv_data->dma_mapped = 0;
+}
+
+static int wait_ssp_rx_stall(void const __iomem *ioaddr)
+{
+	unsigned long limit = loops_per_jiffy << 1;
+
+	while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
+		cpu_relax();
+
+	return limit;
+}
+
+static int wait_dma_channel_stop(int channel)
+{
+	unsigned long limit = loops_per_jiffy << 1;
+
+	while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit)
+		cpu_relax();
+
+	return limit;
+}
+
+static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
+				      const char *msg)
+{
+	void __iomem *reg = drv_data->ioaddr;
+
+	/* Stop and reset */
+	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+	write_SSSR_CS(drv_data, drv_data->clear_sr);
+	write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+	if (!pxa25x_ssp_comp(drv_data))
+		write_SSTO(0, reg);
+	pxa2xx_spi_flush(drv_data);
+	write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+
+	pxa2xx_spi_unmap_dma_buffers(drv_data);
+
+	dev_err(&drv_data->pdev->dev, "%s\n", msg);
+
+	drv_data->cur_msg->state = ERROR_STATE;
+	tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
+{
+	void __iomem *reg = drv_data->ioaddr;
+	struct spi_message *msg = drv_data->cur_msg;
+
+	/* Clear and disable interrupts on SSP and DMA channels*/
+	write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+	write_SSSR_CS(drv_data, drv_data->clear_sr);
+	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+
+	if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
+		dev_err(&drv_data->pdev->dev,
+			"dma_handler: dma rx channel stop failed\n");
+
+	if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+		dev_err(&drv_data->pdev->dev,
+			"dma_transfer: ssp rx stall failed\n");
+
+	pxa2xx_spi_unmap_dma_buffers(drv_data);
+
+	/* update the buffer pointer for the amount completed in dma */
+	drv_data->rx += drv_data->len -
+			(DCMD(drv_data->rx_channel) & DCMD_LENGTH);
+
+	/* read trailing data from fifo, it does not matter how many
+	 * bytes are in the fifo just read until buffer is full
+	 * or fifo is empty, which ever occurs first */
+	drv_data->read(drv_data);
+
+	/* return count of what was actually read */
+	msg->actual_length += drv_data->len -
+				(drv_data->rx_end - drv_data->rx);
+
+	/* Transfer delays and chip select release are
+	 * handled in pump_transfers or giveback
+	 */
+
+	/* Move to next transfer */
+	msg->state = pxa2xx_spi_next_transfer(drv_data);
+
+	/* Schedule transfer tasklet */
+	tasklet_schedule(&drv_data->pump_transfers);
+}
+
+void pxa2xx_spi_dma_handler(int channel, void *data)
+{
+	struct driver_data *drv_data = data;
+	u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+	if (irq_status & DCSR_BUSERR) {
+
+		if (channel == drv_data->tx_channel)
+			pxa2xx_spi_dma_error_stop(drv_data,
+				"dma_handler: bad bus address on tx channel");
+		else
+			pxa2xx_spi_dma_error_stop(drv_data,
+				"dma_handler: bad bus address on rx channel");
+		return;
+	}
+
+	/* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
+	if ((channel == drv_data->tx_channel)
+		&& (irq_status & DCSR_ENDINTR)
+		&& (drv_data->ssp_type == PXA25x_SSP)) {
+
+		/* Wait for rx to stall */
+		if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+			dev_err(&drv_data->pdev->dev,
+				"dma_handler: ssp rx stall failed\n");
+
+		/* finish this transfer, start the next */
+		pxa2xx_spi_dma_transfer_complete(drv_data);
+	}
+}
+
+irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
+{
+	u32 irq_status;
+	void __iomem *reg = drv_data->ioaddr;
+
+	irq_status = read_SSSR(reg) & drv_data->mask_sr;
+	if (irq_status & SSSR_ROR) {
+		pxa2xx_spi_dma_error_stop(drv_data,
+					  "dma_transfer: fifo overrun");
+		return IRQ_HANDLED;
+	}
+
+	/* Check for false positive timeout */
+	if ((irq_status & SSSR_TINT)
+		&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
+		write_SSSR(SSSR_TINT, reg);
+		return IRQ_HANDLED;
+	}
+
+	if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
+
+		/* Clear and disable timeout interrupt, do the rest in
+		 * dma_transfer_complete */
+		if (!pxa25x_ssp_comp(drv_data))
+			write_SSTO(0, reg);
+
+		/* finish this transfer, start the next */
+		pxa2xx_spi_dma_transfer_complete(drv_data);
+
+		return IRQ_HANDLED;
+	}
+
+	/* Opps problem detected */
+	return IRQ_NONE;
+}
+
+int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
+{
+	u32 dma_width;
+
+	switch (drv_data->n_bytes) {
+	case 1:
+		dma_width = DCMD_WIDTH1;
+		break;
+	case 2:
+		dma_width = DCMD_WIDTH2;
+		break;
+	default:
+		dma_width = DCMD_WIDTH4;
+		break;
+	}
+
+	/* Setup rx DMA Channel */
+	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+	DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
+	DTADR(drv_data->rx_channel) = drv_data->rx_dma;
+	if (drv_data->rx == drv_data->null_dma_buf)
+		/* No target address increment */
+		DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
+						| dma_width
+						| dma_burst
+						| drv_data->len;
+	else
+		DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
+						| DCMD_FLOWSRC
+						| dma_width
+						| dma_burst
+						| drv_data->len;
+
+	/* Setup tx DMA Channel */
+	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+	DSADR(drv_data->tx_channel) = drv_data->tx_dma;
+	DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
+	if (drv_data->tx == drv_data->null_dma_buf)
+		/* No source address increment */
+		DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
+						| dma_width
+						| dma_burst
+						| drv_data->len;
+	else
+		DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
+						| DCMD_FLOWTRG
+						| dma_width
+						| dma_burst
+						| drv_data->len;
+
+	/* Enable dma end irqs on SSP to detect end of transfer */
+	if (drv_data->ssp_type == PXA25x_SSP)
+		DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
+
+	return 0;
+}
+
+void pxa2xx_spi_dma_start(struct driver_data *drv_data)
+{
+	DCSR(drv_data->rx_channel) |= DCSR_RUN;
+	DCSR(drv_data->tx_channel) |= DCSR_RUN;
+}
+
+int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
+{
+	struct device *dev = &drv_data->pdev->dev;
+	struct ssp_device *ssp = drv_data->ssp;
+
+	/* Get two DMA channels	(rx and tx) */
+	drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
+						DMA_PRIO_HIGH,
+						pxa2xx_spi_dma_handler,
+						drv_data);
+	if (drv_data->rx_channel < 0) {
+		dev_err(dev, "problem (%d) requesting rx channel\n",
+			drv_data->rx_channel);
+		return -ENODEV;
+	}
+	drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
+						DMA_PRIO_MEDIUM,
+						pxa2xx_spi_dma_handler,
+						drv_data);
+	if (drv_data->tx_channel < 0) {
+		dev_err(dev, "problem (%d) requesting tx channel\n",
+			drv_data->tx_channel);
+		pxa_free_dma(drv_data->rx_channel);
+		return -ENODEV;
+	}
+
+	DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
+	DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
+
+	return 0;
+}
+
+void pxa2xx_spi_dma_release(struct driver_data *drv_data)
+{
+	struct ssp_device *ssp = drv_data->ssp;
+
+	DRCMR(ssp->drcmr_rx) = 0;
+	DRCMR(ssp->drcmr_tx) = 0;
+
+	if (drv_data->tx_channel != 0)
+		pxa_free_dma(drv_data->tx_channel);
+	if (drv_data->rx_channel != 0)
+		pxa_free_dma(drv_data->rx_channel);
+}
+
+void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
+{
+	if (drv_data->rx_channel != -1)
+		DRCMR(drv_data->ssp->drcmr_rx) =
+			DRCMR_MAPVLD | drv_data->rx_channel;
+	if (drv_data->tx_channel != -1)
+		DRCMR(drv_data->ssp->drcmr_tx) =
+			DRCMR_MAPVLD | drv_data->tx_channel;
+}
+
+int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+					   struct spi_device *spi,
+					   u8 bits_per_word, u32 *burst_code,
+					   u32 *threshold)
+{
+	struct pxa2xx_spi_chip *chip_info =
+			(struct pxa2xx_spi_chip *)spi->controller_data;
+	int bytes_per_word;
+	int burst_bytes;
+	int thresh_words;
+	int req_burst_size;
+	int retval = 0;
+
+	/* Set the threshold (in registers) to equal the same amount of data
+	 * as represented by burst size (in bytes).  The computation below
+	 * is (burst_size rounded up to nearest 8 byte, word or long word)
+	 * divided by (bytes/register); the tx threshold is the inverse of
+	 * the rx, so that there will always be enough data in the rx fifo
+	 * to satisfy a burst, and there will always be enough space in the
+	 * tx fifo to accept a burst (a tx burst will overwrite the fifo if
+	 * there is not enough space), there must always remain enough empty
+	 * space in the rx fifo for any data loaded to the tx fifo.
+	 * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
+	 * will be 8, or half the fifo;
+	 * The threshold can only be set to 2, 4 or 8, but not 16, because
+	 * to burst 16 to the tx fifo, the fifo would have to be empty;
+	 * however, the minimum fifo trigger level is 1, and the tx will
+	 * request service when the fifo is at this level, with only 15 spaces.
+	 */
+
+	/* find bytes/word */
+	if (bits_per_word <= 8)
+		bytes_per_word = 1;
+	else if (bits_per_word <= 16)
+		bytes_per_word = 2;
+	else
+		bytes_per_word = 4;
+
+	/* use struct pxa2xx_spi_chip->dma_burst_size if available */
+	if (chip_info)
+		req_burst_size = chip_info->dma_burst_size;
+	else {
+		switch (chip->dma_burst_size) {
+		default:
+			/* if the default burst size is not set,
+			 * do it now */
+			chip->dma_burst_size = DCMD_BURST8;
+		case DCMD_BURST8:
+			req_burst_size = 8;
+			break;
+		case DCMD_BURST16:
+			req_burst_size = 16;
+			break;
+		case DCMD_BURST32:
+			req_burst_size = 32;
+			break;
+		}
+	}
+	if (req_burst_size <= 8) {
+		*burst_code = DCMD_BURST8;
+		burst_bytes = 8;
+	} else if (req_burst_size <= 16) {
+		if (bytes_per_word == 1) {
+			/* don't burst more than 1/2 the fifo */
+			*burst_code = DCMD_BURST8;
+			burst_bytes = 8;
+			retval = 1;
+		} else {
+			*burst_code = DCMD_BURST16;
+			burst_bytes = 16;
+		}
+	} else {
+		if (bytes_per_word == 1) {
+			/* don't burst more than 1/2 the fifo */
+			*burst_code = DCMD_BURST8;
+			burst_bytes = 8;
+			retval = 1;
+		} else if (bytes_per_word == 2) {
+			/* don't burst more than 1/2 the fifo */
+			*burst_code = DCMD_BURST16;
+			burst_bytes = 16;
+			retval = 1;
+		} else {
+			*burst_code = DCMD_BURST32;
+			burst_bytes = 32;
+		}
+	}
+
+	thresh_words = burst_bytes / bytes_per_word;
+
+	/* thresh_words will be between 2 and 8 */
+	*threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
+			| (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
+
+	return retval;
+}
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 5c8c4f5..90b27a3 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ * Copyright (C) 2013, Intel Corporation
  *
  * 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
@@ -24,17 +25,20 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/spi/pxa2xx_spi.h>
-#include <linux/dma-mapping.h>
 #include <linux/spi/spi.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 
+#include "spi-pxa2xx.h"
 
 MODULE_AUTHOR("Stephen Street");
 MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
@@ -45,12 +49,6 @@
 
 #define TIMOUT_DFLT		1000
 
-#define DMA_INT_MASK		(DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
-#define RESET_DMA_CHANNEL	(DCSR_NODESC | DMA_INT_MASK)
-#define IS_DMA_ALIGNED(x)	((((u32)(x)) & 0x07) == 0)
-#define MAX_DMA_LEN		8191
-#define DMA_ALIGNMENT		8
-
 /*
  * for testing SSCR1 changes that require SSP restart, basically
  * everything except the service and interrupt enables, the pxa270 developer
@@ -65,115 +63,97 @@
 				| SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
 				| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
 
-#define DEFINE_SSP_REG(reg, off) \
-static inline u32 read_##reg(void const __iomem *p) \
-{ return __raw_readl(p + (off)); } \
-\
-static inline void write_##reg(u32 v, void __iomem *p) \
-{ __raw_writel(v, p + (off)); }
+#define LPSS_RX_THRESH_DFLT	64
+#define LPSS_TX_LOTHRESH_DFLT	160
+#define LPSS_TX_HITHRESH_DFLT	224
 
-DEFINE_SSP_REG(SSCR0, 0x00)
-DEFINE_SSP_REG(SSCR1, 0x04)
-DEFINE_SSP_REG(SSSR, 0x08)
-DEFINE_SSP_REG(SSITR, 0x0c)
-DEFINE_SSP_REG(SSDR, 0x10)
-DEFINE_SSP_REG(SSTO, 0x28)
-DEFINE_SSP_REG(SSPSP, 0x2c)
+/* Offset from drv_data->lpss_base */
+#define SPI_CS_CONTROL		0x18
+#define SPI_CS_CONTROL_SW_MODE	BIT(0)
+#define SPI_CS_CONTROL_CS_HIGH	BIT(1)
 
-#define START_STATE ((void*)0)
-#define RUNNING_STATE ((void*)1)
-#define DONE_STATE ((void*)2)
-#define ERROR_STATE ((void*)-1)
+static bool is_lpss_ssp(const struct driver_data *drv_data)
+{
+	return drv_data->ssp_type == LPSS_SSP;
+}
 
-#define QUEUE_RUNNING 0
-#define QUEUE_STOPPED 1
+/*
+ * Read and write LPSS SSP private registers. Caller must first check that
+ * is_lpss_ssp() returns true before these can be called.
+ */
+static u32 __lpss_ssp_read_priv(struct driver_data *drv_data, unsigned offset)
+{
+	WARN_ON(!drv_data->lpss_base);
+	return readl(drv_data->lpss_base + offset);
+}
 
-struct driver_data {
-	/* Driver model hookup */
-	struct platform_device *pdev;
+static void __lpss_ssp_write_priv(struct driver_data *drv_data,
+				  unsigned offset, u32 value)
+{
+	WARN_ON(!drv_data->lpss_base);
+	writel(value, drv_data->lpss_base + offset);
+}
 
-	/* SSP Info */
-	struct ssp_device *ssp;
+/*
+ * lpss_ssp_setup - perform LPSS SSP specific setup
+ * @drv_data: pointer to the driver private data
+ *
+ * Perform LPSS SSP specific setup. This function must be called first if
+ * one is going to use LPSS SSP private registers.
+ */
+static void lpss_ssp_setup(struct driver_data *drv_data)
+{
+	unsigned offset = 0x400;
+	u32 value, orig;
 
-	/* SPI framework hookup */
-	enum pxa_ssp_type ssp_type;
-	struct spi_master *master;
+	if (!is_lpss_ssp(drv_data))
+		return;
 
-	/* PXA hookup */
-	struct pxa2xx_spi_master *master_info;
+	/*
+	 * Perform auto-detection of the LPSS SSP private registers. They
+	 * can be either at 1k or 2k offset from the base address.
+	 */
+	orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
 
-	/* DMA setup stuff */
-	int rx_channel;
-	int tx_channel;
-	u32 *null_dma_buf;
+	value = orig | SPI_CS_CONTROL_SW_MODE;
+	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
+	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
+	if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
+		offset = 0x800;
+		goto detection_done;
+	}
 
-	/* SSP register addresses */
-	void __iomem *ioaddr;
-	u32 ssdr_physical;
+	value &= ~SPI_CS_CONTROL_SW_MODE;
+	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
+	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
+	if (value != orig) {
+		offset = 0x800;
+		goto detection_done;
+	}
 
-	/* SSP masks*/
-	u32 dma_cr1;
-	u32 int_cr1;
-	u32 clear_sr;
-	u32 mask_sr;
+detection_done:
+	/* Now set the LPSS base */
+	drv_data->lpss_base = drv_data->ioaddr + offset;
 
-	/* Driver message queue */
-	struct workqueue_struct	*workqueue;
-	struct work_struct pump_messages;
-	spinlock_t lock;
-	struct list_head queue;
-	int busy;
-	int run;
+	/* Enable software chip select control */
+	value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
+	__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+}
 
-	/* Message Transfer pump */
-	struct tasklet_struct pump_transfers;
+static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
+{
+	u32 value;
 
-	/* Current message transfer state info */
-	struct spi_message* cur_msg;
-	struct spi_transfer* cur_transfer;
-	struct chip_data *cur_chip;
-	size_t len;
-	void *tx;
-	void *tx_end;
-	void *rx;
-	void *rx_end;
-	int dma_mapped;
-	dma_addr_t rx_dma;
-	dma_addr_t tx_dma;
-	size_t rx_map_len;
-	size_t tx_map_len;
-	u8 n_bytes;
-	u32 dma_width;
-	int (*write)(struct driver_data *drv_data);
-	int (*read)(struct driver_data *drv_data);
-	irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
-	void (*cs_control)(u32 command);
-};
+	if (!is_lpss_ssp(drv_data))
+		return;
 
-struct chip_data {
-	u32 cr0;
-	u32 cr1;
-	u32 psp;
-	u32 timeout;
-	u8 n_bytes;
-	u32 dma_width;
-	u32 dma_burst_size;
-	u32 threshold;
-	u32 dma_threshold;
-	u8 enable_dma;
-	u8 bits_per_word;
-	u32 speed_hz;
-	union {
-		int gpio_cs;
-		unsigned int frm;
-	};
-	int gpio_cs_inverted;
-	int (*write)(struct driver_data *drv_data);
-	int (*read)(struct driver_data *drv_data);
-	void (*cs_control)(u32 command);
-};
-
-static void pump_messages(struct work_struct *work);
+	value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
+	if (enable)
+		value &= ~SPI_CS_CONTROL_CS_HIGH;
+	else
+		value |= SPI_CS_CONTROL_CS_HIGH;
+	__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+}
 
 static void cs_assert(struct driver_data *drv_data)
 {
@@ -189,8 +169,12 @@
 		return;
 	}
 
-	if (gpio_is_valid(chip->gpio_cs))
+	if (gpio_is_valid(chip->gpio_cs)) {
 		gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted);
+		return;
+	}
+
+	lpss_ssp_cs_control(drv_data, true);
 }
 
 static void cs_deassert(struct driver_data *drv_data)
@@ -205,30 +189,15 @@
 		return;
 	}
 
-	if (gpio_is_valid(chip->gpio_cs))
+	if (gpio_is_valid(chip->gpio_cs)) {
 		gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
+		return;
+	}
+
+	lpss_ssp_cs_control(drv_data, false);
 }
 
-static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
-{
-	void __iomem *reg = drv_data->ioaddr;
-
-	if (drv_data->ssp_type == CE4100_SSP)
-		val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
-
-	write_SSSR(val, reg);
-}
-
-static int pxa25x_ssp_comp(struct driver_data *drv_data)
-{
-	if (drv_data->ssp_type == PXA25x_SSP)
-		return 1;
-	if (drv_data->ssp_type == CE4100_SSP)
-		return 1;
-	return 0;
-}
-
-static int flush(struct driver_data *drv_data)
+int pxa2xx_spi_flush(struct driver_data *drv_data)
 {
 	unsigned long limit = loops_per_jiffy << 1;
 
@@ -354,7 +323,7 @@
 	return drv_data->rx == drv_data->rx_end;
 }
 
-static void *next_transfer(struct driver_data *drv_data)
+void *pxa2xx_spi_next_transfer(struct driver_data *drv_data)
 {
 	struct spi_message *msg = drv_data->cur_msg;
 	struct spi_transfer *trans = drv_data->cur_transfer;
@@ -370,89 +339,15 @@
 		return DONE_STATE;
 }
 
-static int map_dma_buffers(struct driver_data *drv_data)
-{
-	struct spi_message *msg = drv_data->cur_msg;
-	struct device *dev = &msg->spi->dev;
-
-	if (!drv_data->cur_chip->enable_dma)
-		return 0;
-
-	if (msg->is_dma_mapped)
-		return  drv_data->rx_dma && drv_data->tx_dma;
-
-	if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
-		return 0;
-
-	/* Modify setup if rx buffer is null */
-	if (drv_data->rx == NULL) {
-		*drv_data->null_dma_buf = 0;
-		drv_data->rx = drv_data->null_dma_buf;
-		drv_data->rx_map_len = 4;
-	} else
-		drv_data->rx_map_len = drv_data->len;
-
-
-	/* Modify setup if tx buffer is null */
-	if (drv_data->tx == NULL) {
-		*drv_data->null_dma_buf = 0;
-		drv_data->tx = drv_data->null_dma_buf;
-		drv_data->tx_map_len = 4;
-	} else
-		drv_data->tx_map_len = drv_data->len;
-
-	/* Stream map the tx buffer. Always do DMA_TO_DEVICE first
-	 * so we flush the cache *before* invalidating it, in case
-	 * the tx and rx buffers overlap.
-	 */
-	drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
-					drv_data->tx_map_len, DMA_TO_DEVICE);
-	if (dma_mapping_error(dev, drv_data->tx_dma))
-		return 0;
-
-	/* Stream map the rx buffer */
-	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
-					drv_data->rx_map_len, DMA_FROM_DEVICE);
-	if (dma_mapping_error(dev, drv_data->rx_dma)) {
-		dma_unmap_single(dev, drv_data->tx_dma,
-					drv_data->tx_map_len, DMA_TO_DEVICE);
-		return 0;
-	}
-
-	return 1;
-}
-
-static void unmap_dma_buffers(struct driver_data *drv_data)
-{
-	struct device *dev;
-
-	if (!drv_data->dma_mapped)
-		return;
-
-	if (!drv_data->cur_msg->is_dma_mapped) {
-		dev = &drv_data->cur_msg->spi->dev;
-		dma_unmap_single(dev, drv_data->rx_dma,
-					drv_data->rx_map_len, DMA_FROM_DEVICE);
-		dma_unmap_single(dev, drv_data->tx_dma,
-					drv_data->tx_map_len, DMA_TO_DEVICE);
-	}
-
-	drv_data->dma_mapped = 0;
-}
-
 /* caller already set message->status; dma and pio irqs are blocked */
 static void giveback(struct driver_data *drv_data)
 {
 	struct spi_transfer* last_transfer;
-	unsigned long flags;
 	struct spi_message *msg;
 
-	spin_lock_irqsave(&drv_data->lock, flags);
 	msg = drv_data->cur_msg;
 	drv_data->cur_msg = NULL;
 	drv_data->cur_transfer = NULL;
-	queue_work(drv_data->workqueue, &drv_data->pump_messages);
-	spin_unlock_irqrestore(&drv_data->lock, flags);
 
 	last_transfer = list_entry(msg->transfers.prev,
 					struct spi_transfer,
@@ -481,13 +376,7 @@
 		 */
 
 		/* get a pointer to the next message, if any */
-		spin_lock_irqsave(&drv_data->lock, flags);
-		if (list_empty(&drv_data->queue))
-			next_msg = NULL;
-		else
-			next_msg = list_entry(drv_data->queue.next,
-					struct spi_message, queue);
-		spin_unlock_irqrestore(&drv_data->lock, flags);
+		next_msg = spi_get_next_queued_message(drv_data->master);
 
 		/* see if the next and current messages point
 		 * to the same chip
@@ -498,168 +387,10 @@
 			cs_deassert(drv_data);
 	}
 
-	msg->state = NULL;
-	if (msg->complete)
-		msg->complete(msg->context);
-
+	spi_finalize_current_message(drv_data->master);
 	drv_data->cur_chip = NULL;
 }
 
-static int wait_ssp_rx_stall(void const __iomem *ioaddr)
-{
-	unsigned long limit = loops_per_jiffy << 1;
-
-	while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
-		cpu_relax();
-
-	return limit;
-}
-
-static int wait_dma_channel_stop(int channel)
-{
-	unsigned long limit = loops_per_jiffy << 1;
-
-	while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit)
-		cpu_relax();
-
-	return limit;
-}
-
-static void dma_error_stop(struct driver_data *drv_data, const char *msg)
-{
-	void __iomem *reg = drv_data->ioaddr;
-
-	/* Stop and reset */
-	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-	write_SSSR_CS(drv_data, drv_data->clear_sr);
-	write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-	if (!pxa25x_ssp_comp(drv_data))
-		write_SSTO(0, reg);
-	flush(drv_data);
-	write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-
-	unmap_dma_buffers(drv_data);
-
-	dev_err(&drv_data->pdev->dev, "%s\n", msg);
-
-	drv_data->cur_msg->state = ERROR_STATE;
-	tasklet_schedule(&drv_data->pump_transfers);
-}
-
-static void dma_transfer_complete(struct driver_data *drv_data)
-{
-	void __iomem *reg = drv_data->ioaddr;
-	struct spi_message *msg = drv_data->cur_msg;
-
-	/* Clear and disable interrupts on SSP and DMA channels*/
-	write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-	write_SSSR_CS(drv_data, drv_data->clear_sr);
-	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-
-	if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
-		dev_err(&drv_data->pdev->dev,
-			"dma_handler: dma rx channel stop failed\n");
-
-	if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
-		dev_err(&drv_data->pdev->dev,
-			"dma_transfer: ssp rx stall failed\n");
-
-	unmap_dma_buffers(drv_data);
-
-	/* update the buffer pointer for the amount completed in dma */
-	drv_data->rx += drv_data->len -
-			(DCMD(drv_data->rx_channel) & DCMD_LENGTH);
-
-	/* read trailing data from fifo, it does not matter how many
-	 * bytes are in the fifo just read until buffer is full
-	 * or fifo is empty, which ever occurs first */
-	drv_data->read(drv_data);
-
-	/* return count of what was actually read */
-	msg->actual_length += drv_data->len -
-				(drv_data->rx_end - drv_data->rx);
-
-	/* Transfer delays and chip select release are
-	 * handled in pump_transfers or giveback
-	 */
-
-	/* Move to next transfer */
-	msg->state = next_transfer(drv_data);
-
-	/* Schedule transfer tasklet */
-	tasklet_schedule(&drv_data->pump_transfers);
-}
-
-static void dma_handler(int channel, void *data)
-{
-	struct driver_data *drv_data = data;
-	u32 irq_status = DCSR(channel) & DMA_INT_MASK;
-
-	if (irq_status & DCSR_BUSERR) {
-
-		if (channel == drv_data->tx_channel)
-			dma_error_stop(drv_data,
-					"dma_handler: "
-					"bad bus address on tx channel");
-		else
-			dma_error_stop(drv_data,
-					"dma_handler: "
-					"bad bus address on rx channel");
-		return;
-	}
-
-	/* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
-	if ((channel == drv_data->tx_channel)
-		&& (irq_status & DCSR_ENDINTR)
-		&& (drv_data->ssp_type == PXA25x_SSP)) {
-
-		/* Wait for rx to stall */
-		if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
-			dev_err(&drv_data->pdev->dev,
-				"dma_handler: ssp rx stall failed\n");
-
-		/* finish this transfer, start the next */
-		dma_transfer_complete(drv_data);
-	}
-}
-
-static irqreturn_t dma_transfer(struct driver_data *drv_data)
-{
-	u32 irq_status;
-	void __iomem *reg = drv_data->ioaddr;
-
-	irq_status = read_SSSR(reg) & drv_data->mask_sr;
-	if (irq_status & SSSR_ROR) {
-		dma_error_stop(drv_data, "dma_transfer: fifo overrun");
-		return IRQ_HANDLED;
-	}
-
-	/* Check for false positive timeout */
-	if ((irq_status & SSSR_TINT)
-		&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
-		write_SSSR(SSSR_TINT, reg);
-		return IRQ_HANDLED;
-	}
-
-	if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
-
-		/* Clear and disable timeout interrupt, do the rest in
-		 * dma_transfer_complete */
-		if (!pxa25x_ssp_comp(drv_data))
-			write_SSTO(0, reg);
-
-		/* finish this transfer, start the next */
-		dma_transfer_complete(drv_data);
-
-		return IRQ_HANDLED;
-	}
-
-	/* Opps problem detected */
-	return IRQ_NONE;
-}
-
 static void reset_sccr1(struct driver_data *drv_data)
 {
 	void __iomem *reg = drv_data->ioaddr;
@@ -681,7 +412,7 @@
 	reset_sccr1(drv_data);
 	if (!pxa25x_ssp_comp(drv_data))
 		write_SSTO(0, reg);
-	flush(drv_data);
+	pxa2xx_spi_flush(drv_data);
 	write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 
 	dev_err(&drv_data->pdev->dev, "%s\n", msg);
@@ -709,7 +440,7 @@
 	 */
 
 	/* Move to next transfer */
-	drv_data->cur_msg->state = next_transfer(drv_data);
+	drv_data->cur_msg->state = pxa2xx_spi_next_transfer(drv_data);
 
 	/* Schedule transfer tasklet */
 	tasklet_schedule(&drv_data->pump_transfers);
@@ -789,10 +520,20 @@
 {
 	struct driver_data *drv_data = dev_id;
 	void __iomem *reg = drv_data->ioaddr;
-	u32 sccr1_reg = read_SSCR1(reg);
+	u32 sccr1_reg;
 	u32 mask = drv_data->mask_sr;
 	u32 status;
 
+	/*
+	 * The IRQ might be shared with other peripherals so we must first
+	 * check that are we RPM suspended or not. If we are we assume that
+	 * the IRQ was not for us (we shouldn't be RPM suspended when the
+	 * interrupt is enabled).
+	 */
+	if (pm_runtime_suspended(&drv_data->pdev->dev))
+		return IRQ_NONE;
+
+	sccr1_reg = read_SSCR1(reg);
 	status = read_SSSR(reg);
 
 	/* Ignore possible writes if we don't need to write */
@@ -820,106 +561,12 @@
 	return drv_data->transfer_handler(drv_data);
 }
 
-static int set_dma_burst_and_threshold(struct chip_data *chip,
-				struct spi_device *spi,
-				u8 bits_per_word, u32 *burst_code,
-				u32 *threshold)
+static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
 {
-	struct pxa2xx_spi_chip *chip_info =
-			(struct pxa2xx_spi_chip *)spi->controller_data;
-	int bytes_per_word;
-	int burst_bytes;
-	int thresh_words;
-	int req_burst_size;
-	int retval = 0;
+	unsigned long ssp_clk = drv_data->max_clk_rate;
+	const struct ssp_device *ssp = drv_data->ssp;
 
-	/* Set the threshold (in registers) to equal the same amount of data
-	 * as represented by burst size (in bytes).  The computation below
-	 * is (burst_size rounded up to nearest 8 byte, word or long word)
-	 * divided by (bytes/register); the tx threshold is the inverse of
-	 * the rx, so that there will always be enough data in the rx fifo
-	 * to satisfy a burst, and there will always be enough space in the
-	 * tx fifo to accept a burst (a tx burst will overwrite the fifo if
-	 * there is not enough space), there must always remain enough empty
-	 * space in the rx fifo for any data loaded to the tx fifo.
-	 * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
-	 * will be 8, or half the fifo;
-	 * The threshold can only be set to 2, 4 or 8, but not 16, because
-	 * to burst 16 to the tx fifo, the fifo would have to be empty;
-	 * however, the minimum fifo trigger level is 1, and the tx will
-	 * request service when the fifo is at this level, with only 15 spaces.
-	 */
-
-	/* find bytes/word */
-	if (bits_per_word <= 8)
-		bytes_per_word = 1;
-	else if (bits_per_word <= 16)
-		bytes_per_word = 2;
-	else
-		bytes_per_word = 4;
-
-	/* use struct pxa2xx_spi_chip->dma_burst_size if available */
-	if (chip_info)
-		req_burst_size = chip_info->dma_burst_size;
-	else {
-		switch (chip->dma_burst_size) {
-		default:
-			/* if the default burst size is not set,
-			 * do it now */
-			chip->dma_burst_size = DCMD_BURST8;
-		case DCMD_BURST8:
-			req_burst_size = 8;
-			break;
-		case DCMD_BURST16:
-			req_burst_size = 16;
-			break;
-		case DCMD_BURST32:
-			req_burst_size = 32;
-			break;
-		}
-	}
-	if (req_burst_size <= 8) {
-		*burst_code = DCMD_BURST8;
-		burst_bytes = 8;
-	} else if (req_burst_size <= 16) {
-		if (bytes_per_word == 1) {
-			/* don't burst more than 1/2 the fifo */
-			*burst_code = DCMD_BURST8;
-			burst_bytes = 8;
-			retval = 1;
-		} else {
-			*burst_code = DCMD_BURST16;
-			burst_bytes = 16;
-		}
-	} else {
-		if (bytes_per_word == 1) {
-			/* don't burst more than 1/2 the fifo */
-			*burst_code = DCMD_BURST8;
-			burst_bytes = 8;
-			retval = 1;
-		} else if (bytes_per_word == 2) {
-			/* don't burst more than 1/2 the fifo */
-			*burst_code = DCMD_BURST16;
-			burst_bytes = 16;
-			retval = 1;
-		} else {
-			*burst_code = DCMD_BURST32;
-			burst_bytes = 32;
-		}
-	}
-
-	thresh_words = burst_bytes / bytes_per_word;
-
-	/* thresh_words will be between 2 and 8 */
-	*threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
-			| (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
-
-	return retval;
-}
-
-static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
-{
-	unsigned long ssp_clk = clk_get_rate(ssp->clk);
+	rate = min_t(int, ssp_clk, rate);
 
 	if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
 		return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
@@ -934,7 +581,6 @@
 	struct spi_transfer *transfer = NULL;
 	struct spi_transfer *previous = NULL;
 	struct chip_data *chip = NULL;
-	struct ssp_device *ssp = drv_data->ssp;
 	void __iomem *reg = drv_data->ioaddr;
 	u32 clk_div = 0;
 	u8 bits = 0;
@@ -976,8 +622,8 @@
 			cs_deassert(drv_data);
 	}
 
-	/* Check for transfers that need multiple DMA segments */
-	if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
+	/* Check if we can DMA this transfer */
+	if (!pxa2xx_spi_dma_is_possible(transfer->len) && chip->enable_dma) {
 
 		/* reject already-mapped transfers; PIO won't always work */
 		if (message->is_dma_mapped
@@ -1000,21 +646,20 @@
 	}
 
 	/* Setup the transfer state based on the type of transfer */
-	if (flush(drv_data) == 0) {
+	if (pxa2xx_spi_flush(drv_data) == 0) {
 		dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
 		message->status = -EIO;
 		giveback(drv_data);
 		return;
 	}
 	drv_data->n_bytes = chip->n_bytes;
-	drv_data->dma_width = chip->dma_width;
 	drv_data->tx = (void *)transfer->tx_buf;
 	drv_data->tx_end = drv_data->tx + transfer->len;
 	drv_data->rx = transfer->rx_buf;
 	drv_data->rx_end = drv_data->rx + transfer->len;
 	drv_data->rx_dma = transfer->rx_dma;
 	drv_data->tx_dma = transfer->tx_dma;
-	drv_data->len = transfer->len & DCMD_LENGTH;
+	drv_data->len = transfer->len;
 	drv_data->write = drv_data->tx ? chip->write : null_writer;
 	drv_data->read = drv_data->rx ? chip->read : null_reader;
 
@@ -1031,25 +676,22 @@
 		if (transfer->bits_per_word)
 			bits = transfer->bits_per_word;
 
-		clk_div = ssp_get_clk_div(ssp, speed);
+		clk_div = ssp_get_clk_div(drv_data, speed);
 
 		if (bits <= 8) {
 			drv_data->n_bytes = 1;
-			drv_data->dma_width = DCMD_WIDTH1;
 			drv_data->read = drv_data->read != null_reader ?
 						u8_reader : null_reader;
 			drv_data->write = drv_data->write != null_writer ?
 						u8_writer : null_writer;
 		} else if (bits <= 16) {
 			drv_data->n_bytes = 2;
-			drv_data->dma_width = DCMD_WIDTH2;
 			drv_data->read = drv_data->read != null_reader ?
 						u16_reader : null_reader;
 			drv_data->write = drv_data->write != null_writer ?
 						u16_writer : null_writer;
 		} else if (bits <= 32) {
 			drv_data->n_bytes = 4;
-			drv_data->dma_width = DCMD_WIDTH4;
 			drv_data->read = drv_data->read != null_reader ?
 						u32_reader : null_reader;
 			drv_data->write = drv_data->write != null_writer ?
@@ -1058,7 +700,8 @@
 		/* if bits/word is changed in dma mode, then must check the
 		 * thresholds and burst also */
 		if (chip->enable_dma) {
-			if (set_dma_burst_and_threshold(chip, message->spi,
+			if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
+							message->spi,
 							bits, &dma_burst,
 							&dma_thresh))
 				if (printk_ratelimit())
@@ -1077,70 +720,21 @@
 
 	message->state = RUNNING_STATE;
 
-	/* Try to map dma buffer and do a dma transfer if successful, but
-	 * only if the length is non-zero and less than MAX_DMA_LEN.
-	 *
-	 * Zero-length non-descriptor DMA is illegal on PXA2xx; force use
-	 * of PIO instead.  Care is needed above because the transfer may
-	 * have have been passed with buffers that are already dma mapped.
-	 * A zero-length transfer in PIO mode will not try to write/read
-	 * to/from the buffers
-	 *
-	 * REVISIT large transfers are exactly where we most want to be
-	 * using DMA.  If this happens much, split those transfers into
-	 * multiple DMA segments rather than forcing PIO.
-	 */
 	drv_data->dma_mapped = 0;
-	if (drv_data->len > 0 && drv_data->len <= MAX_DMA_LEN)
-		drv_data->dma_mapped = map_dma_buffers(drv_data);
+	if (pxa2xx_spi_dma_is_possible(drv_data->len))
+		drv_data->dma_mapped = pxa2xx_spi_map_dma_buffers(drv_data);
 	if (drv_data->dma_mapped) {
 
 		/* Ensure we have the correct interrupt handler */
-		drv_data->transfer_handler = dma_transfer;
+		drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
 
-		/* Setup rx DMA Channel */
-		DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-		DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
-		DTADR(drv_data->rx_channel) = drv_data->rx_dma;
-		if (drv_data->rx == drv_data->null_dma_buf)
-			/* No target address increment */
-			DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
-							| drv_data->dma_width
-							| dma_burst
-							| drv_data->len;
-		else
-			DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
-							| DCMD_FLOWSRC
-							| drv_data->dma_width
-							| dma_burst
-							| drv_data->len;
-
-		/* Setup tx DMA Channel */
-		DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-		DSADR(drv_data->tx_channel) = drv_data->tx_dma;
-		DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
-		if (drv_data->tx == drv_data->null_dma_buf)
-			/* No source address increment */
-			DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
-							| drv_data->dma_width
-							| dma_burst
-							| drv_data->len;
-		else
-			DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
-							| DCMD_FLOWTRG
-							| drv_data->dma_width
-							| dma_burst
-							| drv_data->len;
-
-		/* Enable dma end irqs on SSP to detect end of transfer */
-		if (drv_data->ssp_type == PXA25x_SSP)
-			DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
+		pxa2xx_spi_dma_prepare(drv_data, dma_burst);
 
 		/* Clear status and start DMA engine */
 		cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
 		write_SSSR(drv_data->clear_sr, reg);
-		DCSR(drv_data->rx_channel) |= DCSR_RUN;
-		DCSR(drv_data->tx_channel) |= DCSR_RUN;
+
+		pxa2xx_spi_dma_start(drv_data);
 	} else {
 		/* Ensure we have the correct interrupt handler	*/
 		drv_data->transfer_handler = interrupt_transfer;
@@ -1150,6 +744,13 @@
 		write_SSSR_CS(drv_data, drv_data->clear_sr);
 	}
 
+	if (is_lpss_ssp(drv_data)) {
+		if ((read_SSIRF(reg) & 0xff) != chip->lpss_rx_threshold)
+			write_SSIRF(chip->lpss_rx_threshold, reg);
+		if ((read_SSITF(reg) & 0xffff) != chip->lpss_tx_threshold)
+			write_SSITF(chip->lpss_tx_threshold, reg);
+	}
+
 	/* see if we need to reload the config registers */
 	if ((read_SSCR0(reg) != cr0)
 		|| (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
@@ -1176,31 +777,12 @@
 	write_SSCR1(cr1, reg);
 }
 
-static void pump_messages(struct work_struct *work)
+static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
+					   struct spi_message *msg)
 {
-	struct driver_data *drv_data =
-		container_of(work, struct driver_data, pump_messages);
-	unsigned long flags;
+	struct driver_data *drv_data = spi_master_get_devdata(master);
 
-	/* Lock queue and check for queue work */
-	spin_lock_irqsave(&drv_data->lock, flags);
-	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
-		drv_data->busy = 0;
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return;
-	}
-
-	/* Make sure we are not already running a message */
-	if (drv_data->cur_msg) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return;
-	}
-
-	/* Extract head of queue */
-	drv_data->cur_msg = list_entry(drv_data->queue.next,
-					struct spi_message, queue);
-	list_del_init(&drv_data->cur_msg->queue);
-
+	drv_data->cur_msg = msg;
 	/* Initial message state*/
 	drv_data->cur_msg->state = START_STATE;
 	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
@@ -1213,34 +795,27 @@
 
 	/* Mark as busy and launch transfers */
 	tasklet_schedule(&drv_data->pump_transfers);
-
-	drv_data->busy = 1;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
+	return 0;
 }
 
-static int transfer(struct spi_device *spi, struct spi_message *msg)
+static int pxa2xx_spi_prepare_transfer(struct spi_master *master)
 {
-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
-	unsigned long flags;
+	struct driver_data *drv_data = spi_master_get_devdata(master);
 
-	spin_lock_irqsave(&drv_data->lock, flags);
+	pm_runtime_get_sync(&drv_data->pdev->dev);
+	return 0;
+}
 
-	if (drv_data->run == QUEUE_STOPPED) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return -ESHUTDOWN;
-	}
+static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
+{
+	struct driver_data *drv_data = spi_master_get_devdata(master);
 
-	msg->actual_length = 0;
-	msg->status = -EINPROGRESS;
-	msg->state = START_STATE;
+	/* Disable the SSP now */
+	write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
+		    drv_data->ioaddr);
 
-	list_add_tail(&msg->queue, &drv_data->queue);
-
-	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
-		queue_work(drv_data->workqueue, &drv_data->pump_messages);
-
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
+	pm_runtime_mark_last_busy(&drv_data->pdev->dev);
+	pm_runtime_put_autosuspend(&drv_data->pdev->dev);
 	return 0;
 }
 
@@ -1287,10 +862,18 @@
 	struct pxa2xx_spi_chip *chip_info = NULL;
 	struct chip_data *chip;
 	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
-	struct ssp_device *ssp = drv_data->ssp;
 	unsigned int clk_div;
-	uint tx_thres = TX_THRESH_DFLT;
-	uint rx_thres = RX_THRESH_DFLT;
+	uint tx_thres, tx_hi_thres, rx_thres;
+
+	if (is_lpss_ssp(drv_data)) {
+		tx_thres = LPSS_TX_LOTHRESH_DFLT;
+		tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
+		rx_thres = LPSS_RX_THRESH_DFLT;
+	} else {
+		tx_thres = TX_THRESH_DFLT;
+		tx_hi_thres = 0;
+		rx_thres = RX_THRESH_DFLT;
+	}
 
 	if (!pxa25x_ssp_comp(drv_data)
 		&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
@@ -1330,8 +913,6 @@
 			chip->gpio_cs = -1;
 		chip->enable_dma = 0;
 		chip->timeout = TIMOUT_DFLT;
-		chip->dma_burst_size = drv_data->master_info->enable_dma ?
-					DCMD_BURST8 : 0;
 	}
 
 	/* protocol drivers may change the chip settings, so...
@@ -1345,23 +926,37 @@
 			chip->timeout = chip_info->timeout;
 		if (chip_info->tx_threshold)
 			tx_thres = chip_info->tx_threshold;
+		if (chip_info->tx_hi_threshold)
+			tx_hi_thres = chip_info->tx_hi_threshold;
 		if (chip_info->rx_threshold)
 			rx_thres = chip_info->rx_threshold;
 		chip->enable_dma = drv_data->master_info->enable_dma;
 		chip->dma_threshold = 0;
 		if (chip_info->enable_loopback)
 			chip->cr1 = SSCR1_LBM;
+	} else if (ACPI_HANDLE(&spi->dev)) {
+		/*
+		 * Slave devices enumerated from ACPI namespace don't
+		 * usually have chip_info but we still might want to use
+		 * DMA with them.
+		 */
+		chip->enable_dma = drv_data->master_info->enable_dma;
 	}
 
 	chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
 			(SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
 
+	chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
+	chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
+				| SSITF_TxHiThresh(tx_hi_thres);
+
 	/* set dma burst and threshold outside of chip_info path so that if
 	 * chip_info goes away after setting chip->enable_dma, the
 	 * burst and threshold can still respond to changes in bits_per_word */
 	if (chip->enable_dma) {
 		/* set up legal burst and threshold for dma */
-		if (set_dma_burst_and_threshold(chip, spi, spi->bits_per_word,
+		if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi,
+						spi->bits_per_word,
 						&chip->dma_burst_size,
 						&chip->dma_threshold)) {
 			dev_warn(&spi->dev, "in setup: DMA burst size reduced "
@@ -1369,7 +964,7 @@
 		}
 	}
 
-	clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
+	clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz);
 	chip->speed_hz = spi->max_speed_hz;
 
 	chip->cr0 = clk_div
@@ -1382,32 +977,32 @@
 	chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
 			| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
 
+	if (spi->mode & SPI_LOOP)
+		chip->cr1 |= SSCR1_LBM;
+
 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
 	if (!pxa25x_ssp_comp(drv_data))
 		dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
-			clk_get_rate(ssp->clk)
+			drv_data->max_clk_rate
 				/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
 			chip->enable_dma ? "DMA" : "PIO");
 	else
 		dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
-			clk_get_rate(ssp->clk) / 2
+			drv_data->max_clk_rate / 2
 				/ (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
 			chip->enable_dma ? "DMA" : "PIO");
 
 	if (spi->bits_per_word <= 8) {
 		chip->n_bytes = 1;
-		chip->dma_width = DCMD_WIDTH1;
 		chip->read = u8_reader;
 		chip->write = u8_writer;
 	} else if (spi->bits_per_word <= 16) {
 		chip->n_bytes = 2;
-		chip->dma_width = DCMD_WIDTH2;
 		chip->read = u16_reader;
 		chip->write = u16_writer;
 	} else if (spi->bits_per_word <= 32) {
 		chip->cr0 |= SSCR0_EDSS;
 		chip->n_bytes = 4;
-		chip->dma_width = DCMD_WIDTH4;
 		chip->read = u32_reader;
 		chip->write = u32_writer;
 	} else {
@@ -1438,93 +1033,98 @@
 	kfree(chip);
 }
 
-static int init_queue(struct driver_data *drv_data)
+#ifdef CONFIG_ACPI
+static int pxa2xx_spi_acpi_add_dma(struct acpi_resource *res, void *data)
 {
-	INIT_LIST_HEAD(&drv_data->queue);
-	spin_lock_init(&drv_data->lock);
+	struct pxa2xx_spi_master *pdata = data;
 
-	drv_data->run = QUEUE_STOPPED;
-	drv_data->busy = 0;
+	if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
+		const struct acpi_resource_fixed_dma *dma;
 
-	tasklet_init(&drv_data->pump_transfers,
-			pump_transfers,	(unsigned long)drv_data);
-
-	INIT_WORK(&drv_data->pump_messages, pump_messages);
-	drv_data->workqueue = create_singlethread_workqueue(
-				dev_name(drv_data->master->dev.parent));
-	if (drv_data->workqueue == NULL)
-		return -EBUSY;
-
-	return 0;
-}
-
-static int start_queue(struct driver_data *drv_data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-
-	if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return -EBUSY;
+		dma = &res->data.fixed_dma;
+		if (pdata->tx_slave_id < 0) {
+			pdata->tx_slave_id = dma->request_lines;
+			pdata->tx_chan_id = dma->channels;
+		} else if (pdata->rx_slave_id < 0) {
+			pdata->rx_slave_id = dma->request_lines;
+			pdata->rx_chan_id = dma->channels;
+		}
 	}
 
-	drv_data->run = QUEUE_RUNNING;
-	drv_data->cur_msg = NULL;
-	drv_data->cur_transfer = NULL;
-	drv_data->cur_chip = NULL;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
-	queue_work(drv_data->workqueue, &drv_data->pump_messages);
-
-	return 0;
+	/* Tell the ACPI core to skip this resource */
+	return 1;
 }
 
-static int stop_queue(struct driver_data *drv_data)
+static struct pxa2xx_spi_master *
+pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 {
-	unsigned long flags;
-	unsigned limit = 500;
-	int status = 0;
+	struct pxa2xx_spi_master *pdata;
+	struct list_head resource_list;
+	struct acpi_device *adev;
+	struct ssp_device *ssp;
+	struct resource *res;
+	int devid;
 
-	spin_lock_irqsave(&drv_data->lock, flags);
+	if (!ACPI_HANDLE(&pdev->dev) ||
+	    acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
+		return NULL;
 
-	/* This is a bit lame, but is optimized for the common execution path.
-	 * A wait_queue on the drv_data->busy could be used, but then the common
-	 * execution path (pump_messages) would be required to call wake_up or
-	 * friends on every SPI message. Do this instead */
-	drv_data->run = QUEUE_STOPPED;
-	while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		msleep(10);
-		spin_lock_irqsave(&drv_data->lock, flags);
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*ssp), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev,
+			"failed to allocate memory for platform data\n");
+		return NULL;
 	}
 
-	if (!list_empty(&drv_data->queue) || drv_data->busy)
-		status = -EBUSY;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return NULL;
 
-	spin_unlock_irqrestore(&drv_data->lock, flags);
+	ssp = &pdata->ssp;
 
-	return status;
+	ssp->phys_base = res->start;
+	ssp->mmio_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!ssp->mmio_base) {
+		dev_err(&pdev->dev, "failed to ioremap mmio_base\n");
+		return NULL;
+	}
+
+	ssp->clk = devm_clk_get(&pdev->dev, NULL);
+	ssp->irq = platform_get_irq(pdev, 0);
+	ssp->type = LPSS_SSP;
+	ssp->pdev = pdev;
+
+	ssp->port_id = -1;
+	if (adev->pnp.unique_id && !kstrtoint(adev->pnp.unique_id, 0, &devid))
+		ssp->port_id = devid;
+
+	pdata->num_chipselect = 1;
+	pdata->rx_slave_id = -1;
+	pdata->tx_slave_id = -1;
+
+	INIT_LIST_HEAD(&resource_list);
+	acpi_dev_get_resources(adev, &resource_list, pxa2xx_spi_acpi_add_dma,
+			       pdata);
+	acpi_dev_free_resource_list(&resource_list);
+
+	pdata->enable_dma = pdata->rx_slave_id >= 0 && pdata->tx_slave_id >= 0;
+
+	return pdata;
 }
 
-static int destroy_queue(struct driver_data *drv_data)
+static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
+	{ "INT33C0", 0 },
+	{ "INT33C1", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
+#else
+static inline struct pxa2xx_spi_master *
+pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 {
-	int status;
-
-	status = stop_queue(drv_data);
-	/* we are unloading the module or failing to load (only two calls
-	 * to this routine), and neither call can handle a return value.
-	 * However, destroy_workqueue calls flush_workqueue, and that will
-	 * block until all work is done.  If the reason that stop_queue
-	 * timed out is that the work will never finish, then it does no
-	 * good to call destroy_workqueue, so return anyway. */
-	if (status != 0)
-		return status;
-
-	destroy_workqueue(drv_data->workqueue);
-
-	return 0;
+	return NULL;
 }
+#endif
 
 static int pxa2xx_spi_probe(struct platform_device *pdev)
 {
@@ -1535,11 +1135,21 @@
 	struct ssp_device *ssp;
 	int status;
 
-	platform_info = dev->platform_data;
+	platform_info = dev_get_platdata(dev);
+	if (!platform_info) {
+		platform_info = pxa2xx_spi_acpi_get_pdata(pdev);
+		if (!platform_info) {
+			dev_err(&pdev->dev, "missing platform data\n");
+			return -ENODEV;
+		}
+	}
 
 	ssp = pxa_ssp_request(pdev->id, pdev->name);
-	if (ssp == NULL) {
-		dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
+	if (!ssp)
+		ssp = &platform_info->ssp;
+
+	if (!ssp->mmio_base) {
+		dev_err(&pdev->dev, "failed to get ssp\n");
 		return -ENODEV;
 	}
 
@@ -1558,19 +1168,21 @@
 
 	master->dev.parent = &pdev->dev;
 	master->dev.of_node = pdev->dev.of_node;
+	ACPI_HANDLE_SET(&master->dev, ACPI_HANDLE(&pdev->dev));
 	/* the spi->mode bits understood by this driver: */
-	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
 
-	master->bus_num = pdev->id;
+	master->bus_num = ssp->port_id;
 	master->num_chipselect = platform_info->num_chipselect;
 	master->dma_alignment = DMA_ALIGNMENT;
 	master->cleanup = cleanup;
 	master->setup = setup;
-	master->transfer = transfer;
+	master->transfer_one_message = pxa2xx_spi_transfer_one_message;
+	master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer;
+	master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
 
 	drv_data->ssp_type = ssp->type;
-	drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
-						sizeof(struct driver_data)), 8);
+	drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
 
 	drv_data->ioaddr = ssp->mmio_base;
 	drv_data->ssdr_physical = ssp->phys_base + SSDR;
@@ -1581,7 +1193,7 @@
 		drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
 	} else {
 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
-		drv_data->dma_cr1 = SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE;
+		drv_data->dma_cr1 = DEFAULT_DMA_CR1;
 		drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
 	}
@@ -1597,35 +1209,17 @@
 	drv_data->tx_channel = -1;
 	drv_data->rx_channel = -1;
 	if (platform_info->enable_dma) {
-
-		/* Get two DMA channels	(rx and tx) */
-		drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
-							DMA_PRIO_HIGH,
-							dma_handler,
-							drv_data);
-		if (drv_data->rx_channel < 0) {
-			dev_err(dev, "problem (%d) requesting rx channel\n",
-				drv_data->rx_channel);
-			status = -ENODEV;
-			goto out_error_irq_alloc;
+		status = pxa2xx_spi_dma_setup(drv_data);
+		if (status) {
+			dev_warn(dev, "failed to setup DMA, using PIO\n");
+			platform_info->enable_dma = false;
 		}
-		drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
-							DMA_PRIO_MEDIUM,
-							dma_handler,
-							drv_data);
-		if (drv_data->tx_channel < 0) {
-			dev_err(dev, "problem (%d) requesting tx channel\n",
-				drv_data->tx_channel);
-			status = -ENODEV;
-			goto out_error_dma_alloc;
-		}
-
-		DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
-		DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
 	}
 
 	/* Enable SOC clock */
-	clk_enable(ssp->clk);
+	clk_prepare_enable(ssp->clk);
+
+	drv_data->max_clk_rate = clk_get_rate(ssp->clk);
 
 	/* Load default SSP configuration */
 	write_SSCR0(0, drv_data->ioaddr);
@@ -1640,41 +1234,29 @@
 		write_SSTO(0, drv_data->ioaddr);
 	write_SSPSP(0, drv_data->ioaddr);
 
-	/* Initial and start queue */
-	status = init_queue(drv_data);
-	if (status != 0) {
-		dev_err(&pdev->dev, "problem initializing queue\n");
-		goto out_error_clock_enabled;
-	}
-	status = start_queue(drv_data);
-	if (status != 0) {
-		dev_err(&pdev->dev, "problem starting queue\n");
-		goto out_error_clock_enabled;
-	}
+	lpss_ssp_setup(drv_data);
+
+	tasklet_init(&drv_data->pump_transfers, pump_transfers,
+		     (unsigned long)drv_data);
 
 	/* Register with the SPI framework */
 	platform_set_drvdata(pdev, drv_data);
 	status = spi_register_master(master);
 	if (status != 0) {
 		dev_err(&pdev->dev, "problem registering spi master\n");
-		goto out_error_queue_alloc;
+		goto out_error_clock_enabled;
 	}
 
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	return status;
 
-out_error_queue_alloc:
-	destroy_queue(drv_data);
-
 out_error_clock_enabled:
-	clk_disable(ssp->clk);
-
-out_error_dma_alloc:
-	if (drv_data->tx_channel != -1)
-		pxa_free_dma(drv_data->tx_channel);
-	if (drv_data->rx_channel != -1)
-		pxa_free_dma(drv_data->rx_channel);
-
-out_error_irq_alloc:
+	clk_disable_unprepare(ssp->clk);
+	pxa2xx_spi_dma_release(drv_data);
 	free_irq(ssp->irq, drv_data);
 
 out_error_master_alloc:
@@ -1687,37 +1269,23 @@
 {
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
 	struct ssp_device *ssp;
-	int status = 0;
 
 	if (!drv_data)
 		return 0;
 	ssp = drv_data->ssp;
 
-	/* Remove the queue */
-	status = destroy_queue(drv_data);
-	if (status != 0)
-		/* the kernel does not check the return status of this
-		 * this routine (mod->exit, within the kernel).  Therefore
-		 * nothing is gained by returning from here, the module is
-		 * going away regardless, and we should not leave any more
-		 * resources allocated than necessary.  We cannot free the
-		 * message memory in drv_data->queue, but we can release the
-		 * resources below.  I think the kernel should honor -EBUSY
-		 * returns but... */
-		dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
-			"complete, message memory not freed\n");
+	pm_runtime_get_sync(&pdev->dev);
 
 	/* Disable the SSP at the peripheral and SOC level */
 	write_SSCR0(0, drv_data->ioaddr);
-	clk_disable(ssp->clk);
+	clk_disable_unprepare(ssp->clk);
 
 	/* Release DMA */
-	if (drv_data->master_info->enable_dma) {
-		DRCMR(ssp->drcmr_rx) = 0;
-		DRCMR(ssp->drcmr_tx) = 0;
-		pxa_free_dma(drv_data->tx_channel);
-		pxa_free_dma(drv_data->rx_channel);
-	}
+	if (drv_data->master_info->enable_dma)
+		pxa2xx_spi_dma_release(drv_data);
+
+	pm_runtime_put_noidle(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
 
 	/* Release IRQ */
 	free_irq(ssp->irq, drv_data);
@@ -1749,11 +1317,11 @@
 	struct ssp_device *ssp = drv_data->ssp;
 	int status = 0;
 
-	status = stop_queue(drv_data);
+	status = spi_master_suspend(drv_data->master);
 	if (status != 0)
 		return status;
 	write_SSCR0(0, drv_data->ioaddr);
-	clk_disable(ssp->clk);
+	clk_disable_unprepare(ssp->clk);
 
 	return 0;
 }
@@ -1764,18 +1332,13 @@
 	struct ssp_device *ssp = drv_data->ssp;
 	int status = 0;
 
-	if (drv_data->rx_channel != -1)
-		DRCMR(drv_data->ssp->drcmr_rx) =
-			DRCMR_MAPVLD | drv_data->rx_channel;
-	if (drv_data->tx_channel != -1)
-		DRCMR(drv_data->ssp->drcmr_tx) =
-			DRCMR_MAPVLD | drv_data->tx_channel;
+	pxa2xx_spi_dma_resume(drv_data);
 
 	/* Enable the SSP clock */
-	clk_enable(ssp->clk);
+	clk_prepare_enable(ssp->clk);
 
 	/* Start the queue running */
-	status = start_queue(drv_data);
+	status = spi_master_resume(drv_data->master);
 	if (status != 0) {
 		dev_err(dev, "problem starting queue (%d)\n", status);
 		return status;
@@ -1783,20 +1346,38 @@
 
 	return 0;
 }
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int pxa2xx_spi_runtime_suspend(struct device *dev)
+{
+	struct driver_data *drv_data = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(drv_data->ssp->clk);
+	return 0;
+}
+
+static int pxa2xx_spi_runtime_resume(struct device *dev)
+{
+	struct driver_data *drv_data = dev_get_drvdata(dev);
+
+	clk_prepare_enable(drv_data->ssp->clk);
+	return 0;
+}
+#endif
 
 static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
-	.suspend	= pxa2xx_spi_suspend,
-	.resume		= pxa2xx_spi_resume,
+	SET_SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume)
+	SET_RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend,
+			   pxa2xx_spi_runtime_resume, NULL)
 };
-#endif
 
 static struct platform_driver driver = {
 	.driver = {
 		.name	= "pxa2xx-spi",
 		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
 		.pm	= &pxa2xx_spi_pm_ops,
-#endif
+		.acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match),
 	},
 	.probe = pxa2xx_spi_probe,
 	.remove = pxa2xx_spi_remove,
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
new file mode 100644
index 0000000..5adc2a1
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
+ * Copyright (C) 2013, Intel Corporation
+ *
+ * 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.
+ */
+
+#ifndef SPI_PXA2XX_H
+#define SPI_PXA2XX_H
+
+#include <linux/atomic.h>
+#include <linux/dmaengine.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+struct driver_data {
+	/* Driver model hookup */
+	struct platform_device *pdev;
+
+	/* SSP Info */
+	struct ssp_device *ssp;
+
+	/* SPI framework hookup */
+	enum pxa_ssp_type ssp_type;
+	struct spi_master *master;
+
+	/* PXA hookup */
+	struct pxa2xx_spi_master *master_info;
+
+	/* PXA private DMA setup stuff */
+	int rx_channel;
+	int tx_channel;
+	u32 *null_dma_buf;
+
+	/* SSP register addresses */
+	void __iomem *ioaddr;
+	u32 ssdr_physical;
+
+	/* SSP masks*/
+	u32 dma_cr1;
+	u32 int_cr1;
+	u32 clear_sr;
+	u32 mask_sr;
+
+	/* Maximun clock rate */
+	unsigned long max_clk_rate;
+
+	/* Message Transfer pump */
+	struct tasklet_struct pump_transfers;
+
+	/* DMA engine support */
+	struct dma_chan *rx_chan;
+	struct dma_chan *tx_chan;
+	struct sg_table rx_sgt;
+	struct sg_table tx_sgt;
+	int rx_nents;
+	int tx_nents;
+	void *dummy;
+	atomic_t dma_running;
+
+	/* Current message transfer state info */
+	struct spi_message *cur_msg;
+	struct spi_transfer *cur_transfer;
+	struct chip_data *cur_chip;
+	size_t len;
+	void *tx;
+	void *tx_end;
+	void *rx;
+	void *rx_end;
+	int dma_mapped;
+	dma_addr_t rx_dma;
+	dma_addr_t tx_dma;
+	size_t rx_map_len;
+	size_t tx_map_len;
+	u8 n_bytes;
+	int (*write)(struct driver_data *drv_data);
+	int (*read)(struct driver_data *drv_data);
+	irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
+	void (*cs_control)(u32 command);
+
+	void __iomem *lpss_base;
+};
+
+struct chip_data {
+	u32 cr0;
+	u32 cr1;
+	u32 psp;
+	u32 timeout;
+	u8 n_bytes;
+	u32 dma_burst_size;
+	u32 threshold;
+	u32 dma_threshold;
+	u16 lpss_rx_threshold;
+	u16 lpss_tx_threshold;
+	u8 enable_dma;
+	u8 bits_per_word;
+	u32 speed_hz;
+	union {
+		int gpio_cs;
+		unsigned int frm;
+	};
+	int gpio_cs_inverted;
+	int (*write)(struct driver_data *drv_data);
+	int (*read)(struct driver_data *drv_data);
+	void (*cs_control)(u32 command);
+};
+
+#define DEFINE_SSP_REG(reg, off) \
+static inline u32 read_##reg(void const __iomem *p) \
+{ return __raw_readl(p + (off)); } \
+\
+static inline void write_##reg(u32 v, void __iomem *p) \
+{ __raw_writel(v, p + (off)); }
+
+DEFINE_SSP_REG(SSCR0, 0x00)
+DEFINE_SSP_REG(SSCR1, 0x04)
+DEFINE_SSP_REG(SSSR, 0x08)
+DEFINE_SSP_REG(SSITR, 0x0c)
+DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(SSTO, 0x28)
+DEFINE_SSP_REG(SSPSP, 0x2c)
+DEFINE_SSP_REG(SSITF, SSITF)
+DEFINE_SSP_REG(SSIRF, SSIRF)
+
+#define START_STATE ((void *)0)
+#define RUNNING_STATE ((void *)1)
+#define DONE_STATE ((void *)2)
+#define ERROR_STATE ((void *)-1)
+
+#define IS_DMA_ALIGNED(x)	IS_ALIGNED((unsigned long)(x), DMA_ALIGNMENT)
+#define DMA_ALIGNMENT		8
+
+static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
+{
+	if (drv_data->ssp_type == PXA25x_SSP)
+		return 1;
+	if (drv_data->ssp_type == CE4100_SSP)
+		return 1;
+	return 0;
+}
+
+static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
+{
+	void __iomem *reg = drv_data->ioaddr;
+
+	if (drv_data->ssp_type == CE4100_SSP)
+		val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
+
+	write_SSSR(val, reg);
+}
+
+extern int pxa2xx_spi_flush(struct driver_data *drv_data);
+extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
+
+/*
+ * Select the right DMA implementation.
+ */
+#if defined(CONFIG_SPI_PXA2XX_PXADMA)
+#define SPI_PXA2XX_USE_DMA	1
+#define MAX_DMA_LEN		8191
+#define DEFAULT_DMA_CR1		(SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE)
+#elif defined(CONFIG_SPI_PXA2XX_DMA)
+#define SPI_PXA2XX_USE_DMA	1
+#define MAX_DMA_LEN		SZ_64K
+#define DEFAULT_DMA_CR1		(SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
+#else
+#undef SPI_PXA2XX_USE_DMA
+#define MAX_DMA_LEN		0
+#define DEFAULT_DMA_CR1		0
+#endif
+
+#ifdef SPI_PXA2XX_USE_DMA
+extern bool pxa2xx_spi_dma_is_possible(size_t len);
+extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
+extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
+extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst);
+extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
+extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
+extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
+extern void pxa2xx_spi_dma_resume(struct driver_data *drv_data);
+extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+						  struct spi_device *spi,
+						  u8 bits_per_word,
+						  u32 *burst_code,
+						  u32 *threshold);
+#else
+static inline bool pxa2xx_spi_dma_is_possible(size_t len) { return false; }
+static inline int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
+{
+	return 0;
+}
+#define pxa2xx_spi_dma_transfer NULL
+static inline void pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
+					  u32 dma_burst) {}
+static inline void pxa2xx_spi_dma_start(struct driver_data *drv_data) {}
+static inline int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
+{
+	return 0;
+}
+static inline void pxa2xx_spi_dma_release(struct driver_data *drv_data) {}
+static inline void pxa2xx_spi_dma_resume(struct driver_data *drv_data) {}
+static inline int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
+							 struct spi_device *spi,
+							 u8 bits_per_word,
+							 u32 *burst_code,
+							 u32 *threshold)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif /* SPI_PXA2XX_H */
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index ad93231..8f492ed 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -62,7 +62,7 @@
 #define S3C64XX_SPI_CLKSEL_SRCMSK	(3<<9)
 #define S3C64XX_SPI_CLKSEL_SRCSHFT	9
 #define S3C64XX_SPI_ENCLK_ENABLE	(1<<8)
-#define S3C64XX_SPI_PSR_MASK 		0xff
+#define S3C64XX_SPI_PSR_MASK		0xff
 
 #define S3C64XX_SPI_MODE_CH_TSZ_BYTE		(0<<29)
 #define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD	(1<<29)
@@ -697,7 +697,7 @@
 		INIT_COMPLETION(sdd->xfer_completion);
 
 		/* Only BPW and Speed may change across transfers */
-		bpw = xfer->bits_per_word ? : spi->bits_per_word;
+		bpw = xfer->bits_per_word;
 		speed = xfer->speed_hz ? : spi->max_speed_hz;
 
 		if (xfer->len % (bpw / 8)) {
@@ -743,8 +743,7 @@
 		       sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 
 		if (status) {
-			dev_err(&spi->dev, "I/O Error: "
-				"rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+			dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
 				xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
 				(sdd->state & RXBUSY) ? 'f' : 'p',
 				(sdd->state & TXBUSY) ? 'f' : 'p',
@@ -799,7 +798,7 @@
 
 	/* Acquire DMA channels */
 	while (!acquire_dma(sdd))
-		msleep(10);
+		usleep_range(10000, 11000);
 
 	pm_runtime_get_sync(&sdd->pdev->dev);
 
@@ -841,16 +840,14 @@
 
 	cs = kzalloc(sizeof(*cs), GFP_KERNEL);
 	if (!cs) {
-		dev_err(&spi->dev, "could not allocate memory for controller"
-					" data\n");
+		dev_err(&spi->dev, "could not allocate memory for controller data\n");
 		of_node_put(data_np);
 		return ERR_PTR(-ENOMEM);
 	}
 
 	cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
 	if (!gpio_is_valid(cs->line)) {
-		dev_err(&spi->dev, "chip select gpio is not specified or "
-					"invalid\n");
+		dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
 		kfree(cs);
 		of_node_put(data_np);
 		return ERR_PTR(-EINVAL);
@@ -957,6 +954,8 @@
 		if (spi->max_speed_hz >= speed) {
 			spi->max_speed_hz = speed;
 		} else {
+			dev_err(&spi->dev, "Can't set %dHz transfer speed\n",
+				spi->max_speed_hz);
 			err = -EINVAL;
 			goto setup_exit;
 		}
@@ -1076,8 +1075,8 @@
 	if (!sdd->pdev->dev.of_node) {
 		res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
 		if (!res) {
-			dev_err(&pdev->dev, "Unable to get SPI-%s dma "
-					"resource\n", chan_str);
+			dev_err(&pdev->dev, "Unable to get SPI-%s dma resource\n",
+				chan_str);
 			return -ENXIO;
 		}
 		dma_data->dmach = res->start;
@@ -1133,8 +1132,7 @@
 		gpio_free(sdd->gpios[idx]);
 }
 
-static struct s3c64xx_spi_info * s3c64xx_spi_parse_dt(
-						struct device *dev)
+static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
 {
 	struct s3c64xx_spi_info *sci;
 	u32 temp;
@@ -1146,16 +1144,14 @@
 	}
 
 	if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
-		dev_warn(dev, "spi bus clock parent not specified, using "
-				"clock at index 0 as parent\n");
+		dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n");
 		sci->src_clk_nr = 0;
 	} else {
 		sci->src_clk_nr = temp;
 	}
 
 	if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
-		dev_warn(dev, "number of chip select lines not specified, "
-				"assuming 1 chip select line\n");
+		dev_warn(dev, "number of chip select lines not specified, assuming 1 chip select line\n");
 		sci->num_cs = 1;
 	} else {
 		sci->num_cs = temp;
@@ -1195,7 +1191,7 @@
 			 platform_get_device_id(pdev)->driver_data;
 }
 
-static int __init s3c64xx_spi_probe(struct platform_device *pdev)
+static int s3c64xx_spi_probe(struct platform_device *pdev)
 {
 	struct resource	*mem_res;
 	struct s3c64xx_spi_driver_data *sdd;
@@ -1245,8 +1241,8 @@
 	if (pdev->dev.of_node) {
 		ret = of_alias_get_id(pdev->dev.of_node, "spi");
 		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to get alias id, "
-						"errno %d\n", ret);
+			dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
+				ret);
 			goto err0;
 		}
 		sdd->port_id = ret;
@@ -1280,7 +1276,7 @@
 	if (sdd->regs == NULL) {
 		dev_err(&pdev->dev, "Unable to remap IO\n");
 		ret = -ENXIO;
-		goto err1;
+		goto err0;
 	}
 
 	if (!sci->cfg_gpio && pdev->dev.of_node) {
@@ -1289,36 +1285,36 @@
 	} else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
 		dev_err(&pdev->dev, "Unable to config gpio\n");
 		ret = -EBUSY;
-		goto err2;
+		goto err0;
 	}
 
 	/* Setup clocks */
-	sdd->clk = clk_get(&pdev->dev, "spi");
+	sdd->clk = devm_clk_get(&pdev->dev, "spi");
 	if (IS_ERR(sdd->clk)) {
 		dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
 		ret = PTR_ERR(sdd->clk);
-		goto err3;
+		goto err1;
 	}
 
 	if (clk_prepare_enable(sdd->clk)) {
 		dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
 		ret = -EBUSY;
-		goto err4;
+		goto err1;
 	}
 
 	sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
-	sdd->src_clk = clk_get(&pdev->dev, clk_name);
+	sdd->src_clk = devm_clk_get(&pdev->dev, clk_name);
 	if (IS_ERR(sdd->src_clk)) {
 		dev_err(&pdev->dev,
 			"Unable to acquire clock '%s'\n", clk_name);
 		ret = PTR_ERR(sdd->src_clk);
-		goto err5;
+		goto err2;
 	}
 
 	if (clk_prepare_enable(sdd->src_clk)) {
 		dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
 		ret = -EBUSY;
-		goto err6;
+		goto err2;
 	}
 
 	/* Setup Deufult Mode */
@@ -1328,11 +1324,12 @@
 	init_completion(&sdd->xfer_completion);
 	INIT_LIST_HEAD(&sdd->queue);
 
-	ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd);
+	ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
+				"spi-s3c64xx", sdd);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
 			irq, ret);
-		goto err7;
+		goto err3;
 	}
 
 	writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
@@ -1342,11 +1339,10 @@
 	if (spi_register_master(master)) {
 		dev_err(&pdev->dev, "cannot register SPI master\n");
 		ret = -EBUSY;
-		goto err8;
+		goto err3;
 	}
 
-	dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
-					"with %d Slaves attached\n",
+	dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
 					sdd->port_id, master->num_chipselect);
 	dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
 					mem_res->end, mem_res->start,
@@ -1356,21 +1352,13 @@
 
 	return 0;
 
-err8:
-	free_irq(irq, sdd);
-err7:
-	clk_disable_unprepare(sdd->src_clk);
-err6:
-	clk_put(sdd->src_clk);
-err5:
-	clk_disable_unprepare(sdd->clk);
-err4:
-	clk_put(sdd->clk);
 err3:
+	clk_disable_unprepare(sdd->src_clk);
+err2:
+	clk_disable_unprepare(sdd->clk);
+err1:
 	if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
 		s3c64xx_spi_dt_gpio_free(sdd);
-err2:
-err1:
 err0:
 	platform_set_drvdata(pdev, NULL);
 	spi_master_put(master);
@@ -1389,13 +1377,9 @@
 
 	writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
 
-	free_irq(platform_get_irq(pdev, 0), sdd);
-
 	clk_disable_unprepare(sdd->src_clk);
-	clk_put(sdd->src_clk);
 
 	clk_disable_unprepare(sdd->clk);
-	clk_put(sdd->clk);
 
 	if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
 		s3c64xx_spi_dt_gpio_free(sdd);
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 96358d0..8b40d08 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
@@ -592,6 +593,37 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
+{
+	struct sh_msiof_spi_info *info;
+	struct device_node *np = dev->of_node;
+	u32 num_cs = 0;
+
+	info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(dev, "failed to allocate setup data\n");
+		return NULL;
+	}
+
+	/* Parse the MSIOF properties */
+	of_property_read_u32(np, "num-cs", &num_cs);
+	of_property_read_u32(np, "renesas,tx-fifo-size",
+					&info->tx_fifo_override);
+	of_property_read_u32(np, "renesas,rx-fifo-size",
+					&info->rx_fifo_override);
+
+	info->num_chipselect = num_cs;
+
+	return info;
+}
+#else
+static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int sh_msiof_spi_probe(struct platform_device *pdev)
 {
 	struct resource	*r;
@@ -610,7 +642,17 @@
 	p = spi_master_get_devdata(master);
 
 	platform_set_drvdata(pdev, p);
-	p->info = pdev->dev.platform_data;
+	if (pdev->dev.of_node)
+		p->info = sh_msiof_spi_parse_dt(&pdev->dev);
+	else
+		p->info = pdev->dev.platform_data;
+
+	if (!p->info) {
+		dev_err(&pdev->dev, "failed to obtain device info\n");
+		ret = -ENXIO;
+		goto err1;
+	}
+
 	init_completion(&p->done);
 
 	p->clk = clk_get(&pdev->dev, NULL);
@@ -715,6 +757,17 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id sh_msiof_match[] = {
+	{ .compatible = "renesas,sh-msiof", },
+	{ .compatible = "renesas,sh-mobile-msiof", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sh_msiof_match);
+#else
+#define sh_msiof_match NULL
+#endif
+
 static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
 	.runtime_suspend = sh_msiof_spi_runtime_nop,
 	.runtime_resume = sh_msiof_spi_runtime_nop,
@@ -727,6 +780,7 @@
 		.name		= "spi_sh_msiof",
 		.owner		= THIS_MODULE,
 		.pm		= &sh_msiof_spi_dev_pm_ops,
+		.of_match_table = sh_msiof_match,
 	},
 };
 module_platform_driver(sh_msiof_spi_drv);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index e0f43a5..6a5626d 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -382,8 +382,7 @@
 
 	sspi = spi_master_get_devdata(spi->master);
 
-	bits_per_word = t && t->bits_per_word ? t->bits_per_word :
-		spi->bits_per_word;
+	bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
 	hz = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz;
 
 	/* Enable IO mode for RX, TX */
@@ -570,7 +569,7 @@
 		ret = -EINVAL;
 		goto free_pin;
 	}
-	clk_enable(sspi->clk);
+	clk_prepare_enable(sspi->clk);
 	sspi->ctrl_freq = clk_get_rate(sspi->clk);
 
 	init_completion(&sspi->done);
@@ -594,7 +593,7 @@
 	return 0;
 
 free_clk:
-	clk_disable(sspi->clk);
+	clk_disable_unprepare(sspi->clk);
 	clk_put(sspi->clk);
 free_pin:
 	pinctrl_put(sspi->p);
@@ -618,7 +617,7 @@
 		if (sspi->chipselect[i] > 0)
 			gpio_free(sspi->chipselect[i]);
 	}
-	clk_disable(sspi->clk);
+	clk_disable_unprepare(sspi->clk);
 	clk_put(sspi->clk);
 	pinctrl_put(sspi->p);
 	spi_master_put(master);
@@ -659,6 +658,7 @@
 
 static const struct of_device_id spi_sirfsoc_of_match[] = {
 	{ .compatible = "sirf,prima2-spi", },
+	{ .compatible = "sirf,marco-spi", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, sirfsoc_spi_of_match);
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 448a8cc..9a42c15 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -269,9 +269,7 @@
 	u32 speed;
 	unsigned long command;
 
-	speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
-	if (!speed)
-		speed = tsd->spi_max_frequency;
+	speed = t->speed_hz;
 	if (speed != tsd->cur_speed) {
 		clk_set_rate(tsd->clk, speed);
 		tsd->cur_speed = speed;
@@ -319,6 +317,15 @@
 	return  tegra_sflash_start_cpu_based_transfer(tsd, t);
 }
 
+static int tegra_sflash_setup(struct spi_device *spi)
+{
+	struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
+
+	/* Set speed to the spi max fequency if spi device has not set */
+	spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
+	return 0;
+}
+
 static int tegra_sflash_transfer_one_message(struct spi_master *master,
 			struct spi_message *msg)
 {
@@ -492,6 +499,7 @@
 
 	/* the spi->mode bits understood by this driver: */
 	master->mode_bits = SPI_CPOL | SPI_CPHA;
+	master->setup = tegra_sflash_setup;
 	master->transfer_one_message = tegra_sflash_transfer_one_message;
 	master->num_chipselect = MAX_CHIP_SELECT;
 	master->bus_num = -1;
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index 651167f..8d51db8 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -284,8 +284,7 @@
 	unsigned max_len;
 	unsigned total_fifo_words;
 
-	bits_per_word = t->bits_per_word ? t->bits_per_word :
-						spi->bits_per_word;
+	bits_per_word = t->bits_per_word;
 	tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1;
 
 	if (bits_per_word == 8 || bits_per_word == 16) {
@@ -378,8 +377,7 @@
 	} else {
 		unsigned int bits_per_word;
 
-		bits_per_word = t->bits_per_word ? t->bits_per_word :
-						tspi->cur_spi->bits_per_word;
+		bits_per_word = t->bits_per_word;
 		for (count = 0; count < rx_full_count; count++) {
 			x = tegra_slink_readl(tspi, SLINK_RX_FIFO);
 			for (i = 0; (i < tspi->bytes_per_word); i++)
@@ -444,8 +442,7 @@
 		unsigned int x;
 		unsigned int rx_mask, bits_per_word;
 
-		bits_per_word = t->bits_per_word ? t->bits_per_word :
-						tspi->cur_spi->bits_per_word;
+		bits_per_word = t->bits_per_word;
 		rx_mask = (1 << bits_per_word) - 1;
 		for (count = 0; count < tspi->curr_dma_words; count++) {
 			x = tspi->rx_dma_buf[count];
@@ -728,9 +725,7 @@
 	unsigned long command2;
 
 	bits_per_word = t->bits_per_word;
-	speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
-	if (!speed)
-		speed = tspi->spi_max_frequency;
+	speed = t->speed_hz;
 	if (speed != tspi->cur_speed) {
 		clk_set_rate(tspi->clk, speed * 4);
 		tspi->cur_speed = speed;
@@ -841,6 +836,8 @@
 
 	BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
 
+	/* Set speed to the spi max fequency if spi device has not set */
+	spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
 	ret = pm_runtime_get_sync(tspi->dev);
 	if (ret < 0) {
 		dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index d5a3cbb..adb8530 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -189,9 +189,8 @@
 		unsigned int len = t->len;
 		unsigned int wsize;
 		u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
-		u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
+		u8 bits_per_word = t->bits_per_word;
 
-		bits_per_word = bits_per_word ? : 8;
 		wsize = bits_per_word >> 3; /* in bytes */
 
 		if (prev_speed_hz != speed_hz
@@ -316,9 +315,8 @@
 	/* check each transfer's parameters */
 	list_for_each_entry (t, &m->transfers, transfer_list) {
 		u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
-		u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
+		u8 bits_per_word = t->bits_per_word;
 
-		bits_per_word = bits_per_word ? : 8;
 		if (!t->tx_buf && !t->rx_buf && t->len)
 			return -EINVAL;
 		if (bits_per_word != 8 && bits_per_word != 16)
@@ -337,7 +335,7 @@
 	return 0;
 }
 
-static int __init txx9spi_probe(struct platform_device *dev)
+static int txx9spi_probe(struct platform_device *dev)
 {
 	struct spi_master *master;
 	struct txx9spi *c;
@@ -432,7 +430,7 @@
 	return ret;
 }
 
-static int __exit txx9spi_remove(struct platform_device *dev)
+static int txx9spi_remove(struct platform_device *dev)
 {
 	struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
 	struct txx9spi *c = spi_master_get_devdata(master);
@@ -450,7 +448,7 @@
 MODULE_ALIAS("platform:spi_txx9");
 
 static struct platform_driver txx9spi_driver = {
-	.remove = __exit_p(txx9spi_remove),
+	.remove = txx9spi_remove,
 	.driver = {
 		.name = "spi_txx9",
 		.owner = THIS_MODULE,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 19ee901..6f193b0 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -33,7 +33,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/export.h>
-#include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/ioport.h>
@@ -1059,15 +1059,14 @@
 #ifdef CONFIG_OF
 static int of_spi_register_master(struct spi_master *master)
 {
-	u16 nb;
-	int i, *cs;
+	int nb, i, *cs;
 	struct device_node *np = master->dev.of_node;
 
 	if (!np)
 		return 0;
 
 	nb = of_gpio_named_count(np, "cs-gpios");
-	master->num_chipselect = max(nb, master->num_chipselect);
+	master->num_chipselect = max(nb, (int)master->num_chipselect);
 
 	if (nb < 1)
 		return 0;
@@ -1080,7 +1079,8 @@
 	if (!master->cs_gpios)
 		return -ENOMEM;
 
-	memset(cs, -EINVAL, master->num_chipselect);
+	for (i = 0; i < master->num_chipselect; i++)
+		cs[i] = -EINVAL;
 
 	for (i = 0; i < nb; i++)
 		cs[i] = of_get_named_gpio(np, "cs-gpios", i);
@@ -1135,6 +1135,9 @@
 	if (master->num_chipselect == 0)
 		return -EINVAL;
 
+	if ((master->bus_num < 0) && master->dev.of_node)
+		master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
+
 	/* convention:  dynamically assigned bus IDs count down from the max */
 	if (master->bus_num < 0) {
 		/* FIXME switch to an IDR based scheme, something like
@@ -1366,12 +1369,14 @@
 	}
 
 	/**
-	 * Set transfer bits_per_word as spi device default if it is not
-	 * set for this transfer.
+	 * Set transfer bits_per_word and max speed as spi device default if
+	 * it is not set for this transfer.
 	 */
 	list_for_each_entry(xfer, &message->transfers, transfer_list) {
 		if (!xfer->bits_per_word)
 			xfer->bits_per_word = spi->bits_per_word;
+		if (!xfer->speed_hz)
+			xfer->speed_hz = spi->max_speed_hz;
 	}
 
 	message->spi = spi;
@@ -1656,7 +1661,8 @@
 	 * using the pre-allocated buffer or the transfer is too large.
 	 */
 	if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
-		local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx), GFP_KERNEL);
+		local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),
+				    GFP_KERNEL | GFP_DMA);
 		if (!local_buf)
 			return -ENOMEM;
 	} else {
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index 5d6f2ec..5ff3a4f 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -136,6 +136,11 @@
 
 	  If unsure, say N
 
+config SSB_SFLASH
+	bool "SSB serial flash support"
+	depends on SSB_DRIVER_MIPS && BROKEN
+	default y
+
 # Assumption: We are on embedded, if we compile the MIPS core.
 config SSB_EMBEDDED
 	bool
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
index 9159ba7..b1ddc11 100644
--- a/drivers/ssb/Makefile
+++ b/drivers/ssb/Makefile
@@ -11,6 +11,7 @@
 # built-in drivers
 ssb-y					+= driver_chipcommon.o
 ssb-y					+= driver_chipcommon_pmu.o
+ssb-$(CONFIG_SSB_SFLASH)		+= driver_chipcommon_sflash.o
 ssb-$(CONFIG_SSB_DRIVER_MIPS)		+= driver_mipscore.o
 ssb-$(CONFIG_SSB_DRIVER_EXTIF)		+= driver_extif.o
 ssb-$(CONFIG_SSB_DRIVER_PCICORE)	+= driver_pcicore.o
diff --git a/drivers/ssb/driver_chipcommon_sflash.c b/drivers/ssb/driver_chipcommon_sflash.c
new file mode 100644
index 0000000..720665c
--- /dev/null
+++ b/drivers/ssb/driver_chipcommon_sflash.c
@@ -0,0 +1,140 @@
+/*
+ * Sonics Silicon Backplane
+ * ChipCommon serial flash interface
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+struct ssb_sflash_tbl_e {
+	char *name;
+	u32 id;
+	u32 blocksize;
+	u16 numblocks;
+};
+
+static struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
+	{ "M25P20", 0x11, 0x10000, 4, },
+	{ "M25P40", 0x12, 0x10000, 8, },
+
+	{ "M25P16", 0x14, 0x10000, 32, },
+	{ "M25P32", 0x15, 0x10000, 64, },
+	{ "M25P64", 0x16, 0x10000, 128, },
+	{ "M25FL128", 0x17, 0x10000, 256, },
+	{ 0 },
+};
+
+static struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
+	{ "SST25WF512", 1, 0x1000, 16, },
+	{ "SST25VF512", 0x48, 0x1000, 16, },
+	{ "SST25WF010", 2, 0x1000, 32, },
+	{ "SST25VF010", 0x49, 0x1000, 32, },
+	{ "SST25WF020", 3, 0x1000, 64, },
+	{ "SST25VF020", 0x43, 0x1000, 64, },
+	{ "SST25WF040", 4, 0x1000, 128, },
+	{ "SST25VF040", 0x44, 0x1000, 128, },
+	{ "SST25VF040B", 0x8d, 0x1000, 128, },
+	{ "SST25WF080", 5, 0x1000, 256, },
+	{ "SST25VF080B", 0x8e, 0x1000, 256, },
+	{ "SST25VF016", 0x41, 0x1000, 512, },
+	{ "SST25VF032", 0x4a, 0x1000, 1024, },
+	{ "SST25VF064", 0x4b, 0x1000, 2048, },
+	{ 0 },
+};
+
+static struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
+	{ "AT45DB011", 0xc, 256, 512, },
+	{ "AT45DB021", 0x14, 256, 1024, },
+	{ "AT45DB041", 0x1c, 256, 2048, },
+	{ "AT45DB081", 0x24, 256, 4096, },
+	{ "AT45DB161", 0x2c, 512, 4096, },
+	{ "AT45DB321", 0x34, 512, 8192, },
+	{ "AT45DB642", 0x3c, 1024, 8192, },
+	{ 0 },
+};
+
+static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
+{
+	int i;
+	chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
+		       SSB_CHIPCO_FLASHCTL_START | opcode);
+	for (i = 0; i < 1000; i++) {
+		if (!(chipco_read32(cc, SSB_CHIPCO_FLASHCTL) &
+		      SSB_CHIPCO_FLASHCTL_BUSY))
+			return;
+		cpu_relax();
+	}
+	pr_err("SFLASH control command failed (timeout)!\n");
+}
+
+/* Initialize serial flash access */
+int ssb_sflash_init(struct ssb_chipcommon *cc)
+{
+	struct ssb_sflash_tbl_e *e;
+	u32 id, id2;
+
+	switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
+	case SSB_CHIPCO_FLASHT_STSER:
+		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
+
+		chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
+		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
+		id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
+
+		chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
+		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
+		id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
+
+		switch (id) {
+		case 0xbf:
+			for (e = ssb_sflash_sst_tbl; e->name; e++) {
+				if (e->id == id2)
+					break;
+			}
+			break;
+		case 0x13:
+			return -ENOTSUPP;
+		default:
+			for (e = ssb_sflash_st_tbl; e->name; e++) {
+				if (e->id == id)
+					break;
+			}
+			break;
+		}
+		if (!e->name) {
+			pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n",
+			       id, id2);
+			return -ENOTSUPP;
+		}
+
+		break;
+	case SSB_CHIPCO_FLASHT_ATSER:
+		ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
+		id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
+
+		for (e = ssb_sflash_at_tbl; e->name; e++) {
+			if (e->id == id)
+				break;
+		}
+		if (!e->name) {
+			pr_err("Unsupported Atmel serial flash (id: 0x%X)\n",
+			       id);
+			return -ENOTSUPP;
+		}
+
+		break;
+	default:
+		pr_err("Unsupported flash type\n");
+		return -ENOTSUPP;
+	}
+
+	pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
+		e->name, e->blocksize, e->numblocks);
+
+	pr_err("Serial flash support is not implemented yet!\n");
+
+	return -ENOTSUPP;
+}
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c
index eb27530..dc109de 100644
--- a/drivers/ssb/driver_gpio.c
+++ b/drivers/ssb/driver_gpio.c
@@ -74,6 +74,16 @@
 	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
 }
 
+static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+	if (bus->bustype == SSB_BUSTYPE_SSB)
+		return ssb_mips_irq(bus->chipco.dev) + 2;
+	else
+		return -EINVAL;
+}
+
 static int ssb_gpio_chipco_init(struct ssb_bus *bus)
 {
 	struct gpio_chip *chip = &bus->gpio;
@@ -86,6 +96,7 @@
 	chip->set		= ssb_gpio_chipco_set_value;
 	chip->direction_input	= ssb_gpio_chipco_direction_input;
 	chip->direction_output	= ssb_gpio_chipco_direction_output;
+	chip->to_irq		= ssb_gpio_chipco_to_irq;
 	chip->ngpio		= 16;
 	/* There is just one SoC in one device and its GPIO addresses should be
 	 * deterministic to address them more easily. The other buses could get
@@ -134,6 +145,16 @@
 	return 0;
 }
 
+static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+	if (bus->bustype == SSB_BUSTYPE_SSB)
+		return ssb_mips_irq(bus->extif.dev) + 2;
+	else
+		return -EINVAL;
+}
+
 static int ssb_gpio_extif_init(struct ssb_bus *bus)
 {
 	struct gpio_chip *chip = &bus->gpio;
@@ -144,6 +165,7 @@
 	chip->set		= ssb_gpio_extif_set_value;
 	chip->direction_input	= ssb_gpio_extif_direction_input;
 	chip->direction_output	= ssb_gpio_extif_direction_output;
+	chip->to_irq		= ssb_gpio_extif_to_irq;
 	chip->ngpio		= 5;
 	/* There is just one SoC in one device and its GPIO addresses should be
 	 * deterministic to address them more easily. The other buses could get
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
index 5bd05b1..33b37da 100644
--- a/drivers/ssb/driver_mipscore.c
+++ b/drivers/ssb/driver_mipscore.c
@@ -10,6 +10,7 @@
 
 #include <linux/ssb/ssb.h>
 
+#include <linux/mtd/physmap.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
@@ -17,6 +18,25 @@
 
 #include "ssb_private.h"
 
+static const char *part_probes[] = { "bcm47xxpart", NULL };
+
+static struct physmap_flash_data ssb_pflash_data = {
+	.part_probe_types	= part_probes,
+};
+
+static struct resource ssb_pflash_resource = {
+	.name	= "ssb_pflash",
+	.flags  = IORESOURCE_MEM,
+};
+
+struct platform_device ssb_pflash_dev = {
+	.name		= "physmap-flash",
+	.dev		= {
+		.platform_data  = &ssb_pflash_data,
+	},
+	.resource	= &ssb_pflash_resource,
+	.num_resources	= 1,
+};
 
 static inline u32 mips_read32(struct ssb_mipscore *mcore,
 			      u16 offset)
@@ -189,34 +209,43 @@
 static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
 {
 	struct ssb_bus *bus = mcore->dev->bus;
+	struct ssb_pflash *pflash = &mcore->pflash;
 
 	/* When there is no chipcommon on the bus there is 4MB flash */
 	if (!ssb_chipco_available(&bus->chipco)) {
-		mcore->pflash.present = true;
-		mcore->pflash.buswidth = 2;
-		mcore->pflash.window = SSB_FLASH1;
-		mcore->pflash.window_size = SSB_FLASH1_SZ;
-		return;
+		pflash->present = true;
+		pflash->buswidth = 2;
+		pflash->window = SSB_FLASH1;
+		pflash->window_size = SSB_FLASH1_SZ;
+		goto ssb_pflash;
 	}
 
 	/* There is ChipCommon, so use it to read info about flash */
 	switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
 	case SSB_CHIPCO_FLASHT_STSER:
 	case SSB_CHIPCO_FLASHT_ATSER:
-		pr_err("Serial flash not supported\n");
+		pr_debug("Found serial flash\n");
+		ssb_sflash_init(&bus->chipco);
 		break;
 	case SSB_CHIPCO_FLASHT_PARA:
 		pr_debug("Found parallel flash\n");
-		mcore->pflash.present = true;
-		mcore->pflash.window = SSB_FLASH2;
-		mcore->pflash.window_size = SSB_FLASH2_SZ;
+		pflash->present = true;
+		pflash->window = SSB_FLASH2;
+		pflash->window_size = SSB_FLASH2_SZ;
 		if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
 		               & SSB_CHIPCO_CFG_DS16) == 0)
-			mcore->pflash.buswidth = 1;
+			pflash->buswidth = 1;
 		else
-			mcore->pflash.buswidth = 2;
+			pflash->buswidth = 2;
 		break;
 	}
+
+ssb_pflash:
+	if (pflash->present) {
+		ssb_pflash_data.width = pflash->buswidth;
+		ssb_pflash_resource.start = pflash->window;
+		ssb_pflash_resource.end = pflash->window + pflash->window_size;
+	}
 }
 
 u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 24dc331..3b645b8 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -549,6 +549,14 @@
 		dev_idx++;
 	}
 
+#ifdef CONFIG_SSB_DRIVER_MIPS
+	if (bus->mipscore.pflash.present) {
+		err = platform_device_register(&ssb_pflash_dev);
+		if (err)
+			pr_err("Error registering parallel flash\n");
+	}
+#endif
+
 	return 0;
 error:
 	/* Unwind the already registered devices. */
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index da38305..466171b 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -217,6 +217,21 @@
 					     u32 ticks);
 extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
 
+/* driver_chipcommon_sflash.c */
+#ifdef CONFIG_SSB_SFLASH
+int ssb_sflash_init(struct ssb_chipcommon *cc);
+#else
+static inline int ssb_sflash_init(struct ssb_chipcommon *cc)
+{
+	pr_err("Serial flash not supported\n");
+	return 0;
+}
+#endif /* CONFIG_SSB_SFLASH */
+
+#ifdef CONFIG_SSB_DRIVER_MIPS
+extern struct platform_device ssb_pflash_dev;
+#endif
+
 #ifdef CONFIG_SSB_DRIVER_EXTIF
 extern u32 ssb_extif_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks);
 extern u32 ssb_extif_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c
index a3b91c7..4e470d4 100644
--- a/drivers/staging/bcm/Bcmnet.c
+++ b/drivers/staging/bcm/Bcmnet.c
@@ -145,8 +145,8 @@
 	struct bcm_interface_adapter *psIntfAdapter = Adapter->pvInterfaceAdapter;
 	struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 	snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u",
 		 Adapter->uiFlashLayoutMajorVersion,
 		 Adapter->uiFlashLayoutMinorVersion);
diff --git a/drivers/staging/ccg/u_ether.c b/drivers/staging/ccg/u_ether.c
index d0dabcf..fed7886 100644
--- a/drivers/staging/ccg/u_ether.c
+++ b/drivers/staging/ccg/u_ether.c
@@ -157,12 +157,12 @@
 
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
-	struct eth_dev	*dev = netdev_priv(net);
+	struct eth_dev *dev = netdev_priv(net);
 
-	strlcpy(p->driver, "g_ether", sizeof p->driver);
-	strlcpy(p->version, UETH__VERSION, sizeof p->version);
-	strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
-	strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+	strlcpy(p->driver, "g_ether", sizeof(p->driver));
+	strlcpy(p->version, UETH__VERSION, sizeof(p->version));
+	strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+	strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
 }
 
 /* REVISIT can also support:
diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c
index 1a1f5c7..7b13359 100644
--- a/drivers/staging/csr/bh.c
+++ b/drivers/staging/csr/bh.c
@@ -15,7 +15,7 @@
  */
 #include "csr_wifi_hip_unifi.h"
 #include "unifi_priv.h"
-
+#include <linux/sched/rt.h>
 
 /*
  * ---------------------------------------------------------------------------
diff --git a/drivers/staging/csr/unifi_sme.c b/drivers/staging/csr/unifi_sme.c
index 7c6c413..49395da 100644
--- a/drivers/staging/csr/unifi_sme.c
+++ b/drivers/staging/csr/unifi_sme.c
@@ -15,7 +15,7 @@
 #include "unifi_priv.h"
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
-
+#include <linux/sched/rt.h>
 
 
 
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 84bbcd4..a0a30b3 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -3560,15 +3560,15 @@
 	regs_buff[num++] = readl(&aregs->rxdma.fbr1_min_des);
 }
 
-#define ET131X_DRVINFO_LEN 32 /* value from ethtool.h */
 static void et131x_get_drvinfo(struct net_device *netdev,
 			       struct ethtool_drvinfo *info)
 {
 	struct et131x_adapter *adapter = netdev_priv(netdev);
 
-	strncpy(info->driver, DRIVER_NAME, ET131X_DRVINFO_LEN);
-	strncpy(info->version, DRIVER_VERSION, ET131X_DRVINFO_LEN);
-	strncpy(info->bus_info, pci_name(adapter->pdev), ET131X_DRVINFO_LEN);
+	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(adapter->pdev),
+		sizeof(info->bus_info));
 }
 
 static struct ethtool_ops et131x_ethtool_ops = {
@@ -3917,7 +3917,7 @@
 	}
 
 	phydev = phy_connect(netdev, dev_name(&phydev->dev),
-			&et131x_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+			     &et131x_adjust_link, PHY_INTERFACE_MODE_MII);
 
 	if (IS_ERR(phydev)) {
 		dev_err(&adapter->pdev->dev, "Could not attach to PHY\n");
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
index 86a680c..67ca5c9 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
@@ -2077,11 +2077,12 @@
 	struct ft1000_info *ft_info;
 	ft_info = netdev_priv(dev);
 
-	snprintf(info->driver, 32, "ft1000");
-	snprintf(info->bus_info, ETHTOOL_BUSINFO_LEN, "PCMCIA 0x%lx",
+	strlcpy(info->driver, "ft1000", sizeof(info->driver));
+	snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
 		 dev->base_addr);
-	snprintf(info->fw_version, 32, "%d.%d.%d.%d", ft_info->DspVer[0],
-		 ft_info->DspVer[1], ft_info->DspVer[2], ft_info->DspVer[3]);
+	snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d.%d.%d",
+		 ft_info->DspVer[0], ft_info->DspVer[1], ft_info->DspVer[2],
+		 ft_info->DspVer[3]);
 }
 
 static u32 ft1000_get_link(struct net_device *dev)
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig
index 7d32075..d44d3ad 100644
--- a/drivers/staging/iio/trigger/Kconfig
+++ b/drivers/staging/iio/trigger/Kconfig
@@ -21,7 +21,6 @@
 config IIO_SYSFS_TRIGGER
 	tristate "SYSFS trigger"
 	depends on SYSFS
-	depends on HAVE_IRQ_WORK
 	select IRQ_WORK
 	help
 	  Provides support for using SYSFS entry as IIO triggers.
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index f15b31b..83b1030 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -46,9 +46,9 @@
 static void cvm_oct_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
 {
-	strcpy(info->driver, "cavium-ethernet");
-	strcpy(info->version, OCTEON_ETHERNET_VERSION);
-	strcpy(info->bus_info, "Builtin");
+	strlcpy(info->driver, "cavium-ethernet", sizeof(info->driver));
+	strlcpy(info->version, OCTEON_ETHERNET_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, "Builtin", sizeof(info->bus_info));
 }
 
 static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index ef32dc1..9a2ec25 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -453,12 +453,10 @@
 	if (priv->of_node)
 		mac = of_get_mac_address(priv->of_node);
 
-	if (mac && is_valid_ether_addr(mac)) {
+	if (mac && is_valid_ether_addr(mac))
 		memcpy(dev->dev_addr, mac, ETH_ALEN);
-		dev->addr_assign_type &= ~NET_ADDR_RANDOM;
-	} else {
+	else
 		eth_hw_addr_random(dev);
-	}
 
 	/*
 	 * Force the interface to use the POW send if always_use_pow
diff --git a/drivers/staging/omapdrm/Kconfig b/drivers/staging/omapdrm/Kconfig
index b724a41..09f65dc 100644
--- a/drivers/staging/omapdrm/Kconfig
+++ b/drivers/staging/omapdrm/Kconfig
@@ -3,8 +3,8 @@
 	tristate "OMAP DRM"
 	depends on DRM && !CONFIG_FB_OMAP2
 	depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
+	depends on OMAP2_DSS
 	select DRM_KMS_HELPER
-	select OMAP2_DSS
 	select FB_SYS_FILLRECT
 	select FB_SYS_COPYAREA
 	select FB_SYS_IMAGEBLIT
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
index cac3207..adb8da5 100644
--- a/drivers/staging/quickstart/quickstart.c
+++ b/drivers/staging/quickstart/quickstart.c
@@ -296,7 +296,7 @@
 	return ret;
 }
 
-static int quickstart_acpi_remove(struct acpi_device *device, int type)
+static int quickstart_acpi_remove(struct acpi_device *device)
 {
 	acpi_status status;
 	struct quickstart_acpi *quickstart;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
index 36452fb..0cfb3ec 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
@@ -34,9 +34,9 @@
 {
 	struct r8192_priv *priv = rtllib_priv(dev);
 
-	strcpy(info->driver, DRV_NAME);
-	strcpy(info->version, DRV_VERSION);
-	strcpy(info->bus_info, pci_name(priv->pdev));
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info));
 }
 
 static u32 rtl819x_ethtool_get_link(struct net_device *dev)
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index fb42140..235cc2a 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -457,17 +457,17 @@
 
 static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-    strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
-    strncpy(info->version, DRV_VERSION_STR, sizeof(info->version) - 1);
-//	strncpy(info.fw_version, priv->fw_name,
-//	sizeof(info.fw_version) - 1);
+    strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+    strlcpy(info->version, DRV_VERSION_STR, sizeof(info->version));
+//	strlcpy(info.fw_version, priv->fw_name,
+//	sizeof(info.fw_version));
 
     if (dev->dev.parent) {
     	dev_set_name(dev->dev.parent, "%s", info->bus_info);
-	//strncpy(info->bus_info, dev->dev.parent->bus_id,
-	//	sizeof(info->bus_info) - 1);
+	//strlcpy(info->bus_info, dev->dev.parent->bus_id,
+	//	sizeof(info->bus_info));
     } else {
-	snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+	snprintf(info->bus_info, sizeof(info->bus_info),
 		"PCMCIA FIXME");
 //		    "PCMCIA 0x%lx", priv->hw.iobase);
     }
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 1d31eab..f1bce18 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -424,7 +424,7 @@
 			goto exit;
 		}
 
-		cfg80211_put_bss(bss);
+		cfg80211_put_bss(wiphy, bss);
 	}
 
 	if (result)
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 7ce3197..dd6277e 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -179,8 +179,7 @@
 
 static void max3100_dowork(struct max3100_port *s)
 {
-	if (!s->force_end_work && !work_pending(&s->work) &&
-	    !freezing(current) && !s->suspending)
+	if (!s->force_end_work && !freezing(current) && !s->suspending)
 		queue_work(s->workqueue, &s->work);
 }
 
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index b3c4a25..814655e 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -15,6 +15,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
@@ -41,6 +42,7 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/uaccess.h>
+#include <linux/moduleparam.h>
 
 #include <asm/ptrace.h>
 #include <asm/irq_regs.h>
@@ -577,8 +579,71 @@
 	bool active;
 	bool need_reinject;
 	bool reinjecting;
+
+	/* reset sequence handling */
+	bool reset_canceled;
+	unsigned long reset_keybit[BITS_TO_LONGS(KEY_CNT)];
+	int reset_seq_len;
+	int reset_seq_cnt;
+	int reset_seq_version;
 };
 
+#define SYSRQ_KEY_RESET_MAX	20 /* Should be plenty */
+static unsigned short sysrq_reset_seq[SYSRQ_KEY_RESET_MAX];
+static unsigned int sysrq_reset_seq_len;
+static unsigned int sysrq_reset_seq_version = 1;
+
+static void sysrq_parse_reset_sequence(struct sysrq_state *state)
+{
+	int i;
+	unsigned short key;
+
+	state->reset_seq_cnt = 0;
+
+	for (i = 0; i < sysrq_reset_seq_len; i++) {
+		key = sysrq_reset_seq[i];
+
+		if (key == KEY_RESERVED || key > KEY_MAX)
+			break;
+
+		__set_bit(key, state->reset_keybit);
+		state->reset_seq_len++;
+
+		if (test_bit(key, state->key_down))
+			state->reset_seq_cnt++;
+	}
+
+	/* Disable reset until old keys are not released */
+	state->reset_canceled = state->reset_seq_cnt != 0;
+
+	state->reset_seq_version = sysrq_reset_seq_version;
+}
+
+static bool sysrq_detect_reset_sequence(struct sysrq_state *state,
+					unsigned int code, int value)
+{
+	if (!test_bit(code, state->reset_keybit)) {
+		/*
+		 * Pressing any key _not_ in reset sequence cancels
+		 * the reset sequence.
+		 */
+		if (value && state->reset_seq_cnt)
+			state->reset_canceled = true;
+	} else if (value == 0) {
+		/* key release */
+		if (--state->reset_seq_cnt == 0)
+			state->reset_canceled = false;
+	} else if (value == 1) {
+		/* key press, not autorepeat */
+		if (++state->reset_seq_cnt == state->reset_seq_len &&
+		    !state->reset_canceled) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 static void sysrq_reinject_alt_sysrq(struct work_struct *work)
 {
 	struct sysrq_state *sysrq =
@@ -605,11 +670,104 @@
 	}
 }
 
+static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
+				  unsigned int code, int value)
+{
+	bool was_active = sysrq->active;
+	bool suppress;
+
+	switch (code) {
+
+	case KEY_LEFTALT:
+	case KEY_RIGHTALT:
+		if (!value) {
+			/* One of ALTs is being released */
+			if (sysrq->active && code == sysrq->alt_use)
+				sysrq->active = false;
+
+			sysrq->alt = KEY_RESERVED;
+
+		} else if (value != 2) {
+			sysrq->alt = code;
+			sysrq->need_reinject = false;
+		}
+		break;
+
+	case KEY_SYSRQ:
+		if (value == 1 && sysrq->alt != KEY_RESERVED) {
+			sysrq->active = true;
+			sysrq->alt_use = sysrq->alt;
+			/*
+			 * If nothing else will be pressed we'll need
+			 * to re-inject Alt-SysRq keysroke.
+			 */
+			sysrq->need_reinject = true;
+		}
+
+		/*
+		 * Pretend that sysrq was never pressed at all. This
+		 * is needed to properly handle KGDB which will try
+		 * to release all keys after exiting debugger. If we
+		 * do not clear key bit it KGDB will end up sending
+		 * release events for Alt and SysRq, potentially
+		 * triggering print screen function.
+		 */
+		if (sysrq->active)
+			clear_bit(KEY_SYSRQ, sysrq->handle.dev->key);
+
+		break;
+
+	default:
+		if (sysrq->active && value && value != 2) {
+			sysrq->need_reinject = false;
+			__handle_sysrq(sysrq_xlate[code], true);
+		}
+		break;
+	}
+
+	suppress = sysrq->active;
+
+	if (!sysrq->active) {
+
+		/*
+		 * See if reset sequence has changed since the last time.
+		 */
+		if (sysrq->reset_seq_version != sysrq_reset_seq_version)
+			sysrq_parse_reset_sequence(sysrq);
+
+		/*
+		 * If we are not suppressing key presses keep track of
+		 * keyboard state so we can release keys that have been
+		 * pressed before entering SysRq mode.
+		 */
+		if (value)
+			set_bit(code, sysrq->key_down);
+		else
+			clear_bit(code, sysrq->key_down);
+
+		if (was_active)
+			schedule_work(&sysrq->reinject_work);
+
+		if (sysrq_detect_reset_sequence(sysrq, code, value)) {
+			/* Force emergency reboot */
+			__handle_sysrq(sysrq_xlate[KEY_B], false);
+		}
+
+	} else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) {
+		/*
+		 * Pass on release events for keys that was pressed before
+		 * entering SysRq mode.
+		 */
+		suppress = false;
+	}
+
+	return suppress;
+}
+
 static bool sysrq_filter(struct input_handle *handle,
 			 unsigned int type, unsigned int code, int value)
 {
 	struct sysrq_state *sysrq = handle->private;
-	bool was_active = sysrq->active;
 	bool suppress;
 
 	/*
@@ -626,79 +784,7 @@
 		break;
 
 	case EV_KEY:
-		switch (code) {
-
-		case KEY_LEFTALT:
-		case KEY_RIGHTALT:
-			if (!value) {
-				/* One of ALTs is being released */
-				if (sysrq->active && code == sysrq->alt_use)
-					sysrq->active = false;
-
-				sysrq->alt = KEY_RESERVED;
-
-			} else if (value != 2) {
-				sysrq->alt = code;
-				sysrq->need_reinject = false;
-			}
-			break;
-
-		case KEY_SYSRQ:
-			if (value == 1 && sysrq->alt != KEY_RESERVED) {
-				sysrq->active = true;
-				sysrq->alt_use = sysrq->alt;
-				/*
-				 * If nothing else will be pressed we'll need
-				 * to re-inject Alt-SysRq keysroke.
-				 */
-				sysrq->need_reinject = true;
-			}
-
-			/*
-			 * Pretend that sysrq was never pressed at all. This
-			 * is needed to properly handle KGDB which will try
-			 * to release all keys after exiting debugger. If we
-			 * do not clear key bit it KGDB will end up sending
-			 * release events for Alt and SysRq, potentially
-			 * triggering print screen function.
-			 */
-			if (sysrq->active)
-				clear_bit(KEY_SYSRQ, handle->dev->key);
-
-			break;
-
-		default:
-			if (sysrq->active && value && value != 2) {
-				sysrq->need_reinject = false;
-				__handle_sysrq(sysrq_xlate[code], true);
-			}
-			break;
-		}
-
-		suppress = sysrq->active;
-
-		if (!sysrq->active) {
-			/*
-			 * If we are not suppressing key presses keep track of
-			 * keyboard state so we can release keys that have been
-			 * pressed before entering SysRq mode.
-			 */
-			if (value)
-				set_bit(code, sysrq->key_down);
-			else
-				clear_bit(code, sysrq->key_down);
-
-			if (was_active)
-				schedule_work(&sysrq->reinject_work);
-
-		} else if (value == 0 &&
-			   test_and_clear_bit(code, sysrq->key_down)) {
-			/*
-			 * Pass on release events for keys that was pressed before
-			 * entering SysRq mode.
-			 */
-			suppress = false;
-		}
+		suppress = sysrq_handle_keypress(sysrq, code, value);
 		break;
 
 	default:
@@ -786,7 +872,20 @@
 
 static inline void sysrq_register_handler(void)
 {
+	extern unsigned short platform_sysrq_reset_seq[] __weak;
+	unsigned short key;
 	int error;
+	int i;
+
+	if (platform_sysrq_reset_seq) {
+		for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
+			key = platform_sysrq_reset_seq[i];
+			if (key == KEY_RESERVED || key > KEY_MAX)
+				break;
+
+			sysrq_reset_seq[sysrq_reset_seq_len++] = key;
+		}
+	}
 
 	error = input_register_handler(&sysrq_handler);
 	if (error)
@@ -803,6 +902,36 @@
 	}
 }
 
+static int sysrq_reset_seq_param_set(const char *buffer,
+				     const struct kernel_param *kp)
+{
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buffer, 0, &val);
+	if (error < 0)
+		return error;
+
+	if (val > KEY_MAX)
+		return -EINVAL;
+
+	*((unsigned short *)kp->arg) = val;
+	sysrq_reset_seq_version++;
+
+	return 0;
+}
+
+static struct kernel_param_ops param_ops_sysrq_reset_seq = {
+	.get	= param_get_ushort,
+	.set	= sysrq_reset_seq_param_set,
+};
+
+#define param_check_sysrq_reset_seq(name, p)	\
+	__param_check(name, p, unsigned short)
+
+module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
+			 &sysrq_reset_seq_len, 0644);
+
 #else
 
 static inline void sysrq_register_handler(void)
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 4ec3c0d..a0aa721 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -159,12 +159,12 @@
 
 static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
-	struct eth_dev	*dev = netdev_priv(net);
+	struct eth_dev *dev = netdev_priv(net);
 
-	strlcpy(p->driver, "g_ether", sizeof p->driver);
-	strlcpy(p->version, UETH__VERSION, sizeof p->version);
-	strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
-	strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+	strlcpy(p->driver, "g_ether", sizeof(p->driver));
+	strlcpy(p->version, UETH__VERSION, sizeof(p->version));
+	strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+	strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
 }
 
 /* REVISIT can also support:
diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
index f088d4c..d843296 100644
--- a/drivers/video/backlight/apple_bl.c
+++ b/drivers/video/backlight/apple_bl.c
@@ -196,7 +196,7 @@
 	return 0;
 }
 
-static int apple_bl_remove(struct acpi_device *dev, int type)
+static int apple_bl_remove(struct acpi_device *dev)
 {
 	backlight_device_unregister(apple_backlight_device);
 
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index 4ef18e2..2d0d144 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -1121,8 +1121,7 @@
 
 	disable_irq(dp->irq);
 
-	if (work_pending(&dp->hotplug_work))
-		flush_work(&dp->hotplug_work);
+	flush_work(&dp->hotplug_work);
 
 	if (pdev->dev.of_node) {
 		if (dp->phy_addr)
@@ -1144,8 +1143,7 @@
 	struct exynos_dp_platdata *pdata = dev->platform_data;
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-	if (work_pending(&dp->hotplug_work))
-		flush_work(&dp->hotplug_work);
+	flush_work(&dp->hotplug_work);
 
 	if (dev->of_node) {
 		if (dp->phy_addr)
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 18688c1..d7d66ef 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -538,6 +538,7 @@
 	FEAT_ALPHA_FIXED_ZORDER,
 	FEAT_FIFO_MERGE,
 	FEAT_OMAP3_DSI_FIFO_BUG,
+	FEAT_DPI_USES_VDDS_DSI,
 };
 
 static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 74d77df..22f77c5 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -1787,7 +1787,7 @@
 	int rc;
 	uint64_t callback_via;
 	if (xen_have_vector_callback) {
-		callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK);
+		callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
 		rc = xen_set_callback_via(callback_via);
 		if (rc) {
 			printk(KERN_ERR "Request for Xen HVM callback vector"
@@ -1798,8 +1798,9 @@
 		printk(KERN_INFO "Xen HVM callback vector for event delivery is "
 				"enabled\n");
 		/* in the restore case the vector has already been allocated */
-		if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors))
-			alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector);
+		if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
+			alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
+					xen_hvm_callback_vector);
 	}
 }
 #else
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c
index 067fcfa..5a27a45 100644
--- a/drivers/xen/pcpu.c
+++ b/drivers/xen/pcpu.c
@@ -278,8 +278,7 @@
 	 * Only those at cpu present map has its sys interface.
 	 */
 	if (info->flags & XEN_PCPU_FLAGS_INVALID) {
-		if (pcpu)
-			unregister_and_remove_pcpu(pcpu);
+		unregister_and_remove_pcpu(pcpu);
 		return 0;
 	}
 
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index da39191..c763479 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -140,8 +140,7 @@
 	return 0;
 }
 
-static int acpi_pad_remove(struct acpi_device *device,
-	int type)
+static int acpi_pad_remove(struct acpi_device *device)
 {
 	mutex_lock(&xen_cpu_lock);
 	xen_acpi_pad_idle_cpus(0);