소스 검색

Update v4.19 patches

Maximilian Luz 5 년 전
부모
커밋
0d20b9d65a

+ 5 - 5
patches/4.19/0009-surface3-power.patch → patches/4.19/0001-surface3-power.patch

@@ -1,7 +1,7 @@
-From e40a7fdd66839e4adfac65ca1ab770d50551d95c Mon Sep 17 00:00:00 2001
+From 1c901a05cc530f763b1e78f2dd3608acccb3f74d Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 28 Sep 2019 18:00:43 +0200
-Subject: [PATCH 09/13] surface3-power
+Subject: [PATCH 01/10] surface3-power
 
 ---
  drivers/platform/x86/Kconfig          |   7 +
@@ -11,7 +11,7 @@ Subject: [PATCH 09/13] surface3-power
  create mode 100644 drivers/platform/x86/surface3_power.c
 
 diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
-index ea17f993320e..7cee1015981d 100644
+index 1e2524de6a63..2ad19dc64a4a 100644
 --- a/drivers/platform/x86/Kconfig
 +++ b/drivers/platform/x86/Kconfig
 @@ -1160,6 +1160,13 @@ config SURFACE_3_BUTTON
@@ -29,7 +29,7 @@ index ea17f993320e..7cee1015981d 100644
  	tristate "Intel P-Unit IPC Driver"
  	---help---
 diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
-index ddc2fbfaf110..cbea9579c1d2 100644
+index dc29af4d8e2f..2ea90039a3e4 100644
 --- a/drivers/platform/x86/Makefile
 +++ b/drivers/platform/x86/Makefile
 @@ -81,6 +81,7 @@ obj-$(CONFIG_INTEL_PMC_IPC)	+= intel_pmc_ipc.o
@@ -651,5 +651,5 @@ index 000000000000..e0af01a60302
 +MODULE_DESCRIPTION("mshw0011 driver");
 +MODULE_LICENSE("GPL v2");
 -- 
-2.24.1
+2.25.0
 

+ 3 - 3
patches/4.19/0013-surface3-spi-dma.patch → patches/4.19/0002-surface3-spi.patch

@@ -1,7 +1,7 @@
-From 981e1123997405f871305892fe26d79ee64abf1d Mon Sep 17 00:00:00 2001
+From 083cd0c2a5211048c01179b7c0fb5f36d9891563 Mon Sep 17 00:00:00 2001
 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
 Date: Fri, 6 Dec 2019 23:10:30 +0900
-Subject: [PATCH 13/13] surface3-spi dma
+Subject: [PATCH 02/10] surface3-spi
 
 ---
  drivers/input/touchscreen/surface3_spi.c | 26 ++++++++++++++++++++++++
@@ -59,5 +59,5 @@ index 5db0f1c4ef38..8935ddbc2357 100644
  }
  
 -- 
-2.24.1
+2.25.0
 

+ 69 - 0
patches/4.19/0003-surface3-oemb.patch

@@ -0,0 +1,69 @@
+From 8b9a6f5b6e20c3a6c6755bc7937ac6b189dc8afe Mon Sep 17 00:00:00 2001
+From: Chih-Wei Huang <cwhuang@linux.org.tw>
+Date: Tue, 18 Sep 2018 11:01:37 +0800
+Subject: [PATCH 03/10] surface3-oemb
+
+---
+ drivers/platform/x86/surface3-wmi.c               | 7 +++++++
+ sound/soc/codecs/rt5645.c                         | 9 +++++++++
+ sound/soc/intel/common/soc-acpi-intel-cht-match.c | 6 ++++++
+ 3 files changed, 22 insertions(+)
+
+diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c
+index 25b176996cb7..58d11877677f 100644
+--- a/drivers/platform/x86/surface3-wmi.c
++++ b/drivers/platform/x86/surface3-wmi.c
+@@ -41,6 +41,13 @@ static const struct dmi_system_id surface3_dmi_table[] = {
+ 			DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ 		},
+ 	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
++			DMI_MATCH(DMI_SYS_VENDOR, "OEMB"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"),
++		},
++	},
+ #endif
+ 	{ }
+ };
+diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
+index 7e3b47eeea04..85c0731dfd4b 100644
+--- a/sound/soc/codecs/rt5645.c
++++ b/sound/soc/codecs/rt5645.c
+@@ -3706,6 +3706,15 @@ static const struct dmi_system_id dmi_platform_data[] = {
+ 		},
+ 		.driver_data = (void *)&intel_braswell_platform_data,
+ 	},
++	{
++		.ident = "Microsoft Surface 3",
++		.matches = {
++			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
++			DMI_MATCH(DMI_SYS_VENDOR, "OEMB"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"),
++		},
++		.driver_data = (void *)&intel_braswell_platform_data,
++	},
+ 	{
+ 		/*
+ 		 * Match for the GPDwin which unfortunately uses somewhat
+diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+index 91bb99b69601..c9f966bacfc1 100644
+--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
++++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+@@ -35,6 +35,12 @@ static const struct dmi_system_id cht_table[] = {
+ 			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ 			DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
+ 		},
++		.callback = cht_surface_quirk_cb,
++		.matches = {
++			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
++			DMI_MATCH(DMI_SYS_VENDOR, "OEMB"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"),
++		},
+ 	},
+ 	{ }
+ };
+-- 
+2.25.0
+

+ 0 - 2753
patches/4.19/0004-cameras.patch

@@ -1,2753 +0,0 @@
-From aba5b117008ee57e9d9d65e971ea75cb9b1bed34 Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sat, 28 Sep 2019 17:53:54 +0200
-Subject: [PATCH 04/13] cameras
-
----
- drivers/media/usb/uvc/uvc_driver.c |   40 +
- drivers/staging/Makefile           |    1 +
- drivers/staging/ov5693/Kconfig     |   10 +
- drivers/staging/ov5693/Makefile    |    5 +
- drivers/staging/ov5693/ad5823.c    |  218 +++++
- drivers/staging/ov5693/ad5823.h    |   90 ++
- drivers/staging/ov5693/ov5693.c    | 1461 ++++++++++++++++++++++++++++
- drivers/staging/ov5693/ov5693.h    |  848 ++++++++++++++++
- 8 files changed, 2673 insertions(+)
- create mode 100644 drivers/staging/ov5693/Kconfig
- create mode 100644 drivers/staging/ov5693/Makefile
- create mode 100644 drivers/staging/ov5693/ad5823.c
- create mode 100644 drivers/staging/ov5693/ad5823.h
- create mode 100644 drivers/staging/ov5693/ov5693.c
- create mode 100644 drivers/staging/ov5693/ov5693.h
-
-diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
-index 063e229ead5e..355777bb8ba8 100644
---- a/drivers/media/usb/uvc/uvc_driver.c
-+++ b/drivers/media/usb/uvc/uvc_driver.c
-@@ -2389,6 +2389,46 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
-  * though they are compliant.
-  */
- static const struct usb_device_id uvc_ids[] = {
-+	/* Microsoft Surface Pro 3 Front */
-+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-+				| USB_DEVICE_ID_MATCH_INT_INFO,
-+	  .idVendor             = 0x045e,
-+	  .idProduct            = 0x07be,
-+	  .bInterfaceClass      = USB_CLASS_VIDEO,
-+	  .bInterfaceSubClass   = 1,
-+	  .bInterfaceProtocol   = 1 },
-+	/* Microsoft Surface Pro 3 Rear */
-+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-+				| USB_DEVICE_ID_MATCH_INT_INFO,
-+	  .idVendor             = 0x045e,
-+	  .idProduct            = 0x07bf,
-+	  .bInterfaceClass      = USB_CLASS_VIDEO,
-+	  .bInterfaceSubClass   = 1,
-+	  .bInterfaceProtocol   = 1 },
-+	/* Microsoft Surface Pro 4 Cam */
-+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-+				| USB_DEVICE_ID_MATCH_INT_INFO,
-+	  .idVendor             = 0x045e,
-+	  .idProduct            = 0x090c,
-+	  .bInterfaceClass      = USB_CLASS_VIDEO,
-+	  .bInterfaceSubClass   = 1,
-+	  .bInterfaceProtocol   = 1 },
-+	/* Microsoft Surface Book Cam 1 */
-+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-+				| USB_DEVICE_ID_MATCH_INT_INFO,
-+	  .idVendor             = 0x045e,
-+	  .idProduct            = 0x090b,
-+	  .bInterfaceClass      = USB_CLASS_VIDEO,
-+	  .bInterfaceSubClass   = 1,
-+	  .bInterfaceProtocol   = 1 },
-+	/* Microsoft Surface Book Cam 2 */
-+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-+				| USB_DEVICE_ID_MATCH_INT_INFO,
-+	  .idVendor             = 0x045e,
-+	  .idProduct            = 0x091a,
-+	  .bInterfaceClass      = USB_CLASS_VIDEO,
-+	  .bInterfaceSubClass   = 1,
-+	  .bInterfaceProtocol   = 1 },
- 	/* LogiLink Wireless Webcam */
- 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
- 				| USB_DEVICE_ID_MATCH_INT_INFO,
-diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
-index ab0cbe8815b1..96c4c669a93f 100644
---- a/drivers/staging/Makefile
-+++ b/drivers/staging/Makefile
-@@ -53,3 +53,4 @@ obj-$(CONFIG_SOC_MT7621)	+= mt7621-dts/
- obj-$(CONFIG_STAGING_GASKET_FRAMEWORK)	+= gasket/
- obj-$(CONFIG_XIL_AXIS_FIFO)	+= axis-fifo/
- obj-$(CONFIG_EROFS_FS)		+= erofs/
-+obj-$(CONFIG_VIDEO_OV5693)	+= ov5693/
-diff --git a/drivers/staging/ov5693/Kconfig b/drivers/staging/ov5693/Kconfig
-new file mode 100644
-index 000000000000..96000f112c4d
---- /dev/null
-+++ b/drivers/staging/ov5693/Kconfig
-@@ -0,0 +1,10 @@
-+config VIDEO_OV5693
-+       tristate "Omnivision ov5693 sensor support"
-+       depends on I2C && VIDEO_V4L2
-+       ---help---
-+         This is a Video4Linux2 sensor-level driver for the Micron
-+         ov5693 5 Mpixel camera.
-+
-+         ov5693 is video camera sensor.
-+
-+         It currently only works with the atomisp driver.
-diff --git a/drivers/staging/ov5693/Makefile b/drivers/staging/ov5693/Makefile
-new file mode 100644
-index 000000000000..d8a63faa591f
---- /dev/null
-+++ b/drivers/staging/ov5693/Makefile
-@@ -0,0 +1,5 @@
-+obj-$(CONFIG_VIDEO_OV5693) += ov569x.o
-+
-+ov569x-objs := ov5693.o ad5823.o
-+
-+ccflags-y += -Werror
-diff --git a/drivers/staging/ov5693/ad5823.c b/drivers/staging/ov5693/ad5823.c
-new file mode 100644
-index 000000000000..7c34c36e77e5
---- /dev/null
-+++ b/drivers/staging/ov5693/ad5823.c
-@@ -0,0 +1,218 @@
-+#include <asm/intel-mid.h>
-+#include <linux/bitops.h>
-+#include <linux/device.h>
-+#include <linux/delay.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/gpio.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/kmod.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/string.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <media/v4l2-chip-ident.h>
-+#include <media/v4l2-device.h>
-+
-+#include "ad5823.h"
-+
-+static struct ad5823_device ad5823_dev;
-+static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
-+{
-+	struct i2c_msg msg;
-+	u8 buf[2];
-+	buf[0] = reg;
-+	buf[1] = val;
-+	msg.addr = AD5823_VCM_ADDR;
-+	msg.flags = 0;
-+	msg.len = AD5823_8BIT;
-+	msg.buf = &buf[0];
-+
-+	if (i2c_transfer(client->adapter, &msg, 1) != 1)
-+		return -EIO;
-+	return 0;
-+}
-+
-+static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
-+{
-+	struct i2c_msg msg[2];
-+	u8 buf[2];
-+	buf[0] = reg;
-+	buf[1] = 0;
-+
-+	msg[0].addr = AD5823_VCM_ADDR;
-+	msg[0].flags = 0;
-+	msg[0].len = AD5823_8BIT;
-+	msg[0].buf = &buf[0];
-+
-+	msg[1].addr = AD5823_VCM_ADDR;
-+	msg[1].flags = I2C_M_RD;
-+	msg[1].len = AD5823_8BIT;
-+	msg[1].buf = &buf[1];
-+	*val = 0;
-+	if (i2c_transfer(client->adapter, msg, 2) != 2)
-+		return -EIO;
-+	*val = buf[1];
-+	return 0;
-+}
-+
-+int ad5823_vcm_power_up(struct v4l2_subdev *sd)
-+{
-+	int ret = -ENODEV;
-+
-+	/* Enable power */
-+	if (ad5823_dev.platform_data)
-+		ret = ad5823_dev.platform_data->power_ctrl(sd, 1);
-+	/*
-+	 * waiting time requested by AD5823(vcm)
-+	 */
-+	usleep_range(1000, 2000);
-+	return ret;
-+}
-+
-+int ad5823_vcm_power_down(struct v4l2_subdev *sd)
-+{
-+	int ret = -ENODEV;
-+
-+	if (ad5823_dev.platform_data)
-+		ret = ad5823_dev.platform_data->power_ctrl(sd, 0);
-+
-+	return ret;
-+}
-+
-+
-+int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
-+{
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int ret = -EINVAL;
-+	u8 vcm_code;
-+	u8 vcm_mode_reg_val[4] = {
-+		AD5823_ARC_RES0,
-+		AD5823_ARC_RES1,
-+		AD5823_ARC_RES2,
-+		AD5823_ESRC
-+	};
-+
-+	if (ad5823_dev.vcm_mode != AD5823_DIRECT) {
-+		ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
-+						AD5823_RING_CTRL_ENABLE);
-+		if (ret)
-+			return ret;
-+
-+		ret = ad5823_i2c_write(client, AD5823_REG_MODE,
-+					vcm_mode_reg_val[ad5823_dev.vcm_mode]);
-+		if (ret)
-+			return ret;
-+	} else {
-+		ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
-+						AD5823_RING_CTRL_DISABLE);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
-+	if (ret)
-+		return ret;
-+
-+	/* set reg VCM_CODE_MSB Bit[1:0] */
-+	vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | ((val >> 8) & ~VCM_CODE_MSB_MASK);
-+	ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
-+	if (ret)
-+		return ret;
-+
-+	/* set reg VCM_CODE_LSB Bit[7:0] */
-+	ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB,
-+							(val & 0x0f));
-+	if (ret)
-+		return ret;
-+
-+	/* set required vcm move time */
-+	vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
-+		   - AD5823_HIGH_FREQ_RANGE;
-+	ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
-+
-+	return ret;
-+}
-+
-+int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
-+{
-+	int ret;
-+
-+	value = min(value, AD5823_MAX_FOCUS_POS);
-+	ret = ad5823_t_focus_vcm(sd, AD5823_MAX_FOCUS_POS - value);
-+	if (ret == 0) {
-+		ad5823_dev.number_of_steps = value - ad5823_dev.focus;
-+		ad5823_dev.focus = value;
-+		ktime_get_ts(&ad5823_dev.timestamp_t_focus_abs);
-+	}
-+
-+	return ret;
-+}
-+
-+int ad5823_t_focus_rel(struct v4l2_subdev *sd, s32 value)
-+{
-+	return ad5823_t_focus_abs(sd, ad5823_dev.focus + value);
-+}
-+
-+int ad5823_q_focus_status(struct v4l2_subdev *sd, s32 *value)
-+{
-+	u32 status = 0;
-+	struct timespec temptime;
-+	const struct timespec timedelay = {
-+		0,
-+		min_t(u32, abs(ad5823_dev.number_of_steps)*DELAY_PER_STEP_NS,
-+			DELAY_MAX_PER_STEP_NS),
-+	};
-+
-+	ktime_get_ts(&temptime);
-+
-+	temptime = timespec_sub(temptime, (ad5823_dev.timestamp_t_focus_abs));
-+
-+	if (timespec_compare(&temptime, &timedelay) <= 0)
-+		status = ATOMISP_FOCUS_STATUS_MOVING
-+			| ATOMISP_FOCUS_HP_IN_PROGRESS;
-+	else
-+		status = ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE
-+			| ATOMISP_FOCUS_HP_COMPLETE;
-+
-+	*value = status;
-+
-+	return 0;
-+}
-+
-+int ad5823_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
-+{
-+	s32 val;
-+
-+	ad5823_q_focus_status(sd, &val);
-+
-+	if (val & ATOMISP_FOCUS_STATUS_MOVING)
-+		*value  = ad5823_dev.focus - ad5823_dev.number_of_steps;
-+	else
-+		*value  = ad5823_dev.focus ;
-+
-+	return 0;
-+}
-+
-+int ad5823_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
-+{
-+	return 0;
-+}
-+
-+int ad5823_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
-+{
-+	return 0;
-+}
-+
-+int ad5823_vcm_init(struct v4l2_subdev *sd)
-+{
-+	/* set vcm mode to ARC RES0.5 */
-+	ad5823_dev.vcm_mode = AD5823_ARC_RES1;
-+	ad5823_dev.platform_data = camera_get_af_platform_data();
-+	return ad5823_dev.platform_data ? 0 : -ENODEV;
-+}
-diff --git a/drivers/staging/ov5693/ad5823.h b/drivers/staging/ov5693/ad5823.h
-new file mode 100644
-index 000000000000..8b046c31f3af
---- /dev/null
-+++ b/drivers/staging/ov5693/ad5823.h
-@@ -0,0 +1,90 @@
-+/*
-+ * Support for AD5823 VCM.
-+ *
-+ * Copyright (c) 2013 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 version
-+ * 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA.
-+ *
-+ */
-+
-+#ifndef __AD5823_H__
-+#define __AD5823_H__
-+
-+#include <linux/atomisp_platform.h>
-+#include <linux/types.h>
-+
-+
-+#define AD5823_VCM_ADDR	0x0c
-+
-+#define AD5823_REG_RESET		0x01
-+#define AD5823_REG_MODE			0x02
-+#define AD5823_REG_VCM_MOVE_TIME	0x03
-+#define AD5823_REG_VCM_CODE_MSB		0x04
-+#define AD5823_REG_VCM_CODE_LSB		0x05
-+#define AD5823_REG_VCM_THRESHOLD_MSB	0x06
-+#define AD5823_REG_VCM_THRESHOLD_LSB	0x07
-+
-+#define AD5823_RING_CTRL_ENABLE		0x04
-+#define AD5823_RING_CTRL_DISABLE	0x00
-+
-+#define AD5823_RESONANCE_PERIOD		100000
-+#define AD5823_RESONANCE_COEF		512
-+#define AD5823_HIGH_FREQ_RANGE		0x80
-+
-+#define VCM_CODE_MSB_MASK		0xfc
-+
-+enum ad5823_tok_type {
-+	AD5823_8BIT  = 0x0001,
-+	AD5823_16BIT = 0x0002,
-+};
-+
-+enum ad5823_vcm_mode {
-+	AD5823_ARC_RES0 = 0x0,	/* Actuator response control RES1 */
-+	AD5823_ARC_RES1 = 0x1,	/* Actuator response control RES0.5 */
-+	AD5823_ARC_RES2 = 0x2,	/* Actuator response control RES2 */
-+	AD5823_ESRC = 0x3,	/* Enhanced slew rate control */
-+	AD5823_DIRECT = 0x4,	/* Direct control */
-+};
-+
-+/* ad5823 device structure */
-+struct ad5823_device {
-+	struct timespec timestamp_t_focus_abs;
-+	enum ad5823_vcm_mode vcm_mode;
-+	s16 number_of_steps;
-+	bool initialized;		/* true if ad5823 is detected */
-+	s32 focus;			/* Current focus value */
-+	struct timespec focus_time;	/* Time when focus was last time set */
-+	__u8 buffer[4];			/* Used for i2c transactions */
-+	const struct camera_af_platform_data *platform_data;
-+};
-+
-+#define AD5823_INVALID_CONFIG	0xffffffff
-+#define AD5823_MAX_FOCUS_POS	1023
-+
-+
-+#define DELAY_PER_STEP_NS	1000000
-+#define DELAY_MAX_PER_STEP_NS	(1000000 * 1023)
-+
-+int ad5823_vcm_power_up(struct v4l2_subdev *sd);
-+int ad5823_vcm_power_down(struct v4l2_subdev *sd);
-+int ad5823_vcm_init(struct v4l2_subdev *sd);
-+
-+int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val);
-+int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value);
-+int ad5823_t_focus_rel(struct v4l2_subdev *sd, s32 value);
-+int ad5823_q_focus_status(struct v4l2_subdev *sd, s32 *value);
-+int ad5823_q_focus_abs(struct v4l2_subdev *sd, s32 *value);
-+
-+#endif
-diff --git a/drivers/staging/ov5693/ov5693.c b/drivers/staging/ov5693/ov5693.c
-new file mode 100644
-index 000000000000..51d218da3722
---- /dev/null
-+++ b/drivers/staging/ov5693/ov5693.c
-@@ -0,0 +1,1461 @@
-+/*
-+ * Support for OmniVision OV5693 5M HD camera sensor.
-+ *
-+ * Copyright (c) 2013 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 version
-+ * 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA.
-+ *
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/delay.h>
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/init.h>
-+#include <linux/i2c.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/kmod.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/moduleparam.h>
-+#include <linux/string.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-chip-ident.h>
-+
-+#include "ov5693.h"
-+
-+/* i2c read/write stuff */
-+static int ov5693_read_reg(struct i2c_client *client,
-+			   u16 data_length, u16 reg, u16 *val)
-+{
-+	int err;
-+	struct i2c_msg msg[2];
-+	unsigned char data[6];
-+
-+	if (!client->adapter) {
-+		dev_err(&client->dev, "%s error, no client->adapter\n",
-+			__func__);
-+		return -ENODEV;
-+	}
-+
-+	if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
-+					&& data_length != OV5693_32BIT) {
-+		dev_err(&client->dev, "%s error, invalid data length\n",
-+			__func__);
-+		return -EINVAL;
-+	}
-+
-+	memset(msg, 0 , sizeof(msg));
-+
-+	msg[0].addr = client->addr;
-+	msg[0].flags = 0;
-+	msg[0].len = I2C_MSG_LENGTH;
-+	msg[0].buf = data;
-+
-+	/* high byte goes out first */
-+	data[0] = (u8)(reg >> 8);
-+	data[1] = (u8)(reg & 0xff);
-+
-+	msg[1].addr = client->addr;
-+	msg[1].len = data_length;
-+	msg[1].flags = I2C_M_RD;
-+	msg[1].buf = data;
-+
-+	err = i2c_transfer(client->adapter, msg, 2);
-+	if (err != 2) {
-+		if (err >= 0)
-+			err = -EIO;
-+		dev_err(&client->dev,
-+			"read from offset 0x%x error %d", reg, err);
-+		return err;
-+	}
-+
-+	*val = 0;
-+	/* high byte comes first */
-+	if (data_length == OV5693_8BIT)
-+		*val = (u8)data[0];
-+	else if (data_length == OV5693_16BIT)
-+		*val = be16_to_cpu(*(u16 *)&data[0]);
-+	else
-+		*val = be32_to_cpu(*(u32 *)&data[0]);
-+
-+	return 0;
-+}
-+
-+static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-+{
-+	struct i2c_msg msg;
-+	const int num_msg = 1;
-+	int ret;
-+
-+	msg.addr = client->addr;
-+	msg.flags = 0;
-+	msg.len = len;
-+	msg.buf = data;
-+	ret = i2c_transfer(client->adapter, &msg, 1);
-+
-+	return ret == num_msg ? 0 : -EIO;
-+}
-+
-+static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
-+							u16 reg, u16 val)
-+{
-+	int ret;
-+	unsigned char data[4] = {0};
-+	u16 *wreg = (u16 *)data;
-+	const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
-+
-+	if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
-+		dev_err(&client->dev,
-+			"%s error, invalid data_length\n", __func__);
-+		return -EINVAL;
-+	}
-+
-+	/* high byte goes out first */
-+	*wreg = cpu_to_be16(reg);
-+
-+	if (data_length == OV5693_8BIT) {
-+		data[2] = (u8)(val);
-+	} else {
-+		/* OV5693_16BIT */
-+		u16 *wdata = (u16 *)&data[2];
-+		*wdata = cpu_to_be16(val);
-+	}
-+
-+	ret = ov5693_i2c_write(client, len, data);
-+	if (ret)
-+		dev_err(&client->dev,
-+			"write error: wrote 0x%x to offset 0x%x error %d",
-+			val, reg, ret);
-+
-+	return ret;
-+}
-+
-+/*
-+ * ov5693_write_reg_array - Initializes a list of OV5693 registers
-+ * @client: i2c driver client structure
-+ * @reglist: list of registers to be written
-+ *
-+ * This function initializes a list of registers. When consecutive addresses
-+ * are found in a row on the list, this function creates a buffer and sends
-+ * consecutive data in a single i2c_transfer().
-+ *
-+ * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
-+ * __ov5693_write_reg_is_consecutive() are internal functions to
-+ * ov5693_write_reg_array_fast() and should be not used anywhere else.
-+ *
-+ */
-+static int __ov5693_flush_reg_array(struct i2c_client *client,
-+				    struct ov5693_write_ctrl *ctrl)
-+{
-+	u16 size;
-+
-+	if (ctrl->index == 0)
-+		return 0;
-+
-+	size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
-+	ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
-+	ctrl->index = 0;
-+
-+	return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer);
-+}
-+
-+static int __ov5693_buf_reg_array(struct i2c_client *client,
-+				  struct ov5693_write_ctrl *ctrl,
-+				  const struct ov5693_reg *next)
-+{
-+	int size;
-+	u16 *data16;
-+
-+	switch (next->type) {
-+	case OV5693_8BIT:
-+		size = 1;
-+		ctrl->buffer.data[ctrl->index] = (u8)next->val;
-+		break;
-+	case OV5693_16BIT:
-+		size = 2;
-+		data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
-+		*data16 = cpu_to_be16((u16)next->val);
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	/* When first item is added, we need to store its starting address */
-+	if (ctrl->index == 0)
-+		ctrl->buffer.addr = next->reg;
-+
-+	ctrl->index += size;
-+
-+	/*
-+	 * Buffer cannot guarantee free space for u32? Better flush it to avoid
-+	 * possible lack of memory for next item.
-+	 */
-+	if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
-+		return __ov5693_flush_reg_array(client, ctrl);
-+
-+	return 0;
-+}
-+
-+static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
-+					     struct ov5693_write_ctrl *ctrl,
-+					     const struct ov5693_reg *next)
-+{
-+	if (ctrl->index == 0)
-+		return 1;
-+
-+	return ctrl->buffer.addr + ctrl->index == next->reg;
-+}
-+
-+static int ov5693_write_reg_array(struct i2c_client *client,
-+				  const struct ov5693_reg *reglist)
-+{
-+	const struct ov5693_reg *next = reglist;
-+	struct ov5693_write_ctrl ctrl;
-+	int err;
-+
-+	ctrl.index = 0;
-+	for (; next->type != OV5693_TOK_TERM; next++) {
-+		switch (next->type & OV5693_TOK_MASK) {
-+		case OV5693_TOK_DELAY:
-+			err = __ov5693_flush_reg_array(client, &ctrl);
-+			if (err)
-+				return err;
-+			usleep_range(next->val * 1000, (next->val + 1) * 1000);
-+			break;
-+		default:
-+			/*
-+			 * If next address is not consecutive, data needs to be
-+			 * flushed before proceed.
-+			 */
-+			if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
-+								next)) {
-+				err = __ov5693_flush_reg_array(client, &ctrl);
-+				if (err)
-+					return err;
-+			}
-+			err = __ov5693_buf_reg_array(client, &ctrl, next);
-+			if (err) {
-+				dev_err(&client->dev, "%s: write error, aborted\n",
-+					 __func__);
-+				return err;
-+			}
-+			break;
-+		}
-+	}
-+
-+	return __ov5693_flush_reg_array(client, &ctrl);
-+}
-+static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
-+{
-+	*val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
-+	return 0;
-+}
-+
-+static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-+{
-+	/*const f number for ov5693*/
-+	*val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
-+	return 0;
-+}
-+
-+static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-+{
-+	*val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
-+		(OV5693_F_NUMBER_DEM << 16) |
-+		(OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
-+	return 0;
-+}
-+
-+
-+static int ov5693_get_intg_factor(struct i2c_client *client,
-+				struct camera_mipi_info *info,
-+				const struct ov5693_resolution *res)
-+{
-+	struct atomisp_sensor_mode_data *buf = &info->data;
-+	unsigned int pix_clk_freq_hz;
-+	u16 reg_val;
-+	int ret;
-+
-+	if (info == NULL)
-+		return -EINVAL;
-+
-+	/* pixel clock calculattion */
-+	pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-+
-+	buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-+
-+	/* get integration time */
-+	buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
-+	buf->coarse_integration_time_max_margin =
-+					OV5693_COARSE_INTG_TIME_MAX_MARGIN;
-+
-+	buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
-+	buf->fine_integration_time_max_margin =
-+					OV5693_FINE_INTG_TIME_MAX_MARGIN;
-+
-+	buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
-+	buf->frame_length_lines = res->lines_per_frame;
-+	buf->line_length_pck = res->pixels_per_line;
-+	buf->read_mode = res->bin_mode;
-+
-+	/* get the cropping and output resolution to ISP for this mode. */
-+	ret =  ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_H_CROP_START_H, &reg_val);
-+	if (ret)
-+		return ret;
-+	buf->crop_horizontal_start = reg_val;
-+
-+	ret =  ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_V_CROP_START_H, &reg_val);
-+	if (ret)
-+		return ret;
-+	buf->crop_vertical_start = reg_val;
-+
-+	ret = ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_H_CROP_END_H, &reg_val);
-+	if (ret)
-+		return ret;
-+	buf->crop_horizontal_end = reg_val;
-+
-+	ret = ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_V_CROP_END_H, &reg_val);
-+	if (ret)
-+		return ret;
-+	buf->crop_vertical_end = reg_val;
-+
-+	ret = ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_H_OUTSIZE_H, &reg_val);
-+	if (ret)
-+		return ret;
-+	buf->output_width = reg_val;
-+
-+	ret = ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_V_OUTSIZE_H, &reg_val);
-+	if (ret)
-+		return ret;
-+	buf->output_height = reg_val;
-+
-+	/*
-+	 * we can't return 0 for bin_factor, this is because camera
-+	 * HAL will use them as denominator, bin_factor = 0 will
-+	 * cause camera HAL crash. So we return bin_factor as this
-+	 * rules:
-+	 * [1]. res->bin_factor = 0, return 1 for bin_factor.
-+	 * [2]. res->bin_factor > 0, return res->bin_factor.
-+	 */
-+	buf->binning_factor_x = res->bin_factor_x ?
-+					res->bin_factor_x : 1;
-+	buf->binning_factor_y = res->bin_factor_y ?
-+					res->bin_factor_y : 1;
-+	return 0;
-+}
-+
-+static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
-+				 int gain, int digitgain)
-+
-+{
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	u16 vts;
-+	int ret;
-+
-+	/*
-+	 * According to spec, the low 4 bits of exposure/gain reg are
-+	 * fraction bits, so need to take 4 bits left shift to align
-+	 * reg integer bits.
-+	 */
-+	coarse_itg <<= 4;
-+	gain <<= 4;
-+
-+	ret = ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_VTS_H, &vts);
-+	if (ret)
-+		return ret;
-+
-+	if (coarse_itg + OV5693_INTEGRATION_TIME_MARGIN >= vts)
-+		vts = coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
-+
-+	ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_VTS_H, vts);
-+	if (ret)
-+		return ret;
-+
-+	/* group hold start */
-+	ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_GROUP_ACCESS, 0);
-+	if (ret)
-+		return ret;
-+
-+	/* set exposure */
-+	ret = ov5693_write_reg(client, OV5693_8BIT,
-+					OV5693_AEC_PK_EXPO_L,
-+					coarse_itg & 0xff);
-+	if (ret)
-+		return ret;
-+
-+	ret = ov5693_write_reg(client, OV5693_16BIT,
-+					OV5693_AEC_PK_EXPO_H,
-+					(coarse_itg >> 8) & 0xfff);
-+	if (ret)
-+		return ret;
-+
-+	/* set analog gain */
-+	ret = ov5693_write_reg(client, OV5693_16BIT,
-+					OV5693_AGC_ADJ_H, gain);
-+	if (ret)
-+		return ret;
-+
-+	/* set digital gain */
-+	ret = ov5693_write_reg(client, OV5693_16BIT,
-+				OV5693_MWB_GAIN_R_H, digitgain);
-+	if (ret)
-+		return ret;
-+
-+	ret = ov5693_write_reg(client, OV5693_16BIT,
-+				OV5693_MWB_GAIN_G_H, digitgain);
-+	if (ret)
-+		return ret;
-+
-+	ret = ov5693_write_reg(client, OV5693_16BIT,
-+				OV5693_MWB_GAIN_B_H, digitgain);
-+	if (ret)
-+		return ret;
-+
-+	/* group hold end */
-+	ret = ov5693_write_reg(client, OV5693_8BIT,
-+					OV5693_GROUP_ACCESS, 0x10);
-+	if (ret)
-+		return ret;
-+
-+	/* group hold launch */
-+	ret = ov5693_write_reg(client, OV5693_8BIT,
-+					OV5693_GROUP_ACCESS, 0xa0);
-+
-+	return ret;
-+}
-+
-+static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
-+	int gain, int digitgain)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret;
-+
-+	mutex_lock(&dev->input_lock);
-+	ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
-+	mutex_unlock(&dev->input_lock);
-+
-+	return ret;
-+}
-+
-+static long ov5693_s_exposure(struct v4l2_subdev *sd,
-+			       struct atomisp_exposure *exposure)
-+{
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int exp = exposure->integration_time[0];
-+	int gain = exposure->gain[0];
-+	int digitgain = exposure->gain[1];
-+
-+	/* we should not accept the invalid value below. */
-+	if (gain == 0) {
-+		dev_err(&client->dev, "%s: invalid value\n", __func__);
-+		return -EINVAL;
-+	}
-+
-+	return ov5693_set_exposure(sd, exp, gain, digitgain);
-+}
-+
-+static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-+{
-+
-+	switch (cmd) {
-+	case ATOMISP_IOC_S_EXPOSURE:
-+		return ov5693_s_exposure(sd, arg);
-+	default:
-+		return -EINVAL;
-+	}
-+	return 0;
-+}
-+
-+/* This returns the exposure time being used. This should only be used
-+   for filling in EXIF data, not for actual image processing. */
-+static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
-+{
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	u16 reg_v, reg_v2;
-+	int ret;
-+
-+	/* get exposure */
-+	ret = ov5693_read_reg(client, OV5693_8BIT,
-+					OV5693_AEC_PK_EXPO_L,
-+					&reg_v);
-+	if (ret)
-+		goto err;
-+
-+	ret = ov5693_read_reg(client, OV5693_8BIT,
-+					OV5693_AEC_PK_EXPO_M,
-+					&reg_v2);
-+	if (ret)
-+		goto err;
-+
-+	reg_v += reg_v2 << 8;
-+	ret = ov5693_read_reg(client, OV5693_8BIT,
-+					OV5693_AEC_PK_EXPO_H,
-+					&reg_v2);
-+	if (ret)
-+		goto err;
-+
-+	*value = (reg_v + (((u32)reg_v2 << 16))) >> 4;
-+err:
-+	return ret;
-+}
-+
-+/*
-+ * This below focus func don't need input_lock mutex_lock
-+ * since they are just called in v4l2 s_ctrl/g_ctrl framework
-+ * where mutex input_lock have been done.
-+ */
-+int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret = 0;
-+
-+	if (dev->vcm_driver && dev->vcm_driver->t_focus_abs)
-+		ret = dev->vcm_driver->t_focus_abs(sd, value);
-+
-+	return ret;
-+}
-+
-+int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret = 0;
-+
-+	if (dev->vcm_driver && dev->vcm_driver->t_focus_rel)
-+		ret = dev->vcm_driver->t_focus_rel(sd, value);
-+
-+	return ret;
-+}
-+
-+int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret = 0;
-+
-+	if (dev->vcm_driver && dev->vcm_driver->q_focus_status)
-+		ret = dev->vcm_driver->q_focus_status(sd, value);
-+
-+	return ret;
-+}
-+
-+int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret = 0;
-+
-+	if (dev->vcm_driver && dev->vcm_driver->q_focus_abs)
-+		ret = dev->vcm_driver->q_focus_abs(sd, value);
-+
-+	return ret;
-+}
-+
-+/* ov5693 control set/get */
-+static int ov5693_g_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+	struct ov5693_device *dev = container_of(
-+		ctrl->handler, struct ov5693_device, ctrl_handler);
-+	int ret = 0;
-+
-+	switch (ctrl->id) {
-+	case V4L2_CID_EXPOSURE_ABSOLUTE:
-+		ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
-+		break;
-+	case V4L2_CID_FOCUS_ABSOLUTE:
-+		ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
-+		break;
-+	case V4L2_CID_FOCUS_STATUS:
-+		ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
-+		break;
-+	case V4L2_CID_FOCAL_ABSOLUTE:
-+		ret = ov5693_g_focal(&dev->sd, &ctrl->val);
-+		break;
-+	case V4L2_CID_FNUMBER_ABSOLUTE:
-+		ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
-+		break;
-+	case V4L2_CID_FNUMBER_RANGE:
-+		ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
-+		break;
-+	case V4L2_CID_BIN_FACTOR_HORZ:
-+		ctrl->val = dev->ov5693_res[dev->fmt_idx].bin_factor_x;
-+		break;
-+	case V4L2_CID_BIN_FACTOR_VERT:
-+		ctrl->val = dev->ov5693_res[dev->fmt_idx].bin_factor_y;
-+		break;
-+	default:
-+		ret = -EINVAL;
-+	}
-+
-+	return ret;
-+}
-+
-+static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+	struct ov5693_device *dev = container_of(
-+		ctrl->handler, struct ov5693_device, ctrl_handler);
-+	int ret = 0;
-+
-+	if (!ctrl)
-+		return -EINVAL;
-+
-+	switch (ctrl->id) {
-+	case V4L2_CID_RUN_MODE:
-+		switch (ctrl->val) {
-+		case ATOMISP_RUN_MODE_VIDEO:
-+			dev->ov5693_res = ov5693_res_video;
-+			dev->curr_res_num = N_RES_VIDEO;
-+			break;
-+		case ATOMISP_RUN_MODE_STILL_CAPTURE:
-+			dev->ov5693_res = ov5693_res_still;
-+			dev->curr_res_num = N_RES_STILL;
-+			break;
-+		default:
-+			dev->ov5693_res = ov5693_res_preview;
-+			dev->curr_res_num = N_RES_PREVIEW;
-+		}
-+		break;
-+	case V4L2_CID_FOCUS_ABSOLUTE:
-+		ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
-+		break;
-+	case V4L2_CID_FOCUS_RELATIVE:
-+		ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
-+		break;
-+	default:
-+		ret = -EINVAL;
-+	}
-+
-+	return ret;
-+}
-+
-+static int ov5693_init(struct v4l2_subdev *sd)
-+{
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret = 0;
-+
-+	/* restore settings */
-+	dev->ov5693_res = ov5693_res_preview;
-+	dev->curr_res_num = N_RES_PREVIEW;
-+
-+	ret = ov5693_write_reg_array(client, ov5693_init_setting);
-+	if (ret)
-+		dev_err(&client->dev, "ov5693 write init setting reg err.\n");
-+
-+	return ret;
-+}
-+
-+
-+static int power_up(struct v4l2_subdev *sd)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int ret;
-+
-+	if (NULL == dev->platform_data) {
-+		dev_err(&client->dev,
-+			"no camera_sensor_platform_data");
-+		return -ENODEV;
-+	}
-+
-+	/* power control */
-+	ret = dev->platform_data->power_ctrl(sd, 1);
-+	if (ret)
-+		goto fail_power;
-+
-+	/* gpio ctrl */
-+	ret = dev->platform_data->gpio_ctrl(sd, 1);
-+	if (ret)
-+		goto fail_power;
-+
-+	/* flis clock control */
-+	ret = dev->platform_data->flisclk_ctrl(sd, 1);
-+	if (ret)
-+		goto fail_clk;
-+
-+	/* according to DS, 20ms is needed between PWDN and i2c access */
-+	msleep(20);
-+
-+	return 0;
-+
-+fail_clk:
-+	dev->platform_data->gpio_ctrl(sd, 0);
-+fail_power:
-+	dev->platform_data->power_ctrl(sd, 0);
-+	dev_err(&client->dev, "sensor power-up failed\n");
-+
-+	return ret;
-+}
-+
-+static int power_down(struct v4l2_subdev *sd)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int ret = 0;
-+
-+	if (NULL == dev->platform_data) {
-+		dev_err(&client->dev,
-+			"no camera_sensor_platform_data");
-+		return -ENODEV;
-+	}
-+
-+	ret = dev->platform_data->flisclk_ctrl(sd, 0);
-+	if (ret)
-+		dev_err(&client->dev, "flisclk failed\n");
-+
-+	/* gpio ctrl */
-+	ret = dev->platform_data->gpio_ctrl(sd, 0);
-+	if (ret)
-+		dev_err(&client->dev, "gpio failed.\n");
-+
-+	/* power control */
-+	ret = dev->platform_data->power_ctrl(sd, 0);
-+	if (ret)
-+		dev_err(&client->dev, "vprog failed.\n");
-+
-+	return ret;
-+}
-+
-+static int ov5693_s_power(struct v4l2_subdev *sd, int on)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int ret = 0;
-+
-+	mutex_lock(&dev->input_lock);
-+	if (on == 0) {
-+		if (dev->vcm_driver && dev->vcm_driver->power_down)
-+			ret = dev->vcm_driver->power_down(sd);
-+		if (ret)
-+			dev_err(&client->dev, "vcm power-down failed.\n");
-+
-+		ret = power_down(sd);
-+	} else {
-+		if (dev->vcm_driver && dev->vcm_driver->power_up)
-+			ret = dev->vcm_driver->power_up(sd);
-+		if (ret)
-+			dev_err(&client->dev, "vcm power-up failed.\n");
-+
-+		ret = power_up(sd);
-+		if (!ret)
-+			ret = ov5693_init(sd);
-+	}
-+	mutex_unlock(&dev->input_lock);
-+	return ret;
-+}
-+
-+/*
-+ * distance - calculate the distance
-+ * @res: resolution
-+ * @w: width
-+ * @h: height
-+ *
-+ * Get the gap between resolution and w/h.
-+ * res->width/height smaller than w/h wouldn't be considered.
-+ * Returns the value of gap or -1 if fail.
-+ */
-+static int distance(struct ov5693_resolution *res, u32 w, u32 h)
-+{
-+	unsigned int w_ratio = ((res->width << RATIO_SHIFT_BITS)/w);
-+	unsigned int h_ratio;
-+	int match;
-+
-+	if (h == 0)
-+		return -1;
-+	h_ratio = ((res->height << RATIO_SHIFT_BITS) / h);
-+	if (h_ratio == 0)
-+		return -1;
-+	match   = abs(((w_ratio << RATIO_SHIFT_BITS) / h_ratio)
-+			- ((int)(1 << RATIO_SHIFT_BITS)));
-+
-+	if ((w_ratio < (int)(1 << RATIO_SHIFT_BITS))
-+	    || (h_ratio < (int)(1 << RATIO_SHIFT_BITS))  ||
-+		(match > LARGEST_ALLOWED_RATIO_MISMATCH))
-+		return -1;
-+
-+	return w_ratio + h_ratio;
-+}
-+
-+/* Return the nearest higher resolution index */
-+static int nearest_resolution_index(struct v4l2_subdev *sd,
-+				    int w, int h)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int i;
-+	int idx = dev->curr_res_num-1;
-+	int dist;
-+	int min_dist = INT_MAX;
-+	struct ov5693_resolution *tmp_res = NULL;
-+
-+	for (i = 0; i < dev->curr_res_num; i++) {
-+		tmp_res = &dev->ov5693_res[i];
-+		dist = distance(tmp_res, w, h);
-+		if (dist == -1)
-+			continue;
-+		if (dist < min_dist) {
-+			min_dist = dist;
-+			idx = i;
-+		}
-+	}
-+
-+	return idx;
-+}
-+
-+static int get_resolution_index(struct v4l2_subdev *sd,
-+				int w, int h)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int i;
-+
-+	for (i = 0; i < dev->curr_res_num; i++) {
-+		if (w != dev->ov5693_res[i].width)
-+			continue;
-+		if (h != dev->ov5693_res[i].height)
-+			continue;
-+
-+		return i;
-+	}
-+
-+	return -1;
-+}
-+
-+static int __ov5693_try_mbus_fmt(struct v4l2_subdev *sd,
-+				 struct v4l2_mbus_framefmt *fmt)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int idx;
-+
-+	if (!fmt)
-+		return -EINVAL;
-+
-+	idx = nearest_resolution_index(sd, fmt->width, fmt->height);
-+	fmt->width = dev->ov5693_res[idx].width;
-+	fmt->height = dev->ov5693_res[idx].height;
-+	fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
-+
-+	return 0;
-+}
-+
-+static int ov5693_try_mbus_fmt(struct v4l2_subdev *sd,
-+				struct v4l2_mbus_framefmt *fmt)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int ret;
-+
-+	mutex_lock(&dev->input_lock);
-+	ret = __ov5693_try_mbus_fmt(sd, fmt);
-+	mutex_unlock(&dev->input_lock);
-+
-+	return ret;
-+}
-+
-+static int ov5693_s_mbus_fmt(struct v4l2_subdev *sd,
-+			     struct v4l2_mbus_framefmt *fmt)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	struct camera_mipi_info *ov5693_info = NULL;
-+	int ret = 0;
-+
-+	ov5693_info = v4l2_get_subdev_hostdata(sd);
-+	if (ov5693_info == NULL)
-+		return -EINVAL;
-+
-+	mutex_lock(&dev->input_lock);
-+	ret = __ov5693_try_mbus_fmt(sd, fmt);
-+	if (ret == -1) {
-+		dev_err(&client->dev, "try fmt fail\n");
-+		goto done;
-+	}
-+
-+	dev->fmt_idx = get_resolution_index(sd, fmt->width, fmt->height);
-+	if (dev->fmt_idx == -1) {
-+		dev_err(&client->dev, "get resolution fail\n");
-+		goto done;
-+	}
-+
-+	ret = ov5693_write_reg_array(client, dev->ov5693_res[dev->fmt_idx].regs);
-+	if (ret) {
-+		dev_err(&client->dev, "ov5693 write fmt register err.\n");
-+		goto done;
-+	}
-+
-+	ret = ov5693_get_intg_factor(client, ov5693_info,
-+					&dev->ov5693_res[dev->fmt_idx]);
-+	if (ret)
-+		dev_err(&client->dev, "failed to get integration_factor\n");
-+
-+done:
-+	mutex_unlock(&dev->input_lock);
-+	return ret;
-+}
-+static int ov5693_g_mbus_fmt(struct v4l2_subdev *sd,
-+			     struct v4l2_mbus_framefmt *fmt)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+
-+	mutex_lock(&dev->input_lock);
-+	fmt->width = dev->ov5693_res[dev->fmt_idx].width;
-+	fmt->height = dev->ov5693_res[dev->fmt_idx].height;
-+	fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10;
-+	mutex_unlock(&dev->input_lock);
-+
-+	return 0;
-+}
-+
-+static int ov5693_detect(struct i2c_client *client)
-+{
-+	struct i2c_adapter *adapter = client->adapter;
-+	int ret = 0;
-+	u16 id;
-+	u8 revision;
-+
-+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-+		return -ENODEV;
-+
-+	ret = ov5693_read_reg(client, OV5693_16BIT,
-+					OV5693_SC_CMMN_CHIP_ID, &id);
-+	if (ret) {
-+		dev_err(&client->dev, "read sensor_id err.\n");
-+		return -ENODEV;
-+	}
-+
-+	if (id != OV5693_ID) {
-+		dev_err(&client->dev, "sensor ID error\n");
-+		return -ENODEV;
-+	}
-+
-+	ret = ov5693_read_reg(client, OV5693_8BIT,
-+					OV5693_SC_CMMN_SUB_ID, &id);
-+	revision = (u8)id & 0x0f;
-+
-+	dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
-+	dev_dbg(&client->dev, "detect ov5693 success\n");
-+	return ret;
-+}
-+
-+static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int ret;
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
-+				enable ? OV5693_START_STREAMING :
-+				OV5693_STOP_STREAMING);
-+
-+	mutex_unlock(&dev->input_lock);
-+	return ret;
-+}
-+
-+/* ov5693 enum frame size, frame intervals */
-+static int ov5693_enum_framesizes(struct v4l2_subdev *sd,
-+				  struct v4l2_frmsizeenum *fsize)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	unsigned int index = fsize->index;
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	if (index >= dev->curr_res_num) {
-+		mutex_unlock(&dev->input_lock);
-+		return -EINVAL;
-+	}
-+
-+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-+	fsize->discrete.width = dev->ov5693_res[index].width;
-+	fsize->discrete.height = dev->ov5693_res[index].height;
-+
-+	mutex_unlock(&dev->input_lock);
-+	return 0;
-+}
-+
-+static int ov5693_enum_frameintervals(struct v4l2_subdev *sd,
-+				      struct v4l2_frmivalenum *fival)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	unsigned int index = fival->index;
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	if (index >= dev->curr_res_num) {
-+		mutex_unlock(&dev->input_lock);
-+		return -EINVAL;
-+	}
-+
-+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
-+	fival->width = dev->ov5693_res[index].width;
-+	fival->height = dev->ov5693_res[index].height;
-+	fival->discrete.numerator = 1;
-+	fival->discrete.denominator = dev->ov5693_res[index].fps;
-+
-+	mutex_unlock(&dev->input_lock);
-+
-+	return 0;
-+}
-+
-+static int ov5693_enum_mbus_fmt(struct v4l2_subdev *sd,
-+				unsigned int index,
-+				enum v4l2_mbus_pixelcode *code)
-+{
-+	*code = V4L2_MBUS_FMT_SBGGR10_1X10;
-+
-+	return 0;
-+}
-+
-+static int ov5693_s_config(struct v4l2_subdev *sd,
-+			   int irq, void *platform_data)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+	int ret = 0;
-+
-+	if (platform_data == NULL)
-+		return -ENODEV;
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	dev->platform_data = platform_data;
-+
-+	ret = power_up(sd);
-+	if (ret) {
-+		dev_err(&client->dev, "ov5693 power-up err.\n");
-+		goto fail_power_on;
-+	}
-+
-+	ret = dev->platform_data->csi_cfg(sd, 1);
-+	if (ret)
-+		goto fail_csi_cfg;
-+
-+	/* config & detect sensor */
-+	ret = ov5693_detect(client);
-+	if (ret) {
-+		dev_err(&client->dev, "ov5693_detect err s_config.\n");
-+		goto fail_csi_cfg;
-+	}
-+
-+	/* turn off sensor, after probed */
-+	ret = power_down(sd);
-+	if (ret) {
-+		dev_err(&client->dev, "ov5693 power-off err.\n");
-+		goto fail_csi_cfg;
-+	}
-+	mutex_unlock(&dev->input_lock);
-+
-+	return 0;
-+
-+fail_csi_cfg:
-+	dev->platform_data->csi_cfg(sd, 0);
-+fail_power_on:
-+	power_down(sd);
-+	dev_err(&client->dev, "sensor power-gating failed\n");
-+	mutex_unlock(&dev->input_lock);
-+	return ret;
-+}
-+
-+static int ov5693_g_parm(struct v4l2_subdev *sd,
-+			struct v4l2_streamparm *param)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct i2c_client *client = v4l2_get_subdevdata(sd);
-+
-+	if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-+		dev_err(&client->dev,  "unsupported buffer type.\n");
-+		return -EINVAL;
-+	}
-+
-+	memset(param, 0, sizeof(*param));
-+	param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+
-+	mutex_lock(&dev->input_lock);
-+	if (dev->fmt_idx >= 0 && dev->fmt_idx < dev->curr_res_num) {
-+		param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-+		param->parm.capture.timeperframe.numerator = 1;
-+		param->parm.capture.capturemode = dev->run_mode->val;
-+		param->parm.capture.timeperframe.denominator =
-+					dev->ov5693_res[dev->fmt_idx].fps;
-+	}
-+	mutex_unlock(&dev->input_lock);
-+	return 0;
-+}
-+
-+static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
-+				   struct v4l2_subdev_frame_interval *interval)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+
-+	mutex_lock(&dev->input_lock);
-+	interval->interval.numerator = 1;
-+	interval->interval.denominator = dev->ov5693_res[dev->fmt_idx].fps;
-+	mutex_unlock(&dev->input_lock);
-+
-+	return 0;
-+}
-+
-+static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
-+				struct v4l2_subdev_fh *fh,
-+				struct v4l2_subdev_mbus_code_enum *code)
-+{
-+	code->code = V4L2_MBUS_FMT_SBGGR10_1X10;
-+	return 0;
-+}
-+
-+static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
-+				struct v4l2_subdev_fh *fh,
-+				struct v4l2_subdev_frame_size_enum *fse)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	int index = fse->index;
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	if (index >= dev->curr_res_num) {
-+		mutex_unlock(&dev->input_lock);
-+		return -EINVAL;
-+	}
-+
-+	fse->min_width = dev->ov5693_res[index].width;
-+	fse->min_height = dev->ov5693_res[index].height;
-+	fse->max_width = dev->ov5693_res[index].width;
-+	fse->max_height = dev->ov5693_res[index].height;
-+
-+	mutex_unlock(&dev->input_lock);
-+	return 0;
-+}
-+
-+static int ov5693_get_pad_format(struct v4l2_subdev *sd,
-+				struct v4l2_subdev_fh *fh,
-+				struct v4l2_subdev_format *fmt)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	struct v4l2_mbus_framefmt *format;
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	switch (fmt->which) {
-+	case V4L2_SUBDEV_FORMAT_TRY:
-+		format = v4l2_subdev_get_try_format(fh, fmt->pad);
-+		break;
-+	case V4L2_SUBDEV_FORMAT_ACTIVE:
-+		format = &dev->format;
-+		break;
-+	default:
-+		format = NULL;
-+	}
-+
-+	mutex_unlock(&dev->input_lock);
-+
-+	if (!format)
-+		return -EINVAL;
-+
-+	fmt->format = *format;
-+	return 0;
-+}
-+
-+static int ov5693_set_pad_format(struct v4l2_subdev *sd,
-+				struct v4l2_subdev_fh *fh,
-+				struct v4l2_subdev_format *fmt)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+
-+	mutex_lock(&dev->input_lock);
-+
-+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-+		dev->format = fmt->format;
-+
-+	mutex_unlock(&dev->input_lock);
-+	return 0;
-+}
-+
-+static int ov5693_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-+{
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+
-+	mutex_lock(&dev->input_lock);
-+	*frames = dev->ov5693_res[dev->fmt_idx].skip_frames;
-+	mutex_unlock(&dev->input_lock);
-+
-+	return 0;
-+}
-+
-+static const struct v4l2_ctrl_ops ctrl_ops = {
-+	.s_ctrl = ov5693_s_ctrl,
-+	.g_volatile_ctrl = ov5693_g_ctrl,
-+};
-+
-+static const char * const ctrl_run_mode_menu[] = {
-+	NULL,
-+	"Video",
-+	"Still capture",
-+	"Continuous capture",
-+	"Preview",
-+};
-+
-+static const struct v4l2_ctrl_config ctrl_run_mode = {
-+	.ops = &ctrl_ops,
-+	.id = V4L2_CID_RUN_MODE,
-+	.name = "run mode",
-+	.type = V4L2_CTRL_TYPE_MENU,
-+	.min = 1,
-+	.def = 4,
-+	.max = 4,
-+	.qmenu = ctrl_run_mode_menu,
-+};
-+
-+static const struct v4l2_ctrl_config ctrls[] = {
-+	{
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_EXPOSURE_ABSOLUTE,
-+		.name = "absolute exposure",
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.min = 0x0,
-+		.max = 0xffff,
-+		.step = 0x01,
-+		.def = 0x00,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_FOCUS_ABSOLUTE,
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.name = "focus move absolute",
-+		.min = 0,
-+		.max = OV5693_MAX_FOCUS_POS,
-+		.step = 1,
-+		.def = 0,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_FOCUS_RELATIVE,
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.name = "focus move relative",
-+		.min = OV5693_MAX_FOCUS_NEG,
-+		.max = OV5693_MAX_FOCUS_POS,
-+		.step = 1,
-+		.def = 0,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_FOCUS_STATUS,
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.name = "focus status",
-+		.min = 0,
-+		.max = 100,
-+		.step = 1,
-+		.def = 0,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_FOCAL_ABSOLUTE,
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.name = "focal length",
-+		.min = OV5693_FOCAL_LENGTH_DEFAULT,
-+		.max = OV5693_FOCAL_LENGTH_DEFAULT,
-+		.step = 0x01,
-+		.def = OV5693_FOCAL_LENGTH_DEFAULT,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_FNUMBER_ABSOLUTE,
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.name = "f-number",
-+		.min = OV5693_F_NUMBER_DEFAULT,
-+		.max = OV5693_F_NUMBER_DEFAULT,
-+		.step = 0x01,
-+		.def = OV5693_F_NUMBER_DEFAULT,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_FNUMBER_RANGE,
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.name = "f-number range",
-+		.min = OV5693_F_NUMBER_RANGE,
-+		.max =  OV5693_F_NUMBER_RANGE,
-+		.step = 0x01,
-+		.def = OV5693_F_NUMBER_RANGE,
-+		.flags = 0,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_BIN_FACTOR_HORZ,
-+		.name = "horizontal binning factor",
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.max = OV5693_BIN_FACTOR_MAX,
-+		.step = 2,
-+		.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
-+	}, {
-+		.ops = &ctrl_ops,
-+		.id = V4L2_CID_BIN_FACTOR_VERT,
-+		.name = "vertical binning factor",
-+		.type = V4L2_CTRL_TYPE_INTEGER,
-+		.max = OV5693_BIN_FACTOR_MAX,
-+		.step = 2,
-+		.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
-+	}
-+};
-+
-+static const struct v4l2_subdev_sensor_ops ov5693_sensor_ops = {
-+	.g_skip_frames	= ov5693_g_skip_frames,
-+};
-+
-+static const struct v4l2_subdev_video_ops ov5693_video_ops = {
-+	.s_stream = ov5693_s_stream,
-+	.g_parm = ov5693_g_parm,
-+	.enum_framesizes = ov5693_enum_framesizes,
-+	.enum_frameintervals = ov5693_enum_frameintervals,
-+	.enum_mbus_fmt = ov5693_enum_mbus_fmt,
-+	.try_mbus_fmt = ov5693_try_mbus_fmt,
-+	.g_mbus_fmt = ov5693_g_mbus_fmt,
-+	.s_mbus_fmt = ov5693_s_mbus_fmt,
-+	.g_frame_interval = ov5693_g_frame_interval,
-+};
-+
-+static const struct v4l2_subdev_core_ops ov5693_core_ops = {
-+	.s_power = ov5693_s_power,
-+	.queryctrl = v4l2_subdev_queryctrl,
-+	.g_ctrl = v4l2_subdev_g_ctrl,
-+	.s_ctrl = v4l2_subdev_s_ctrl,
-+	.ioctl = ov5693_ioctl,
-+};
-+
-+static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
-+	.enum_mbus_code = ov5693_enum_mbus_code,
-+	.enum_frame_size = ov5693_enum_frame_size,
-+	.get_fmt = ov5693_get_pad_format,
-+	.set_fmt = ov5693_set_pad_format,
-+};
-+
-+static const struct v4l2_subdev_ops ov5693_ops = {
-+	.core = &ov5693_core_ops,
-+	.video = &ov5693_video_ops,
-+	.pad = &ov5693_pad_ops,
-+	.sensor = &ov5693_sensor_ops,
-+};
-+
-+static int ov5693_remove(struct i2c_client *client)
-+{
-+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+	struct ov5693_device *dev = to_ov5693_sensor(sd);
-+	dev_dbg(&client->dev, "ov5693_remove...\n");
-+
-+	dev->platform_data->csi_cfg(sd, 0);
-+
-+	v4l2_device_unregister_subdev(sd);
-+	media_entity_cleanup(&dev->sd.entity);
-+	devm_kfree(&client->dev, dev);
-+
-+	return 0;
-+}
-+
-+static int ov5693_probe(struct i2c_client *client,
-+			const struct i2c_device_id *id)
-+{
-+	struct ov5693_device *dev;
-+	int i;
-+	int ret;
-+
-+	dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
-+	if (!dev) {
-+		dev_err(&client->dev, "out of memory\n");
-+		return -ENOMEM;
-+	}
-+
-+	mutex_init(&dev->input_lock);
-+
-+	/*
-+	 * Initialize related res members of dev.
-+	 */
-+	dev->fmt_idx = 0;
-+	dev->ov5693_res = ov5693_res_preview;
-+	dev->curr_res_num = N_RES_PREVIEW;
-+
-+	v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops);
-+
-+	if (client->dev.platform_data) {
-+		ret = ov5693_s_config(&dev->sd, client->irq,
-+				       client->dev.platform_data);
-+		if (ret)
-+			goto out_free;
-+	}
-+
-+	dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+	dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-+	dev->format.code = V4L2_MBUS_FMT_SBGGR10_1X10;
-+	dev->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
-+	dev->vcm_driver = &ov5693_vcm_ops;
-+
-+	ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls) + 1);
-+	if (ret) {
-+		ov5693_remove(client);
-+		return ret;
-+	}
-+
-+	dev->run_mode = v4l2_ctrl_new_custom(&dev->ctrl_handler,
-+					     &ctrl_run_mode, NULL);
-+
-+	for (i = 0; i < ARRAY_SIZE(ctrls); i++)
-+		v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);
-+
-+	if (dev->ctrl_handler.error) {
-+		ov5693_remove(client);
-+		return dev->ctrl_handler.error;
-+	}
-+
-+	dev->ctrl_handler.lock = &dev->input_lock;
-+	dev->sd.ctrl_handler = &dev->ctrl_handler;
-+	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
-+
-+	ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0);
-+	if (ret)
-+		ov5693_remove(client);
-+
-+	/* vcm initialization */
-+	if (dev->vcm_driver && dev->vcm_driver->init)
-+		ret = dev->vcm_driver->init(&dev->sd);
-+	if (ret) {
-+		dev_err(&client->dev, "vcm init failed.\n");
-+		ov5693_remove(client);
-+	}
-+
-+	return ret;
-+out_free:
-+	v4l2_device_unregister_subdev(&dev->sd);
-+	devm_kfree(&client->dev, dev);
-+	return ret;
-+}
-+
-+MODULE_DEVICE_TABLE(i2c, ov5693_id);
-+static struct i2c_driver ov5693_driver = {
-+	.driver = {
-+		.owner = THIS_MODULE,
-+		.name = OV5693_NAME,
-+	},
-+	.probe = ov5693_probe,
-+	.remove = ov5693_remove,
-+	.id_table = ov5693_id,
-+};
-+
-+module_i2c_driver(ov5693_driver);
-+
-+MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/staging/ov5693/ov5693.h b/drivers/staging/ov5693/ov5693.h
-new file mode 100644
-index 000000000000..79aef69666e8
---- /dev/null
-+++ b/drivers/staging/ov5693/ov5693.h
-@@ -0,0 +1,848 @@
-+/*
-+ * Support for OmniVision OV5693 5M HD camera sensor.
-+ *
-+ * Copyright (c) 2013 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 version
-+ * 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-+ * 02110-1301, USA.
-+ *
-+ */
-+
-+#ifndef __OV5693_H__
-+#define __OV5693_H__
-+#include <linux/delay.h>
-+#include <linux/i2c.h>
-+#include <linux/kernel.h>
-+#include <media/media-entity.h>
-+#include <linux/spinlock.h>
-+#include <linux/types.h>
-+#include <linux/videodev2.h>
-+#include <media/v4l2-subdev.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-chip-ident.h>
-+#include <linux/v4l2-mediabus.h>
-+
-+#include <linux/atomisp_platform.h>
-+#include "ad5823.h"
-+
-+#define OV5693_NAME		"ov5693"
-+
-+/* Defines for register writes and register array processing */
-+#define I2C_MSG_LENGTH		0x2
-+
-+#define OV5693_FOCAL_LENGTH_NUM	278	/*2.78mm*/
-+#define OV5693_FOCAL_LENGTH_DEM	100
-+#define OV5693_F_NUMBER_DEFAULT_NUM	26
-+#define OV5693_F_NUMBER_DEM	10
-+
-+#define OV5693_MAX_FOCUS_POS	1023
-+#define OV5693_MAX_FOCUS_POS	1023
-+#define OV5693_MAX_FOCUS_NEG	(-1023)
-+
-+#define LARGEST_ALLOWED_RATIO_MISMATCH	800
-+#define RATIO_SHIFT_BITS		13
-+
-+/*
-+ * focal length bits definition:
-+ * bits 31-16: numerator, bits 15-0: denominator
-+ */
-+#define OV5693_FOCAL_LENGTH_DEFAULT 0x1160064
-+
-+/*
-+ * current f-number bits definition:
-+ * bits 31-16: numerator, bits 15-0: denominator
-+ */
-+#define OV5693_F_NUMBER_DEFAULT 0x1a000a
-+
-+/*
-+ * f-number range bits definition:
-+ * bits 31-24: max f-number numerator
-+ * bits 23-16: max f-number denominator
-+ * bits 15-8: min f-number numerator
-+ * bits 7-0: min f-number denominator
-+ */
-+#define OV5693_F_NUMBER_RANGE 0x1a0a1a0a
-+#define OV5693_ID	0x5690
-+
-+#define OV5693_FINE_INTG_TIME_MIN 0
-+#define OV5693_FINE_INTG_TIME_MAX_MARGIN 0
-+#define OV5693_COARSE_INTG_TIME_MIN 1
-+#define OV5693_COARSE_INTG_TIME_MAX_MARGIN (0xffff - 6)
-+#define OV5693_INTEGRATION_TIME_MARGIN	8
-+
-+#define OV5693_BIN_FACTOR_MAX	2
-+
-+/*
-+ * OV5693 System control registers
-+ */
-+#define OV5693_SW_RESET				0x0103
-+#define OV5693_SW_STREAM			0x0100
-+
-+#define OV5693_SC_CMMN_CHIP_ID			0x300a
-+#define OV5693_SC_CMMN_SUB_ID			0x302a /* process, version*/
-+
-+#define OV5693_AEC_PK_EXPO_H			0x3500
-+#define OV5693_AEC_PK_EXPO_M			0x3501
-+#define OV5693_AEC_PK_EXPO_L			0x3502
-+#define OV5693_AGC_ADJ_H			0x350a
-+#define OV5693_VTS_H				0x380e
-+#define OV5693_GROUP_ACCESS			0x3208
-+
-+#define OV5693_MWB_GAIN_R_H			0x3400
-+#define OV5693_MWB_GAIN_G_H			0x3402
-+#define OV5693_MWB_GAIN_B_H			0x3404
-+
-+#define OV5693_H_CROP_START_H			0x3800
-+#define OV5693_V_CROP_START_H			0x3802
-+#define OV5693_H_CROP_END_H			0x3804
-+#define OV5693_V_CROP_END_H			0x3806
-+#define OV5693_H_OUTSIZE_H			0x3808
-+#define OV5693_V_OUTSIZE_H			0x380a
-+
-+#define OV5693_START_STREAMING			0x01
-+#define OV5693_STOP_STREAMING			0x00
-+
-+struct ov5693_vcm {
-+	int (*power_up)(struct v4l2_subdev *sd);
-+	int (*power_down)(struct v4l2_subdev *sd);
-+	int (*init)(struct v4l2_subdev *sd);
-+	int (*t_focus_vcm)(struct v4l2_subdev *sd, u16 val);
-+	int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value);
-+	int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value);
-+	int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value);
-+	int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value);
-+};
-+
-+struct ov5693_resolution {
-+	u8 *desc;
-+	const struct ov5693_reg *regs;
-+	int res;
-+	int width;
-+	int height;
-+	int fps;
-+	int pix_clk_freq;
-+	u16 skip_frames;
-+	u16 pixels_per_line;
-+	u16 lines_per_frame;
-+	u8 bin_factor_x;
-+	u8 bin_factor_y;
-+	u8 bin_mode;
-+	bool used;
-+};
-+
-+struct ov5693_control {
-+	struct v4l2_queryctrl qc;
-+	int (*query)(struct v4l2_subdev *sd, s32 *value);
-+	int (*tweak)(struct v4l2_subdev *sd, s32 value);
-+};
-+
-+/*
-+ * ov5693 device structure.
-+ */
-+struct ov5693_device {
-+	struct v4l2_subdev sd;
-+	struct media_pad pad;
-+	struct v4l2_mbus_framefmt format;
-+	struct mutex input_lock;
-+
-+	struct camera_sensor_platform_data *platform_data;
-+	struct ov5693_vcm *vcm_driver;
-+	int fmt_idx;
-+	u8 res;
-+	u8 type;
-+
-+	struct ov5693_resolution *ov5693_res;
-+	int curr_res_num;
-+
-+	struct v4l2_ctrl_handler ctrl_handler;
-+	struct v4l2_ctrl *run_mode;
-+};
-+
-+enum ov5693_tok_type {
-+	OV5693_8BIT  = 0x0001,
-+	OV5693_16BIT = 0x0002,
-+	OV5693_32BIT = 0x0004,
-+	OV5693_TOK_TERM   = 0xf000,	/* terminating token for reg list */
-+	OV5693_TOK_DELAY  = 0xfe00,	/* delay token for reg list */
-+	OV5693_TOK_MASK = 0xfff0
-+};
-+
-+/**
-+ * struct ov5693_reg - MI sensor  register format
-+ * @type: type of the register
-+ * @reg: 16-bit offset to register
-+ * @val: 8/16/32-bit register value
-+ *
-+ * Define a structure for sensor register initialization values
-+ */
-+struct ov5693_reg {
-+	enum ov5693_tok_type type;
-+	u16 reg;
-+	u32 val;	/* @set value for read/mod/write, @mask */
-+};
-+
-+#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd)
-+
-+#define OV5693_MAX_WRITE_BUF_SIZE	30
-+
-+struct ov5693_write_buffer {
-+	u16 addr;
-+	u8 data[OV5693_MAX_WRITE_BUF_SIZE];
-+};
-+
-+struct ov5693_write_ctrl {
-+	int index;
-+	struct ov5693_write_buffer buffer;
-+};
-+
-+static const struct i2c_device_id ov5693_id[] = {
-+	{OV5693_NAME, 0},
-+	{}
-+};
-+
-+/* ov5693 sensor initialization setting */
-+static struct ov5693_reg const ov5693_init_setting[] = {
-+	{OV5693_8BIT, 0x0103, 0x01},
-+	{OV5693_8BIT, 0x3001, 0x0a},
-+	{OV5693_8BIT, 0x3002, 0x80},
-+	{OV5693_8BIT, 0x3006, 0x00},
-+	{OV5693_8BIT, 0x3011, 0x21},
-+	{OV5693_8BIT, 0x3012, 0x09},
-+	{OV5693_8BIT, 0x3013, 0x10},
-+	{OV5693_8BIT, 0x3014, 0x00},
-+	{OV5693_8BIT, 0x3015, 0x08},
-+	{OV5693_8BIT, 0x3016, 0xf0},
-+	{OV5693_8BIT, 0x3017, 0xf0},
-+	{OV5693_8BIT, 0x3018, 0xf0},
-+	{OV5693_8BIT, 0x301b, 0xb4},
-+	{OV5693_8BIT, 0x301d, 0x02},
-+	{OV5693_8BIT, 0x3021, 0x00},
-+	{OV5693_8BIT, 0x3022, 0x01},
-+	{OV5693_8BIT, 0x3028, 0x44},
-+	{OV5693_8BIT, 0x3098, 0x02},
-+	{OV5693_8BIT, 0x3099, 0x19},
-+	{OV5693_8BIT, 0x309a, 0x02},
-+	{OV5693_8BIT, 0x309b, 0x01},
-+	{OV5693_8BIT, 0x309c, 0x00},
-+	{OV5693_8BIT, 0x30a0, 0xd2},
-+	{OV5693_8BIT, 0x30a2, 0x01},
-+	{OV5693_8BIT, 0x30b2, 0x00},
-+	{OV5693_8BIT, 0x30b3, 0x7d},
-+	{OV5693_8BIT, 0x30b4, 0x03},
-+	{OV5693_8BIT, 0x30b5, 0x04},
-+	{OV5693_8BIT, 0x30b6, 0x01},
-+	{OV5693_8BIT, 0x3104, 0x21},
-+	{OV5693_8BIT, 0x3106, 0x00},
-+
-+	/* Manual white balance */
-+	{OV5693_8BIT, 0x3400, 0x04},
-+	{OV5693_8BIT, 0x3401, 0x00},
-+	{OV5693_8BIT, 0x3402, 0x04},
-+	{OV5693_8BIT, 0x3403, 0x00},
-+	{OV5693_8BIT, 0x3404, 0x04},
-+	{OV5693_8BIT, 0x3405, 0x00},
-+	{OV5693_8BIT, 0x3406, 0x01},
-+
-+	/* Manual exposure control */
-+	{OV5693_8BIT, 0x3500, 0x00},
-+	{OV5693_8BIT, 0x3503, 0x07},
-+	{OV5693_8BIT, 0x3504, 0x00},
-+	{OV5693_8BIT, 0x3505, 0x00},
-+	{OV5693_8BIT, 0x3506, 0x00},
-+	{OV5693_8BIT, 0x3507, 0x02},
-+	{OV5693_8BIT, 0x3508, 0x00},
-+
-+	/* Manual gain control */
-+	{OV5693_8BIT, 0x3509, 0x10},
-+	{OV5693_8BIT, 0x350a, 0x00},
-+	{OV5693_8BIT, 0x350b, 0x40},
-+
-+	{OV5693_8BIT, 0x3601, 0x0a},
-+	{OV5693_8BIT, 0x3602, 0x38},
-+	{OV5693_8BIT, 0x3612, 0x80},
-+	{OV5693_8BIT, 0x3620, 0x54},
-+	{OV5693_8BIT, 0x3621, 0xc7},
-+	{OV5693_8BIT, 0x3622, 0x0f},
-+	{OV5693_8BIT, 0x3625, 0x10},
-+	{OV5693_8BIT, 0x3630, 0x55},
-+	{OV5693_8BIT, 0x3631, 0xf4},
-+	{OV5693_8BIT, 0x3632, 0x00},
-+	{OV5693_8BIT, 0x3633, 0x34},
-+	{OV5693_8BIT, 0x3634, 0x02},
-+	{OV5693_8BIT, 0x364d, 0x0d},
-+	{OV5693_8BIT, 0x364f, 0xdd},
-+	{OV5693_8BIT, 0x3660, 0x04},
-+	{OV5693_8BIT, 0x3662, 0x10},
-+	{OV5693_8BIT, 0x3663, 0xf1},
-+	{OV5693_8BIT, 0x3665, 0x00},
-+	{OV5693_8BIT, 0x3666, 0x20},
-+	{OV5693_8BIT, 0x3667, 0x00},
-+	{OV5693_8BIT, 0x366a, 0x80},
-+	{OV5693_8BIT, 0x3680, 0xe0},
-+	{OV5693_8BIT, 0x3681, 0x00},
-+	{OV5693_8BIT, 0x3700, 0x42},
-+	{OV5693_8BIT, 0x3701, 0x14},
-+	{OV5693_8BIT, 0x3702, 0xa0},
-+	{OV5693_8BIT, 0x3703, 0xd8},
-+	{OV5693_8BIT, 0x3704, 0x78},
-+	{OV5693_8BIT, 0x3705, 0x02},
-+	{OV5693_8BIT, 0x370a, 0x00},
-+	{OV5693_8BIT, 0x370b, 0x20},
-+	{OV5693_8BIT, 0x370c, 0x0c},
-+	{OV5693_8BIT, 0x370d, 0x11},
-+	{OV5693_8BIT, 0x370e, 0x00},
-+	{OV5693_8BIT, 0x370f, 0x40},
-+	{OV5693_8BIT, 0x3710, 0x00},
-+	{OV5693_8BIT, 0x371a, 0x1c},
-+	{OV5693_8BIT, 0x371b, 0x05},
-+	{OV5693_8BIT, 0x371c, 0x01},
-+	{OV5693_8BIT, 0x371e, 0xa1},
-+	{OV5693_8BIT, 0x371f, 0x0c},
-+	{OV5693_8BIT, 0x3721, 0x00},
-+	{OV5693_8BIT, 0x3724, 0x10},
-+	{OV5693_8BIT, 0x3726, 0x00},
-+	{OV5693_8BIT, 0x372a, 0x01},
-+	{OV5693_8BIT, 0x3730, 0x10},
-+	{OV5693_8BIT, 0x3738, 0x22},
-+	{OV5693_8BIT, 0x3739, 0xe5},
-+	{OV5693_8BIT, 0x373a, 0x50},
-+	{OV5693_8BIT, 0x373b, 0x02},
-+	{OV5693_8BIT, 0x373c, 0x41},
-+	{OV5693_8BIT, 0x373f, 0x02},
-+	{OV5693_8BIT, 0x3740, 0x42},
-+	{OV5693_8BIT, 0x3741, 0x02},
-+	{OV5693_8BIT, 0x3742, 0x18},
-+	{OV5693_8BIT, 0x3743, 0x01},
-+	{OV5693_8BIT, 0x3744, 0x02},
-+	{OV5693_8BIT, 0x3747, 0x10},
-+	{OV5693_8BIT, 0x374c, 0x04},
-+	{OV5693_8BIT, 0x3751, 0xf0},
-+	{OV5693_8BIT, 0x3752, 0x00},
-+	{OV5693_8BIT, 0x3753, 0x00},
-+	{OV5693_8BIT, 0x3754, 0xc0},
-+	{OV5693_8BIT, 0x3755, 0x00},
-+	{OV5693_8BIT, 0x3756, 0x1a},
-+	{OV5693_8BIT, 0x3758, 0x00},
-+	{OV5693_8BIT, 0x3759, 0x0f},
-+	{OV5693_8BIT, 0x376b, 0x44},
-+	{OV5693_8BIT, 0x375c, 0x04},
-+	{OV5693_8BIT, 0x3774, 0x10},
-+	{OV5693_8BIT, 0x3776, 0x00},
-+	{OV5693_8BIT, 0x377f, 0x08},
-+	{OV5693_8BIT, 0x3780, 0x22},
-+	{OV5693_8BIT, 0x3781, 0x0c},
-+	{OV5693_8BIT, 0x3784, 0x2c},
-+	{OV5693_8BIT, 0x3785, 0x1e},
-+	{OV5693_8BIT, 0x378f, 0xf5},
-+	{OV5693_8BIT, 0x3791, 0xb0},
-+	{OV5693_8BIT, 0x3795, 0x00},
-+	{OV5693_8BIT, 0x3796, 0x64},
-+	{OV5693_8BIT, 0x3797, 0x11},
-+	{OV5693_8BIT, 0x3798, 0x30},
-+	{OV5693_8BIT, 0x3799, 0x41},
-+	{OV5693_8BIT, 0x379a, 0x07},
-+	{OV5693_8BIT, 0x379b, 0xb0},
-+	{OV5693_8BIT, 0x379c, 0x0c},
-+	{OV5693_8BIT, 0x37c5, 0x00},
-+	{OV5693_8BIT, 0x37c6, 0x00},
-+	{OV5693_8BIT, 0x37c7, 0x00},
-+	{OV5693_8BIT, 0x37c9, 0x00},
-+	{OV5693_8BIT, 0x37ca, 0x00},
-+	{OV5693_8BIT, 0x37cb, 0x00},
-+	{OV5693_8BIT, 0x37de, 0x00},
-+	{OV5693_8BIT, 0x37df, 0x00},
-+	{OV5693_8BIT, 0x3800, 0x00},
-+	{OV5693_8BIT, 0x3801, 0x00},
-+	{OV5693_8BIT, 0x3802, 0x00},
-+	{OV5693_8BIT, 0x3804, 0x0a},
-+	{OV5693_8BIT, 0x3805, 0x3f},
-+	{OV5693_8BIT, 0x3810, 0x00},
-+	{OV5693_8BIT, 0x3812, 0x00},
-+	{OV5693_8BIT, 0x3823, 0x00},
-+	{OV5693_8BIT, 0x3824, 0x00},
-+	{OV5693_8BIT, 0x3825, 0x00},
-+	{OV5693_8BIT, 0x3826, 0x00},
-+	{OV5693_8BIT, 0x3827, 0x00},
-+	{OV5693_8BIT, 0x382a, 0x04},
-+	{OV5693_8BIT, 0x3a04, 0x06},
-+	{OV5693_8BIT, 0x3a05, 0x14},
-+	{OV5693_8BIT, 0x3a06, 0x00},
-+	{OV5693_8BIT, 0x3a07, 0xfe},
-+	{OV5693_8BIT, 0x3b00, 0x00},
-+	{OV5693_8BIT, 0x3b02, 0x00},
-+	{OV5693_8BIT, 0x3b03, 0x00},
-+	{OV5693_8BIT, 0x3b04, 0x00},
-+	{OV5693_8BIT, 0x3b05, 0x00},
-+	{OV5693_8BIT, 0x3e07, 0x20},
-+	{OV5693_8BIT, 0x4000, 0x08},
-+	{OV5693_8BIT, 0x4001, 0x04},
-+	{OV5693_8BIT, 0x4002, 0x45},
-+	{OV5693_8BIT, 0x4004, 0x08},
-+	{OV5693_8BIT, 0x4005, 0x18},
-+	{OV5693_8BIT, 0x4006, 0x20},
-+	{OV5693_8BIT, 0x4008, 0x24},
-+	{OV5693_8BIT, 0x4009, 0x10},
-+	{OV5693_8BIT, 0x400c, 0x00},
-+	{OV5693_8BIT, 0x400d, 0x00},
-+	{OV5693_8BIT, 0x4058, 0x00},
-+	{OV5693_8BIT, 0x404e, 0x37},
-+	{OV5693_8BIT, 0x404f, 0x8f},
-+	{OV5693_8BIT, 0x4058, 0x00},
-+	{OV5693_8BIT, 0x4101, 0xb2},
-+	{OV5693_8BIT, 0x4303, 0x00},
-+	{OV5693_8BIT, 0x4304, 0x08},
-+	{OV5693_8BIT, 0x4307, 0x30},
-+	{OV5693_8BIT, 0x4311, 0x04},
-+	{OV5693_8BIT, 0x4315, 0x01},
-+	{OV5693_8BIT, 0x4511, 0x05},
-+	{OV5693_8BIT, 0x4512, 0x01},
-+	{OV5693_8BIT, 0x4806, 0x00},
-+	{OV5693_8BIT, 0x4816, 0x52},
-+	{OV5693_8BIT, 0x481f, 0x30},
-+	{OV5693_8BIT, 0x4826, 0x2c},
-+	{OV5693_8BIT, 0x4831, 0x64},
-+	{OV5693_8BIT, 0x4d00, 0x04},
-+	{OV5693_8BIT, 0x4d01, 0x71},
-+	{OV5693_8BIT, 0x4d02, 0xfd},
-+	{OV5693_8BIT, 0x4d03, 0xf5},
-+	{OV5693_8BIT, 0x4d04, 0x0c},
-+	{OV5693_8BIT, 0x4d05, 0xcc},
-+	{OV5693_8BIT, 0x4837, 0x0a},
-+	{OV5693_8BIT, 0x5000, 0x06},
-+	{OV5693_8BIT, 0x5001, 0x01},
-+	{OV5693_8BIT, 0x5003, 0x20},
-+	{OV5693_8BIT, 0x5046, 0x0a},
-+	{OV5693_8BIT, 0x5013, 0x00},
-+	{OV5693_8BIT, 0x5046, 0x0a},
-+	{OV5693_8BIT, 0x5780, 0x1c},
-+	{OV5693_8BIT, 0x5786, 0x20},
-+	{OV5693_8BIT, 0x5787, 0x10},
-+	{OV5693_8BIT, 0x5788, 0x18},
-+	{OV5693_8BIT, 0x578a, 0x04},
-+	{OV5693_8BIT, 0x578b, 0x02},
-+	{OV5693_8BIT, 0x578c, 0x02},
-+	{OV5693_8BIT, 0x578e, 0x06},
-+	{OV5693_8BIT, 0x578f, 0x02},
-+	{OV5693_8BIT, 0x5790, 0x02},
-+	{OV5693_8BIT, 0x5791, 0xff},
-+	{OV5693_8BIT, 0x5842, 0x01},
-+	{OV5693_8BIT, 0x5843, 0x2b},
-+	{OV5693_8BIT, 0x5844, 0x01},
-+	{OV5693_8BIT, 0x5845, 0x92},
-+	{OV5693_8BIT, 0x5846, 0x01},
-+	{OV5693_8BIT, 0x5847, 0x8f},
-+	{OV5693_8BIT, 0x5848, 0x01},
-+	{OV5693_8BIT, 0x5849, 0x0c},
-+	{OV5693_8BIT, 0x5e00, 0x00},
-+	{OV5693_8BIT, 0x5e10, 0x0c},
-+	{OV5693_8BIT, 0x0100, 0x00},
-+	{OV5693_TOK_TERM, 0, 0}
-+};
-+
-+/*
-+ * Register settings for various resolution
-+ */
-+
-+/*
-+------------------------------------
-+@@ FULL QSXGA (2592x1944) 15fps 33.33ms VBlank 2lane 10Bit
-+100 99 2592 1944
-+100 98 1 0
-+102 3601 bb8 ;Pather tool use only
-+c8  1 f2 ; New FPGA Board
-+c8 20 22 ; New FPGA Board
-+c8 10 42 ; MIPI DFGA CYCY3 Board use only
-+;
-+c8 f 32  ; input clock to 19.2MHz
-+;
-+; OV5690 setting version History
-+;
-+;
-+; V18b
-+*/
-+static struct ov5693_reg const ov5693_5M_15fps[] = {
-+	{OV5693_8BIT, 0x3501, 0x7b},
-+	{OV5693_8BIT, 0x3502, 0x00},
-+	{OV5693_8BIT, 0x3708, 0xe2},
-+	{OV5693_8BIT, 0x3709, 0xc3},
-+	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
-+	{OV5693_8BIT, 0x3801, 0x00},
-+	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 0 */
-+	{OV5693_8BIT, 0x3803, 0x00},
-+	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
-+	{OV5693_8BIT, 0x3805, 0x3f},
-+	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
-+	{OV5693_8BIT, 0x3807, 0xa3},
-+	{OV5693_8BIT, 0x3808, 0x0a},	/* x output size: 2592 */
-+	{OV5693_8BIT, 0x3809, 0x20},
-+	{OV5693_8BIT, 0x380a, 0x07},	/* y output size: 1944 */
-+	{OV5693_8BIT, 0x380b, 0x98},
-+	{OV5693_8BIT, 0x380c, 0x0e},	/* total x output size: 3688 */
-+	{OV5693_8BIT, 0x380d, 0x68},
-+	{OV5693_8BIT, 0x380e, 0x0f},	/* total y output size: 3968 */
-+	{OV5693_8BIT, 0x380f, 0x80},
-+	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 16 */
-+	{OV5693_8BIT, 0x3811, 0x10},
-+	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 6 */
-+	{OV5693_8BIT, 0x3813, 0x06},
-+	{OV5693_8BIT, 0x3814, 0x11},
-+	{OV5693_8BIT, 0x3815, 0x11},
-+	{OV5693_8BIT, 0x3820, 0x00},
-+	{OV5693_8BIT, 0x3821, 0x1e},
-+	{OV5693_8BIT, 0x5002, 0x00},
-+	{OV5693_TOK_TERM, 0, 0}
-+};
-+
-+/*
-+@@ OV5693 1940x1096 30fps 8.8ms VBlanking 2lane 10Bit(Scaling)
-+100 99 1940 1096
-+100 98 1 0
-+102 3601 bb8 ;Pather tool use only
-+102 40 0 ; HDR Mode off
-+c8  1 f2 ; New FPGA Board
-+c8 20 22 ; New FPGA Board
-+c8 10 42 ; MIPI DFGA CYCY3 Board use only
-+;
-+c8 f 32  ; input clock to 19.2MHz
-+;
-+; OV5690 setting version History
-+;
-+;
-+; V18b
-+*/
-+static struct ov5693_reg const ov5693_1080p_30fps[] = {
-+	{OV5693_8BIT, 0x3501, 0x7b},
-+	{OV5693_8BIT, 0x3502, 0x00},
-+	{OV5693_8BIT, 0x3708, 0xe2},
-+	{OV5693_8BIT, 0x3709, 0xc3},
-+	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
-+	{OV5693_8BIT, 0x3801, 0x00},
-+	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 240 */
-+	{OV5693_8BIT, 0x3803, 0xf0},
-+	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2591 */
-+	{OV5693_8BIT, 0x3805, 0x1f},
-+	{OV5693_8BIT, 0x3806, 0x06},	/* y_addr_end: 1703 */
-+	{OV5693_8BIT, 0x3807, 0xa7},
-+	{OV5693_8BIT, 0x3808, 0x07},	/* x output size: 1940 */
-+	{OV5693_8BIT, 0x3809, 0x94},
-+	{OV5693_8BIT, 0x380a, 0x04},	/* y output size: 1096 */
-+	{OV5693_8BIT, 0x380b, 0x48},
-+	{OV5693_8BIT, 0x380c, 0x0e},	/* total x output size: 3688 */
-+	{OV5693_8BIT, 0x380d, 0x68},
-+	{OV5693_8BIT, 0x380e, 0x0b},	/* total y output size: 2984 */
-+	{OV5693_8BIT, 0x380f, 0xa8},
-+	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 2 */
-+	{OV5693_8BIT, 0x3811, 0x02},
-+	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 2 */
-+	{OV5693_8BIT, 0x3813, 0x02},
-+	{OV5693_8BIT, 0x3814, 0x11},
-+	{OV5693_8BIT, 0x3815, 0x11},
-+	{OV5693_8BIT, 0x3820, 0x00},
-+	{OV5693_8BIT, 0x3821, 0x1e},
-+	{OV5693_8BIT, 0x5002, 0x80},
-+	{OV5693_TOK_TERM, 0, 0}
-+};
-+
-+/*
-+ * 1296x736 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
-+ */
-+static struct ov5693_reg const ov5693_720p_30fps[] = {
-+	{OV5693_8BIT, 0x3501, 0x3d},
-+	{OV5693_8BIT, 0x3502, 0x00},
-+	{OV5693_8BIT, 0x3708, 0xe6},
-+	{OV5693_8BIT, 0x3709, 0xc7},
-+	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
-+	{OV5693_8BIT, 0x3801, 0x00},
-+	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 0 */
-+	{OV5693_8BIT, 0x3803, 0x00},
-+	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
-+	{OV5693_8BIT, 0x3805, 0x3f},
-+	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
-+	{OV5693_8BIT, 0x3807, 0xa3},
-+	{OV5693_8BIT, 0x3808, 0x05},	/* x output size: 1296 */
-+	{OV5693_8BIT, 0x3809, 0x10},
-+	{OV5693_8BIT, 0x380a, 0x02},	/* y output size: 736 */
-+	{OV5693_8BIT, 0x380b, 0xe0},
-+	{OV5693_8BIT, 0x380c, 0x0a},	/* total x output size: 2688 */
-+	{OV5693_8BIT, 0x380d, 0x80},
-+	{OV5693_8BIT, 0x380e, 0x07},	/* total y output size: 1984 */
-+	{OV5693_8BIT, 0x380f, 0xc0},
-+	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 8 */
-+	{OV5693_8BIT, 0x3811, 0x08},
-+	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 2 */
-+	{OV5693_8BIT, 0x3813, 0x02},
-+	{OV5693_8BIT, 0x3814, 0x31},
-+	{OV5693_8BIT, 0x3815, 0x31},
-+	{OV5693_8BIT, 0x3820, 0x04},
-+	{OV5693_8BIT, 0x3821, 0x1f},
-+	{OV5693_8BIT, 0x5002, 0x80},
-+	{OV5693_TOK_TERM, 0, 0}
-+};
-+
-+/*
-+ * 736x496 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
-+ */
-+static struct ov5693_reg const ov5693_480p_30fps[] = {
-+	{OV5693_8BIT, 0x3501, 0x3d},
-+	{OV5693_8BIT, 0x3502, 0x00},
-+	{OV5693_8BIT, 0x3708, 0xe6},
-+	{OV5693_8BIT, 0x3709, 0xc7},
-+	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
-+	{OV5693_8BIT, 0x3801, 0x00},
-+	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 7 */
-+	{OV5693_8BIT, 0x3803, 0x07},
-+	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
-+	{OV5693_8BIT, 0x3805, 0x3f},
-+	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
-+	{OV5693_8BIT, 0x3807, 0xa3},
-+	{OV5693_8BIT, 0x3808, 0x02},	/* x output size: 736 */
-+	{OV5693_8BIT, 0x3809, 0xe0},
-+	{OV5693_8BIT, 0x380a, 0x01},	/* y output size: 496 */
-+	{OV5693_8BIT, 0x380b, 0xf0},
-+	{OV5693_8BIT, 0x380c, 0x0a},	/* total x output size: 2688 */
-+	{OV5693_8BIT, 0x380d, 0x80},
-+	{OV5693_8BIT, 0x380e, 0x07},	/* total y output size: 1984 */
-+	{OV5693_8BIT, 0x380f, 0xc0},
-+	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 8 */
-+	{OV5693_8BIT, 0x3811, 0x08},
-+	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 2 */
-+	{OV5693_8BIT, 0x3813, 0x02},
-+	{OV5693_8BIT, 0x3814, 0x31},
-+	{OV5693_8BIT, 0x3815, 0x31},
-+	{OV5693_8BIT, 0x3820, 0x04},
-+	{OV5693_8BIT, 0x3821, 0x1f},
-+	{OV5693_8BIT, 0x5002, 0x80},
-+	{OV5693_TOK_TERM, 0, 0}
-+};
-+
-+/*
-+@@ OV5693 656x496 30fps 17ms VBlanking 2lane 10Bit(Scaling)
-+100 99 656 496
-+100 98 1 0
-+102 3601 BB8 ;Pather tool use only
-+c8  1 f2 ; New FPGA Board
-+c8 20 22 ; New FPGA Board
-+; OV5690 setting version History
-+;
-+c8 f 32  ; input clock to 19.2MHz
-+;
-+; V18b
-+*/
-+static struct ov5693_reg const ov5693_VGA_30fps[] = {
-+	{OV5693_8BIT, 0x3501, 0x3d},
-+	{OV5693_8BIT, 0x3502, 0x00},
-+	{OV5693_8BIT, 0x3708, 0xe6},
-+	{OV5693_8BIT, 0x3709, 0xc7},
-+	{OV5693_8BIT, 0x3800, 0x00},	/* x_addr_start: 0 */
-+	{OV5693_8BIT, 0x3801, 0x00},
-+	{OV5693_8BIT, 0x3802, 0x00},	/* y_addr_start: 0 */
-+	{OV5693_8BIT, 0x3803, 0x00},
-+	{OV5693_8BIT, 0x3804, 0x0a},	/* x_addr_end: 2623 */
-+	{OV5693_8BIT, 0x3805, 0x3f},
-+	{OV5693_8BIT, 0x3806, 0x07},	/* y_addr_end: 1955 */
-+	{OV5693_8BIT, 0x3807, 0xa3},
-+	{OV5693_8BIT, 0x3808, 0x02},	/* x output size: 656 */
-+	{OV5693_8BIT, 0x3809, 0x90},
-+	{OV5693_8BIT, 0x380a, 0x01},	/* y output size: 496 */
-+	{OV5693_8BIT, 0x380b, 0xf0},
-+	{OV5693_8BIT, 0x380c, 0x0a},	/* total x output size: 2688 */
-+	{OV5693_8BIT, 0x380d, 0x80},
-+	{OV5693_8BIT, 0x380e, 0x07},	/* total y output size: 1984 */
-+	{OV5693_8BIT, 0x380f, 0xc0},
-+	{OV5693_8BIT, 0x3810, 0x00},	/* x offset: 13 */
-+	{OV5693_8BIT, 0x3811, 0x0d},
-+	{OV5693_8BIT, 0x3812, 0x00},	/* y offset: 3 */
-+	{OV5693_8BIT, 0x3813, 0x03},
-+	{OV5693_8BIT, 0x3814, 0x31},
-+	{OV5693_8BIT, 0x3815, 0x31},
-+	{OV5693_8BIT, 0x3820, 0x04},
-+	{OV5693_8BIT, 0x3821, 0x1f},
-+	{OV5693_8BIT, 0x5002, 0x80},
-+	{OV5693_TOK_TERM, 0, 0}
-+};
-+
-+struct ov5693_resolution ov5693_res_preview[] = {
-+	{
-+		.desc = "ov5693_VGA_30fps",
-+		.width = 656,
-+		.height = 496,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 2688,
-+		.lines_per_frame = 1984,
-+		.bin_factor_x = 2,
-+		.bin_factor_y = 2,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_VGA_30fps,
-+	},
-+	{
-+		.desc = "ov5693_1080P_30fps",
-+		.width = 1940,
-+		.height = 1096,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 3688,
-+		.lines_per_frame = 2984,
-+		.bin_factor_x = 0,
-+		.bin_factor_y = 0,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_1080p_30fps,
-+	},
-+	{
-+		.desc = "ov5693_5M_15fps",
-+		.width = 2592,
-+		.height = 1944,
-+		.fps = 15,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 3688,
-+		.lines_per_frame = 3968,
-+		.bin_factor_x = 0,
-+		.bin_factor_y = 0,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_5M_15fps,
-+	},
-+};
-+#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview))
-+
-+struct ov5693_resolution ov5693_res_still[] = {
-+	{
-+		.desc = "ov5693_VGA_30fps",
-+		.width = 656,
-+		.height = 496,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 2688,
-+		.lines_per_frame = 1984,
-+		.bin_factor_x = 2,
-+		.bin_factor_y = 2,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_VGA_30fps,
-+	},
-+	{
-+		.desc = "ov5693_1080P_30fps",
-+		.width = 1940,
-+		.height = 1096,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 3688,
-+		.lines_per_frame = 2984,
-+		.bin_factor_x = 0,
-+		.bin_factor_y = 0,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_1080p_30fps,
-+	},
-+	{
-+		.desc = "ov5693_5M_15fps",
-+		.width = 2592,
-+		.height = 1944,
-+		.fps = 15,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 3688,
-+		.lines_per_frame = 3968,
-+		.bin_factor_x = 0,
-+		.bin_factor_y = 0,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_5M_15fps,
-+	},
-+};
-+#define N_RES_STILL (ARRAY_SIZE(ov5693_res_still))
-+
-+struct ov5693_resolution ov5693_res_video[] = {
-+	{
-+		.desc = "ov5693_VGA_30fps",
-+		.width = 656,
-+		.height = 496,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 2688,
-+		.lines_per_frame = 1984,
-+		.bin_factor_x = 2,
-+		.bin_factor_y = 2,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_VGA_30fps,
-+	},
-+	{
-+		.desc = "ov5693_480P_30fps",
-+		.width = 736,
-+		.height = 496,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 2688,
-+		.lines_per_frame = 1984,
-+		.bin_factor_x = 2,
-+		.bin_factor_y = 2,
-+		.bin_mode = 0,
-+		.skip_frames = 1,
-+		.regs = ov5693_480p_30fps,
-+	},
-+	{
-+		.desc = "ov5693_720p_30fps",
-+		.width = 1296,
-+		.height = 736,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 2688,
-+		.lines_per_frame = 1984,
-+		.bin_factor_x = 2,
-+		.bin_factor_y = 2,
-+		.bin_mode = 0,
-+		.skip_frames = 1,
-+		.regs = ov5693_720p_30fps,
-+	},
-+	{
-+		.desc = "ov5693_1080P_30fps",
-+		.width = 1940,
-+		.height = 1096,
-+		.fps = 30,
-+		.pix_clk_freq = 81,
-+		.used = 0,
-+		.pixels_per_line = 3688,
-+		.lines_per_frame = 2984,
-+		.bin_factor_x = 0,
-+		.bin_factor_y = 0,
-+		.bin_mode = 0,
-+		.skip_frames = 3,
-+		.regs = ov5693_1080p_30fps,
-+	},
-+};
-+#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video))
-+
-+struct ov5693_vcm ov5693_vcm_ops = {
-+	.power_up = ad5823_vcm_power_up,
-+	.power_down = ad5823_vcm_power_down,
-+	.init = ad5823_vcm_init,
-+	.t_focus_vcm = ad5823_t_focus_vcm,
-+	.t_focus_abs = ad5823_t_focus_abs,
-+	.t_focus_rel = ad5823_t_focus_rel,
-+	.q_focus_status = ad5823_q_focus_status,
-+	.q_focus_abs = ad5823_q_focus_abs,
-+};
-+#endif
--- 
-2.24.1
-

+ 3 - 3
patches/4.19/0003-buttons.patch → patches/4.19/0004-surface-buttons.patch

@@ -1,7 +1,7 @@
-From 54e82d57d6201545852600365c240fcf26440226 Mon Sep 17 00:00:00 2001
+From 73b1b21ad56e73a9c33e93df9e10a5ce28b00dd5 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 27 Jul 2019 17:51:37 +0200
-Subject: [PATCH 03/13] buttons
+Subject: [PATCH 04/10] surface-buttons
 
 ---
  drivers/input/misc/Kconfig                |   6 +-
@@ -270,5 +270,5 @@ index 1b491690ce07..96627627060e 100644
  	if (!button)
  		return -ENOMEM;
 -- 
-2.24.1
+2.25.0
 

+ 0 - 6852
patches/4.19/0005-ipts.patch

@@ -1,6852 +0,0 @@
-From 687d4da6fce826b6d0f02c99420badadb262bcb0 Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sat, 28 Sep 2019 17:58:17 +0200
-Subject: [PATCH 05/13] ipts
-
----
- drivers/gpu/drm/i915/Makefile               |    3 +
- drivers/gpu/drm/i915/i915_debugfs.c         |   63 +-
- drivers/gpu/drm/i915/i915_drv.c             |    7 +
- drivers/gpu/drm/i915/i915_drv.h             |    3 +
- drivers/gpu/drm/i915/i915_gem_context.c     |   12 +
- drivers/gpu/drm/i915/i915_irq.c             |    7 +-
- drivers/gpu/drm/i915/i915_params.c          |    5 +-
- drivers/gpu/drm/i915/i915_params.h          |    5 +-
- drivers/gpu/drm/i915/intel_dp.c             |    4 +-
- drivers/gpu/drm/i915/intel_guc.h            |    1 +
- drivers/gpu/drm/i915/intel_guc_submission.c |   90 +-
- drivers/gpu/drm/i915/intel_guc_submission.h |    4 +
- drivers/gpu/drm/i915/intel_ipts.c           |  651 ++++++++++++
- drivers/gpu/drm/i915/intel_ipts.h           |   34 +
- drivers/gpu/drm/i915/intel_lrc.c            |   12 +-
- drivers/gpu/drm/i915/intel_lrc.h            |    8 +
- drivers/gpu/drm/i915/intel_panel.c          |    7 +
- drivers/hid/hid-multitouch.c                |   22 +-
- drivers/misc/Kconfig                        |    1 +
- drivers/misc/Makefile                       |    1 +
- drivers/misc/ipts/Kconfig                   |   11 +
- drivers/misc/ipts/Makefile                  |   17 +
- drivers/misc/ipts/companion/Kconfig         |    9 +
- drivers/misc/ipts/companion/Makefile        |    1 +
- drivers/misc/ipts/companion/ipts-surface.c  |  100 ++
- drivers/misc/ipts/ipts-binary-spec.h        |  118 +++
- drivers/misc/ipts/ipts-dbgfs.c              |  364 +++++++
- drivers/misc/ipts/ipts-fw.c                 |  113 ++
- drivers/misc/ipts/ipts-fw.h                 |   12 +
- drivers/misc/ipts/ipts-gfx.c                |  185 ++++
- drivers/misc/ipts/ipts-gfx.h                |   24 +
- drivers/misc/ipts/ipts-hid.c                |  497 +++++++++
- drivers/misc/ipts/ipts-hid.h                |   34 +
- drivers/misc/ipts/ipts-kernel.c             | 1042 +++++++++++++++++++
- drivers/misc/ipts/ipts-kernel.h             |   23 +
- drivers/misc/ipts/ipts-mei-msgs.h           |  585 +++++++++++
- drivers/misc/ipts/ipts-mei.c                |  290 ++++++
- drivers/misc/ipts/ipts-msg-handler.c        |  437 ++++++++
- drivers/misc/ipts/ipts-msg-handler.h        |   33 +
- drivers/misc/ipts/ipts-params.c             |   21 +
- drivers/misc/ipts/ipts-params.h             |   14 +
- drivers/misc/ipts/ipts-resource.c           |  277 +++++
- drivers/misc/ipts/ipts-resource.h           |   30 +
- drivers/misc/ipts/ipts-sensor-regs.h        |  700 +++++++++++++
- drivers/misc/ipts/ipts-state.h              |   29 +
- drivers/misc/ipts/ipts.h                    |  200 ++++
- drivers/misc/mei/hw-me-regs.h               |    1 +
- drivers/misc/mei/pci-me.c                   |    1 +
- include/linux/intel_ipts_fw.h               |   14 +
- include/linux/intel_ipts_if.h               |   76 ++
- 50 files changed, 6172 insertions(+), 26 deletions(-)
- create mode 100644 drivers/gpu/drm/i915/intel_ipts.c
- create mode 100644 drivers/gpu/drm/i915/intel_ipts.h
- create mode 100644 drivers/misc/ipts/Kconfig
- create mode 100644 drivers/misc/ipts/Makefile
- create mode 100644 drivers/misc/ipts/companion/Kconfig
- create mode 100644 drivers/misc/ipts/companion/Makefile
- create mode 100644 drivers/misc/ipts/companion/ipts-surface.c
- create mode 100644 drivers/misc/ipts/ipts-binary-spec.h
- create mode 100644 drivers/misc/ipts/ipts-dbgfs.c
- create mode 100644 drivers/misc/ipts/ipts-fw.c
- create mode 100644 drivers/misc/ipts/ipts-fw.h
- create mode 100644 drivers/misc/ipts/ipts-gfx.c
- create mode 100644 drivers/misc/ipts/ipts-gfx.h
- create mode 100644 drivers/misc/ipts/ipts-hid.c
- create mode 100644 drivers/misc/ipts/ipts-hid.h
- create mode 100644 drivers/misc/ipts/ipts-kernel.c
- create mode 100644 drivers/misc/ipts/ipts-kernel.h
- create mode 100644 drivers/misc/ipts/ipts-mei-msgs.h
- create mode 100644 drivers/misc/ipts/ipts-mei.c
- create mode 100644 drivers/misc/ipts/ipts-msg-handler.c
- create mode 100644 drivers/misc/ipts/ipts-msg-handler.h
- create mode 100644 drivers/misc/ipts/ipts-params.c
- create mode 100644 drivers/misc/ipts/ipts-params.h
- create mode 100644 drivers/misc/ipts/ipts-resource.c
- create mode 100644 drivers/misc/ipts/ipts-resource.h
- create mode 100644 drivers/misc/ipts/ipts-sensor-regs.h
- create mode 100644 drivers/misc/ipts/ipts-state.h
- create mode 100644 drivers/misc/ipts/ipts.h
- create mode 100644 include/linux/intel_ipts_fw.h
- create mode 100644 include/linux/intel_ipts_if.h
-
-diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
-index 5794f102f9b8..6ae0e91a213a 100644
---- a/drivers/gpu/drm/i915/Makefile
-+++ b/drivers/gpu/drm/i915/Makefile
-@@ -155,6 +155,9 @@ i915-y += dvo_ch7017.o \
- 	  vlv_dsi.o \
- 	  vlv_dsi_pll.o
- 
-+# intel precise touch & stylus
-+i915-y  += intel_ipts.o
-+
- # Post-mortem debug and GPU hang state capture
- i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
- i915-$(CONFIG_DRM_I915_SELFTEST) += \
-diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
-index e063e98d1e82..32d648c8adc5 100644
---- a/drivers/gpu/drm/i915/i915_debugfs.c
-+++ b/drivers/gpu/drm/i915/i915_debugfs.c
-@@ -31,6 +31,7 @@
- #include <linux/sched/mm.h>
- #include "intel_drv.h"
- #include "intel_guc_submission.h"
-+#include "intel_ipts.h"
- 
- static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node)
- {
-@@ -4695,6 +4696,64 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
- 	.llseek = default_llseek,
- };
- 
-+static ssize_t
-+i915_intel_ipts_cleanup_write(struct file *filp,
-+			       const char __user *ubuf,
-+			       size_t cnt, loff_t *ppos)
-+{
-+	struct drm_i915_private *dev_priv = filp->private_data;
-+	struct drm_device *dev = &dev_priv->drm;
-+	int ret;
-+	bool flag;
-+
-+	ret = kstrtobool_from_user(ubuf, cnt, &flag);
-+	if (ret)
-+		return ret;
-+
-+	if (!flag)
-+		return cnt;
-+
-+	intel_ipts_cleanup(dev);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations i915_intel_ipts_cleanup_ops = {
-+	.owner = THIS_MODULE,
-+	.open = simple_open,
-+	.write = i915_intel_ipts_cleanup_write,
-+	.llseek = default_llseek,
-+};
-+
-+static ssize_t
-+i915_intel_ipts_init_write(struct file *filp,
-+			       const char __user *ubuf,
-+			       size_t cnt, loff_t *ppos)
-+{
-+	struct drm_i915_private *dev_priv = filp->private_data;
-+	struct drm_device *dev = &dev_priv->drm;
-+	int ret;
-+	bool flag;
-+
-+	ret = kstrtobool_from_user(ubuf, cnt, &flag);
-+	if (ret)
-+		return ret;
-+
-+	if (!flag)
-+		return cnt;
-+
-+	intel_ipts_init(dev);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations i915_intel_ipts_init_ops = {
-+	.owner = THIS_MODULE,
-+	.open = simple_open,
-+	.write = i915_intel_ipts_init_write,
-+	.llseek = default_llseek,
-+};
-+
- static const struct drm_info_list i915_debugfs_list[] = {
- 	{"i915_capabilities", i915_capabilities, 0},
- 	{"i915_gem_objects", i915_gem_object_info, 0},
-@@ -4773,7 +4832,9 @@ static const struct i915_debugfs_files {
- 	{"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
- 	{"i915_ipc_status", &i915_ipc_status_fops},
- 	{"i915_drrs_ctl", &i915_drrs_ctl_fops},
--	{"i915_edp_psr_debug", &i915_edp_psr_debug_fops}
-+	{"i915_edp_psr_debug", &i915_edp_psr_debug_fops},
-+	{"i915_intel_ipts_cleanup", &i915_intel_ipts_cleanup_ops},
-+	{"i915_intel_ipts_init", &i915_intel_ipts_init_ops},
- };
- 
- int i915_debugfs_register(struct drm_i915_private *dev_priv)
-diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
-index b0d76a7a0946..7598616d9122 100644
---- a/drivers/gpu/drm/i915/i915_drv.c
-+++ b/drivers/gpu/drm/i915/i915_drv.c
-@@ -53,6 +53,7 @@
- #include "i915_vgpu.h"
- #include "intel_drv.h"
- #include "intel_uc.h"
-+#include "intel_ipts.h"
- 
- static struct drm_driver driver;
- 
-@@ -696,6 +697,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
- 	/* Only enable hotplug handling once the fbdev is fully set up. */
- 	intel_hpd_init(dev_priv);
- 
-+	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
-+        intel_ipts_init(dev);
-+
- 	return 0;
- 
- cleanup_gem:
-@@ -1438,6 +1442,9 @@ void i915_driver_unload(struct drm_device *dev)
- 	struct drm_i915_private *dev_priv = to_i915(dev);
- 	struct pci_dev *pdev = dev_priv->drm.pdev;
- 
-+	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
-+		intel_ipts_cleanup(dev);
-+
- 	i915_driver_unregister(dev_priv);
- 
- 	if (i915_gem_suspend(dev_priv))
-diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
-index db2e9af49ae6..99bc0c92c411 100644
---- a/drivers/gpu/drm/i915/i915_drv.h
-+++ b/drivers/gpu/drm/i915/i915_drv.h
-@@ -3232,6 +3232,9 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj,
- void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj,
- 					 struct sg_table *pages);
- 
-+struct i915_gem_context *
-+i915_gem_context_create_ipts(struct drm_device *dev);
-+
- static inline struct i915_gem_context *
- __i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
- {
-diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
-index 7a0e6dbbad2e..e805c1de54f6 100644
---- a/drivers/gpu/drm/i915/i915_gem_context.c
-+++ b/drivers/gpu/drm/i915/i915_gem_context.c
-@@ -472,6 +472,18 @@ static bool needs_preempt_context(struct drm_i915_private *i915)
- 	return HAS_LOGICAL_RING_PREEMPTION(i915);
- }
- 
-+struct i915_gem_context *i915_gem_context_create_ipts(struct drm_device *dev)
-+{
-+	struct drm_i915_private *dev_priv = to_i915(dev);
-+	struct i915_gem_context *ctx;
-+
-+	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-+
-+	ctx = i915_gem_create_context(dev_priv, NULL);
-+
-+	return ctx;
-+}
-+
- int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
- {
- 	struct i915_gem_context *ctx;
-diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
-index 29877969310d..f98fdb5fc282 100644
---- a/drivers/gpu/drm/i915/i915_irq.c
-+++ b/drivers/gpu/drm/i915/i915_irq.c
-@@ -36,6 +36,7 @@
- #include "i915_drv.h"
- #include "i915_trace.h"
- #include "intel_drv.h"
-+#include "intel_ipts.h"
- 
- /**
-  * DOC: interrupt handling
-@@ -1503,6 +1504,9 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
- 		tasklet |= USES_GUC_SUBMISSION(engine->i915);
- 	}
- 
-+	if (iir & GT_RENDER_PIPECTL_NOTIFY_INTERRUPT && i915_modparams.enable_ipts)
-+		intel_ipts_notify_complete();
-+
- 	if (tasklet)
- 		tasklet_hi_schedule(&engine->execlists.tasklet);
- }
-@@ -4122,7 +4126,8 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
- {
- 	/* These are interrupts we'll toggle with the ring mask register */
- 	uint32_t gt_interrupts[] = {
--		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
-+		GT_RENDER_PIPECTL_NOTIFY_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
-+			GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
- 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
- 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
- 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
-diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
-index 295e981e4a39..84415814c007 100644
---- a/drivers/gpu/drm/i915/i915_params.c
-+++ b/drivers/gpu/drm/i915/i915_params.c
-@@ -145,7 +145,10 @@ i915_param_named_unsafe(edp_vswing, int, 0400,
- i915_param_named_unsafe(enable_guc, int, 0400,
- 	"Enable GuC load for GuC submission and/or HuC load. "
- 	"Required functionality can be selected using bitmask values. "
--	"(-1=auto, 0=disable [default], 1=GuC submission, 2=HuC load)");
-+	"(-1=auto [default], 0=disable, 1=GuC submission, 2=HuC load)");
-+
-+i915_param_named_unsafe(enable_ipts, int, 0400,
-+	"Enable IPTS Touchscreen and Pen support (default: 1)");
- 
- i915_param_named(guc_log_level, int, 0400,
- 	"GuC firmware logging level. Requires GuC to be loaded. "
-diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
-index 6c4d4a21474b..4ab800c3de6d 100644
---- a/drivers/gpu/drm/i915/i915_params.h
-+++ b/drivers/gpu/drm/i915/i915_params.h
-@@ -46,7 +46,7 @@ struct drm_printer;
- 	param(int, disable_power_well, -1) \
- 	param(int, enable_ips, 1) \
- 	param(int, invert_brightness, 0) \
--	param(int, enable_guc, 0) \
-+	param(int, enable_guc, -1) \
- 	param(int, guc_log_level, -1) \
- 	param(char *, guc_firmware_path, NULL) \
- 	param(char *, huc_firmware_path, NULL) \
-@@ -68,7 +68,8 @@ struct drm_printer;
- 	param(bool, nuclear_pageflip, false) \
- 	param(bool, enable_dp_mst, true) \
- 	param(bool, enable_dpcd_backlight, false) \
--	param(bool, enable_gvt, false)
-+	param(bool, enable_gvt, false) \
-+	param(int, enable_ipts, 1)
- 
- #define MEMBER(T, member, ...) T member;
- struct i915_params {
-diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
-index 20cd4c8acecc..6ec301a91e87 100644
---- a/drivers/gpu/drm/i915/intel_dp.c
-+++ b/drivers/gpu/drm/i915/intel_dp.c
-@@ -2634,8 +2634,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
- 		return;
- 
- 	if (mode != DRM_MODE_DPMS_ON) {
--		if (downstream_hpd_needs_d0(intel_dp))
--			return;
-+		//if (downstream_hpd_needs_d0(intel_dp))
-+		//	return;
- 
- 		ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
- 					 DP_SET_POWER_D3);
-diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
-index 4121928a495e..8967376accf3 100644
---- a/drivers/gpu/drm/i915/intel_guc.h
-+++ b/drivers/gpu/drm/i915/intel_guc.h
-@@ -69,6 +69,7 @@ struct intel_guc {
- 
- 	struct intel_guc_client *execbuf_client;
- 	struct intel_guc_client *preempt_client;
-+	struct intel_guc_client *ipts_client;
- 
- 	struct guc_preempt_work preempt_work[I915_NUM_ENGINES];
- 	struct workqueue_struct *preempt_wq;
-diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
-index 4aa5e6463e7b..f60c42390006 100644
---- a/drivers/gpu/drm/i915/intel_guc_submission.c
-+++ b/drivers/gpu/drm/i915/intel_guc_submission.c
-@@ -88,12 +88,17 @@ static inline struct i915_priolist *to_priolist(struct rb_node *rb)
- 
- static inline bool is_high_priority(struct intel_guc_client *client)
- {
--	return (client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH ||
--		client->priority == GUC_CLIENT_PRIORITY_HIGH);
-+	return (client->priority == GUC_CLIENT_PRIORITY_HIGH);
-+}
-+
-+static inline bool is_high_priority_kmd(struct intel_guc_client *client)
-+{
-+	return (client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH);
- }
- 
- static int reserve_doorbell(struct intel_guc_client *client)
- {
-+	struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
- 	unsigned long offset;
- 	unsigned long end;
- 	u16 id;
-@@ -106,10 +111,15 @@ static int reserve_doorbell(struct intel_guc_client *client)
- 	 * priority contexts, the second half for high-priority ones.
- 	 */
- 	offset = 0;
--	end = GUC_NUM_DOORBELLS / 2;
--	if (is_high_priority(client)) {
--		offset = end;
--		end += offset;
-+	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
-+		end = GUC_NUM_DOORBELLS;
-+	}
-+	else {
-+		end = GUC_NUM_DOORBELLS/2;
-+		if (is_high_priority(client)) {
-+			offset = end;
-+			end += offset;
-+		}
- 	}
- 
- 	id = find_next_zero_bit(client->guc->doorbell_bitmap, end, offset);
-@@ -355,9 +365,15 @@ static void guc_stage_desc_init(struct intel_guc *guc,
- 	desc = __get_stage_desc(client);
- 	memset(desc, 0, sizeof(*desc));
- 
--	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE |
--			  GUC_STAGE_DESC_ATTR_KERNEL;
--	if (is_high_priority(client))
-+	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE;
-+	if ((client->priority == GUC_CLIENT_PRIORITY_KMD_NORMAL) ||
-+			(client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH)) {
-+		desc->attribute  |= GUC_STAGE_DESC_ATTR_KERNEL;
-+	} else {
-+		desc->attribute  |= GUC_STAGE_DESC_ATTR_PCH;
-+	}
-+
-+	if (is_high_priority_kmd(client))
- 		desc->attribute |= GUC_STAGE_DESC_ATTR_PREEMPT;
- 	desc->stage_id = client->stage_id;
- 	desc->priority = client->priority;
-@@ -1204,7 +1220,8 @@ static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
- 		I915_WRITE(RING_MODE_GEN7(engine), irqs);
- 
- 	/* route USER_INTERRUPT to Host, all others are sent to GuC. */
--	irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
-+	irqs = (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)
-+							<< GEN8_RCS_IRQ_SHIFT |
- 	       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
- 	/* These three registers have the same bit definitions */
- 	I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
-@@ -1349,6 +1366,59 @@ void intel_guc_submission_disable(struct intel_guc *guc)
- 	guc_clients_doorbell_fini(guc);
- }
- 
-+int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv,
-+				    struct i915_gem_context *ctx)
-+{
-+	struct intel_guc *guc = &dev_priv->guc;
-+	struct intel_guc_client *client;
-+	int err;
-+	int ret;
-+
-+	/* client for execbuf submission */
-+	client = guc_client_alloc(dev_priv,
-+				  INTEL_INFO(dev_priv)->ring_mask,
-+				  IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ? GUC_CLIENT_PRIORITY_HIGH : GUC_CLIENT_PRIORITY_NORMAL,
-+				  ctx);
-+	if (IS_ERR(client)) {
-+		DRM_ERROR("Failed to create normal GuC client!\n");
-+		return -ENOMEM;
-+	}
-+
-+	guc->ipts_client = client;
-+
-+	err = intel_guc_sample_forcewake(guc);
-+	if (err)
-+		return err;
-+
-+	ret = create_doorbell(guc->ipts_client);
-+	if (ret)
-+		return ret;
-+
-+	return 0;
-+}
-+
-+void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv)
-+{
-+	struct intel_guc *guc = &dev_priv->guc;
-+
-+	if (!guc->ipts_client)
-+		return;
-+
-+	destroy_doorbell(guc->ipts_client);
-+	guc_client_free(guc->ipts_client);
-+	guc->ipts_client = NULL;
-+}
-+
-+void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv)
-+{
-+	struct intel_guc *guc = &dev_priv->guc;
-+
-+	int err = __guc_allocate_doorbell(guc, guc->ipts_client->stage_id);
-+
-+	if (err)
-+		DRM_ERROR("Not able to reacquire IPTS doorbell\n");
-+}
-+
- #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
- #include "selftests/intel_guc.c"
- #endif
-diff --git a/drivers/gpu/drm/i915/intel_guc_submission.h b/drivers/gpu/drm/i915/intel_guc_submission.h
-index fb081cefef93..71fc7986585a 100644
---- a/drivers/gpu/drm/i915/intel_guc_submission.h
-+++ b/drivers/gpu/drm/i915/intel_guc_submission.h
-@@ -79,5 +79,9 @@ void intel_guc_submission_disable(struct intel_guc *guc);
- void intel_guc_submission_fini(struct intel_guc *guc);
- int intel_guc_preempt_work_create(struct intel_guc *guc);
- void intel_guc_preempt_work_destroy(struct intel_guc *guc);
-+int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv,
-+				    struct i915_gem_context *ctx);
-+void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv);
-+void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv);
- 
- #endif
-diff --git a/drivers/gpu/drm/i915/intel_ipts.c b/drivers/gpu/drm/i915/intel_ipts.c
-new file mode 100644
-index 000000000000..8ad1d22df5cd
---- /dev/null
-+++ b/drivers/gpu/drm/i915/intel_ipts.c
-@@ -0,0 +1,651 @@
-+/*
-+ * Copyright  2016 Intel Corporation
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ *
-+ */
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/intel_ipts_if.h>
-+#include <drm/drmP.h>
-+
-+#include "intel_guc_submission.h"
-+#include "i915_drv.h"
-+
-+#define SUPPORTED_IPTS_INTERFACE_VERSION	1
-+
-+#define REACQUIRE_DB_THRESHOLD				10
-+#define DB_LOST_CHECK_STEP1_INTERVAL		2500	/* ms */
-+#define DB_LOST_CHECK_STEP2_INTERVAL		1000	/* ms */
-+
-+/* intel IPTS ctx for ipts support */
-+typedef struct intel_ipts {
-+	struct drm_device *dev;
-+	struct i915_gem_context *ipts_context;
-+	intel_ipts_callback_t ipts_clbks;
-+
-+	/* buffers' list */
-+	struct {
-+		spinlock_t       lock;
-+		struct list_head list;
-+	} buffers;
-+
-+	void *data;
-+
-+	struct delayed_work reacquire_db_work;
-+	intel_ipts_wq_info_t wq_info;
-+	u32	old_tail;
-+	u32	old_head;
-+	bool	need_reacquire_db;
-+
-+	bool	connected;
-+	bool	initialized;
-+} intel_ipts_t;
-+
-+intel_ipts_t intel_ipts;
-+
-+typedef struct intel_ipts_object {
-+	struct list_head list;
-+	struct drm_i915_gem_object *gem_obj;
-+	void	*cpu_addr;
-+} intel_ipts_object_t;
-+
-+static intel_ipts_object_t *ipts_object_create(size_t size, u32 flags)
-+{
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+	intel_ipts_object_t *obj = NULL;
-+	struct drm_i915_gem_object *gem_obj = NULL;
-+	int ret = 0;
-+
-+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
-+	if (!obj)
-+		return NULL;
-+
-+	size = roundup(size, PAGE_SIZE);
-+	if (size == 0) {
-+		ret = -EINVAL;
-+		goto err_out;
-+	}
-+
-+	/* Allocate the new object */
-+	gem_obj = i915_gem_object_create(dev_priv, size);
-+	if (gem_obj == NULL) {
-+		ret = -ENOMEM;
-+		goto err_out;
-+	}
-+
-+	if (flags & IPTS_BUF_FLAG_CONTIGUOUS) {
-+		ret = i915_gem_object_attach_phys(gem_obj, PAGE_SIZE);
-+		if (ret) {
-+			pr_info(">> ipts no contiguous : %d\n", ret);
-+			goto err_out;
-+		}
-+	}
-+
-+	obj->gem_obj = gem_obj;
-+
-+	spin_lock(&intel_ipts.buffers.lock);
-+	list_add_tail(&obj->list, &intel_ipts.buffers.list);
-+	spin_unlock(&intel_ipts.buffers.lock);
-+
-+	return obj;
-+
-+err_out:
-+	if (gem_obj)
-+		i915_gem_free_object(&gem_obj->base);
-+
-+	if (obj)
-+		kfree(obj);
-+
-+	return NULL;
-+}
-+
-+static void ipts_object_free(intel_ipts_object_t* obj)
-+{
-+	spin_lock(&intel_ipts.buffers.lock);
-+	list_del(&obj->list);
-+	spin_unlock(&intel_ipts.buffers.lock);
-+
-+	i915_gem_free_object(&obj->gem_obj->base);
-+	kfree(obj);
-+}
-+
-+static int ipts_object_pin(intel_ipts_object_t* obj,
-+					struct i915_gem_context *ipts_ctx)
-+{
-+	struct i915_address_space *vm = NULL;
-+	struct i915_vma *vma = NULL;
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+	int ret = 0;
-+
-+	if (ipts_ctx->ppgtt) {
-+		vm = &ipts_ctx->ppgtt->vm;
-+	} else {
-+		vm = &dev_priv->ggtt.vm;
-+	}
-+
-+	vma = i915_vma_instance(obj->gem_obj, vm, NULL);
-+	if (IS_ERR(vma)) {
-+		DRM_ERROR("cannot find or create vma\n");
-+		return -1;
-+	}
-+
-+	ret = i915_vma_pin(vma, 0, PAGE_SIZE, PIN_USER);
-+
-+	return ret;
-+}
-+
-+static void ipts_object_unpin(intel_ipts_object_t *obj)
-+{
-+	/* TBD: Add support */
-+}
-+
-+static void* ipts_object_map(intel_ipts_object_t *obj)
-+{
-+
-+	return i915_gem_object_pin_map(obj->gem_obj, I915_MAP_WB);
-+}
-+
-+static void ipts_object_unmap(intel_ipts_object_t* obj)
-+{
-+	i915_gem_object_unpin_map(obj->gem_obj);
-+	obj->cpu_addr = NULL;
-+}
-+
-+static int create_ipts_context(void)
-+{
-+	struct i915_gem_context *ipts_ctx = NULL;
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+	struct intel_context *ce = NULL;
-+	struct intel_context *pin_ret;
-+	int ret = 0;
-+
-+	/* Initialize the context right away.*/
-+	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
-+	if (ret) {
-+		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
-+		return ret;
-+	}
-+
-+	ipts_ctx = i915_gem_context_create_ipts(intel_ipts.dev);
-+	if (IS_ERR(ipts_ctx)) {
-+		DRM_ERROR("Failed to create IPTS context (error %ld)\n",
-+			  PTR_ERR(ipts_ctx));
-+		ret = PTR_ERR(ipts_ctx);
-+		goto err_unlock;
-+	}
-+
-+	ce = to_intel_context(ipts_ctx, dev_priv->engine[RCS]);
-+	if (IS_ERR(ce)) {
-+		DRM_ERROR("Failed to create intel context (error %ld)\n",
-+			  PTR_ERR(ce));
-+		ret = PTR_ERR(ce);
-+		goto err_unlock;
-+	}
-+
-+	ret = execlists_context_deferred_alloc(ipts_ctx, dev_priv->engine[RCS], ce);
-+	if (ret) {
-+		DRM_DEBUG("lr context allocation failed : %d\n", ret);
-+		goto err_ctx;
-+	}
-+
-+	pin_ret = execlists_context_pin(dev_priv->engine[RCS], ipts_ctx);
-+	if (IS_ERR(pin_ret)) {
-+		DRM_DEBUG("lr context pinning failed :  %ld\n", PTR_ERR(pin_ret));
-+		goto err_ctx;
-+	}
-+
-+	/* Release the mutex */
-+	mutex_unlock(&intel_ipts.dev->struct_mutex);
-+
-+	spin_lock_init(&intel_ipts.buffers.lock);
-+	INIT_LIST_HEAD(&intel_ipts.buffers.list);
-+
-+	intel_ipts.ipts_context = ipts_ctx;
-+
-+	return 0;
-+
-+err_ctx:
-+	if (ipts_ctx)
-+		i915_gem_context_put(ipts_ctx);
-+
-+err_unlock:
-+	mutex_unlock(&intel_ipts.dev->struct_mutex);
-+
-+	return ret;
-+}
-+
-+static void destroy_ipts_context(void)
-+{
-+	struct i915_gem_context *ipts_ctx = NULL;
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+	struct intel_context *ce = NULL;
-+	int ret = 0;
-+
-+	ipts_ctx = intel_ipts.ipts_context;
-+
-+	ce = to_intel_context(ipts_ctx, dev_priv->engine[RCS]);
-+
-+	/* Initialize the context right away.*/
-+	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
-+	if (ret) {
-+		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
-+		return;
-+	}
-+
-+	execlists_context_unpin(ce);
-+	i915_gem_context_put(ipts_ctx);
-+
-+	mutex_unlock(&intel_ipts.dev->struct_mutex);
-+}
-+
-+int intel_ipts_notify_complete(void)
-+{
-+	if (intel_ipts.ipts_clbks.workload_complete)
-+		intel_ipts.ipts_clbks.workload_complete(intel_ipts.data);
-+
-+	return 0;
-+}
-+
-+int intel_ipts_notify_backlight_status(bool backlight_on)
-+{
-+	if (intel_ipts.ipts_clbks.notify_gfx_status) {
-+		if (backlight_on) {
-+			intel_ipts.ipts_clbks.notify_gfx_status(
-+						IPTS_NOTIFY_STA_BACKLIGHT_ON,
-+						intel_ipts.data);
-+			schedule_delayed_work(&intel_ipts.reacquire_db_work,
-+				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
-+		} else {
-+			intel_ipts.ipts_clbks.notify_gfx_status(
-+						IPTS_NOTIFY_STA_BACKLIGHT_OFF,
-+						intel_ipts.data);
-+			cancel_delayed_work(&intel_ipts.reacquire_db_work);
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static void intel_ipts_reacquire_db(intel_ipts_t *intel_ipts_p)
-+{
-+	int ret = 0;
-+
-+	ret = i915_mutex_lock_interruptible(intel_ipts_p->dev);
-+	if (ret) {
-+		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
-+		return;
-+	}
-+
-+	/* Reacquire the doorbell */
-+	i915_guc_ipts_reacquire_doorbell(intel_ipts_p->dev->dev_private);
-+
-+	mutex_unlock(&intel_ipts_p->dev->struct_mutex);
-+
-+	return;
-+}
-+
-+static int intel_ipts_get_wq_info(uint64_t gfx_handle,
-+						intel_ipts_wq_info_t *wq_info)
-+{
-+	if (gfx_handle != (uint64_t)&intel_ipts) {
-+		DRM_ERROR("invalid gfx handle\n");
-+		return -EINVAL;
-+	}
-+
-+	*wq_info = intel_ipts.wq_info;
-+
-+	intel_ipts_reacquire_db(&intel_ipts);
-+	schedule_delayed_work(&intel_ipts.reacquire_db_work,
-+				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
-+
-+	return 0;
-+}
-+
-+static int set_wq_info(void)
-+{
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+	struct intel_guc *guc = &dev_priv->guc;
-+	struct intel_guc_client *client;
-+	struct guc_process_desc *desc;
-+	void *base = NULL;
-+	intel_ipts_wq_info_t *wq_info;
-+	u64 phy_base = 0;
-+
-+	wq_info = &intel_ipts.wq_info;
-+
-+	client = guc->ipts_client;
-+	if (!client) {
-+		DRM_ERROR("IPTS GuC client is NOT available\n");
-+		return -EINVAL;
-+	}
-+
-+	base = client->vaddr;
-+	desc = (struct guc_process_desc *)((u64)base + client->proc_desc_offset);
-+
-+	desc->wq_base_addr = (u64)base + GUC_DB_SIZE;
-+	desc->db_base_addr = (u64)base + client->doorbell_offset;
-+
-+	/* IPTS expects physical addresses to pass it to ME */
-+	phy_base = sg_dma_address(client->vma->pages->sgl);
-+
-+	wq_info->db_addr = desc->db_base_addr;
-+        wq_info->db_phy_addr = phy_base + client->doorbell_offset;
-+        wq_info->db_cookie_offset = offsetof(struct guc_doorbell_info, cookie);
-+        wq_info->wq_addr = desc->wq_base_addr;
-+        wq_info->wq_phy_addr = phy_base + GUC_DB_SIZE;
-+        wq_info->wq_head_addr = (u64)&desc->head;
-+        wq_info->wq_head_phy_addr = phy_base + client->proc_desc_offset +
-+					offsetof(struct guc_process_desc, head);
-+        wq_info->wq_tail_addr = (u64)&desc->tail;
-+        wq_info->wq_tail_phy_addr = phy_base + client->proc_desc_offset +
-+					offsetof(struct guc_process_desc, tail);
-+        wq_info->wq_size = desc->wq_size_bytes;
-+
-+	return 0;
-+}
-+
-+static int intel_ipts_init_wq(void)
-+{
-+	int ret = 0;
-+
-+	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
-+	if (ret) {
-+		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
-+		return ret;
-+	}
-+
-+	/* disable IPTS submission */
-+	i915_guc_ipts_submission_disable(intel_ipts.dev->dev_private);
-+
-+	/* enable IPTS submission */
-+	ret = i915_guc_ipts_submission_enable(intel_ipts.dev->dev_private,
-+							intel_ipts.ipts_context);
-+	if (ret) {
-+		DRM_ERROR("i915_guc_ipts_submission_enable failed : %d\n", ret);
-+		goto out;
-+        }
-+
-+	ret = set_wq_info();
-+	if (ret) {
-+		DRM_ERROR("set_wq_info failed\n");
-+		goto out;
-+	}
-+
-+out:
-+	mutex_unlock(&intel_ipts.dev->struct_mutex);
-+
-+	return ret;
-+}
-+
-+static void intel_ipts_release_wq(void)
-+{
-+	int ret = 0;
-+
-+	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
-+	if (ret) {
-+		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
-+		return;
-+	}
-+
-+	/* disable IPTS submission */
-+	i915_guc_ipts_submission_disable(intel_ipts.dev->dev_private);
-+
-+	mutex_unlock(&intel_ipts.dev->struct_mutex);
-+}
-+
-+static int intel_ipts_map_buffer(u64 gfx_handle, intel_ipts_mapbuffer_t *mapbuf)
-+{
-+	intel_ipts_object_t* obj;
-+	struct i915_gem_context *ipts_ctx = NULL;
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+	struct i915_address_space *vm = NULL;
-+	struct i915_vma *vma = NULL;
-+	int ret = 0;
-+
-+	if (gfx_handle != (uint64_t)&intel_ipts) {
-+		DRM_ERROR("invalid gfx handle\n");
-+		return -EINVAL;
-+	}
-+
-+	/* Acquire mutex first */
-+	ret = i915_mutex_lock_interruptible(intel_ipts.dev);
-+	if (ret) {
-+		DRM_ERROR("i915_mutex_lock_interruptible failed \n");
-+		return -EINVAL;
-+	}
-+
-+	obj = ipts_object_create(mapbuf->size, mapbuf->flags);
-+	if (!obj)
-+		return -ENOMEM;
-+
-+	ipts_ctx = intel_ipts.ipts_context;
-+	ret = ipts_object_pin(obj, ipts_ctx);
-+	if (ret) {
-+		DRM_ERROR("Not able to pin iTouch obj\n");
-+		ipts_object_free(obj);
-+		mutex_unlock(&intel_ipts.dev->struct_mutex);
-+		return -ENOMEM;
-+	}
-+
-+	if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS) {
-+		obj->cpu_addr = obj->gem_obj->phys_handle->vaddr;
-+	} else {
-+		obj->cpu_addr = ipts_object_map(obj);
-+	}
-+
-+	if (ipts_ctx->ppgtt) {
-+		vm = &ipts_ctx->ppgtt->vm;
-+	} else {
-+		vm = &dev_priv->ggtt.vm;
-+	}
-+
-+	vma = i915_vma_instance(obj->gem_obj, vm, NULL);
-+	if (IS_ERR(vma)) {
-+		DRM_ERROR("cannot find or create vma\n");
-+		return -EINVAL;
-+	}
-+
-+	mapbuf->gfx_addr = (void*)vma->node.start;
-+	mapbuf->cpu_addr = (void*)obj->cpu_addr;
-+	mapbuf->buf_handle = (u64)obj;
-+	if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS) {
-+		mapbuf->phy_addr = (u64)obj->gem_obj->phys_handle->busaddr;
-+	}
-+
-+	/* Release the mutex */
-+	mutex_unlock(&intel_ipts.dev->struct_mutex);
-+
-+	return 0;
-+}
-+
-+static int intel_ipts_unmap_buffer(uint64_t gfx_handle, uint64_t buf_handle)
-+{
-+	intel_ipts_object_t* obj = (intel_ipts_object_t*)buf_handle;
-+
-+	if (gfx_handle != (uint64_t)&intel_ipts) {
-+		DRM_ERROR("invalid gfx handle\n");
-+		return -EINVAL;
-+	}
-+
-+	if (!obj->gem_obj->phys_handle)
-+		ipts_object_unmap(obj);
-+	ipts_object_unpin(obj);
-+	ipts_object_free(obj);
-+
-+	return 0;
-+}
-+
-+int intel_ipts_connect(intel_ipts_connect_t *ipts_connect)
-+{
-+	u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
-+	struct drm_i915_private *dev_priv = to_i915(intel_ipts.dev);
-+
-+	if (!intel_ipts.initialized)
-+		return -EIO;
-+
-+	if (!ipts_connect)
-+		return -EINVAL;
-+
-+	if (ipts_connect->if_version > SUPPORTED_IPTS_INTERFACE_VERSION)
-+		return -EINVAL;
-+
-+	/* set up device-link for PM */
-+	if (!device_link_add(ipts_connect->client, intel_ipts.dev->dev, flags))
-+		return -EFAULT;
-+
-+	/* return gpu operations for ipts */
-+	ipts_connect->ipts_ops.get_wq_info = intel_ipts_get_wq_info;
-+	ipts_connect->ipts_ops.map_buffer = intel_ipts_map_buffer;
-+	ipts_connect->ipts_ops.unmap_buffer = intel_ipts_unmap_buffer;
-+	ipts_connect->gfx_version = INTEL_INFO(dev_priv)->gen;
-+	ipts_connect->gfx_handle = (uint64_t)&intel_ipts;
-+
-+	/* save callback and data */
-+	intel_ipts.data = ipts_connect->data;
-+	intel_ipts.ipts_clbks = ipts_connect->ipts_cb;
-+
-+	intel_ipts.connected = true;
-+
-+	return 0;
-+}
-+EXPORT_SYMBOL_GPL(intel_ipts_connect);
-+
-+void intel_ipts_disconnect(uint64_t gfx_handle)
-+{
-+	if (!intel_ipts.initialized)
-+		return;
-+
-+	if (gfx_handle != (uint64_t)&intel_ipts ||
-+					intel_ipts.connected == false) {
-+		DRM_ERROR("invalid gfx handle\n");
-+		return;
-+	}
-+
-+	intel_ipts.data = 0;
-+	memset(&intel_ipts.ipts_clbks, 0, sizeof(intel_ipts_callback_t));
-+
-+	intel_ipts.connected = false;
-+}
-+EXPORT_SYMBOL_GPL(intel_ipts_disconnect);
-+
-+static void reacquire_db_work_func(struct work_struct *work)
-+{
-+	struct delayed_work *d_work = container_of(work, struct delayed_work,
-+							work);
-+	intel_ipts_t *intel_ipts_p = container_of(d_work, intel_ipts_t,
-+							reacquire_db_work);
-+	u32 head;
-+	u32 tail;
-+	u32 size;
-+	u32 load;
-+
-+	head = *(u32*)intel_ipts_p->wq_info.wq_head_addr;
-+	tail = *(u32*)intel_ipts_p->wq_info.wq_tail_addr;
-+	size = intel_ipts_p->wq_info.wq_size;
-+
-+	if (head >= tail)
-+		load = head - tail;
-+	else
-+		load = head + size - tail;
-+
-+	if (load < REACQUIRE_DB_THRESHOLD) {
-+		intel_ipts_p->need_reacquire_db = false;
-+		goto reschedule_work;
-+	}
-+
-+	if (intel_ipts_p->need_reacquire_db) {
-+		if (intel_ipts_p->old_head == head && intel_ipts_p->old_tail == tail)
-+			intel_ipts_reacquire_db(intel_ipts_p);
-+		intel_ipts_p->need_reacquire_db = false;
-+	} else {
-+		intel_ipts_p->old_head = head;
-+		intel_ipts_p->old_tail = tail;
-+		intel_ipts_p->need_reacquire_db = true;
-+
-+		/* recheck */
-+		schedule_delayed_work(&intel_ipts_p->reacquire_db_work,
-+				msecs_to_jiffies(DB_LOST_CHECK_STEP2_INTERVAL));
-+		return;
-+	}
-+
-+reschedule_work:
-+	schedule_delayed_work(&intel_ipts_p->reacquire_db_work,
-+				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
-+}
-+
-+/**
-+ * intel_ipts_init - Initialize ipts support
-+ * @dev: drm device
-+ *
-+ * Setup the required structures for ipts.
-+ */
-+int intel_ipts_init(struct drm_device *dev)
-+{
-+	int ret = 0;
-+
-+	pr_info("ipts: initializing ipts\n");
-+
-+	intel_ipts.dev = dev;
-+	INIT_DELAYED_WORK(&intel_ipts.reacquire_db_work, reacquire_db_work_func);
-+
-+	ret = create_ipts_context();
-+	if (ret)
-+		return -ENOMEM;
-+
-+	ret = intel_ipts_init_wq();
-+	if (ret)
-+		return ret;
-+
-+	intel_ipts.initialized = true;
-+	pr_info("ipts: Intel iTouch framework initialized\n");
-+
-+	return ret;
-+}
-+
-+void intel_ipts_cleanup(struct drm_device *dev)
-+{
-+	intel_ipts_object_t *obj, *n;
-+
-+	if (intel_ipts.dev == dev) {
-+		list_for_each_entry_safe(obj, n, &intel_ipts.buffers.list, list) {
-+			struct i915_vma *vma, *vn;
-+
-+			list_for_each_entry_safe(vma, vn,
-+						 &obj->list, obj_link) {
-+				vma->flags &= ~I915_VMA_PIN_MASK;
-+				i915_vma_destroy(vma);
-+			}
-+
-+			list_del(&obj->list);
-+
-+			if (!obj->gem_obj->phys_handle)
-+				ipts_object_unmap(obj);
-+			ipts_object_unpin(obj);
-+			i915_gem_free_object(&obj->gem_obj->base);
-+			kfree(obj);
-+		}
-+
-+		intel_ipts_release_wq();
-+		destroy_ipts_context();
-+		cancel_delayed_work(&intel_ipts.reacquire_db_work);
-+	}
-+}
-diff --git a/drivers/gpu/drm/i915/intel_ipts.h b/drivers/gpu/drm/i915/intel_ipts.h
-new file mode 100644
-index 000000000000..a6965d102417
---- /dev/null
-+++ b/drivers/gpu/drm/i915/intel_ipts.h
-@@ -0,0 +1,34 @@
-+/*
-+ * Copyright © 2016 Intel Corporation
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ *
-+ */
-+#ifndef _INTEL_IPTS_H_
-+#define _INTEL_IPTS_H_
-+
-+struct drm_device;
-+
-+int intel_ipts_init(struct drm_device *dev);
-+void intel_ipts_cleanup(struct drm_device *dev);
-+int intel_ipts_notify_backlight_status(bool backlight_on);
-+int intel_ipts_notify_complete(void);
-+
-+#endif //_INTEL_IPTS_H_
-diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
-index 6937ef0b4bfc..f669087d6419 100644
---- a/drivers/gpu/drm/i915/intel_lrc.c
-+++ b/drivers/gpu/drm/i915/intel_lrc.c
-@@ -164,9 +164,6 @@
- #define WA_TAIL_DWORDS 2
- #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS)
- 
--static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
--					    struct intel_engine_cs *engine,
--					    struct intel_context *ce);
- static void execlists_init_reg_state(u32 *reg_state,
- 				     struct i915_gem_context *ctx,
- 				     struct intel_engine_cs *engine,
-@@ -1292,7 +1289,7 @@ static void execlists_context_destroy(struct intel_context *ce)
- 	i915_gem_object_put(ce->state->obj);
- }
- 
--static void execlists_context_unpin(struct intel_context *ce)
-+void execlists_context_unpin(struct intel_context *ce)
- {
- 	intel_ring_unpin(ce->ring);
- 
-@@ -1379,7 +1376,7 @@ static const struct intel_context_ops execlists_context_ops = {
- 	.destroy = execlists_context_destroy,
- };
- 
--static struct intel_context *
-+struct intel_context *
- execlists_context_pin(struct intel_engine_cs *engine,
- 		      struct i915_gem_context *ctx)
- {
-@@ -2470,6 +2467,9 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
- 
- 	logical_ring_setup(engine);
- 
-+	engine->irq_keep_mask |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT
-+							<< GEN8_RCS_IRQ_SHIFT;
-+
- 	if (HAS_L3_DPF(dev_priv))
- 		engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
- 
-@@ -2734,7 +2734,7 @@ populate_lr_context(struct i915_gem_context *ctx,
- 	return ret;
- }
- 
--static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
-+int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
- 					    struct intel_engine_cs *engine,
- 					    struct intel_context *ce)
- {
-diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
-index 4dfb78e3ec7e..32159231a16e 100644
---- a/drivers/gpu/drm/i915/intel_lrc.h
-+++ b/drivers/gpu/drm/i915/intel_lrc.h
-@@ -106,4 +106,12 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv);
- 
- void intel_execlists_set_default_submission(struct intel_engine_cs *engine);
- 
-+struct intel_context *
-+execlists_context_pin(struct intel_engine_cs *engine,
-+		      struct i915_gem_context *ctx);
-+void execlists_context_unpin(struct intel_context *ce);
-+int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
-+					    struct intel_engine_cs *engine,
-+						struct intel_context *ce);
-+
- #endif /* _INTEL_LRC_H_ */
-diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
-index 4a9f139e7b73..a800b93cf33d 100644
---- a/drivers/gpu/drm/i915/intel_panel.c
-+++ b/drivers/gpu/drm/i915/intel_panel.c
-@@ -34,6 +34,7 @@
- #include <linux/moduleparam.h>
- #include <linux/pwm.h>
- #include "intel_drv.h"
-+#include "intel_ipts.h"
- 
- #define CRC_PMIC_PWM_PERIOD_NS	21333
- 
-@@ -659,6 +660,9 @@ static void lpt_disable_backlight(const struct drm_connector_state *old_conn_sta
- 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- 	u32 tmp;
- 
-+	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
-+		intel_ipts_notify_backlight_status(false);
-+
- 	intel_panel_actually_set_backlight(old_conn_state, 0);
- 
- 	/*
-@@ -846,6 +850,9 @@ static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
- 
- 	/* This won't stick until the above enable. */
- 	intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
-+
-+	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
-+		intel_ipts_notify_backlight_status(true);
- }
- 
- static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
-diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index f9167d0e095c..28b729c9d804 100644
---- a/drivers/hid/hid-multitouch.c
-+++ b/drivers/hid/hid-multitouch.c
-@@ -173,6 +173,7 @@ struct mt_device {
- static void mt_post_parse_default_settings(struct mt_device *td,
- 					   struct mt_application *app);
- static void mt_post_parse(struct mt_device *td, struct mt_application *app);
-+static int cc_seen = 0;
- 
- /* classes of device behavior */
- #define MT_CLS_DEFAULT				0x0001
-@@ -799,8 +800,11 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- 			app->scantime_logical_max = field->logical_maximum;
- 			return 1;
- 		case HID_DG_CONTACTCOUNT:
--			app->have_contact_count = true;
--			app->raw_cc = &field->value[usage->usage_index];
-+			if(cc_seen != 1) {
-+				app->have_contact_count = true;
-+				app->raw_cc = &field->value[usage->usage_index];
-+				cc_seen++;
-+			}
- 			return 1;
- 		case HID_DG_AZIMUTH:
- 			/*
-@@ -1290,9 +1294,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- 	    field->application != HID_DG_TOUCHSCREEN &&
- 	    field->application != HID_DG_PEN &&
- 	    field->application != HID_DG_TOUCHPAD &&
-+		field->application != HID_GD_MOUSE &&
- 	    field->application != HID_GD_KEYBOARD &&
- 	    field->application != HID_GD_SYSTEM_CONTROL &&
- 	    field->application != HID_CP_CONSUMER_CONTROL &&
-+		field->logical != HID_DG_TOUCHSCREEN &&
- 	    field->application != HID_GD_WIRELESS_RADIO_CTLS &&
- 	    field->application != HID_GD_SYSTEM_MULTIAXIS &&
- 	    !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
-@@ -1337,6 +1343,14 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- 	struct mt_device *td = hid_get_drvdata(hdev);
- 	struct mt_report_data *rdata;
- 
-+	if (field->application == HID_DG_TOUCHSCREEN ||
-+			field->application == HID_DG_TOUCHPAD) {
-+		if (usage->type == EV_KEY || usage->type == EV_ABS)
-+			set_bit(usage->type, hi->input->evbit);
-+
-+		return -1;
-+	}
-+
- 	rdata = mt_find_report_data(td, field->report);
- 	if (rdata && rdata->is_mt_collection) {
- 		/* We own these mappings, tell hid-input to ignore them */
-@@ -1562,12 +1576,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
- 			/* already handled by hid core */
- 			break;
- 		case HID_DG_TOUCHSCREEN:
--			/* we do not set suffix = "Touchscreen" */
-+			suffix = "Touchscreen";
- 			hi->input->name = hdev->name;
- 			break;
- 		case HID_DG_STYLUS:
- 			/* force BTN_STYLUS to allow tablet matching in udev */
- 			__set_bit(BTN_STYLUS, hi->input->keybit);
-+			__set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
- 			break;
- 		case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
- 			suffix = "Custom Media Keys";
-@@ -1684,6 +1699,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
- 	td->hdev = hdev;
- 	td->mtclass = *mtclass;
- 	td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
-+	cc_seen = 0;
- 	hid_set_drvdata(hdev, td);
- 
- 	INIT_LIST_HEAD(&td->applications);
-diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
-index 3726eacdf65d..77263b5f5915 100644
---- a/drivers/misc/Kconfig
-+++ b/drivers/misc/Kconfig
-@@ -520,6 +520,7 @@ source "drivers/misc/ti-st/Kconfig"
- source "drivers/misc/lis3lv02d/Kconfig"
- source "drivers/misc/altera-stapl/Kconfig"
- source "drivers/misc/mei/Kconfig"
-+source "drivers/misc/ipts/Kconfig"
- source "drivers/misc/vmw_vmci/Kconfig"
- source "drivers/misc/mic/Kconfig"
- source "drivers/misc/genwqe/Kconfig"
-diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
-index af22bbc3d00c..eb1eb0d58c32 100644
---- a/drivers/misc/Makefile
-+++ b/drivers/misc/Makefile
-@@ -44,6 +44,7 @@ obj-y				+= lis3lv02d/
- obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
- obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
- obj-$(CONFIG_INTEL_MEI)		+= mei/
-+obj-$(CONFIG_INTEL_IPTS)	+= ipts/
- obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
- obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
- obj-$(CONFIG_SRAM)		+= sram.o
-diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig
-new file mode 100644
-index 000000000000..992a51061b38
---- /dev/null
-+++ b/drivers/misc/ipts/Kconfig
-@@ -0,0 +1,11 @@
-+config INTEL_IPTS
-+	tristate "Intel Precise Touch & Stylus"
-+	select INTEL_MEI
-+	depends on X86 && PCI && HID && DRM_I915
-+	help
-+	  Intel Precise Touch & Stylus support
-+	  Supported SoCs:
-+	  Intel Skylake
-+	  Intel Kabylake
-+
-+source "drivers/misc/ipts/companion/Kconfig"
-diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile
-new file mode 100644
-index 000000000000..78bb61933387
---- /dev/null
-+++ b/drivers/misc/ipts/Makefile
-@@ -0,0 +1,17 @@
-+#
-+# Makefile - Intel Precise Touch & Stylus device driver
-+# Copyright (c) 2016, Intel Corporation.
-+#
-+
-+obj-$(CONFIG_INTEL_IPTS)+= intel-ipts.o
-+intel-ipts-objs += ipts-fw.o
-+intel-ipts-objs += ipts-mei.o
-+intel-ipts-objs += ipts-hid.o
-+intel-ipts-objs += ipts-msg-handler.o
-+intel-ipts-objs += ipts-kernel.o
-+intel-ipts-objs += ipts-params.o
-+intel-ipts-objs += ipts-resource.o
-+intel-ipts-objs += ipts-gfx.o
-+intel-ipts-$(CONFIG_DEBUG_FS) += ipts-dbgfs.o
-+
-+obj-y += companion/
-diff --git a/drivers/misc/ipts/companion/Kconfig b/drivers/misc/ipts/companion/Kconfig
-new file mode 100644
-index 000000000000..877a04494779
---- /dev/null
-+++ b/drivers/misc/ipts/companion/Kconfig
-@@ -0,0 +1,9 @@
-+config INTEL_IPTS_SURFACE
-+	tristate "IPTS companion driver for Microsoft Surface"
-+	depends on INTEL_IPTS
-+	depends on ACPI
-+	help
-+	  IPTS companion driver for Microsoft Surface. This driver is responsible
-+	  for loading firmware using surface-specific hardware IDs.
-+
-+	  If you have a Microsoft Surface using IPTS, select y or m here.
-diff --git a/drivers/misc/ipts/companion/Makefile b/drivers/misc/ipts/companion/Makefile
-new file mode 100644
-index 000000000000..fb4d58935f01
---- /dev/null
-+++ b/drivers/misc/ipts/companion/Makefile
-@@ -0,0 +1 @@
-+obj-$(CONFIG_INTEL_IPTS_SURFACE)+= ipts-surface.o
-diff --git a/drivers/misc/ipts/companion/ipts-surface.c b/drivers/misc/ipts/companion/ipts-surface.c
-new file mode 100644
-index 000000000000..6f5aabb14e5a
---- /dev/null
-+++ b/drivers/misc/ipts/companion/ipts-surface.c
-@@ -0,0 +1,100 @@
-+#include <linux/acpi.h>
-+#include <linux/firmware.h>
-+#include <linux/intel_ipts_fw.h>
-+#include <linux/intel_ipts_if.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#define IPTS_SURFACE_FW_PATH_FMT "intel/ipts/%s/%s"
-+
-+#define __IPTS_SURFACE_FIRMWARE(X, Y)				\
-+	MODULE_FIRMWARE("intel/ipts/" X "/" Y)
-+
-+#define IPTS_SURFACE_FIRMWARE(X)				\
-+	__IPTS_SURFACE_FIRMWARE(X, "config.bin");		\
-+	__IPTS_SURFACE_FIRMWARE(X, "intel_desc.bin");		\
-+	__IPTS_SURFACE_FIRMWARE(X, "intel_fw_config.bin");	\
-+	__IPTS_SURFACE_FIRMWARE(X, "vendor_desc.bin");		\
-+	__IPTS_SURFACE_FIRMWARE(X, "vendor_kernel.bin")
-+
-+IPTS_SURFACE_FIRMWARE("MSHW0076");
-+IPTS_SURFACE_FIRMWARE("MSHW0078");
-+IPTS_SURFACE_FIRMWARE("MSHW0079");
-+IPTS_SURFACE_FIRMWARE("MSHW0101");
-+IPTS_SURFACE_FIRMWARE("MSHW0102");
-+IPTS_SURFACE_FIRMWARE("MSHW0103");
-+IPTS_SURFACE_FIRMWARE("MSHW0137");
-+
-+int ipts_surface_request_firmware(const struct firmware **fw, const char *name,
-+	struct device *device, void *data)
-+{
-+	char fw_path[MAX_IOCL_FILE_PATH_LEN];
-+
-+	if (data == NULL) {
-+		return -ENOENT;
-+	}
-+
-+	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_SURFACE_FW_PATH_FMT,
-+		(const char *)data, name);
-+	return request_firmware(fw, fw_path, device);
-+}
-+
-+static int ipts_surface_probe(struct platform_device *pdev)
-+{
-+	int ret;
-+	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
-+
-+	if (!adev) {
-+		dev_err(&pdev->dev, "Unable to find ACPI info for device\n");
-+		return -ENODEV;
-+	}
-+
-+	ret = intel_ipts_add_fw_handler(&ipts_surface_request_firmware,
-+		(void *)acpi_device_hid(adev));
-+	if (ret) {
-+		dev_info(&pdev->dev, "Adding IPTS firmware handler failed, "
-+			"error: %d\n", ret);
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int ipts_surface_remove(struct platform_device *pdev)
-+{
-+	int ret;
-+
-+	ret = intel_ipts_rm_fw_handler(&ipts_surface_request_firmware);
-+	if (ret) {
-+		dev_info(&pdev->dev, "Removing IPTS firmware handler failed, "
-+			"error: %d\n", ret);
-+	}
-+
-+	return 0;
-+}
-+
-+static const struct acpi_device_id ipts_surface_acpi_match[] = {
-+	{ "MSHW0076", 0 },	/* Surface Book 1 / Surface Studio */
-+	{ "MSHW0078", 0 },	/* Surface Pro 4 */
-+	{ "MSHW0079", 0 },	/* Surface Laptop 1 / 2 */
-+	{ "MSHW0101", 0 },	/* Surface Book 2 15" */
-+	{ "MSHW0102", 0 },	/* Surface Pro 2017 / 6 */
-+	{ "MSHW0103", 0 },	/* unknown, but firmware exists */
-+	{ "MSHW0137", 0 },	/* Surface Book 2 */
-+	{ },
-+};
-+MODULE_DEVICE_TABLE(acpi, ipts_surface_acpi_match);
-+
-+static struct platform_driver ipts_surface_driver = {
-+	.probe = ipts_surface_probe,
-+	.remove = ipts_surface_remove,
-+	.driver = {
-+		.name = "ipts_surface",
-+		.acpi_match_table = ACPI_PTR(ipts_surface_acpi_match),
-+	},
-+};
-+module_platform_driver(ipts_surface_driver);
-+
-+MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
-+MODULE_DESCRIPTION("IPTS companion driver for Microsoft Surface");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/misc/ipts/ipts-binary-spec.h b/drivers/misc/ipts/ipts-binary-spec.h
-new file mode 100644
-index 000000000000..87d4bc4133c4
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-binary-spec.h
-@@ -0,0 +1,118 @@
-+/*
-+ *
-+ * Intel Precise Touch & Stylus binary spec
-+ * Copyright (c) 2016 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.
-+ *
-+ */
-+
-+#ifndef _IPTS_BINARY_SPEC_H
-+#define _IPTS_BINARY_SPEC_H
-+
-+#define IPTS_BIN_HEADER_VERSION 2
-+
-+#pragma pack(1)
-+
-+/* we support 16 output buffers(1:feedback, 15:HID) */
-+#define  MAX_NUM_OUTPUT_BUFFERS 16
-+
-+typedef enum {
-+	IPTS_BIN_KERNEL,
-+	IPTS_BIN_RO_DATA,
-+	IPTS_BIN_RW_DATA,
-+	IPTS_BIN_SENSOR_FRAME,
-+	IPTS_BIN_OUTPUT,
-+	IPTS_BIN_DYNAMIC_STATE_HEAP,
-+	IPTS_BIN_PATCH_LOCATION_LIST,
-+	IPTS_BIN_ALLOCATION_LIST,
-+	IPTS_BIN_COMMAND_BUFFER_PACKET,
-+	IPTS_BIN_TAG,
-+} ipts_bin_res_type_t;
-+
-+typedef struct ipts_bin_header {
-+	char str[4];
-+	unsigned int version;
-+
-+#if IPTS_BIN_HEADER_VERSION > 1
-+	unsigned int gfxcore;
-+	unsigned int revid;
-+#endif
-+} ipts_bin_header_t;
-+
-+typedef struct ipts_bin_alloc {
-+	unsigned int handle;
-+	unsigned int reserved;
-+} ipts_bin_alloc_t;
-+
-+typedef struct ipts_bin_alloc_list {
-+	unsigned int num;
-+	ipts_bin_alloc_t alloc[];
-+} ipts_bin_alloc_list_t;
-+
-+typedef struct ipts_bin_cmdbuf {
-+	unsigned int size;
-+	char data[];
-+} ipts_bin_cmdbuf_t;
-+
-+typedef struct ipts_bin_res {
-+	unsigned int handle;
-+	ipts_bin_res_type_t type;
-+	unsigned int initialize;
-+	unsigned int aligned_size;
-+	unsigned int size;
-+	char data[];
-+} ipts_bin_res_t;
-+
-+typedef enum {
-+	IPTS_INPUT,
-+	IPTS_OUTPUT,
-+	IPTS_CONFIGURATION,
-+	IPTS_CALIBRATION,
-+	IPTS_FEATURE,
-+} ipts_bin_io_buffer_type_t;
-+
-+typedef struct ipts_bin_io_header {
-+	char str[10];
-+	unsigned short type;
-+} ipts_bin_io_header_t;
-+
-+typedef struct ipts_bin_res_list {
-+	unsigned int num;
-+	ipts_bin_res_t res[];
-+} ipts_bin_res_list_t;
-+
-+typedef struct ipts_bin_patch {
-+	unsigned int index;
-+	unsigned int reserved1[2];
-+	unsigned int alloc_offset;
-+	unsigned int patch_offset;
-+	unsigned int reserved2;
-+} ipts_bin_patch_t;
-+
-+typedef struct ipts_bin_patch_list {
-+	unsigned int num;
-+	ipts_bin_patch_t patch[];
-+} ipts_bin_patch_list_t;
-+
-+typedef struct ipts_bin_guc_wq_info {
-+	unsigned int batch_offset;
-+	unsigned int size;
-+	char data[];
-+} ipts_bin_guc_wq_info_t;
-+
-+typedef struct ipts_bin_bufid_patch {
-+	unsigned int imm_offset;
-+	unsigned int mem_offset;
-+} ipts_bin_bufid_patch_t;
-+
-+#pragma pack()
-+
-+#endif /* _IPTS_BINARY_SPEC_H */
-diff --git a/drivers/misc/ipts/ipts-dbgfs.c b/drivers/misc/ipts/ipts-dbgfs.c
-new file mode 100644
-index 000000000000..7581b21f81e0
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-dbgfs.c
-@@ -0,0 +1,364 @@
-+/*
-+ * Intel Precise Touch & Stylus device driver
-+ * Copyright (c) 2016, 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.
-+ *
-+ */
-+#include <linux/debugfs.h>
-+#include <linux/ctype.h>
-+#include <linux/uaccess.h>
-+
-+#include "ipts.h"
-+#include "ipts-sensor-regs.h"
-+#include "ipts-msg-handler.h"
-+#include "ipts-state.h"
-+#include "../mei/mei_dev.h"
-+
-+const char sensor_mode_fmt[] = "sensor mode : %01d\n";
-+const char ipts_status_fmt[] = "sensor mode : %01d\nipts state : %01d\n";
-+const char ipts_debug_fmt[] = ">> tdt : fw status : %s\n"
-+							  ">> == DB s:%x, c:%x ==\n"
-+							  ">> == WQ h:%u, t:%u ==\n";
-+
-+static ssize_t ipts_dbgfs_mode_read(struct file *fp, char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	char mode[80];
-+	int len = 0;
-+
-+	if (cnt < sizeof(sensor_mode_fmt) - 3)
-+		return -EINVAL;
-+
-+	len = scnprintf(mode, 80, sensor_mode_fmt, ipts->sensor_mode);
-+	if (len < 0)
-+		return -EIO;
-+
-+	return simple_read_from_buffer(ubuf, cnt, ppos, mode, len);
-+}
-+
-+static ssize_t ipts_dbgfs_mode_write(struct file *fp, const char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	ipts_state_t state;
-+	int sensor_mode, len;
-+	char mode[3];
-+
-+	if (cnt == 0 || cnt > 3)
-+		return -EINVAL;
-+
-+	state = ipts_get_state(ipts);
-+	if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED) {
-+		return -EIO;
-+	}
-+
-+	len = cnt;
-+	if (copy_from_user(mode, ubuf, len))
-+		return -EFAULT;
-+
-+	while(len > 0 && (isspace(mode[len-1]) || mode[len-1] == '\n'))
-+		len--;
-+	mode[len] = '\0';
-+
-+	if (sscanf(mode, "%d", &sensor_mode) != 1)
-+		return -EINVAL;
-+
-+	if (sensor_mode != TOUCH_SENSOR_MODE_RAW_DATA &&
-+					sensor_mode != TOUCH_SENSOR_MODE_HID) {
-+		return -EINVAL;
-+	}
-+
-+	if (sensor_mode == ipts->sensor_mode)
-+		return 0;
-+
-+	ipts_switch_sensor_mode(ipts, sensor_mode);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations ipts_mode_dbgfs_fops = {
-+        .open = simple_open,
-+        .read = ipts_dbgfs_mode_read,
-+        .write = ipts_dbgfs_mode_write,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_status_read(struct file *fp, char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	char status[256];
-+	int len = 0;
-+
-+	if (cnt < sizeof(ipts_status_fmt) - 3)
-+		return -EINVAL;
-+
-+	len = scnprintf(status, 256, ipts_status_fmt, ipts->sensor_mode,
-+						     ipts->state);
-+	if (len < 0)
-+		return -EIO;
-+
-+	return simple_read_from_buffer(ubuf, cnt, ppos, status, len);
-+}
-+
-+static const struct file_operations ipts_status_dbgfs_fops = {
-+        .open = simple_open,
-+        .read = ipts_dbgfs_status_read,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_quiesce_io_cmd_write(struct file *fp, const char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	bool result;
-+	int rc;
-+
-+	rc = kstrtobool_from_user(ubuf, cnt, &result);
-+	if (rc)
-+		return rc;
-+
-+	if (!result)
-+		return -EINVAL;
-+
-+	ipts_send_sensor_quiesce_io_cmd(ipts);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations ipts_quiesce_io_cmd_dbgfs_fops = {
-+        .open = simple_open,
-+        .write = ipts_dbgfs_quiesce_io_cmd_write,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_clear_mem_window_cmd_write(struct file *fp, const char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	bool result;
-+	int rc;
-+
-+	rc = kstrtobool_from_user(ubuf, cnt, &result);
-+	if (rc)
-+		return rc;
-+
-+	if (!result)
-+		return -EINVAL;
-+
-+	ipts_send_sensor_clear_mem_window_cmd(ipts);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations ipts_clear_mem_window_cmd_dbgfs_fops = {
-+        .open = simple_open,
-+        .write = ipts_dbgfs_clear_mem_window_cmd_write,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_debug_read(struct file *fp, char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	char dbg_info[1024];
-+	int len = 0;
-+
-+	char fw_sts_str[MEI_FW_STATUS_STR_SZ];
-+	u32 *db, *head, *tail;
-+	intel_ipts_wq_info_t* wq_info;
-+
-+	wq_info = &ipts->resource.wq_info;
-+
-+	mei_fw_status_str(ipts->cldev->bus, fw_sts_str, MEI_FW_STATUS_STR_SZ);
-+	// pr_info(">> tdt : fw status : %s\n", fw_sts_str);
-+
-+	db = (u32*)wq_info->db_addr;
-+	head = (u32*)wq_info->wq_head_addr;
-+	tail = (u32*)wq_info->wq_tail_addr;
-+	// pr_info(">> == DB s:%x, c:%x ==\n", *db, *(db+1));
-+	// pr_info(">> == WQ h:%u, t:%u ==\n", *head, *tail);
-+
-+	if (cnt < sizeof(ipts_debug_fmt) - 3)
-+		return -EINVAL;
-+
-+	len = scnprintf(dbg_info, 1024, ipts_debug_fmt,
-+							fw_sts_str,
-+							*db, *(db+1),
-+							*head, *tail);
-+	if (len < 0)
-+		return -EIO;
-+
-+	return simple_read_from_buffer(ubuf, cnt, ppos, dbg_info, len);
-+}
-+
-+static const struct file_operations ipts_debug_dbgfs_fops = {
-+        .open = simple_open,
-+        .read = ipts_dbgfs_debug_read,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_ipts_restart_write(struct file *fp, const char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	bool result;
-+	int rc;
-+
-+	rc = kstrtobool_from_user(ubuf, cnt, &result);
-+	if (rc)
-+		return rc;
-+
-+	if (!result)
-+		return -EINVAL;
-+
-+	ipts_restart(ipts);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations ipts_ipts_restart_dbgfs_fops = {
-+        .open = simple_open,
-+        .write = ipts_dbgfs_ipts_restart_write,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_ipts_stop_write(struct file *fp, const char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	bool result;
-+	int rc;
-+
-+	rc = kstrtobool_from_user(ubuf, cnt, &result);
-+	if (rc)
-+		return rc;
-+
-+	if (!result)
-+		return -EINVAL;
-+
-+	ipts_stop(ipts);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations ipts_ipts_stop_dbgfs_fops = {
-+        .open = simple_open,
-+        .write = ipts_dbgfs_ipts_stop_write,
-+        .llseek = generic_file_llseek,
-+};
-+
-+static ssize_t ipts_dbgfs_ipts_start_write(struct file *fp, const char __user *ubuf,
-+						size_t cnt, loff_t *ppos)
-+{
-+	ipts_info_t *ipts = fp->private_data;
-+	bool result;
-+	int rc;
-+
-+	rc = kstrtobool_from_user(ubuf, cnt, &result);
-+	if (rc)
-+		return rc;
-+
-+	if (!result)
-+		return -EINVAL;
-+
-+	ipts_start(ipts);
-+
-+	return cnt;
-+}
-+
-+static const struct file_operations ipts_ipts_start_dbgfs_fops = {
-+        .open = simple_open,
-+        .write = ipts_dbgfs_ipts_start_write,
-+        .llseek = generic_file_llseek,
-+};
-+
-+void ipts_dbgfs_deregister(ipts_info_t* ipts)
-+{
-+	if (!ipts->dbgfs_dir)
-+		return;
-+
-+	debugfs_remove_recursive(ipts->dbgfs_dir);
-+	ipts->dbgfs_dir = NULL;
-+}
-+
-+int ipts_dbgfs_register(ipts_info_t* ipts, const char *name)
-+{
-+	struct dentry *dir, *f;
-+
-+	dir = debugfs_create_dir(name, NULL);
-+	if (!dir)
-+		return -ENOMEM;
-+
-+        f = debugfs_create_file("mode", S_IRUSR | S_IWUSR, dir,
-+                                ipts, &ipts_mode_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs mode creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("status", S_IRUSR, dir,
-+                                ipts, &ipts_status_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs status creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("quiesce_io_cmd", S_IWUSR, dir,
-+                                ipts, &ipts_quiesce_io_cmd_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs quiesce_io_cmd creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("clear_mem_window_cmd", S_IWUSR, dir,
-+                                ipts, &ipts_clear_mem_window_cmd_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs clear_mem_window_cmd creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("debug", S_IRUSR, dir,
-+                                ipts, &ipts_debug_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs debug creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("ipts_restart", S_IWUSR, dir,
-+                                ipts, &ipts_ipts_restart_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs ipts_restart creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("ipts_stop", S_IWUSR, dir,
-+                                ipts, &ipts_ipts_stop_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs ipts_stop creation failed\n");
-+                goto err;
-+        }
-+
-+        f = debugfs_create_file("ipts_start", S_IWUSR, dir,
-+                                ipts, &ipts_ipts_start_dbgfs_fops);
-+        if (!f) {
-+                ipts_err(ipts, "debugfs ipts_start creation failed\n");
-+                goto err;
-+        }
-+
-+	ipts->dbgfs_dir = dir;
-+
-+	return 0;
-+err:
-+	ipts_dbgfs_deregister(ipts);
-+	return -ENODEV;
-+}
-diff --git a/drivers/misc/ipts/ipts-fw.c b/drivers/misc/ipts/ipts-fw.c
-new file mode 100644
-index 000000000000..82e6e44c9908
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-fw.c
-@@ -0,0 +1,113 @@
-+#include <linux/firmware.h>
-+#include <linux/intel_ipts_fw.h>
-+#include <linux/intel_ipts_if.h>
-+#include <linux/mutex.h>
-+
-+#include "ipts.h"
-+#include "ipts-fw.h"
-+#include "ipts-params.h"
-+
-+#define IPTS_GENERIC_FW_PATH_FMT "intel/ipts/%s"
-+
-+/*
-+ * This function pointer allows a companion driver to register a custom logic
-+ * for loading firmware files. This can be used to detect devices that can
-+ * be used for IPTS versioning, but that are not connected over the MEI bus,
-+ * and cannot be detected by the ME driver.
-+ */
-+IPTS_FW_HANDLER(ipts_fw_handler);
-+DEFINE_MUTEX(ipts_fw_handler_lock);
-+void *ipts_fw_handler_data = NULL;
-+
-+bool ipts_fw_handler_available(void)
-+{
-+	bool ret;
-+	mutex_lock(&ipts_fw_handler_lock);
-+
-+	ret = ipts_fw_handler != NULL;
-+
-+	mutex_unlock(&ipts_fw_handler_lock);
-+	return ret;
-+}
-+
-+int intel_ipts_add_fw_handler(IPTS_FW_HANDLER(handler), void *data)
-+{
-+	int ret = 0;
-+	mutex_lock(&ipts_fw_handler_lock);
-+
-+	if (ipts_fw_handler != NULL) {
-+		ret = -EBUSY;
-+		goto ipts_add_fw_handler_return;
-+	}
-+
-+	ipts_fw_handler = handler;
-+	ipts_fw_handler_data = data;
-+
-+ipts_add_fw_handler_return:
-+
-+	mutex_unlock(&ipts_fw_handler_lock);
-+	return ret;
-+}
-+EXPORT_SYMBOL(intel_ipts_add_fw_handler);
-+
-+int intel_ipts_rm_fw_handler(IPTS_FW_HANDLER(handler))
-+{
-+	int ret = 0;
-+	mutex_lock(&ipts_fw_handler_lock);
-+
-+	if (ipts_fw_handler == NULL) {
-+		ret = 0;
-+		goto ipts_rm_fw_handler_return;
-+	}
-+
-+	if (*handler != *ipts_fw_handler) {
-+		ret = -EPERM;
-+		goto ipts_rm_fw_handler_return;
-+	}
-+
-+	ipts_fw_handler = NULL;
-+	ipts_fw_handler_data = NULL;
-+
-+ipts_rm_fw_handler_return:
-+
-+	mutex_unlock(&ipts_fw_handler_lock);
-+	return ret;
-+}
-+EXPORT_SYMBOL(intel_ipts_rm_fw_handler);
-+
-+int ipts_request_firmware(const struct firmware **fw, const char *name,
-+	struct device *device)
-+{
-+	int ret = 0;
-+	char fw_path[MAX_IOCL_FILE_PATH_LEN];
-+	mutex_lock(&ipts_fw_handler_lock);
-+
-+	// Check if a firmware handler was registered. If not, skip
-+	// forward and try to load the firmware from the legacy path
-+	if (ipts_fw_handler == NULL || ipts_modparams.ignore_companion) {
-+		goto ipts_request_firmware_fallback;
-+	}
-+
-+	ret = (*ipts_fw_handler)(fw, name, device, ipts_fw_handler_data);
-+	if (!ret) {
-+		goto ipts_request_firmware_return;
-+	}
-+
-+ipts_request_firmware_fallback:
-+
-+	// If fallback loading for firmware was disabled, abort.
-+	// Return -ENOENT as no firmware file was found.
-+	if (ipts_modparams.ignore_fw_fallback) {
-+		ret = -ENOENT;
-+		goto ipts_request_firmware_return;
-+	}
-+
-+	// No firmware was found by the companion driver, try the generic path now.
-+	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_GENERIC_FW_PATH_FMT, name);
-+	ret = request_firmware(fw, fw_path, device);
-+
-+ipts_request_firmware_return:
-+
-+	mutex_unlock(&ipts_fw_handler_lock);
-+	return ret;
-+}
-diff --git a/drivers/misc/ipts/ipts-fw.h b/drivers/misc/ipts/ipts-fw.h
-new file mode 100644
-index 000000000000..4c1c9a0dd77f
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-fw.h
-@@ -0,0 +1,12 @@
-+#ifndef _IPTS_FW_H_
-+#define _IPTS_FW_H_
-+
-+#include <linux/firmware.h>
-+
-+#include "ipts.h"
-+
-+int ipts_request_firmware(const struct firmware **fw, const char *name,
-+	struct device *device);
-+bool ipts_fw_handler_available(void);
-+
-+#endif // _IPTS_FW_H_
-diff --git a/drivers/misc/ipts/ipts-gfx.c b/drivers/misc/ipts/ipts-gfx.c
-new file mode 100644
-index 000000000000..4989a22227d2
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-gfx.c
-@@ -0,0 +1,185 @@
-+/*
-+ *
-+ * Intel Integrated Touch Gfx Interface Layer
-+ * Copyright (c) 2016 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.
-+ *
-+ */
-+#include <linux/kthread.h>
-+#include <linux/delay.h>
-+#include <linux/intel_ipts_if.h>
-+
-+#include "ipts.h"
-+#include "ipts-msg-handler.h"
-+#include "ipts-state.h"
-+
-+static void gfx_processing_complete(void *data)
-+{
-+	ipts_info_t *ipts = data;
-+
-+	if (ipts_get_state(ipts) == IPTS_STA_RAW_DATA_STARTED) {
-+		schedule_work(&ipts->raw_data_work);
-+		return;
-+	}
-+
-+	ipts_dbg(ipts, "not ready to handle gfx event\n");
-+}
-+
-+static void notify_gfx_status(u32 status, void *data)
-+{
-+	ipts_info_t *ipts = data;
-+
-+	ipts->gfx_status = status;
-+	schedule_work(&ipts->gfx_status_work);
-+}
-+
-+static int connect_gfx(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+	intel_ipts_connect_t ipts_connect;
-+
-+	ipts_connect.client = ipts->cldev->dev.parent;
-+	ipts_connect.if_version = IPTS_INTERFACE_V1;
-+	ipts_connect.ipts_cb.workload_complete = gfx_processing_complete;
-+	ipts_connect.ipts_cb.notify_gfx_status = notify_gfx_status;
-+	ipts_connect.data = (void*)ipts;
-+
-+	ret = intel_ipts_connect(&ipts_connect);
-+	if (ret)
-+		return ret;
-+
-+	/* TODO: gfx version check */
-+	ipts->gfx_info.gfx_handle = ipts_connect.gfx_handle;
-+	ipts->gfx_info.ipts_ops = ipts_connect.ipts_ops;
-+
-+	return ret;
-+}
-+
-+static void disconnect_gfx(ipts_info_t *ipts)
-+{
-+	intel_ipts_disconnect(ipts->gfx_info.gfx_handle);
-+}
-+
-+#ifdef RUN_DBG_THREAD
-+#include "../mei/mei_dev.h"
-+
-+static struct task_struct *dbg_thread;
-+
-+static void ipts_print_dbg_info(ipts_info_t* ipts)
-+{
-+        char fw_sts_str[MEI_FW_STATUS_STR_SZ];
-+	u32 *db, *head, *tail;
-+	intel_ipts_wq_info_t* wq_info;
-+
-+	wq_info = &ipts->resource.wq_info;
-+
-+	mei_fw_status_str(ipts->cldev->bus, fw_sts_str, MEI_FW_STATUS_STR_SZ);
-+	pr_info(">> tdt : fw status : %s\n", fw_sts_str);
-+
-+	db = (u32*)wq_info->db_addr;
-+	head = (u32*)wq_info->wq_head_addr;
-+	tail = (u32*)wq_info->wq_tail_addr;
-+	pr_info(">> == DB s:%x, c:%x ==\n", *db, *(db+1));
-+	pr_info(">> == WQ h:%u, t:%u ==\n", *head, *tail);
-+}
-+
-+static int ipts_dbg_thread(void *data)
-+{
-+	ipts_info_t *ipts = (ipts_info_t *)data;
-+
-+	pr_info(">> start debug thread\n");
-+
-+	while (!kthread_should_stop()) {
-+		if (ipts_get_state(ipts) != IPTS_STA_RAW_DATA_STARTED) {
-+			pr_info("state is not IPTS_STA_RAW_DATA_STARTED : %d\n",
-+							ipts_get_state(ipts));
-+			msleep(5000);
-+			continue;
-+		}
-+
-+		ipts_print_dbg_info(ipts);
-+
-+		msleep(3000);
-+	}
-+
-+	return 0;
-+}
-+#endif
-+
-+int ipts_open_gpu(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+
-+	ret = connect_gfx(ipts);
-+	if (ret) {
-+		ipts_dbg(ipts, "cannot connect GPU\n");
-+		return ret;
-+	}
-+
-+	ret = ipts->gfx_info.ipts_ops.get_wq_info(ipts->gfx_info.gfx_handle,
-+							&ipts->resource.wq_info);
-+	if (ret) {
-+		ipts_dbg(ipts, "error in get_wq_info\n");
-+		return ret;
-+	}
-+
-+#ifdef	RUN_DBG_THREAD
-+	dbg_thread = kthread_run(ipts_dbg_thread, (void *)ipts, "ipts_debug");
-+#endif
-+
-+	return 0;
-+}
-+
-+void ipts_close_gpu(ipts_info_t *ipts)
-+{
-+	disconnect_gfx(ipts);
-+
-+#ifdef	RUN_DBG_THREAD
-+	kthread_stop(dbg_thread);
-+#endif
-+}
-+
-+intel_ipts_mapbuffer_t *ipts_map_buffer(ipts_info_t *ipts, u32 size, u32 flags)
-+{
-+	intel_ipts_mapbuffer_t *buf;
-+	u64 handle;
-+	int ret;
-+
-+	buf = devm_kzalloc(&ipts->cldev->dev, sizeof(*buf), GFP_KERNEL);
-+	if (!buf)
-+		return NULL;
-+
-+	buf->size = size;
-+	buf->flags = flags;
-+
-+	handle = ipts->gfx_info.gfx_handle;
-+	ret = ipts->gfx_info.ipts_ops.map_buffer(handle, buf);
-+	if (ret) {
-+		devm_kfree(&ipts->cldev->dev, buf);
-+		return NULL;
-+	}
-+
-+	return buf;
-+}
-+
-+void ipts_unmap_buffer(ipts_info_t *ipts, intel_ipts_mapbuffer_t *buf)
-+{
-+	u64 handle;
-+	int ret;
-+
-+	if (!buf)
-+		return;
-+
-+	handle = ipts->gfx_info.gfx_handle;
-+	ret = ipts->gfx_info.ipts_ops.unmap_buffer(handle, buf->buf_handle);
-+
-+	devm_kfree(&ipts->cldev->dev, buf);
-+}
-diff --git a/drivers/misc/ipts/ipts-gfx.h b/drivers/misc/ipts/ipts-gfx.h
-new file mode 100644
-index 000000000000..03a5f3551ddf
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-gfx.h
-@@ -0,0 +1,24 @@
-+/*
-+ * Intel Precise Touch & Stylus gpu wrapper
-+ * Copyright (c) 2016, 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.
-+ */
-+
-+
-+#ifndef _IPTS_GFX_H_
-+#define _IPTS_GFX_H_
-+
-+int ipts_open_gpu(ipts_info_t *ipts);
-+void ipts_close_gpu(ipts_info_t *ipts);
-+intel_ipts_mapbuffer_t *ipts_map_buffer(ipts_info_t *ipts, u32 size, u32 flags);
-+void ipts_unmap_buffer(ipts_info_t *ipts, intel_ipts_mapbuffer_t *buf);
-+
-+#endif // _IPTS_GFX_H_
-diff --git a/drivers/misc/ipts/ipts-hid.c b/drivers/misc/ipts/ipts-hid.c
-new file mode 100644
-index 000000000000..32cf5927f949
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-hid.c
-@@ -0,0 +1,497 @@
-+/*
-+ * Intel Precise Touch & Stylus HID driver
-+ *
-+ * Copyright (c) 2016, 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.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/firmware.h>
-+#include <linux/hid.h>
-+#include <linux/vmalloc.h>
-+#include <linux/dmi.h>
-+
-+#include "ipts.h"
-+#include "ipts-fw.h"
-+#include "ipts-params.h"
-+#include "ipts-resource.h"
-+#include "ipts-sensor-regs.h"
-+#include "ipts-msg-handler.h"
-+
-+#define BUS_MEI				0x44
-+
-+#define	HID_DESC_INTEL	"intel_desc.bin"
-+#define	HID_DESC_VENDOR	"vendor_desc.bin"
-+
-+typedef enum output_buffer_payload_type {
-+	OUTPUT_BUFFER_PAYLOAD_ERROR = 0,
-+	OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT,
-+	OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT,
-+	OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD,
-+	OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER
-+} output_buffer_payload_type_t;
-+
-+typedef struct kernel_output_buffer_header {
-+	u16 length;
-+	u8 payload_type;
-+	u8 reserved1;
-+	touch_hid_private_data_t hid_private_data;
-+	u8 reserved2[28];
-+	u8 data[0];
-+} kernel_output_buffer_header_t;
-+
-+typedef struct kernel_output_payload_error {
-+	u16 severity;
-+	u16 source;
-+	u8 code[4];
-+	char string[128];
-+} kernel_output_payload_error_t;
-+
-+static const struct dmi_system_id no_feedback_dmi_table[] = {
-+	{
-+		.matches = {
-+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
-+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
-+		},
-+	},
-+	{
-+		.matches = {
-+			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
-+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
-+		},
-+	},
-+	{ }
-+};
-+
-+static int ipts_hid_get_hid_descriptor(ipts_info_t *ipts, u8 **desc, int *size)
-+{
-+	u8 *buf;
-+	int hid_size = 0, ret = 0;
-+	const struct firmware *intel_desc = NULL;
-+	const struct firmware *vendor_desc = NULL;
-+	const char *intel_desc_path = HID_DESC_INTEL;
-+	const char *vendor_desc_path = HID_DESC_VENDOR;
-+
-+	ret = ipts_request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev);
-+	if (ret) {
-+		goto no_hid;
-+	}
-+	hid_size = intel_desc->size;
-+
-+	ret = ipts_request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev);
-+	if (ret) {
-+		ipts_dbg(ipts, "error in reading HID Vendor Descriptor\n");
-+	} else {
-+		hid_size += vendor_desc->size;
-+	}
-+
-+	ipts_dbg(ipts, "hid size = %d\n", hid_size);
-+	buf = vmalloc(hid_size);
-+	if (buf == NULL) {
-+		ret = -ENOMEM;
-+		goto no_mem;
-+	}
-+
-+	memcpy(buf, intel_desc->data, intel_desc->size);
-+	if (vendor_desc) {
-+		memcpy(&buf[intel_desc->size], vendor_desc->data,
-+							vendor_desc->size);
-+		release_firmware(vendor_desc);
-+	}
-+
-+	release_firmware(intel_desc);
-+
-+	*desc = buf;
-+	*size = hid_size;
-+
-+	return 0;
-+no_mem :
-+	if (vendor_desc)
-+		release_firmware(vendor_desc);
-+	release_firmware(intel_desc);
-+
-+no_hid :
-+	return ret;
-+}
-+
-+static int ipts_hid_parse(struct hid_device *hid)
-+{
-+	ipts_info_t *ipts = hid->driver_data;
-+	int ret = 0, size;
-+	u8 *buf;
-+
-+	ipts_dbg(ipts, "ipts_hid_parse() start\n");
-+	ret = ipts_hid_get_hid_descriptor(ipts, &buf, &size);
-+	if (ret != 0) {
-+		ipts_dbg(ipts, "ipts_hid_ipts_get_hid_descriptor ret %d\n", ret);
-+		return -EIO;
-+	}
-+
-+	ret = hid_parse_report(hid, buf, size);
-+	vfree(buf);
-+	if (ret) {
-+		ipts_err(ipts, "hid_parse_report error : %d\n", ret);
-+		goto out;
-+	}
-+
-+	ipts->hid_desc_ready = true;
-+out:
-+	return ret;
-+}
-+
-+static int ipts_hid_start(struct hid_device *hid)
-+{
-+	return 0;
-+}
-+
-+static void ipts_hid_stop(struct hid_device *hid)
-+{
-+	return;
-+}
-+
-+static int ipts_hid_open(struct hid_device *hid)
-+{
-+	return 0;
-+}
-+
-+static void ipts_hid_close(struct hid_device *hid)
-+{
-+	ipts_info_t *ipts = hid->driver_data;
-+
-+	ipts->hid_desc_ready = false;
-+
-+	return;
-+}
-+
-+static int ipts_hid_send_hid2me_feedback(ipts_info_t *ipts, u32 fb_data_type,
-+							__u8 *buf, size_t count)
-+{
-+	ipts_buffer_info_t *fb_buf;
-+	touch_feedback_hdr_t *feedback;
-+	u8 *payload;
-+	int header_size;
-+	ipts_state_t state;
-+
-+	header_size = sizeof(touch_feedback_hdr_t);
-+
-+	if (count > ipts->resource.hid2me_buffer_size - header_size)
-+		return -EINVAL;
-+
-+	state = ipts_get_state(ipts);
-+	if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED)
-+		return 0;
-+
-+	fb_buf = ipts_get_hid2me_buffer(ipts);
-+	feedback = (touch_feedback_hdr_t *)fb_buf->addr;
-+	payload = fb_buf->addr + header_size;
-+	memset(feedback, 0, header_size);
-+
-+	feedback->feedback_data_type = fb_data_type;
-+	feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE;
-+	feedback->payload_size_bytes = count;
-+	feedback->buffer_id = TOUCH_HID_2_ME_BUFFER_ID;
-+	feedback->protocol_ver = 0;
-+	feedback->reserved[0] = 0xAC;
-+
-+	/* copy payload */
-+	memcpy(payload, buf, count);
-+
-+	ipts_send_feedback(ipts, TOUCH_HID_2_ME_BUFFER_ID, 0);
-+
-+	return 0;
-+}
-+
-+static int ipts_hid_raw_request(struct hid_device *hid,
-+				unsigned char report_number, __u8 *buf,
-+				size_t count, unsigned char report_type,
-+				int reqtype)
-+{
-+	ipts_info_t *ipts = hid->driver_data;
-+	u32 fb_data_type;
-+
-+	ipts_dbg(ipts, "hid raw request => report %d, request %d\n",
-+						 (int)report_type, reqtype);
-+
-+	if (report_type != HID_FEATURE_REPORT)
-+		return 0;
-+
-+	switch (reqtype) {
-+		case HID_REQ_GET_REPORT:
-+			fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES;
-+			break;
-+		case HID_REQ_SET_REPORT:
-+			fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES;
-+			break;
-+		default:
-+			ipts_err(ipts, "raw request not supprted: %d\n", reqtype);
-+			return -EIO;
-+	}
-+
-+	return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count);
-+}
-+
-+static int ipts_hid_output_report(struct hid_device *hid,
-+					__u8 *buf, size_t count)
-+{
-+	ipts_info_t *ipts = hid->driver_data;
-+	u32 fb_data_type;
-+
-+	ipts_dbg(ipts, "hid output report\n");
-+
-+	fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT;
-+
-+	return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count);
-+}
-+
-+static struct hid_ll_driver ipts_hid_ll_driver = {
-+	.parse = ipts_hid_parse,
-+	.start = ipts_hid_start,
-+	.stop = ipts_hid_stop,
-+	.open = ipts_hid_open,
-+	.close = ipts_hid_close,
-+	.raw_request = ipts_hid_raw_request,
-+	.output_report = ipts_hid_output_report,
-+};
-+
-+int ipts_hid_init(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+	struct hid_device *hid;
-+
-+	hid = hid_allocate_device();
-+	if (IS_ERR(hid)) {
-+		ret = PTR_ERR(hid);
-+		goto err_dev;
-+	}
-+
-+	hid->driver_data = ipts;
-+	hid->ll_driver = &ipts_hid_ll_driver;
-+	hid->dev.parent = &ipts->cldev->dev;
-+	hid->bus = BUS_MEI;
-+	hid->version = ipts->device_info.fw_rev;
-+	hid->vendor = ipts->device_info.vendor_id;
-+	hid->product = ipts->device_info.device_id;
-+
-+	snprintf(hid->phys, sizeof(hid->phys), "heci3");
-+	snprintf(hid->name, sizeof(hid->name),
-+		 "%s %04hX:%04hX", "ipts", hid->vendor, hid->product);
-+
-+	ret = hid_add_device(hid);
-+	if (ret) {
-+		if (ret != -ENODEV)
-+			ipts_err(ipts, "can't add hid device: %d\n", ret);
-+		goto err_mem_free;
-+	}
-+
-+	ipts->hid = hid;
-+
-+	return 0;
-+
-+err_mem_free:
-+	hid_destroy_device(hid);
-+err_dev:
-+	return ret;
-+}
-+
-+void ipts_hid_release(ipts_info_t *ipts)
-+{
-+	if (!ipts->hid)
-+			return;
-+	hid_destroy_device(ipts->hid);
-+}
-+
-+int ipts_handle_hid_data(ipts_info_t *ipts,
-+			touch_sensor_hid_ready_for_data_rsp_data_t *hid_rsp)
-+{
-+	touch_raw_data_hdr_t *raw_header;
-+	ipts_buffer_info_t *buffer_info;
-+	touch_feedback_hdr_t *feedback;
-+	u8 *raw_data;
-+	int touch_data_buffer_index;
-+	int transaction_id;
-+	int ret = 0;
-+
-+	touch_data_buffer_index = (int)hid_rsp->touch_data_buffer_index;
-+	buffer_info = ipts_get_touch_data_buffer_hid(ipts);
-+	raw_header = (touch_raw_data_hdr_t *)buffer_info->addr;
-+	transaction_id = raw_header->hid_private_data.transaction_id;
-+
-+	raw_data = (u8*)raw_header + sizeof(touch_raw_data_hdr_t);
-+	if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_HID_REPORT) {
-+		memcpy(ipts->hid_input_report, raw_data,
-+				raw_header->raw_data_size_bytes);
-+
-+		ret = hid_input_report(ipts->hid, HID_INPUT_REPORT,
-+					(u8*)ipts->hid_input_report,
-+					raw_header->raw_data_size_bytes, 1);
-+		if (ret) {
-+			ipts_err(ipts, "error in hid_input_report : %d\n", ret);
-+		}
-+	} else if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_GET_FEATURES) {
-+		/* TODO: implement together with "get feature ioctl" */
-+	} else if (raw_header->data_type == TOUCH_RAW_DATA_TYPE_ERROR) {
-+		touch_error_t *touch_err = (touch_error_t *)raw_data;
-+
-+		ipts_err(ipts, "error type : %d, me fw error : %x, err reg : %x\n",
-+				touch_err->touch_error_type,
-+				touch_err->touch_me_fw_error.value,
-+				touch_err->touch_error_register.reg_value);
-+	}
-+
-+	/* send feedback data for HID mode */
-+        buffer_info = ipts_get_feedback_buffer(ipts, touch_data_buffer_index);
-+	feedback = (touch_feedback_hdr_t *)buffer_info->addr;
-+	memset(feedback, 0, sizeof(touch_feedback_hdr_t));
-+	feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE;
-+	feedback->payload_size_bytes = 0;
-+	feedback->buffer_id = touch_data_buffer_index;
-+	feedback->protocol_ver = 0;
-+	feedback->reserved[0] = 0xAC;
-+
-+	ret = ipts_send_feedback(ipts, touch_data_buffer_index, transaction_id);
-+
-+	return ret;
-+}
-+
-+static int handle_outputs(ipts_info_t *ipts, int parallel_idx)
-+{
-+	kernel_output_buffer_header_t *out_buf_hdr;
-+	ipts_buffer_info_t *output_buf, *fb_buf = NULL;
-+	u8 *input_report, *payload;
-+	u32 transaction_id;
-+	int i, payload_size, ret = 0, header_size;
-+
-+	header_size = sizeof(kernel_output_buffer_header_t);
-+	output_buf = ipts_get_output_buffers_by_parallel_id(ipts, parallel_idx);
-+	for (i = 0; i < ipts->resource.num_of_outputs; i++) {
-+		out_buf_hdr = (kernel_output_buffer_header_t*)output_buf[i].addr;
-+		if (out_buf_hdr->length < header_size)
-+			continue;
-+
-+		payload_size = out_buf_hdr->length - header_size;
-+		payload = out_buf_hdr->data;
-+
-+		switch(out_buf_hdr->payload_type) {
-+			case OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT:
-+				input_report = ipts->hid_input_report;
-+				memcpy(input_report, payload, payload_size);
-+				hid_input_report(ipts->hid, HID_INPUT_REPORT,
-+						input_report, payload_size, 1);
-+				break;
-+			case OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT:
-+				ipts_dbg(ipts, "output hid feature report\n");
-+				break;
-+			case OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD:
-+				ipts_dbg(ipts, "output kernel load\n");
-+				break;
-+			case OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER:
-+			{
-+				/* send feedback data for raw data mode */
-+                                fb_buf = ipts_get_feedback_buffer(ipts,
-+								parallel_idx);
-+				transaction_id = out_buf_hdr->
-+						hid_private_data.transaction_id;
-+				memcpy(fb_buf->addr, payload, payload_size);
-+				break;
-+			}
-+			case OUTPUT_BUFFER_PAYLOAD_ERROR:
-+			{
-+				kernel_output_payload_error_t *err_payload;
-+
-+				if (payload_size == 0)
-+					break;
-+
-+				err_payload =
-+					(kernel_output_payload_error_t*)payload;
-+
-+				ipts_err(ipts, "error : severity : %d,"
-+						" source : %d,"
-+						" code : %d:%d:%d:%d\n"
-+						"string %s\n",
-+						err_payload->severity,
-+						err_payload->source,
-+						err_payload->code[0],
-+						err_payload->code[1],
-+						err_payload->code[2],
-+						err_payload->code[3],
-+						err_payload->string);
-+
-+				break;
-+			}
-+			default:
-+				ipts_err(ipts, "invalid output buffer payload\n");
-+				break;
-+		}
-+	}
-+
-+	/*
-+	 * XXX: Calling the "ipts_send_feedback" function repeatedly seems to be
-+	 * what is causing touch to crash (found by sebanc, see the link below for
-+	 * the comment) on some models, especially on Surface Pro 4 and
-+	 * Surface Book 1.
-+	 * The most desirable fix could be done by raising IPTS GuC priority. Until
-+	 * we find a better solution, use this workaround.
-+	 *
-+	 * Link to the comment where sebanc found this workaround:
-+	 * https://github.com/jakeday/linux-surface/issues/374#issuecomment-508234110
-+	 * (Touch and pen issue persists · Issue #374 · jakeday/linux-surface)
-+	 *
-+	 * Link to the usage from kitakar5525 who made this change:
-+	 * https://github.com/jakeday/linux-surface/issues/374#issuecomment-517289171
-+	 * (Touch and pen issue persists · Issue #374 · jakeday/linux-surface)
-+	 */
-+	if (fb_buf) {
-+		/* A negative value means "decide by dmi table" */
-+		if (ipts_modparams.no_feedback < 0)
-+			ipts_modparams.no_feedback =
-+				dmi_check_system(no_feedback_dmi_table) ? true : false;
-+
-+		if (ipts_modparams.no_feedback)
-+			return 0;
-+
-+		ret = ipts_send_feedback(ipts, parallel_idx, transaction_id);
-+		if (ret)
-+			return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int handle_output_buffers(ipts_info_t *ipts, int cur_idx, int end_idx)
-+{
-+	int max_num_of_buffers = ipts_get_num_of_parallel_buffers(ipts);
-+
-+	do {
-+		cur_idx++; /* cur_idx has last completed so starts with +1 */
-+		cur_idx %= max_num_of_buffers;
-+		handle_outputs(ipts, cur_idx);
-+	} while (cur_idx != end_idx);
-+
-+	return 0;
-+}
-+
-+int ipts_handle_processed_data(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+	int current_buffer_idx;
-+	int last_buffer_idx;
-+
-+	current_buffer_idx = *ipts->last_submitted_id;
-+	last_buffer_idx = ipts->last_buffer_completed;
-+
-+	if (current_buffer_idx == last_buffer_idx)
-+		return 0;
-+
-+	ipts->last_buffer_completed = current_buffer_idx;
-+	handle_output_buffers(ipts, last_buffer_idx, current_buffer_idx);
-+
-+	return ret;
-+}
-diff --git a/drivers/misc/ipts/ipts-hid.h b/drivers/misc/ipts/ipts-hid.h
-new file mode 100644
-index 000000000000..f1b22c912df7
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-hid.h
-@@ -0,0 +1,34 @@
-+/*
-+ * Intel Precise Touch & Stylus HID definition
-+ *
-+ * Copyright (c) 2016, 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.
-+ */
-+
-+#ifndef _IPTS_HID_H_
-+#define	_IPTS_HID_H_
-+
-+#define	BUS_MEI				0x44
-+
-+#if 0 /* TODO : we have special report ID. will implement them */
-+#define WRITE_CHANNEL_REPORT_ID		0xa
-+#define READ_CHANNEL_REPORT_ID		0xb
-+#define CONFIG_CHANNEL_REPORT_ID	0xd
-+#define VENDOR_INFO_REPORT_ID		0xF
-+#define SINGLE_TOUCH_REPORT_ID		0x40
-+#endif
-+
-+int ipts_hid_init(ipts_info_t *ipts);
-+void ipts_hid_release(ipts_info_t *ipts);
-+int ipts_handle_hid_data(ipts_info_t *ipts,
-+			touch_sensor_hid_ready_for_data_rsp_data_t *hid_rsp);
-+
-+#endif /* _IPTS_HID_H_ */
-diff --git a/drivers/misc/ipts/ipts-kernel.c b/drivers/misc/ipts/ipts-kernel.c
-new file mode 100644
-index 000000000000..5933b190cdaf
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-kernel.c
-@@ -0,0 +1,1042 @@
-+#include <linux/module.h>
-+#include <linux/firmware.h>
-+#include <linux/vmalloc.h>
-+#include <linux/intel_ipts_fw.h>
-+#include <linux/intel_ipts_if.h>
-+
-+#include "ipts.h"
-+#include "ipts-fw.h"
-+#include "ipts-resource.h"
-+#include "ipts-binary-spec.h"
-+#include "ipts-state.h"
-+#include "ipts-msg-handler.h"
-+#include "ipts-gfx.h"
-+
-+#pragma pack(1)
-+typedef struct bin_data_file_info {
-+    u32 io_buffer_type;
-+    u32 flags;
-+    char file_name[MAX_IOCL_FILE_NAME_LEN];
-+} bin_data_file_info_t;
-+
-+typedef struct bin_fw_info {
-+	char fw_name[MAX_IOCL_FILE_NAME_LEN];
-+
-+	/* list of parameters to load a kernel */
-+	s32 vendor_output;	/* output index. -1 for no use */
-+	u32 num_of_data_files;
-+	bin_data_file_info_t data_file[];
-+} bin_fw_info_t;
-+
-+typedef struct bin_fw_list {
-+	u32 num_of_fws;
-+	bin_fw_info_t fw_info[];
-+} bin_fw_list_t;
-+#pragma pack()
-+
-+/* OpenCL kernel */
-+typedef struct bin_workload {
-+	int cmdbuf_index;
-+	int iobuf_input;
-+	int iobuf_output[MAX_NUM_OUTPUT_BUFFERS];
-+} bin_workload_t;
-+
-+typedef struct bin_buffer {
-+	unsigned int handle;
-+	intel_ipts_mapbuffer_t *buf;
-+	bool no_unmap;	/* only releasing vendor kernel unmaps output buffers */
-+} bin_buffer_t;
-+
-+typedef struct bin_alloc_info {
-+	bin_buffer_t *buffs;
-+	int num_of_allocations;
-+	int num_of_outputs;
-+
-+	int num_of_buffers;
-+} bin_alloc_info_t;
-+
-+typedef struct bin_guc_wq_item {
-+	unsigned int batch_offset;
-+	unsigned int size;
-+	char data[];
-+} bin_guc_wq_item_t;
-+
-+typedef struct bin_kernel_info {
-+	bin_workload_t *wl;
-+	bin_alloc_info_t *alloc_info;
-+	bin_guc_wq_item_t *guc_wq_item;
-+	ipts_bin_bufid_patch_t bufid_patch;
-+
-+	bool is_vendor; /* 1: vendor, 0: postprocessing */
-+} bin_kernel_info_t;
-+
-+typedef struct bin_kernel_list {
-+	intel_ipts_mapbuffer_t *bufid_buf;
-+	int num_of_kernels;
-+	bin_kernel_info_t kernels[];
-+} bin_kernel_list_t;
-+
-+typedef struct bin_parse_info {
-+	u8 *data;
-+	int size;
-+	int parsed;
-+
-+	bin_fw_info_t *fw_info;
-+
-+	/* only used by postprocessing */
-+	bin_kernel_info_t *vendor_kernel;
-+	u32 interested_vendor_output; /* interested vendor output index */
-+} bin_parse_info_t;
-+
-+#define BDW_SURFACE_BASE_ADDRESS		0x6101000e
-+#define SURFACE_STATE_OFFSET_WORD		4
-+#define SBA_OFFSET_BYTES			16384
-+#define LASTSUBMITID_DEFAULT_VALUE		-1
-+
-+#define IPTS_FW_CONFIG_FILE			"ipts_fw_config.bin"
-+
-+#define IPTS_INPUT_ON				((u32)1 << IPTS_INPUT)
-+#define IPTS_OUTPUT_ON				((u32)1 << IPTS_OUTPUT)
-+#define IPTS_CONFIGURATION_ON			((u32)1 << IPTS_CONFIGURATION)
-+#define IPTS_CALIBRATION_ON			((u32)1 << IPTS_CALIBRATION)
-+#define IPTS_FEATURE_ON				((u32)1 << IPTS_FEATURE)
-+
-+#define	DATA_FILE_FLAG_SHARE			0x00000001
-+#define	DATA_FILE_FLAG_ALLOC_CONTIGUOUS		0x00000002
-+
-+static int bin_read_fw(ipts_info_t *ipts, const char *fw_name,
-+						u8* data, int size)
-+{
-+	const struct firmware *fw = NULL;
-+	int ret = 0;
-+
-+	ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
-+	if (ret) {
-+		ipts_err(ipts, "cannot read fw %s\n", fw_name);
-+		return ret;
-+	}
-+
-+	if (fw->size > size) {
-+		ipts_dbg(ipts, "too small buffer to contain fw data\n");
-+		ret = -EINVAL;
-+		goto rel_return;
-+	}
-+
-+	memcpy(data, fw->data, fw->size);
-+
-+rel_return:
-+	release_firmware(fw);
-+
-+	return ret;
-+}
-+
-+
-+static bin_data_file_info_t* bin_get_data_file_info(bin_fw_info_t* fw_info,
-+							u32 io_buffer_type)
-+{
-+	int i;
-+
-+	for (i = 0; i < fw_info->num_of_data_files; i++) {
-+		if (fw_info->data_file[i].io_buffer_type == io_buffer_type)
-+			break;
-+	}
-+
-+	if (i == fw_info->num_of_data_files)
-+		return NULL;
-+
-+	return &fw_info->data_file[i];
-+}
-+
-+static inline bool is_shared_data(const bin_data_file_info_t *data_file)
-+{
-+	if (data_file)
-+		return (!!(data_file->flags & DATA_FILE_FLAG_SHARE));
-+
-+	return false;
-+}
-+
-+static inline bool is_alloc_cont_data(const bin_data_file_info_t *data_file)
-+{
-+	if (data_file)
-+		return (!!(data_file->flags & DATA_FILE_FLAG_ALLOC_CONTIGUOUS));
-+
-+	return false;
-+}
-+
-+static inline bool is_parsing_vendor_kernel(const bin_parse_info_t *parse_info)
-+{
-+	/* vendor_kernel == null while loading itself(vendor kernel) */
-+	return parse_info->vendor_kernel == NULL;
-+}
-+
-+static int bin_read_allocation_list(ipts_info_t *ipts,
-+					bin_parse_info_t *parse_info,
-+					bin_alloc_info_t *alloc_info)
-+{
-+	ipts_bin_alloc_list_t *alloc_list;
-+	int alloc_idx, parallel_idx, num_of_parallels, buf_idx, num_of_buffers;
-+	int parsed, size;
-+
-+	parsed = parse_info->parsed;
-+	size = parse_info->size;
-+
-+	alloc_list = (ipts_bin_alloc_list_t *)&parse_info->data[parsed];
-+
-+	/* validation check */
-+	if (sizeof(alloc_list->num) > size - parsed)
-+		return -EINVAL;
-+
-+	/* read the number of aloocations */
-+	parsed += sizeof(alloc_list->num);
-+
-+	/* validation check */
-+	if (sizeof(alloc_list->alloc[0]) * alloc_list->num > size - parsed)
-+		return -EINVAL;
-+
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	num_of_buffers = num_of_parallels * alloc_list->num + num_of_parallels;
-+
-+	alloc_info->buffs = vmalloc(sizeof(bin_buffer_t) * num_of_buffers);
-+	if (alloc_info->buffs == NULL)
-+		return -ENOMEM;
-+
-+	memset(alloc_info->buffs, 0, sizeof(bin_buffer_t) * num_of_buffers);
-+	for (alloc_idx = 0; alloc_idx < alloc_list->num; alloc_idx++) {
-+		for (parallel_idx = 0; parallel_idx < num_of_parallels;
-+								parallel_idx++) {
-+			buf_idx = alloc_idx + (parallel_idx * alloc_list->num);
-+			alloc_info->buffs[buf_idx].handle =
-+					alloc_list->alloc[alloc_idx].handle;
-+
-+		}
-+
-+		parsed += sizeof(alloc_list->alloc[0]);
-+	}
-+
-+	parse_info->parsed = parsed;
-+	alloc_info->num_of_allocations = alloc_list->num;
-+	alloc_info->num_of_buffers = num_of_buffers;
-+
-+	ipts_dbg(ipts, "number of allocations = %d, buffers = %d\n",
-+						alloc_info->num_of_allocations,
-+						alloc_info->num_of_buffers);
-+
-+	return 0;
-+}
-+
-+static void patch_SBA(u32 *buf_addr, u64 gpu_addr, int size)
-+{
-+	u64 *stateBase;
-+	u64 SBA;
-+	u32 inst;
-+	int i;
-+
-+	SBA = gpu_addr + SBA_OFFSET_BYTES;
-+
-+	for (i = 0; i < size/4; i++) {
-+		inst = buf_addr[i];
-+		if (inst == BDW_SURFACE_BASE_ADDRESS) {
-+			stateBase = (u64*)&buf_addr[i + SURFACE_STATE_OFFSET_WORD];
-+			*stateBase |= SBA;
-+			*stateBase |= 0x01; // enable
-+			break;
-+		}
-+	}
-+}
-+
-+static int bin_read_cmd_buffer(ipts_info_t *ipts,
-+					bin_parse_info_t *parse_info,
-+					bin_alloc_info_t *alloc_info,
-+					bin_workload_t *wl)
-+{
-+	ipts_bin_cmdbuf_t *cmd;
-+	intel_ipts_mapbuffer_t *buf;
-+	int cmdbuf_idx, size, parsed, parallel_idx, num_of_parallels;
-+
-+	size = parse_info->size;
-+	parsed = parse_info->parsed;
-+
-+	cmd = (ipts_bin_cmdbuf_t *)&parse_info->data[parsed];
-+
-+	if (sizeof(cmd->size) > size - parsed)
-+		return -EINVAL;
-+
-+	parsed += sizeof(cmd->size);
-+	if (cmd->size > size - parsed)
-+		return -EINVAL;
-+
-+	ipts_dbg(ipts, "cmd buf size = %d\n", cmd->size);
-+
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	/* command buffers are located after the other allocations */
-+	cmdbuf_idx = num_of_parallels * alloc_info->num_of_allocations;
-+	for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) {
-+		buf = ipts_map_buffer(ipts, cmd->size, 0);
-+		if (buf == NULL)
-+			return -ENOMEM;
-+
-+		ipts_dbg(ipts, "cmd_idx[%d] = %d, g:0x%p, c:0x%p\n", parallel_idx,
-+					cmdbuf_idx, buf->gfx_addr, buf->cpu_addr);
-+
-+		memcpy((void *)buf->cpu_addr, &(cmd->data[0]), cmd->size);
-+		patch_SBA(buf->cpu_addr, (u64)buf->gfx_addr, cmd->size);
-+		alloc_info->buffs[cmdbuf_idx].buf = buf;
-+		wl[parallel_idx].cmdbuf_index = cmdbuf_idx;
-+
-+		cmdbuf_idx++;
-+	}
-+
-+	parsed += cmd->size;
-+	parse_info->parsed = parsed;
-+
-+	return 0;
-+}
-+
-+static int bin_find_alloc(ipts_info_t *ipts,
-+					bin_alloc_info_t *alloc_info,
-+					u32 handle)
-+{
-+	int i;
-+
-+	for (i = 0; i < alloc_info->num_of_allocations; i++) {
-+		if (alloc_info->buffs[i].handle == handle)
-+			return i;
-+	}
-+
-+	return -1;
-+}
-+
-+static intel_ipts_mapbuffer_t* bin_get_vendor_kernel_output(
-+						bin_parse_info_t *parse_info,
-+						int parallel_idx)
-+{
-+	bin_kernel_info_t *vendor = parse_info->vendor_kernel;
-+	bin_alloc_info_t *alloc_info;
-+	int buf_idx, vendor_output_idx;
-+
-+	alloc_info = vendor->alloc_info;
-+	vendor_output_idx = parse_info->interested_vendor_output;
-+
-+	if (vendor_output_idx >= alloc_info->num_of_outputs)
-+		return NULL;
-+
-+	buf_idx = vendor->wl[parallel_idx].iobuf_output[vendor_output_idx];
-+	return alloc_info->buffs[buf_idx].buf;
-+}
-+
-+static int bin_read_res_list(ipts_info_t *ipts,
-+					bin_parse_info_t *parse_info,
-+					bin_alloc_info_t *alloc_info,
-+					bin_workload_t *wl)
-+{
-+	ipts_bin_res_list_t *res_list;
-+	ipts_bin_res_t *res;
-+	intel_ipts_mapbuffer_t *buf;
-+	bin_data_file_info_t *data_file;
-+	u8 *bin_data;
-+	int i, size, parsed, parallel_idx, num_of_parallels, output_idx = -1;
-+	int buf_idx, num_of_alloc;
-+	u32 buf_size, flags, io_buf_type;
-+	bool initialize;
-+
-+	parsed = parse_info->parsed;
-+	size = parse_info->size;
-+	bin_data = parse_info->data;
-+
-+	res_list = (ipts_bin_res_list_t *)&parse_info->data[parsed];
-+	if (sizeof(res_list->num) > (size - parsed))
-+		return -EINVAL;
-+	parsed += sizeof(res_list->num);
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+
-+	ipts_dbg(ipts, "number of resources %u\n", res_list->num);
-+	for (i = 0; i < res_list->num; i++) {
-+		initialize = false;
-+		io_buf_type = 0;
-+		flags = 0;
-+
-+		/* initial data */
-+		data_file = NULL;
-+
-+		res = (ipts_bin_res_t *)(&(bin_data[parsed]));
-+		if (sizeof(res[0]) > (size - parsed)) {
-+			return -EINVAL;
-+		}
-+
-+		ipts_dbg(ipts, "Resource(%d):handle 0x%08x type %u init %u"
-+				" size %u alsigned %u\n",
-+				i, res->handle, res->type, res->initialize,
-+				res->size, res->aligned_size);
-+                parsed += sizeof(res[0]);
-+
-+		if (res->initialize) {
-+			if (res->size > (size - parsed)) {
-+				return -EINVAL;
-+			}
-+			parsed += res->size;
-+		}
-+
-+		initialize = res->initialize;
-+		if (initialize && res->size > sizeof(ipts_bin_io_header_t)) {
-+			ipts_bin_io_header_t *io_hdr;
-+			io_hdr = (ipts_bin_io_header_t *)(&res->data[0]);
-+			if (strncmp(io_hdr->str, "INTELTOUCH", 10) == 0) {
-+				data_file = bin_get_data_file_info(
-+							parse_info->fw_info,
-+							(u32)io_hdr->type);
-+				switch (io_hdr->type) {
-+				case IPTS_INPUT:
-+					ipts_dbg(ipts, "input detected\n");
-+					io_buf_type = IPTS_INPUT_ON;
-+					flags = IPTS_BUF_FLAG_CONTIGUOUS;
-+					break;
-+				case IPTS_OUTPUT:
-+					ipts_dbg(ipts, "output detected\n");
-+					io_buf_type = IPTS_OUTPUT_ON;
-+					output_idx++;
-+					break;
-+				default:
-+					if ((u32)io_hdr->type > 31) {
-+						ipts_err(ipts,
-+							"invalid io buffer : %u\n",
-+							(u32)io_hdr->type);
-+						continue;
-+					}
-+
-+					if (is_alloc_cont_data(data_file))
-+						flags = IPTS_BUF_FLAG_CONTIGUOUS;
-+
-+					io_buf_type = ((u32)1 << (u32)io_hdr->type);
-+					ipts_dbg(ipts, "special io buffer %u\n",
-+								io_hdr->type);
-+					break;
-+				}
-+
-+				initialize = false;
-+			}
-+		}
-+
-+		num_of_alloc = alloc_info->num_of_allocations;
-+		buf_idx = bin_find_alloc(ipts, alloc_info, res->handle);
-+		if (buf_idx == -1) {
-+			ipts_dbg(ipts, "cannot find alloc info\n");
-+			return -EINVAL;
-+		}
-+		for (parallel_idx = 0; parallel_idx < num_of_parallels;
-+					parallel_idx++, buf_idx += num_of_alloc) {
-+			if (!res->aligned_size)
-+				continue;
-+
-+			if (!(parallel_idx == 0 ||
-+				    (io_buf_type && !is_shared_data(data_file))))
-+				continue;
-+
-+			buf_size = res->aligned_size;
-+			if (io_buf_type & IPTS_INPUT_ON) {
-+				buf_size = max_t(u32,
-+						ipts->device_info.frame_size,
-+						buf_size);
-+				wl[parallel_idx].iobuf_input = buf_idx;
-+			} else if (io_buf_type & IPTS_OUTPUT_ON) {
-+				wl[parallel_idx].iobuf_output[output_idx] = buf_idx;
-+
-+				if (!is_parsing_vendor_kernel(parse_info) &&
-+								output_idx > 0) {
-+					ipts_err(ipts,
-+						"postproc with more than one inout"
-+						" is not supported : %d\n", output_idx);
-+					return -EINVAL;
-+				}
-+			}
-+
-+			if (!is_parsing_vendor_kernel(parse_info) &&
-+						io_buf_type & IPTS_OUTPUT_ON) {
-+				buf = bin_get_vendor_kernel_output(
-+								parse_info,
-+								parallel_idx);
-+				alloc_info->buffs[buf_idx].no_unmap = true;
-+			} else
-+				buf = ipts_map_buffer(ipts, buf_size, flags);
-+
-+			if (buf == NULL) {
-+				ipts_dbg(ipts, "ipts_map_buffer failed\n");
-+				return -ENOMEM;
-+			}
-+
-+			if (initialize) {
-+				memcpy((void *)buf->cpu_addr, &(res->data[0]),
-+								res->size);
-+			} else {
-+				if (data_file && strlen(data_file->file_name)) {
-+					bin_read_fw(ipts, data_file->file_name,
-+                                                        buf->cpu_addr, buf_size);
-+				} else if (is_parsing_vendor_kernel(parse_info) ||
-+						!(io_buf_type & IPTS_OUTPUT_ON)) {
-+					memset((void *)buf->cpu_addr, 0, res->size);
-+				}
-+			}
-+
-+			alloc_info->buffs[buf_idx].buf = buf;
-+		}
-+	}
-+
-+        alloc_info->num_of_outputs = output_idx + 1;
-+	parse_info->parsed = parsed;
-+
-+	return 0;
-+}
-+
-+static int bin_read_patch_list(ipts_info_t *ipts,
-+					bin_parse_info_t *parse_info,
-+					bin_alloc_info_t *alloc_info,
-+					bin_workload_t *wl)
-+{
-+	ipts_bin_patch_list_t *patch_list;
-+	ipts_bin_patch_t *patch;
-+	intel_ipts_mapbuffer_t *cmd = NULL;
-+	u8 *batch;
-+	int parsed, size, i, parallel_idx, num_of_parallels, cmd_idx, buf_idx;
-+	unsigned int gtt_offset;
-+
-+	parsed = parse_info->parsed;
-+	size = parse_info->size;
-+	patch_list = (ipts_bin_patch_list_t *)&parse_info->data[parsed];
-+
-+	if (sizeof(patch_list->num) > (size - parsed)) {
-+		return -EFAULT;
-+	}
-+	parsed += sizeof(patch_list->num);
-+
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	patch = (ipts_bin_patch_t *)(&patch_list->patch[0]);
-+	for (i = 0; i < patch_list->num; i++) {
-+		if (sizeof(patch_list->patch[0]) > (size - parsed)) {
-+			return -EFAULT;
-+		}
-+
-+		for (parallel_idx = 0; parallel_idx < num_of_parallels;
-+								parallel_idx++) {
-+			cmd_idx = wl[parallel_idx].cmdbuf_index;
-+			buf_idx = patch[i].index + parallel_idx *
-+						alloc_info->num_of_allocations;
-+
-+			if (alloc_info->buffs[buf_idx].buf == NULL) {
-+				/* buffer shared */
-+				buf_idx = patch[i].index;
-+			}
-+
-+			cmd = alloc_info->buffs[cmd_idx].buf;
-+			batch = (char *)(u64)cmd->cpu_addr;
-+
-+			gtt_offset = 0;
-+			if(alloc_info->buffs[buf_idx].buf != NULL) {
-+				gtt_offset = (u32)(u64)
-+					alloc_info->buffs[buf_idx].buf->gfx_addr;
-+			}
-+			gtt_offset += patch[i].alloc_offset;
-+
-+			batch += patch[i].patch_offset;
-+			*(u32*)batch = gtt_offset;
-+		}
-+
-+		parsed += sizeof(patch_list->patch[0]);
-+	}
-+
-+	parse_info->parsed = parsed;
-+
-+	return 0;
-+}
-+
-+static int bin_read_guc_wq_item(ipts_info_t *ipts,
-+					bin_parse_info_t *parse_info,
-+					bin_guc_wq_item_t **guc_wq_item)
-+{
-+	ipts_bin_guc_wq_info_t *bin_guc_wq;
-+	bin_guc_wq_item_t *item;
-+	u8 *wi_data;
-+	int size, parsed, hdr_size, wi_size;
-+	int i, batch_offset;
-+
-+	parsed = parse_info->parsed;
-+	size = parse_info->size;
-+	bin_guc_wq = (ipts_bin_guc_wq_info_t *)&parse_info->data[parsed];
-+
-+	wi_size = bin_guc_wq->size;
-+	wi_data = bin_guc_wq->data;
-+	batch_offset = bin_guc_wq->batch_offset;
-+	ipts_dbg(ipts, "wi size = %d, bt offset = %d\n", wi_size, batch_offset);
-+	for (i = 0; i < wi_size / sizeof(u32); i++) {
-+		ipts_dbg(ipts, "wi[%d] = 0x%08x\n", i, *((u32*)wi_data + i));
-+	}
-+	hdr_size = sizeof(bin_guc_wq->size) + sizeof(bin_guc_wq->batch_offset);
-+
-+	if (hdr_size > (size - parsed)) {
-+		return -EINVAL;
-+	}
-+	parsed += hdr_size;
-+
-+	item = vmalloc(sizeof(bin_guc_wq_item_t) + wi_size);
-+	if (item == NULL)
-+		return -ENOMEM;
-+
-+	item->size = wi_size;
-+	item->batch_offset = batch_offset;
-+	memcpy(item->data, wi_data, wi_size);
-+
-+	*guc_wq_item = item;
-+
-+	parsed += wi_size;
-+	parse_info->parsed = parsed;
-+
-+	return 0;
-+}
-+
-+static int bin_setup_guc_workqueue(ipts_info_t *ipts,
-+					bin_kernel_list_t *kernel_list)
-+{
-+	bin_alloc_info_t *alloc_info;
-+	bin_workload_t *wl;
-+	bin_kernel_info_t *kernel;
-+	u8 *wq_start, *wq_addr, *wi_data;
-+	bin_buffer_t *bin_buf;
-+	int wq_size, wi_size, parallel_idx, cmd_idx, k_idx, iter_size;
-+	int i, num_of_parallels, batch_offset, k_num, total_workload;
-+
-+	wq_addr = (u8*)ipts->resource.wq_info.wq_addr;
-+	wq_size = ipts->resource.wq_info.wq_size;
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	total_workload = ipts_get_wq_item_size(ipts);
-+	k_num = kernel_list->num_of_kernels;
-+
-+	iter_size = total_workload * num_of_parallels;
-+	if (wq_size % iter_size) {
-+		ipts_err(ipts, "wq item cannot fit into wq\n");
-+		return -EINVAL;
-+	}
-+
-+	wq_start = wq_addr;
-+	for (parallel_idx = 0; parallel_idx < num_of_parallels;
-+							parallel_idx++) {
-+		kernel = &kernel_list->kernels[0];
-+		for (k_idx = 0; k_idx < k_num; k_idx++, kernel++) {
-+			wl = kernel->wl;
-+			alloc_info = kernel->alloc_info;
-+
-+			batch_offset = kernel->guc_wq_item->batch_offset;
-+			wi_size = kernel->guc_wq_item->size;
-+			wi_data = &kernel->guc_wq_item->data[0];
-+
-+			cmd_idx = wl[parallel_idx].cmdbuf_index;
-+			bin_buf = &alloc_info->buffs[cmd_idx];
-+
-+			/* Patch the WQ Data with proper batch buffer offset */
-+			*(u32*)(wi_data + batch_offset) =
-+				(u32)(unsigned long)(bin_buf->buf->gfx_addr);
-+
-+			memcpy(wq_addr, wi_data, wi_size);
-+
-+			wq_addr += wi_size;
-+		}
-+	}
-+
-+	for (i = 0; i < (wq_size / iter_size) - 1; i++) {
-+		memcpy(wq_addr, wq_start, iter_size);
-+		wq_addr += iter_size;
-+	}
-+
-+	return 0;
-+}
-+
-+static int bin_read_bufid_patch(ipts_info_t *ipts,
-+					bin_parse_info_t *parse_info,
-+					ipts_bin_bufid_patch_t *bufid_patch)
-+{
-+	ipts_bin_bufid_patch_t *patch;
-+	int size, parsed;
-+
-+	parsed = parse_info->parsed;
-+	size = parse_info->size;
-+	patch = (ipts_bin_bufid_patch_t *)&parse_info->data[parsed];
-+
-+	if (sizeof(ipts_bin_bufid_patch_t) > (size - parsed)) {
-+		ipts_dbg(ipts, "invalid bufid info\n");
-+		return -EINVAL;
-+	}
-+	parsed += sizeof(ipts_bin_bufid_patch_t);
-+
-+	memcpy(bufid_patch, patch, sizeof(ipts_bin_bufid_patch_t));
-+
-+	parse_info->parsed = parsed;
-+
-+	return 0;
-+}
-+
-+static int bin_setup_bufid_buffer(ipts_info_t *ipts, bin_kernel_list_t *kernel_list)
-+{
-+	intel_ipts_mapbuffer_t *buf, *cmd_buf;
-+	bin_kernel_info_t *last_kernel;
-+	bin_alloc_info_t *alloc_info;
-+	bin_workload_t *wl;
-+	u8 *batch;
-+	int parallel_idx, num_of_parallels, cmd_idx;
-+	u32 mem_offset, imm_offset;
-+
-+	buf = ipts_map_buffer(ipts, PAGE_SIZE, 0);
-+	if (!buf) {
-+		return -ENOMEM;
-+	}
-+
-+	last_kernel = &kernel_list->kernels[kernel_list->num_of_kernels - 1];
-+
-+	mem_offset = last_kernel->bufid_patch.mem_offset;
-+	imm_offset = last_kernel->bufid_patch.imm_offset;
-+	wl = last_kernel->wl;
-+	alloc_info = last_kernel->alloc_info;
-+
-+	/* Initialize the buffer with default value */
-+        *((u32*)buf->cpu_addr) = LASTSUBMITID_DEFAULT_VALUE;
-+	ipts->current_buffer_index = LASTSUBMITID_DEFAULT_VALUE;
-+	ipts->last_buffer_completed = LASTSUBMITID_DEFAULT_VALUE;
-+	ipts->last_submitted_id = (int*)buf->cpu_addr;
-+
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) {
-+		cmd_idx = wl[parallel_idx].cmdbuf_index;
-+		cmd_buf = alloc_info->buffs[cmd_idx].buf;
-+		batch = (u8*)(u64)cmd_buf->cpu_addr;
-+
-+		*((u32*)(batch + mem_offset)) = (u32)(u64)(buf->gfx_addr);
-+                *((u32*)(batch + imm_offset)) = parallel_idx;
-+	}
-+
-+	kernel_list->bufid_buf = buf;
-+
-+	return 0;
-+}
-+
-+static void unmap_buffers(ipts_info_t *ipts, bin_alloc_info_t *alloc_info)
-+{
-+	bin_buffer_t *buffs;
-+	int i, num_of_buffers;
-+
-+	num_of_buffers = alloc_info->num_of_buffers;
-+	buffs = &alloc_info->buffs[0];
-+
-+	for (i = 0; i < num_of_buffers; i++) {
-+		if (buffs[i].no_unmap != true && buffs[i].buf != NULL)
-+			ipts_unmap_buffer(ipts, buffs[i].buf);
-+	}
-+}
-+
-+static int load_kernel(ipts_info_t *ipts, bin_parse_info_t *parse_info,
-+						bin_kernel_info_t *kernel)
-+{
-+	ipts_bin_header_t *hdr;
-+	bin_workload_t *wl;
-+	bin_alloc_info_t *alloc_info;
-+	bin_guc_wq_item_t *guc_wq_item = NULL;
-+	ipts_bin_bufid_patch_t bufid_patch;
-+	int num_of_parallels, ret;
-+
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+
-+        /* check header version and magic numbers */
-+	hdr = (ipts_bin_header_t *)parse_info->data;
-+	if (hdr->version != IPTS_BIN_HEADER_VERSION ||
-+					strncmp(hdr->str, "IOCL", 4) != 0) {
-+		ipts_err(ipts, "binary header is not correct version = %d, "
-+				"string = %c%c%c%c\n", hdr->version,
-+				hdr->str[0], hdr->str[1],
-+				hdr->str[2], hdr->str[3] );
-+		return -EINVAL;
-+	}
-+
-+	parse_info->parsed = sizeof(ipts_bin_header_t);
-+	wl = vmalloc(sizeof(bin_workload_t) * num_of_parallels);
-+	if (wl == NULL)
-+		return -ENOMEM;
-+	memset(wl, 0, sizeof(bin_workload_t) * num_of_parallels);
-+
-+	alloc_info = vmalloc(sizeof(bin_alloc_info_t));
-+	if (alloc_info == NULL) {
-+		vfree(wl);
-+		return -ENOMEM;
-+	}
-+	memset(alloc_info, 0, sizeof(bin_alloc_info_t));
-+
-+        ipts_dbg(ipts, "kernel setup(size : %d)\n", parse_info->size);
-+
-+	ret = bin_read_allocation_list(ipts, parse_info, alloc_info);
-+	if (ret) {
-+		ipts_dbg(ipts, "error read_allocation_list\n");
-+		goto setup_error;
-+	}
-+
-+	ret = bin_read_cmd_buffer(ipts, parse_info, alloc_info, wl);
-+	if (ret) {
-+		ipts_dbg(ipts, "error read_cmd_buffer\n");
-+		goto setup_error;
-+	}
-+
-+	ret = bin_read_res_list(ipts, parse_info, alloc_info, wl);
-+	if (ret) {
-+		ipts_dbg(ipts, "error read_res_list\n");
-+		goto setup_error;
-+	}
-+
-+	ret = bin_read_patch_list(ipts, parse_info, alloc_info, wl);
-+	if (ret) {
-+		ipts_dbg(ipts, "error read_patch_list\n");
-+		goto setup_error;
-+	}
-+
-+	ret = bin_read_guc_wq_item(ipts, parse_info, &guc_wq_item);
-+	if (ret) {
-+		ipts_dbg(ipts, "error read_guc_workqueue\n");
-+		goto setup_error;
-+	}
-+
-+	memset(&bufid_patch, 0, sizeof(bufid_patch));
-+	ret = bin_read_bufid_patch(ipts, parse_info, &bufid_patch);
-+	if (ret) {
-+		ipts_dbg(ipts, "error read_bufid_patch\n");
-+		goto setup_error;
-+	}
-+
-+	kernel->wl = wl;
-+	kernel->alloc_info = alloc_info;
-+	kernel->is_vendor = is_parsing_vendor_kernel(parse_info);
-+	kernel->guc_wq_item = guc_wq_item;
-+	memcpy(&kernel->bufid_patch, &bufid_patch, sizeof(bufid_patch));
-+
-+	return 0;
-+
-+setup_error:
-+	vfree(guc_wq_item);
-+
-+	unmap_buffers(ipts, alloc_info);
-+
-+	vfree(alloc_info->buffs);
-+	vfree(alloc_info);
-+	vfree(wl);
-+
-+	return ret;
-+}
-+
-+void bin_setup_input_output(ipts_info_t *ipts, bin_kernel_list_t *kernel_list)
-+{
-+	bin_kernel_info_t *vendor_kernel;
-+	bin_workload_t *wl;
-+	intel_ipts_mapbuffer_t *buf;
-+	bin_alloc_info_t *alloc_info;
-+	int parallel_idx, num_of_parallels, i, buf_idx;
-+
-+	vendor_kernel = &kernel_list->kernels[0];
-+
-+	wl = vendor_kernel->wl;
-+	alloc_info = vendor_kernel->alloc_info;
-+	ipts->resource.num_of_outputs = alloc_info->num_of_outputs;
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+
-+	for (parallel_idx = 0; parallel_idx < num_of_parallels; parallel_idx++) {
-+		buf_idx = wl[parallel_idx].iobuf_input;
-+		buf = alloc_info->buffs[buf_idx].buf;
-+
-+		ipts_dbg(ipts, "in_buf[%d](%d) c:%p, p:%p, g:%p\n",
-+					parallel_idx, buf_idx, (void*)buf->cpu_addr,
-+					(void*)buf->phy_addr, (void*)buf->gfx_addr);
-+
-+		ipts_set_input_buffer(ipts, parallel_idx, buf->cpu_addr,
-+								buf->phy_addr);
-+
-+		for (i = 0; i < alloc_info->num_of_outputs; i++) {
-+			buf_idx = wl[parallel_idx].iobuf_output[i];
-+			buf = alloc_info->buffs[buf_idx].buf;
-+
-+			ipts_dbg(ipts, "out_buf[%d][%d] c:%p, p:%p, g:%p\n",
-+					parallel_idx, i, (void*)buf->cpu_addr,
-+					(void*)buf->phy_addr, (void*)buf->gfx_addr);
-+
-+			ipts_set_output_buffer(ipts, parallel_idx, i,
-+					buf->cpu_addr, buf->phy_addr);
-+		}
-+	}
-+}
-+
-+static void unload_kernel(ipts_info_t *ipts, bin_kernel_info_t *kernel)
-+{
-+	bin_alloc_info_t *alloc_info = kernel->alloc_info;
-+	bin_guc_wq_item_t *guc_wq_item = kernel->guc_wq_item;
-+
-+	if (guc_wq_item) {
-+		vfree(guc_wq_item);
-+	}
-+
-+	if (alloc_info) {
-+		unmap_buffers(ipts, alloc_info);
-+
-+		vfree(alloc_info->buffs);
-+		vfree(alloc_info);
-+	}
-+}
-+
-+static int setup_kernel(ipts_info_t *ipts, bin_fw_list_t *fw_list)
-+{
-+	bin_kernel_list_t *kernel_list = NULL;
-+	bin_kernel_info_t *kernel = NULL;
-+	const struct firmware *fw = NULL;
-+	bin_workload_t *wl;
-+	bin_fw_info_t *fw_info;
-+	char *fw_name, *fw_data;
-+	bin_parse_info_t parse_info;
-+	int ret = 0, kernel_idx = 0, num_of_kernels = 0;
-+	int vendor_output_idx, total_workload = 0;
-+
-+	num_of_kernels = fw_list->num_of_fws;
-+	kernel_list = vmalloc(sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list));
-+	if (kernel_list == NULL)
-+		return -ENOMEM;
-+
-+	memset(kernel_list, 0, sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list));
-+	kernel_list->num_of_kernels = num_of_kernels;
-+	kernel = &kernel_list->kernels[0];
-+
-+	fw_data = (char *)&fw_list->fw_info[0];
-+	for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) {
-+		fw_info = (bin_fw_info_t *)fw_data;
-+		fw_name = &fw_info->fw_name[0];
-+		vendor_output_idx = fw_info->vendor_output;
-+		ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
-+		if (ret) {
-+			ipts_err(ipts, "cannot read fw %s\n", fw_name);
-+			goto error_exit;
-+		}
-+
-+		parse_info.data = (u8*)fw->data;
-+		parse_info.size = fw->size;
-+		parse_info.parsed = 0;
-+		parse_info.fw_info = fw_info;
-+		parse_info.vendor_kernel = (kernel_idx == 0) ? NULL : &kernel[0];
-+		parse_info.interested_vendor_output = vendor_output_idx;
-+
-+		ret = load_kernel(ipts, &parse_info, &kernel[kernel_idx]);
-+		if (ret) {
-+			ipts_err(ipts, "do_setup_kernel error : %d\n", ret);
-+			release_firmware(fw);
-+			goto error_exit;
-+		}
-+
-+		release_firmware(fw);
-+
-+		total_workload += kernel[kernel_idx].guc_wq_item->size;
-+
-+		/* advance to the next kernel */
-+		fw_data += sizeof(bin_fw_info_t);
-+		fw_data += sizeof(bin_data_file_info_t) * fw_info->num_of_data_files;
-+	}
-+
-+	ipts_set_wq_item_size(ipts, total_workload);
-+
-+	ret = bin_setup_guc_workqueue(ipts, kernel_list);
-+	if (ret) {
-+		ipts_dbg(ipts, "error setup_guc_workqueue\n");
-+		goto error_exit;
-+	}
-+
-+	ret = bin_setup_bufid_buffer(ipts, kernel_list);
-+	if (ret) {
-+		ipts_dbg(ipts, "error setup_lastbubmit_buffer\n");
-+		goto error_exit;
-+	}
-+
-+	bin_setup_input_output(ipts, kernel_list);
-+
-+	/* workload is not needed during run-time so free them */
-+	for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) {
-+		wl = kernel[kernel_idx].wl;
-+		vfree(wl);
-+	}
-+
-+	ipts->kernel_handle = (u64)kernel_list;
-+
-+	return 0;
-+
-+error_exit:
-+
-+	for (kernel_idx = 0; kernel_idx < num_of_kernels; kernel_idx++) {
-+		wl = kernel[kernel_idx].wl;
-+		vfree(wl);
-+		unload_kernel(ipts, &kernel[kernel_idx]);
-+	}
-+
-+	vfree(kernel_list);
-+
-+	return ret;
-+}
-+
-+
-+static void release_kernel(ipts_info_t *ipts)
-+{
-+	bin_kernel_list_t *kernel_list;
-+	bin_kernel_info_t *kernel;
-+	int k_idx, k_num;
-+
-+	kernel_list = (bin_kernel_list_t *)ipts->kernel_handle;
-+	k_num = kernel_list->num_of_kernels;
-+	kernel = &kernel_list->kernels[0];
-+
-+	for (k_idx = 0; k_idx < k_num; k_idx++) {
-+		unload_kernel(ipts, kernel);
-+		kernel++;
-+	}
-+
-+	ipts_unmap_buffer(ipts, kernel_list->bufid_buf);
-+
-+	vfree(kernel_list);
-+	ipts->kernel_handle = 0;
-+}
-+
-+int ipts_init_kernels(ipts_info_t *ipts)
-+{
-+	const struct firmware *config_fw = NULL;
-+	const char *config_fw_path = IPTS_FW_CONFIG_FILE;
-+	bin_fw_list_t *fw_list;
-+	int ret;
-+
-+	ret = ipts_open_gpu(ipts);
-+	if (ret) {
-+		ipts_err(ipts, "open gpu error : %d\n", ret);
-+		return ret;
-+	}
-+
-+	ret = ipts_request_firmware(&config_fw, config_fw_path,	&ipts->cldev->dev);
-+	if (ret) {
-+		ipts_err(ipts, "request firmware error : %d\n", ret);
-+		goto close_gpu;
-+	}
-+
-+	fw_list = (bin_fw_list_t *)config_fw->data;
-+	ret = setup_kernel(ipts, fw_list);
-+	if (ret) {
-+		ipts_err(ipts, "setup kernel error : %d\n", ret);
-+		goto close_firmware;
-+	}
-+
-+	release_firmware(config_fw);
-+
-+	return ret;
-+
-+close_firmware:
-+	release_firmware(config_fw);
-+
-+close_gpu:
-+	ipts_close_gpu(ipts);
-+
-+	return ret;
-+}
-+
-+void ipts_release_kernels(ipts_info_t *ipts)
-+{
-+	release_kernel(ipts);
-+	ipts_close_gpu(ipts);
-+}
-diff --git a/drivers/misc/ipts/ipts-kernel.h b/drivers/misc/ipts/ipts-kernel.h
-new file mode 100644
-index 000000000000..0e7f1393b807
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-kernel.h
-@@ -0,0 +1,23 @@
-+/*
-+ *
-+ * Intel Precise Touch & Stylus Linux driver
-+ * Copyright (c) 2016, 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.
-+ *
-+ */
-+
-+#ifndef _ITPS_GFX_H
-+#define _ITPS_GFX_H
-+
-+int ipts_init_kernels(ipts_info_t *ipts);
-+void ipts_release_kernels(ipts_info_t *ipts);
-+
-+#endif
-diff --git a/drivers/misc/ipts/ipts-mei-msgs.h b/drivers/misc/ipts/ipts-mei-msgs.h
-new file mode 100644
-index 000000000000..8ca146800a47
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-mei-msgs.h
-@@ -0,0 +1,585 @@
-+/*
-+ * Precise Touch HECI Message
-+ *
-+ * Copyright (c) 2013-2016, 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.
-+ */
-+
-+#ifndef _IPTS_MEI_MSGS_H_
-+#define _IPTS_MEI_MSGS_H_
-+
-+#include "ipts-sensor-regs.h"
-+
-+#pragma pack(1)
-+
-+
-+// Initial protocol version
-+#define TOUCH_HECI_CLIENT_PROTOCOL_VERSION      10
-+
-+// GUID that identifies the Touch HECI client.
-+#define TOUCH_HECI_CLIENT_GUID  \
-+            {0x3e8d0870, 0x271a, 0x4208, {0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04}}
-+
-+
-+// define C_ASSERT macro to check structure size and fail compile for unexpected mismatch
-+#ifndef C_ASSERT
-+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
-+#endif
-+
-+
-+// General Type Defines for compatibility with HID driver and BIOS
-+#ifndef BIT0
-+#define BIT0 1
-+#endif
-+#ifndef BIT1
-+#define BIT1 2
-+#endif
-+#ifndef BIT2
-+#define BIT2 4
-+#endif
-+
-+
-+#define TOUCH_SENSOR_GET_DEVICE_INFO_CMD        0x00000001
-+#define TOUCH_SENSOR_GET_DEVICE_INFO_RSP        0x80000001
-+
-+
-+#define TOUCH_SENSOR_SET_MODE_CMD               0x00000002
-+#define TOUCH_SENSOR_SET_MODE_RSP               0x80000002
-+
-+
-+#define TOUCH_SENSOR_SET_MEM_WINDOW_CMD         0x00000003
-+#define TOUCH_SENSOR_SET_MEM_WINDOW_RSP         0x80000003
-+
-+
-+#define TOUCH_SENSOR_QUIESCE_IO_CMD             0x00000004
-+#define TOUCH_SENSOR_QUIESCE_IO_RSP             0x80000004
-+
-+
-+#define TOUCH_SENSOR_HID_READY_FOR_DATA_CMD     0x00000005
-+#define TOUCH_SENSOR_HID_READY_FOR_DATA_RSP     0x80000005
-+
-+
-+#define TOUCH_SENSOR_FEEDBACK_READY_CMD         0x00000006
-+#define TOUCH_SENSOR_FEEDBACK_READY_RSP         0x80000006
-+
-+
-+#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD       0x00000007
-+#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP       0x80000007
-+
-+
-+#define TOUCH_SENSOR_NOTIFY_DEV_READY_CMD       0x00000008
-+#define TOUCH_SENSOR_NOTIFY_DEV_READY_RSP       0x80000008
-+
-+
-+#define TOUCH_SENSOR_SET_POLICIES_CMD           0x00000009
-+#define TOUCH_SENSOR_SET_POLICIES_RSP           0x80000009
-+
-+
-+#define TOUCH_SENSOR_GET_POLICIES_CMD           0x0000000A
-+#define TOUCH_SENSOR_GET_POLICIES_RSP           0x8000000A
-+
-+
-+#define TOUCH_SENSOR_RESET_CMD                  0x0000000B
-+#define TOUCH_SENSOR_RESET_RSP                  0x8000000B
-+
-+
-+#define TOUCH_SENSOR_READ_ALL_REGS_CMD          0x0000000C
-+#define TOUCH_SENSOR_READ_ALL_REGS_RSP          0x8000000C
-+
-+
-+#define TOUCH_SENSOR_CMD_ERROR_RSP              0x8FFFFFFF  // M2H: ME sends this message to indicate previous command was unrecognized/unsupported
-+
-+
-+
-+//*******************************************************************
-+//
-+// Touch Sensor Status Codes
-+//
-+//*******************************************************************
-+typedef enum touch_status
-+{
-+    TOUCH_STATUS_SUCCESS = 0,               //  0 Requested operation was successful
-+    TOUCH_STATUS_INVALID_PARAMS,            //  1 Invalid parameter(s) sent
-+    TOUCH_STATUS_ACCESS_DENIED,             //  2 Unable to validate address range
-+    TOUCH_STATUS_CMD_SIZE_ERROR,            //  3 HECI message incorrect size for specified command
-+    TOUCH_STATUS_NOT_READY,                 //  4 Memory window not set or device is not armed for operation
-+    TOUCH_STATUS_REQUEST_OUTSTANDING,       //  5 There is already an outstanding message of the same type, must wait for response before sending another request of that type
-+    TOUCH_STATUS_NO_SENSOR_FOUND,           //  6 Sensor could not be found. Either no sensor is connected, the sensor has not yet initialized, or the system is improperly configured.
-+    TOUCH_STATUS_OUT_OF_MEMORY,             //  7 Not enough memory/storage for requested operation
-+    TOUCH_STATUS_INTERNAL_ERROR,            //  8 Unexpected error occurred
-+    TOUCH_STATUS_SENSOR_DISABLED,           //  9 Used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP to indicate sensor has been disabled or reset and must be reinitialized.
-+    TOUCH_STATUS_COMPAT_CHECK_FAIL,         // 10 Used to indicate compatibility revision check between sensor and ME failed, or protocol ver between ME/HID/Kernels failed.
-+    TOUCH_STATUS_SENSOR_EXPECTED_RESET,     // 11 Indicates sensor went through a reset initiated by ME
-+    TOUCH_STATUS_SENSOR_UNEXPECTED_RESET,   // 12 Indicates sensor went through an unexpected reset
-+    TOUCH_STATUS_RESET_FAILED,              // 13 Requested sensor reset failed to complete
-+    TOUCH_STATUS_TIMEOUT,                   // 14 Operation timed out
-+    TOUCH_STATUS_TEST_MODE_FAIL,            // 15 Test mode pattern did not match expected values
-+    TOUCH_STATUS_SENSOR_FAIL_FATAL,         // 16 Indicates sensor reported fatal error during reset sequence. Further progress is not possible.
-+    TOUCH_STATUS_SENSOR_FAIL_NONFATAL,      // 17 Indicates sensor reported non-fatal error during reset sequence. HID/BIOS logs error and attempts to continue.
-+    TOUCH_STATUS_INVALID_DEVICE_CAPS,       // 18 Indicates sensor reported invalid capabilities, such as not supporting required minimum frequency or I/O mode.
-+    TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS,    // 19 Indicates that command cannot be complete until ongoing Quiesce I/O flow has completed.
-+    TOUCH_STATUS_MAX                        // 20 Invalid value, never returned
-+} touch_status_t;
-+C_ASSERT(sizeof(touch_status_t) == 4);
-+
-+
-+
-+//*******************************************************************
-+//
-+// Defines for message structures used for Host to ME communication
-+//
-+//*******************************************************************
-+
-+
-+typedef enum touch_sensor_mode
-+{
-+    TOUCH_SENSOR_MODE_HID = 0,          // Set mode to HID mode
-+    TOUCH_SENSOR_MODE_RAW_DATA,         // Set mode to Raw Data mode
-+    TOUCH_SENSOR_MODE_SENSOR_DEBUG = 4, // Used like TOUCH_SENSOR_MODE_HID but data coming from sensor is not necessarily a HID packet.
-+    TOUCH_SENSOR_MODE_MAX               // Invalid value
-+} touch_sensor_mode_t;
-+C_ASSERT(sizeof(touch_sensor_mode_t) == 4);
-+
-+typedef struct touch_sensor_set_mode_cmd_data
-+{
-+    touch_sensor_mode_t	sensor_mode;     // Indicate desired sensor mode
-+    u32					Reserved[3];    // For future expansion
-+} touch_sensor_set_mode_cmd_data_t;
-+C_ASSERT(sizeof(touch_sensor_set_mode_cmd_data_t) == 16);
-+
-+
-+#define TOUCH_SENSOR_MAX_DATA_BUFFERS   16
-+#define TOUCH_HID_2_ME_BUFFER_ID        TOUCH_SENSOR_MAX_DATA_BUFFERS
-+#define TOUCH_HID_2_ME_BUFFER_SIZE_MAX  1024
-+#define TOUCH_INVALID_BUFFER_ID         0xFF
-+
-+typedef struct touch_sensor_set_mem_window_cmd_data
-+{
-+    u32  touch_data_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS];    // Lower 32 bits of Touch Data Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize
-+    u32  touch_data_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS];    // Upper 32 bits of Touch Data Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize
-+    u32  tail_offset_addr_lower;                                        // Lower 32 bits of Tail Offset physical address
-+    u32  tail_offset_addr_upper;                                        // Upper 32 bits of Tail Offset physical address, always 32 bit, increment by WorkQueueItemSize
-+    u32  doorbell_cookie_addr_lower;                                    // Lower 32 bits of Doorbell register physical address
-+    u32  doorbell_cookie_addr_upper;                                    // Upper 32 bits of Doorbell register physical address, always 32 bit, increment as integer, rollover to 1
-+    u32  feedback_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS];     // Lower 32 bits of Feedback Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize
-+    u32  feedback_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS];     // Upper 32 bits of Feedback Buffer physical address. Size of each buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize
-+    u32  hid2me_buffer_addr_lower;                                      // Lower 32 bits of dedicated HID to ME communication buffer. Size is Hid2MeBufferSize.
-+    u32  hid2me_buffer_addr_upper;                                      // Upper 32 bits of dedicated HID to ME communication buffer. Size is Hid2MeBufferSize.
-+    u32  hid2me_buffer_size;                                           // Size in bytes of Hid2MeBuffer, can be no bigger than TOUCH_HID_2_ME_BUFFER_SIZE_MAX
-+    u8   reserved1;                                                  // For future expansion
-+    u8   work_queue_item_size;                                          // Size in bytes of the GuC Work Queue Item pointed to by TailOffset
-+    u16  work_queue_size;                                              // Size in bytes of the entire GuC Work Queue
-+    u32  reserved[8];                                                // For future expansion
-+} touch_sensor_set_mem_window_cmd_data_t;
-+C_ASSERT(sizeof(touch_sensor_set_mem_window_cmd_data_t) == 320);
-+
-+
-+#define TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET BIT0   // indicates GuC got reset and ME must re-read GuC data such as TailOffset and Doorbell Cookie values
-+
-+typedef struct touch_sensor_quiesce_io_cmd_data
-+{
-+    u32  quiesce_flags;   // Optionally set TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET
-+    u32  reserved[2];
-+} touch_sensor_quiesce_io_cmd_data_t;
-+C_ASSERT(sizeof(touch_sensor_quiesce_io_cmd_data_t) == 12);
-+
-+
-+typedef struct touch_sensor_feedback_ready_cmd_data
-+{
-+    u8   feedback_index;  // Index value from 0 to TOUCH_HID_2_ME_BUFFER_ID used to indicate which Feedback Buffer to use. Using special value TOUCH_HID_2_ME_BUFFER_ID
-+                            // is an indication to ME to get feedback data from the Hid2Me buffer instead of one of the standard Feedback buffers.
-+    u8   reserved1[3];   // For future expansion
-+    u32  transaction_id;  // Transaction ID that was originally passed to host in TOUCH_HID_PRIVATE_DATA. Used to track round trip of a given transaction for performance measurements.
-+    u32  reserved2[2];   // For future expansion
-+} touch_sensor_feedback_ready_cmd_data_t;
-+C_ASSERT(sizeof(touch_sensor_feedback_ready_cmd_data_t) == 16);
-+
-+
-+#define TOUCH_DEFAULT_DOZE_TIMER_SECONDS    30
-+
-+typedef enum touch_freq_override
-+{
-+    TOUCH_FREQ_OVERRIDE_NONE,   // Do not apply any override
-+    TOUCH_FREQ_OVERRIDE_10MHZ,  // Force frequency to 10MHz (not currently supported)
-+    TOUCH_FREQ_OVERRIDE_17MHZ,  // Force frequency to 17MHz
-+    TOUCH_FREQ_OVERRIDE_30MHZ,  // Force frequency to 30MHz
-+    TOUCH_FREQ_OVERRIDE_50MHZ,  // Force frequency to 50MHz (not currently supported)
-+    TOUCH_FREQ_OVERRIDE_MAX     // Invalid value
-+} touch_freq_override_t;
-+C_ASSERT(sizeof(touch_freq_override_t) == 4);
-+
-+typedef enum touch_spi_io_mode_override
-+{
-+    TOUCH_SPI_IO_MODE_OVERRIDE_NONE,    // Do not apply any override
-+    TOUCH_SPI_IO_MODE_OVERRIDE_SINGLE,  // Force Single I/O
-+    TOUCH_SPI_IO_MODE_OVERRIDE_DUAL,    // Force Dual I/O
-+    TOUCH_SPI_IO_MODE_OVERRIDE_QUAD,    // Force Quad I/O
-+    TOUCH_SPI_IO_MODE_OVERRIDE_MAX      // Invalid value
-+} touch_spi_io_mode_override_t;
-+C_ASSERT(sizeof(touch_spi_io_mode_override_t) == 4);
-+
-+// Debug Policy bits used by TOUCH_POLICY_DATA.DebugOverride
-+#define TOUCH_DBG_POLICY_OVERRIDE_STARTUP_TIMER_DIS BIT0    // Disable sensor startup timer
-+#define TOUCH_DBG_POLICY_OVERRIDE_SYNC_BYTE_DIS     BIT1    // Disable Sync Byte check
-+#define TOUCH_DBG_POLICY_OVERRIDE_ERR_RESET_DIS     BIT2    // Disable error resets
-+
-+typedef struct touch_policy_data
-+{
-+    u32                      reserved0;          // For future expansion.
-+    u32                      doze_timer     :16;  // Value in seconds, after which ME will put the sensor into Doze power state if no activity occurs. Set
-+                                                    // to 0 to disable Doze mode (not recommended). Value will be set to TOUCH_DEFAULT_DOZE_TIMER_SECONDS by
-+                                                    // default.
-+    touch_freq_override_t         freq_override  :3;   // Override frequency requested by sensor
-+    touch_spi_io_mode_override_t  spi_io_override :3;   // Override IO mode requested by sensor
-+    u32                      reserved1     :10;  // For future expansion
-+    u32                      reserved2;          // For future expansion
-+    u32                      debug_override;      // Normally all bits will be zero. Bits will be defined as needed for enabling special debug features
-+} touch_policy_data_t;
-+C_ASSERT(sizeof(touch_policy_data_t) == 16);
-+
-+typedef struct touch_sensor_set_policies_cmd_data
-+{
-+    touch_policy_data_t           policy_data;         // Contains the desired policy to be set
-+} touch_sensor_set_policies_cmd_data_t;
-+C_ASSERT(sizeof(touch_sensor_set_policies_cmd_data_t) == 16);
-+
-+
-+typedef enum touch_sensor_reset_type
-+{
-+    TOUCH_SENSOR_RESET_TYPE_HARD,   // Hardware Reset using dedicated GPIO pin
-+    TOUCH_SENSOR_RESET_TYPE_SOFT,   // Software Reset using command written over SPI interface
-+    TOUCH_SENSOR_RESET_TYPE_MAX     // Invalid value
-+} touch_sensor_reset_type_t;
-+C_ASSERT(sizeof(touch_sensor_reset_type_t) == 4);
-+
-+typedef struct touch_sensor_reset_cmd_data
-+{
-+    touch_sensor_reset_type_t reset_type;  // Indicate desired reset type
-+    u32                  reserved;   // For future expansion
-+} touch_sensor_reset_cmd_data_t;
-+C_ASSERT(sizeof(touch_sensor_reset_cmd_data_t) == 8);
-+
-+
-+//
-+// Host to ME message
-+//
-+typedef struct touch_sensor_msg_h2m
-+{
-+    u32  command_code;
-+    union
-+    {
-+        touch_sensor_set_mode_cmd_data_t        set_mode_cmd_data;
-+        touch_sensor_set_mem_window_cmd_data_t  set_window_cmd_data;
-+        touch_sensor_quiesce_io_cmd_data_t      quiesce_io_cmd_data;
-+        touch_sensor_feedback_ready_cmd_data_t  feedback_ready_cmd_data;
-+        touch_sensor_set_policies_cmd_data_t    set_policies_cmd_data;
-+        touch_sensor_reset_cmd_data_t           reset_cmd_data;
-+    } h2m_data;
-+} touch_sensor_msg_h2m_t;
-+C_ASSERT(sizeof(touch_sensor_msg_h2m_t) == 324);
-+
-+
-+//*******************************************************************
-+//
-+// Defines for message structures used for ME to Host communication
-+//
-+//*******************************************************************
-+
-+// I/O mode values used by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
-+typedef enum touch_spi_io_mode
-+{
-+    TOUCH_SPI_IO_MODE_SINGLE = 0,   // Sensor set for Single I/O SPI
-+    TOUCH_SPI_IO_MODE_DUAL,         // Sensor set for Dual I/O SPI
-+    TOUCH_SPI_IO_MODE_QUAD,         // Sensor set for Quad I/O SPI
-+    TOUCH_SPI_IO_MODE_MAX           // Invalid value
-+} touch_spi_io_mode_t;
-+C_ASSERT(sizeof(touch_spi_io_mode_t) == 4);
-+
-+//
-+// TOUCH_SENSOR_GET_DEVICE_INFO_RSP code is sent in response to TOUCH_SENSOR_GET_DEVICE_INFO_CMD. This code will be followed
-+// by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:               Command was processed successfully and sensor details are reported.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:        Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_NO_SENSOR_FOUND:       Sensor has not yet been detected. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_DEVICE_CAPS:   Indicates sensor does not support minimum required Frequency or I/O Mode. ME firmware will choose best possible option for the errant
-+//                                          field. Caller should attempt to continue.
-+//      TOUCH_STATUS_COMPAT_CHECK_FAIL:     Indicates TouchIC/ME compatibility mismatch. Caller should attempt to continue.
-+//
-+typedef struct touch_sensor_get_device_info_rsp_data
-+{
-+    u16				vendor_id;               // Touch Sensor vendor ID
-+    u16              device_id;               // Touch Sensor device ID
-+    u32              hw_rev;                  // Touch Sensor Hardware Revision
-+    u32              fw_rev;                  // Touch Sensor Firmware Revision
-+    u32              frame_size;              // Max size of one frame returned by Touch IC in bytes. This data will be TOUCH_RAW_DATA_HDR followed
-+                                                // by a payload. The payload can be raw data or a HID structure depending on mode.
-+    u32              feedback_size;           // Max size of one Feedback structure in bytes
-+    touch_sensor_mode_t	sensor_mode;             // Current operating mode of the sensor
-+    u32              max_touch_points  :8;     // Maximum number of simultaneous touch points that can be reported by sensor
-+    touch_freq_t          spi_frequency    :8;     // SPI bus Frequency supported by sensor and ME firmware
-+    touch_spi_io_mode_t   spi_io_mode       :8;     // SPI bus I/O Mode supported by sensor and ME firmware
-+    u32              reserved0       :8;     // For future expansion
-+    u8               sensor_minor_eds_rev;      // Minor version number of EDS spec supported by sensor (from Compat Rev ID Reg)
-+    u8               sensor_major_eds_rev;      // Major version number of EDS spec supported by sensor (from Compat Rev ID Reg)
-+    u8               me_minor_eds_rev;          // Minor version number of EDS spec supported by ME
-+    u8               me_major_eds_rev;          // Major version number of EDS spec supported by ME
-+    u8               sensor_eds_intf_rev;       // EDS Interface Revision Number supported by sensor (from Compat Rev ID Reg)
-+    u8               me_eds_intf_rev;           // EDS Interface Revision Number supported by ME
-+    u8               kernel_compat_ver;        // EU Kernel Compatibility Version  (from Compat Rev ID Reg)
-+    u8               reserved1;              // For future expansion
-+    u32              reserved2[2];           // For future expansion
-+} touch_sensor_get_device_info_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_get_device_info_rsp_data_t) == 44);
-+
-+
-+//
-+// TOUCH_SENSOR_SET_MODE_RSP code is sent in response to TOUCH_SENSOR_SET_MODE_CMD. This code will be followed
-+// by TOUCH_SENSOR_SET_MODE_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and mode was set.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
-+//
-+typedef struct touch_sensor_set_mode_rsp_data
-+{
-+    u32          reserved[3];    // For future expansion
-+} touch_sensor_set_mode_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_set_mode_rsp_data_t) == 12);
-+
-+
-+//
-+// TOUCH_SENSOR_SET_MEM_WINDOW_RSP code is sent in response to TOUCH_SENSOR_SET_MEM_WINDOW_CMD. This code will be followed
-+// by TOUCH_SENSOR_SET_MEM_WINDOW_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and memory window was set.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
-+//      TOUCH_STATUS_ACCESS_DENIED:     Unable to map host address ranges for DMA.
-+//      TOUCH_STATUS_OUT_OF_MEMORY:     Unable to allocate enough space for needed buffers.
-+//
-+typedef struct touch_sensor_set_mem_window_rsp_data
-+{
-+    u32          reserved[3];    // For future expansion
-+} touch_sensor_set_mem_window_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_set_mem_window_rsp_data_t) == 12);
-+
-+
-+//
-+// TOUCH_SENSOR_QUIESCE_IO_RSP code is sent in response to TOUCH_SENSOR_QUIESCE_IO_CMD. This code will be followed
-+// by TOUCH_SENSOR_QUIESCE_IO_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and touch flow has stopped.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
-+//      TOUCH_STATIS_TIMEOUT:                   Indicates ME timed out waiting for Quiesce I/O flow to complete.
-+//
-+typedef struct touch_sensor_quiesce_io_rsp_data
-+{
-+    u32          reserved[3];    // For future expansion
-+} touch_sensor_quiesce_io_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_quiesce_io_rsp_data_t) == 12);
-+
-+
-+// Reset Reason values used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA
-+typedef enum touch_reset_reason
-+{
-+    TOUCH_RESET_REASON_UNKNOWN = 0,         // Reason for sensor reset is not known
-+    TOUCH_RESET_REASON_FEEDBACK_REQUEST,    // Reset was requested as part of TOUCH_SENSOR_FEEDBACK_READY_CMD
-+    TOUCH_RESET_REASON_HECI_REQUEST,        // Reset was requested via TOUCH_SENSOR_RESET_CMD
-+    TOUCH_RESET_REASON_MAX
-+} touch_reset_reason_t;
-+C_ASSERT(sizeof(touch_reset_reason_t) == 4);
-+
-+//
-+// TOUCH_SENSOR_HID_READY_FOR_DATA_RSP code is sent in response to TOUCH_SENSOR_HID_READY_FOR_DATA_CMD. This code will be followed
-+// by TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and HID data was sent by DMA. This will only be sent in HID mode.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_REQUEST_OUTSTANDING:       Previous request is still outstanding, ME FW cannot handle another request for the same command.
-+//      TOUCH_STATUS_NOT_READY:                 Indicates memory window has not yet been set by BIOS/HID.
-+//      TOUCH_STATUS_SENSOR_DISABLED:           Indicates that ME to HID communication has been stopped either by TOUCH_SENSOR_QUIESCE_IO_CMD or TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD.
-+//      TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:   Sensor signaled a Reset Interrupt. ME did not expect this and has no info about why this occurred.
-+//      TOUCH_STATUS_SENSOR_EXPECTED_RESET:     Sensor signaled a Reset Interrupt. ME either directly requested this reset, or it was expected as part of a defined flow in the EDS.
-+//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
-+//      TOUCH_STATUS_TIMEOUT:                   Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning.
-+//
-+typedef struct touch_sensor_hid_ready_for_data_rsp_data
-+{
-+    u32          data_size;               // Size of the data the ME DMA'd into a RawDataBuffer. Valid only when Status == TOUCH_STATUS_SUCCESS
-+    u8           touch_data_buffer_index;   // Index to indicate which RawDataBuffer was used. Valid only when Status == TOUCH_STATUS_SUCCESS
-+    u8           reset_reason;            // If Status is TOUCH_STATUS_SENSOR_EXPECTED_RESET, ME will provide the cause. See TOUCH_RESET_REASON.
-+    u8           reserved1[2];           // For future expansion
-+    u32          reserved2[5];           // For future expansion
-+} touch_sensor_hid_ready_for_data_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_hid_ready_for_data_rsp_data_t) == 28);
-+
-+
-+//
-+// TOUCH_SENSOR_FEEDBACK_READY_RSP code is sent in response to TOUCH_SENSOR_FEEDBACK_READY_CMD. This code will be followed
-+// by TOUCH_SENSOR_FEEDBACK_READY_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and any feedback or commands were sent to sensor.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
-+//      TOUCH_STATUS_COMPAT_CHECK_FAIL  Indicates ProtocolVer does not match ME supported version. (non-fatal error)
-+//      TOUCH_STATUS_INTERNAL_ERROR:    Unexpected error occurred. This should not normally be seen.
-+//      TOUCH_STATUS_OUT_OF_MEMORY:     Insufficient space to store Calibration Data
-+//
-+typedef struct touch_sensor_feedback_ready_rsp_data
-+{
-+    u8           feedback_index;  // Index value from 0 to TOUCH_SENSOR_MAX_DATA_BUFFERS used to indicate which Feedback Buffer to use
-+    u8           reserved1[3];   // For future expansion
-+    u32          reserved2[6];   // For future expansion
-+} touch_sensor_feedback_ready_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_feedback_ready_rsp_data_t) == 28);
-+
-+
-+//
-+// TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP code is sent in response to TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD. This code will be followed
-+// by TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and memory window was set.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_PARAMS:            Input parameters are out of range.
-+//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
-+//
-+typedef struct touch_sensor_clear_mem_window_rsp_data
-+{
-+    u32          reserved[3];    // For future expansion
-+} touch_sensor_clear_mem_window_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_clear_mem_window_rsp_data_t) == 12);
-+
-+
-+//
-+// TOUCH_SENSOR_NOTIFY_DEV_READY_RSP code is sent in response to TOUCH_SENSOR_NOTIFY_DEV_READY_CMD. This code will be followed
-+// by TOUCH_SENSOR_NOTIFY_DEV_READY_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:               Command was processed successfully and sensor has been detected by ME FW.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:        Command sent did not match expected size.
-+//      TOUCH_STATUS_REQUEST_OUTSTANDING:   Previous request is still outstanding, ME FW cannot handle another request for the same command.
-+//      TOUCH_STATUS_TIMEOUT:               Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning.
-+//      TOUCH_STATUS_SENSOR_FAIL_FATAL:     Sensor indicated a fatal error, further operation is not possible. Error details can be found in ErrReg.
-+//      TOUCH_STATUS_SENSOR_FAIL_NONFATAL:  Sensor indicated a non-fatal error. Error should be logged by caller and init flow can continue. Error details can be found in ErrReg.
-+//
-+typedef struct touch_sensor_notify_dev_ready_rsp_data
-+{
-+    touch_err_reg_t   err_reg;         // Value of sensor Error Register, field is only valid for Status == TOUCH_STATUS_SENSOR_FAIL_FATAL or TOUCH_STATUS_SENSOR_FAIL_NONFATAL
-+    u32          reserved[2];    // For future expansion
-+} touch_sensor_notify_dev_ready_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_notify_dev_ready_rsp_data_t) == 12);
-+
-+
-+//
-+// TOUCH_SENSOR_SET_POLICIES_RSP code is sent in response to TOUCH_SENSOR_SET_POLICIES_CMD. This code will be followed
-+// by TOUCH_SENSOR_SET_POLICIES_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and new policies were set.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_PARAMS:    Input parameters are out of range.
-+//
-+typedef struct touch_sensor_set_policies_rsp_data
-+{
-+    u32          reserved[3];    // For future expansion
-+} touch_sensor_set_policies_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_set_policies_rsp_data_t) == 12);
-+
-+
-+//
-+// TOUCH_SENSOR_GET_POLICIES_RSP code is sent in response to TOUCH_SENSOR_GET_POLICIES_CMD. This code will be followed
-+// by TOUCH_SENSOR_GET_POLICIES_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and new policies were set.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
-+//
-+typedef struct touch_sensor_get_policies_rsp_data
-+{
-+    touch_policy_data_t   policy_data;         // Contains the current policy
-+} touch_sensor_get_policies_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_get_policies_rsp_data_t) == 16);
-+
-+
-+//
-+// TOUCH_SENSOR_RESET_RSP code is sent in response to TOUCH_SENSOR_RESET_CMD. This code will be followed
-+// by TOUCH_SENSOR_RESET_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:                   Command was processed successfully and sensor reset was completed.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:            Command sent did not match expected size. Other fields will not contain valid data.
-+//      TOUCH_STATUS_INVALID_PARAMS:            Input parameters are out of range.
-+//      TOUCH_STATUS_TIMEOUT:                   Sensor did not generate a reset interrupt in the time allotted. Could indicate sensor is not connected or malfunctioning.
-+//      TOUCH_STATUS_RESET_FAILED:              Sensor generated an invalid or unexpected interrupt.
-+//      TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:    Indicates that Quiesce I/O is already in progress and this command cannot be accepted at this time.
-+//
-+typedef struct touch_sensor_reset_rsp_data
-+{
-+    u32          reserved[3];    // For future expansion
-+} touch_sensor_reset_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_reset_rsp_data_t) == 12);
-+
-+
-+//
-+// TOUCH_SENSOR_READ_ALL_REGS_RSP code is sent in response to TOUCH_SENSOR_READ_ALL_REGS_CMD. This code will be followed
-+// by TOUCH_SENSOR_READ_ALL_REGS_RSP_DATA.
-+//
-+// Possible Status values:
-+//      TOUCH_STATUS_SUCCESS:           Command was processed successfully and new policies were set.
-+//      TOUCH_STATUS_CMD_SIZE_ERROR:    Command sent did not match expected size. Other fields will not contain valid data.
-+//
-+typedef struct touch_sensor_read_all_regs_rsp_data
-+{
-+    touch_reg_block_t sensor_regs; // Returns first 64 bytes of register space used for normal touch operation. Does not include test mode register.
-+    u32          reserved[4];
-+} touch_sensor_read_all_regs_rsp_data_t;
-+C_ASSERT(sizeof(touch_sensor_read_all_regs_rsp_data_t) == 80);
-+
-+//
-+// ME to Host Message
-+//
-+typedef struct touch_sensor_msg_m2h
-+{
-+    u32  command_code;
-+    touch_status_t	status;
-+    union
-+    {
-+        touch_sensor_get_device_info_rsp_data_t     device_info_rsp_data;
-+        touch_sensor_set_mode_rsp_data_t            set_mode_rsp_data;
-+        touch_sensor_set_mem_window_rsp_data_t      set_mem_window_rsp_data;
-+        touch_sensor_quiesce_io_rsp_data_t          quiesce_io_rsp_data;
-+        touch_sensor_hid_ready_for_data_rsp_data_t  hid_ready_for_data_rsp_data;
-+        touch_sensor_feedback_ready_rsp_data_t      feedback_ready_rsp_data;
-+        touch_sensor_clear_mem_window_rsp_data_t    clear_mem_window_rsp_data;
-+        touch_sensor_notify_dev_ready_rsp_data_t    notify_dev_ready_rsp_data;
-+        touch_sensor_set_policies_rsp_data_t        set_policies_rsp_data;
-+        touch_sensor_get_policies_rsp_data_t        get_policies_rsp_data;
-+        touch_sensor_reset_rsp_data_t               reset_rsp_data;
-+	touch_sensor_read_all_regs_rsp_data_t       read_all_regs_rsp_data;
-+    } m2h_data;
-+} touch_sensor_msg_m2h_t;
-+C_ASSERT(sizeof(touch_sensor_msg_m2h_t) == 88);
-+
-+
-+#define TOUCH_MSG_SIZE_MAX_BYTES    (MAX(sizeof(touch_sensor_msg_m2h_t), sizeof(touch_sensor_msg_h2m_t)))
-+
-+#pragma pack()
-+
-+#endif // _IPTS_MEI_MSGS_H_
-diff --git a/drivers/misc/ipts/ipts-mei.c b/drivers/misc/ipts/ipts-mei.c
-new file mode 100644
-index 000000000000..6fbe257bc7cc
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-mei.c
-@@ -0,0 +1,290 @@
-+/*
-+ * MEI client driver for Intel Precise Touch and Stylus
-+ *
-+ * Copyright (c) 2016, 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.
-+ */
-+
-+#include <linux/mei_cl_bus.h>
-+#include <linux/module.h>
-+#include <linux/mod_devicetable.h>
-+#include <linux/hid.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/kthread.h>
-+#include <linux/intel_ipts_if.h>
-+
-+#include "ipts.h"
-+#include "ipts-fw.h"
-+#include "ipts-hid.h"
-+#include "ipts-params.h"
-+#include "ipts-msg-handler.h"
-+#include "ipts-mei-msgs.h"
-+#include "ipts-binary-spec.h"
-+#include "ipts-state.h"
-+
-+#define IPTS_DRIVER_NAME	"ipts"
-+#define IPTS_MEI_UUID		UUID_LE(0x3e8d0870, 0x271a, 0x4208, \
-+				0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04)
-+
-+static struct mei_cl_device_id ipts_mei_cl_tbl[] = {
-+	{ "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY},
-+	{}
-+};
-+
-+static ssize_t sensor_mode_show(struct device *dev,
-+				struct device_attribute *attr, char *buf)
-+{
-+	ipts_info_t *ipts;
-+	ipts = dev_get_drvdata(dev);
-+
-+	return sprintf(buf, "%d\n", ipts->sensor_mode);
-+}
-+
-+//TODO: Verify the function implementation
-+static ssize_t sensor_mode_store(struct device *dev,
-+				struct device_attribute *attr, const char *buf,
-+				size_t count)
-+{
-+	int ret;
-+	long val;
-+	ipts_info_t *ipts;
-+
-+	ipts = dev_get_drvdata(dev);
-+	ret = kstrtol(buf, 10, &val);
-+	if (ret)
-+	   return ret;
-+
-+	ipts_dbg(ipts, "try sensor mode = %ld\n", val);
-+
-+	switch (val) {
-+		case TOUCH_SENSOR_MODE_HID:
-+			break;
-+		case TOUCH_SENSOR_MODE_RAW_DATA:
-+			break;
-+		default:
-+			ipts_err(ipts, "sensor mode %ld is not supported\n", val);
-+	}
-+
-+	return count;
-+}
-+
-+static ssize_t device_info_show(struct device *dev,
-+				struct device_attribute *attr, char *buf)
-+{
-+	ipts_info_t *ipts;
-+
-+	ipts = dev_get_drvdata(dev);
-+	return sprintf(buf, "vendor id = 0x%04hX\n"
-+				"device id = 0x%04hX\n"
-+				"HW rev = 0x%08X\n"
-+				"firmware rev = 0x%08X\n",
-+			ipts->device_info.vendor_id, ipts->device_info.device_id,
-+			ipts->device_info.hw_rev, ipts->device_info.fw_rev);
-+}
-+
-+static DEVICE_ATTR_RW(sensor_mode);
-+static DEVICE_ATTR_RO(device_info);
-+
-+static struct attribute *ipts_attrs[] = {
-+	&dev_attr_sensor_mode.attr,
-+	&dev_attr_device_info.attr,
-+	NULL
-+};
-+
-+static const struct attribute_group ipts_grp = {
-+	.attrs = ipts_attrs,
-+};
-+
-+MODULE_DEVICE_TABLE(mei, ipts_mei_cl_tbl);
-+
-+static void raw_data_work_func(struct work_struct *work)
-+{
-+	ipts_info_t *ipts = container_of(work, ipts_info_t, raw_data_work);
-+
-+	ipts_handle_processed_data(ipts);
-+}
-+
-+static void gfx_status_work_func(struct work_struct *work)
-+{
-+	ipts_info_t *ipts = container_of(work, ipts_info_t, gfx_status_work);
-+	ipts_state_t state;
-+	int status = ipts->gfx_status;
-+
-+	ipts_dbg(ipts, "notify gfx status : %d\n", status);
-+
-+	state = ipts_get_state(ipts);
-+
-+	if (state == IPTS_STA_RAW_DATA_STARTED || state == IPTS_STA_HID_STARTED) {
-+		if (status == IPTS_NOTIFY_STA_BACKLIGHT_ON &&
-+					ipts->display_status == false) {
-+			ipts_send_sensor_clear_mem_window_cmd(ipts);
-+			ipts->display_status = true;
-+		} else if (status == IPTS_NOTIFY_STA_BACKLIGHT_OFF &&
-+					ipts->display_status == true) {
-+			ipts_send_sensor_quiesce_io_cmd(ipts);
-+			ipts->display_status = false;
-+		}
-+	}
-+}
-+
-+/* event loop */
-+static int ipts_mei_cl_event_thread(void *data)
-+{
-+	ipts_info_t *ipts = (ipts_info_t *)data;
-+	struct mei_cl_device *cldev = ipts->cldev;
-+	ssize_t msg_len;
-+	touch_sensor_msg_m2h_t m2h_msg;
-+
-+	while (!kthread_should_stop()) {
-+		msg_len = mei_cldev_recv(cldev, (u8*)&m2h_msg, sizeof(m2h_msg));
-+		if (msg_len <= 0) {
-+			ipts_err(ipts, "error in reading m2h msg\n");
-+			continue;
-+		}
-+
-+		if (ipts_handle_resp(ipts, &m2h_msg, msg_len) != 0) {
-+			ipts_err(ipts, "error in handling resp msg\n");
-+		}
-+	}
-+
-+	ipts_dbg(ipts, "!! end event loop !!\n");
-+
-+	return 0;
-+}
-+
-+static void init_work_func(struct work_struct *work)
-+{
-+	ipts_info_t *ipts = container_of(work, ipts_info_t, init_work);
-+
-+	ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA;
-+	ipts->display_status = true;
-+
-+	ipts_start(ipts);
-+}
-+
-+static int ipts_mei_cl_probe(struct mei_cl_device *cldev,
-+			const struct mei_cl_device_id *id)
-+{
-+	int ret = 0;
-+	ipts_info_t *ipts = NULL;
-+
-+	// Check if a companion driver for firmware loading was registered
-+	// If not, defer probing until it was properly registere
-+	if (!ipts_fw_handler_available() && !ipts_modparams.ignore_companion) {
-+		return -EPROBE_DEFER;
-+	}
-+
-+	pr_info("probing Intel Precise Touch & Stylus\n");
-+
-+	// setup the DMA BIT mask, the system will choose the best possible
-+	if (dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64)) == 0) {
-+		pr_info("IPTS using DMA_BIT_MASK(64)\n");
-+	} else if (dma_coerce_mask_and_coherent(&cldev->dev,
-+						DMA_BIT_MASK(32)) == 0) {
-+		pr_info("IPTS using  DMA_BIT_MASK(32)\n");
-+	} else {
-+		pr_err("IPTS: No suitable DMA available\n");
-+		return -EFAULT;
-+	}
-+
-+	ret = mei_cldev_enable(cldev);
-+	if (ret < 0) {
-+		pr_err("cannot enable IPTS\n");
-+		return ret;
-+	}
-+
-+	ipts = devm_kzalloc(&cldev->dev, sizeof(ipts_info_t), GFP_KERNEL);
-+	if (ipts == NULL) {
-+		ret = -ENOMEM;
-+		goto disable_mei;
-+	}
-+	ipts->cldev = cldev;
-+	mei_cldev_set_drvdata(cldev, ipts);
-+
-+	ipts->event_loop = kthread_run(ipts_mei_cl_event_thread, (void*)ipts,
-+							"ipts_event_thread");
-+
-+	if(ipts_dbgfs_register(ipts, "ipts"))
-+		pr_debug("cannot register debugfs for IPTS\n");
-+
-+	INIT_WORK(&ipts->init_work, init_work_func);
-+	INIT_WORK(&ipts->raw_data_work, raw_data_work_func);
-+	INIT_WORK(&ipts->gfx_status_work, gfx_status_work_func);
-+
-+	ret = sysfs_create_group(&cldev->dev.kobj, &ipts_grp);
-+	if (ret != 0) {
-+		pr_debug("cannot create sysfs for IPTS\n");
-+	}
-+
-+	schedule_work(&ipts->init_work);
-+
-+	return 0;
-+
-+disable_mei :
-+	mei_cldev_disable(cldev);
-+
-+	return ret;
-+}
-+
-+static int ipts_mei_cl_remove(struct mei_cl_device *cldev)
-+{
-+	ipts_info_t *ipts = mei_cldev_get_drvdata(cldev);
-+
-+	ipts_stop(ipts);
-+
-+	sysfs_remove_group(&cldev->dev.kobj, &ipts_grp);
-+	ipts_hid_release(ipts);
-+	ipts_dbgfs_deregister(ipts);
-+	mei_cldev_disable(cldev);
-+
-+	kthread_stop(ipts->event_loop);
-+
-+	pr_info("IPTS removed\n");
-+
-+	return 0;
-+}
-+
-+static struct mei_cl_driver ipts_mei_cl_driver = {
-+	.id_table = ipts_mei_cl_tbl,
-+	.name = IPTS_DRIVER_NAME,
-+	.probe = ipts_mei_cl_probe,
-+	.remove = ipts_mei_cl_remove,
-+};
-+
-+static int ipts_mei_cl_init(void)
-+{
-+	int ret;
-+
-+	pr_info("IPTS %s() is called\n", __func__);
-+
-+	ret = mei_cldev_driver_register(&ipts_mei_cl_driver);
-+	if (ret) {
-+		pr_err("unable to register IPTS mei client driver\n");
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static void __exit ipts_mei_cl_exit(void)
-+{
-+	pr_info("IPTS %s() is called\n", __func__);
-+
-+	mei_cldev_driver_unregister(&ipts_mei_cl_driver);
-+}
-+
-+module_init(ipts_mei_cl_init);
-+module_exit(ipts_mei_cl_exit);
-+
-+MODULE_DESCRIPTION
-+	("Intel(R) Management Engine Interface Client Driver for "\
-+	"Intel Precision Touch and Sylus");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/misc/ipts/ipts-msg-handler.c b/drivers/misc/ipts/ipts-msg-handler.c
-new file mode 100644
-index 000000000000..db5356a1c84e
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-msg-handler.c
-@@ -0,0 +1,437 @@
-+#include <linux/mei_cl_bus.h>
-+
-+#include "ipts.h"
-+#include "ipts-hid.h"
-+#include "ipts-resource.h"
-+#include "ipts-mei-msgs.h"
-+
-+int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size)
-+{
-+	int ret = 0;
-+	touch_sensor_msg_h2m_t h2m_msg;
-+	int len = 0;
-+
-+	memset(&h2m_msg, 0, sizeof(h2m_msg));
-+
-+	h2m_msg.command_code = cmd;
-+	len = sizeof(h2m_msg.command_code) + data_size;
-+	if (data != NULL && data_size != 0)
-+		memcpy(&h2m_msg.h2m_data, data, data_size); /* copy payload */
-+
-+	ret = mei_cldev_send(ipts->cldev, (u8*)&h2m_msg, len);
-+	if (ret < 0) {
-+		ipts_err(ipts, "mei_cldev_send() error 0x%X:%d\n",
-+							cmd, ret);
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id)
-+{
-+	int ret;
-+	int cmd_len;
-+	touch_sensor_feedback_ready_cmd_data_t fb_ready_cmd;
-+
-+	cmd_len = sizeof(touch_sensor_feedback_ready_cmd_data_t);
-+	memset(&fb_ready_cmd, 0, cmd_len);
-+
-+	fb_ready_cmd.feedback_index = buffer_idx;
-+	fb_ready_cmd.transaction_id = transaction_id;
-+
-+	ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_FEEDBACK_READY_CMD,
-+				&fb_ready_cmd, cmd_len);
-+
-+	return ret;
-+}
-+
-+int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts)
-+{
-+	int ret;
-+	int cmd_len;
-+	touch_sensor_quiesce_io_cmd_data_t quiesce_io_cmd;
-+
-+	cmd_len = sizeof(touch_sensor_quiesce_io_cmd_data_t);
-+	memset(&quiesce_io_cmd, 0, cmd_len);
-+
-+	ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_QUIESCE_IO_CMD,
-+				&quiesce_io_cmd, cmd_len);
-+
-+	return ret;
-+}
-+
-+int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts)
-+{
-+	return ipts_handle_cmd(ipts, TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, NULL, 0);
-+}
-+
-+int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts)
-+{
-+	return ipts_handle_cmd(ipts, TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD, NULL, 0);
-+}
-+
-+static int check_validity(touch_sensor_msg_m2h_t *m2h_msg, u32 msg_len)
-+{
-+	int ret = 0;
-+	int valid_msg_len = sizeof(m2h_msg->command_code);
-+	u32 cmd_code = m2h_msg->command_code;
-+
-+	switch (cmd_code) {
-+		case TOUCH_SENSOR_SET_MODE_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_set_mode_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_set_mem_window_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_QUIESCE_IO_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_quiesce_io_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_hid_ready_for_data_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_FEEDBACK_READY_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_feedback_ready_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_clear_mem_window_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_notify_dev_ready_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_SET_POLICIES_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_set_policies_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_GET_POLICIES_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_get_policies_rsp_data_t);
-+			break;
-+		case TOUCH_SENSOR_RESET_RSP:
-+			valid_msg_len +=
-+				sizeof(touch_sensor_reset_rsp_data_t);
-+			break;
-+	}
-+
-+	if (valid_msg_len != msg_len) {
-+		return -EINVAL;
-+	}
-+
-+	return ret;
-+}
-+
-+int ipts_start(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+	/* TODO : check if we need to do SET_POLICIES_CMD
-+	we need to do this when protocol version doesn't match with reported one
-+	how we keep vendor specific data is the first thing to solve */
-+
-+	ipts_set_state(ipts, IPTS_STA_INIT);
-+	ipts->num_of_parallel_data_buffers = TOUCH_SENSOR_MAX_DATA_BUFFERS;
-+
-+	ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA; /* start with RAW_DATA */
-+
-+	ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_NOTIFY_DEV_READY_CMD, NULL, 0);
-+
-+	return ret;
-+}
-+
-+void ipts_stop(ipts_info_t *ipts)
-+{
-+	ipts_state_t old_state;
-+
-+	old_state = ipts_get_state(ipts);
-+	ipts_set_state(ipts, IPTS_STA_STOPPING);
-+
-+	ipts_send_sensor_quiesce_io_cmd(ipts);
-+	ipts_send_sensor_clear_mem_window_cmd(ipts);
-+
-+	if (old_state < IPTS_STA_RESOURCE_READY)
-+		return;
-+
-+	if (old_state == IPTS_STA_RAW_DATA_STARTED ||
-+					old_state == IPTS_STA_HID_STARTED) {
-+		ipts_free_default_resource(ipts);
-+		ipts_free_raw_data_resource(ipts);
-+
-+		return;
-+	}
-+}
-+
-+int ipts_restart(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+
-+	ipts_dbg(ipts, "ipts restart\n");
-+
-+	ipts_stop(ipts);
-+
-+	ipts->retry++;
-+	if (ipts->retry == IPTS_MAX_RETRY &&
-+			ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) {
-+		/* try with HID mode */
-+		ipts->sensor_mode = TOUCH_SENSOR_MODE_HID;
-+	} else if (ipts->retry > IPTS_MAX_RETRY) {
-+		return -EPERM;
-+	}
-+
-+	ipts_send_sensor_quiesce_io_cmd(ipts);
-+	ipts->restart = true;
-+
-+	return ret;
-+}
-+
-+int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode)
-+{
-+	int ret = 0;
-+
-+        ipts->new_sensor_mode = new_sensor_mode;
-+	ipts->switch_sensor_mode = true;
-+        ret = ipts_send_sensor_quiesce_io_cmd(ipts);
-+
-+	return ret;
-+}
-+
-+#define rsp_failed(ipts, cmd, status) ipts_err(ipts, \
-+				"0x%08x failed status = %d\n", cmd, status);
-+
-+int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg,
-+								u32 msg_len)
-+{
-+	int ret = 0;
-+	int rsp_status = 0;
-+	int cmd_status = 0;
-+	int cmd_len = 0;
-+	u32 cmd;
-+
-+	if (!check_validity(m2h_msg, msg_len)) {
-+		ipts_err(ipts, "wrong rsp\n");
-+		return -EINVAL;
-+	}
-+
-+	rsp_status = m2h_msg->status;
-+	cmd = m2h_msg->command_code;
-+
-+	switch (cmd) {
-+		case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
-+			if (rsp_status != 0 &&
-+			  rsp_status != TOUCH_STATUS_SENSOR_FAIL_NONFATAL) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			cmd_status = ipts_handle_cmd(ipts,
-+					TOUCH_SENSOR_GET_DEVICE_INFO_CMD,
-+					NULL, 0);
-+			break;
-+		case TOUCH_SENSOR_GET_DEVICE_INFO_RSP:
-+			if (rsp_status != 0 &&
-+			  rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			memcpy(&ipts->device_info,
-+				&m2h_msg->m2h_data.device_info_rsp_data,
-+				sizeof(touch_sensor_get_device_info_rsp_data_t));
-+
-+			/*
-+			    TODO : support raw_request during HID init.
-+			    Although HID init happens here, technically most of
-+			    reports (for both direction) can be issued only
-+			    after SET_MEM_WINDOWS_CMD since they may require
-+			    ME or touch IC. If ipts vendor requires raw_request
-+			    during HID init, we need to consider to move HID init.
-+			*/
-+			if (ipts->hid_desc_ready == false) {
-+				ret = ipts_hid_init(ipts);
-+				if (ret)
-+					break;
-+			}
-+
-+			cmd_status = ipts_send_sensor_clear_mem_window_cmd(ipts);
-+
-+			break;
-+		case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
-+		{
-+			touch_sensor_set_mode_cmd_data_t sensor_mode_cmd;
-+
-+			if (rsp_status != 0 &&
-+					rsp_status != TOUCH_STATUS_TIMEOUT) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			if (ipts_get_state(ipts) == IPTS_STA_STOPPING)
-+				break;
-+
-+			/* allocate default resource : common & hid only */
-+			if (!ipts_is_default_resource_ready(ipts)) {
-+				ret = ipts_allocate_default_resource(ipts);
-+				if (ret)
-+					break;
-+			}
-+
-+			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA &&
-+					!ipts_is_raw_data_resource_ready(ipts)) {
-+				ret = ipts_allocate_raw_data_resource(ipts);
-+				if (ret) {
-+					ipts_free_default_resource(ipts);
-+					break;
-+				}
-+			}
-+
-+			ipts_set_state(ipts, IPTS_STA_RESOURCE_READY);
-+
-+			cmd_len = sizeof(touch_sensor_set_mode_cmd_data_t);
-+			memset(&sensor_mode_cmd, 0, cmd_len);
-+			sensor_mode_cmd.sensor_mode = ipts->sensor_mode;
-+			cmd_status = ipts_handle_cmd(ipts,
-+				TOUCH_SENSOR_SET_MODE_CMD,
-+				&sensor_mode_cmd, cmd_len);
-+			break;
-+		}
-+		case TOUCH_SENSOR_SET_MODE_RSP:
-+		{
-+			touch_sensor_set_mem_window_cmd_data_t smw_cmd;
-+
-+			if (rsp_status != 0) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			cmd_len = sizeof(touch_sensor_set_mem_window_cmd_data_t);
-+			memset(&smw_cmd, 0, cmd_len);
-+			ipts_get_set_mem_window_cmd_data(ipts, &smw_cmd);
-+			cmd_status = ipts_handle_cmd(ipts,
-+				TOUCH_SENSOR_SET_MEM_WINDOW_CMD,
-+				&smw_cmd, cmd_len);
-+			break;
-+		}
-+		case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
-+			if (rsp_status != 0) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			cmd_status = ipts_send_sensor_hid_ready_for_data_cmd(ipts);
-+			if (cmd_status)
-+				break;
-+
-+			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) {
-+				ipts_set_state(ipts, IPTS_STA_HID_STARTED);
-+			} else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) {
-+				ipts_set_state(ipts, IPTS_STA_RAW_DATA_STARTED);
-+			}
-+
-+			ipts_err(ipts, "touch enabled %d\n", ipts_get_state(ipts));
-+
-+			break;
-+		case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
-+		{
-+			touch_sensor_hid_ready_for_data_rsp_data_t *hid_data;
-+			ipts_state_t state;
-+
-+			if (rsp_status != 0 &&
-+				  rsp_status != TOUCH_STATUS_SENSOR_DISABLED) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			state = ipts_get_state(ipts);
-+			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID &&
-+						state == IPTS_STA_HID_STARTED) {
-+
-+				hid_data = &m2h_msg->m2h_data.hid_ready_for_data_rsp_data;
-+
-+				/* HID mode only uses buffer 0 */
-+				if (hid_data->touch_data_buffer_index != 0)
-+					break;
-+
-+				/* handle hid data */
-+				ipts_handle_hid_data(ipts, hid_data);
-+			}
-+
-+			break;
-+		}
-+		case TOUCH_SENSOR_FEEDBACK_READY_RSP:
-+			if (rsp_status != 0 &&
-+			  rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			if (m2h_msg->m2h_data.feedback_ready_rsp_data.
-+					feedback_index == TOUCH_HID_2_ME_BUFFER_ID)
-+				break;
-+
-+			if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) {
-+				cmd_status = ipts_handle_cmd(ipts,
-+					TOUCH_SENSOR_HID_READY_FOR_DATA_CMD,
-+					NULL, 0);
-+			}
-+
-+			/* reset retry since we are getting touch data */
-+			ipts->retry = 0;
-+
-+			break;
-+		case TOUCH_SENSOR_QUIESCE_IO_RSP:
-+		{
-+			ipts_state_t state;
-+
-+			if (rsp_status != 0) {
-+				rsp_failed(ipts, cmd, rsp_status);
-+				break;
-+			}
-+
-+			state = ipts_get_state(ipts);
-+			if (state == IPTS_STA_STOPPING && ipts->restart) {
-+				ipts_dbg(ipts, "restart\n");
-+			        ipts_start(ipts);
-+				ipts->restart = 0;
-+				break;
-+			}
-+
-+			/* support sysfs debug node for switch sensor mode */
-+			if (ipts->switch_sensor_mode) {
-+				ipts_set_state(ipts, IPTS_STA_INIT);
-+				ipts->sensor_mode = ipts->new_sensor_mode;
-+				ipts->switch_sensor_mode = false;
-+
-+				ipts_send_sensor_clear_mem_window_cmd(ipts);
-+			}
-+
-+			break;
-+		}
-+	}
-+
-+	/* handle error in rsp_status */
-+	if (rsp_status != 0) {
-+		switch (rsp_status) {
-+			case TOUCH_STATUS_SENSOR_EXPECTED_RESET:
-+			case TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:
-+				ipts_dbg(ipts, "sensor reset %d\n", rsp_status);
-+				ipts_restart(ipts);
-+				break;
-+			default:
-+				ipts_dbg(ipts, "cmd : 0x%08x, status %d\n",
-+								cmd,
-+								rsp_status);
-+				break;
-+		}
-+	}
-+
-+	if (cmd_status) {
-+		ipts_restart(ipts);
-+	}
-+
-+	return ret;
-+}
-diff --git a/drivers/misc/ipts/ipts-msg-handler.h b/drivers/misc/ipts/ipts-msg-handler.h
-new file mode 100644
-index 000000000000..f37d9ad9af8c
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-msg-handler.h
-@@ -0,0 +1,33 @@
-+/*
-+ *
-+ * Intel Precise Touch & Stylus ME message handler
-+ * Copyright (c) 2016, 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.
-+ *
-+ */
-+
-+#ifndef _IPTS_MSG_HANDLER_H
-+#define _IPTS_MSG_HANDLER_H
-+
-+int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size);
-+int ipts_start(ipts_info_t *ipts);
-+void ipts_stop(ipts_info_t *ipts);
-+int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode);
-+int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg,
-+                     u32 msg_len);
-+int ipts_handle_processed_data(ipts_info_t *ipts);
-+int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id);
-+int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts);
-+int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts);
-+int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts);
-+int ipts_restart(ipts_info_t *ipts);
-+
-+#endif /* _IPTS_MSG_HANDLER_H */
-diff --git a/drivers/misc/ipts/ipts-params.c b/drivers/misc/ipts/ipts-params.c
-new file mode 100644
-index 000000000000..b4faa1afc046
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-params.c
-@@ -0,0 +1,21 @@
-+#include <linux/moduleparam.h>
-+
-+#include "ipts-params.h"
-+
-+struct ipts_params ipts_modparams = {
-+	.ignore_fw_fallback = false,
-+	.ignore_companion = false,
-+	.no_feedback = -1,
-+};
-+
-+module_param_named(ignore_fw_fallback, ipts_modparams.ignore_fw_fallback, bool, 0400);
-+MODULE_PARM_DESC(ignore_fw_fallback, "Don't use the IPTS firmware fallback path");
-+
-+module_param_named(ignore_companion, ipts_modparams.ignore_companion, bool, 0400);
-+MODULE_PARM_DESC(ignore_companion, "Don't use a companion driver to load firmware");
-+
-+module_param_named(no_feedback, ipts_modparams.no_feedback, int, 0644);
-+MODULE_PARM_DESC(no_feedback, "Disable sending feedback in order to work around the issue that IPTS "
-+	"stops working after some amount of use. "
-+	"-1=auto (true if your model is SB1/SP4, false if another model), "
-+	"0=false, 1=true, (default: -1)");
-diff --git a/drivers/misc/ipts/ipts-params.h b/drivers/misc/ipts/ipts-params.h
-new file mode 100644
-index 000000000000..6fd62fb46d26
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-params.h
-@@ -0,0 +1,14 @@
-+#ifndef _IPTS_PARAMS_H_
-+#define _IPTS_PARAMS_H_
-+
-+#include <linux/types.h>
-+
-+struct ipts_params {
-+	bool ignore_fw_fallback;
-+	bool ignore_companion;
-+	int no_feedback;
-+};
-+
-+extern struct ipts_params ipts_modparams;
-+
-+#endif // _IPTS_PARAMS_H_
-diff --git a/drivers/misc/ipts/ipts-resource.c b/drivers/misc/ipts/ipts-resource.c
-new file mode 100644
-index 000000000000..47607ef7c461
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-resource.c
-@@ -0,0 +1,277 @@
-+#include <linux/dma-mapping.h>
-+
-+#include "ipts.h"
-+#include "ipts-mei-msgs.h"
-+#include "ipts-kernel.h"
-+
-+static void free_common_resource(ipts_info_t *ipts)
-+{
-+	char *addr;
-+	ipts_buffer_info_t *feedback_buffer;
-+	dma_addr_t dma_addr;
-+	u32 buffer_size;
-+	int i, num_of_parallels;
-+
-+	if (ipts->resource.me2hid_buffer) {
-+		devm_kfree(&ipts->cldev->dev, ipts->resource.me2hid_buffer);
-+		ipts->resource.me2hid_buffer = 0;
-+	}
-+
-+	addr = ipts->resource.hid2me_buffer.addr;
-+	dma_addr = ipts->resource.hid2me_buffer.dma_addr;
-+	buffer_size = ipts->resource.hid2me_buffer_size;
-+
-+	if (ipts->resource.hid2me_buffer.addr) {
-+		dmam_free_coherent(&ipts->cldev->dev, buffer_size, addr, dma_addr);
-+		ipts->resource.hid2me_buffer.addr = 0;
-+		ipts->resource.hid2me_buffer.dma_addr = 0;
-+		ipts->resource.hid2me_buffer_size = 0;
-+	}
-+
-+	feedback_buffer = ipts->resource.feedback_buffer;
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	for (i = 0; i < num_of_parallels; i++) {
-+		if (feedback_buffer[i].addr) {
-+			dmam_free_coherent(&ipts->cldev->dev,
-+				ipts->device_info.feedback_size,
-+				feedback_buffer[i].addr,
-+				feedback_buffer[i].dma_addr);
-+			feedback_buffer[i].addr = 0;
-+			feedback_buffer[i].dma_addr = 0;
-+		}
-+	}
-+}
-+
-+static int allocate_common_resource(ipts_info_t *ipts)
-+{
-+	char *addr, *me2hid_addr;
-+	ipts_buffer_info_t *feedback_buffer;
-+	dma_addr_t dma_addr;
-+	int i, ret = 0, num_of_parallels;
-+	u32 buffer_size;
-+
-+	buffer_size = ipts->device_info.feedback_size;
-+
-+	addr = dmam_alloc_coherent(&ipts->cldev->dev,
-+			buffer_size,
-+			&dma_addr,
-+			GFP_ATOMIC|__GFP_ZERO);
-+	if (addr == NULL)
-+		return -ENOMEM;
-+
-+	me2hid_addr = devm_kzalloc(&ipts->cldev->dev, buffer_size, GFP_KERNEL);
-+	if (me2hid_addr == NULL) {
-+		ret = -ENOMEM;
-+		goto release_resource;
-+	}
-+
-+	ipts->resource.hid2me_buffer.addr = addr;
-+	ipts->resource.hid2me_buffer.dma_addr = dma_addr;
-+	ipts->resource.hid2me_buffer_size = buffer_size;
-+	ipts->resource.me2hid_buffer = me2hid_addr;
-+
-+	feedback_buffer = ipts->resource.feedback_buffer;
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	for (i = 0; i < num_of_parallels; i++) {
-+		feedback_buffer[i].addr = dmam_alloc_coherent(&ipts->cldev->dev,
-+				ipts->device_info.feedback_size,
-+				&feedback_buffer[i].dma_addr,
-+				GFP_ATOMIC|__GFP_ZERO);
-+
-+		if (feedback_buffer[i].addr == NULL) {
-+			ret = -ENOMEM;
-+			goto release_resource;
-+		}
-+	}
-+
-+	return 0;
-+
-+release_resource:
-+	free_common_resource(ipts);
-+
-+	return ret;
-+}
-+
-+void ipts_free_raw_data_resource(ipts_info_t *ipts)
-+{
-+	if (ipts_is_raw_data_resource_ready(ipts)) {
-+		ipts->resource.raw_data_resource_ready = false;
-+
-+		ipts_release_kernels(ipts);
-+	}
-+}
-+
-+static int allocate_hid_resource(ipts_info_t *ipts)
-+{
-+	ipts_buffer_info_t *buffer_hid;
-+
-+	/* hid mode uses only one touch data buffer */
-+	buffer_hid = &ipts->resource.touch_data_buffer_hid;
-+	buffer_hid->addr = dmam_alloc_coherent(&ipts->cldev->dev,
-+				ipts->device_info.frame_size,
-+				&buffer_hid->dma_addr,
-+				GFP_ATOMIC|__GFP_ZERO);
-+	if (buffer_hid->addr == NULL) {
-+		return -ENOMEM;
-+	}
-+
-+	return 0;
-+}
-+
-+static void free_hid_resource(ipts_info_t *ipts)
-+{
-+	ipts_buffer_info_t *buffer_hid;
-+
-+	buffer_hid = &ipts->resource.touch_data_buffer_hid;
-+	if (buffer_hid->addr) {
-+		dmam_free_coherent(&ipts->cldev->dev,
-+				ipts->device_info.frame_size,
-+				buffer_hid->addr,
-+				buffer_hid->dma_addr);
-+		buffer_hid->addr = 0;
-+		buffer_hid->dma_addr = 0;
-+	}
-+}
-+
-+int ipts_allocate_default_resource(ipts_info_t *ipts)
-+{
-+	int ret;
-+
-+	ret = allocate_common_resource(ipts);
-+	if (ret) {
-+		ipts_dbg(ipts, "cannot allocate common resource\n");
-+		return ret;
-+	}
-+
-+	ret = allocate_hid_resource(ipts);
-+	if (ret) {
-+		ipts_dbg(ipts, "cannot allocate hid resource\n");
-+		free_common_resource(ipts);
-+		return ret;
-+	}
-+
-+	ipts->resource.default_resource_ready = true;
-+
-+	return 0;
-+}
-+
-+void ipts_free_default_resource(ipts_info_t *ipts)
-+{
-+	if (ipts_is_default_resource_ready(ipts)) {
-+		ipts->resource.default_resource_ready = false;
-+
-+		free_hid_resource(ipts);
-+		free_common_resource(ipts);
-+	}
-+}
-+
-+int ipts_allocate_raw_data_resource(ipts_info_t *ipts)
-+{
-+	int ret = 0;
-+
-+	ret = ipts_init_kernels(ipts);
-+	if (ret) {
-+		return ret;
-+	}
-+
-+	ipts->resource.raw_data_resource_ready = true;
-+
-+	return 0;
-+}
-+
-+static void get_hid_only_smw_cmd_data(ipts_info_t *ipts,
-+				touch_sensor_set_mem_window_cmd_data_t *data,
-+				ipts_resource_t *resrc)
-+{
-+	ipts_buffer_info_t *touch_buf;
-+	ipts_buffer_info_t *feedback_buf;
-+
-+	touch_buf = &resrc->touch_data_buffer_hid;
-+	feedback_buf = &resrc->feedback_buffer[0];
-+
-+	data->touch_data_buffer_addr_lower[0] =
-+				lower_32_bits(touch_buf->dma_addr);
-+	data->touch_data_buffer_addr_upper[0] =
-+				upper_32_bits(touch_buf->dma_addr);
-+	data->feedback_buffer_addr_lower[0] =
-+				lower_32_bits(feedback_buf->dma_addr);
-+	data->feedback_buffer_addr_upper[0] =
-+				upper_32_bits(feedback_buf->dma_addr);
-+}
-+
-+static void get_raw_data_only_smw_cmd_data(ipts_info_t *ipts,
-+				touch_sensor_set_mem_window_cmd_data_t *data,
-+				ipts_resource_t *resrc)
-+{
-+	u64 wq_tail_phy_addr;
-+	u64 cookie_phy_addr;
-+	ipts_buffer_info_t *touch_buf;
-+	ipts_buffer_info_t *feedback_buf;
-+	int i, num_of_parallels;
-+
-+	touch_buf = resrc->touch_data_buffer_raw;
-+	feedback_buf = resrc->feedback_buffer;
-+
-+	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
-+	for (i = 0; i < num_of_parallels; i++) {
-+		data->touch_data_buffer_addr_lower[i] =
-+					lower_32_bits(touch_buf[i].dma_addr);
-+		data->touch_data_buffer_addr_upper[i] =
-+					upper_32_bits(touch_buf[i].dma_addr);
-+		data->feedback_buffer_addr_lower[i] =
-+					lower_32_bits(feedback_buf[i].dma_addr);
-+		data->feedback_buffer_addr_upper[i] =
-+					upper_32_bits(feedback_buf[i].dma_addr);
-+	}
-+
-+	wq_tail_phy_addr = resrc->wq_info.wq_tail_phy_addr;
-+	data->tail_offset_addr_lower = lower_32_bits(wq_tail_phy_addr);
-+	data->tail_offset_addr_upper = upper_32_bits(wq_tail_phy_addr);
-+
-+	cookie_phy_addr = resrc->wq_info.db_phy_addr +
-+						resrc->wq_info.db_cookie_offset;
-+	data->doorbell_cookie_addr_lower = lower_32_bits(cookie_phy_addr);
-+	data->doorbell_cookie_addr_upper = upper_32_bits(cookie_phy_addr);
-+	data->work_queue_size = resrc->wq_info.wq_size;
-+
-+	data->work_queue_item_size = resrc->wq_item_size;
-+}
-+
-+void ipts_get_set_mem_window_cmd_data(ipts_info_t *ipts,
-+				touch_sensor_set_mem_window_cmd_data_t *data)
-+{
-+	ipts_resource_t *resrc = &ipts->resource;
-+
-+	if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA)
-+		get_raw_data_only_smw_cmd_data(ipts, data, resrc);
-+	else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID)
-+		get_hid_only_smw_cmd_data(ipts, data, resrc);
-+
-+	/* hid2me is common for "raw data" and "hid" */
-+	data->hid2me_buffer_addr_lower =
-+				lower_32_bits(resrc->hid2me_buffer.dma_addr);
-+	data->hid2me_buffer_addr_upper =
-+				upper_32_bits(resrc->hid2me_buffer.dma_addr);
-+	data->hid2me_buffer_size = resrc->hid2me_buffer_size;
-+}
-+
-+void ipts_set_input_buffer(ipts_info_t *ipts, int parallel_idx,
-+						u8* cpu_addr, u64 dma_addr)
-+{
-+	ipts_buffer_info_t *touch_buf;
-+
-+	touch_buf = ipts->resource.touch_data_buffer_raw;
-+	touch_buf[parallel_idx].dma_addr = dma_addr;
-+	touch_buf[parallel_idx].addr = cpu_addr;
-+}
-+
-+void ipts_set_output_buffer(ipts_info_t *ipts, int parallel_idx, int output_idx,
-+						u8* cpu_addr, u64 dma_addr)
-+{
-+	ipts_buffer_info_t *output_buf;
-+
-+	output_buf = &ipts->resource.raw_data_mode_output_buffer[parallel_idx][output_idx];
-+
-+	output_buf->dma_addr = dma_addr;
-+	output_buf->addr = cpu_addr;
-+}
-diff --git a/drivers/misc/ipts/ipts-resource.h b/drivers/misc/ipts/ipts-resource.h
-new file mode 100644
-index 000000000000..7d66ac72b475
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-resource.h
-@@ -0,0 +1,30 @@
-+/*
-+ * Intel Precise Touch & Stylus state codes
-+ *
-+ * Copyright (c) 2016, 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.
-+ */
-+
-+#ifndef _IPTS_RESOURCE_H_
-+#define _IPTS_RESOURCE_H_
-+
-+int ipts_allocate_default_resource(ipts_info_t *ipts);
-+void ipts_free_default_resource(ipts_info_t *ipts);
-+int ipts_allocate_raw_data_resource(ipts_info_t *ipts);
-+void ipts_free_raw_data_resource(ipts_info_t *ipts);
-+void ipts_get_set_mem_window_cmd_data(ipts_info_t *ipts,
-+				touch_sensor_set_mem_window_cmd_data_t *data);
-+void ipts_set_input_buffer(ipts_info_t *ipts, int parallel_idx,
-+						u8* cpu_addr, u64 dma_addr);
-+void ipts_set_output_buffer(ipts_info_t *ipts, int parallel_idx, int output_idx,
-+						u8* cpu_addr, u64 dma_addr);
-+
-+#endif // _IPTS_RESOURCE_H_
-diff --git a/drivers/misc/ipts/ipts-sensor-regs.h b/drivers/misc/ipts/ipts-sensor-regs.h
-new file mode 100644
-index 000000000000..96812b0eb980
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-sensor-regs.h
-@@ -0,0 +1,700 @@
-+/*
-+ * Touch Sensor Register definition
-+ *
-+ * Copyright (c) 2013-2016, 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.
-+ */
-+
-+
-+#ifndef _TOUCH_SENSOR_REGS_H
-+#define _TOUCH_SENSOR_REGS_H
-+
-+#pragma pack(1)
-+
-+// define C_ASSERT macro to check structure size and fail compile for unexpected mismatch
-+#ifndef C_ASSERT
-+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
-+#endif
-+
-+//
-+// Compatibility versions for this header file
-+//
-+#define TOUCH_EDS_REV_MINOR     0
-+#define TOUCH_EDS_REV_MAJOR     1
-+#define TOUCH_EDS_INTF_REV      1
-+#define TOUCH_PROTOCOL_VER      0
-+
-+
-+//
-+// Offset 00h: TOUCH_STS: Status Register
-+// This register is read by the SPI Controller immediately following an interrupt.
-+//
-+#define TOUCH_STS_REG_OFFSET                0x00
-+
-+typedef enum touch_sts_reg_int_type
-+{
-+    TOUCH_STS_REG_INT_TYPE_DATA_AVAIL = 0,  // Touch Data Available
-+    TOUCH_STS_REG_INT_TYPE_RESET_OCCURRED,  // Reset Occurred
-+    TOUCH_STS_REG_INT_TYPE_ERROR_OCCURRED,  // Error Occurred
-+    TOUCH_STS_REG_INT_TYPE_VENDOR_DATA,     // Vendor specific data, treated same as raw frame
-+    TOUCH_STS_REG_INT_TYPE_GET_FEATURES,    // Get Features response data available
-+    TOUCH_STS_REG_INT_TYPE_MAX
-+} touch_sts_reg_int_type_t;
-+C_ASSERT(sizeof(touch_sts_reg_int_type_t) == 4);
-+
-+typedef enum touch_sts_reg_pwr_state
-+{
-+    TOUCH_STS_REG_PWR_STATE_SLEEP = 0,  // Sleep
-+    TOUCH_STS_REG_PWR_STATE_DOZE,       // Doze
-+    TOUCH_STS_REG_PWR_STATE_ARMED,      // Armed
-+    TOUCH_STS_REG_PWR_STATE_SENSING,    // Sensing
-+    TOUCH_STS_REG_PWR_STATE_MAX
-+} touch_sts_reg_pwr_state_t;
-+C_ASSERT(sizeof(touch_sts_reg_pwr_state_t) == 4);
-+
-+typedef enum touch_sts_reg_init_state
-+{
-+    TOUCH_STS_REG_INIT_STATE_READY_FOR_OP = 0,  // Ready for normal operation
-+    TOUCH_STS_REG_INIT_STATE_FW_NEEDED,         // Touch IC needs its Firmware loaded
-+    TOUCH_STS_REG_INIT_STATE_DATA_NEEDED,       // Touch IC needs its Data loaded
-+    TOUCH_STS_REG_INIT_STATE_INIT_ERROR,        // Error info in TOUCH_ERR_REG
-+    TOUCH_STS_REG_INIT_STATE_MAX
-+} touch_sts_reg_init_state_t;
-+C_ASSERT(sizeof(touch_sts_reg_init_state_t) == 4);
-+
-+#define TOUCH_SYNC_BYTE_VALUE   0x5A
-+
-+typedef union touch_sts_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // When set, this indicates the hardware has data that needs to be read.
-+        u32  int_status           :1;
-+        // see TOUCH_STS_REG_INT_TYPE
-+        u32  int_type             :4;
-+        // see TOUCH_STS_REG_PWR_STATE
-+        u32  pwr_state            :2;
-+        // see TOUCH_STS_REG_INIT_STATE
-+        u32  init_state           :2;
-+        // Busy bit indicates that sensor cannot accept writes at this time
-+        u32  busy                :1;
-+        // Reserved
-+        u32  reserved            :14;
-+        // Synchronization bit, should always be TOUCH_SYNC_BYTE_VALUE
-+        u32  sync_byte            :8;
-+    } fields;
-+} touch_sts_reg_t;
-+C_ASSERT(sizeof(touch_sts_reg_t) == 4);
-+
-+
-+//
-+// Offset 04h: TOUCH_FRAME_CHAR: Frame Characteristics Register
-+// This registers describes the characteristics of each data frame read by the SPI Controller in
-+// response to a touch interrupt.
-+//
-+#define TOUCH_FRAME_CHAR_REG_OFFSET         0x04
-+
-+typedef union touch_frame_char_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Micro-Frame Size (MFS):  Indicates the size of a touch micro-frame in byte increments.
-+        // When a micro-frame is to be read for processing (in data mode), this is the total number of
-+        // bytes that must be read per interrupt, split into multiple read commands no longer than RPS.
-+        // Maximum micro-frame size is 256KB.
-+        u32  microframe_size      :18;
-+        // Micro-Frames per Frame (MFPF): Indicates the number of micro-frames per frame. If a
-+        // sensor's frame does not contain micro-frames this value will be 1. Valid values are 1-31.
-+        u32  microframes_per_frame :5;
-+        // Micro-Frame Index (MFI): Indicates the index of the micro-frame within a frame. This allows
-+        // the SPI Controller to maintain synchronization with the sensor and determine when the final
-+        // micro-frame has arrived. Valid values are 1-31.
-+        u32  microframe_index     :5;
-+        // HID/Raw Data: This bit describes whether the data from the sensor is Raw data or a HID
-+        // report. When set, the data is a HID report.
-+        u32  hid_report           :1;
-+        // Reserved
-+        u32  reserved            :3;
-+    } fields;
-+} touch_frame_char_reg_t;
-+C_ASSERT(sizeof(touch_frame_char_reg_t) == 4);
-+
-+
-+//
-+// Offset 08h: Touch Error Register
-+//
-+#define TOUCH_ERR_REG_OFFSET                0x08
-+
-+// bit definition is vendor specific
-+typedef union touch_err_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        u32  invalid_fw           :1;
-+        u32  invalid_data        :1;
-+        u32  self_test_failed       :1;
-+        u32  reserved            :12;
-+        u32  fatal_error          :1;
-+        u32  vendor_errors        :16;
-+    } fields;
-+} touch_err_reg_t;
-+C_ASSERT(sizeof(touch_err_reg_t) == 4);
-+
-+
-+//
-+// Offset 0Ch: RESERVED
-+// This register is reserved for future use.
-+//
-+
-+
-+//
-+// Offset 10h: Touch Identification Register
-+//
-+#define TOUCH_ID_REG_OFFSET                 0x10
-+
-+#define TOUCH_ID_REG_VALUE                  0x43495424
-+
-+// expected value is "$TIC" or 0x43495424
-+typedef u32  touch_id_reg_t;
-+C_ASSERT(sizeof(touch_id_reg_t) == 4);
-+
-+
-+//
-+// Offset 14h: TOUCH_DATA_SZ: Touch Data Size Register
-+// This register describes the maximum size of frames and feedback data
-+//
-+#define TOUCH_DATA_SZ_REG_OFFSET            0x14
-+
-+#define TOUCH_MAX_FRAME_SIZE_INCREMENT      64
-+#define TOUCH_MAX_FEEDBACK_SIZE_INCREMENT   64
-+
-+#define TOUCH_SENSOR_MAX_FRAME_SIZE         (32 * 1024)     // Max allowed frame size 32KB
-+#define TOUCH_SENSOR_MAX_FEEDBACK_SIZE      (16 * 1024)     // Max allowed feedback size 16KB
-+
-+typedef union touch_data_sz_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // This value describes the maximum frame size in 64byte increments.
-+        u32  max_frame_size        :12;
-+        // This value describes the maximum feedback size in 64byte increments.
-+        u32  max_feedback_size     :8;
-+        // Reserved
-+        u32  reserved            :12;
-+    } fields;
-+} touch_data_sz_reg_t;
-+C_ASSERT(sizeof(touch_data_sz_reg_t) == 4);
-+
-+
-+//
-+// Offset 18h: TOUCH_CAPABILITIES: Touch Capabilities Register
-+// This register informs the host as to the capabilities of the touch IC.
-+//
-+#define TOUCH_CAPS_REG_OFFSET               0x18
-+
-+typedef enum touch_caps_reg_read_delay_time
-+{
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_0,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_10uS,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_50uS,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_100uS,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_150uS,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_250uS,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_500uS,
-+    TOUCH_CAPS_REG_READ_DELAY_TIME_1mS,
-+} touch_caps_reg_read_delay_time_t;
-+C_ASSERT(sizeof(touch_caps_reg_read_delay_time_t) == 4);
-+
-+#define TOUCH_BULK_DATA_MAX_WRITE_INCREMENT 64
-+
-+typedef union touch_caps_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Reserved for future frequency
-+        u32  reserved0           :1;
-+        // 17 MHz (14 MHz on Atom) Supported: 0b - Not supported, 1b - Supported
-+        u32  supported_17Mhz      :1;
-+        // 30 MHz (25MHz on Atom) Supported: 0b - Not supported, 1b - Supported
-+        u32  supported_30Mhz      :1;
-+        // 50 MHz Supported: 0b - Not supported, 1b - Supported
-+        u32  supported_50Mhz      :1;
-+        // Reserved
-+        u32  reserved1           :4;
-+        // Single I/O Supported: 0b - Not supported, 1b - Supported
-+        u32  supported_single_io   :1;
-+        // Dual I/O Supported: 0b - Not supported, 1b - Supported
-+        u32  supported_dual_io     :1;
-+        // Quad I/O Supported: 0b - Not supported, 1b - Supported
-+        u32  supported_quad_io     :1;
-+        // Bulk Data Area Max Write Size: The amount of data the SPI Controller can write to the bulk
-+        // data area before it has to poll the busy bit. This field is in multiples of 64 bytes. The
-+        // SPI Controller will write the amount of data specified in this field, then check and wait
-+        // for the Status.Busy bit to be zero before writing the next data chunk. This field is 6 bits
-+        // long, allowing for 4KB of contiguous writes w/o a poll of the busy bit. If this field is
-+        // 0x00 the Touch IC has no limit in the amount of data the SPI Controller can write to the
-+        // bulk data area.
-+        u32  bulk_data_max_write    :6;
-+        // Read Delay Timer Value: This field describes the delay the SPI Controller will initiate when
-+        // a read interrupt follows a write data command. Uses values from TOUCH_CAPS_REG_READ_DELAY_TIME
-+        u32  read_delay_timer_value :3;
-+        // Reserved
-+        u32  reserved2           :4;
-+        // Maximum Touch Points: A byte value based on the HID descriptor definition.
-+        u32  max_touch_points      :8;
-+    } fields;
-+} touch_caps_reg_t;
-+C_ASSERT(sizeof(touch_caps_reg_t) == 4);
-+
-+
-+//
-+// Offset 1Ch: TOUCH_CFG: Touch Configuration Register
-+// This register allows the SPI Controller to configure the touch sensor as needed during touch
-+// operations.
-+//
-+#define TOUCH_CFG_REG_OFFSET                0x1C
-+
-+typedef enum touch_cfg_reg_bulk_xfer_size
-+{
-+    TOUCH_CFG_REG_BULK_XFER_SIZE_4B  = 0,   // Bulk Data Transfer Size is 4 bytes
-+    TOUCH_CFG_REG_BULK_XFER_SIZE_8B,        // Bulk Data Transfer Size is 8 bytes
-+    TOUCH_CFG_REG_BULK_XFER_SIZE_16B,       // Bulk Data Transfer Size is 16 bytes
-+    TOUCH_CFG_REG_BULK_XFER_SIZE_32B,       // Bulk Data Transfer Size is 32 bytes
-+    TOUCH_CFG_REG_BULK_XFER_SIZE_64B,       // Bulk Data Transfer Size is 64 bytes
-+    TOUCH_CFG_REG_BULK_XFER_SIZE_MAX
-+} touch_cfg_reg_bulk_xfer_size_t;
-+C_ASSERT(sizeof(touch_cfg_reg_bulk_xfer_size_t) == 4);
-+
-+// Frequency values used by TOUCH_CFG_REG and TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
-+typedef enum touch_freq
-+{
-+    TOUCH_FREQ_RSVD = 0,    // Reserved value
-+    TOUCH_FREQ_17MHZ,       // Sensor set for 17MHz operation (14MHz on Atom)
-+    TOUCH_FREQ_30MHZ,       // Sensor set for 30MHz operation (25MHz on Atom)
-+    TOUCH_FREQ_MAX          // Invalid value
-+} touch_freq_t;
-+C_ASSERT(sizeof(touch_freq_t) == 4);
-+
-+typedef union touch_cfg_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Touch Enable (TE):  This bit is used as a HW semaphore for the Touch IC to guarantee to the
-+        // SPI Controller to that (when 0) no sensing operations will occur and only the Reset
-+        // interrupt will be generated. When TE is cleared by the SPI Controller:
-+        //  - TICs must flush all output buffers
-+        //  - TICs must De-assert any pending interrupt
-+        //  - ME must throw away any partial frame and pending interrupt must be cleared/not serviced.
-+        // The SPI Controller will only modify the configuration of the TIC when TE is cleared. TE is
-+        // defaulted to 0h on a power-on reset.
-+        u32  touch_enable         :1;
-+        // Data/HID Packet Mode (DHPM): Raw Data Mode: 0h, HID Packet Mode: 1h
-+        u32  dhpm                :1;
-+        // Bulk Data Transfer Size: This field represents the amount of data written to the Bulk Data
-+        // Area (SPI Offset 0x1000-0x2FFF) in a single SPI write protocol
-+        u32  bulk_xfer_size        :4;
-+        // Frequency Select: Frequency for the TouchIC to run at. Use values from TOUCH_FREQ
-+        u32  freq_select          :3;
-+        // Reserved
-+        u32  reserved            :23;
-+    } fields;
-+} touch_cfg_reg_t;
-+C_ASSERT(sizeof(touch_cfg_reg_t) == 4);
-+
-+
-+//
-+// Offset 20h: TOUCH_CMD: Touch Command Register
-+// This register is used for sending commands to the Touch IC.
-+//
-+#define TOUCH_CMD_REG_OFFSET                0x20
-+
-+typedef enum touch_cmd_reg_code
-+{
-+    TOUCH_CMD_REG_CODE_NOP = 0,             // No Operation
-+    TOUCH_CMD_REG_CODE_SOFT_RESET,          // Soft Reset
-+    TOUCH_CMD_REG_CODE_PREP_4_READ,         // Prepare All Registers for Read
-+    TOUCH_CMD_REG_CODE_GEN_TEST_PACKETS,    // Generate Test Packets according to value in TOUCH_TEST_CTRL_REG
-+    TOUCH_CMD_REG_CODE_MAX
-+} touch_cmd_reg_code_t;
-+C_ASSERT(sizeof(touch_cmd_reg_code_t) == 4);
-+
-+typedef union touch_cmd_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Command Code: See TOUCH_CMD_REG_CODE
-+        u32  command_code :8;
-+        // Reserved
-+        u32  reserved    :24;
-+    } fields;
-+} touch_cmd_reg_t;
-+C_ASSERT(sizeof(touch_cmd_reg_t) == 4);
-+
-+
-+//
-+// Offset 24h: Power Management Control
-+// This register is used for active power management. The Touch IC is allowed to mover from Doze or
-+// Armed to Sensing after a touch has occurred. All other transitions will be made at the request
-+// of the SPI Controller.
-+//
-+#define TOUCH_PWR_MGMT_CTRL_REG_OFFSET      0x24
-+
-+typedef enum touch_pwr_mgmt_ctrl_reg_cmd
-+{
-+    TOUCH_PWR_MGMT_CTRL_REG_CMD_NOP = 0,    // No change to power state
-+    TOUCH_PWR_MGMT_CTRL_REG_CMD_SLEEP,      // Sleep   - set when the system goes into connected standby
-+    TOUCH_PWR_MGMT_CTRL_REG_CMD_DOZE,       // Doze    - set after 300 seconds of inactivity
-+    TOUCH_PWR_MGMT_CTRL_REG_CMD_ARMED,      // Armed   - Set by FW when a "finger off" message is received from the EUs
-+    TOUCH_PWR_MGMT_CTRL_REG_CMD_SENSING,    // Sensing - not typically set by FW
-+    TOUCH_PWR_MGMT_CTRL_REG_CMD_MAX         // Values will result in no change to the power state of the Touch IC
-+} touch_pwr_mgmt_ctrl_reg_cmd_t;
-+C_ASSERT(sizeof(touch_pwr_mgmt_ctrl_reg_cmd_t) == 4);
-+
-+typedef union touch_pwr_mgmt_ctrl_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Power State Command: See TOUCH_PWR_MGMT_CTRL_REG_CMD
-+        u32  pwr_state_cmd         :3;
-+        // Reserved
-+        u32  reserved            :29;
-+    } fields;
-+} touch_pwr_mgmt_ctrl_reg_t;
-+C_ASSERT(sizeof(touch_pwr_mgmt_ctrl_reg_t) == 4);
-+
-+
-+//
-+// Offset 28h: Vendor HW Information Register
-+// This register is used to relay Intel-assigned vendor ID information to the SPI Controller, which
-+// may be forwarded to SW running on the host CPU.
-+//
-+#define TOUCH_VEN_HW_INFO_REG_OFFSET        0x28
-+
-+typedef union touch_ven_hw_info_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Touch Sensor Vendor ID
-+        u32  vendor_id            :16;
-+        // Touch Sensor Device ID
-+        u32  device_id            :16;
-+    } fields;
-+} touch_ven_hw_info_reg_t;
-+C_ASSERT(sizeof(touch_ven_hw_info_reg_t) == 4);
-+
-+
-+//
-+// Offset 2Ch: HW Revision ID Register
-+// This register is used to relay vendor HW revision information to the SPI Controller which may be
-+// forwarded to SW running on the host CPU.
-+//
-+#define TOUCH_HW_REV_REG_OFFSET             0x2C
-+
-+typedef u32  touch_hw_rev_reg_t;   // bit definition is vendor specific
-+C_ASSERT(sizeof(touch_hw_rev_reg_t) == 4);
-+
-+
-+//
-+// Offset 30h: FW Revision ID Register
-+// This register is used to relay vendor FW revision information to the SPI Controller which may be
-+// forwarded to SW running on the host CPU.
-+//
-+#define TOUCH_FW_REV_REG_OFFSET             0x30
-+
-+typedef u32  touch_fw_rev_reg_t;    // bit definition is vendor specific
-+C_ASSERT(sizeof(touch_fw_rev_reg_t) == 4);
-+
-+
-+//
-+// Offset 34h: Compatibility Revision ID Register
-+// This register is used to relay vendor compatibility information to the SPI Controller which may
-+// be forwarded to SW running on the host CPU. Compatibility Information is a numeric value given
-+// by Intel to the Touch IC vendor based on the major and minor revision of the EDS supported. From
-+// a nomenclature point of view in an x.y revision number of the EDS, the major version is the value
-+// of x and the minor version is the value of y. For example, a Touch IC supporting an EDS version
-+// of 0.61 would contain a major version of 0 and a minor version of 61 in the register.
-+//
-+#define TOUCH_COMPAT_REV_REG_OFFSET             0x34
-+
-+typedef union touch_compat_rev_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // EDS Minor Revision
-+        u8   minor;
-+        // EDS Major Revision
-+        u8   major;
-+        // Interface Revision Number (from EDS)
-+        u8   intf_rev;
-+        // EU Kernel Compatibility Version - vendor specific value
-+        u8   kernel_compat_ver;
-+    } fields;
-+} touch_compat_rev_reg_t;
-+C_ASSERT(sizeof(touch_compat_rev_reg_t) == 4);
-+
-+
-+//
-+// Touch Register Block is the full set of registers from offset 0x00h to 0x3F
-+// This is the entire set of registers needed for normal touch operation. It does not include test
-+// registers such as TOUCH_TEST_CTRL_REG
-+//
-+#define TOUCH_REG_BLOCK_OFFSET              TOUCH_STS_REG_OFFSET
-+
-+typedef struct touch_reg_block
-+{
-+    touch_sts_reg_t         sts_reg;         // 0x00
-+    touch_frame_char_reg_t  frame_char_reg;   // 0x04
-+    touch_err_reg_t         error_reg;       // 0x08
-+    u32                  reserved0;      // 0x0C
-+    touch_id_reg_t          id_reg;          // 0x10
-+    touch_data_sz_reg_t     data_size_reg;    // 0x14
-+    touch_caps_reg_t        caps_reg;        // 0x18
-+    touch_cfg_reg_t         cfg_reg;         // 0x1C
-+    touch_cmd_reg_t         cmd_reg;         // 0x20
-+    touch_pwr_mgmt_ctrl_reg_t  pwm_mgme_ctrl_reg; // 0x24
-+    touch_ven_hw_info_reg_t ven_hw_info_reg;   // 0x28
-+    touch_hw_rev_reg_t      hw_rev_reg;       // 0x2C
-+    touch_fw_rev_reg_t      fw_rev_reg;       // 0x30
-+    touch_compat_rev_reg_t  compat_rev_reg;   // 0x34
-+    u32                  reserved1;      // 0x38
-+    u32                  reserved2;      // 0x3C
-+} touch_reg_block_t;
-+C_ASSERT(sizeof(touch_reg_block_t) == 64);
-+
-+
-+//
-+// Offset 40h: Test Control Register
-+// This register
-+//
-+#define TOUCH_TEST_CTRL_REG_OFFSET              0x40
-+
-+typedef union touch_test_ctrl_reg
-+{
-+    u32  reg_value;
-+
-+    struct
-+    {
-+        // Size of Test Frame in Raw Data Mode: This field specifies the test frame size in raw data
-+        // mode in multiple of 64 bytes. For example, if this field value is 16, the test frame size
-+        // will be 16x64 = 1K.
-+        u32  raw_test_frame_size    :16;
-+        // Number of Raw Data Frames or HID Report Packets Generation. This field represents the number
-+        // of test frames or HID reports to be generated when test mode is enabled. When multiple
-+        // packets/frames are generated, they need be generated at 100 Hz frequency, i.e. 10ms per
-+        // packet/frame.
-+        u32  num_test_frames       :16;
-+    } fields;
-+} touch_test_ctrl_reg_t;
-+C_ASSERT(sizeof(touch_test_ctrl_reg_t) == 4);
-+
-+
-+//
-+// Offsets 0x000 to 0xFFF are reserved for Intel-defined Registers
-+//
-+#define TOUCH_REGISTER_LIMIT                0xFFF
-+
-+
-+//
-+// Data Window: Address 0x1000-0x1FFFF
-+// The data window is reserved for writing and reading large quantities of data to and from the
-+// sensor.
-+//
-+#define TOUCH_DATA_WINDOW_OFFSET            0x1000
-+#define TOUCH_DATA_WINDOW_LIMIT             0x1FFFF
-+
-+#define TOUCH_SENSOR_MAX_OFFSET             TOUCH_DATA_WINDOW_LIMIT
-+
-+
-+//
-+// The following data structures represent the headers defined in the Data Structures chapter of the
-+// Intel Integrated Touch EDS
-+//
-+
-+// Enumeration used in TOUCH_RAW_DATA_HDR
-+typedef enum touch_raw_data_types
-+{
-+    TOUCH_RAW_DATA_TYPE_FRAME = 0,
-+    TOUCH_RAW_DATA_TYPE_ERROR,          // RawData will be the TOUCH_ERROR struct below
-+    TOUCH_RAW_DATA_TYPE_VENDOR_DATA,    // Set when InterruptType is Vendor Data
-+    TOUCH_RAW_DATA_TYPE_HID_REPORT,
-+    TOUCH_RAW_DATA_TYPE_GET_FEATURES,
-+    TOUCH_RAW_DATA_TYPE_MAX
-+} touch_raw_data_types_t;
-+C_ASSERT(sizeof(touch_raw_data_types_t) == 4);
-+
-+// Private data structure. Kernels must copy to HID driver buffer
-+typedef struct touch_hid_private_data
-+{
-+    u32  transaction_id;
-+    u8   reserved[28];
-+} touch_hid_private_data_t;
-+C_ASSERT(sizeof(touch_hid_private_data_t) == 32);
-+
-+// This is the data structure sent from the PCH FW to the EU kernel
-+typedef struct touch_raw_data_hdr
-+{
-+    u32                  data_type;           // use values from TOUCH_RAW_DATA_TYPES
-+    u32                  raw_data_size_bytes;   // The size in bytes of the raw data read from the
-+                                                // sensor, does not include TOUCH_RAW_DATA_HDR. Will
-+                                                // be the sum of all uFrames, or size of TOUCH_ERROR
-+                                                // for if DataType is TOUCH_RAW_DATA_TYPE_ERROR
-+    u32                  buffer_id;           // An ID to qualify with the feedback data to track
-+                                                // buffer usage
-+    u32                  protocol_ver;        // Must match protocol version of the EDS
-+    u8                   kernel_compat_id;     // Copied from the Compatibility Revision ID Reg
-+    u8                   reserved[15];       // Padding to extend header to full 64 bytes and
-+                                                // allow for growth
-+    touch_hid_private_data_t  hid_private_data;     // Private data structure. Kernels must copy to HID
-+                                                // driver buffer
-+} touch_raw_data_hdr_t;
-+C_ASSERT(sizeof(touch_raw_data_hdr_t) == 64);
-+
-+typedef struct touch_raw_data
-+{
-+    touch_raw_data_hdr_t  header;
-+    u8               raw_data[1]; // used to access the raw data as an array and keep the
-+                                    // compilers happy. Actual size of this array is
-+                                    // Header.RawDataSizeBytes
-+} touch_raw_data_t;
-+
-+
-+// The following section describes the data passed in TOUCH_RAW_DATA.RawData when DataType equals
-+// TOUCH_RAW_DATA_TYPE_ERROR
-+// Note: This data structure is also applied to HID mode
-+typedef enum touch_err_types
-+{
-+    TOUCH_RAW_DATA_ERROR = 0,
-+    TOUCH_RAW_ERROR_MAX
-+} touch_err_types_t;
-+C_ASSERT(sizeof(touch_err_types_t) == 4);
-+
-+typedef union touch_me_fw_error
-+{
-+    u32  value;
-+
-+    struct
-+    {
-+        u32 invalid_frame_characteristics : 1;
-+        u32 microframe_index_invalid      : 1;
-+        u32 reserved                    : 30;
-+    } fields;
-+} touch_me_fw_error_t;
-+C_ASSERT(sizeof(touch_me_fw_error_t) == 4);
-+
-+typedef struct touch_error
-+{
-+    u8			touch_error_type; // This must be a value from TOUCH_ERROR_TYPES
-+    u8			reserved[3];
-+    touch_me_fw_error_t	touch_me_fw_error;
-+    touch_err_reg_t	touch_error_register; // Contains the value copied from the Touch Error Reg
-+} touch_error_t;
-+C_ASSERT(sizeof(touch_error_t) == 12);
-+
-+// Enumeration used in TOUCH_FEEDBACK_BUFFER
-+typedef enum touch_feedback_cmd_types
-+{
-+    TOUCH_FEEDBACK_CMD_TYPE_NONE = 0,
-+    TOUCH_FEEDBACK_CMD_TYPE_SOFT_RESET,
-+    TOUCH_FEEDBACK_CMD_TYPE_GOTO_ARMED,
-+    TOUCH_FEEDBACK_CMD_TYPE_GOTO_SENSING,
-+    TOUCH_FEEDBACK_CMD_TYPE_GOTO_SLEEP,
-+    TOUCH_FEEDBACK_CMD_TYPE_GOTO_DOZE,
-+    TOUCH_FEEDBACK_CMD_TYPE_HARD_RESET,
-+    TOUCH_FEEDBACK_CMD_TYPE_MAX
-+} touch_feedback_cmd_types_t;
-+C_ASSERT(sizeof(touch_feedback_cmd_types_t) == 4);
-+
-+// Enumeration used in TOUCH_FEEDBACK_HDR
-+typedef enum touch_feedback_data_types
-+{
-+    TOUCH_FEEDBACK_DATA_TYPE_FEEDBACK = 0,  // This is vendor specific feedback to be written to the sensor
-+    TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES,  // This is a set features command to be written to the sensor
-+    TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES,  // This is a get features command to be written to the sensor
-+    TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT, // This is a HID output report to be written to the sensor
-+    TOUCH_FEEDBACK_DATA_TYPE_STORE_DATA,    // This is calibration data to be written to system flash
-+    TOUCH_FEEDBACK_DATA_TYPE_MAX
-+} touch_feedback_data_types_t;
-+C_ASSERT(sizeof(touch_feedback_data_types_t) == 4);
-+
-+// This is the data structure sent from the EU kernels back to the ME FW.
-+// In addition to "feedback" data, the FW can execute a "command" described by the command type parameter.
-+// Any payload data will always be sent to the TIC first, then any command will be issued.
-+typedef struct touch_feedback_hdr
-+{
-+    u32  feedback_cmd_type;    // use values from TOUCH_FEEDBACK_CMD_TYPES
-+    u32  payload_size_bytes;   // The amount of data to be written to the sensor, not including the header
-+    u32  buffer_id;           // The ID of the raw data buffer that generated this feedback data
-+    u32  protocol_ver;        // Must match protocol version of the EDS
-+    u32  feedback_data_type;   // use values from TOUCH_FEEDBACK_DATA_TYPES. This is not relevant if PayloadSizeBytes is 0
-+    u32  spi_offest;          // The offset from TOUCH_DATA_WINDOW_OFFSET at which to write the Payload data. Maximum offset is 0x1EFFF.
-+    u8   reserved[40];       // Padding to extend header to full 64 bytes and allow for growth
-+} touch_feedback_hdr_t;
-+C_ASSERT(sizeof(touch_feedback_hdr_t) == 64);
-+
-+typedef struct touch_feedback_buffer
-+{
-+    touch_feedback_hdr_t  Header;
-+    u8               feedback_data[1];    // used to access the feedback data as an array and keep the compilers happy. Actual size of this array is Header.PayloadSizeBytes
-+} touch_feedback_buffer_t;
-+
-+
-+//
-+// This data structure describes the header prepended to all data
-+// written to the touch IC at the bulk data write (TOUCH_DATA_WINDOW_OFFSET + TOUCH_FEEDBACK_HDR.SpiOffest) address.
-+typedef enum touch_write_data_type
-+{
-+    TOUCH_WRITE_DATA_TYPE_FW_LOAD = 0,
-+    TOUCH_WRITE_DATA_TYPE_DATA_LOAD,
-+    TOUCH_WRITE_DATA_TYPE_FEEDBACK,
-+    TOUCH_WRITE_DATA_TYPE_SET_FEATURES,
-+    TOUCH_WRITE_DATA_TYPE_GET_FEATURES,
-+    TOUCH_WRITE_DATA_TYPE_OUTPUT_REPORT,
-+    TOUCH_WRITE_DATA_TYPE_NO_DATA_USE_DEFAULTS,
-+    TOUCH_WRITE_DATA_TYPE_MAX
-+} touch_write_data_type_t;
-+C_ASSERT(sizeof(touch_write_data_type_t) == 4);
-+
-+typedef struct touch_write_hdr
-+{
-+    u32  write_data_type;   // Use values from TOUCH_WRITE_DATA_TYPE
-+    u32  write_data_len;    // This field designates the amount of data to follow
-+} touch_write_hdr_t;
-+C_ASSERT(sizeof(touch_write_hdr_t) == 8);
-+
-+typedef struct touch_write_data
-+{
-+    touch_write_hdr_t header;
-+    u8           write_data[1];   // used to access the write data as an array and keep the compilers happy. Actual size of this array is Header.WriteDataLen
-+} touch_write_data_t;
-+
-+#pragma pack()
-+
-+#endif // _TOUCH_SENSOR_REGS_H
-diff --git a/drivers/misc/ipts/ipts-state.h b/drivers/misc/ipts/ipts-state.h
-new file mode 100644
-index 000000000000..39a2eaf5f004
---- /dev/null
-+++ b/drivers/misc/ipts/ipts-state.h
-@@ -0,0 +1,29 @@
-+/*
-+ * Intel Precise Touch & Stylus state codes
-+ *
-+ * Copyright (c) 2016, 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.
-+ */
-+
-+#ifndef _IPTS_STATE_H_
-+#define _IPTS_STATE_H_
-+
-+/* ipts driver states */
-+typedef enum ipts_state {
-+	IPTS_STA_NONE,
-+	IPTS_STA_INIT,
-+	IPTS_STA_RESOURCE_READY,
-+	IPTS_STA_HID_STARTED,
-+	IPTS_STA_RAW_DATA_STARTED,
-+	IPTS_STA_STOPPING
-+} ipts_state_t;
-+
-+#endif // _IPTS_STATE_H_
-diff --git a/drivers/misc/ipts/ipts.h b/drivers/misc/ipts/ipts.h
-new file mode 100644
-index 000000000000..9c34b55ff036
---- /dev/null
-+++ b/drivers/misc/ipts/ipts.h
-@@ -0,0 +1,200 @@
-+/*
-+ *
-+ * Intel Management Engine Interface (Intel MEI) Client Driver for IPTS
-+ * Copyright (c) 2016, 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.
-+ *
-+ */
-+
-+#ifndef _IPTS_H_
-+#define _IPTS_H_
-+
-+#include <linux/types.h>
-+#include <linux/mei_cl_bus.h>
-+#include <linux/hid.h>
-+#include <linux/intel_ipts_if.h>
-+
-+#include "ipts-mei-msgs.h"
-+#include "ipts-state.h"
-+#include "ipts-binary-spec.h"
-+
-+#define ENABLE_IPTS_DEBUG		/* enable IPTS debug */
-+
-+#ifdef ENABLE_IPTS_DEBUG
-+
-+#define ipts_info(ipts, format, arg...) do {\
-+	dev_info(&ipts->cldev->dev, format, ##arg);\
-+} while (0)
-+
-+#define ipts_dbg(ipts, format, arg...) do {\
-+	dev_info(&ipts->cldev->dev, format, ##arg);\
-+} while (0)
-+
-+//#define RUN_DBG_THREAD
-+
-+#else
-+
-+#define ipts_info(ipts, format, arg...) do {} while(0);
-+#define ipts_dbg(ipts, format, arg...) do {} while(0);
-+
-+#endif
-+
-+#define ipts_err(ipts, format, arg...) do {\
-+	dev_err(&ipts->cldev->dev, format, ##arg);\
-+} while (0)
-+
-+#define HID_PARALLEL_DATA_BUFFERS	TOUCH_SENSOR_MAX_DATA_BUFFERS
-+
-+#define IPTS_MAX_RETRY			3
-+
-+typedef struct ipts_buffer_info {
-+	char *addr;
-+	dma_addr_t dma_addr;
-+} ipts_buffer_info_t;
-+
-+typedef struct ipts_gfx_info {
-+	u64     gfx_handle;
-+	intel_ipts_ops_t ipts_ops;
-+} ipts_gfx_info_t;
-+
-+typedef struct ipts_resource {
-+	/* ME & Gfx resource */
-+	ipts_buffer_info_t touch_data_buffer_raw[HID_PARALLEL_DATA_BUFFERS];
-+	ipts_buffer_info_t touch_data_buffer_hid;
-+
-+	ipts_buffer_info_t feedback_buffer[HID_PARALLEL_DATA_BUFFERS];
-+
-+	ipts_buffer_info_t hid2me_buffer;
-+	u32 hid2me_buffer_size;
-+
-+	u8 wq_item_size;
-+	intel_ipts_wq_info_t wq_info;
-+
-+	/* ME2HID buffer */
-+	char *me2hid_buffer;
-+
-+	/* Gfx specific resource */
-+	ipts_buffer_info_t raw_data_mode_output_buffer
-+	    [HID_PARALLEL_DATA_BUFFERS][MAX_NUM_OUTPUT_BUFFERS];
-+
-+	int num_of_outputs;
-+
-+	bool default_resource_ready;
-+	bool raw_data_resource_ready;
-+} ipts_resource_t;
-+
-+typedef struct ipts_info {
-+	struct mei_cl_device *cldev;
-+	struct hid_device *hid;
-+
-+	struct work_struct init_work;
-+	struct work_struct raw_data_work;
-+	struct work_struct gfx_status_work;
-+
-+	struct task_struct *event_loop;
-+
-+#if IS_ENABLED(CONFIG_DEBUG_FS)
-+        struct dentry *dbgfs_dir;
-+#endif
-+
-+	ipts_state_t	state;
-+
-+	touch_sensor_mode_t	sensor_mode;
-+	touch_sensor_get_device_info_rsp_data_t device_info;
-+	ipts_resource_t	resource;
-+	u8		hid_input_report[HID_MAX_BUFFER_SIZE];
-+	int		num_of_parallel_data_buffers;
-+	bool		hid_desc_ready;
-+
-+	int current_buffer_index;
-+	int last_buffer_completed;
-+	int *last_submitted_id;
-+
-+	ipts_gfx_info_t gfx_info;
-+	u64		kernel_handle;
-+	int             gfx_status;
-+	bool		display_status;
-+
-+	bool		switch_sensor_mode;
-+	touch_sensor_mode_t	new_sensor_mode;
-+
-+	int		retry;
-+	bool		restart;
-+} ipts_info_t;
-+
-+#if IS_ENABLED(CONFIG_DEBUG_FS)
-+int ipts_dbgfs_register(ipts_info_t *ipts, const char *name);
-+void ipts_dbgfs_deregister(ipts_info_t *ipts);
-+#else
-+static int ipts_dbgfs_register(ipts_info_t *ipts, const char *name);
-+static void ipts_dbgfs_deregister(ipts_info_t *ipts);
-+#endif /* CONFIG_DEBUG_FS */
-+
-+/* inline functions */
-+static inline void ipts_set_state(ipts_info_t *ipts, ipts_state_t state)
-+{
-+	ipts->state = state;
-+}
-+
-+static inline ipts_state_t ipts_get_state(const ipts_info_t *ipts)
-+{
-+	return ipts->state;
-+}
-+
-+static inline bool ipts_is_default_resource_ready(const ipts_info_t *ipts)
-+{
-+	return ipts->resource.default_resource_ready;
-+}
-+
-+static inline bool ipts_is_raw_data_resource_ready(const ipts_info_t *ipts)
-+{
-+	return ipts->resource.raw_data_resource_ready;
-+}
-+
-+static inline ipts_buffer_info_t* ipts_get_feedback_buffer(ipts_info_t *ipts,
-+								int buffer_idx)
-+{
-+	return &ipts->resource.feedback_buffer[buffer_idx];
-+}
-+
-+static inline ipts_buffer_info_t* ipts_get_touch_data_buffer_hid(ipts_info_t *ipts)
-+{
-+	return &ipts->resource.touch_data_buffer_hid;
-+}
-+
-+static inline ipts_buffer_info_t* ipts_get_output_buffers_by_parallel_id(
-+							ipts_info_t *ipts,
-+                                                        int parallel_idx)
-+{
-+	return &ipts->resource.raw_data_mode_output_buffer[parallel_idx][0];
-+}
-+
-+static inline ipts_buffer_info_t* ipts_get_hid2me_buffer(ipts_info_t *ipts)
-+{
-+	return &ipts->resource.hid2me_buffer;
-+}
-+
-+static inline void ipts_set_wq_item_size(ipts_info_t *ipts, u8 size)
-+{
-+	ipts->resource.wq_item_size = size;
-+}
-+
-+static inline u8 ipts_get_wq_item_size(const ipts_info_t *ipts)
-+{
-+	return ipts->resource.wq_item_size;
-+}
-+
-+static inline int ipts_get_num_of_parallel_buffers(const ipts_info_t *ipts)
-+{
-+	return ipts->num_of_parallel_data_buffers;
-+}
-+
-+#endif // _IPTS_H_
-diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
-index 9c4042420022..5d63ebba3e9f 100644
---- a/drivers/misc/mei/hw-me-regs.h
-+++ b/drivers/misc/mei/hw-me-regs.h
-@@ -119,6 +119,7 @@
- 
- #define MEI_DEV_ID_SPT        0x9D3A  /* Sunrise Point */
- #define MEI_DEV_ID_SPT_2      0x9D3B  /* Sunrise Point 2 */
-+#define MEI_DEV_ID_SPT_4      0x9D3E  /* Sunrise Point 4 */
- #define MEI_DEV_ID_SPT_H      0xA13A  /* Sunrise Point H */
- #define MEI_DEV_ID_SPT_H_2    0xA13B  /* Sunrise Point H 2 */
- 
-diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
-index 41a10e392839..2b93a067cebc 100644
---- a/drivers/misc/mei/pci-me.c
-+++ b/drivers/misc/mei/pci-me.c
-@@ -86,6 +86,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
- 
- 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)},
- 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)},
-+	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)},
- 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
- 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
- 	{MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)},
-diff --git a/include/linux/intel_ipts_fw.h b/include/linux/intel_ipts_fw.h
-new file mode 100644
-index 000000000000..adbfd29459a2
---- /dev/null
-+++ b/include/linux/intel_ipts_fw.h
-@@ -0,0 +1,14 @@
-+#ifndef _INTEL_IPTS_FW_H_
-+#define _INTEL_IPTS_FW_H_
-+
-+#include <linux/firmware.h>
-+
-+#define MAX_IOCL_FILE_NAME_LEN 80
-+#define MAX_IOCL_FILE_PATH_LEN 256
-+#define IPTS_FW_HANDLER(name) int(*name)(const struct firmware **, \
-+	const char *, struct device *, void *)
-+
-+int intel_ipts_add_fw_handler(IPTS_FW_HANDLER(handler), void *data);
-+int intel_ipts_rm_fw_handler(IPTS_FW_HANDLER(handler));
-+
-+#endif // _INTEL_IPTS_FW_H_
-diff --git a/include/linux/intel_ipts_if.h b/include/linux/intel_ipts_if.h
-new file mode 100644
-index 000000000000..bad44fb4f233
---- /dev/null
-+++ b/include/linux/intel_ipts_if.h
-@@ -0,0 +1,76 @@
-+/*
-+ *
-+ * GFX interface to support Intel Precise Touch & Stylus
-+ * Copyright (c) 2016 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.
-+ *
-+ */
-+
-+#ifndef INTEL_IPTS_IF_H
-+#define INTEL_IPTS_IF_H
-+
-+enum {
-+	IPTS_INTERFACE_V1 = 1,
-+};
-+
-+#define IPTS_BUF_FLAG_CONTIGUOUS	0x01
-+
-+#define IPTS_NOTIFY_STA_BACKLIGHT_OFF	0x00
-+#define IPTS_NOTIFY_STA_BACKLIGHT_ON	0x01
-+
-+typedef struct intel_ipts_mapbuffer {
-+	u32	size;
-+	u32	flags;
-+	void	*gfx_addr;
-+	void	*cpu_addr;
-+	u64	buf_handle;
-+	u64	phy_addr;
-+} intel_ipts_mapbuffer_t;
-+
-+typedef struct intel_ipts_wq_info {
-+	u64 db_addr;
-+	u64 db_phy_addr;
-+	u32 db_cookie_offset;
-+	u32 wq_size;
-+	u64 wq_addr;
-+	u64 wq_phy_addr;
-+	u64 wq_head_addr;	/* head of wq is managed by GPU */
-+	u64 wq_head_phy_addr;	/* head of wq is managed by GPU */
-+	u64 wq_tail_addr;	/* tail of wq is managed by CSME */
-+	u64 wq_tail_phy_addr;	/* tail of wq is managed by CSME */
-+} intel_ipts_wq_info_t;
-+
-+typedef struct intel_ipts_ops {
-+	int (*get_wq_info)(uint64_t gfx_handle, intel_ipts_wq_info_t *wq_info);
-+	int (*map_buffer)(uint64_t gfx_handle, intel_ipts_mapbuffer_t *mapbuffer);
-+	int (*unmap_buffer)(uint64_t gfx_handle, uint64_t buf_handle);
-+} intel_ipts_ops_t;
-+
-+typedef struct intel_ipts_callback {
-+        void (*workload_complete)(void *data);
-+        void (*notify_gfx_status)(u32 status, void *data);
-+} intel_ipts_callback_t;
-+
-+typedef struct intel_ipts_connect {
-+	struct device *client;		/* input : client device for PM setup */
-+        intel_ipts_callback_t ipts_cb;	/* input : callback addresses */
-+	void *data;			/* input : callback data */
-+        u32 if_version;			/* input : interface version */
-+
-+        u32 gfx_version;		/* output : gfx version */
-+        u64 gfx_handle;			/* output : gfx handle */
-+	intel_ipts_ops_t ipts_ops;	/* output : gfx ops for IPTS */
-+} intel_ipts_connect_t;
-+
-+int intel_ipts_connect(intel_ipts_connect_t *ipts_connect);
-+void intel_ipts_disconnect(uint64_t gfx_handle);
-+
-+#endif // INTEL_IPTS_IF_H
--- 
-2.24.1
-

+ 19 - 18
patches/4.19/0001-surface-acpi.patch → patches/4.19/0005-surface-sam.patch

@@ -1,14 +1,14 @@
-From 0003680bafe3efd813a0802fcf7add69873a3b4a Mon Sep 17 00:00:00 2001
+From 84a947d275f9d1bd02854f402f2e5867eb7772a0 Mon Sep 17 00:00:00 2001
 From: qzed <qzed@users.noreply.github.com>
 Date: Mon, 26 Aug 2019 01:15:40 +0200
-Subject: [PATCH 01/13] surface-acpi
+Subject: [PATCH 05/10] surface-sam
 
 ---
  drivers/acpi/acpica/dsopcode.c                |    2 +-
  drivers/acpi/acpica/exfield.c                 |   26 +-
  drivers/platform/x86/Kconfig                  |    2 +
  drivers/platform/x86/Makefile                 |    1 +
- drivers/platform/x86/surface_sam/Kconfig      |  166 ++
+ drivers/platform/x86/surface_sam/Kconfig      |  163 ++
  drivers/platform/x86/surface_sam/Makefile     |   10 +
  .../x86/surface_sam/surface_sam_dtx.c         |  623 ++++++
  .../x86/surface_sam/surface_sam_hps.c         | 1110 +++++++++++
@@ -23,7 +23,7 @@ Subject: [PATCH 01/13] surface-acpi
  .../x86/surface_sam/surface_sam_ssh.h         |   97 +
  .../x86/surface_sam/surface_sam_vhf.c         |  276 +++
  drivers/tty/serdev/core.c                     |  111 +-
- 19 files changed, 7358 insertions(+), 29 deletions(-)
+ 19 files changed, 7355 insertions(+), 29 deletions(-)
  create mode 100644 drivers/platform/x86/surface_sam/Kconfig
  create mode 100644 drivers/platform/x86/surface_sam/Makefile
  create mode 100644 drivers/platform/x86/surface_sam/surface_sam_dtx.c
@@ -106,10 +106,10 @@ index b272c329d45d..cf547883a993 100644
  		} else {	/* IPMI */
  
 diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
-index 1e2524de6a63..ea17f993320e 100644
+index 2ad19dc64a4a..7cee1015981d 100644
 --- a/drivers/platform/x86/Kconfig
 +++ b/drivers/platform/x86/Kconfig
-@@ -1243,6 +1243,8 @@ config INTEL_ATOMISP2_PM
+@@ -1250,6 +1250,8 @@ config INTEL_ATOMISP2_PM
  	  To compile this driver as a module, choose M here: the module
  	  will be called intel_atomisp2_pm.
  
@@ -119,20 +119,20 @@ index 1e2524de6a63..ea17f993320e 100644
  
  config PMC_ATOM
 diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
-index dc29af4d8e2f..ddc2fbfaf110 100644
+index 2ea90039a3e4..cbea9579c1d2 100644
 --- a/drivers/platform/x86/Makefile
 +++ b/drivers/platform/x86/Makefile
-@@ -93,3 +93,4 @@ obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
+@@ -94,3 +94,4 @@ obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
  obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN)	+= intel_chtdc_ti_pwrbtn.o
  obj-$(CONFIG_I2C_MULTI_INSTANTIATE)	+= i2c-multi-instantiate.o
  obj-$(CONFIG_INTEL_ATOMISP2_PM)	+= intel_atomisp2_pm.o
 +obj-$(CONFIG_SURFACE_SAM)	+= surface_sam/
 diff --git a/drivers/platform/x86/surface_sam/Kconfig b/drivers/platform/x86/surface_sam/Kconfig
 new file mode 100644
-index 000000000000..4eff58a121cb
+index 000000000000..b4513c234c4d
 --- /dev/null
 +++ b/drivers/platform/x86/surface_sam/Kconfig
-@@ -0,0 +1,166 @@
+@@ -0,0 +1,163 @@
 +menuconfig SURFACE_SAM
 +    depends on ACPI
 +    tristate "Microsoft Surface/System Aggregator Module and Platform Drivers"
@@ -150,9 +150,6 @@ index 000000000000..4eff58a121cb
 +config SURFACE_SAM_SSH
 +	tristate "Surface Serial Hub Driver"
 +	depends on SURFACE_SAM
-+	depends on X86_INTEL_LPSS
-+	depends on SERIAL_8250_DW
-+	depends on SERIAL_8250_DMA
 +	depends on SERIAL_DEV_CTRL_TTYPORT
 +	select CRC_CCITT
 +	default m
@@ -7457,7 +7454,7 @@ index 000000000000..0ed0ebbdb3cb
 +MODULE_DESCRIPTION("Virtual HID Framework Driver for 5th Generation Surface Devices");
 +MODULE_LICENSE("GPL v2");
 diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
-index 9db93f500b4e..42d1dae34b21 100644
+index c66a04d24f1d..1b18d12d217f 100644
 --- a/drivers/tty/serdev/core.c
 +++ b/drivers/tty/serdev/core.c
 @@ -496,16 +496,97 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
@@ -7564,8 +7561,8 @@ index 9db93f500b4e..42d1dae34b21 100644
  	serdev = serdev_device_alloc(ctrl);
  	if (!serdev) {
  		dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n",
-@@ -527,7 +608,7 @@ static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl,
- }
+@@ -533,7 +614,7 @@ static const struct acpi_device_id serdev_acpi_devices_blacklist[] = {
+ };
  
  static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
 -				       void *data, void **return_value)
@@ -7573,13 +7570,17 @@ index 9db93f500b4e..42d1dae34b21 100644
  {
  	struct serdev_controller *ctrl = data;
  	struct acpi_device *adev;
-@@ -535,22 +616,28 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
+@@ -541,26 +622,32 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
  	if (acpi_bus_get_device(handle, &adev))
  		return AE_OK;
  
 +	if (acpi_device_enumerated(adev))
 +		return AE_OK;
 +
+ 	/* Skip if black listed */
+ 	if (!acpi_match_device_ids(adev, serdev_acpi_devices_blacklist))
+ 		return AE_OK;
+ 
 +	if (acpi_serdev_check_resources(ctrl, adev))
 +		return AE_OK;
 +
@@ -7608,5 +7609,5 @@ index 9db93f500b4e..42d1dae34b21 100644
  	if (!ctrl->serdev)
  		return -ENODEV;
 -- 
-2.24.1
+2.25.0
 

+ 0 - 27
patches/4.19/0006-hid.patch

@@ -1,27 +0,0 @@
-From 927b2d49811547c673eb3fc16126c8afca385757 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= <blaz@mxxn.io>
-Date: Wed, 6 Nov 2019 19:43:26 +0900
-Subject: [PATCH 06/13] hid
-
----
- drivers/hid/hid-core.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
-index b0c8fae7f903..3a359716fb38 100644
---- a/drivers/hid/hid-core.c
-+++ b/drivers/hid/hid-core.c
-@@ -780,6 +780,10 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
- 	if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
- 	    parser->global.report_size == 8)
- 		parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
-+
-+	if (usage == 0xff0000c6 && parser->global.report_count == 1 &&
-+	    parser->global.report_size == 8)
-+		parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
- }
- 
- static void hid_scan_collection(struct hid_parser *parser, unsigned type)
--- 
-2.24.1
-

+ 9 - 61
patches/4.19/0002-suspend.patch → patches/4.19/0006-suspend.patch

@@ -1,7 +1,7 @@
-From 55e646f0c2850aaf2732fa3f8d97aa97c0863837 Mon Sep 17 00:00:00 2001
+From 9f416015d2889678dc4cb6eee7e7f62ceac27e02 Mon Sep 17 00:00:00 2001
 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
 Date: Sat, 28 Sep 2019 17:48:21 +0200
-Subject: [PATCH 02/13] suspend
+Subject: [PATCH 06/10] suspend
 
 ---
  drivers/nvme/host/core.c |  36 ++++++++++++--
@@ -9,15 +9,13 @@ Subject: [PATCH 02/13] suspend
  drivers/nvme/host/pci.c  | 103 +++++++++++++++++++++++++++++++++++++--
  drivers/pci/pcie/aspm.c  |  20 ++++++++
  include/linux/pci.h      |   2 +
- kernel/power/suspend.c   |  11 +++++
- kernel/sysctl.c          |   9 ++++
- 7 files changed, 182 insertions(+), 6 deletions(-)
+ 5 files changed, 162 insertions(+), 6 deletions(-)
 
 diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
-index b2d9bd564960..7c522d2a0f99 100644
+index b7bd89b3b2f9..a9c689c10d3d 100644
 --- a/drivers/nvme/host/core.c
 +++ b/drivers/nvme/host/core.c
-@@ -1049,15 +1049,15 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl *ctrl,
+@@ -1055,15 +1055,15 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl *ctrl,
  	return id;
  }
  
@@ -36,7 +34,7 @@ index b2d9bd564960..7c522d2a0f99 100644
  	c.features.fid = cpu_to_le32(fid);
  	c.features.dword11 = cpu_to_le32(dword11);
  
-@@ -1068,6 +1068,24 @@ static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword
+@@ -1074,6 +1074,24 @@ static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword
  	return ret;
  }
  
@@ -61,7 +59,7 @@ index b2d9bd564960..7c522d2a0f99 100644
  int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
  {
  	u32 q_count = (*count - 1) | ((*count - 1) << 16);
-@@ -3584,6 +3602,18 @@ static void nvme_free_ctrl(struct device *dev)
+@@ -3590,6 +3608,18 @@ static void nvme_free_ctrl(struct device *dev)
  		nvme_put_subsystem(subsys);
  }
  
@@ -106,7 +104,7 @@ index cc4273f11989..40192b661798 100644
  void nvme_stop_keep_alive(struct nvme_ctrl *ctrl);
  int nvme_reset_ctrl(struct nvme_ctrl *ctrl);
 diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
-index 124f41157173..288ae6bf6213 100644
+index 3c68a5b35ec1..0cc7bea4eb70 100644
 --- a/drivers/nvme/host/pci.c
 +++ b/drivers/nvme/host/pci.c
 @@ -26,6 +26,7 @@
@@ -313,56 +311,6 @@ index b1f297f4b7b0..94ab2fc800d3 100644
  #endif
  
  #ifdef CONFIG_PCIEAER
-diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
-index 0bd595a0b610..a8385e8894a5 100644
---- a/kernel/power/suspend.c
-+++ b/kernel/power/suspend.c
-@@ -526,6 +526,8 @@ int suspend_devices_and_enter(suspend_state_t state)
- 	goto Resume_devices;
- }
- 
-+unsigned int resume_delay = 3000;
-+
- /**
-  * suspend_finish - Clean up before finishing the suspend sequence.
-  *
-@@ -534,6 +536,15 @@ int suspend_devices_and_enter(suspend_state_t state)
-  */
- static void suspend_finish(void)
- {
-+	if (resume_delay) {
-+		/* Give kernel threads a head start, such that usb-storage
-+		 * can detect devices before syslog attempts to write log
-+		 * messages from the suspend code.
-+		 */
-+		thaw_kernel_threads();
-+		pr_debug("PM: Sleeping for %d milliseconds.\n", resume_delay);
-+		msleep(resume_delay);
-+	}
- 	suspend_thaw_processes();
- 	pm_notifier_call_chain(PM_POST_SUSPEND);
- 	pm_restore_console();
-diff --git a/kernel/sysctl.c b/kernel/sysctl.c
-index f8576509c7be..a5fa80e72aba 100644
---- a/kernel/sysctl.c
-+++ b/kernel/sysctl.c
-@@ -313,7 +313,16 @@ static int min_extfrag_threshold;
- static int max_extfrag_threshold = 1000;
- #endif
- 
-+extern unsigned int resume_delay;
-+
- static struct ctl_table kern_table[] = {
-+	{
-+		.procname	= "resume_delay",
-+		.data		= &resume_delay,
-+		.maxlen		= sizeof(unsigned int),
-+		.mode		= 0644,
-+		.proc_handler	= proc_dointvec,
-+	},
- 	{
- 		.procname	= "sched_child_runs_first",
- 		.data		= &sysctl_sched_child_runs_first,
 -- 
-2.24.1
+2.25.0
 

+ 7445 - 0
patches/4.19/0007-ipts.patch

@@ -0,0 +1,7445 @@
+From f75f69ab7c9af49ceedabfdd5fedc3bb44375f01 Mon Sep 17 00:00:00 2001
+From: Maximilian Luz <luzmaximilian@gmail.com>
+Date: Sat, 28 Sep 2019 17:58:17 +0200
+Subject: [PATCH 07/10] ipts
+
+---
+ drivers/gpu/drm/i915/Makefile               |    3 +
+ drivers/gpu/drm/i915/i915_debugfs.c         |   63 +-
+ drivers/gpu/drm/i915/i915_drv.c             |    9 +-
+ drivers/gpu/drm/i915/i915_drv.h             |    3 +
+ drivers/gpu/drm/i915/i915_gem_context.c     |   12 +
+ drivers/gpu/drm/i915/i915_irq.c             |    7 +-
+ drivers/gpu/drm/i915/i915_params.c          |    5 +-
+ drivers/gpu/drm/i915/i915_params.h          |    5 +-
+ drivers/gpu/drm/i915/intel_guc.h            |    1 +
+ drivers/gpu/drm/i915/intel_guc_submission.c |   89 +-
+ drivers/gpu/drm/i915/intel_guc_submission.h |    4 +
+ drivers/gpu/drm/i915/intel_ipts.c           |  650 ++++++++++++
+ drivers/gpu/drm/i915/intel_ipts.h           |   34 +
+ drivers/gpu/drm/i915/intel_lrc.c            |   12 +-
+ drivers/gpu/drm/i915/intel_lrc.h            |    8 +
+ drivers/gpu/drm/i915/intel_panel.c          |    7 +
+ drivers/hid/hid-core.c                      |    5 +-
+ drivers/misc/Kconfig                        |    1 +
+ drivers/misc/Makefile                       |    1 +
+ drivers/misc/ipts/Kconfig                   |   12 +
+ drivers/misc/ipts/Makefile                  |   19 +
+ drivers/misc/ipts/companion.c               |  230 ++++
+ drivers/misc/ipts/companion.h               |   26 +
+ drivers/misc/ipts/companion/Kconfig         |    8 +
+ drivers/misc/ipts/companion/Makefile        |    2 +
+ drivers/misc/ipts/companion/ipts-surface.c  |  224 ++++
+ drivers/misc/ipts/dbgfs.c                   |  277 +++++
+ drivers/misc/ipts/gfx.c                     |  180 ++++
+ drivers/misc/ipts/gfx.h                     |   25 +
+ drivers/misc/ipts/hid.c                     |  499 +++++++++
+ drivers/misc/ipts/hid.h                     |   21 +
+ drivers/misc/ipts/ipts.c                    |   62 ++
+ drivers/misc/ipts/ipts.h                    |  172 +++
+ drivers/misc/ipts/kernel.c                  | 1047 +++++++++++++++++++
+ drivers/misc/ipts/kernel.h                  |   17 +
+ drivers/misc/ipts/mei-msgs.h                |  901 ++++++++++++++++
+ drivers/misc/ipts/mei.c                     |  238 +++++
+ drivers/misc/ipts/msg-handler.c             |  396 +++++++
+ drivers/misc/ipts/msg-handler.h             |   28 +
+ drivers/misc/ipts/params.c                  |   46 +
+ drivers/misc/ipts/params.h                  |   26 +
+ drivers/misc/ipts/resource.c                |  291 ++++++
+ drivers/misc/ipts/resource.h                |   26 +
+ drivers/misc/ipts/sensor-regs.h             |  834 +++++++++++++++
+ drivers/misc/ipts/state.h                   |   22 +
+ drivers/misc/mei/hw-me-regs.h               |    1 +
+ drivers/misc/mei/pci-me.c                   |    1 +
+ include/linux/ipts-binary.h                 |  140 +++
+ include/linux/ipts-companion.h              |   30 +
+ include/linux/ipts-gfx.h                    |   86 ++
+ include/linux/ipts.h                        |   20 +
+ 51 files changed, 6802 insertions(+), 24 deletions(-)
+ create mode 100644 drivers/gpu/drm/i915/intel_ipts.c
+ create mode 100644 drivers/gpu/drm/i915/intel_ipts.h
+ create mode 100644 drivers/misc/ipts/Kconfig
+ create mode 100644 drivers/misc/ipts/Makefile
+ create mode 100644 drivers/misc/ipts/companion.c
+ create mode 100644 drivers/misc/ipts/companion.h
+ create mode 100644 drivers/misc/ipts/companion/Kconfig
+ create mode 100644 drivers/misc/ipts/companion/Makefile
+ create mode 100644 drivers/misc/ipts/companion/ipts-surface.c
+ create mode 100644 drivers/misc/ipts/dbgfs.c
+ create mode 100644 drivers/misc/ipts/gfx.c
+ create mode 100644 drivers/misc/ipts/gfx.h
+ create mode 100644 drivers/misc/ipts/hid.c
+ create mode 100644 drivers/misc/ipts/hid.h
+ create mode 100644 drivers/misc/ipts/ipts.c
+ create mode 100644 drivers/misc/ipts/ipts.h
+ create mode 100644 drivers/misc/ipts/kernel.c
+ create mode 100644 drivers/misc/ipts/kernel.h
+ create mode 100644 drivers/misc/ipts/mei-msgs.h
+ create mode 100644 drivers/misc/ipts/mei.c
+ create mode 100644 drivers/misc/ipts/msg-handler.c
+ create mode 100644 drivers/misc/ipts/msg-handler.h
+ create mode 100644 drivers/misc/ipts/params.c
+ create mode 100644 drivers/misc/ipts/params.h
+ create mode 100644 drivers/misc/ipts/resource.c
+ create mode 100644 drivers/misc/ipts/resource.h
+ create mode 100644 drivers/misc/ipts/sensor-regs.h
+ create mode 100644 drivers/misc/ipts/state.h
+ create mode 100644 include/linux/ipts-binary.h
+ create mode 100644 include/linux/ipts-companion.h
+ create mode 100644 include/linux/ipts-gfx.h
+ create mode 100644 include/linux/ipts.h
+
+diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
+index 5794f102f9b8..6ae0e91a213a 100644
+--- a/drivers/gpu/drm/i915/Makefile
++++ b/drivers/gpu/drm/i915/Makefile
+@@ -155,6 +155,9 @@ i915-y += dvo_ch7017.o \
+ 	  vlv_dsi.o \
+ 	  vlv_dsi_pll.o
+ 
++# intel precise touch & stylus
++i915-y  += intel_ipts.o
++
+ # Post-mortem debug and GPU hang state capture
+ i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
+ i915-$(CONFIG_DRM_I915_SELFTEST) += \
+diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
+index e063e98d1e82..99becb6aed68 100644
+--- a/drivers/gpu/drm/i915/i915_debugfs.c
++++ b/drivers/gpu/drm/i915/i915_debugfs.c
+@@ -31,6 +31,7 @@
+ #include <linux/sched/mm.h>
+ #include "intel_drv.h"
+ #include "intel_guc_submission.h"
++#include "intel_ipts.h"
+ 
+ static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node)
+ {
+@@ -4695,6 +4696,64 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
+ 	.llseek = default_llseek,
+ };
+ 
++static ssize_t
++i915_ipts_cleanup_write(struct file *filp,
++			       const char __user *ubuf,
++			       size_t cnt, loff_t *ppos)
++{
++	struct drm_i915_private *dev_priv = filp->private_data;
++	struct drm_device *dev = &dev_priv->drm;
++	int ret;
++	bool flag;
++
++	ret = kstrtobool_from_user(ubuf, cnt, &flag);
++	if (ret)
++		return ret;
++
++	if (!flag)
++		return cnt;
++
++	ipts_cleanup(dev);
++
++	return cnt;
++}
++
++static const struct file_operations i915_ipts_cleanup_ops = {
++	.owner = THIS_MODULE,
++	.open = simple_open,
++	.write = i915_ipts_cleanup_write,
++	.llseek = default_llseek,
++};
++
++static ssize_t
++i915_ipts_init_write(struct file *filp,
++			       const char __user *ubuf,
++			       size_t cnt, loff_t *ppos)
++{
++	struct drm_i915_private *dev_priv = filp->private_data;
++	struct drm_device *dev = &dev_priv->drm;
++	int ret;
++	bool flag;
++
++	ret = kstrtobool_from_user(ubuf, cnt, &flag);
++	if (ret)
++		return ret;
++
++	if (!flag)
++		return cnt;
++
++	ipts_init(dev);
++
++	return cnt;
++}
++
++static const struct file_operations i915_ipts_init_ops = {
++	.owner = THIS_MODULE,
++	.open = simple_open,
++	.write = i915_ipts_init_write,
++	.llseek = default_llseek,
++};
++
+ static const struct drm_info_list i915_debugfs_list[] = {
+ 	{"i915_capabilities", i915_capabilities, 0},
+ 	{"i915_gem_objects", i915_gem_object_info, 0},
+@@ -4773,7 +4832,9 @@ static const struct i915_debugfs_files {
+ 	{"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
+ 	{"i915_ipc_status", &i915_ipc_status_fops},
+ 	{"i915_drrs_ctl", &i915_drrs_ctl_fops},
+-	{"i915_edp_psr_debug", &i915_edp_psr_debug_fops}
++	{"i915_edp_psr_debug", &i915_edp_psr_debug_fops},
++	{"i915_ipts_cleanup", &i915_ipts_cleanup_ops},
++	{"i915_ipts_init", &i915_ipts_init_ops},
+ };
+ 
+ int i915_debugfs_register(struct drm_i915_private *dev_priv)
+diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
+index b0d76a7a0946..81fba8e5ab05 100644
+--- a/drivers/gpu/drm/i915/i915_drv.c
++++ b/drivers/gpu/drm/i915/i915_drv.c
+@@ -47,11 +47,12 @@
+ #include <drm/i915_drm.h>
+ 
+ #include "i915_drv.h"
+-#include "i915_trace.h"
+ #include "i915_pmu.h"
+ #include "i915_query.h"
++#include "i915_trace.h"
+ #include "i915_vgpu.h"
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+ #include "intel_uc.h"
+ 
+ static struct drm_driver driver;
+@@ -696,6 +697,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
+ 	/* Only enable hotplug handling once the fbdev is fully set up. */
+ 	intel_hpd_init(dev_priv);
+ 
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		ipts_init(dev);
++
+ 	return 0;
+ 
+ cleanup_gem:
+@@ -1438,6 +1442,9 @@ void i915_driver_unload(struct drm_device *dev)
+ 	struct drm_i915_private *dev_priv = to_i915(dev);
+ 	struct pci_dev *pdev = dev_priv->drm.pdev;
+ 
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		ipts_cleanup(dev);
++
+ 	i915_driver_unregister(dev_priv);
+ 
+ 	if (i915_gem_suspend(dev_priv))
+diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
+index db2e9af49ae6..99bc0c92c411 100644
+--- a/drivers/gpu/drm/i915/i915_drv.h
++++ b/drivers/gpu/drm/i915/i915_drv.h
+@@ -3232,6 +3232,9 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj,
+ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj,
+ 					 struct sg_table *pages);
+ 
++struct i915_gem_context *
++i915_gem_context_create_ipts(struct drm_device *dev);
++
+ static inline struct i915_gem_context *
+ __i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
+ {
+diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
+index ef383fd42988..89da4ff09431 100644
+--- a/drivers/gpu/drm/i915/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/i915_gem_context.c
+@@ -472,6 +472,18 @@ static bool needs_preempt_context(struct drm_i915_private *i915)
+ 	return HAS_LOGICAL_RING_PREEMPTION(i915);
+ }
+ 
++struct i915_gem_context *i915_gem_context_create_ipts(struct drm_device *dev)
++{
++	struct drm_i915_private *dev_priv = to_i915(dev);
++	struct i915_gem_context *ctx;
++
++	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
++
++	ctx = i915_gem_create_context(dev_priv, NULL);
++
++	return ctx;
++}
++
+ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
+ {
+ 	struct i915_gem_context *ctx;
+diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
+index 29877969310d..37a58b19ec3f 100644
+--- a/drivers/gpu/drm/i915/i915_irq.c
++++ b/drivers/gpu/drm/i915/i915_irq.c
+@@ -36,6 +36,7 @@
+ #include "i915_drv.h"
+ #include "i915_trace.h"
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+ 
+ /**
+  * DOC: interrupt handling
+@@ -1503,6 +1504,9 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
+ 		tasklet |= USES_GUC_SUBMISSION(engine->i915);
+ 	}
+ 
++	if (iir & GT_RENDER_PIPECTL_NOTIFY_INTERRUPT && i915_modparams.enable_ipts)
++		ipts_notify_complete();
++
+ 	if (tasklet)
+ 		tasklet_hi_schedule(&engine->execlists.tasklet);
+ }
+@@ -4122,7 +4126,8 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
+ {
+ 	/* These are interrupts we'll toggle with the ring mask register */
+ 	uint32_t gt_interrupts[] = {
+-		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
++		GT_RENDER_PIPECTL_NOTIFY_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
++			GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+ 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+ 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+ 			GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
+index 295e981e4a39..84415814c007 100644
+--- a/drivers/gpu/drm/i915/i915_params.c
++++ b/drivers/gpu/drm/i915/i915_params.c
+@@ -145,7 +145,10 @@ i915_param_named_unsafe(edp_vswing, int, 0400,
+ i915_param_named_unsafe(enable_guc, int, 0400,
+ 	"Enable GuC load for GuC submission and/or HuC load. "
+ 	"Required functionality can be selected using bitmask values. "
+-	"(-1=auto, 0=disable [default], 1=GuC submission, 2=HuC load)");
++	"(-1=auto [default], 0=disable, 1=GuC submission, 2=HuC load)");
++
++i915_param_named_unsafe(enable_ipts, int, 0400,
++	"Enable IPTS Touchscreen and Pen support (default: 1)");
+ 
+ i915_param_named(guc_log_level, int, 0400,
+ 	"GuC firmware logging level. Requires GuC to be loaded. "
+diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
+index 6c4d4a21474b..4ab800c3de6d 100644
+--- a/drivers/gpu/drm/i915/i915_params.h
++++ b/drivers/gpu/drm/i915/i915_params.h
+@@ -46,7 +46,7 @@ struct drm_printer;
+ 	param(int, disable_power_well, -1) \
+ 	param(int, enable_ips, 1) \
+ 	param(int, invert_brightness, 0) \
+-	param(int, enable_guc, 0) \
++	param(int, enable_guc, -1) \
+ 	param(int, guc_log_level, -1) \
+ 	param(char *, guc_firmware_path, NULL) \
+ 	param(char *, huc_firmware_path, NULL) \
+@@ -68,7 +68,8 @@ struct drm_printer;
+ 	param(bool, nuclear_pageflip, false) \
+ 	param(bool, enable_dp_mst, true) \
+ 	param(bool, enable_dpcd_backlight, false) \
+-	param(bool, enable_gvt, false)
++	param(bool, enable_gvt, false) \
++	param(int, enable_ipts, 1)
+ 
+ #define MEMBER(T, member, ...) T member;
+ struct i915_params {
+diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
+index 4121928a495e..8967376accf3 100644
+--- a/drivers/gpu/drm/i915/intel_guc.h
++++ b/drivers/gpu/drm/i915/intel_guc.h
+@@ -69,6 +69,7 @@ struct intel_guc {
+ 
+ 	struct intel_guc_client *execbuf_client;
+ 	struct intel_guc_client *preempt_client;
++	struct intel_guc_client *ipts_client;
+ 
+ 	struct guc_preempt_work preempt_work[I915_NUM_ENGINES];
+ 	struct workqueue_struct *preempt_wq;
+diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
+index 4aa5e6463e7b..da80c5f17fee 100644
+--- a/drivers/gpu/drm/i915/intel_guc_submission.c
++++ b/drivers/gpu/drm/i915/intel_guc_submission.c
+@@ -88,12 +88,17 @@ static inline struct i915_priolist *to_priolist(struct rb_node *rb)
+ 
+ static inline bool is_high_priority(struct intel_guc_client *client)
+ {
+-	return (client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH ||
+-		client->priority == GUC_CLIENT_PRIORITY_HIGH);
++	return (client->priority == GUC_CLIENT_PRIORITY_HIGH);
++}
++
++static inline bool is_high_priority_kmd(struct intel_guc_client *client)
++{
++	return (client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH);
+ }
+ 
+ static int reserve_doorbell(struct intel_guc_client *client)
+ {
++	struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
+ 	unsigned long offset;
+ 	unsigned long end;
+ 	u16 id;
+@@ -106,10 +111,14 @@ static int reserve_doorbell(struct intel_guc_client *client)
+ 	 * priority contexts, the second half for high-priority ones.
+ 	 */
+ 	offset = 0;
+-	end = GUC_NUM_DOORBELLS / 2;
+-	if (is_high_priority(client)) {
+-		offset = end;
+-		end += offset;
++	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
++		end = GUC_NUM_DOORBELLS;
++	} else {
++		end = GUC_NUM_DOORBELLS/2;
++		if (is_high_priority(client)) {
++			offset = end;
++			end += offset;
++		}
+ 	}
+ 
+ 	id = find_next_zero_bit(client->guc->doorbell_bitmap, end, offset);
+@@ -355,9 +364,15 @@ static void guc_stage_desc_init(struct intel_guc *guc,
+ 	desc = __get_stage_desc(client);
+ 	memset(desc, 0, sizeof(*desc));
+ 
+-	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE |
+-			  GUC_STAGE_DESC_ATTR_KERNEL;
+-	if (is_high_priority(client))
++	desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE;
++	if ((client->priority == GUC_CLIENT_PRIORITY_KMD_NORMAL) ||
++			(client->priority == GUC_CLIENT_PRIORITY_KMD_HIGH)) {
++		desc->attribute  |= GUC_STAGE_DESC_ATTR_KERNEL;
++	} else {
++		desc->attribute  |= GUC_STAGE_DESC_ATTR_PCH;
++	}
++
++	if (is_high_priority_kmd(client))
+ 		desc->attribute |= GUC_STAGE_DESC_ATTR_PREEMPT;
+ 	desc->stage_id = client->stage_id;
+ 	desc->priority = client->priority;
+@@ -1204,7 +1219,8 @@ static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
+ 		I915_WRITE(RING_MODE_GEN7(engine), irqs);
+ 
+ 	/* route USER_INTERRUPT to Host, all others are sent to GuC. */
+-	irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
++	irqs = (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)
++							<< GEN8_RCS_IRQ_SHIFT |
+ 	       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+ 	/* These three registers have the same bit definitions */
+ 	I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
+@@ -1349,6 +1365,59 @@ void intel_guc_submission_disable(struct intel_guc *guc)
+ 	guc_clients_doorbell_fini(guc);
+ }
+ 
++int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv,
++				    struct i915_gem_context *ctx)
++{
++	struct intel_guc *guc = &dev_priv->guc;
++	struct intel_guc_client *client;
++	int err;
++	int ret;
++
++	/* client for execbuf submission */
++	client = guc_client_alloc(dev_priv,
++				  INTEL_INFO(dev_priv)->ring_mask,
++				  IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ? GUC_CLIENT_PRIORITY_HIGH : GUC_CLIENT_PRIORITY_NORMAL,
++				  ctx);
++	if (IS_ERR(client)) {
++		DRM_ERROR("Failed to create normal GuC client!\n");
++		return -ENOMEM;
++	}
++
++	guc->ipts_client = client;
++
++	err = intel_guc_sample_forcewake(guc);
++	if (err)
++		return err;
++
++	ret = create_doorbell(guc->ipts_client);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv)
++{
++	struct intel_guc *guc = &dev_priv->guc;
++
++	if (!guc->ipts_client)
++		return;
++
++	destroy_doorbell(guc->ipts_client);
++	guc_client_free(guc->ipts_client);
++	guc->ipts_client = NULL;
++}
++
++void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv)
++{
++	struct intel_guc *guc = &dev_priv->guc;
++
++	int err = __guc_allocate_doorbell(guc, guc->ipts_client->stage_id);
++
++	if (err)
++		DRM_ERROR("Not able to reacquire IPTS doorbell\n");
++}
++
+ #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+ #include "selftests/intel_guc.c"
+ #endif
+diff --git a/drivers/gpu/drm/i915/intel_guc_submission.h b/drivers/gpu/drm/i915/intel_guc_submission.h
+index fb081cefef93..71fc7986585a 100644
+--- a/drivers/gpu/drm/i915/intel_guc_submission.h
++++ b/drivers/gpu/drm/i915/intel_guc_submission.h
+@@ -79,5 +79,9 @@ void intel_guc_submission_disable(struct intel_guc *guc);
+ void intel_guc_submission_fini(struct intel_guc *guc);
+ int intel_guc_preempt_work_create(struct intel_guc *guc);
+ void intel_guc_preempt_work_destroy(struct intel_guc *guc);
++int i915_guc_ipts_submission_enable(struct drm_i915_private *dev_priv,
++				    struct i915_gem_context *ctx);
++void i915_guc_ipts_submission_disable(struct drm_i915_private *dev_priv);
++void i915_guc_ipts_reacquire_doorbell(struct drm_i915_private *dev_priv);
+ 
+ #endif
+diff --git a/drivers/gpu/drm/i915/intel_ipts.c b/drivers/gpu/drm/i915/intel_ipts.c
+new file mode 100644
+index 000000000000..c1199074924a
+--- /dev/null
++++ b/drivers/gpu/drm/i915/intel_ipts.c
+@@ -0,0 +1,650 @@
++/*
++ * Copyright  2016 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ *
++ */
++
++#include <drm/drmP.h>
++#include <linux/ipts-gfx.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++
++#include "intel_guc_submission.h"
++#include "i915_drv.h"
++
++#define SUPPORTED_IPTS_INTERFACE_VERSION 1
++
++#define REACQUIRE_DB_THRESHOLD 10
++
++#define DB_LOST_CHECK_STEP1_INTERVAL 2500 // ms
++#define DB_LOST_CHECK_STEP2_INTERVAL 1000 // ms
++
++// CTX for ipts support
++struct ipts {
++	struct drm_device *dev;
++	struct i915_gem_context *ipts_context;
++	struct ipts_callback ipts_clbks;
++
++	// buffers' list
++	struct {
++		spinlock_t lock;
++		struct list_head list;
++	} buffers;
++
++	void *data;
++
++	struct delayed_work reacquire_db_work;
++	struct ipts_wq_info wq_info;
++	u32 old_tail;
++	u32 old_head;
++	bool need_reacquire_db;
++
++	bool connected;
++	bool initialized;
++};
++
++struct ipts ipts;
++
++struct ipts_object {
++	struct list_head list;
++	struct drm_i915_gem_object *gem_obj;
++	void *cpu_addr;
++};
++
++static struct ipts_object *ipts_object_create(size_t size, u32 flags)
++{
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++	struct ipts_object *obj = NULL;
++	struct drm_i915_gem_object *gem_obj = NULL;
++	int ret = 0;
++
++	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
++	if (!obj)
++		return NULL;
++
++	size = roundup(size, PAGE_SIZE);
++	if (size == 0) {
++		ret = -EINVAL;
++		goto err_out;
++	}
++
++	// Allocate the new object
++	gem_obj = i915_gem_object_create(dev_priv, size);
++	if (gem_obj == NULL) {
++		ret = -ENOMEM;
++		goto err_out;
++	}
++
++	if (flags & IPTS_BUF_FLAG_CONTIGUOUS) {
++		ret = i915_gem_object_attach_phys(gem_obj, PAGE_SIZE);
++		if (ret) {
++			pr_info(">> ipts no contiguous : %d\n", ret);
++			goto err_out;
++		}
++	}
++
++	obj->gem_obj = gem_obj;
++
++	spin_lock(&ipts.buffers.lock);
++	list_add_tail(&obj->list, &ipts.buffers.list);
++	spin_unlock(&ipts.buffers.lock);
++
++	return obj;
++
++err_out:
++
++	if (gem_obj)
++		i915_gem_free_object(&gem_obj->base);
++
++	kfree(obj);
++
++	return NULL;
++}
++
++static void ipts_object_free(struct ipts_object *obj)
++{
++	spin_lock(&ipts.buffers.lock);
++	list_del(&obj->list);
++	spin_unlock(&ipts.buffers.lock);
++
++	i915_gem_free_object(&obj->gem_obj->base);
++	kfree(obj);
++}
++
++static int ipts_object_pin(struct ipts_object *obj,
++		struct i915_gem_context *ipts_ctx)
++{
++	struct i915_address_space *vm = NULL;
++	struct i915_vma *vma = NULL;
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++	int ret = 0;
++
++	if (ipts_ctx->ppgtt)
++		vm = &ipts_ctx->ppgtt->vm;
++	else
++		vm = &dev_priv->ggtt.vm;
++
++	vma = i915_vma_instance(obj->gem_obj, vm, NULL);
++	if (IS_ERR(vma)) {
++		DRM_ERROR("cannot find or create vma\n");
++		return -1;
++	}
++
++	ret = i915_vma_pin(vma, 0, PAGE_SIZE, PIN_USER);
++
++	return ret;
++}
++
++static void ipts_object_unpin(struct ipts_object *obj)
++{
++	// TODO: Add support
++}
++
++static void *ipts_object_map(struct ipts_object *obj)
++{
++	return i915_gem_object_pin_map(obj->gem_obj, I915_MAP_WB);
++}
++
++static void ipts_object_unmap(struct ipts_object *obj)
++{
++	i915_gem_object_unpin_map(obj->gem_obj);
++	obj->cpu_addr = NULL;
++}
++
++static int create_ipts_context(void)
++{
++	struct i915_gem_context *ipts_ctx = NULL;
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++	struct intel_context *ce = NULL;
++	struct intel_context *pin_ret;
++	int ret = 0;
++
++	// Initialize the context right away.
++	ret = i915_mutex_lock_interruptible(ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return ret;
++	}
++
++	ipts_ctx = i915_gem_context_create_ipts(ipts.dev);
++	if (IS_ERR(ipts_ctx)) {
++		DRM_ERROR("Failed to create IPTS context (error %ld)\n",
++			  PTR_ERR(ipts_ctx));
++		ret = PTR_ERR(ipts_ctx);
++		goto err_unlock;
++	}
++
++	ce = to_intel_context(ipts_ctx, dev_priv->engine[RCS]);
++	if (IS_ERR(ce)) {
++		DRM_ERROR("Failed to create intel context (error %ld)\n",
++			  PTR_ERR(ce));
++		ret = PTR_ERR(ce);
++		goto err_unlock;
++	}
++
++	ret = execlists_context_deferred_alloc(ipts_ctx, dev_priv->engine[RCS], ce);
++	if (ret) {
++		DRM_DEBUG("lr context allocation failed: %d\n", ret);
++		goto err_ctx;
++	}
++
++	pin_ret = execlists_context_pin(dev_priv->engine[RCS], ipts_ctx);
++	if (IS_ERR(pin_ret)) {
++		DRM_DEBUG("lr context pinning failed: %ld\n", PTR_ERR(pin_ret));
++		goto err_ctx;
++	}
++
++	// Release the mutex
++	mutex_unlock(&ipts.dev->struct_mutex);
++
++	spin_lock_init(&ipts.buffers.lock);
++	INIT_LIST_HEAD(&ipts.buffers.list);
++
++	ipts.ipts_context = ipts_ctx;
++
++	return 0;
++
++err_ctx:
++	if (ipts_ctx)
++		i915_gem_context_put(ipts_ctx);
++
++err_unlock:
++	mutex_unlock(&ipts.dev->struct_mutex);
++
++	return ret;
++}
++
++static void destroy_ipts_context(void)
++{
++	struct i915_gem_context *ipts_ctx = NULL;
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++	struct intel_context *ce = NULL;
++	int ret = 0;
++
++	ipts_ctx = ipts.ipts_context;
++
++	ce = to_intel_context(ipts_ctx, dev_priv->engine[RCS]);
++
++	// Initialize the context right away.
++	ret = i915_mutex_lock_interruptible(ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return;
++	}
++
++	execlists_context_unpin(ce);
++	i915_gem_context_put(ipts_ctx);
++
++	mutex_unlock(&ipts.dev->struct_mutex);
++}
++
++int ipts_notify_complete(void)
++{
++	if (ipts.ipts_clbks.workload_complete)
++		ipts.ipts_clbks.workload_complete(ipts.data);
++
++	return 0;
++}
++
++int ipts_notify_backlight_status(bool backlight_on)
++{
++	if (ipts.ipts_clbks.notify_gfx_status) {
++		if (backlight_on) {
++			ipts.ipts_clbks.notify_gfx_status(
++				IPTS_NOTIFY_STA_BACKLIGHT_ON, ipts.data);
++			schedule_delayed_work(&ipts.reacquire_db_work,
++				msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
++		} else {
++			ipts.ipts_clbks.notify_gfx_status(
++				IPTS_NOTIFY_STA_BACKLIGHT_OFF, ipts.data);
++			cancel_delayed_work(&ipts.reacquire_db_work);
++		}
++	}
++
++	return 0;
++}
++
++static void ipts_reacquire_db(struct ipts *ipts_p)
++{
++	int ret = 0;
++
++	ret = i915_mutex_lock_interruptible(ipts_p->dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return;
++	}
++
++	// Reacquire the doorbell
++	i915_guc_ipts_reacquire_doorbell(ipts_p->dev->dev_private);
++
++	mutex_unlock(&ipts_p->dev->struct_mutex);
++}
++
++static int ipts_get_wq_info(uint64_t gfx_handle,
++		struct ipts_wq_info *wq_info)
++{
++	if (gfx_handle != (uint64_t)&ipts) {
++		DRM_ERROR("invalid gfx handle\n");
++		return -EINVAL;
++	}
++
++	*wq_info = ipts.wq_info;
++
++	ipts_reacquire_db(&ipts);
++	schedule_delayed_work(&ipts.reacquire_db_work,
++		msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
++
++	return 0;
++}
++
++static int set_wq_info(void)
++{
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++	struct intel_guc *guc = &dev_priv->guc;
++	struct intel_guc_client *client;
++	struct guc_process_desc *desc;
++	struct ipts_wq_info *wq_info;
++	void *base = NULL;
++	u64 phy_base = 0;
++
++	wq_info = &ipts.wq_info;
++
++	client = guc->ipts_client;
++	if (!client) {
++		DRM_ERROR("IPTS GuC client is NOT available\n");
++		return -EINVAL;
++	}
++
++	base = client->vaddr;
++	desc = (struct guc_process_desc *)
++		((u64)base + client->proc_desc_offset);
++
++	desc->wq_base_addr = (u64)base + GUC_DB_SIZE;
++	desc->db_base_addr = (u64)base + client->doorbell_offset;
++
++	// IPTS expects physical addresses to pass it to ME
++	phy_base = sg_dma_address(client->vma->pages->sgl);
++
++	wq_info->db_addr = desc->db_base_addr;
++	wq_info->db_phy_addr = phy_base + client->doorbell_offset;
++	wq_info->db_cookie_offset = offsetof(struct guc_doorbell_info, cookie);
++	wq_info->wq_addr = desc->wq_base_addr;
++	wq_info->wq_phy_addr = phy_base + GUC_DB_SIZE;
++	wq_info->wq_head_addr = (u64)&desc->head;
++	wq_info->wq_tail_addr = (u64)&desc->tail;
++	wq_info->wq_size = desc->wq_size_bytes;
++
++	wq_info->wq_head_phy_addr = phy_base + client->proc_desc_offset +
++		offsetof(struct guc_process_desc, head);
++
++	wq_info->wq_tail_phy_addr = phy_base + client->proc_desc_offset +
++		offsetof(struct guc_process_desc, tail);
++
++	return 0;
++}
++
++static int ipts_init_wq(void)
++{
++	int ret = 0;
++
++	ret = i915_mutex_lock_interruptible(ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return ret;
++	}
++
++	// disable IPTS submission
++	i915_guc_ipts_submission_disable(ipts.dev->dev_private);
++
++	// enable IPTS submission
++	ret = i915_guc_ipts_submission_enable(ipts.dev->dev_private,
++		ipts.ipts_context);
++	if (ret) {
++		DRM_ERROR("i915_guc_ipts_submission_enable failed: %d\n", ret);
++		goto out;
++	}
++
++	ret = set_wq_info();
++	if (ret) {
++		DRM_ERROR("set_wq_info failed\n");
++		goto out;
++	}
++
++out:
++	mutex_unlock(&ipts.dev->struct_mutex);
++
++	return ret;
++}
++
++static void ipts_release_wq(void)
++{
++	int ret = 0;
++
++	ret = i915_mutex_lock_interruptible(ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return;
++	}
++
++	// disable IPTS submission
++	i915_guc_ipts_submission_disable(ipts.dev->dev_private);
++
++	mutex_unlock(&ipts.dev->struct_mutex);
++}
++
++static int ipts_map_buffer(u64 gfx_handle, struct ipts_mapbuffer *mapbuf)
++{
++	struct ipts_object *obj;
++	struct i915_gem_context *ipts_ctx = NULL;
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++	struct i915_address_space *vm = NULL;
++	struct i915_vma *vma = NULL;
++	int ret = 0;
++
++	if (gfx_handle != (uint64_t)&ipts) {
++		DRM_ERROR("invalid gfx handle\n");
++		return -EINVAL;
++	}
++
++	// Acquire mutex first
++	ret = i915_mutex_lock_interruptible(ipts.dev);
++	if (ret) {
++		DRM_ERROR("i915_mutex_lock_interruptible failed\n");
++		return -EINVAL;
++	}
++
++	obj = ipts_object_create(mapbuf->size, mapbuf->flags);
++	if (!obj)
++		return -ENOMEM;
++
++	ipts_ctx = ipts.ipts_context;
++	ret = ipts_object_pin(obj, ipts_ctx);
++	if (ret) {
++		DRM_ERROR("Not able to pin iTouch obj\n");
++		ipts_object_free(obj);
++		mutex_unlock(&ipts.dev->struct_mutex);
++		return -ENOMEM;
++	}
++
++	if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS)
++		obj->cpu_addr = obj->gem_obj->phys_handle->vaddr;
++	else
++		obj->cpu_addr = ipts_object_map(obj);
++
++	if (ipts_ctx->ppgtt)
++		vm = &ipts_ctx->ppgtt->vm;
++	else
++		vm = &dev_priv->ggtt.vm;
++
++	vma = i915_vma_instance(obj->gem_obj, vm, NULL);
++	if (IS_ERR(vma)) {
++		DRM_ERROR("cannot find or create vma\n");
++		return -EINVAL;
++	}
++
++	mapbuf->gfx_addr = (void *)vma->node.start;
++	mapbuf->cpu_addr = (void *)obj->cpu_addr;
++	mapbuf->buf_handle = (u64)obj;
++	if (mapbuf->flags & IPTS_BUF_FLAG_CONTIGUOUS)
++		mapbuf->phy_addr = (u64)obj->gem_obj->phys_handle->busaddr;
++
++	// Release the mutex
++	mutex_unlock(&ipts.dev->struct_mutex);
++
++	return 0;
++}
++
++static int ipts_unmap_buffer(uint64_t gfx_handle, uint64_t buf_handle)
++{
++	struct ipts_object *obj = (struct ipts_object *)buf_handle;
++
++	if (gfx_handle != (uint64_t)&ipts) {
++		DRM_ERROR("invalid gfx handle\n");
++		return -EINVAL;
++	}
++
++	if (!obj->gem_obj->phys_handle)
++		ipts_object_unmap(obj);
++
++	ipts_object_unpin(obj);
++	ipts_object_free(obj);
++
++	return 0;
++}
++
++int ipts_connect(struct ipts_connect *ipts_connect)
++{
++	u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
++	struct drm_i915_private *dev_priv = to_i915(ipts.dev);
++
++	if (!ipts.initialized)
++		return -EIO;
++
++	if (!ipts_connect)
++		return -EINVAL;
++
++	if (ipts_connect->if_version > SUPPORTED_IPTS_INTERFACE_VERSION)
++		return -EINVAL;
++
++	// set up device-link for PM
++	if (!device_link_add(ipts_connect->client, ipts.dev->dev, flags))
++		return -EFAULT;
++
++	// return gpu operations for ipts
++	ipts_connect->ipts_ops.get_wq_info = ipts_get_wq_info;
++	ipts_connect->ipts_ops.map_buffer = ipts_map_buffer;
++	ipts_connect->ipts_ops.unmap_buffer = ipts_unmap_buffer;
++	ipts_connect->gfx_version = INTEL_INFO(dev_priv)->gen;
++	ipts_connect->gfx_handle = (uint64_t)&ipts;
++
++	// save callback and data
++	ipts.data = ipts_connect->data;
++	ipts.ipts_clbks = ipts_connect->ipts_cb;
++
++	ipts.connected = true;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(ipts_connect);
++
++void ipts_disconnect(uint64_t gfx_handle)
++{
++	if (!ipts.initialized)
++		return;
++
++	if (gfx_handle != (uint64_t)&ipts || !ipts.connected) {
++		DRM_ERROR("invalid gfx handle\n");
++		return;
++	}
++
++	ipts.data = 0;
++	memset(&ipts.ipts_clbks, 0, sizeof(struct ipts_callback));
++
++	ipts.connected = false;
++}
++EXPORT_SYMBOL_GPL(ipts_disconnect);
++
++static void reacquire_db_work_func(struct work_struct *work)
++{
++	struct delayed_work *d_work = container_of(work,
++		struct delayed_work, work);
++	struct ipts *ipts_p = container_of(d_work,
++		struct ipts, reacquire_db_work);
++	u32 head;
++	u32 tail;
++	u32 size;
++	u32 load;
++
++	head = *(u32 *)ipts_p->wq_info.wq_head_addr;
++	tail = *(u32 *)ipts_p->wq_info.wq_tail_addr;
++	size = ipts_p->wq_info.wq_size;
++
++	if (head >= tail)
++		load = head - tail;
++	else
++		load = head + size - tail;
++
++	if (load < REACQUIRE_DB_THRESHOLD) {
++		ipts_p->need_reacquire_db = false;
++		goto reschedule_work;
++	}
++
++	if (ipts_p->need_reacquire_db) {
++		if (ipts_p->old_head == head &&
++				ipts_p->old_tail == tail)
++			ipts_reacquire_db(ipts_p);
++		ipts_p->need_reacquire_db = false;
++	} else {
++		ipts_p->old_head = head;
++		ipts_p->old_tail = tail;
++		ipts_p->need_reacquire_db = true;
++
++		// recheck
++		schedule_delayed_work(&ipts_p->reacquire_db_work,
++			msecs_to_jiffies(DB_LOST_CHECK_STEP2_INTERVAL));
++		return;
++	}
++
++reschedule_work:
++	schedule_delayed_work(&ipts_p->reacquire_db_work,
++		msecs_to_jiffies(DB_LOST_CHECK_STEP1_INTERVAL));
++}
++
++/**
++ * ipts_init - Initialize ipts support
++ * @dev: drm device
++ *
++ * Setup the required structures for ipts.
++ */
++int ipts_init(struct drm_device *dev)
++{
++	int ret = 0;
++
++	pr_info("ipts: initializing ipts\n");
++
++	ipts.dev = dev;
++	INIT_DELAYED_WORK(&ipts.reacquire_db_work,
++		reacquire_db_work_func);
++
++	ret = create_ipts_context();
++	if (ret)
++		return -ENOMEM;
++
++	ret = ipts_init_wq();
++	if (ret)
++		return ret;
++
++	ipts.initialized = true;
++	pr_info("ipts: Intel iTouch framework initialized\n");
++
++	return ret;
++}
++
++void ipts_cleanup(struct drm_device *dev)
++{
++	struct ipts_object *obj, *n;
++
++	if (ipts.dev != dev)
++		return;
++
++	list_for_each_entry_safe(obj, n, &ipts.buffers.list, list) {
++		struct i915_vma *vma, *vn;
++
++		list_for_each_entry_safe(vma, vn, &obj->list, obj_link) {
++			vma->flags &= ~I915_VMA_PIN_MASK;
++			i915_vma_destroy(vma);
++		}
++
++		list_del(&obj->list);
++
++		if (!obj->gem_obj->phys_handle)
++			ipts_object_unmap(obj);
++
++		ipts_object_unpin(obj);
++		i915_gem_free_object(&obj->gem_obj->base);
++		kfree(obj);
++	}
++
++	ipts_release_wq();
++	destroy_ipts_context();
++	cancel_delayed_work(&ipts.reacquire_db_work);
++}
+diff --git a/drivers/gpu/drm/i915/intel_ipts.h b/drivers/gpu/drm/i915/intel_ipts.h
+new file mode 100644
+index 000000000000..67f90b72f237
+--- /dev/null
++++ b/drivers/gpu/drm/i915/intel_ipts.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright © 2016 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ *
++ */
++#ifndef _INTEL_IPTS_H_
++#define _INTEL_IPTS_H_
++
++#include <drm/drm_device.h>
++
++int ipts_init(struct drm_device *dev);
++void ipts_cleanup(struct drm_device *dev);
++int ipts_notify_backlight_status(bool backlight_on);
++int ipts_notify_complete(void);
++
++#endif //_INTEL_IPTS_H_
+diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
+index 13e97faabaa7..a4af67d3d6ff 100644
+--- a/drivers/gpu/drm/i915/intel_lrc.c
++++ b/drivers/gpu/drm/i915/intel_lrc.c
+@@ -164,9 +164,6 @@
+ #define WA_TAIL_DWORDS 2
+ #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS)
+ 
+-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
+-					    struct intel_engine_cs *engine,
+-					    struct intel_context *ce);
+ static void execlists_init_reg_state(u32 *reg_state,
+ 				     struct i915_gem_context *ctx,
+ 				     struct intel_engine_cs *engine,
+@@ -1292,7 +1289,7 @@ static void execlists_context_destroy(struct intel_context *ce)
+ 	i915_gem_object_put(ce->state->obj);
+ }
+ 
+-static void execlists_context_unpin(struct intel_context *ce)
++void execlists_context_unpin(struct intel_context *ce)
+ {
+ 	intel_ring_unpin(ce->ring);
+ 
+@@ -1379,7 +1376,7 @@ static const struct intel_context_ops execlists_context_ops = {
+ 	.destroy = execlists_context_destroy,
+ };
+ 
+-static struct intel_context *
++struct intel_context *
+ execlists_context_pin(struct intel_engine_cs *engine,
+ 		      struct i915_gem_context *ctx)
+ {
+@@ -2479,6 +2476,9 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
+ 
+ 	logical_ring_setup(engine);
+ 
++	engine->irq_keep_mask |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT
++							<< GEN8_RCS_IRQ_SHIFT;
++
+ 	if (HAS_L3_DPF(dev_priv))
+ 		engine->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+ 
+@@ -2743,7 +2743,7 @@ populate_lr_context(struct i915_gem_context *ctx,
+ 	return ret;
+ }
+ 
+-static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
++int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
+ 					    struct intel_engine_cs *engine,
+ 					    struct intel_context *ce)
+ {
+diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
+index 4dfb78e3ec7e..32159231a16e 100644
+--- a/drivers/gpu/drm/i915/intel_lrc.h
++++ b/drivers/gpu/drm/i915/intel_lrc.h
+@@ -106,4 +106,12 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv);
+ 
+ void intel_execlists_set_default_submission(struct intel_engine_cs *engine);
+ 
++struct intel_context *
++execlists_context_pin(struct intel_engine_cs *engine,
++		      struct i915_gem_context *ctx);
++void execlists_context_unpin(struct intel_context *ce);
++int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
++					    struct intel_engine_cs *engine,
++						struct intel_context *ce);
++
+ #endif /* _INTEL_LRC_H_ */
+diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
+index 4a9f139e7b73..c137a57f6702 100644
+--- a/drivers/gpu/drm/i915/intel_panel.c
++++ b/drivers/gpu/drm/i915/intel_panel.c
+@@ -34,6 +34,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/pwm.h>
+ #include "intel_drv.h"
++#include "intel_ipts.h"
+ 
+ #define CRC_PMIC_PWM_PERIOD_NS	21333
+ 
+@@ -659,6 +660,9 @@ static void lpt_disable_backlight(const struct drm_connector_state *old_conn_sta
+ 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ 	u32 tmp;
+ 
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		ipts_notify_backlight_status(false);
++
+ 	intel_panel_actually_set_backlight(old_conn_state, 0);
+ 
+ 	/*
+@@ -846,6 +850,9 @@ static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
+ 
+ 	/* This won't stick until the above enable. */
+ 	intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
++
++	if (INTEL_GEN(dev_priv) >= 9 && i915_modparams.enable_guc && i915_modparams.enable_ipts)
++		ipts_notify_backlight_status(true);
+ }
+ 
+ static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index e723156057a6..11795c7a1662 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -290,8 +290,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
+ 
+ 	/* Total size check: Allow for possible report index byte */
+ 	if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) {
+-		hid_err(parser->device, "report is too long\n");
+-		return -1;
++		hid_warn(parser->device, "report is too long (%u), skipping\n",
++			 report->size);
++		return 0;
+ 	}
+ 
+ 	if (!parser->local.usage_index) /* Ignore padding fields */
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 3726eacdf65d..77263b5f5915 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -520,6 +520,7 @@ source "drivers/misc/ti-st/Kconfig"
+ source "drivers/misc/lis3lv02d/Kconfig"
+ source "drivers/misc/altera-stapl/Kconfig"
+ source "drivers/misc/mei/Kconfig"
++source "drivers/misc/ipts/Kconfig"
+ source "drivers/misc/vmw_vmci/Kconfig"
+ source "drivers/misc/mic/Kconfig"
+ source "drivers/misc/genwqe/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index af22bbc3d00c..eb1eb0d58c32 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -44,6 +44,7 @@ obj-y				+= lis3lv02d/
+ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
+ obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
+ obj-$(CONFIG_INTEL_MEI)		+= mei/
++obj-$(CONFIG_INTEL_IPTS)	+= ipts/
+ obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
+ obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
+ obj-$(CONFIG_SRAM)		+= sram.o
+diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig
+new file mode 100644
+index 000000000000..900d2c58ca74
+--- /dev/null
++++ b/drivers/misc/ipts/Kconfig
+@@ -0,0 +1,12 @@
++# SPDX-License-Identifier: GPL-2.0-or-later
++config INTEL_IPTS
++	tristate "Intel Precise Touch & Stylus"
++	select INTEL_MEI
++	depends on X86 && PCI && HID && DRM_I915
++	help
++	  Intel Precise Touch & Stylus support
++	  Supported SoCs:
++	  Intel Skylake
++	  Intel Kabylake
++
++source "drivers/misc/ipts/companion/Kconfig"
+diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile
+new file mode 100644
+index 000000000000..bb3982f48afc
+--- /dev/null
++++ b/drivers/misc/ipts/Makefile
+@@ -0,0 +1,19 @@
++# SPDX-License-Identifier: GPL-2.0-or-later
++#
++# Makefile - Intel Precise Touch & Stylus device driver
++# Copyright (c) 2016 Intel Corporation
++#
++
++obj-$(CONFIG_INTEL_IPTS)+= intel-ipts.o
++intel-ipts-objs += companion.o
++intel-ipts-objs += ipts.o
++intel-ipts-objs += mei.o
++intel-ipts-objs += hid.o
++intel-ipts-objs += msg-handler.o
++intel-ipts-objs += kernel.o
++intel-ipts-objs += params.o
++intel-ipts-objs += resource.o
++intel-ipts-objs += gfx.o
++intel-ipts-$(CONFIG_DEBUG_FS) += dbgfs.o
++
++obj-y += companion/
+diff --git a/drivers/misc/ipts/companion.c b/drivers/misc/ipts/companion.c
+new file mode 100644
+index 000000000000..c8199d8be5d6
+--- /dev/null
++++ b/drivers/misc/ipts/companion.c
+@@ -0,0 +1,230 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/firmware.h>
++#include <linux/ipts.h>
++#include <linux/ipts-binary.h>
++#include <linux/ipts-companion.h>
++#include <linux/mutex.h>
++
++#include "companion.h"
++#include "ipts.h"
++#include "params.h"
++
++#define IPTS_FW_PATH_FMT "intel/ipts/%s"
++#define IPTS_FW_CONFIG_FILE "ipts_fw_config.bin"
++
++struct ipts_companion *ipts_companion;
++DEFINE_MUTEX(ipts_companion_lock);
++
++bool ipts_companion_available(void)
++{
++	bool ret;
++
++	mutex_lock(&ipts_companion_lock);
++
++	ret = ipts_companion != NULL;
++
++	mutex_unlock(&ipts_companion_lock);
++
++	return ret;
++}
++
++/*
++ * General purpose API for adding or removing a companion driver
++ * A companion driver is a driver that implements hardware specific
++ * behaviour into IPTS, so it doesn't have to be hardcoded into the
++ * main driver. All requests to the companion driver should be wrapped,
++ * with a fallback in case a companion driver cannot be found.
++ */
++
++int ipts_add_companion(struct ipts_companion *companion)
++{
++	int ret;
++
++	// Make sure that access to the companion is synchronized
++	mutex_lock(&ipts_companion_lock);
++
++	if (ipts_companion == NULL) {
++		ret = 0;
++		ipts_companion = companion;
++	} else {
++		ret = -EBUSY;
++	}
++
++	mutex_unlock(&ipts_companion_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(ipts_add_companion);
++
++int ipts_remove_companion(struct ipts_companion *companion)
++{
++	int ret;
++
++	// Make sure that access to the companion is synchronized
++	mutex_lock(&ipts_companion_lock);
++
++	if (ipts_companion != NULL && companion != NULL &&
++			ipts_companion->name != companion->name) {
++		ret = -EPERM;
++	} else {
++		ret = 0;
++		ipts_companion = NULL;
++	}
++
++	mutex_unlock(&ipts_companion_lock);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(ipts_remove_companion);
++
++/*
++ * Utility functions for IPTS. These functions replace codepaths in the IPTS
++ * driver, and redirect them to the companion driver, if one was found.
++ * Otherwise the legacy code gets executed as a fallback.
++ */
++
++int ipts_request_firmware(const struct firmware **fw, const char *name,
++		struct device *device)
++{
++	int ret = 0;
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++
++	// Make sure that access to the companion is synchronized
++	mutex_lock(&ipts_companion_lock);
++
++	// Check if a companion was registered. If not, skip
++	// forward and try to load the firmware from the legacy path
++	if (ipts_companion == NULL || ipts_modparams.ignore_companion)
++		goto request_firmware_fallback;
++
++	ret = ipts_companion->firmware_request(ipts_companion, fw,
++		name, device);
++	if (!ret)
++		goto request_firmware_return;
++
++request_firmware_fallback:
++
++	// If fallback loading for firmware was disabled, abort.
++	// Return -ENOENT as no firmware file was found.
++	if (ipts_modparams.ignore_fw_fallback) {
++		ret = -ENOENT;
++		goto request_firmware_return;
++	}
++
++	// No firmware was found by the companion driver, try the generic path.
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, name);
++	ret = request_firmware(fw, fw_path, device);
++
++request_firmware_return:
++
++	mutex_unlock(&ipts_companion_lock);
++
++	return ret;
++}
++
++static struct ipts_bin_fw_list *ipts_alloc_fw_list(
++		struct ipts_bin_fw_info **fw)
++{
++	int size, len, i, j;
++	struct ipts_bin_fw_list *fw_list;
++	char *itr;
++
++	// Figure out the amount of firmware files inside of the array
++	len = 0;
++	while (fw[len] != NULL)
++		len++;
++
++	// Determine the size that the final list will need in memory
++	size = sizeof(struct ipts_bin_fw_list);
++	for (i = 0; i < len; i++) {
++		size += sizeof(struct ipts_bin_fw_info);
++		size += sizeof(struct ipts_bin_data_file_info) *
++			fw[i]->num_of_data_files;
++	}
++
++	fw_list = kmalloc(size, GFP_KERNEL);
++	fw_list->num_of_fws = len;
++
++	itr = (char *)fw_list->fw_info;
++	for (i = 0; i < len; i++) {
++		*(struct ipts_bin_fw_info *)itr = *fw[i];
++
++		itr += sizeof(struct ipts_bin_fw_info);
++
++		for (j = 0; j < fw[i]->num_of_data_files; j++) {
++			*(struct ipts_bin_data_file_info *)itr =
++				fw[i]->data_file[j];
++
++			itr += sizeof(struct ipts_bin_data_file_info);
++		}
++	}
++
++	return fw_list;
++}
++
++int ipts_request_firmware_config(struct ipts_info *ipts,
++		struct ipts_bin_fw_list **cfg)
++{
++	int ret;
++	const struct firmware *config_fw = NULL;
++
++	// Make sure that access to the companion is synchronized
++	mutex_lock(&ipts_companion_lock);
++
++	// Check if a companion was registered. If not, skip
++	// forward and try to load the firmware config from a file
++	if (ipts_modparams.ignore_companion || ipts_companion == NULL) {
++		mutex_unlock(&ipts_companion_lock);
++		goto config_fallback;
++	}
++
++	if (ipts_companion->firmware_config != NULL) {
++		*cfg = ipts_alloc_fw_list(ipts_companion->firmware_config);
++		mutex_unlock(&ipts_companion_lock);
++		return 0;
++	}
++
++config_fallback:
++
++	// If fallback loading for the firmware config was disabled, abort.
++	// Return -ENOENT as no config file was found.
++	if (ipts_modparams.ignore_config_fallback)
++		return -ENOENT;
++
++	// No firmware config was found by the companion driver,
++	// try loading it from a file now
++	ret = ipts_request_firmware(&config_fw, IPTS_FW_CONFIG_FILE,
++		&ipts->cldev->dev);
++	if (!ret)
++		*cfg = (struct ipts_bin_fw_list *)config_fw->data;
++	else
++		release_firmware(config_fw);
++
++	return ret;
++
++}
++
++unsigned int ipts_get_quirks(void)
++{
++	unsigned int ret;
++
++	// Make sure that access to the companion is synchronized
++	mutex_lock(&ipts_companion_lock);
++
++	// If the companion is ignored, or doesn't exist, assume that
++	// the device doesn't have any quirks
++	if (ipts_modparams.ignore_companion || ipts_companion == NULL)
++		ret = IPTS_QUIRK_NONE;
++	else
++		ret = ipts_companion->get_quirks(ipts_companion);
++
++	mutex_unlock(&ipts_companion_lock);
++
++	return ret;
++}
+diff --git a/drivers/misc/ipts/companion.h b/drivers/misc/ipts/companion.h
+new file mode 100644
+index 000000000000..bb3368b41a38
+--- /dev/null
++++ b/drivers/misc/ipts/companion.h
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_COMPANION_H_
++#define _IPTS_COMPANION_H_
++
++#include <linux/firmware.h>
++#include <linux/ipts-binary.h>
++
++#include "ipts.h"
++
++bool ipts_companion_available(void);
++unsigned int ipts_get_quirks(void);
++
++int ipts_request_firmware(const struct firmware **fw, const char *name,
++		struct device *device);
++
++int ipts_request_firmware_config(struct ipts_info *ipts,
++		struct ipts_bin_fw_list **firmware_config);
++
++#endif // _IPTS_COMPANION_H_
+diff --git a/drivers/misc/ipts/companion/Kconfig b/drivers/misc/ipts/companion/Kconfig
+new file mode 100644
+index 000000000000..ef17d9bb5242
+--- /dev/null
++++ b/drivers/misc/ipts/companion/Kconfig
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0-or-later
++config INTEL_IPTS_SURFACE
++	tristate "IPTS companion driver for Microsoft Surface"
++	depends on INTEL_IPTS && ACPI
++	help
++	  IPTS companion driver for Microsoft Surface. This driver is
++	  responsible for loading firmware using surface-specific hardware IDs.
++	  If you have a Microsoft Surface using IPTS, select y or m here.
+diff --git a/drivers/misc/ipts/companion/Makefile b/drivers/misc/ipts/companion/Makefile
+new file mode 100644
+index 000000000000..b37f2f59937a
+--- /dev/null
++++ b/drivers/misc/ipts/companion/Makefile
+@@ -0,0 +1,2 @@
++# SPDX-License-Identifier: GPL-2.0-or-later
++obj-$(CONFIG_INTEL_IPTS_SURFACE)+= ipts-surface.o
+diff --git a/drivers/misc/ipts/companion/ipts-surface.c b/drivers/misc/ipts/companion/ipts-surface.c
+new file mode 100644
+index 000000000000..1a151538b898
+--- /dev/null
++++ b/drivers/misc/ipts/companion/ipts-surface.c
+@@ -0,0 +1,224 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ * Copyright (c) 2019 Dorian Stoll
++ *
++ */
++
++#include <linux/acpi.h>
++#include <linux/firmware.h>
++#include <linux/ipts.h>
++#include <linux/ipts-companion.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#define IPTS_SURFACE_FW_PATH_FMT "intel/ipts/%s/%s"
++
++/*
++ * checkpatch complains about this and wants it wrapped with do { } while(0);
++ * Since this would absolutely not work, just ignore checkpatch in this case.
++ */
++#define IPTS_SURFACE_FIRMWARE(X)					\
++	MODULE_FIRMWARE("intel/ipts/" X "/config.bin");			\
++	MODULE_FIRMWARE("intel/ipts/" X "/intel_desc.bin");		\
++	MODULE_FIRMWARE("intel/ipts/" X "/vendor_desc.bin");		\
++	MODULE_FIRMWARE("intel/ipts/" X "/vendor_kernel.bin")
++
++struct ipts_surface_data {
++	const char *hid;
++	unsigned int quirks;
++};
++
++// Surface Book 1 / Surface Studio
++static const struct ipts_surface_data ipts_surface_mshw0076 = {
++	.hid = "MSHW0076",
++	.quirks = IPTS_QUIRK_NO_FEEDBACK,
++};
++
++// Surface Pro 4
++static const struct ipts_surface_data ipts_surface_mshw0078 = {
++	.hid = "MSHW0078",
++	.quirks = IPTS_QUIRK_NO_FEEDBACK,
++};
++
++// Surface Laptop 1 / 2
++static const struct ipts_surface_data ipts_surface_mshw0079 = {
++	.hid = "MSHW0079",
++	.quirks = IPTS_QUIRK_NONE,
++};
++
++// Surface Pro 5 / 6
++static const struct ipts_surface_data ipts_surface_mshw0101 = {
++	.hid = "MSHW0101",
++	.quirks = IPTS_QUIRK_NONE,
++};
++
++// Surface Book 2 15"
++static const struct ipts_surface_data ipts_surface_mshw0102 = {
++	.hid = "MSHW0102",
++	.quirks = IPTS_QUIRK_NONE,
++};
++
++// Unknown, but firmware exists
++static const struct ipts_surface_data ipts_surface_mshw0103 = {
++	.hid = "MSHW0103",
++	.quirks = IPTS_QUIRK_NONE,
++};
++
++// Surface Book 2 13"
++static const struct ipts_surface_data ipts_surface_mshw0137 = {
++	.hid = "MSHW0137",
++	.quirks = IPTS_QUIRK_NONE,
++};
++
++/*
++ * Checkpatch complains about the following lines because it sees them as
++ * header files mixed with .c files. However, forward declaration is perfectly
++ * fine in C, and this allows us to seperate the companion data from the
++ * functions for the companion.
++ */
++int ipts_surface_request_firmware(struct ipts_companion *companion,
++		const struct firmware **fw, const char *name,
++		struct device *device);
++
++unsigned int ipts_surface_get_quirks(struct ipts_companion *companion);
++
++static struct ipts_bin_fw_info ipts_surface_vendor_kernel = {
++	.fw_name = "vendor_kernel.bin",
++	.vendor_output = -1,
++	.num_of_data_files = 3,
++	.data_file = {
++		{
++			.io_buffer_type = IPTS_CONFIGURATION,
++			.flags = IPTS_DATA_FILE_FLAG_NONE,
++			.file_name = "config.bin",
++		},
++
++		// The following files are part of the config, but they don't
++		// exist, and the driver never requests them.
++		{
++			.io_buffer_type = IPTS_CALIBRATION,
++			.flags = IPTS_DATA_FILE_FLAG_NONE,
++			.file_name = "calib.bin",
++		},
++		{
++			.io_buffer_type = IPTS_FEATURE,
++			.flags = IPTS_DATA_FILE_FLAG_SHARE,
++			.file_name = "feature.bin",
++		},
++	},
++};
++
++static struct ipts_bin_fw_info *ipts_surface_fw_config[] = {
++	&ipts_surface_vendor_kernel,
++	NULL,
++};
++
++static struct ipts_companion ipts_surface_companion = {
++	.firmware_request = &ipts_surface_request_firmware,
++	.firmware_config = ipts_surface_fw_config,
++	.get_quirks = &ipts_surface_get_quirks,
++	.name = "ipts_surface",
++};
++
++int ipts_surface_request_firmware(struct ipts_companion *companion,
++		const struct firmware **fw, const char *name,
++		struct device *device)
++{
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++	struct ipts_surface_data *data;
++
++	if (companion == NULL || companion->data == NULL)
++		return -ENOENT;
++
++	data = (struct ipts_surface_data *)companion->data;
++
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_SURFACE_FW_PATH_FMT,
++		data->hid, name);
++	return request_firmware(fw, fw_path, device);
++}
++
++unsigned int ipts_surface_get_quirks(struct ipts_companion *companion)
++{
++	struct ipts_surface_data *data;
++
++	// In case something went wrong, assume that the
++	// device doesn't have any quirks
++	if (companion == NULL || companion->data == NULL)
++		return IPTS_QUIRK_NONE;
++
++	data = (struct ipts_surface_data *)companion->data;
++
++	return data->quirks;
++}
++
++static int ipts_surface_probe(struct platform_device *pdev)
++{
++	int r;
++	const struct ipts_surface_data *data =
++		acpi_device_get_match_data(&pdev->dev);
++
++	if (!data) {
++		dev_err(&pdev->dev, "Unable to find ACPI info for device\n");
++		return -ENODEV;
++	}
++
++	ipts_surface_companion.data = (void *)data;
++
++	r = ipts_add_companion(&ipts_surface_companion);
++	if (r) {
++		dev_warn(&pdev->dev, "Adding IPTS companion failed: %d\n", r);
++		return r;
++	}
++
++	return 0;
++}
++
++static int ipts_surface_remove(struct platform_device *pdev)
++{
++	int r = ipts_remove_companion(&ipts_surface_companion);
++
++	if (r) {
++		dev_warn(&pdev->dev, "Removing IPTS companion failed: %d\n", r);
++		return r;
++	}
++
++	return 0;
++}
++
++static const struct acpi_device_id ipts_surface_acpi_match[] = {
++	{ "MSHW0076", (unsigned long)&ipts_surface_mshw0076 },
++	{ "MSHW0078", (unsigned long)&ipts_surface_mshw0078 },
++	{ "MSHW0079", (unsigned long)&ipts_surface_mshw0079 },
++	{ "MSHW0101", (unsigned long)&ipts_surface_mshw0101 },
++	{ "MSHW0102", (unsigned long)&ipts_surface_mshw0102 },
++	{ "MSHW0103", (unsigned long)&ipts_surface_mshw0103 },
++	{ "MSHW0137", (unsigned long)&ipts_surface_mshw0137 },
++	{ },
++};
++MODULE_DEVICE_TABLE(acpi, ipts_surface_acpi_match);
++
++static struct platform_driver ipts_surface_driver = {
++	.probe = ipts_surface_probe,
++	.remove = ipts_surface_remove,
++	.driver = {
++		.name = "ipts_surface",
++		.acpi_match_table = ACPI_PTR(ipts_surface_acpi_match),
++	},
++};
++module_platform_driver(ipts_surface_driver);
++
++MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
++MODULE_DESCRIPTION("IPTS companion driver for Microsoft Surface");
++MODULE_LICENSE("GPL v2");
++
++IPTS_SURFACE_FIRMWARE("MSHW0076");
++IPTS_SURFACE_FIRMWARE("MSHW0078");
++IPTS_SURFACE_FIRMWARE("MSHW0079");
++IPTS_SURFACE_FIRMWARE("MSHW0101");
++IPTS_SURFACE_FIRMWARE("MSHW0102");
++IPTS_SURFACE_FIRMWARE("MSHW0103");
++
++IPTS_SURFACE_FIRMWARE("MSHW0137");
+diff --git a/drivers/misc/ipts/dbgfs.c b/drivers/misc/ipts/dbgfs.c
+new file mode 100644
+index 000000000000..fd9388de17e7
+--- /dev/null
++++ b/drivers/misc/ipts/dbgfs.c
+@@ -0,0 +1,277 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/ctype.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++
++#include "ipts.h"
++#include "msg-handler.h"
++#include "sensor-regs.h"
++#include "state.h"
++#include "../mei/mei_dev.h"
++
++static const char ipts_status_fmt[] = "ipts state : %01d\n";
++static const char ipts_debug_fmt[] = ">> tdt : fw status : %s\n"
++	">> == Doorbell status:%x, count:%x ==\n"
++	">> == Workqueue head:%u, tail:%u ==\n";
++
++static ssize_t ipts_dbgfs_status_read(struct file *fp, char __user *ubuf,
++		size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	char status[256];
++	int len = 0;
++
++	if (cnt < sizeof(ipts_status_fmt) - 3)
++		return -EINVAL;
++
++	len = scnprintf(status, 256, ipts_status_fmt, ipts->state);
++	if (len < 0)
++		return -EIO;
++
++	return simple_read_from_buffer(ubuf, cnt, ppos, status, len);
++}
++
++static const struct file_operations ipts_status_dbgfs_fops = {
++	.open = simple_open,
++	.read = ipts_dbgfs_status_read,
++	.llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_quiesce_io_cmd_write(struct file *fp,
++		const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	bool result;
++	int rc;
++
++	rc = kstrtobool_from_user(ubuf, cnt, &result);
++	if (rc)
++		return rc;
++
++	if (!result)
++		return -EINVAL;
++
++	ipts_send_sensor_quiesce_io_cmd(ipts);
++	return cnt;
++}
++
++static const struct file_operations ipts_quiesce_io_cmd_dbgfs_fops = {
++	.open = simple_open,
++	.write = ipts_dbgfs_quiesce_io_cmd_write,
++	.llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_clear_mem_window_cmd_write(struct file *fp,
++		const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	bool result;
++	int rc;
++
++	rc = kstrtobool_from_user(ubuf, cnt, &result);
++	if (rc)
++		return rc;
++
++	if (!result)
++		return -EINVAL;
++
++	ipts_send_sensor_clear_mem_window_cmd(ipts);
++
++	return cnt;
++}
++
++static const struct file_operations ipts_clear_mem_window_cmd_dbgfs_fops = {
++	.open = simple_open,
++	.write = ipts_dbgfs_clear_mem_window_cmd_write,
++	.llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_debug_read(struct file *fp, char __user *ubuf,
++		size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	char dbg_info[1024];
++	int len = 0;
++
++	char fw_sts_str[MEI_FW_STATUS_STR_SZ];
++	u32 *db, *head, *tail;
++	struct ipts_wq_info *wq_info;
++
++	wq_info = &ipts->resource.wq_info;
++	mei_fw_status_str(ipts->cldev->bus, fw_sts_str, MEI_FW_STATUS_STR_SZ);
++
++	db = (u32 *)wq_info->db_addr;
++	head = (u32 *)wq_info->wq_head_addr;
++	tail = (u32 *)wq_info->wq_tail_addr;
++
++	if (cnt < sizeof(ipts_debug_fmt) - 3)
++		return -EINVAL;
++
++	len = scnprintf(dbg_info, 1024, ipts_debug_fmt,
++		fw_sts_str, *db, *(db+1), *head, *tail);
++
++	if (len < 0)
++		return -EIO;
++
++	return simple_read_from_buffer(ubuf, cnt, ppos, dbg_info, len);
++}
++
++static const struct file_operations ipts_debug_dbgfs_fops = {
++	.open = simple_open,
++	.read = ipts_dbgfs_debug_read,
++	.llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_ipts_restart_write(struct file *fp,
++		const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	bool result;
++	int rc;
++
++	rc = kstrtobool_from_user(ubuf, cnt, &result);
++	if (rc)
++		return rc;
++	if (!result)
++		return -EINVAL;
++
++	ipts_restart(ipts);
++	return cnt;
++}
++
++static const struct file_operations ipts_ipts_restart_dbgfs_fops = {
++	.open = simple_open,
++	.write = ipts_dbgfs_ipts_restart_write,
++	.llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_ipts_stop_write(struct file *fp,
++		const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	bool result;
++	int rc;
++
++	rc = kstrtobool_from_user(ubuf, cnt, &result);
++	if (rc)
++		return rc;
++
++	if (!result)
++		return -EINVAL;
++
++	ipts_stop(ipts);
++	return cnt;
++}
++
++static const struct file_operations ipts_ipts_stop_dbgfs_fops = {
++	.open = simple_open,
++	.write = ipts_dbgfs_ipts_stop_write,
++	.llseek = generic_file_llseek,
++};
++
++static ssize_t ipts_dbgfs_ipts_start_write(struct file *fp,
++		const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++	struct ipts_info *ipts = fp->private_data;
++	bool result;
++	int rc;
++
++	rc = kstrtobool_from_user(ubuf, cnt, &result);
++	if (rc)
++		return rc;
++
++	if (!result)
++		return -EINVAL;
++
++	ipts_start(ipts);
++	return cnt;
++}
++
++static const struct file_operations ipts_ipts_start_dbgfs_fops = {
++	.open = simple_open,
++	.write = ipts_dbgfs_ipts_start_write,
++	.llseek = generic_file_llseek,
++};
++
++void ipts_dbgfs_deregister(struct ipts_info *ipts)
++{
++	if (!ipts->dbgfs_dir)
++		return;
++
++	debugfs_remove_recursive(ipts->dbgfs_dir);
++	ipts->dbgfs_dir = NULL;
++}
++
++int ipts_dbgfs_register(struct ipts_info *ipts, const char *name)
++{
++	struct dentry *dir, *f;
++
++	dir = debugfs_create_dir(name, NULL);
++	if (!dir)
++		return -ENOMEM;
++
++	f = debugfs_create_file("status", 0200, dir, ipts,
++		&ipts_status_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs status creation failed\n");
++		goto err;
++	}
++
++	f = debugfs_create_file("quiesce_io_cmd", 0200, dir, ipts,
++		&ipts_quiesce_io_cmd_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs quiesce_io_cmd creation failed\n");
++		goto err;
++	}
++
++	f = debugfs_create_file("clear_mem_window_cmd", 0200, dir, ipts,
++		&ipts_clear_mem_window_cmd_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs clear_mem_window_cmd creation failed\n");
++		goto err;
++	}
++
++	f = debugfs_create_file("debug", 0200, dir, ipts,
++		&ipts_debug_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs debug creation failed\n");
++		goto err;
++	}
++
++	f = debugfs_create_file("ipts_restart", 0200, dir, ipts,
++		&ipts_ipts_restart_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs ipts_restart creation failed\n");
++		goto err;
++	}
++
++	f = debugfs_create_file("ipts_stop", 0200, dir, ipts,
++		&ipts_ipts_stop_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs ipts_stop creation failed\n");
++		goto err;
++	}
++
++	f = debugfs_create_file("ipts_start", 0200, dir, ipts,
++		&ipts_ipts_start_dbgfs_fops);
++	if (!f) {
++		ipts_err(ipts, "debugfs ipts_start creation failed\n");
++		goto err;
++	}
++
++	ipts->dbgfs_dir = dir;
++
++	return 0;
++
++err:
++	ipts_dbgfs_deregister(ipts);
++
++	return -ENODEV;
++}
+diff --git a/drivers/misc/ipts/gfx.c b/drivers/misc/ipts/gfx.c
+new file mode 100644
+index 000000000000..b8900f514c75
+--- /dev/null
++++ b/drivers/misc/ipts/gfx.c
+@@ -0,0 +1,180 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/kthread.h>
++
++#include "ipts.h"
++#include "msg-handler.h"
++#include "params.h"
++#include "state.h"
++#include "../mei/mei_dev.h"
++
++static void gfx_processing_complete(void *data)
++{
++	struct ipts_info *ipts = data;
++
++	if (ipts_get_state(ipts) == IPTS_STA_RAW_DATA_STARTED) {
++		schedule_work(&ipts->raw_data_work);
++		return;
++	}
++
++	ipts_dbg(ipts, "not ready to handle gfx event\n");
++}
++
++static void notify_gfx_status(u32 status, void *data)
++{
++	struct ipts_info *ipts = data;
++
++	ipts->gfx_status = status;
++	schedule_work(&ipts->gfx_status_work);
++}
++
++static int connect_gfx(struct ipts_info *ipts)
++{
++	int ret = 0;
++	struct ipts_connect connect;
++
++	connect.client = ipts->cldev->dev.parent;
++	connect.if_version = IPTS_INTERFACE_V1;
++	connect.ipts_cb.workload_complete = gfx_processing_complete;
++	connect.ipts_cb.notify_gfx_status = notify_gfx_status;
++	connect.data = (void *)ipts;
++
++	ret = ipts_connect(&connect);
++	if (ret)
++		return ret;
++
++	// TODO: GFX version check
++	ipts->gfx_info.gfx_handle = connect.gfx_handle;
++	ipts->gfx_info.ipts_ops = connect.ipts_ops;
++
++	return ret;
++}
++
++static void disconnect_gfx(struct ipts_info *ipts)
++{
++	ipts_disconnect(ipts->gfx_info.gfx_handle);
++}
++
++static struct task_struct *dbg_thread;
++
++static void ipts_print_dbg_info(struct ipts_info *ipts)
++{
++	char fw_sts_str[MEI_FW_STATUS_STR_SZ];
++	u32 *db, *head, *tail;
++	struct ipts_wq_info *wq_info;
++
++	wq_info = &ipts->resource.wq_info;
++
++	mei_fw_status_str(ipts->cldev->bus, fw_sts_str, MEI_FW_STATUS_STR_SZ);
++	pr_info(">> tdt : fw status : %s\n", fw_sts_str);
++
++	db = (u32 *)wq_info->db_addr;
++	head = (u32 *)wq_info->wq_head_addr;
++	tail = (u32 *)wq_info->wq_tail_addr;
++
++	// Every time the ME has filled up the touch input buffer, and the GuC
++	// doorbell is rang, the doorbell count will increase by one
++	// The workqueue is the queue of touch events that the GuC has to
++	// process. Head is the currently processed event, while tail is
++	// the last one that is currently available. If head and tail are
++	// not equal, this can be an indicator for GuC / GPU hang.
++	pr_info(">> == Doorbell status:%x, count:%x ==\n", *db, *(db+1));
++	pr_info(">> == Workqueue head:%u, tail:%u ==\n", *head, *tail);
++}
++
++static int ipts_dbg_thread(void *data)
++{
++	struct ipts_info *ipts = (struct ipts_info *)data;
++
++	pr_info(">> start debug thread\n");
++
++	while (!kthread_should_stop()) {
++		if (ipts_get_state(ipts) != IPTS_STA_RAW_DATA_STARTED) {
++			pr_info("state is not IPTS_STA_RAW_DATA_STARTED : %d\n",
++				ipts_get_state(ipts));
++
++			msleep(5000);
++			continue;
++		}
++
++		ipts_print_dbg_info(ipts);
++		msleep(3000);
++	}
++
++	return 0;
++}
++
++int ipts_open_gpu(struct ipts_info *ipts)
++{
++	int ret = 0;
++
++	ret = connect_gfx(ipts);
++	if (ret) {
++		ipts_dbg(ipts, "cannot connect GPU\n");
++		return ret;
++	}
++
++	ret = ipts->gfx_info.ipts_ops.get_wq_info(ipts->gfx_info.gfx_handle,
++		&ipts->resource.wq_info);
++	if (ret) {
++		ipts_dbg(ipts, "error in get_wq_info\n");
++		return ret;
++	}
++
++	if (ipts_modparams.debug_thread)
++		dbg_thread = kthread_run(
++			ipts_dbg_thread, (void *)ipts, "ipts_debug");
++
++	return 0;
++}
++
++void ipts_close_gpu(struct ipts_info *ipts)
++{
++	disconnect_gfx(ipts);
++
++	if (ipts_modparams.debug_thread)
++		kthread_stop(dbg_thread);
++}
++
++struct ipts_mapbuffer *ipts_map_buffer(struct ipts_info *ipts,
++		u32 size, u32 flags)
++{
++	struct ipts_mapbuffer *buf;
++	u64 handle;
++	int ret;
++
++	buf = devm_kzalloc(&ipts->cldev->dev, sizeof(*buf), GFP_KERNEL);
++	if (!buf)
++		return NULL;
++
++	buf->size = size;
++	buf->flags = flags;
++
++	handle = ipts->gfx_info.gfx_handle;
++	ret = ipts->gfx_info.ipts_ops.map_buffer(handle, buf);
++	if (ret) {
++		devm_kfree(&ipts->cldev->dev, buf);
++		return NULL;
++	}
++
++	return buf;
++}
++
++void ipts_unmap_buffer(struct ipts_info *ipts, struct ipts_mapbuffer *buf)
++{
++	u64 handle;
++
++	if (!buf)
++		return;
++
++	handle = ipts->gfx_info.gfx_handle;
++	ipts->gfx_info.ipts_ops.unmap_buffer(handle, buf->buf_handle);
++	devm_kfree(&ipts->cldev->dev, buf);
++}
+diff --git a/drivers/misc/ipts/gfx.h b/drivers/misc/ipts/gfx.h
+new file mode 100644
+index 000000000000..2880e122e9f9
+--- /dev/null
++++ b/drivers/misc/ipts/gfx.h
+@@ -0,0 +1,25 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_GFX_H_
++#define _IPTS_GFX_H_
++
++#include <linux/ipts-gfx.h>
++
++#include "ipts.h"
++
++int ipts_open_gpu(struct ipts_info *ipts);
++void ipts_close_gpu(struct ipts_info *ipts);
++
++struct ipts_mapbuffer *ipts_map_buffer(struct ipts_info *ipts,
++		u32 size, u32 flags);
++
++void ipts_unmap_buffer(struct ipts_info *ipts,
++		struct ipts_mapbuffer *buf);
++
++#endif // _IPTS_GFX_H_
+diff --git a/drivers/misc/ipts/hid.c b/drivers/misc/ipts/hid.c
+new file mode 100644
+index 000000000000..3652803b5376
+--- /dev/null
++++ b/drivers/misc/ipts/hid.c
+@@ -0,0 +1,499 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/dmi.h>
++#include <linux/firmware.h>
++#include <linux/hid.h>
++#include <linux/ipts.h>
++#include <linux/module.h>
++#include <linux/vmalloc.h>
++
++#include "companion.h"
++#include "hid.h"
++#include "ipts.h"
++#include "msg-handler.h"
++#include "params.h"
++#include "resource.h"
++#include "sensor-regs.h"
++
++#define HID_DESC_INTEL  "intel_desc.bin"
++#define HID_DESC_VENDOR "vendor_desc.bin"
++
++enum output_buffer_payload_type {
++	OUTPUT_BUFFER_PAYLOAD_ERROR = 0,
++	OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT,
++	OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT,
++	OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD,
++	OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER
++};
++
++struct kernel_output_buffer_header {
++	u16 length;
++	u8 payload_type;
++	u8 reserved1;
++	struct touch_hid_private_data hid_private_data;
++	u8 reserved2[28];
++	u8 data[0];
++};
++
++struct kernel_output_payload_error {
++	u16 severity;
++	u16 source;
++	u8 code[4];
++	char string[128];
++};
++
++static int ipts_hid_get_descriptor(struct ipts_info *ipts,
++		u8 **desc, int *size)
++{
++	u8 *buf;
++	int hid_size = 0, ret = 0;
++	const struct firmware *intel_desc = NULL;
++	const struct firmware *vendor_desc = NULL;
++
++	ret = ipts_request_firmware(&intel_desc, HID_DESC_INTEL,
++		&ipts->cldev->dev);
++	if (ret)
++		goto no_hid;
++
++	hid_size = intel_desc->size;
++
++	ret = ipts_request_firmware(&vendor_desc, HID_DESC_VENDOR,
++			&ipts->cldev->dev);
++	if (ret)
++		ipts_dbg(ipts, "error in reading HID Vendor Descriptor\n");
++	else
++		hid_size += vendor_desc->size;
++
++	ipts_dbg(ipts, "HID descriptor size = %d\n", hid_size);
++
++	buf = vmalloc(hid_size);
++	if (buf == NULL) {
++		ret = -ENOMEM;
++		goto no_mem;
++	}
++
++	memcpy(buf, intel_desc->data, intel_desc->size);
++	if (vendor_desc) {
++		memcpy(&buf[intel_desc->size], vendor_desc->data,
++			vendor_desc->size);
++		release_firmware(vendor_desc);
++	}
++	release_firmware(intel_desc);
++
++	*desc = buf;
++	*size = hid_size;
++
++	return 0;
++
++no_mem:
++	if (vendor_desc)
++		release_firmware(vendor_desc);
++
++	release_firmware(intel_desc);
++
++no_hid:
++	return ret;
++}
++
++static int ipts_hid_parse(struct hid_device *hid)
++{
++	struct ipts_info *ipts = hid->driver_data;
++	int ret = 0, size;
++	u8 *buf;
++
++	ipts_dbg(ipts, "%s() start\n", __func__);
++
++	ret = ipts_hid_get_descriptor(ipts, &buf, &size);
++	if (ret != 0) {
++		ipts_dbg(ipts, "ipts_hid_get_descriptor: %d\n",
++			ret);
++		return -EIO;
++	}
++
++	ret = hid_parse_report(hid, buf, size);
++	vfree(buf);
++	if (ret) {
++		ipts_err(ipts, "hid_parse_report error : %d\n", ret);
++		return ret;
++	}
++
++	ipts->hid_desc_ready = true;
++
++	return 0;
++}
++
++static int ipts_hid_start(struct hid_device *hid)
++{
++	return 0;
++}
++
++static void ipts_hid_stop(struct hid_device *hid)
++{
++
++}
++
++static int ipts_hid_open(struct hid_device *hid)
++{
++	return 0;
++}
++
++static void ipts_hid_close(struct hid_device *hid)
++{
++	struct ipts_info *ipts = hid->driver_data;
++
++	ipts->hid_desc_ready = false;
++}
++
++static int ipts_hid_send_hid2me_feedback(struct ipts_info *ipts,
++		u32 fb_data_type, __u8 *buf, size_t count)
++{
++	struct ipts_buffer_info *fb_buf;
++	struct touch_feedback_hdr *feedback;
++	enum ipts_state state;
++	u8 *payload;
++	int header_size;
++
++	header_size = sizeof(struct touch_feedback_hdr);
++
++	if (count > ipts->resource.hid2me_buffer_size - header_size)
++		return -EINVAL;
++
++	state = ipts_get_state(ipts);
++	if (state != IPTS_STA_RAW_DATA_STARTED &&
++			state != IPTS_STA_HID_STARTED)
++		return 0;
++
++	fb_buf = ipts_get_hid2me_buffer(ipts);
++	feedback = (struct touch_feedback_hdr *)fb_buf->addr;
++	payload = fb_buf->addr + header_size;
++	memset(feedback, 0, header_size);
++
++	feedback->feedback_data_type = fb_data_type;
++	feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE;
++	feedback->payload_size_bytes = count;
++	feedback->buffer_id = TOUCH_HID_2_ME_BUFFER_ID;
++	feedback->protocol_ver = 0;
++	feedback->reserved[0] = 0xAC;
++
++	// copy payload
++	memcpy(payload, buf, count);
++
++	ipts_send_feedback(ipts, TOUCH_HID_2_ME_BUFFER_ID, 0);
++
++	return 0;
++}
++
++static int ipts_hid_raw_request(struct hid_device *hid,
++		unsigned char report_number, __u8 *buf, size_t count,
++		unsigned char report_type, int reqtype)
++{
++	struct ipts_info *ipts = hid->driver_data;
++	u32 fb_data_type;
++
++	ipts_dbg(ipts, "hid raw request => report %d, request %d\n",
++		(int)report_type, reqtype);
++
++	if (report_type != HID_FEATURE_REPORT)
++		return 0;
++
++	switch (reqtype) {
++	case HID_REQ_GET_REPORT:
++		fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES;
++		break;
++	case HID_REQ_SET_REPORT:
++		fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES;
++		break;
++	default:
++		ipts_err(ipts, "raw request not supprted: %d\n", reqtype);
++		return -EIO;
++	}
++
++	return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count);
++}
++
++static int ipts_hid_output_report(struct hid_device *hid,
++		__u8 *buf, size_t count)
++{
++	struct ipts_info *ipts = hid->driver_data;
++	u32 fb_data_type;
++
++	ipts_dbg(ipts, "hid output report\n");
++
++	fb_data_type = TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT;
++
++	return ipts_hid_send_hid2me_feedback(ipts, fb_data_type, buf, count);
++}
++
++static struct hid_ll_driver ipts_hid_ll_driver = {
++	.parse = ipts_hid_parse,
++	.start = ipts_hid_start,
++	.stop = ipts_hid_stop,
++	.open = ipts_hid_open,
++	.close = ipts_hid_close,
++	.raw_request = ipts_hid_raw_request,
++	.output_report = ipts_hid_output_report,
++};
++
++int ipts_hid_init(struct ipts_info *ipts)
++{
++	int ret = 0;
++	struct hid_device *hid;
++
++	hid = hid_allocate_device();
++	if (IS_ERR(hid))
++		return PTR_ERR(hid);
++
++	hid->driver_data = ipts;
++	hid->ll_driver = &ipts_hid_ll_driver;
++	hid->dev.parent = &ipts->cldev->dev;
++	hid->bus = BUS_MEI;
++	hid->version = ipts->device_info.fw_rev;
++	hid->vendor = ipts->device_info.vendor_id;
++	hid->product = ipts->device_info.device_id;
++
++	snprintf(hid->phys, sizeof(hid->phys), "heci3");
++	snprintf(hid->name, sizeof(hid->name),
++		"ipts %04hX:%04hX", hid->vendor, hid->product);
++
++	ret = hid_add_device(hid);
++	if (ret) {
++		if (ret != -ENODEV)
++			ipts_err(ipts, "can't add hid device: %d\n", ret);
++
++		hid_destroy_device(hid);
++
++		return ret;
++	}
++
++	ipts->hid = hid;
++
++	return 0;
++}
++
++void ipts_hid_release(struct ipts_info *ipts)
++{
++	if (!ipts->hid)
++		return;
++
++	hid_destroy_device(ipts->hid);
++}
++
++int ipts_handle_hid_data(struct ipts_info *ipts,
++		struct touch_sensor_hid_ready_for_data_rsp_data *hid_rsp)
++{
++	struct touch_raw_data_hdr *raw_header;
++	struct ipts_buffer_info *buffer_info;
++	struct touch_feedback_hdr *feedback;
++	u8 *raw_data;
++	int touch_data_buffer_index;
++	int transaction_id;
++	int ret = 0;
++
++	touch_data_buffer_index = (int)hid_rsp->touch_data_buffer_index;
++	buffer_info = ipts_get_touch_data_buffer_hid(ipts);
++	raw_header = (struct touch_raw_data_hdr *)buffer_info->addr;
++	transaction_id = raw_header->hid_private_data.transaction_id;
++	raw_data = (u8 *)raw_header + sizeof(struct touch_raw_data_hdr);
++
++	switch (raw_header->data_type) {
++	case TOUCH_RAW_DATA_TYPE_HID_REPORT: {
++		if (raw_header->raw_data_size_bytes > HID_MAX_BUFFER_SIZE)
++			raw_header->raw_data_size_bytes = HID_MAX_BUFFER_SIZE;
++
++		memcpy(ipts->hid_input_report, raw_data,
++			raw_header->raw_data_size_bytes);
++
++		ret = hid_input_report(ipts->hid, HID_INPUT_REPORT,
++			(u8 *)ipts->hid_input_report,
++			raw_header->raw_data_size_bytes, 1);
++		if (ret)
++			ipts_err(ipts, "error in hid_input_report: %d\n", ret);
++
++		break;
++	}
++	case TOUCH_RAW_DATA_TYPE_GET_FEATURES: {
++		// TODO: implement together with "get feature ioctl"
++		break;
++	}
++	case TOUCH_RAW_DATA_TYPE_ERROR: {
++		struct touch_error *touch_err = (struct touch_error *)raw_data;
++
++		ipts_err(ipts, "error type: %d, me error: %x, err reg: %x\n",
++			touch_err->touch_error_type,
++			touch_err->touch_me_fw_error.value,
++			touch_err->touch_error_register.reg_value);
++
++		break;
++	}
++	default:
++		break;
++	}
++
++	// send feedback data for HID mode
++	buffer_info = ipts_get_feedback_buffer(ipts, touch_data_buffer_index);
++	feedback = (struct touch_feedback_hdr *)buffer_info->addr;
++	memset(feedback, 0, sizeof(struct touch_feedback_hdr));
++	feedback->feedback_cmd_type = TOUCH_FEEDBACK_CMD_TYPE_NONE;
++	feedback->payload_size_bytes = 0;
++	feedback->buffer_id = touch_data_buffer_index;
++	feedback->protocol_ver = 0;
++	feedback->reserved[0] = 0xAC;
++
++	ret = ipts_send_feedback(ipts, touch_data_buffer_index, transaction_id);
++
++	return ret;
++}
++
++static int handle_outputs(struct ipts_info *ipts, int parallel_idx)
++{
++	struct kernel_output_buffer_header *out_buf_hdr;
++	struct ipts_buffer_info *output_buf, *fb_buf = NULL;
++	u8 *input_report, *payload;
++	u32 tr_id;
++	int i, payload_size, ret = 0, header_size;
++
++	header_size = sizeof(struct kernel_output_buffer_header);
++	output_buf = ipts_get_output_buffers_by_parallel_id(ipts,
++			parallel_idx);
++
++	for (i = 0; i < ipts->resource.num_of_outputs; i++) {
++		out_buf_hdr = (struct kernel_output_buffer_header *)
++			output_buf[i].addr;
++
++		if (out_buf_hdr->length < header_size)
++			continue;
++
++		payload_size = out_buf_hdr->length - header_size;
++		payload = out_buf_hdr->data;
++
++		switch (out_buf_hdr->payload_type) {
++		case OUTPUT_BUFFER_PAYLOAD_HID_INPUT_REPORT: {
++			input_report = ipts->hid_input_report;
++			memcpy(input_report, payload, payload_size);
++
++			hid_input_report(ipts->hid, HID_INPUT_REPORT,
++				input_report, payload_size, 1);
++
++			break;
++		}
++		case OUTPUT_BUFFER_PAYLOAD_HID_FEATURE_REPORT: {
++			ipts_dbg(ipts, "output hid feature report\n");
++			break;
++		}
++		case OUTPUT_BUFFER_PAYLOAD_KERNEL_LOAD: {
++			ipts_dbg(ipts, "output kernel load\n");
++			break;
++		}
++		case OUTPUT_BUFFER_PAYLOAD_FEEDBACK_BUFFER: {
++			// send feedback data for raw data mode
++			fb_buf = ipts_get_feedback_buffer(ipts, parallel_idx);
++			tr_id = out_buf_hdr->hid_private_data.transaction_id;
++
++			memcpy(fb_buf->addr, payload, payload_size);
++
++			break;
++		}
++		case OUTPUT_BUFFER_PAYLOAD_ERROR: {
++			struct kernel_output_payload_error *err_payload;
++
++			if (payload_size == 0)
++				break;
++
++			err_payload = (struct kernel_output_payload_error *)
++					payload;
++
++			ipts_err(ipts, "severity: %d, source: %d ",
++					err_payload->severity,
++					err_payload->source);
++			ipts_err(ipts, "code : %d:%d:%d:%d\nstring %s\n",
++					err_payload->code[0],
++					err_payload->code[1],
++					err_payload->code[2],
++					err_payload->code[3],
++					err_payload->string);
++
++			break;
++		}
++		default:
++			ipts_err(ipts, "invalid output buffer payload\n");
++			break;
++		}
++	}
++
++	/*
++	 * XXX: Calling the "ipts_send_feedback" function repeatedly seems to
++	 * be what is causing touch to crash (found by sebanc, see the link
++	 * below for the comment) on some models, especially on Surface Pro 4
++	 * and Surface Book 1.
++	 * The most desirable fix could be done by raising IPTS GuC priority.
++	 * Until we find a better solution, use this workaround.
++	 *
++	 * The decision which devices have no_feedback enabled by default is
++	 * made by the companion driver. If no companion driver was loaded,
++	 * no_feedback is disabled and the default behaviour is used.
++	 *
++	 * Link to the comment where sebanc found this workaround:
++	 * https://github.com/jakeday/linux-surface/issues/374#issuecomment-508234110
++	 * (Touch and pen issue persists · Issue #374 · jakeday/linux-surface)
++	 *
++	 * Link to the usage from kitakar5525 who made this change:
++	 * https://github.com/jakeday/linux-surface/issues/374#issuecomment-517289171
++	 * (Touch and pen issue persists · Issue #374 · jakeday/linux-surface)
++	 */
++	if (fb_buf) {
++		// A negative value means "decide by dmi table"
++		if (ipts_modparams.no_feedback < 0) {
++			if (ipts_get_quirks() & IPTS_QUIRK_NO_FEEDBACK)
++				ipts_modparams.no_feedback = true;
++			else
++				ipts_modparams.no_feedback = false;
++		}
++
++		if (ipts_modparams.no_feedback)
++			return 0;
++
++		ret = ipts_send_feedback(ipts, parallel_idx, tr_id);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int handle_output_buffers(struct ipts_info *ipts,
++		int cur_idx, int end_idx)
++{
++	int max_num_of_buffers = ipts_get_num_of_parallel_buffers(ipts);
++
++	do {
++		cur_idx++; // cur_idx has last completed so starts with +1
++		cur_idx %= max_num_of_buffers;
++		handle_outputs(ipts, cur_idx);
++	} while (cur_idx != end_idx);
++
++	return 0;
++}
++
++int ipts_handle_processed_data(struct ipts_info *ipts)
++{
++	int ret = 0;
++	int current_buffer_idx;
++	int last_buffer_idx;
++
++	current_buffer_idx = *ipts->last_submitted_id;
++	last_buffer_idx = ipts->last_buffer_completed;
++
++	if (current_buffer_idx == last_buffer_idx)
++		return 0;
++
++	ipts->last_buffer_completed = current_buffer_idx;
++	handle_output_buffers(ipts, last_buffer_idx, current_buffer_idx);
++
++	return ret;
++}
+diff --git a/drivers/misc/ipts/hid.h b/drivers/misc/ipts/hid.h
+new file mode 100644
+index 000000000000..c943979e0198
+--- /dev/null
++++ b/drivers/misc/ipts/hid.h
+@@ -0,0 +1,21 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_HID_H_
++#define _IPTS_HID_H_
++
++#include "ipts.h"
++
++#define BUS_MEI 0x44
++
++int ipts_hid_init(struct ipts_info *ipts);
++void ipts_hid_release(struct ipts_info *ipts);
++int ipts_handle_hid_data(struct ipts_info *ipts,
++		struct touch_sensor_hid_ready_for_data_rsp_data *hid_rsp);
++
++#endif // _IPTS_HID_H_
+diff --git a/drivers/misc/ipts/ipts.c b/drivers/misc/ipts/ipts.c
+new file mode 100644
+index 000000000000..dfafabf8dd94
+--- /dev/null
++++ b/drivers/misc/ipts/ipts.c
+@@ -0,0 +1,62 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/device.h>
++#include <stdarg.h>
++
++#include "ipts.h"
++#include "params.h"
++
++static void ipts_printk(const char *level, const struct device *dev,
++		struct va_format *vaf)
++{
++	if (dev) {
++		dev_printk_emit(level[1] - '0', dev, "%s %s: %pV",
++			dev_driver_string(dev), dev_name(dev), vaf);
++	} else {
++		// checkpatch wants this to be prefixed with KERN_*, but
++		// since the level is passed as a parameter, ignore it
++		printk("%s(NULL device *): %pV", level, vaf);
++	}
++}
++
++void ipts_info(struct ipts_info *ipts, const char *fmt, ...)
++{
++	va_list args;
++	struct va_format vaf;
++
++	if (!ipts_modparams.debug)
++		return;
++
++	va_start(args, fmt);
++
++	vaf.fmt = fmt;
++	vaf.va = &args;
++
++	ipts_printk(KERN_INFO, &ipts->cldev->dev, &vaf);
++
++	va_end(args);
++}
++
++void ipts_dbg(struct ipts_info *ipts, const char *fmt, ...)
++{
++	va_list args;
++	struct va_format vaf;
++
++	if (!ipts_modparams.debug)
++		return;
++
++	va_start(args, fmt);
++
++	vaf.fmt = fmt;
++	vaf.va = &args;
++
++	ipts_printk(KERN_DEBUG, &ipts->cldev->dev, &vaf);
++
++	va_end(args);
++}
+diff --git a/drivers/misc/ipts/ipts.h b/drivers/misc/ipts/ipts.h
+new file mode 100644
+index 000000000000..32eb3ffd68a3
+--- /dev/null
++++ b/drivers/misc/ipts/ipts.h
+@@ -0,0 +1,172 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_H_
++#define _IPTS_H_
++
++#include <linux/hid.h>
++#include <linux/ipts-binary.h>
++#include <linux/ipts-gfx.h>
++#include <linux/mei_cl_bus.h>
++#include <linux/types.h>
++
++#include "mei-msgs.h"
++#include "state.h"
++
++#define HID_PARALLEL_DATA_BUFFERS TOUCH_SENSOR_MAX_DATA_BUFFERS
++
++#define IPTS_MAX_RETRY 3
++
++struct ipts_buffer_info {
++	char *addr;
++	dma_addr_t dma_addr;
++};
++
++struct ipts_gfx_info {
++	u64 gfx_handle;
++	struct ipts_ops ipts_ops;
++};
++
++struct ipts_resource {
++	// ME & GFX resource
++	struct ipts_buffer_info touch_data_buffer_raw
++		[HID_PARALLEL_DATA_BUFFERS];
++	struct ipts_buffer_info touch_data_buffer_hid;
++	struct ipts_buffer_info feedback_buffer[HID_PARALLEL_DATA_BUFFERS];
++	struct ipts_buffer_info hid2me_buffer;
++	u32 hid2me_buffer_size;
++
++	u8 wq_item_size;
++	struct ipts_wq_info wq_info;
++
++	// ME2HID buffer
++	char *me2hid_buffer;
++
++	// GFX specific resource
++	struct ipts_buffer_info raw_data_mode_output_buffer
++		[HID_PARALLEL_DATA_BUFFERS][MAX_NUM_OUTPUT_BUFFERS];
++
++	int num_of_outputs;
++	bool default_resource_ready;
++	bool raw_data_resource_ready;
++};
++
++struct ipts_info {
++	struct mei_cl_device *cldev;
++	struct hid_device *hid;
++
++	struct work_struct init_work;
++	struct work_struct raw_data_work;
++	struct work_struct gfx_status_work;
++
++	struct task_struct *event_loop;
++
++#if IS_ENABLED(CONFIG_DEBUG_FS)
++	struct dentry *dbgfs_dir;
++#endif
++
++	enum ipts_state state;
++
++	enum touch_sensor_mode sensor_mode;
++	struct touch_sensor_get_device_info_rsp_data device_info;
++	struct ipts_resource resource;
++	u8 hid_input_report[HID_MAX_BUFFER_SIZE];
++	int num_of_parallel_data_buffers;
++	bool hid_desc_ready;
++
++	int current_buffer_index;
++	int last_buffer_completed;
++	int *last_submitted_id;
++
++	struct ipts_gfx_info gfx_info;
++	u64 kernel_handle;
++	int gfx_status;
++	bool display_status;
++
++	bool restart;
++};
++
++#if IS_ENABLED(CONFIG_DEBUG_FS)
++int ipts_dbgfs_register(struct ipts_info *ipts, const char *name);
++void ipts_dbgfs_deregister(struct ipts_info *ipts);
++#else
++static int ipts_dbgfs_register(struct ipts_info *ipts, const char *name);
++static void ipts_dbgfs_deregister(struct ipts_info *ipts);
++#endif
++
++void ipts_info(struct ipts_info *ipts, const char *fmt, ...);
++void ipts_dbg(struct ipts_info *ipts, const char *fmt, ...);
++
++// Because ipts_err is unconditional, this can stay a macro for now
++#define ipts_err(ipts, format, arg...) \
++	dev_err(&ipts->cldev->dev, format, ##arg)
++
++/*
++ * Inline functions
++ */
++static inline void ipts_set_state(struct ipts_info *ipts,
++		enum ipts_state state)
++{
++	ipts->state = state;
++}
++
++static inline enum ipts_state ipts_get_state(const struct ipts_info *ipts)
++{
++	return ipts->state;
++}
++
++static inline bool ipts_is_default_resource_ready(const struct ipts_info *ipts)
++{
++	return ipts->resource.default_resource_ready;
++}
++
++static inline bool ipts_is_raw_data_resource_ready(const struct ipts_info *ipts)
++{
++	return ipts->resource.raw_data_resource_ready;
++}
++
++static inline struct ipts_buffer_info *ipts_get_feedback_buffer(
++		struct ipts_info *ipts, int buffer_idx)
++{
++	return &ipts->resource.feedback_buffer[buffer_idx];
++}
++
++static inline struct ipts_buffer_info *ipts_get_touch_data_buffer_hid(
++		struct ipts_info *ipts)
++{
++	return &ipts->resource.touch_data_buffer_hid;
++}
++
++static inline struct ipts_buffer_info *ipts_get_output_buffers_by_parallel_id(
++		struct ipts_info *ipts, int parallel_idx)
++{
++	return &ipts->resource.raw_data_mode_output_buffer[parallel_idx][0];
++}
++
++static inline struct ipts_buffer_info *ipts_get_hid2me_buffer(
++		struct ipts_info *ipts)
++{
++	return &ipts->resource.hid2me_buffer;
++}
++
++static inline void ipts_set_wq_item_size(struct ipts_info *ipts, u8 size)
++{
++	ipts->resource.wq_item_size = size;
++}
++
++static inline u8 ipts_get_wq_item_size(const struct ipts_info *ipts)
++{
++	return ipts->resource.wq_item_size;
++}
++
++static inline int ipts_get_num_of_parallel_buffers(const struct ipts_info *ipts)
++{
++	return ipts->num_of_parallel_data_buffers;
++}
++
++#endif // _IPTS_H_
+diff --git a/drivers/misc/ipts/kernel.c b/drivers/misc/ipts/kernel.c
+new file mode 100644
+index 000000000000..a2c43228e2c7
+--- /dev/null
++++ b/drivers/misc/ipts/kernel.c
+@@ -0,0 +1,1047 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/ipts.h>
++#include <linux/ipts-binary.h>
++#include <linux/vmalloc.h>
++
++#include "companion.h"
++#include "gfx.h"
++#include "ipts.h"
++#include "msg-handler.h"
++#include "resource.h"
++#include "state.h"
++
++#define BDW_SURFACE_BASE_ADDRESS   0x6101000e
++#define SURFACE_STATE_OFFSET_WORD  4
++#define SBA_OFFSET_BYTES           16384
++#define LASTSUBMITID_DEFAULT_VALUE -1
++
++#define IPTS_INPUT_ON          ((u32)1 << IPTS_INPUT)
++#define IPTS_OUTPUT_ON         ((u32)1 << IPTS_OUTPUT)
++#define IPTS_CONFIGURATION_ON  ((u32)1 << IPTS_CONFIGURATION)
++#define IPTS_CALIBRATION_ON    ((u32)1 << IPTS_CALIBRATION)
++#define IPTS_FEATURE_ON        ((u32)1 << IPTS_FEATURE)
++
++// OpenCL kernel
++struct bin_workload {
++	int cmdbuf_index;
++	int iobuf_input;
++	int iobuf_output[MAX_NUM_OUTPUT_BUFFERS];
++};
++
++struct bin_buffer {
++	unsigned int handle;
++	struct ipts_mapbuffer *buf;
++
++	// only releasing vendor kernel unmaps output buffers
++	bool no_unmap;
++};
++
++struct bin_alloc_info {
++	struct bin_buffer *buffs;
++	int num_of_allocations;
++	int num_of_outputs;
++
++	int num_of_buffers;
++};
++
++struct bin_guc_wq_item {
++	unsigned int batch_offset;
++	unsigned int size;
++	char data[];
++};
++
++struct bin_kernel_info {
++	struct bin_workload *wl;
++	struct bin_alloc_info *alloc_info;
++	struct bin_guc_wq_item *guc_wq_item;
++	struct ipts_bin_bufid_patch bufid_patch;
++
++	// 1: vendor, 0: postprocessing
++	bool is_vendor;
++};
++
++struct bin_kernel_list {
++	struct ipts_mapbuffer *bufid_buf;
++	int num_of_kernels;
++	struct bin_kernel_info kernels[];
++};
++
++struct bin_parse_info {
++	u8 *data;
++	int size;
++	int parsed;
++
++	struct ipts_bin_fw_info *fw_info;
++
++	// only used by postprocessing
++	struct bin_kernel_info *vendor_kernel;
++
++	// interested vendor output index
++	u32 interested_vendor_output;
++};
++
++static int bin_read_fw(struct ipts_info *ipts, const char *fw_name,
++		u8 *data, int size)
++{
++	const struct firmware *fw = NULL;
++	int ret = 0;
++
++	ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
++	if (ret) {
++		ipts_err(ipts, "cannot read fw %s\n", fw_name);
++		return ret;
++	}
++
++	if (fw->size > size) {
++		ipts_dbg(ipts, "too small buffer to contain fw data\n");
++		ret = -EINVAL;
++	} else {
++		memcpy(data, fw->data, fw->size);
++	}
++
++	release_firmware(fw);
++
++	return ret;
++}
++
++
++static struct ipts_bin_data_file_info *bin_get_data_file_info(
++		struct ipts_bin_fw_info *fw_info, u32 io_buffer_type)
++{
++	int i;
++
++	for (i = 0; i < fw_info->num_of_data_files; i++) {
++		if (fw_info->data_file[i].io_buffer_type == io_buffer_type)
++			break;
++	}
++
++	if (i == fw_info->num_of_data_files)
++		return NULL;
++
++	return &fw_info->data_file[i];
++}
++
++static inline bool is_shared_data(
++		const struct ipts_bin_data_file_info *data_file)
++{
++	if (!data_file)
++		return false;
++
++	return (!!(data_file->flags & IPTS_DATA_FILE_FLAG_SHARE));
++}
++
++static inline bool is_alloc_cont_data(
++		const struct ipts_bin_data_file_info *data_file)
++{
++	if (!data_file)
++		return false;
++
++	return (!!(data_file->flags & IPTS_DATA_FILE_FLAG_ALLOC_CONTIGUOUS));
++}
++
++static inline bool is_parsing_vendor_kernel(
++		const struct bin_parse_info *parse_info)
++{
++	// vendor_kernel == null while loading itself
++	return parse_info->vendor_kernel == NULL;
++}
++
++static int bin_read_allocation_list(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct bin_alloc_info *alloc_info)
++{
++	struct ipts_bin_alloc_list *alloc_list;
++	int aidx, pidx, num_of_parallels, bidx, num_of_buffers;
++	int parsed, size;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++
++	alloc_list = (struct ipts_bin_alloc_list *)&parse_info->data[parsed];
++
++	// validation check
++	if (sizeof(alloc_list->num) > size - parsed)
++		return -EINVAL;
++
++	// read the number of aloocations
++	parsed += sizeof(alloc_list->num);
++
++	// validation check
++	if (sizeof(alloc_list->alloc[0]) * alloc_list->num > size - parsed)
++		return -EINVAL;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	num_of_buffers = num_of_parallels * alloc_list->num + num_of_parallels;
++	alloc_info->buffs = vmalloc(sizeof(struct bin_buffer) *
++		num_of_buffers);
++
++	if (alloc_info->buffs == NULL)
++		return -ENOMEM;
++
++	memset(alloc_info->buffs, 0, sizeof(struct bin_buffer) *
++			num_of_buffers);
++
++	for (aidx = 0; aidx < alloc_list->num; aidx++) {
++		for (pidx = 0; pidx < num_of_parallels; pidx++) {
++			bidx = aidx + (pidx * alloc_list->num);
++			alloc_info->buffs[bidx].handle =
++				alloc_list->alloc[aidx].handle;
++		}
++
++		parsed += sizeof(alloc_list->alloc[0]);
++	}
++
++	parse_info->parsed = parsed;
++	alloc_info->num_of_allocations = alloc_list->num;
++	alloc_info->num_of_buffers = num_of_buffers;
++
++	ipts_dbg(ipts, "number of allocations = %d, buffers = %d\n",
++			alloc_info->num_of_allocations,
++			alloc_info->num_of_buffers);
++
++	return 0;
++}
++
++static void patch_SBA(u32 *buf_addr, u64 gpu_addr, int size)
++{
++	u64 *stateBase;
++	u64 SBA;
++	u32 inst;
++	int i;
++
++	SBA = gpu_addr + SBA_OFFSET_BYTES;
++
++	for (i = 0; i < size / 4; i++) {
++		inst = buf_addr[i];
++		if (inst == BDW_SURFACE_BASE_ADDRESS) {
++			stateBase = (u64 *)&buf_addr
++				[i + SURFACE_STATE_OFFSET_WORD];
++			*stateBase |= SBA;
++			*stateBase |= 0x01; // enable
++			break;
++		}
++	}
++}
++
++static int bin_read_cmd_buffer(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct bin_alloc_info *alloc_info, struct bin_workload *wl)
++{
++	struct ipts_bin_cmdbuf *cmd;
++	struct ipts_mapbuffer *buf;
++	int cidx, size, parsed, pidx, num_of_parallels;
++
++	size = parse_info->size;
++	parsed = parse_info->parsed;
++
++	cmd = (struct ipts_bin_cmdbuf *)&parse_info->data[parsed];
++
++	if (sizeof(cmd->size) > size - parsed)
++		return -EINVAL;
++
++	parsed += sizeof(cmd->size);
++	if (cmd->size > size - parsed)
++		return -EINVAL;
++
++	ipts_dbg(ipts, "cmd buf size = %d\n", cmd->size);
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	// command buffers are located after the other allocations
++	cidx = num_of_parallels * alloc_info->num_of_allocations;
++	for (pidx = 0; pidx < num_of_parallels; pidx++) {
++		buf = ipts_map_buffer(ipts, cmd->size, 0);
++
++		if (buf == NULL)
++			return -ENOMEM;
++
++		ipts_dbg(ipts, "cmd_idx[%d] = %d, g:0x%p, c:0x%p\n", pidx,
++			cidx, buf->gfx_addr, buf->cpu_addr);
++
++		memcpy((void *)buf->cpu_addr, &(cmd->data[0]), cmd->size);
++		patch_SBA(buf->cpu_addr, (u64)buf->gfx_addr, cmd->size);
++
++		alloc_info->buffs[cidx].buf = buf;
++		wl[pidx].cmdbuf_index = cidx;
++		cidx++;
++	}
++
++	parsed += cmd->size;
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_find_alloc(struct ipts_info *ipts,
++		struct bin_alloc_info *alloc_info, u32 handle)
++{
++	int i;
++
++	for (i = 0; i < alloc_info->num_of_allocations; i++) {
++		if (alloc_info->buffs[i].handle == handle)
++			return i;
++	}
++
++	return -1;
++}
++
++static struct ipts_mapbuffer *bin_get_vendor_kernel_output(
++		struct bin_parse_info *parse_info, int pidx)
++{
++	struct bin_kernel_info *vendor = parse_info->vendor_kernel;
++	struct bin_alloc_info *alloc_info;
++	int bidx, vidx;
++
++	alloc_info = vendor->alloc_info;
++	vidx = parse_info->interested_vendor_output;
++
++	if (vidx >= alloc_info->num_of_outputs)
++		return NULL;
++
++	bidx = vendor->wl[pidx].iobuf_output[vidx];
++
++	return alloc_info->buffs[bidx].buf;
++}
++
++static int bin_read_res_list(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct bin_alloc_info *alloc_info, struct bin_workload *wl)
++{
++	struct ipts_bin_res_list *res_list;
++	struct ipts_bin_res *res;
++	struct ipts_mapbuffer *buf;
++	struct ipts_bin_data_file_info *data_file;
++	u8 *bin_data;
++	int i, size, parsed, pidx, num_of_parallels, oidx = -1;
++	int bidx, num_of_alloc;
++	u32 buf_size, flags, io_buf_type;
++	bool initialize;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	bin_data = parse_info->data;
++
++	res_list = (struct ipts_bin_res_list *)&parse_info->data[parsed];
++
++	if (sizeof(res_list->num) > (size - parsed))
++		return -EINVAL;
++
++	parsed += sizeof(res_list->num);
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	ipts_dbg(ipts, "number of resources %u\n", res_list->num);
++
++	for (i = 0; i < res_list->num; i++) {
++		struct ipts_bin_io_header *io_hdr;
++
++		initialize = false;
++		io_buf_type = 0;
++		flags = 0;
++
++		// initial data
++		data_file = NULL;
++
++		res = (struct ipts_bin_res *)(&(bin_data[parsed]));
++		if (sizeof(res[0]) > (size - parsed))
++			return -EINVAL;
++
++		ipts_dbg(ipts, "Resource(%d): handle 0x%08x type %u init %u size %u alsigned %u\n",
++			i, res->handle, res->type, res->initialize,
++			res->size, res->aligned_size);
++
++		parsed += sizeof(res[0]);
++
++		if (res->initialize) {
++			if (res->size > (size - parsed))
++				return -EINVAL;
++			parsed += res->size;
++		}
++
++		initialize = res->initialize;
++		if (!initialize || res->size <=
++				sizeof(struct ipts_bin_io_header))
++			goto read_res_list_no_init;
++
++		io_hdr = (struct ipts_bin_io_header *)(&res->data[0]);
++
++		if (strncmp(io_hdr->str, "INTELTOUCH", 10) != 0)
++			goto read_res_list_no_init;
++
++		data_file = bin_get_data_file_info(parse_info->fw_info,
++			(u32)io_hdr->type);
++
++		switch (io_hdr->type) {
++		case IPTS_INPUT: {
++			ipts_dbg(ipts, "input detected\n");
++			io_buf_type = IPTS_INPUT_ON;
++			flags = IPTS_BUF_FLAG_CONTIGUOUS;
++			break;
++		}
++		case IPTS_OUTPUT: {
++			ipts_dbg(ipts, "output detected\n");
++			io_buf_type = IPTS_OUTPUT_ON;
++			oidx++;
++			break;
++		}
++		default: {
++			if ((u32)io_hdr->type > 31) {
++				ipts_err(ipts, "invalid io buffer : %u\n",
++					(u32)io_hdr->type);
++				continue;
++			}
++
++			if (is_alloc_cont_data(data_file))
++				flags = IPTS_BUF_FLAG_CONTIGUOUS;
++
++			io_buf_type = ((u32)1 << (u32)io_hdr->type);
++			ipts_dbg(ipts, "special io buffer %u\n",
++				io_hdr->type);
++
++			break;
++		}
++		}
++
++		initialize = false;
++
++read_res_list_no_init:
++		num_of_alloc = alloc_info->num_of_allocations;
++		bidx = bin_find_alloc(ipts, alloc_info, res->handle);
++
++		if (bidx == -1) {
++			ipts_dbg(ipts, "cannot find alloc info\n");
++			return -EINVAL;
++		}
++
++		for (pidx = 0; pidx < num_of_parallels; pidx++,
++				bidx += num_of_alloc) {
++			if (!res->aligned_size)
++				continue;
++
++			if (!(pidx == 0 || (io_buf_type &&
++					!is_shared_data(data_file))))
++				continue;
++
++			buf_size = res->aligned_size;
++			if (io_buf_type & IPTS_INPUT_ON) {
++				buf_size = max_t(u32, buf_size,
++					ipts->device_info.frame_size);
++
++				wl[pidx].iobuf_input = bidx;
++			} else if (io_buf_type & IPTS_OUTPUT_ON) {
++				wl[pidx].iobuf_output[oidx] = bidx;
++
++				if (is_parsing_vendor_kernel(parse_info) ||
++						oidx == 0)
++					goto read_res_list_no_inout_err;
++
++				ipts_err(ipts, "postproc with >1 inout is not supported: %d\n",
++					oidx);
++
++				return -EINVAL;
++			}
++
++read_res_list_no_inout_err:
++			if (!is_parsing_vendor_kernel(parse_info) &&
++					io_buf_type & IPTS_OUTPUT_ON) {
++				buf = bin_get_vendor_kernel_output(
++					parse_info, pidx);
++
++				alloc_info->buffs[bidx].no_unmap = true;
++			} else {
++				buf = ipts_map_buffer(ipts, buf_size, flags);
++			}
++
++			if (buf == NULL) {
++				ipts_dbg(ipts, "ipts_map_buffer failed\n");
++				return -ENOMEM;
++			}
++
++			if (initialize) {
++				memcpy((void *)buf->cpu_addr, &(res->data[0]),
++					res->size);
++			} else if (data_file && strlen(data_file->file_name)) {
++				bin_read_fw(ipts, data_file->file_name,
++					buf->cpu_addr, buf_size);
++			} else if (is_parsing_vendor_kernel(parse_info) ||
++					!(io_buf_type & IPTS_OUTPUT_ON)) {
++				memset((void *)buf->cpu_addr, 0, res->size);
++			}
++
++			alloc_info->buffs[bidx].buf = buf;
++		}
++	}
++
++	alloc_info->num_of_outputs = oidx + 1;
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_read_patch_list(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct bin_alloc_info *alloc_info, struct bin_workload *wl)
++{
++	struct ipts_bin_patch_list *patch_list;
++	struct ipts_bin_patch *patch;
++	struct ipts_mapbuffer *cmd = NULL;
++	u8 *batch;
++	int parsed, size, i, pidx, num_of_parallels, cidx, bidx;
++	unsigned int gtt_offset;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	patch_list = (struct ipts_bin_patch_list *)&parse_info->data[parsed];
++
++	if (sizeof(patch_list->num) > (size - parsed))
++		return -EFAULT;
++	parsed += sizeof(patch_list->num);
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	patch = (struct ipts_bin_patch *)(&patch_list->patch[0]);
++
++	for (i = 0; i < patch_list->num; i++) {
++		if (sizeof(patch_list->patch[0]) > (size - parsed))
++			return -EFAULT;
++
++		for (pidx = 0; pidx < num_of_parallels; pidx++) {
++			cidx = wl[pidx].cmdbuf_index;
++			bidx = patch[i].index + pidx *
++				alloc_info->num_of_allocations;
++
++			// buffer is shared
++			if (alloc_info->buffs[bidx].buf == NULL)
++				bidx = patch[i].index;
++
++			cmd = alloc_info->buffs[cidx].buf;
++			batch = (char *)(u64)cmd->cpu_addr;
++
++			gtt_offset = 0;
++			if (alloc_info->buffs[bidx].buf != NULL) {
++				gtt_offset = (u32)(u64)alloc_info->buffs
++					[bidx].buf->gfx_addr;
++			}
++			gtt_offset += patch[i].alloc_offset;
++
++			batch += patch[i].patch_offset;
++			*(u32 *)batch = gtt_offset;
++		}
++
++		parsed += sizeof(patch_list->patch[0]);
++	}
++
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_read_guc_wq_item(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct bin_guc_wq_item **guc_wq_item)
++{
++	struct ipts_bin_guc_wq_info *bin_guc_wq;
++	struct bin_guc_wq_item *item;
++	u8 *wi_data;
++	int size, parsed, hdr_size, wi_size;
++	int i, batch_offset;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	bin_guc_wq = (struct ipts_bin_guc_wq_info *)&parse_info->data[parsed];
++
++	wi_size = bin_guc_wq->size;
++	wi_data = bin_guc_wq->data;
++	batch_offset = bin_guc_wq->batch_offset;
++
++	ipts_dbg(ipts, "wi size = %d, bt offset = %d\n", wi_size, batch_offset);
++
++	for (i = 0; i < wi_size / sizeof(u32); i++)
++		ipts_dbg(ipts, "wi[%d] = 0x%08x\n", i, *((u32 *)wi_data + i));
++
++	hdr_size = sizeof(bin_guc_wq->size) + sizeof(bin_guc_wq->batch_offset);
++
++	if (hdr_size > (size - parsed))
++		return -EINVAL;
++
++	parsed += hdr_size;
++	item = vmalloc(sizeof(struct bin_guc_wq_item) + wi_size);
++
++	if (item == NULL)
++		return -ENOMEM;
++
++	item->size = wi_size;
++	item->batch_offset = batch_offset;
++	memcpy(item->data, wi_data, wi_size);
++
++	*guc_wq_item = item;
++
++	parsed += wi_size;
++	parse_info->parsed = parsed;
++
++	return 0;
++}
++
++static int bin_setup_guc_workqueue(struct ipts_info *ipts,
++		struct bin_kernel_list *kernel_list)
++{
++	struct bin_alloc_info *alloc_info;
++	struct bin_workload *wl;
++	struct bin_kernel_info *kernel;
++	struct bin_buffer *bin_buf;
++	u8 *wq_start, *wq_addr, *wi_data;
++	int wq_size, wi_size, pidx, cidx, kidx, iter_size;
++	int i, num_of_parallels, batch_offset, k_num, total_workload;
++
++	wq_addr = (u8 *)ipts->resource.wq_info.wq_addr;
++	wq_size = ipts->resource.wq_info.wq_size;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	total_workload = ipts_get_wq_item_size(ipts);
++	k_num = kernel_list->num_of_kernels;
++
++	iter_size = total_workload * num_of_parallels;
++	if (wq_size % iter_size) {
++		ipts_err(ipts, "wq item cannot fit into wq\n");
++		return -EINVAL;
++	}
++
++	wq_start = wq_addr;
++	for (pidx = 0; pidx < num_of_parallels; pidx++) {
++		kernel = &kernel_list->kernels[0];
++
++		for (kidx = 0; kidx < k_num; kidx++, kernel++) {
++			wl = kernel->wl;
++			alloc_info = kernel->alloc_info;
++
++			batch_offset = kernel->guc_wq_item->batch_offset;
++			wi_size = kernel->guc_wq_item->size;
++			wi_data = &kernel->guc_wq_item->data[0];
++
++			cidx = wl[pidx].cmdbuf_index;
++			bin_buf = &alloc_info->buffs[cidx];
++
++			// Patch the WQ Data with proper batch buffer offset
++			*(u32 *)(wi_data + batch_offset) =
++				(u32)(unsigned long)(bin_buf->buf->gfx_addr);
++
++			memcpy(wq_addr, wi_data, wi_size);
++			wq_addr += wi_size;
++		}
++	}
++
++	for (i = 0; i < (wq_size / iter_size) - 1; i++) {
++		memcpy(wq_addr, wq_start, iter_size);
++		wq_addr += iter_size;
++	}
++
++	return 0;
++}
++
++static int bin_read_bufid_patch(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct ipts_bin_bufid_patch *bufid_patch)
++{
++	struct ipts_bin_bufid_patch *patch;
++	int size, parsed;
++
++	parsed = parse_info->parsed;
++	size = parse_info->size;
++	patch = (struct ipts_bin_bufid_patch *)&parse_info->data[parsed];
++
++	if (sizeof(struct ipts_bin_bufid_patch) > (size - parsed)) {
++		ipts_dbg(ipts, "invalid bufid info\n");
++		return -EINVAL;
++	}
++
++	parsed += sizeof(struct ipts_bin_bufid_patch);
++	parse_info->parsed = parsed;
++
++	memcpy(bufid_patch, patch, sizeof(struct ipts_bin_bufid_patch));
++
++	return 0;
++}
++
++static int bin_setup_bufid_buffer(struct ipts_info *ipts,
++		struct bin_kernel_list *kernel_list)
++{
++	struct ipts_mapbuffer *buf, *cmd_buf;
++	struct bin_kernel_info *last_kernel;
++	struct bin_alloc_info *alloc_info;
++	struct bin_workload *wl;
++	u8 *batch;
++	int pidx, num_of_parallels, cidx;
++	u32 mem_offset, imm_offset;
++
++	buf = ipts_map_buffer(ipts, PAGE_SIZE, 0);
++	if (!buf)
++		return -ENOMEM;
++
++	last_kernel = &kernel_list->kernels[kernel_list->num_of_kernels - 1];
++
++	mem_offset = last_kernel->bufid_patch.mem_offset;
++	imm_offset = last_kernel->bufid_patch.imm_offset;
++	wl = last_kernel->wl;
++	alloc_info = last_kernel->alloc_info;
++
++	// Initialize the buffer with default value
++	*((u32 *)buf->cpu_addr) = LASTSUBMITID_DEFAULT_VALUE;
++	ipts->current_buffer_index = LASTSUBMITID_DEFAULT_VALUE;
++	ipts->last_buffer_completed = LASTSUBMITID_DEFAULT_VALUE;
++	ipts->last_submitted_id = (int *)buf->cpu_addr;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	for (pidx = 0; pidx < num_of_parallels; pidx++) {
++		cidx = wl[pidx].cmdbuf_index;
++		cmd_buf = alloc_info->buffs[cidx].buf;
++		batch = (u8 *)(u64)cmd_buf->cpu_addr;
++
++		*((u32 *)(batch + mem_offset)) = (u32)(u64)(buf->gfx_addr);
++		*((u32 *)(batch + imm_offset)) = pidx;
++	}
++
++	kernel_list->bufid_buf = buf;
++
++	return 0;
++}
++
++static void unmap_buffers(struct ipts_info *ipts,
++		struct bin_alloc_info *alloc_info)
++{
++	struct bin_buffer *buffs;
++	int i, num_of_buffers;
++
++	num_of_buffers = alloc_info->num_of_buffers;
++	buffs = &alloc_info->buffs[0];
++
++	for (i = 0; i < num_of_buffers; i++) {
++		if (buffs[i].no_unmap != true && buffs[i].buf != NULL)
++			ipts_unmap_buffer(ipts, buffs[i].buf);
++	}
++}
++
++static int load_kernel(struct ipts_info *ipts,
++		struct bin_parse_info *parse_info,
++		struct bin_kernel_info *kernel)
++{
++	struct ipts_bin_header *hdr;
++	struct bin_workload *wl;
++	struct bin_alloc_info *alloc_info;
++	struct bin_guc_wq_item *guc_wq_item = NULL;
++	struct ipts_bin_bufid_patch bufid_patch;
++	int num_of_parallels, ret;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	// check header version and magic numbers
++	hdr = (struct ipts_bin_header *)parse_info->data;
++	if (hdr->version != IPTS_BIN_HEADER_VERSION ||
++			strncmp(hdr->str, "IOCL", 4) != 0) {
++		ipts_err(ipts, "binary header is not correct version = %d, ",
++			hdr->version);
++
++		ipts_err(ipts, "string = %c%c%c%c\n", hdr->str[0], hdr->str[1],
++			hdr->str[2], hdr->str[3]);
++
++		return -EINVAL;
++	}
++
++	parse_info->parsed = sizeof(struct ipts_bin_header);
++	wl = vmalloc(sizeof(struct bin_workload) * num_of_parallels);
++
++	if (wl == NULL)
++		return -ENOMEM;
++
++	memset(wl, 0, sizeof(struct bin_workload) * num_of_parallels);
++	alloc_info = vmalloc(sizeof(struct bin_alloc_info));
++
++	if (alloc_info == NULL) {
++		vfree(wl);
++		return -ENOMEM;
++	}
++
++	memset(alloc_info, 0, sizeof(struct bin_alloc_info));
++
++	ipts_dbg(ipts, "kernel setup(size : %d)\n", parse_info->size);
++
++	ret = bin_read_allocation_list(ipts, parse_info, alloc_info);
++	if (ret) {
++		ipts_dbg(ipts, "error read_allocation_list\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_cmd_buffer(ipts, parse_info, alloc_info, wl);
++	if (ret) {
++		ipts_dbg(ipts, "error read_cmd_buffer\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_res_list(ipts, parse_info, alloc_info, wl);
++	if (ret) {
++		ipts_dbg(ipts, "error read_res_list\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_patch_list(ipts, parse_info, alloc_info, wl);
++	if (ret) {
++		ipts_dbg(ipts, "error read_patch_list\n");
++		goto setup_error;
++	}
++
++	ret = bin_read_guc_wq_item(ipts, parse_info, &guc_wq_item);
++	if (ret) {
++		ipts_dbg(ipts, "error read_guc_workqueue\n");
++		goto setup_error;
++	}
++
++	memset(&bufid_patch, 0, sizeof(bufid_patch));
++
++	ret = bin_read_bufid_patch(ipts, parse_info, &bufid_patch);
++	if (ret) {
++		ipts_dbg(ipts, "error read_bufid_patch\n");
++		goto setup_error;
++	}
++
++	kernel->wl = wl;
++	kernel->alloc_info = alloc_info;
++	kernel->is_vendor = is_parsing_vendor_kernel(parse_info);
++	kernel->guc_wq_item = guc_wq_item;
++
++	memcpy(&kernel->bufid_patch, &bufid_patch, sizeof(bufid_patch));
++
++	return 0;
++
++setup_error:
++	vfree(guc_wq_item);
++
++	unmap_buffers(ipts, alloc_info);
++
++	vfree(alloc_info->buffs);
++	vfree(alloc_info);
++	vfree(wl);
++
++	return ret;
++}
++
++void bin_setup_input_output(struct ipts_info *ipts,
++		struct bin_kernel_list *kernel_list)
++{
++	struct bin_kernel_info *vendor_kernel;
++	struct bin_workload *wl;
++	struct ipts_mapbuffer *buf;
++	struct bin_alloc_info *alloc_info;
++	int pidx, num_of_parallels, i, bidx;
++
++	vendor_kernel = &kernel_list->kernels[0];
++
++	wl = vendor_kernel->wl;
++	alloc_info = vendor_kernel->alloc_info;
++	ipts->resource.num_of_outputs = alloc_info->num_of_outputs;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	for (pidx = 0; pidx < num_of_parallels; pidx++) {
++		bidx = wl[pidx].iobuf_input;
++		buf = alloc_info->buffs[bidx].buf;
++
++		ipts_dbg(ipts, "in_buf[%d](%d) c:%p, p:%p, g:%p\n",
++			pidx, bidx, (void *)buf->cpu_addr,
++			(void *)buf->phy_addr, (void *)buf->gfx_addr);
++
++		ipts_set_input_buffer(ipts, pidx, buf->cpu_addr, buf->phy_addr);
++
++		for (i = 0; i < alloc_info->num_of_outputs; i++) {
++			bidx = wl[pidx].iobuf_output[i];
++			buf = alloc_info->buffs[bidx].buf;
++
++			ipts_dbg(ipts, "out_buf[%d][%d] c:%p, p:%p, g:%p\n",
++				pidx, i, (void *)buf->cpu_addr,
++				(void *)buf->phy_addr, (void *)buf->gfx_addr);
++
++			ipts_set_output_buffer(ipts, pidx, i,
++				buf->cpu_addr, buf->phy_addr);
++		}
++	}
++}
++
++static void unload_kernel(struct ipts_info *ipts,
++		struct bin_kernel_info *kernel)
++{
++	struct bin_alloc_info *alloc_info = kernel->alloc_info;
++	struct bin_guc_wq_item *guc_wq_item = kernel->guc_wq_item;
++
++	if (guc_wq_item)
++		vfree(guc_wq_item);
++
++	if (alloc_info) {
++		unmap_buffers(ipts, alloc_info);
++
++		vfree(alloc_info->buffs);
++		vfree(alloc_info);
++	}
++}
++
++static int setup_kernel(struct ipts_info *ipts,
++		struct ipts_bin_fw_list *fw_list)
++{
++	struct bin_kernel_list *kernel_list = NULL;
++	struct bin_kernel_info *kernel = NULL;
++	const struct firmware *fw = NULL;
++	struct bin_workload *wl;
++	struct ipts_bin_fw_info *fw_info;
++	char *fw_name, *fw_data;
++	struct bin_parse_info parse_info;
++	int ret = 0, kidx = 0, num_of_kernels = 0;
++	int vidx, total_workload = 0;
++
++	num_of_kernels = fw_list->num_of_fws;
++	kernel_list = vmalloc(sizeof(*kernel) *
++		num_of_kernels + sizeof(*kernel_list));
++
++	if (kernel_list == NULL)
++		return -ENOMEM;
++
++	memset(kernel_list, 0, sizeof(*kernel) *
++		num_of_kernels + sizeof(*kernel_list));
++
++	kernel_list->num_of_kernels = num_of_kernels;
++	kernel = &kernel_list->kernels[0];
++
++	fw_data = (char *)&fw_list->fw_info[0];
++	for (kidx = 0; kidx < num_of_kernels; kidx++) {
++		fw_info = (struct ipts_bin_fw_info *)fw_data;
++		fw_name = &fw_info->fw_name[0];
++		vidx = fw_info->vendor_output;
++
++		ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
++		if (ret) {
++			ipts_err(ipts, "cannot read fw %s\n", fw_name);
++			goto error_exit;
++		}
++
++		parse_info.data = (u8 *)fw->data;
++		parse_info.size = fw->size;
++		parse_info.parsed = 0;
++		parse_info.fw_info = fw_info;
++		parse_info.vendor_kernel = (kidx == 0) ? NULL : &kernel[0];
++		parse_info.interested_vendor_output = vidx;
++
++		ret = load_kernel(ipts, &parse_info, &kernel[kidx]);
++		if (ret) {
++			ipts_err(ipts, "do_setup_kernel error : %d\n", ret);
++			release_firmware(fw);
++			goto error_exit;
++		}
++
++		release_firmware(fw);
++
++		total_workload += kernel[kidx].guc_wq_item->size;
++
++		// advance to the next kernel
++		fw_data += sizeof(struct ipts_bin_fw_info);
++		fw_data += sizeof(struct ipts_bin_data_file_info) *
++			fw_info->num_of_data_files;
++	}
++
++	ipts_set_wq_item_size(ipts, total_workload);
++
++	ret = bin_setup_guc_workqueue(ipts, kernel_list);
++	if (ret) {
++		ipts_dbg(ipts, "error setup_guc_workqueue\n");
++		goto error_exit;
++	}
++
++	ret = bin_setup_bufid_buffer(ipts, kernel_list);
++	if (ret) {
++		ipts_dbg(ipts, "error setup_lastbubmit_buffer\n");
++		goto error_exit;
++	}
++
++	bin_setup_input_output(ipts, kernel_list);
++
++	// workload is not needed during run-time so free them
++	for (kidx = 0; kidx < num_of_kernels; kidx++) {
++		wl = kernel[kidx].wl;
++		vfree(wl);
++	}
++
++	ipts->kernel_handle = (u64)kernel_list;
++
++	return 0;
++
++error_exit:
++
++	for (kidx = 0; kidx < num_of_kernels; kidx++) {
++		wl = kernel[kidx].wl;
++		vfree(wl);
++		unload_kernel(ipts, &kernel[kidx]);
++	}
++
++	vfree(kernel_list);
++
++	return ret;
++}
++
++
++static void release_kernel(struct ipts_info *ipts)
++{
++	struct bin_kernel_list *kernel_list;
++	struct bin_kernel_info *kernel;
++	int kidx, knum;
++
++	kernel_list = (struct bin_kernel_list *)ipts->kernel_handle;
++	knum = kernel_list->num_of_kernels;
++	kernel = &kernel_list->kernels[0];
++
++	for (kidx = 0; kidx < knum; kidx++) {
++		unload_kernel(ipts, kernel);
++		kernel++;
++	}
++
++	ipts_unmap_buffer(ipts, kernel_list->bufid_buf);
++
++	vfree(kernel_list);
++	ipts->kernel_handle = 0;
++}
++
++int ipts_init_kernels(struct ipts_info *ipts)
++{
++	struct ipts_bin_fw_list *fw_list;
++	int ret;
++
++	ret = ipts_open_gpu(ipts);
++	if (ret) {
++		ipts_err(ipts, "open gpu error : %d\n", ret);
++		return ret;
++	}
++
++	ret = ipts_request_firmware_config(ipts, &fw_list);
++	if (ret) {
++		ipts_err(ipts, "request firmware config error : %d\n", ret);
++		goto close_gpu;
++	}
++
++	ret = setup_kernel(ipts, fw_list);
++	if (ret) {
++		ipts_err(ipts, "setup kernel error : %d\n", ret);
++		goto close_gpu;
++	}
++
++	return ret;
++
++close_gpu:
++	ipts_close_gpu(ipts);
++
++	return ret;
++}
++
++void ipts_release_kernels(struct ipts_info *ipts)
++{
++	release_kernel(ipts);
++	ipts_close_gpu(ipts);
++}
+diff --git a/drivers/misc/ipts/kernel.h b/drivers/misc/ipts/kernel.h
+new file mode 100644
+index 000000000000..7be45da01cfc
+--- /dev/null
++++ b/drivers/misc/ipts/kernel.h
+@@ -0,0 +1,17 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_KERNEL_H_
++#define _IPTS_KERNEL_H_
++
++#include "ipts.h"
++
++int ipts_init_kernels(struct ipts_info *ipts);
++void ipts_release_kernels(struct ipts_info *ipts);
++
++#endif // _IPTS_KERNEL_H_
+diff --git a/drivers/misc/ipts/mei-msgs.h b/drivers/misc/ipts/mei-msgs.h
+new file mode 100644
+index 000000000000..036b74f7234e
+--- /dev/null
++++ b/drivers/misc/ipts/mei-msgs.h
+@@ -0,0 +1,901 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2013-2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_MEI_MSGS_H_
++#define _IPTS_MEI_MSGS_H_
++
++#include <linux/build_bug.h>
++
++#include "sensor-regs.h"
++
++#pragma pack(1)
++
++// Define static_assert macro (which will be available after 5.1
++// and not available on 4.19 yet) to check structure size and fail
++// compile for unexpected mismatch.
++// Taken from upstream commit 6bab69c65013bed5fce9f101a64a84d0385b3946.
++#define static_assert(expr, ...) __static_assert(expr, ##__VA_ARGS__, #expr)
++#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
++
++// Initial protocol version
++#define TOUCH_HECI_CLIENT_PROTOCOL_VERSION 10
++
++// GUID that identifies the Touch HECI client.
++#define TOUCH_HECI_CLIENT_GUID					\
++	{0x3e8d0870, 0x271a, 0x4208,				\
++	{0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04} }
++
++#define TOUCH_SENSOR_GET_DEVICE_INFO_CMD 0x00000001
++#define TOUCH_SENSOR_GET_DEVICE_INFO_RSP 0x80000001
++
++#define TOUCH_SENSOR_SET_MODE_CMD 0x00000002
++#define TOUCH_SENSOR_SET_MODE_RSP 0x80000002
++
++#define TOUCH_SENSOR_SET_MEM_WINDOW_CMD 0x00000003
++#define TOUCH_SENSOR_SET_MEM_WINDOW_RSP 0x80000003
++
++#define TOUCH_SENSOR_QUIESCE_IO_CMD 0x00000004
++#define TOUCH_SENSOR_QUIESCE_IO_RSP 0x80000004
++
++#define TOUCH_SENSOR_HID_READY_FOR_DATA_CMD 0x00000005
++#define TOUCH_SENSOR_HID_READY_FOR_DATA_RSP 0x80000005
++
++#define TOUCH_SENSOR_FEEDBACK_READY_CMD 0x00000006
++#define TOUCH_SENSOR_FEEDBACK_READY_RSP 0x80000006
++
++#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD 0x00000007
++#define TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP 0x80000007
++
++#define TOUCH_SENSOR_NOTIFY_DEV_READY_CMD 0x00000008
++#define TOUCH_SENSOR_NOTIFY_DEV_READY_RSP 0x80000008
++
++#define TOUCH_SENSOR_SET_POLICIES_CMD 0x00000009
++#define TOUCH_SENSOR_SET_POLICIES_RSP 0x80000009
++
++#define TOUCH_SENSOR_GET_POLICIES_CMD 0x0000000A
++#define TOUCH_SENSOR_GET_POLICIES_RSP 0x8000000A
++
++#define TOUCH_SENSOR_RESET_CMD 0x0000000B
++#define TOUCH_SENSOR_RESET_RSP 0x8000000B
++
++#define TOUCH_SENSOR_READ_ALL_REGS_CMD 0x0000000C
++#define TOUCH_SENSOR_READ_ALL_REGS_RSP 0x8000000C
++
++// ME sends this message to indicate previous command was unrecognized
++#define TOUCH_SENSOR_CMD_ERROR_RSP 0x8FFFFFFF
++
++#define TOUCH_SENSOR_MAX_DATA_BUFFERS   16
++#define TOUCH_HID_2_ME_BUFFER_ID        TOUCH_SENSOR_MAX_DATA_BUFFERS
++#define TOUCH_HID_2_ME_BUFFER_SIZE_MAX  1024
++#define TOUCH_INVALID_BUFFER_ID         0xFF
++
++#define TOUCH_DEFAULT_DOZE_TIMER_SECONDS 30
++
++#define TOUCH_MSG_SIZE_MAX_BYTES			\
++	(MAX(sizeof(struct touch_sensor_msg_m2h),	\
++	     sizeof(struct touch_sensor_msg_h2m)))
++
++// indicates GuC got reset and ME must re-read GuC data such as
++// TailOffset and Doorbell Cookie values
++#define TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET BIT(0)
++
++/*
++ * Debug Policy bits used by TOUCH_POLICY_DATA.DebugOverride
++ */
++
++// Disable sensor startup timer
++#define TOUCH_DBG_POLICY_OVERRIDE_STARTUP_TIMER_DIS BIT(0)
++
++// Disable Sync Byte check
++#define TOUCH_DBG_POLICY_OVERRIDE_SYNC_BYTE_DIS BIT(1)
++
++// Disable error resets
++#define TOUCH_DBG_POLICY_OVERRIDE_ERR_RESET_DIS BIT(2)
++
++/*
++ * Touch Sensor Status Codes
++ */
++enum touch_status {
++	// Requested operation was successful
++	TOUCH_STATUS_SUCCESS = 0,
++
++	// Invalid parameter(s) sent
++	TOUCH_STATUS_INVALID_PARAMS,
++
++	// Unable to validate address range
++	TOUCH_STATUS_ACCESS_DENIED,
++
++	// HECI message incorrect size for specified command
++	TOUCH_STATUS_CMD_SIZE_ERROR,
++
++	// Memory window not set or device is not armed for operation
++	TOUCH_STATUS_NOT_READY,
++
++	// There is already an outstanding message of the same type, must
++	// wait for response before sending another request of that type
++	TOUCH_STATUS_REQUEST_OUTSTANDING,
++
++	// Sensor could not be found. Either no sensor is connected,
++	// the sensor has not yet initialized, or the system is
++	// improperly configured.
++	TOUCH_STATUS_NO_SENSOR_FOUND,
++
++	// Not enough memory/storage for requested operation
++	TOUCH_STATUS_OUT_OF_MEMORY,
++
++	// Unexpected error occurred
++	TOUCH_STATUS_INTERNAL_ERROR,
++
++	// Used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP to indicate sensor
++	// has been disabled or reset and must be reinitialized.
++	TOUCH_STATUS_SENSOR_DISABLED,
++
++	// Used to indicate compatibility revision check between sensor and ME
++	// failed, or protocol ver between ME/HID/Kernels failed.
++	TOUCH_STATUS_COMPAT_CHECK_FAIL,
++
++	// Indicates sensor went through a reset initiated by ME
++	TOUCH_STATUS_SENSOR_EXPECTED_RESET,
++
++	// Indicates sensor went through an unexpected reset
++	TOUCH_STATUS_SENSOR_UNEXPECTED_RESET,
++
++	// Requested sensor reset failed to complete
++	TOUCH_STATUS_RESET_FAILED,
++
++	// Operation timed out
++	TOUCH_STATUS_TIMEOUT,
++
++	// Test mode pattern did not match expected values
++	TOUCH_STATUS_TEST_MODE_FAIL,
++
++	// Indicates sensor reported fatal error during reset sequence.
++	// Further progress is not possible.
++	TOUCH_STATUS_SENSOR_FAIL_FATAL,
++
++	// Indicates sensor reported non-fatal error during reset sequence.
++	// HID/BIOS logs error and attempts to continue.
++	TOUCH_STATUS_SENSOR_FAIL_NONFATAL,
++
++	// Indicates sensor reported invalid capabilities, such as not
++	// supporting required minimum frequency or I/O mode.
++	TOUCH_STATUS_INVALID_DEVICE_CAPS,
++
++	// Indicates that command cannot be complete until ongoing Quiesce I/O
++	// flow has completed.
++	TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS,
++
++	// Invalid value, never returned
++	TOUCH_STATUS_MAX
++};
++static_assert(sizeof(enum touch_status) == 4);
++
++/*
++ * Defines for message structures used for Host to ME communication
++ */
++enum touch_sensor_mode {
++	// Set mode to HID mode
++	TOUCH_SENSOR_MODE_HID = 0,
++
++	// Set mode to Raw Data mode
++	TOUCH_SENSOR_MODE_RAW_DATA,
++
++	// Used like TOUCH_SENSOR_MODE_HID but data coming from sensor is
++	// not necessarily a HID packet.
++	TOUCH_SENSOR_MODE_SENSOR_DEBUG = 4,
++
++	// Invalid value
++	TOUCH_SENSOR_MODE_MAX
++};
++static_assert(sizeof(enum touch_sensor_mode) == 4);
++
++struct touch_sensor_set_mode_cmd_data {
++	// Indicate desired sensor mode
++	enum touch_sensor_mode sensor_mode;
++
++	// For future expansion
++	u32 Reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_set_mode_cmd_data) == 16);
++
++struct touch_sensor_set_mem_window_cmd_data {
++	// Lower 32 bits of Touch Data Buffer physical address. Size of each
++	// buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize
++	u32 touch_data_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS];
++
++	// Upper 32 bits of Touch Data Buffer physical address. Size of each
++	// buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FrameSize
++	u32 touch_data_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS];
++
++	// Lower 32 bits of Tail Offset physical address
++	u32 tail_offset_addr_lower;
++
++	// Upper 32 bits of Tail Offset physical address, always 32 bit,
++	// increment by WorkQueueItemSize
++	u32 tail_offset_addr_upper;
++
++	// Lower 32 bits of Doorbell register physical address
++	u32 doorbell_cookie_addr_lower;
++
++	// Upper 32 bits of Doorbell register physical address, always 32 bit,
++	// increment as integer, rollover to 1
++	u32 doorbell_cookie_addr_upper;
++
++	// Lower 32 bits of Feedback Buffer physical address. Size of each
++	// buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize
++	u32 feedback_buffer_addr_lower[TOUCH_SENSOR_MAX_DATA_BUFFERS];
++
++	// Upper 32 bits of Feedback Buffer physical address. Size of each
++	// buffer should be TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.FeedbackSize
++	u32 feedback_buffer_addr_upper[TOUCH_SENSOR_MAX_DATA_BUFFERS];
++
++	// Lower 32 bits of dedicated HID to ME communication buffer.
++	// Size is Hid2MeBufferSize.
++	u32 hid2me_buffer_addr_lower;
++
++	// Upper 32 bits of dedicated HID to ME communication buffer.
++	// Size is Hid2MeBufferSize.
++	u32 hid2me_buffer_addr_upper;
++
++	// Size in bytes of Hid2MeBuffer, can be no bigger than
++	// TOUCH_HID_2_ME_BUFFER_SIZE_MAX
++	u32 hid2me_buffer_size;
++
++	// For future expansion
++	u8 reserved1;
++
++	// Size in bytes of the GuC Work Queue Item pointed to by TailOffset
++	u8 work_queue_item_size;
++
++	// Size in bytes of the entire GuC Work Queue
++	u16 work_queue_size;
++
++	// For future expansion
++	u32 reserved[8];
++};
++static_assert(sizeof(struct touch_sensor_set_mem_window_cmd_data) == 320);
++
++struct touch_sensor_quiesce_io_cmd_data {
++	// Optionally set TOUCH_SENSOR_QUIESCE_FLAG_GUC_RESET
++	u32 quiesce_flags;
++	u32 reserved[2];
++};
++static_assert(sizeof(struct touch_sensor_quiesce_io_cmd_data) == 12);
++
++struct touch_sensor_feedback_ready_cmd_data {
++	// Index value from 0 to TOUCH_HID_2_ME_BUFFER_ID used to indicate
++	// which Feedback Buffer to use. Using special value
++	// TOUCH_HID_2_ME_BUFFER_ID is an indication to ME to
++	// get feedback data from the Hid2Me buffer instead of one
++	// of the standard Feedback buffers.
++	u8 feedback_index;
++
++	// For future expansion
++	u8 reserved1[3];
++
++	// Transaction ID that was originally passed to host in
++	// TOUCH_HID_PRIVATE_DATA. Used to track round trip of a given
++	// transaction for performance measurements.
++	u32 transaction_id;
++
++	// For future expansion
++	u32 reserved2[2];
++};
++static_assert(sizeof(struct touch_sensor_feedback_ready_cmd_data) == 16);
++
++enum touch_freq_override {
++	// Do not apply any override
++	TOUCH_FREQ_OVERRIDE_NONE,
++
++	// Force frequency to 10MHz (not currently supported)
++	TOUCH_FREQ_OVERRIDE_10MHZ,
++
++	// Force frequency to 17MHz
++	TOUCH_FREQ_OVERRIDE_17MHZ,
++
++	// Force frequency to 30MHz
++	TOUCH_FREQ_OVERRIDE_30MHZ,
++
++	// Force frequency to 50MHz (not currently supported)
++	TOUCH_FREQ_OVERRIDE_50MHZ,
++
++	// Invalid value
++	TOUCH_FREQ_OVERRIDE_MAX
++};
++static_assert(sizeof(enum touch_freq_override) == 4);
++
++enum touch_spi_io_mode_override {
++	// Do not apply any override
++	TOUCH_SPI_IO_MODE_OVERRIDE_NONE,
++
++	// Force Single I/O
++	TOUCH_SPI_IO_MODE_OVERRIDE_SINGLE,
++
++	// Force Dual I/O
++	TOUCH_SPI_IO_MODE_OVERRIDE_DUAL,
++
++	// Force Quad I/O
++	TOUCH_SPI_IO_MODE_OVERRIDE_QUAD,
++
++	// Invalid value
++	TOUCH_SPI_IO_MODE_OVERRIDE_MAX
++};
++static_assert(sizeof(enum touch_spi_io_mode_override) == 4);
++
++struct touch_policy_data {
++	// For future expansion.
++	u32 reserved0;
++
++	// Value in seconds, after which ME will put the sensor into Doze power
++	// state if no activity occurs. Set to 0 to disable Doze mode
++	// (not recommended). Value will be set to
++	// TOUCH_DEFAULT_DOZE_TIMER_SECONDS by default
++	u32 doze_timer:16;
++
++	// Override frequency requested by sensor
++	enum touch_freq_override freq_override:3;
++
++	// Override IO mode requested by sensor
++	enum touch_spi_io_mode_override spi_io_override :3;
++
++	// For future expansion
++	u32 reserved1:10;
++
++	// For future expansion
++	u32 reserved2;
++
++	// Normally all bits will be zero. Bits will be defined as needed
++	// for enabling special debug features
++	u32 debug_override;
++};
++static_assert(sizeof(struct touch_policy_data) == 16);
++
++struct touch_sensor_set_policies_cmd_data {
++	// Contains the desired policy to be set
++	struct touch_policy_data policy_data;
++};
++static_assert(sizeof(struct touch_sensor_set_policies_cmd_data) == 16);
++
++enum touch_sensor_reset_type {
++	// Hardware Reset using dedicated GPIO pin
++	TOUCH_SENSOR_RESET_TYPE_HARD,
++
++	// Software Reset using command written over SPI interface
++	TOUCH_SENSOR_RESET_TYPE_SOFT,
++
++	// Invalid value
++	TOUCH_SENSOR_RESET_TYPE_MAX
++};
++static_assert(sizeof(enum touch_sensor_reset_type) == 4);
++
++struct touch_sensor_reset_cmd_data {
++	// Indicate desired reset type
++	enum touch_sensor_reset_type reset_type;
++
++	// For future expansion
++	u32 reserved;
++};
++static_assert(sizeof(struct touch_sensor_reset_cmd_data) == 8);
++
++/*
++ * Host to ME message
++ */
++union touch_sensor_data_h2m {
++	struct touch_sensor_set_mode_cmd_data        set_mode_cmd_data;
++	struct touch_sensor_set_mem_window_cmd_data  set_window_cmd_data;
++	struct touch_sensor_quiesce_io_cmd_data      quiesce_io_cmd_data;
++	struct touch_sensor_feedback_ready_cmd_data  feedback_ready_cmd_data;
++	struct touch_sensor_set_policies_cmd_data    set_policies_cmd_data;
++	struct touch_sensor_reset_cmd_data           reset_cmd_data;
++};
++struct touch_sensor_msg_h2m {
++	u32 command_code;
++	union touch_sensor_data_h2m h2m_data;
++};
++static_assert(sizeof(struct touch_sensor_msg_h2m) == 324);
++
++/*
++ * Message structures used for ME to Host communication
++ */
++
++// I/O mode values used by TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
++enum touch_spi_io_mode {
++	// Sensor set for Single I/O SPI
++	TOUCH_SPI_IO_MODE_SINGLE = 0,
++
++	// Sensor set for Dual I/O SPI
++	TOUCH_SPI_IO_MODE_DUAL,
++
++	// Sensor set for Quad I/O SPI
++	TOUCH_SPI_IO_MODE_QUAD,
++
++	// Invalid value
++	TOUCH_SPI_IO_MODE_MAX
++};
++static_assert(sizeof(enum touch_spi_io_mode) == 4);
++
++/*
++ * TOUCH_SENSOR_GET_DEVICE_INFO_RSP code is sent in response to
++ * TOUCH_SENSOR_GET_DEVICE_INFO_CMD. This code will be followed by
++ * TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and sensor
++ *         details are reported.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_NO_SENSOR_FOUND:
++ *         Sensor has not yet been detected. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_DEVICE_CAPS:
++ *         Indicates sensor does not support minimum required Frequency
++ *         or I/O Mode. ME firmware will choose best possible option for
++ *         the errant field. Caller should attempt to continue.
++ *
++ *     TOUCH_STATUS_COMPAT_CHECK_FAIL:
++ *         Indicates TouchIC/ME compatibility mismatch. Caller should
++ *         attempt to continue.
++ */
++struct touch_sensor_get_device_info_rsp_data {
++	// Touch Sensor vendor ID
++	u16 vendor_id;
++
++	// Touch Sensor device ID
++	u16 device_id;
++
++	// Touch Sensor Hardware Revision
++	u32 hw_rev;
++
++	// Touch Sensor Firmware Revision
++	u32 fw_rev;
++
++	// Max size of one frame returned by Touch IC in bytes. This data
++	// will be TOUCH_RAW_DATA_HDR followed by a payload. The payload can be
++	// raw data or a HID structure depending on mode.
++	u32 frame_size;
++
++	// Max size of one Feedback structure in bytes
++	u32 feedback_size;
++
++	// Current operating mode of the sensor
++	enum touch_sensor_mode sensor_mode;
++
++	// Maximum number of simultaneous touch points that
++	// can be reported by sensor
++	u32 max_touch_points:8;
++
++	// SPI bus Frequency supported by sensor and ME firmware
++	enum touch_freq spi_frequency:8;
++
++	// SPI bus I/O Mode supported by sensor and ME firmware
++	enum touch_spi_io_mode spi_io_mode:8;
++
++	// For future expansion
++	u32 reserved0:8;
++
++	// Minor version number of EDS spec supported by
++	// sensor (from Compat Rev ID Reg)
++	u8 sensor_minor_eds_rev;
++
++	// Major version number of EDS spec supported by
++	// sensor (from Compat Rev ID Reg)
++	u8 sensor_major_eds_rev;
++
++	// Minor version number of EDS spec supported by ME
++	u8 me_minor_eds_rev;
++
++	// Major version number of EDS spec supported by ME
++	u8 me_major_eds_rev;
++
++	// EDS Interface Revision Number supported by
++	// sensor (from Compat Rev ID Reg)
++	u8 sensor_eds_intf_rev;
++
++	// EDS Interface Revision Number supported by ME
++	u8 me_eds_intf_rev;
++
++	// EU Kernel Compatibility Version  (from Compat Rev ID Reg)
++	u8 kernel_compat_ver;
++
++	// For future expansion
++	u8 reserved1;
++
++	// For future expansion
++	u32 reserved2[2];
++};
++static_assert(sizeof(struct touch_sensor_get_device_info_rsp_data) == 44);
++
++/*
++ * TOUCH_SENSOR_SET_MODE_RSP code is sent in response to
++ * TOUCH_SENSOR_SET_MODE_CMD. This code will be followed by
++ * TOUCH_SENSOR_SET_MODE_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and mode was set.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_PARAMS:
++ *         Input parameters are out of range.
++ */
++struct touch_sensor_set_mode_rsp_data {
++	// For future expansion
++	u32 reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_set_mode_rsp_data) == 12);
++
++/*
++ * TOUCH_SENSOR_SET_MEM_WINDOW_RSP code is sent in response to
++ * TOUCH_SENSOR_SET_MEM_WINDOW_CMD. This code will be followed
++ * by TOUCH_SENSOR_SET_MEM_WINDOW_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and memory window was set.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_PARAMS:
++ *         Input parameters are out of range.
++ *
++ *     TOUCH_STATUS_ACCESS_DENIED:
++ *         Unable to map host address ranges for DMA.
++ *
++ *     TOUCH_STATUS_OUT_OF_MEMORY:
++ *         Unable to allocate enough space for needed buffers.
++ */
++struct touch_sensor_set_mem_window_rsp_data {
++	// For future expansion
++	u32 reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_set_mem_window_rsp_data) == 12);
++
++/*
++ * TOUCH_SENSOR_QUIESCE_IO_RSP code is sent in response to
++ * TOUCH_SENSOR_QUIESCE_IO_CMD. This code will be followed
++ * by TOUCH_SENSOR_QUIESCE_IO_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and touch flow has stopped.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:
++ *         Indicates that Quiesce I/O is already in progress and this
++ *         command cannot be accepted at this time.
++ *
++ *     TOUCH_STATIS_TIMEOUT:
++ *         Indicates ME timed out waiting for Quiesce I/O flow to complete.
++ */
++struct touch_sensor_quiesce_io_rsp_data {
++	// For future expansion
++	u32 reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_quiesce_io_rsp_data) == 12);
++
++// Reset Reason values used in TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA
++enum touch_reset_reason {
++	// Reason for sensor reset is not known
++	TOUCH_RESET_REASON_UNKNOWN = 0,
++
++	// Reset was requested as part of TOUCH_SENSOR_FEEDBACK_READY_CMD
++	TOUCH_RESET_REASON_FEEDBACK_REQUEST,
++
++	// Reset was requested via TOUCH_SENSOR_RESET_CMD
++	TOUCH_RESET_REASON_HECI_REQUEST,
++
++	TOUCH_RESET_REASON_MAX
++};
++static_assert(sizeof(enum touch_reset_reason) == 4);
++
++/*
++ * TOUCH_SENSOR_HID_READY_FOR_DATA_RSP code is sent in response to
++ * TOUCH_SENSOR_HID_READY_FOR_DATA_CMD. This code will be followed
++ * by TOUCH_SENSOR_HID_READY_FOR_DATA_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and HID data was sent by DMA.
++ *         This will only be sent in HID mode.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_REQUEST_OUTSTANDING:
++ *         Previous request is still outstanding, ME FW cannot handle
++ *         another request for the same command.
++ *
++ *     TOUCH_STATUS_NOT_READY:
++ *         Indicates memory window has not yet been set by BIOS/HID.
++ *
++ *     TOUCH_STATUS_SENSOR_DISABLED:
++ *         Indicates that ME to HID communication has been stopped either
++ *         by TOUCH_SENSOR_QUIESCE_IO_CMD or
++ *         TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD.
++ *
++ *     TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:
++ *         Sensor signaled a Reset Interrupt. ME did not expect this and
++ *         has no info about why this occurred.
++ *
++ *     TOUCH_STATUS_SENSOR_EXPECTED_RESET:
++ *         Sensor signaled a Reset Interrupt. ME either directly requested
++ *         this reset, or it was expected as part of a defined flow
++ *         in the EDS.
++ *
++ *     TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:
++ *         Indicates that Quiesce I/O is already in progress and this
++ *         command cannot be accepted at this time.
++ *
++ *     TOUCH_STATUS_TIMEOUT:
++ *         Sensor did not generate a reset interrupt in the time allotted.
++ *         Could indicate sensor is not connected or malfunctioning.
++ */
++struct touch_sensor_hid_ready_for_data_rsp_data {
++	// Size of the data the ME DMA'd into a RawDataBuffer.
++	// Valid only when Status == TOUCH_STATUS_SUCCESS
++	u32 data_size;
++
++	// Index to indicate which RawDataBuffer was used.
++	// Valid only when Status == TOUCH_STATUS_SUCCESS
++	u8 touch_data_buffer_index;
++
++	// If Status is TOUCH_STATUS_SENSOR_EXPECTED_RESET, ME will provide
++	// the cause. See TOUCH_RESET_REASON.
++	u8 reset_reason;
++
++	// For future expansion
++	u8 reserved1[2];
++	u32 reserved2[5];
++};
++static_assert(sizeof(struct touch_sensor_hid_ready_for_data_rsp_data) == 28);
++
++/*
++ * TOUCH_SENSOR_FEEDBACK_READY_RSP code is sent in response to
++ * TOUCH_SENSOR_FEEDBACK_READY_CMD. This code will be followed
++ * by TOUCH_SENSOR_FEEDBACK_READY_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and any feedback or
++ *         commands were sent to sensor.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_PARAMS:
++ *         Input parameters are out of range.
++ *
++ *     TOUCH_STATUS_COMPAT_CHECK_FAIL:
++ *         Indicates ProtocolVer does not match ME supported
++ *         version. (non-fatal error)
++ *
++ *     TOUCH_STATUS_INTERNAL_ERROR:
++ *         Unexpected error occurred. This should not normally be seen.
++ *
++ *     TOUCH_STATUS_OUT_OF_MEMORY:
++ *         Insufficient space to store Calibration Data
++ */
++struct touch_sensor_feedback_ready_rsp_data {
++	// Index value from 0 to TOUCH_SENSOR_MAX_DATA_BUFFERS used
++	// to indicate which Feedback Buffer to use
++	u8 feedback_index;
++
++	// For future expansion
++	u8 reserved1[3];
++	u32 reserved2[6];
++};
++static_assert(sizeof(struct touch_sensor_feedback_ready_rsp_data) == 28);
++
++/*
++ * TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP code is sent in response to
++ * TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD. This code will be followed
++ * by TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and memory window was set.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_PARAMS:
++ *         Input parameters are out of range.
++ *
++ *     TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:
++ *         Indicates that Quiesce I/O is already in progress and this
++ *         command cannot be accepted at this time.
++ */
++struct touch_sensor_clear_mem_window_rsp_data {
++	// For future expansion
++	u32 reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_clear_mem_window_rsp_data) == 12);
++
++/*
++ * TOUCH_SENSOR_NOTIFY_DEV_READY_RSP code is sent in response to
++ * TOUCH_SENSOR_NOTIFY_DEV_READY_CMD. This code will be followed
++ * by TOUCH_SENSOR_NOTIFY_DEV_READY_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and sensor has
++ *         been detected by ME FW.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size.
++ *
++ *     TOUCH_STATUS_REQUEST_OUTSTANDING:
++ *         Previous request is still outstanding, ME FW cannot handle
++ *         another request for the same command.
++ *
++ *     TOUCH_STATUS_TIMEOUT:
++ *         Sensor did not generate a reset interrupt in the time allotted.
++ *         Could indicate sensor is not connected or malfunctioning.
++ *
++ *     TOUCH_STATUS_SENSOR_FAIL_FATAL:
++ *         Sensor indicated a fatal error, further operation is not
++ *         possible. Error details can be found in ErrReg.
++ *
++ *     TOUCH_STATUS_SENSOR_FAIL_NONFATAL:
++ *         Sensor indicated a non-fatal error. Error should be logged by
++ *         caller and init flow can continue. Error details can be found
++ *         in ErrReg.
++ */
++struct touch_sensor_notify_dev_ready_rsp_data {
++	// Value of sensor Error Register, field is only valid for
++	// Status == TOUCH_STATUS_SENSOR_FAIL_FATAL or
++	// TOUCH_STATUS_SENSOR_FAIL_NONFATAL
++	union touch_err_reg err_reg;
++
++	// For future expansion
++	u32 reserved[2];
++};
++static_assert(sizeof(struct touch_sensor_notify_dev_ready_rsp_data) == 12);
++
++/*
++ * TOUCH_SENSOR_SET_POLICIES_RSP code is sent in response to
++ * TOUCH_SENSOR_SET_POLICIES_CMD. This code will be followed
++ * by TOUCH_SENSOR_SET_POLICIES_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and new policies were set.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_PARAMS:
++ *         Input parameters are out of range.
++ */
++struct touch_sensor_set_policies_rsp_data {
++	// For future expansion
++	u32 reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_set_policies_rsp_data) == 12);
++
++/*
++ * TOUCH_SENSOR_GET_POLICIES_RSP code is sent in response to
++ * TOUCH_SENSOR_GET_POLICIES_CMD. This code will be followed
++ * by TOUCH_SENSOR_GET_POLICIES_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and new policies were set.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ */
++struct touch_sensor_get_policies_rsp_data {
++	// Contains the current policy
++	struct touch_policy_data policy_data;
++};
++static_assert(sizeof(struct touch_sensor_get_policies_rsp_data) == 16);
++
++
++/*
++ * TOUCH_SENSOR_RESET_RSP code is sent in response to
++ * TOUCH_SENSOR_RESET_CMD. This code will be followed
++ * by TOUCH_SENSOR_RESET_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and
++ *         sensor reset was completed.
++ *
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ *
++ *     TOUCH_STATUS_INVALID_PARAMS:
++ *         Input parameters are out of range.
++ *
++ *     TOUCH_STATUS_TIMEOUT:
++ *         Sensor did not generate a reset interrupt in the time allotted.
++ *         Could indicate sensor is not connected or malfunctioning.
++ *
++ *     TOUCH_STATUS_RESET_FAILED:
++ *         Sensor generated an invalid or unexpected interrupt.
++ *
++ *     TOUCH_STATUS_QUIESCE_IO_IN_PROGRESS:
++ *         Indicates that Quiesce I/O is already in progress and this
++ *         command cannot be accepted at this time.
++ */
++struct touch_sensor_reset_rsp_data {
++	// For future expansion
++	u32 reserved[3];
++};
++static_assert(sizeof(struct touch_sensor_reset_rsp_data) == 12);
++
++/*
++ * TOUCH_SENSOR_READ_ALL_REGS_RSP code is sent in response to
++ * TOUCH_SENSOR_READ_ALL_REGS_CMD. This code will be followed
++ * by TOUCH_SENSOR_READ_ALL_REGS_RSP_DATA.
++ *
++ * Possible Status values:
++ *     TOUCH_STATUS_SUCCESS:
++ *         Command was processed successfully and new policies were set.
++ *     TOUCH_STATUS_CMD_SIZE_ERROR:
++ *         Command sent did not match expected size. Other fields will
++ *         not contain valid data.
++ */
++struct touch_sensor_read_all_regs_rsp_data {
++	// Returns first 64 bytes of register space used for normal
++	// touch operation. Does not include test mode register.
++	struct touch_reg_block sensor_regs;
++	u32 reserved[4];
++};
++static_assert(sizeof(struct touch_sensor_read_all_regs_rsp_data) == 80);
++
++/*
++ * ME to Host Message
++ */
++union touch_sensor_data_m2h {
++	struct touch_sensor_get_device_info_rsp_data  device_info_rsp_data;
++	struct touch_sensor_set_mode_rsp_data         set_mode_rsp_data;
++	struct touch_sensor_set_mem_window_rsp_data   set_mem_window_rsp_data;
++	struct touch_sensor_quiesce_io_rsp_data       quiesce_io_rsp_data;
++
++	struct touch_sensor_hid_ready_for_data_rsp_data
++						hid_ready_for_data_rsp_data;
++
++	struct touch_sensor_feedback_ready_rsp_data   feedback_ready_rsp_data;
++	struct touch_sensor_clear_mem_window_rsp_data clear_mem_window_rsp_data;
++	struct touch_sensor_notify_dev_ready_rsp_data notify_dev_ready_rsp_data;
++	struct touch_sensor_set_policies_rsp_data     set_policies_rsp_data;
++	struct touch_sensor_get_policies_rsp_data     get_policies_rsp_data;
++	struct touch_sensor_reset_rsp_data            reset_rsp_data;
++	struct touch_sensor_read_all_regs_rsp_data    read_all_regs_rsp_data;
++};
++struct touch_sensor_msg_m2h {
++	u32 command_code;
++	enum touch_status status;
++	union touch_sensor_data_m2h m2h_data;
++};
++static_assert(sizeof(struct touch_sensor_msg_m2h) == 88);
++
++#pragma pack()
++
++#endif // _IPTS_MEI_MSGS_H_
+diff --git a/drivers/misc/ipts/mei.c b/drivers/misc/ipts/mei.c
+new file mode 100644
+index 000000000000..03b5d747a728
+--- /dev/null
++++ b/drivers/misc/ipts/mei.c
+@@ -0,0 +1,238 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/dma-mapping.h>
++#include <linux/hid.h>
++#include <linux/ipts-binary.h>
++#include <linux/kthread.h>
++#include <linux/mei_cl_bus.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++
++#include "companion.h"
++#include "hid.h"
++#include "ipts.h"
++#include "params.h"
++#include "msg-handler.h"
++#include "mei-msgs.h"
++#include "state.h"
++
++#define IPTS_DRIVER_NAME "ipts"
++#define IPTS_MEI_UUID UUID_LE(0x3e8d0870, 0x271a, 0x4208, \
++		0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04)
++
++static struct mei_cl_device_id ipts_mei_cl_tbl[] = {
++	{ "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY },
++	{ }
++};
++MODULE_DEVICE_TABLE(mei, ipts_mei_cl_tbl);
++
++static ssize_t device_info_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	struct ipts_info *ipts;
++
++	ipts = dev_get_drvdata(dev);
++	return sprintf(buf, "vendor id = 0x%04hX\ndevice id = 0x%04hX\n"
++		"HW rev = 0x%08X\nfirmware rev = 0x%08X\n",
++		ipts->device_info.vendor_id, ipts->device_info.device_id,
++		ipts->device_info.hw_rev, ipts->device_info.fw_rev);
++}
++static DEVICE_ATTR_RO(device_info);
++
++static struct attribute *ipts_attrs[] = {
++	&dev_attr_device_info.attr,
++	NULL
++};
++
++static const struct attribute_group ipts_grp = {
++	.attrs = ipts_attrs,
++};
++
++static void raw_data_work_func(struct work_struct *work)
++{
++	struct ipts_info *ipts = container_of(work,
++		struct ipts_info, raw_data_work);
++
++	ipts_handle_processed_data(ipts);
++}
++
++static void gfx_status_work_func(struct work_struct *work)
++{
++	struct ipts_info *ipts = container_of(work, struct ipts_info,
++		gfx_status_work);
++	enum ipts_state state;
++	int status = ipts->gfx_status;
++
++	ipts_dbg(ipts, "notify gfx status : %d\n", status);
++
++	state = ipts_get_state(ipts);
++
++	if (state != IPTS_STA_RAW_DATA_STARTED && state != IPTS_STA_HID_STARTED)
++		return;
++
++	if (status == IPTS_NOTIFY_STA_BACKLIGHT_ON && !ipts->display_status) {
++		ipts_send_sensor_clear_mem_window_cmd(ipts);
++		ipts->display_status = true;
++	}
++
++	if (status == IPTS_NOTIFY_STA_BACKLIGHT_OFF && ipts->display_status) {
++		ipts_send_sensor_quiesce_io_cmd(ipts);
++		ipts->display_status = false;
++	}
++}
++
++// event loop
++static int ipts_mei_cl_event_thread(void *data)
++{
++	struct ipts_info *ipts = (struct ipts_info *)data;
++	struct mei_cl_device *cldev = ipts->cldev;
++	ssize_t msg_len;
++	struct touch_sensor_msg_m2h m2h_msg;
++
++	while (!kthread_should_stop()) {
++		msg_len = mei_cldev_recv(cldev,
++			(u8 *)&m2h_msg, sizeof(m2h_msg));
++		if (msg_len <= 0) {
++			ipts_err(ipts, "error in reading m2h msg\n");
++			continue;
++		}
++
++		if (ipts_handle_resp(ipts, &m2h_msg, msg_len) != 0)
++			ipts_err(ipts, "error in handling resp msg\n");
++	}
++
++	ipts_dbg(ipts, "!! end event loop !!\n");
++
++	return 0;
++}
++
++static void init_work_func(struct work_struct *work)
++{
++	struct ipts_info *ipts = container_of(work,
++			struct ipts_info, init_work);
++
++	ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA;
++	ipts->display_status = true;
++
++	ipts_start(ipts);
++}
++
++static int ipts_mei_cl_probe(struct mei_cl_device *cldev,
++		const struct mei_cl_device_id *id)
++{
++	int ret = 0;
++	struct ipts_info *ipts = NULL;
++
++	// Check if a companion driver for firmware loading was registered
++	// If not, defer probing until it was properly registered
++	if (!ipts_companion_available() && !ipts_modparams.ignore_companion)
++		return -EPROBE_DEFER;
++
++	pr_info("probing Intel Precise Touch & Stylus\n");
++
++	// setup the DMA BIT mask, the system will choose the best possible
++	if (dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64)) == 0) {
++		pr_info("IPTS using DMA_BIT_MASK(64)\n");
++	} else if (dma_coerce_mask_and_coherent(&cldev->dev,
++			DMA_BIT_MASK(32)) == 0) {
++		pr_info("IPTS using  DMA_BIT_MASK(32)\n");
++	} else {
++		pr_err("IPTS: No suitable DMA available\n");
++		return -EFAULT;
++	}
++
++	ret = mei_cldev_enable(cldev);
++	if (ret < 0) {
++		pr_err("cannot enable IPTS\n");
++		return ret;
++	}
++
++	ipts = devm_kzalloc(&cldev->dev, sizeof(struct ipts_info), GFP_KERNEL);
++	if (ipts == NULL) {
++		ret = -ENOMEM;
++		goto disable_mei;
++	}
++
++	ipts->cldev = cldev;
++	mei_cldev_set_drvdata(cldev, ipts);
++	ipts->event_loop = kthread_run(ipts_mei_cl_event_thread, (void *)ipts,
++		"ipts_event_thread");
++
++	if (ipts_dbgfs_register(ipts, "ipts"))
++		pr_debug("cannot register debugfs for IPTS\n");
++
++	INIT_WORK(&ipts->init_work, init_work_func);
++	INIT_WORK(&ipts->raw_data_work, raw_data_work_func);
++	INIT_WORK(&ipts->gfx_status_work, gfx_status_work_func);
++
++	ret = sysfs_create_group(&cldev->dev.kobj, &ipts_grp);
++	if (ret != 0)
++		pr_debug("cannot create sysfs for IPTS\n");
++
++	schedule_work(&ipts->init_work);
++
++	return 0;
++
++disable_mei:
++	mei_cldev_disable(cldev);
++
++	return ret;
++}
++
++static int ipts_mei_cl_remove(struct mei_cl_device *cldev)
++{
++	struct ipts_info *ipts = mei_cldev_get_drvdata(cldev);
++
++	ipts_stop(ipts);
++
++	sysfs_remove_group(&cldev->dev.kobj, &ipts_grp);
++	ipts_hid_release(ipts);
++	ipts_dbgfs_deregister(ipts);
++	mei_cldev_disable(cldev);
++
++	kthread_stop(ipts->event_loop);
++
++	pr_info("IPTS removed\n");
++
++	return 0;
++}
++
++static struct mei_cl_driver ipts_mei_cl_driver = {
++	.id_table = ipts_mei_cl_tbl,
++	.name = IPTS_DRIVER_NAME,
++	.probe = ipts_mei_cl_probe,
++	.remove = ipts_mei_cl_remove,
++};
++
++static int ipts_mei_cl_init(void)
++{
++	int ret;
++
++	pr_info("IPTS %s() is called\n", __func__);
++
++	ret = mei_cldev_driver_register(&ipts_mei_cl_driver);
++	if (ret) {
++		pr_err("unable to register IPTS mei client driver\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static void __exit ipts_mei_cl_exit(void)
++{
++	pr_info("IPTS %s() is called\n", __func__);
++	mei_cldev_driver_unregister(&ipts_mei_cl_driver);
++}
++
++module_init(ipts_mei_cl_init);
++module_exit(ipts_mei_cl_exit);
++
++MODULE_DESCRIPTION("Intel(R) ME Interface Client Driver for IPTS");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/misc/ipts/msg-handler.c b/drivers/misc/ipts/msg-handler.c
+new file mode 100644
+index 000000000000..b2b382ea4675
+--- /dev/null
++++ b/drivers/misc/ipts/msg-handler.c
+@@ -0,0 +1,396 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/mei_cl_bus.h>
++
++#include "hid.h"
++#include "ipts.h"
++#include "mei-msgs.h"
++#include "resource.h"
++
++#define rsp_failed(ipts, cmd, status) \
++	ipts_err(ipts, "0x%08x failed status = %d\n", cmd, status)
++
++int ipts_handle_cmd(struct ipts_info *ipts, u32 cmd, void *data, int data_size)
++{
++	int ret = 0;
++	int len = 0;
++	struct touch_sensor_msg_h2m h2m_msg;
++
++	memset(&h2m_msg, 0, sizeof(h2m_msg));
++
++	h2m_msg.command_code = cmd;
++	len = sizeof(h2m_msg.command_code) + data_size;
++
++	if (data != NULL && data_size != 0)
++		memcpy(&h2m_msg.h2m_data, data, data_size); // copy payload
++
++	ret = mei_cldev_send(ipts->cldev, (u8 *)&h2m_msg, len);
++	if (ret < 0) {
++		ipts_err(ipts, "mei_cldev_send() error 0x%X:%d\n", cmd, ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++int ipts_send_feedback(struct ipts_info *ipts, int buffer_idx,
++		u32 transaction_id)
++{
++	int cmd_len = sizeof(struct touch_sensor_feedback_ready_cmd_data);
++	struct touch_sensor_feedback_ready_cmd_data fb_ready_cmd;
++
++	memset(&fb_ready_cmd, 0, cmd_len);
++
++	fb_ready_cmd.feedback_index = buffer_idx;
++	fb_ready_cmd.transaction_id = transaction_id;
++
++	return ipts_handle_cmd(ipts, TOUCH_SENSOR_FEEDBACK_READY_CMD,
++		&fb_ready_cmd, cmd_len);
++}
++
++int ipts_send_sensor_quiesce_io_cmd(struct ipts_info *ipts)
++{
++	int cmd_len = sizeof(struct touch_sensor_quiesce_io_cmd_data);
++	struct touch_sensor_quiesce_io_cmd_data quiesce_io_cmd;
++
++	memset(&quiesce_io_cmd, 0, cmd_len);
++
++	return ipts_handle_cmd(ipts, TOUCH_SENSOR_QUIESCE_IO_CMD,
++		&quiesce_io_cmd, cmd_len);
++}
++
++int ipts_send_sensor_hid_ready_for_data_cmd(struct ipts_info *ipts)
++{
++	return ipts_handle_cmd(ipts,
++		TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, NULL, 0);
++}
++
++int ipts_send_sensor_clear_mem_window_cmd(struct ipts_info *ipts)
++{
++	return ipts_handle_cmd(ipts,
++		TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD, NULL, 0);
++}
++
++static int check_validity(struct touch_sensor_msg_m2h *m2h_msg, u32 msg_len)
++{
++	int ret = 0;
++	int valid_msg_len = sizeof(m2h_msg->command_code);
++	u32 cmd_code = m2h_msg->command_code;
++
++	switch (cmd_code) {
++	case TOUCH_SENSOR_SET_MODE_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_set_mode_rsp_data);
++		break;
++	case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_set_mem_window_rsp_data);
++		break;
++	case TOUCH_SENSOR_QUIESCE_IO_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_quiesce_io_rsp_data);
++		break;
++	case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_hid_ready_for_data_rsp_data);
++		break;
++	case TOUCH_SENSOR_FEEDBACK_READY_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_feedback_ready_rsp_data);
++		break;
++	case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_clear_mem_window_rsp_data);
++		break;
++	case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_notify_dev_ready_rsp_data);
++		break;
++	case TOUCH_SENSOR_SET_POLICIES_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_set_policies_rsp_data);
++		break;
++	case TOUCH_SENSOR_GET_POLICIES_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_get_policies_rsp_data);
++		break;
++	case TOUCH_SENSOR_RESET_RSP:
++		valid_msg_len +=
++			sizeof(struct touch_sensor_reset_rsp_data);
++		break;
++	}
++
++	if (valid_msg_len != msg_len)
++		return -EINVAL;
++	return ret;
++}
++
++int ipts_start(struct ipts_info *ipts)
++{
++	/*
++	 * TODO: check if we need to do SET_POLICIES_CMD we need to do this
++	 * when protocol version doesn't match with reported one how we keep
++	 * vendor specific data is the first thing to solve.
++	 */
++	ipts_set_state(ipts, IPTS_STA_INIT);
++	ipts->num_of_parallel_data_buffers = TOUCH_SENSOR_MAX_DATA_BUFFERS;
++
++	// start with RAW_DATA
++	ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA;
++
++	return ipts_handle_cmd(ipts,
++		TOUCH_SENSOR_NOTIFY_DEV_READY_CMD, NULL, 0);
++}
++
++void ipts_stop(struct ipts_info *ipts)
++{
++	enum ipts_state old_state = ipts_get_state(ipts);
++
++	ipts_set_state(ipts, IPTS_STA_STOPPING);
++
++	ipts_send_sensor_quiesce_io_cmd(ipts);
++	ipts_send_sensor_clear_mem_window_cmd(ipts);
++
++	if (old_state < IPTS_STA_RESOURCE_READY)
++		return;
++
++	if (old_state == IPTS_STA_RAW_DATA_STARTED ||
++			old_state == IPTS_STA_HID_STARTED) {
++		ipts_free_default_resource(ipts);
++		ipts_free_raw_data_resource(ipts);
++	}
++}
++
++int ipts_restart(struct ipts_info *ipts)
++{
++	ipts_dbg(ipts, "ipts restart\n");
++	ipts_stop(ipts);
++
++	ipts_send_sensor_quiesce_io_cmd(ipts);
++	ipts->restart = true;
++
++	return 0;
++}
++
++int ipts_handle_resp(struct ipts_info *ipts,
++		struct touch_sensor_msg_m2h *m2h_msg, u32 msg_len)
++{
++	int ret = 0;
++	int rsp_status = 0;
++	int cmd_status = 0;
++	int cmd_len = 0;
++	u32 cmd;
++
++	if (!check_validity(m2h_msg, msg_len)) {
++		ipts_err(ipts, "wrong rsp\n");
++		return -EINVAL;
++	}
++
++	rsp_status = m2h_msg->status;
++	cmd = m2h_msg->command_code;
++
++	switch (cmd) {
++	case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP: {
++		if (rsp_status != TOUCH_STATUS_SENSOR_FAIL_NONFATAL &&
++				rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		cmd_status = ipts_handle_cmd(ipts,
++			TOUCH_SENSOR_GET_DEVICE_INFO_CMD, NULL, 0);
++
++		break;
++	}
++	case TOUCH_SENSOR_GET_DEVICE_INFO_RSP: {
++		if (rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL &&
++				rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		memcpy(&ipts->device_info,
++			&m2h_msg->m2h_data.device_info_rsp_data,
++			sizeof(struct touch_sensor_get_device_info_rsp_data));
++
++		/*
++		 * TODO: support raw_request during HID init. Although HID
++		 * init happens here, technically most of reports
++		 * (for both direction) can be issued only after
++		 * SET_MEM_WINDOWS_CMD since they may require ME or touch IC.
++		 * If ipts vendor requires raw_request during HID init, we
++		 * need to consider to move HID init.
++		 */
++		if (ipts->hid_desc_ready == false) {
++			ret = ipts_hid_init(ipts);
++			if (ret)
++				break;
++		}
++
++		cmd_status = ipts_send_sensor_clear_mem_window_cmd(ipts);
++
++		break;
++	}
++	case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP: {
++		struct touch_sensor_set_mode_cmd_data sensor_mode_cmd;
++
++		if (rsp_status != TOUCH_STATUS_TIMEOUT && rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		if (ipts_get_state(ipts) == IPTS_STA_STOPPING)
++			break;
++
++		// allocate default resource: common & hid only
++		if (!ipts_is_default_resource_ready(ipts)) {
++			ret = ipts_allocate_default_resource(ipts);
++			if (ret)
++				break;
++		}
++
++		if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA &&
++				!ipts_is_raw_data_resource_ready(ipts)) {
++			ret = ipts_allocate_raw_data_resource(ipts);
++			if (ret) {
++				ipts_free_default_resource(ipts);
++				break;
++			}
++		}
++
++		ipts_set_state(ipts, IPTS_STA_RESOURCE_READY);
++
++		cmd_len = sizeof(struct touch_sensor_set_mode_cmd_data);
++		memset(&sensor_mode_cmd, 0, cmd_len);
++
++		sensor_mode_cmd.sensor_mode = ipts->sensor_mode;
++		cmd_status = ipts_handle_cmd(ipts, TOUCH_SENSOR_SET_MODE_CMD,
++			&sensor_mode_cmd, cmd_len);
++
++		break;
++	}
++	case TOUCH_SENSOR_SET_MODE_RSP: {
++		struct touch_sensor_set_mem_window_cmd_data smw_cmd;
++
++		if (rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		cmd_len = sizeof(struct touch_sensor_set_mem_window_cmd_data);
++		memset(&smw_cmd, 0, cmd_len);
++
++		ipts_get_set_mem_window_cmd_data(ipts, &smw_cmd);
++		cmd_status = ipts_handle_cmd(ipts,
++			TOUCH_SENSOR_SET_MEM_WINDOW_CMD, &smw_cmd, cmd_len);
++
++		break;
++	}
++	case TOUCH_SENSOR_SET_MEM_WINDOW_RSP: {
++		if (rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		cmd_status = ipts_send_sensor_hid_ready_for_data_cmd(ipts);
++		if (cmd_status)
++			break;
++
++		if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID)
++			ipts_set_state(ipts, IPTS_STA_HID_STARTED);
++		else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA)
++			ipts_set_state(ipts, IPTS_STA_RAW_DATA_STARTED);
++
++		ipts_dbg(ipts, "touch enabled %d\n", ipts_get_state(ipts));
++
++		break;
++	}
++	case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP: {
++		struct touch_sensor_hid_ready_for_data_rsp_data *hid_data;
++		enum ipts_state state;
++
++		if (rsp_status != TOUCH_STATUS_SENSOR_DISABLED &&
++				rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		state = ipts_get_state(ipts);
++		if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID &&
++				state == IPTS_STA_HID_STARTED) {
++			hid_data =
++				&m2h_msg->m2h_data.hid_ready_for_data_rsp_data;
++
++			// HID mode only uses buffer 0
++			if (hid_data->touch_data_buffer_index != 0)
++				break;
++
++			// handle hid data
++			ipts_handle_hid_data(ipts, hid_data);
++		}
++
++		break;
++	}
++	case TOUCH_SENSOR_FEEDBACK_READY_RSP: {
++		if (rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL &&
++				rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		if (m2h_msg->m2h_data.feedback_ready_rsp_data.feedback_index
++				== TOUCH_HID_2_ME_BUFFER_ID)
++			break;
++
++		if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID)
++			cmd_status = ipts_handle_cmd(ipts,
++				TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, NULL, 0);
++
++		break;
++	}
++	case TOUCH_SENSOR_QUIESCE_IO_RSP: {
++		enum ipts_state state;
++
++		if (rsp_status != 0) {
++			rsp_failed(ipts, cmd, rsp_status);
++			break;
++		}
++
++		state = ipts_get_state(ipts);
++		if (state == IPTS_STA_STOPPING && ipts->restart) {
++			ipts_dbg(ipts, "restart\n");
++			ipts_start(ipts);
++			ipts->restart = 0;
++			break;
++		}
++
++		break;
++	}
++	}
++
++	// handle error in rsp_status
++	if (rsp_status != 0) {
++		switch (rsp_status) {
++		case TOUCH_STATUS_SENSOR_EXPECTED_RESET:
++		case TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:
++			ipts_dbg(ipts, "sensor reset %d\n", rsp_status);
++			ipts_restart(ipts);
++			break;
++		default:
++			ipts_dbg(ipts, "cmd : 0x%08x, status %d\n",
++				cmd, rsp_status);
++			break;
++		}
++	}
++
++	if (cmd_status)
++		ipts_restart(ipts);
++
++	return ret;
++}
+diff --git a/drivers/misc/ipts/msg-handler.h b/drivers/misc/ipts/msg-handler.h
+new file mode 100644
+index 000000000000..eca4238adf4b
+--- /dev/null
++++ b/drivers/misc/ipts/msg-handler.h
+@@ -0,0 +1,28 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_MSG_HANDLER_H_
++#define _IPTS_MSG_HANDLER_H_
++
++int ipts_start(struct ipts_info *ipts);
++void ipts_stop(struct ipts_info *ipts);
++int ipts_handle_cmd(struct ipts_info *ipts, u32 cmd, void *data, int data_size);
++
++int ipts_handle_resp(struct ipts_info *ipts,
++		struct touch_sensor_msg_m2h *m2h_msg, u32 msg_len);
++
++int ipts_send_feedback(struct ipts_info *ipts,
++		int buffer_idx, u32 transaction_id);
++
++int ipts_handle_processed_data(struct ipts_info *ipts);
++int ipts_send_sensor_quiesce_io_cmd(struct ipts_info *ipts);
++int ipts_send_sensor_hid_ready_for_data_cmd(struct ipts_info *ipts);
++int ipts_send_sensor_clear_mem_window_cmd(struct ipts_info *ipts);
++int ipts_restart(struct ipts_info *ipts);
++
++#endif /* _IPTS_MSG_HANDLER_H */
+diff --git a/drivers/misc/ipts/params.c b/drivers/misc/ipts/params.c
+new file mode 100644
+index 000000000000..93b19cbf4786
+--- /dev/null
++++ b/drivers/misc/ipts/params.c
+@@ -0,0 +1,46 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/moduleparam.h>
++
++#include "params.h"
++
++#define IPTS_PARAM(NAME, TYPE, PERM, DESC)				\
++	module_param_named(NAME, ipts_modparams.NAME, TYPE, PERM);	\
++	MODULE_PARM_DESC(NAME, DESC)
++
++struct ipts_params ipts_modparams = {
++	.ignore_fw_fallback = false,
++	.ignore_config_fallback = false,
++	.ignore_companion = false,
++	.no_feedback = -1,
++
++	.debug = false,
++	.debug_thread = false,
++};
++
++IPTS_PARAM(ignore_fw_fallback, bool, 0400,
++	"Don't use the IPTS firmware fallback path. (default: false)"
++);
++IPTS_PARAM(ignore_config_fallback, bool, 0400,
++	"Don't try to load the IPTS firmware config from a file. (default: false)"
++);
++IPTS_PARAM(ignore_companion, bool, 0400,
++	"Don't use a companion driver to load firmware. (default: false)"
++);
++IPTS_PARAM(no_feedback, int, 0644,
++	"Disable sending feedback to ME (can prevent crashes on Skylake). (-1=auto [default], 0=false, 1=true)"
++);
++
++IPTS_PARAM(debug, bool, 0400,
++	"Enable IPTS debugging output. (default: false)"
++);
++IPTS_PARAM(debug_thread, bool, 0400,
++	"Periodically print the ME status into the kernel log. (default: false)"
++);
++
+diff --git a/drivers/misc/ipts/params.h b/drivers/misc/ipts/params.h
+new file mode 100644
+index 000000000000..4d9d2bca5ede
+--- /dev/null
++++ b/drivers/misc/ipts/params.h
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_PARAMS_H_
++#define _IPTS_PARAMS_H_
++
++#include <linux/types.h>
++
++struct ipts_params {
++	bool ignore_fw_fallback;
++	bool ignore_config_fallback;
++	bool ignore_companion;
++	int no_feedback;
++
++	bool debug;
++	bool debug_thread;
++};
++
++extern struct ipts_params ipts_modparams;
++
++#endif // _IPTS_PARAMS_H_
+diff --git a/drivers/misc/ipts/resource.c b/drivers/misc/ipts/resource.c
+new file mode 100644
+index 000000000000..cfd212f2cac0
+--- /dev/null
++++ b/drivers/misc/ipts/resource.c
+@@ -0,0 +1,291 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#include <linux/dma-mapping.h>
++
++#include "ipts.h"
++#include "kernel.h"
++#include "mei-msgs.h"
++
++static void free_common_resource(struct ipts_info *ipts)
++{
++	char *addr;
++	struct ipts_buffer_info *feedback_buffer;
++	dma_addr_t dma_addr;
++	u32 buffer_size;
++	int i, num_of_parallels;
++
++	if (ipts->resource.me2hid_buffer) {
++		devm_kfree(&ipts->cldev->dev, ipts->resource.me2hid_buffer);
++		ipts->resource.me2hid_buffer = 0;
++	}
++
++	addr = ipts->resource.hid2me_buffer.addr;
++	dma_addr = ipts->resource.hid2me_buffer.dma_addr;
++	buffer_size = ipts->resource.hid2me_buffer_size;
++
++	if (ipts->resource.hid2me_buffer.addr) {
++		dmam_free_coherent(&ipts->cldev->dev, buffer_size,
++			addr, dma_addr);
++
++		ipts->resource.hid2me_buffer.addr = 0;
++		ipts->resource.hid2me_buffer.dma_addr = 0;
++		ipts->resource.hid2me_buffer_size = 0;
++	}
++
++	feedback_buffer = ipts->resource.feedback_buffer;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	for (i = 0; i < num_of_parallels; i++) {
++
++		if (!feedback_buffer[i].addr)
++			continue;
++
++		dmam_free_coherent(&ipts->cldev->dev,
++			ipts->device_info.feedback_size,
++			feedback_buffer[i].addr, feedback_buffer[i].dma_addr);
++
++		feedback_buffer[i].addr = 0;
++		feedback_buffer[i].dma_addr = 0;
++	}
++}
++
++static int allocate_common_resource(struct ipts_info *ipts)
++{
++	char *addr, *me2hid_addr;
++	struct ipts_buffer_info *feedback_buffer;
++	dma_addr_t dma_addr;
++	int i, ret = 0, num_of_parallels;
++	u32 buffer_size;
++
++	buffer_size = ipts->device_info.feedback_size;
++
++	addr = dmam_alloc_coherent(&ipts->cldev->dev, buffer_size, &dma_addr,
++		GFP_ATOMIC | __GFP_ZERO);
++	if (addr == NULL)
++		return -ENOMEM;
++
++	me2hid_addr = devm_kzalloc(&ipts->cldev->dev, buffer_size, GFP_KERNEL);
++	if (me2hid_addr == NULL) {
++		ret = -ENOMEM;
++		goto release_resource;
++	}
++
++	ipts->resource.hid2me_buffer.addr = addr;
++	ipts->resource.hid2me_buffer.dma_addr = dma_addr;
++	ipts->resource.hid2me_buffer_size = buffer_size;
++	ipts->resource.me2hid_buffer = me2hid_addr;
++
++	feedback_buffer = ipts->resource.feedback_buffer;
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++
++	for (i = 0; i < num_of_parallels; i++) {
++		feedback_buffer[i].addr = dmam_alloc_coherent(&ipts->cldev->dev,
++			ipts->device_info.feedback_size,
++			&feedback_buffer[i].dma_addr, GFP_ATOMIC|__GFP_ZERO);
++
++		if (feedback_buffer[i].addr == NULL) {
++			ret = -ENOMEM;
++			goto release_resource;
++		}
++	}
++
++	return 0;
++
++release_resource:
++	free_common_resource(ipts);
++
++	return ret;
++}
++
++void ipts_free_raw_data_resource(struct ipts_info *ipts)
++{
++	if (ipts_is_raw_data_resource_ready(ipts)) {
++		ipts->resource.raw_data_resource_ready = false;
++		ipts_release_kernels(ipts);
++	}
++}
++
++static int allocate_hid_resource(struct ipts_info *ipts)
++{
++	struct ipts_buffer_info *buffer_hid;
++
++	// hid mode uses only one touch data buffer
++	buffer_hid = &ipts->resource.touch_data_buffer_hid;
++	buffer_hid->addr = dmam_alloc_coherent(&ipts->cldev->dev,
++		ipts->device_info.frame_size, &buffer_hid->dma_addr,
++		GFP_ATOMIC|__GFP_ZERO);
++
++	if (buffer_hid->addr == NULL)
++		return -ENOMEM;
++
++	return 0;
++}
++
++static void free_hid_resource(struct ipts_info *ipts)
++{
++	struct ipts_buffer_info *buffer_hid;
++
++	buffer_hid = &ipts->resource.touch_data_buffer_hid;
++	if (buffer_hid->addr) {
++		dmam_free_coherent(&ipts->cldev->dev,
++			ipts->device_info.frame_size,
++			buffer_hid->addr, buffer_hid->dma_addr);
++
++		buffer_hid->addr = 0;
++		buffer_hid->dma_addr = 0;
++	}
++}
++
++int ipts_allocate_default_resource(struct ipts_info *ipts)
++{
++	int ret;
++
++	ret = allocate_common_resource(ipts);
++	if (ret) {
++		ipts_dbg(ipts, "cannot allocate common resource\n");
++		return ret;
++	}
++
++	ret = allocate_hid_resource(ipts);
++	if (ret) {
++		ipts_dbg(ipts, "cannot allocate hid resource\n");
++		free_common_resource(ipts);
++		return ret;
++	}
++
++	ipts->resource.default_resource_ready = true;
++
++	return 0;
++}
++
++void ipts_free_default_resource(struct ipts_info *ipts)
++{
++	if (ipts_is_default_resource_ready(ipts)) {
++		ipts->resource.default_resource_ready = false;
++		free_hid_resource(ipts);
++		free_common_resource(ipts);
++	}
++}
++
++int ipts_allocate_raw_data_resource(struct ipts_info *ipts)
++{
++	int ret = 0;
++
++	ret = ipts_init_kernels(ipts);
++	if (ret)
++		return ret;
++
++	ipts->resource.raw_data_resource_ready = true;
++	return 0;
++}
++
++static void get_hid_only_smw_cmd_data(struct ipts_info *ipts,
++		struct touch_sensor_set_mem_window_cmd_data *data,
++		struct ipts_resource *resrc)
++{
++	struct ipts_buffer_info *touch_buf;
++	struct ipts_buffer_info *feedback_buf;
++
++	touch_buf = &resrc->touch_data_buffer_hid;
++	feedback_buf = &resrc->feedback_buffer[0];
++
++	data->touch_data_buffer_addr_lower[0] =
++		lower_32_bits(touch_buf->dma_addr);
++
++	data->touch_data_buffer_addr_upper[0] =
++		upper_32_bits(touch_buf->dma_addr);
++
++	data->feedback_buffer_addr_lower[0] =
++		lower_32_bits(feedback_buf->dma_addr);
++
++	data->feedback_buffer_addr_upper[0] =
++		upper_32_bits(feedback_buf->dma_addr);
++}
++
++static void get_raw_data_only_smw_cmd_data(struct ipts_info *ipts,
++		struct touch_sensor_set_mem_window_cmd_data *data,
++		struct ipts_resource *resrc)
++{
++	u64 wq_tail_phy_addr;
++	u64 cookie_phy_addr;
++	struct ipts_buffer_info *touch_buf;
++	struct ipts_buffer_info *feedback_buf;
++	int i, num_of_parallels;
++
++	touch_buf = resrc->touch_data_buffer_raw;
++	feedback_buf = resrc->feedback_buffer;
++
++	num_of_parallels = ipts_get_num_of_parallel_buffers(ipts);
++	for (i = 0; i < num_of_parallels; i++) {
++		data->touch_data_buffer_addr_lower[i] =
++			lower_32_bits(touch_buf[i].dma_addr);
++
++		data->touch_data_buffer_addr_upper[i] =
++			upper_32_bits(touch_buf[i].dma_addr);
++
++		data->feedback_buffer_addr_lower[i] =
++			lower_32_bits(feedback_buf[i].dma_addr);
++
++		data->feedback_buffer_addr_upper[i] =
++			upper_32_bits(feedback_buf[i].dma_addr);
++	}
++
++	wq_tail_phy_addr = resrc->wq_info.wq_tail_phy_addr;
++	data->tail_offset_addr_lower = lower_32_bits(wq_tail_phy_addr);
++	data->tail_offset_addr_upper = upper_32_bits(wq_tail_phy_addr);
++
++	cookie_phy_addr = resrc->wq_info.db_phy_addr +
++		resrc->wq_info.db_cookie_offset;
++
++	data->doorbell_cookie_addr_lower = lower_32_bits(cookie_phy_addr);
++	data->doorbell_cookie_addr_upper = upper_32_bits(cookie_phy_addr);
++	data->work_queue_size = resrc->wq_info.wq_size;
++	data->work_queue_item_size = resrc->wq_item_size;
++}
++
++void ipts_get_set_mem_window_cmd_data(struct ipts_info *ipts,
++		struct touch_sensor_set_mem_window_cmd_data *data)
++{
++	struct ipts_resource *resrc = &ipts->resource;
++
++	if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA)
++		get_raw_data_only_smw_cmd_data(ipts, data, resrc);
++	else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID)
++		get_hid_only_smw_cmd_data(ipts, data, resrc);
++
++	// hid2me is common for "raw data" and "hid"
++	data->hid2me_buffer_addr_lower =
++		lower_32_bits(resrc->hid2me_buffer.dma_addr);
++
++	data->hid2me_buffer_addr_upper =
++		upper_32_bits(resrc->hid2me_buffer.dma_addr);
++
++	data->hid2me_buffer_size = resrc->hid2me_buffer_size;
++}
++
++void ipts_set_input_buffer(struct ipts_info *ipts, int parallel_idx,
++		u8 *cpu_addr, u64 dma_addr)
++{
++	struct ipts_buffer_info *touch_buf;
++
++	touch_buf = ipts->resource.touch_data_buffer_raw;
++	touch_buf[parallel_idx].dma_addr = dma_addr;
++	touch_buf[parallel_idx].addr = cpu_addr;
++}
++
++void ipts_set_output_buffer(struct ipts_info *ipts, int parallel_idx,
++		int output_idx, u8 *cpu_addr, u64 dma_addr)
++{
++	struct ipts_buffer_info *output_buf;
++
++	output_buf = &ipts->resource.raw_data_mode_output_buffer
++		[parallel_idx][output_idx];
++
++	output_buf->dma_addr = dma_addr;
++	output_buf->addr = cpu_addr;
++}
+diff --git a/drivers/misc/ipts/resource.h b/drivers/misc/ipts/resource.h
+new file mode 100644
+index 000000000000..27b9c17fcb89
+--- /dev/null
++++ b/drivers/misc/ipts/resource.h
+@@ -0,0 +1,26 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_RESOURCE_H_
++#define _IPTS_RESOURCE_H_
++
++int ipts_allocate_default_resource(struct ipts_info *ipts);
++void ipts_free_default_resource(struct ipts_info *ipts);
++int ipts_allocate_raw_data_resource(struct ipts_info *ipts);
++void ipts_free_raw_data_resource(struct ipts_info *ipts);
++
++void ipts_get_set_mem_window_cmd_data(struct ipts_info *ipts,
++		struct touch_sensor_set_mem_window_cmd_data *data);
++
++void ipts_set_input_buffer(struct ipts_info *ipts, int parallel_idx,
++		u8 *cpu_addr, u64 dma_addr);
++
++void ipts_set_output_buffer(struct ipts_info *ipts, int parallel_idx,
++		int output_idx, u8 *cpu_addr, u64 dma_addr);
++
++#endif // _IPTS_RESOURCE_H_
+diff --git a/drivers/misc/ipts/sensor-regs.h b/drivers/misc/ipts/sensor-regs.h
+new file mode 100644
+index 000000000000..c1afab48249b
+--- /dev/null
++++ b/drivers/misc/ipts/sensor-regs.h
+@@ -0,0 +1,834 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2013-2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_SENSOR_REGS_H_
++#define _IPTS_SENSOR_REGS_H_
++
++#include <linux/build_bug.h>
++
++#pragma pack(1)
++
++// Define static_assert macro (which will be available after 5.1
++// and not available on 4.19 yet) to check structure size and fail
++// compile for unexpected mismatch.
++// Taken from upstream commit 6bab69c65013bed5fce9f101a64a84d0385b3946.
++#define static_assert(expr, ...) __static_assert(expr, ##__VA_ARGS__, #expr)
++#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
++
++/*
++ * Compatibility versions for this header file
++ */
++#define TOUCH_EDS_REV_MINOR 0
++#define TOUCH_EDS_REV_MAJOR 1
++#define TOUCH_EDS_INTF_REV 1
++#define TOUCH_PROTOCOL_VER 0
++
++/*
++ * Offset 00h: TOUCH_STS: Status Register
++ * This register is read by the SPI Controller immediately following
++ * an interrupt.
++ */
++#define TOUCH_STS_REG_OFFSET 0x00
++
++#define TOUCH_SYNC_BYTE_VALUE 0x5A
++
++/*
++ * Offset 04h: TOUCH_FRAME_CHAR: Frame Characteristics Register
++ * This registers describes the characteristics of each data frame read by the
++ * SPI Controller in response to a touch interrupt.
++ */
++#define TOUCH_FRAME_CHAR_REG_OFFSET 0x04
++
++/*
++ * Offset 08h: Touch Error Register
++ */
++#define TOUCH_ERR_REG_OFFSET 0x08
++
++/*
++ * Offset 10h: Touch Identification Register
++ */
++#define TOUCH_ID_REG_OFFSET 0x10
++#define TOUCH_ID_REG_VALUE  0x43495424
++
++/*
++ * Offset 14h: TOUCH_DATA_SZ: Touch Data Size Register
++ * This register describes the maximum size of frames and feedback data
++ */
++#define TOUCH_DATA_SZ_REG_OFFSET 0x14
++
++#define TOUCH_MAX_FRAME_SIZE_INCREMENT    64
++#define TOUCH_MAX_FEEDBACK_SIZE_INCREMENT 64
++
++/*
++ * Max allowed frame size 32KB
++ * Max allowed feedback size 16KB
++ */
++#define TOUCH_SENSOR_MAX_FRAME_SIZE    (32 * 1024)
++#define TOUCH_SENSOR_MAX_FEEDBACK_SIZE (16 * 1024)
++
++/*
++ * Offset 18h: TOUCH_CAPABILITIES: Touch Capabilities Register
++ * This register informs the host as to the capabilities of the touch IC.
++ */
++#define TOUCH_CAPS_REG_OFFSET 0x18
++
++#define TOUCH_BULK_DATA_MAX_WRITE_INCREMENT 64
++
++/*
++ * Offset 1Ch: TOUCH_CFG: Touch Configuration Register
++ * This register allows the SPI Controller to configure the touch sensor as
++ * needed during touch operations.
++ */
++#define TOUCH_CFG_REG_OFFSET 0x1C
++
++/*
++ * Offset 20h: TOUCH_CMD: Touch Command Register
++ * This register is used for sending commands to the Touch IC.
++ */
++#define TOUCH_CMD_REG_OFFSET 0x20
++
++/*
++ * Offset 24h: Power Management Control
++ * This register is used for active power management. The Touch IC is allowed
++ * to mover from Doze or Armed to Sensing after a touch has occurred. All other
++ * transitions will be made at the request of the SPI Controller.
++ */
++#define TOUCH_PWR_MGMT_CTRL_REG_OFFSET 0x24
++
++/*
++ * Offset 28h: Vendor HW Information Register
++ * This register is used to relay Intel-assigned vendor ID information to the
++ * SPI Controller, which may be forwarded to SW running on the host CPU.
++ */
++#define TOUCH_VEN_HW_INFO_REG_OFFSET 0x28
++
++/*
++ * Offset 2Ch: HW Revision ID Register
++ * This register is used to relay vendor HW revision information to the SPI
++ * Controller which may be forwarded to SW running on the host CPU.
++ */
++#define TOUCH_HW_REV_REG_OFFSET 0x2C
++
++/*
++ * Offset 30h: FW Revision ID Register
++ * This register is used to relay vendor FW revision information to the SPI
++ * Controller which may be forwarded to SW running on the host CPU.
++ */
++#define TOUCH_FW_REV_REG_OFFSET 0x30
++
++/*
++ * Offset 34h: Compatibility Revision ID Register
++ * This register is used to relay vendor compatibility information to the SPI
++ * Controller which may be forwarded to SW running on the host CPU.
++ * Compatibility Information is a numeric value given by Intel to the Touch IC
++ * vendor based on the major and minor revision of the EDS supported. From a
++ * nomenclature point of view in an x.y revision number of the EDS, the major
++ * version is the value of x and the minor version is the value of y. For
++ * example, a Touch IC supporting an EDS version of 0.61 would contain a major
++ * version of 0 and a minor version of 61 in the register.
++ */
++#define TOUCH_COMPAT_REV_REG_OFFSET 0x34
++
++/*
++ * Touch Register Block is the full set of registers from offset 0x00h to 0x3F
++ * This is the entire set of registers needed for normal touch operation. It
++ * does not include test registers such as TOUCH_TEST_CTRL_REG
++ */
++#define TOUCH_REG_BLOCK_OFFSET TOUCH_STS_REG_OFFSET
++
++/*
++ * Offset 40h: Test Control Register
++ * This register
++ */
++#define TOUCH_TEST_CTRL_REG_OFFSET 0x40
++
++/*
++ * Offsets 0x000 to 0xFFF are reserved for Intel-defined Registers
++ */
++#define TOUCH_REGISTER_LIMIT 0xFFF
++
++/*
++ * Data Window: Address 0x1000-0x1FFFF
++ * The data window is reserved for writing and reading large quantities of
++ * data to and from the sensor.
++ */
++#define TOUCH_DATA_WINDOW_OFFSET 0x1000
++#define TOUCH_DATA_WINDOW_LIMIT  0x1FFFF
++
++#define TOUCH_SENSOR_MAX_OFFSET TOUCH_DATA_WINDOW_LIMIT
++
++enum touch_sts_reg_int_type {
++	// Touch Data Available
++	TOUCH_STS_REG_INT_TYPE_DATA_AVAIL = 0,
++
++	// Reset Occurred
++	TOUCH_STS_REG_INT_TYPE_RESET_OCCURRED,
++
++	// Error Occurred
++	TOUCH_STS_REG_INT_TYPE_ERROR_OCCURRED,
++
++	// Vendor specific data, treated same as raw frame
++	TOUCH_STS_REG_INT_TYPE_VENDOR_DATA,
++
++	// Get Features response data available
++	TOUCH_STS_REG_INT_TYPE_GET_FEATURES,
++
++	TOUCH_STS_REG_INT_TYPE_MAX
++};
++static_assert(sizeof(enum touch_sts_reg_int_type) == 4);
++
++enum touch_sts_reg_pwr_state {
++	// Sleep
++	TOUCH_STS_REG_PWR_STATE_SLEEP = 0,
++
++	// Doze
++	TOUCH_STS_REG_PWR_STATE_DOZE,
++
++	// Armed
++	TOUCH_STS_REG_PWR_STATE_ARMED,
++
++	// Sensing
++	TOUCH_STS_REG_PWR_STATE_SENSING,
++
++	TOUCH_STS_REG_PWR_STATE_MAX
++};
++static_assert(sizeof(enum touch_sts_reg_pwr_state) == 4);
++
++enum touch_sts_reg_init_state {
++	// Ready for normal operation
++	TOUCH_STS_REG_INIT_STATE_READY_FOR_OP = 0,
++
++	// Touch IC needs its Firmware loaded
++	TOUCH_STS_REG_INIT_STATE_FW_NEEDED,
++
++	// Touch IC needs its Data loaded
++	TOUCH_STS_REG_INIT_STATE_DATA_NEEDED,
++
++	// Error info in TOUCH_ERR_REG
++	TOUCH_STS_REG_INIT_STATE_INIT_ERROR,
++
++	TOUCH_STS_REG_INIT_STATE_MAX
++};
++static_assert(sizeof(enum touch_sts_reg_init_state) == 4);
++
++union touch_sts_reg {
++	u32 reg_value;
++	struct {
++		// When set, this indicates the hardware has data
++		// that needs to be read.
++		u32 int_status:1;
++
++		// see TOUCH_STS_REG_INT_TYPE
++		u32 int_type:4;
++
++		// see TOUCH_STS_REG_PWR_STATE
++		u32 pwr_state:2;
++
++		// see TOUCH_STS_REG_INIT_STATE
++		u32 init_state:2;
++
++		// Busy bit indicates that sensor cannot
++		// accept writes at this time
++		u32 busy:1;
++
++		// Reserved
++		u32 reserved:14;
++
++		// Synchronization bit, should always be TOUCH_SYNC_BYTE_VALUE
++		u32 sync_byte:8;
++	} fields;
++};
++static_assert(sizeof(union touch_sts_reg) == 4);
++
++union touch_frame_char_reg {
++	u32  reg_value;
++	struct {
++		// Micro-Frame Size (MFS): Indicates the size of a touch
++		// micro-frame in byte increments. When a micro-frame is to be
++		// read for processing (in data mode), this is the total number
++		// of bytes that must be read per interrupt, split into
++		// multiple read commands no longer than RPS.
++		// Maximum micro-frame size is 256KB.
++		u32 microframe_size:18;
++
++		// Micro-Frames per Frame (MFPF): Indicates the number of
++		// micro-frames per frame. If a sensor's frame does not contain
++		// micro-frames this value will be 1. Valid values are 1-31.
++		u32 microframes_per_frame:5;
++
++		// Micro-Frame Index (MFI): Indicates the index of the
++		// micro-frame within a frame. This allows the SPI Controller
++		// to maintain synchronization with the sensor and determine
++		// when the final micro-frame has arrived.
++		// Valid values are 1-31.
++		u32 microframe_index:5;
++
++		// HID/Raw Data: This bit describes whether the data from the
++		// sensor is Raw data or a HID report. When set, the data
++		// is a HID report.
++		u32 hid_report:1;
++
++		// Reserved
++		u32 reserved:3;
++	} fields;
++};
++static_assert(sizeof(union touch_frame_char_reg) == 4);
++
++// bit definition is vendor specific
++union touch_err_reg {
++	u32  reg_value;
++	struct {
++		u32 invalid_fw:1;
++		u32 invalid_data:1;
++		u32 self_test_failed:1;
++		u32 reserved:12;
++		u32 fatal_error:1;
++		u32 vendor_errors:16;
++	} fields;
++};
++static_assert(sizeof(union touch_err_reg) == 4);
++
++union touch_data_sz_reg {
++	u32  reg_value;
++	struct {
++		// This value describes the maximum frame size in
++		// 64byte increments.
++		u32 max_frame_size:12;
++
++		// This value describes the maximum feedback size in
++		// 64byte increments.
++		u32 max_feedback_size:8;
++
++		// Reserved
++		u32 reserved:12;
++	} fields;
++};
++static_assert(sizeof(union touch_data_sz_reg) == 4);
++
++enum touch_caps_reg_read_delay_time {
++	TOUCH_CAPS_REG_READ_DELAY_TIME_0,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_10uS,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_50uS,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_100uS,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_150uS,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_250uS,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_500uS,
++	TOUCH_CAPS_REG_READ_DELAY_TIME_1mS,
++};
++static_assert(sizeof(enum touch_caps_reg_read_delay_time) == 4);
++
++union touch_caps_reg {
++	u32  reg_value;
++	struct {
++		// Reserved for future frequency
++		u32 reserved0:1;
++
++		// 17 MHz (14 MHz on Atom) Supported
++		// 0b - Not supported, 1b - Supported
++		u32 supported_17Mhz:1;
++
++		// 30 MHz (25MHz on Atom) Supported
++		// 0b - Not supported, 1b - Supported
++		u32 supported_30Mhz:1;
++
++		// 50 MHz Supported
++		// 0b - Not supported, 1b - Supported
++		u32 supported_50Mhz:1;
++
++		// Reserved
++		u32 reserved1:4;
++
++		// Single I/O Supported
++		// 0b - Not supported, 1b - Supported
++		u32 supported_single_io:1;
++
++		// Dual I/O Supported
++		// 0b - Not supported, 1b - Supported
++		u32 supported_dual_io:1;
++
++		// Quad I/O Supported
++		// 0b - Not supported, 1b - Supported
++		u32 supported_quad_io:1;
++
++		// Bulk Data Area Max Write Size: The amount of data the SPI
++		// Controller can write to the bulk data area before it has to
++		// poll the busy bit. This field is in multiples of 64 bytes.
++		// The SPI Controller will write the amount of data specified
++		// in this field, then check and wait for the Status.Busy bit
++		// to be zero before writing the next data chunk. This field is
++		// 6 bits long, allowing for 4KB of contiguous writes w/o a
++		// poll of the busy bit. If this field is 0x00 the Touch IC has
++		// no limit in the amount of data the SPI Controller can write
++		// to the bulk data area.
++		u32 bulk_data_max_write:6;
++
++		// Read Delay Timer Value: This field describes the delay the
++		// SPI Controller will initiate when a read interrupt follows
++		// a write data command. Uses values from
++		// TOUCH_CAPS_REG_READ_DELAY_TIME
++		u32 read_delay_timer_value:3;
++
++		// Reserved
++		u32 reserved2:4;
++
++		// Maximum Touch Points: A byte value based on the
++		// HID descriptor definition.
++		u32 max_touch_points:8;
++	} fields;
++};
++static_assert(sizeof(union touch_caps_reg) == 4);
++
++enum touch_cfg_reg_bulk_xfer_size {
++	// Bulk Data Transfer Size is 4 bytes
++	TOUCH_CFG_REG_BULK_XFER_SIZE_4B  = 0,
++
++	// Bulk Data Transfer Size is 8 bytes
++	TOUCH_CFG_REG_BULK_XFER_SIZE_8B,
++
++	// Bulk Data Transfer Size is 16 bytes
++	TOUCH_CFG_REG_BULK_XFER_SIZE_16B,
++
++	// Bulk Data Transfer Size is 32 bytes
++	TOUCH_CFG_REG_BULK_XFER_SIZE_32B,
++
++	// Bulk Data Transfer Size is 64 bytes
++	TOUCH_CFG_REG_BULK_XFER_SIZE_64B,
++
++	TOUCH_CFG_REG_BULK_XFER_SIZE_MAX
++};
++static_assert(sizeof(enum touch_cfg_reg_bulk_xfer_size) == 4);
++
++/*
++ * Frequency values used by TOUCH_CFG_REG
++ * and TOUCH_SENSOR_GET_DEVICE_INFO_RSP_DATA.
++ */
++enum touch_freq {
++	// Reserved value
++	TOUCH_FREQ_RSVD = 0,
++
++	// Sensor set for 17MHz operation (14MHz on Atom)
++	TOUCH_FREQ_17MHZ,
++
++	// Sensor set for 30MHz operation (25MHz on Atom)
++	TOUCH_FREQ_30MHZ,
++
++	// Invalid value
++	TOUCH_FREQ_MAX
++};
++static_assert(sizeof(enum touch_freq) == 4);
++
++union touch_cfg_reg {
++	u32  reg_value;
++	struct {
++		// Touch Enable (TE): This bit is used as a HW semaphore for
++		// the Touch IC to guarantee to the SPI Controller to that
++		// (when 0) no sensing operations will occur and only the Reset
++		// interrupt will be generated.
++		//
++		// When TE is cleared by the SPI
++		// Controller:
++		//     - TICs must flush all output buffers
++		//     - TICs must De-assert any pending interrupt
++		//     - ME must throw away any partial frame and pending
++		//       interrupt must be cleared/not serviced.
++		//
++		// The SPI Controller will only modify the configuration of the
++		// TIC when TE is cleared.
++		// TE is defaulted to 0h on a power-on reset.
++		u32 touch_enable:1;
++
++		// Data/HID Packet Mode (DHPM)
++		// Raw Data Mode: 0h, HID Packet Mode: 1h
++		u32 dhpm:1;
++
++		// Bulk Data Transfer Size: This field represents the amount
++		// of data written to the Bulk Data Area
++		// (SPI Offset 0x1000-0x2FFF) in a single SPI write protocol
++		u32 bulk_xfer_size:4;
++
++		// Frequency Select: Frequency for the TouchIC to run at.
++		// Use values from TOUCH_FREQ
++		u32 freq_select:3;
++
++		// Reserved
++		u32 reserved:23;
++	} fields;
++};
++static_assert(sizeof(union touch_cfg_reg) == 4);
++
++enum touch_cmd_reg_code {
++	// No Operation
++	TOUCH_CMD_REG_CODE_NOP = 0,
++
++	// Soft Reset
++	TOUCH_CMD_REG_CODE_SOFT_RESET,
++
++	// Prepare All Registers for Read
++	TOUCH_CMD_REG_CODE_PREP_4_READ,
++
++	// Generate Test Packets according to value in TOUCH_TEST_CTRL_REG
++	TOUCH_CMD_REG_CODE_GEN_TEST_PACKETS,
++
++	TOUCH_CMD_REG_CODE_MAX
++};
++static_assert(sizeof(enum touch_cmd_reg_code) == 4);
++
++union touch_cmd_reg {
++	u32 reg_value;
++	struct {
++		// Command Code: See TOUCH_CMD_REG_CODE
++		u32 command_code:8;
++
++		// Reserved
++		u32 reserved:24;
++	} fields;
++};
++static_assert(sizeof(union touch_cmd_reg) == 4);
++
++enum touch_pwr_mgmt_ctrl_reg_cmd {
++	// No change to power state
++	TOUCH_PWR_MGMT_CTRL_REG_CMD_NOP = 0,
++
++	// Sleep - set when the system goes into connected standby
++	TOUCH_PWR_MGMT_CTRL_REG_CMD_SLEEP,
++
++	// Doze - set after 300 seconds of inactivity
++	TOUCH_PWR_MGMT_CTRL_REG_CMD_DOZE,
++
++	// Armed - Set by FW when a "finger off" message is
++	// received from the EUs
++	TOUCH_PWR_MGMT_CTRL_REG_CMD_ARMED,
++
++	// Sensing - not typically set by FW
++	TOUCH_PWR_MGMT_CTRL_REG_CMD_SENSING,
++
++	// Values will result in no change to the power state of the Touch IC
++	TOUCH_PWR_MGMT_CTRL_REG_CMD_MAX
++};
++static_assert(sizeof(enum touch_pwr_mgmt_ctrl_reg_cmd) == 4);
++
++union touch_pwr_mgmt_ctrl_reg {
++	u32  reg_value;
++	struct {
++		// Power State Command: See TOUCH_PWR_MGMT_CTRL_REG_CMD
++		u32 pwr_state_cmd:3;
++
++		// Reserved
++		u32 reserved:29;
++	} fields;
++};
++static_assert(sizeof(union touch_pwr_mgmt_ctrl_reg) == 4);
++
++union touch_ven_hw_info_reg {
++	u32  reg_value;
++	struct {
++		// Touch Sensor Vendor ID
++		u32 vendor_id:16;
++
++		// Touch Sensor Device ID
++		u32 device_id:16;
++	} fields;
++};
++static_assert(sizeof(union touch_ven_hw_info_reg) == 4);
++
++union touch_compat_rev_reg {
++	u32  reg_value;
++
++	struct {
++		// EDS Minor Revision
++		u8 minor;
++
++		// EDS Major Revision
++		u8 major;
++
++		// Interface Revision Number (from EDS)
++		u8 intf_rev;
++
++		// EU Kernel Compatibility Version - vendor specific value
++		u8 kernel_compat_ver;
++	} fields;
++};
++static_assert(sizeof(union touch_compat_rev_reg) == 4);
++
++struct touch_reg_block {
++	// 0x00
++	union touch_sts_reg sts_reg;
++
++	// 0x04
++	union touch_frame_char_reg frame_char_reg;
++
++	// 0x08
++	union touch_err_reg error_reg;
++
++	// 0x0C
++	u32 reserved0;
++
++	// 0x10 - expected value is "$TIC" or 0x43495424
++	u32 id_reg;
++
++	// 0x14
++	union touch_data_sz_reg data_size_reg;
++
++	// 0x18
++	union touch_caps_reg caps_reg;
++
++	// 0x1C
++	union touch_cfg_reg cfg_reg;
++
++	// 0x20
++	union touch_cmd_reg cmd_reg;
++
++	// 0x24
++	union touch_pwr_mgmt_ctrl_reg pwm_mgme_ctrl_reg;
++
++	// 0x28
++	union touch_ven_hw_info_reg ven_hw_info_reg;
++
++	// 0x2C
++	u32 hw_rev_reg;
++
++	// 0x30
++	u32 fw_rev_reg;
++
++	// 0x34
++	union touch_compat_rev_reg compat_rev_reg;
++
++	// 0x38
++	u32 reserved1;
++
++	// 0x3C
++	u32 reserved2;
++};
++static_assert(sizeof(struct touch_reg_block) == 64);
++
++union touch_test_ctrl_reg {
++	u32  reg_value;
++	struct {
++		// Size of Test Frame in Raw Data Mode: This field specifies
++		// the test frame size in raw data mode in multiple of 64 bytes.
++		// For example, if this field value is 16, the test frame size
++		// will be 16x64 = 1K.
++		u32 raw_test_frame_size:16;
++
++		// Number of Raw Data Frames or HID Report Packets Generation.
++		// This field represents the number of test frames or HID
++		// reports to be generated when test mode is enabled. When
++		// multiple packets/frames are generated, they need be
++		// generated at 100 Hz frequency, i.e. 10ms per packet/frame.
++		u32 num_test_frames:16;
++	} fields;
++};
++static_assert(sizeof(union touch_test_ctrl_reg) == 4);
++
++/*
++ * The following data structures represent the headers defined in the Data
++ * Structures chapter of the Intel Integrated Touch EDS
++ */
++
++// Enumeration used in TOUCH_RAW_DATA_HDR
++enum touch_raw_data_types {
++	TOUCH_RAW_DATA_TYPE_FRAME = 0,
++
++	// RawData will be the TOUCH_ERROR struct below
++	TOUCH_RAW_DATA_TYPE_ERROR,
++
++	// Set when InterruptType is Vendor Data
++	TOUCH_RAW_DATA_TYPE_VENDOR_DATA,
++
++	TOUCH_RAW_DATA_TYPE_HID_REPORT,
++	TOUCH_RAW_DATA_TYPE_GET_FEATURES,
++	TOUCH_RAW_DATA_TYPE_MAX
++};
++static_assert(sizeof(enum touch_raw_data_types) == 4);
++
++// Private data structure. Kernels must copy to HID driver buffer
++struct touch_hid_private_data {
++	u32 transaction_id;
++	u8 reserved[28];
++};
++static_assert(sizeof(struct touch_hid_private_data) == 32);
++
++// This is the data structure sent from the PCH FW to the EU kernel
++struct touch_raw_data_hdr {
++	// use values from TOUCH_RAW_DATA_TYPES
++	u32 data_type;
++
++	// The size in bytes of the raw data read from the sensor, does not
++	// include TOUCH_RAW_DATA_HDR. Will be the sum of all uFrames, or size
++	// of TOUCH_ERROR for if DataType is TOUCH_RAW_DATA_TYPE_ERROR
++	u32 raw_data_size_bytes;
++
++	// An ID to qualify with the feedback data to track buffer usage
++	u32 buffer_id;
++
++	// Must match protocol version of the EDS
++	u32 protocol_ver;
++
++	// Copied from the Compatibility Revision ID Reg
++	u8 kernel_compat_id;
++
++	// Padding to extend header to full 64 bytes and allow for growth
++	u8 reserved[15];
++
++	// Private data structure. Kernels must copy to HID driver buffer
++	struct touch_hid_private_data hid_private_data;
++};
++static_assert(sizeof(struct touch_raw_data_hdr) == 64);
++
++struct touch_raw_data {
++	struct touch_raw_data_hdr header;
++
++	// used to access the raw data as an array and keep the compilers
++	// happy. Actual size of this array is Header.RawDataSizeBytes
++	u8 raw_data[1];
++};
++
++/*
++ * The following section describes the data passed in TOUCH_RAW_DATA.RawData
++ * when DataType equals TOUCH_RAW_DATA_TYPE_ERROR
++ * Note: This data structure is also applied to HID mode
++ */
++enum touch_err_types {
++	TOUCH_RAW_DATA_ERROR = 0,
++	TOUCH_RAW_ERROR_MAX
++};
++static_assert(sizeof(enum touch_err_types) == 4);
++
++union touch_me_fw_error {
++	u32  value;
++	struct {
++		u32 invalid_frame_characteristics:1;
++		u32 microframe_index_invalid:1;
++		u32 reserved:30;
++	} fields;
++};
++static_assert(sizeof(union touch_me_fw_error) == 4);
++
++struct touch_error {
++	// This must be a value from TOUCH_ERROR_TYPES
++	u8 touch_error_type;
++	u8 reserved[3];
++	union touch_me_fw_error touch_me_fw_error;
++
++	// Contains the value copied from the Touch Error Reg
++	union touch_err_reg touch_error_register;
++};
++static_assert(sizeof(struct touch_error) == 12);
++
++// Enumeration used in TOUCH_FEEDBACK_BUFFER
++enum touch_feedback_cmd_types {
++	TOUCH_FEEDBACK_CMD_TYPE_NONE = 0,
++	TOUCH_FEEDBACK_CMD_TYPE_SOFT_RESET,
++	TOUCH_FEEDBACK_CMD_TYPE_GOTO_ARMED,
++	TOUCH_FEEDBACK_CMD_TYPE_GOTO_SENSING,
++	TOUCH_FEEDBACK_CMD_TYPE_GOTO_SLEEP,
++	TOUCH_FEEDBACK_CMD_TYPE_GOTO_DOZE,
++	TOUCH_FEEDBACK_CMD_TYPE_HARD_RESET,
++	TOUCH_FEEDBACK_CMD_TYPE_MAX
++};
++static_assert(sizeof(enum touch_feedback_cmd_types) == 4);
++
++// Enumeration used in TOUCH_FEEDBACK_HDR
++enum touch_feedback_data_types {
++	// This is vendor specific feedback to be written to the sensor
++	TOUCH_FEEDBACK_DATA_TYPE_FEEDBACK = 0,
++
++	// This is a set features command to be written to the sensor
++	TOUCH_FEEDBACK_DATA_TYPE_SET_FEATURES,
++
++	// This is a get features command to be written to the sensor
++	TOUCH_FEEDBACK_DATA_TYPE_GET_FEATURES,
++
++	// This is a HID output report to be written to the sensor
++	TOUCH_FEEDBACK_DATA_TYPE_OUTPUT_REPORT,
++
++	// This is calibration data to be written to system flash
++	TOUCH_FEEDBACK_DATA_TYPE_STORE_DATA,
++
++	TOUCH_FEEDBACK_DATA_TYPE_MAX
++};
++static_assert(sizeof(enum touch_feedback_data_types) == 4);
++
++/*
++ * This is the data structure sent from the EU kernels back to the ME FW.
++ * In addition to "feedback" data, the FW can execute a "command" described by
++ * the command type parameter. Any payload data will always be sent to the TIC
++ * first, then any command will be issued.
++ */
++struct touch_feedback_hdr {
++	// use values from TOUCH_FEEDBACK_CMD_TYPES
++	u32 feedback_cmd_type;
++
++	// The amount of data to be written to the sensor,
++	// not including the header
++	u32 payload_size_bytes;
++
++	// The ID of the raw data buffer that generated this feedback data
++	u32 buffer_id;
++
++	// Must match protocol version of the EDS
++	u32 protocol_ver;
++
++	// use values from TOUCH_FEEDBACK_DATA_TYPES. This is not relevant
++	// if PayloadSizeBytes is 0
++	u32 feedback_data_type;
++
++	// The offset from TOUCH_DATA_WINDOW_OFFSET at which to write the
++	// Payload data. Maximum offset is 0x1EFFF.
++	u32 spi_offest;
++
++	// Padding to extend header to full 64 bytes and allow for growth
++	u8 reserved[40];
++};
++static_assert(sizeof(struct touch_feedback_hdr) == 64);
++
++struct touch_feedback_buffer {
++	struct touch_feedback_hdr Header;
++
++	// used to access the feedback data as an array and keep the compilers
++	// happy. Actual size of this array is Header.PayloadSizeBytes
++	u8 feedback_data[1];
++};
++
++/*
++ * This data structure describes the header prepended to all data
++ * written to the touch IC at the bulk data write
++ * (TOUCH_DATA_WINDOW_OFFSET + TOUCH_FEEDBACK_HDR.SpiOffest) address.
++ */
++enum touch_write_data_type {
++	TOUCH_WRITE_DATA_TYPE_FW_LOAD = 0,
++	TOUCH_WRITE_DATA_TYPE_DATA_LOAD,
++	TOUCH_WRITE_DATA_TYPE_FEEDBACK,
++	TOUCH_WRITE_DATA_TYPE_SET_FEATURES,
++	TOUCH_WRITE_DATA_TYPE_GET_FEATURES,
++	TOUCH_WRITE_DATA_TYPE_OUTPUT_REPORT,
++	TOUCH_WRITE_DATA_TYPE_NO_DATA_USE_DEFAULTS,
++	TOUCH_WRITE_DATA_TYPE_MAX
++};
++static_assert(sizeof(enum touch_write_data_type) == 4);
++
++struct touch_write_hdr {
++	// Use values from TOUCH_WRITE_DATA_TYPE
++	u32 write_data_type;
++
++	// This field designates the amount of data to follow
++	u32 write_data_len;
++};
++static_assert(sizeof(struct touch_write_hdr) == 8);
++
++struct touch_write_data {
++	struct touch_write_hdr header;
++
++	// used to access the write data as an array and keep the compilers
++	// happy. Actual size of this array is Header.WriteDataLen
++	u8 write_data[1];
++};
++
++#pragma pack()
++
++#endif // _IPTS_SENSOR_REGS_H_
+diff --git a/drivers/misc/ipts/state.h b/drivers/misc/ipts/state.h
+new file mode 100644
+index 000000000000..ef73d28db47c
+--- /dev/null
++++ b/drivers/misc/ipts/state.h
+@@ -0,0 +1,22 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef _IPTS_STATE_H_
++#define _IPTS_STATE_H_
++
++// IPTS driver states
++enum ipts_state {
++	IPTS_STA_NONE,
++	IPTS_STA_INIT,
++	IPTS_STA_RESOURCE_READY,
++	IPTS_STA_HID_STARTED,
++	IPTS_STA_RAW_DATA_STARTED,
++	IPTS_STA_STOPPING
++};
++
++#endif // _IPTS_STATE_H_
+diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
+index 9c4042420022..5d63ebba3e9f 100644
+--- a/drivers/misc/mei/hw-me-regs.h
++++ b/drivers/misc/mei/hw-me-regs.h
+@@ -119,6 +119,7 @@
+ 
+ #define MEI_DEV_ID_SPT        0x9D3A  /* Sunrise Point */
+ #define MEI_DEV_ID_SPT_2      0x9D3B  /* Sunrise Point 2 */
++#define MEI_DEV_ID_SPT_4      0x9D3E  /* Sunrise Point 4 */
+ #define MEI_DEV_ID_SPT_H      0xA13A  /* Sunrise Point H */
+ #define MEI_DEV_ID_SPT_H_2    0xA13B  /* Sunrise Point H 2 */
+ 
+diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
+index 41a10e392839..2b93a067cebc 100644
+--- a/drivers/misc/mei/pci-me.c
++++ b/drivers/misc/mei/pci-me.c
+@@ -86,6 +86,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
+ 
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)},
++	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
+ 	{MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)},
+diff --git a/include/linux/ipts-binary.h b/include/linux/ipts-binary.h
+new file mode 100644
+index 000000000000..98b54d74ff88
+--- /dev/null
++++ b/include/linux/ipts-binary.h
+@@ -0,0 +1,140 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef IPTS_BINARY_H
++#define IPTS_BINARY_H
++
++#include <linux/ipts.h>
++#include <linux/types.h>
++
++#define IPTS_BIN_HEADER_VERSION 2
++
++#pragma pack(1)
++
++// we support 16 output buffers (1:feedback, 15:HID)
++#define  MAX_NUM_OUTPUT_BUFFERS 16
++
++enum ipts_bin_res_type {
++	IPTS_BIN_KERNEL,
++	IPTS_BIN_RO_DATA,
++	IPTS_BIN_RW_DATA,
++	IPTS_BIN_SENSOR_FRAME,
++	IPTS_BIN_OUTPUT,
++	IPTS_BIN_DYNAMIC_STATE_HEAP,
++	IPTS_BIN_PATCH_LOCATION_LIST,
++	IPTS_BIN_ALLOCATION_LIST,
++	IPTS_BIN_COMMAND_BUFFER_PACKET,
++	IPTS_BIN_TAG,
++};
++
++struct ipts_bin_header {
++	char str[4];
++	u32 version;
++
++#if IPTS_BIN_HEADER_VERSION > 1
++	u32 gfxcore;
++	u32 revid;
++#endif
++};
++
++struct ipts_bin_alloc {
++	u32 handle;
++	u32 reserved;
++};
++
++struct ipts_bin_alloc_list {
++	u32 num;
++	struct ipts_bin_alloc alloc[];
++};
++
++struct ipts_bin_cmdbuf {
++	u32 size;
++	char data[];
++};
++
++struct ipts_bin_res {
++	u32 handle;
++	enum ipts_bin_res_type type;
++	u32 initialize;
++	u32 aligned_size;
++	u32 size;
++	char data[];
++};
++
++enum ipts_bin_io_buffer_type {
++	IPTS_INPUT,
++	IPTS_OUTPUT,
++	IPTS_CONFIGURATION,
++	IPTS_CALIBRATION,
++	IPTS_FEATURE,
++};
++
++struct ipts_bin_io_header {
++	char str[10];
++	u16 type;
++};
++
++struct ipts_bin_res_list {
++	u32 num;
++	struct ipts_bin_res res[];
++};
++
++struct ipts_bin_patch {
++	u32 index;
++	u32 reserved1[2];
++	u32 alloc_offset;
++	u32 patch_offset;
++	u32 reserved2;
++};
++
++struct ipts_bin_patch_list {
++	u32 num;
++	struct ipts_bin_patch patch[];
++};
++
++struct ipts_bin_guc_wq_info {
++	u32 batch_offset;
++	u32 size;
++	char data[];
++};
++
++struct ipts_bin_bufid_patch {
++	u32 imm_offset;
++	u32 mem_offset;
++};
++
++enum ipts_bin_data_file_flags {
++	IPTS_DATA_FILE_FLAG_NONE = 0,
++	IPTS_DATA_FILE_FLAG_SHARE = 1,
++	IPTS_DATA_FILE_FLAG_ALLOC_CONTIGUOUS = 2,
++};
++
++struct ipts_bin_data_file_info {
++	u32 io_buffer_type;
++	u32 flags;
++	char file_name[MAX_IOCL_FILE_NAME_LEN];
++};
++
++struct ipts_bin_fw_info {
++	char fw_name[MAX_IOCL_FILE_NAME_LEN];
++
++	// output index. -1 for no use
++	s32 vendor_output;
++
++	u32 num_of_data_files;
++	struct ipts_bin_data_file_info data_file[];
++};
++
++struct ipts_bin_fw_list {
++	u32 num_of_fws;
++	struct ipts_bin_fw_info fw_info[];
++};
++
++#pragma pack()
++
++#endif // IPTS_BINARY_H
+diff --git a/include/linux/ipts-companion.h b/include/linux/ipts-companion.h
+new file mode 100644
+index 000000000000..1f606a5fb5f2
+--- /dev/null
++++ b/include/linux/ipts-companion.h
+@@ -0,0 +1,30 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ * Copyright (c) 2019 Dorian Stoll
++ *
++ */
++
++#ifndef IPTS_COMPANION_H
++#define IPTS_COMPANION_H
++
++#include <linux/firmware.h>
++#include <linux/ipts-binary.h>
++
++struct ipts_companion {
++	unsigned int (*get_quirks)(struct ipts_companion *companion);
++	int (*firmware_request)(struct ipts_companion *companion,
++		const struct firmware **fw,
++		const char *name, struct device *device);
++
++	struct ipts_bin_fw_info **firmware_config;
++	void *data;
++	const char *name;
++};
++
++int ipts_add_companion(struct ipts_companion *companion);
++int ipts_remove_companion(struct ipts_companion *companion);
++
++#endif // IPTS_COMPANION_H
+diff --git a/include/linux/ipts-gfx.h b/include/linux/ipts-gfx.h
+new file mode 100644
+index 000000000000..cb9d98fe96e4
+--- /dev/null
++++ b/include/linux/ipts-gfx.h
+@@ -0,0 +1,86 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef IPTS_GFX_H
++#define IPTS_GFX_H
++
++enum {
++	IPTS_INTERFACE_V1 = 1,
++};
++
++#define IPTS_BUF_FLAG_CONTIGUOUS 0x01
++
++#define IPTS_NOTIFY_STA_BACKLIGHT_OFF 0x00
++#define IPTS_NOTIFY_STA_BACKLIGHT_ON  0x01
++
++struct ipts_mapbuffer {
++	u32 size;
++	u32 flags;
++	void *gfx_addr;
++	void *cpu_addr;
++	u64 buf_handle;
++	u64 phy_addr;
++};
++
++struct ipts_wq_info {
++	u64 db_addr;
++	u64 db_phy_addr;
++	u32 db_cookie_offset;
++	u32 wq_size;
++	u64 wq_addr;
++	u64 wq_phy_addr;
++
++	// head of wq is managed by GPU
++	u64 wq_head_addr;
++	u64 wq_head_phy_addr;
++
++	// tail of wq is managed by CSME
++	u64 wq_tail_addr;
++	u64 wq_tail_phy_addr;
++};
++
++struct ipts_ops {
++	int (*get_wq_info)(uint64_t gfx_handle,
++		struct ipts_wq_info *wq_info);
++	int (*map_buffer)(uint64_t gfx_handle,
++		struct ipts_mapbuffer *mapbuffer);
++	int (*unmap_buffer)(uint64_t gfx_handle, uint64_t buf_handle);
++};
++
++struct ipts_callback {
++	void (*workload_complete)(void *data);
++	void (*notify_gfx_status)(u32 status, void *data);
++};
++
++struct ipts_connect {
++	// input: Client device for PM setup
++	struct device *client;
++
++	// input: Callback addresses
++	struct ipts_callback ipts_cb;
++
++	// input: Callback data
++	void *data;
++
++	// input: interface version
++	u32 if_version;
++
++	// output: GFX version
++	u32 gfx_version;
++
++	// output: GFX handle
++	u64 gfx_handle;
++
++	// output: GFX ops for IPTS
++	struct ipts_ops ipts_ops;
++};
++
++int ipts_connect(struct ipts_connect *ipts_connect);
++void ipts_disconnect(uint64_t gfx_handle);
++
++#endif // IPTS_GFX_H
+diff --git a/include/linux/ipts.h b/include/linux/ipts.h
+new file mode 100644
+index 000000000000..bfa8e1375926
+--- /dev/null
++++ b/include/linux/ipts.h
+@@ -0,0 +1,20 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/*
++ *
++ * Intel Precise Touch & Stylus
++ * Copyright (c) 2016 Intel Corporation
++ *
++ */
++
++#ifndef IPTS_H
++#define IPTS_H
++
++#include <linux/bits.h>
++
++#define MAX_IOCL_FILE_NAME_LEN 80
++#define MAX_IOCL_FILE_PATH_LEN 256
++
++#define IPTS_QUIRK_NONE        0
++#define IPTS_QUIRK_NO_FEEDBACK BIT(0)
++
++#endif // IPTS_H
+-- 
+2.25.0
+

+ 0 - 26
patches/4.19/0007-sdcard-reader.patch

@@ -1,26 +0,0 @@
-From 97eabdac0e56338eb68d67eb46d9e589e0621f1f Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sat, 28 Sep 2019 17:59:13 +0200
-Subject: [PATCH 07/13] sdcard-reader
-
----
- drivers/usb/core/hub.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
-index b33ec768404b..360477fe8d0c 100644
---- a/drivers/usb/core/hub.c
-+++ b/drivers/usb/core/hub.c
-@@ -4171,7 +4171,8 @@ void usb_enable_lpm(struct usb_device *udev)
- 	if (!udev || !udev->parent ||
- 			udev->speed < USB_SPEED_SUPER ||
- 			!udev->lpm_capable ||
--			udev->state < USB_STATE_DEFAULT)
-+			udev->state < USB_STATE_DEFAULT ||
-+			!udev->bos || !udev->bos->ss_cap)
- 		return;
- 
- 	udev->lpm_disable_count--;
--- 
-2.24.1
-

+ 3 - 3
patches/4.19/0011-surface-lte.patch → patches/4.19/0008-surface-lte.patch

@@ -1,7 +1,7 @@
-From e3295d7e95d4ccc587677e9e96664187b10ecec5 Mon Sep 17 00:00:00 2001
+From 21bd7d9f54af1f143b4018d53315ff0798cb6b62 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 28 Sep 2019 18:02:03 +0200
-Subject: [PATCH 11/13] surface-lte
+Subject: [PATCH 08/10] surface-lte
 
 ---
  drivers/usb/serial/qcserial.c | 1 +
@@ -20,5 +20,5 @@ index 613f91add03d..e1428222dd73 100644
  	/* Huawei devices */
  	{DEVICE_HWI(0x03f0, 0x581d)},	/* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
 -- 
-2.24.1
+2.25.0
 

+ 0 - 270
patches/4.19/0008-wifi.patch

@@ -1,270 +0,0 @@
-From eb5625524a9f025ade096508db976f6318387fc4 Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sat, 28 Sep 2019 18:00:19 +0200
-Subject: [PATCH 08/13] wifi
-
----
- drivers/net/wireless/marvell/mwifiex/11n_aggr.c |  3 +--
- drivers/net/wireless/marvell/mwifiex/cfg80211.c |  5 ++++-
- drivers/net/wireless/marvell/mwifiex/cmdevt.c   | 10 ++++++----
- drivers/net/wireless/marvell/mwifiex/fw.h       |  1 +
- drivers/net/wireless/marvell/mwifiex/main.c     | 17 +++++++++++++----
- drivers/net/wireless/marvell/mwifiex/main.h     |  2 ++
- drivers/net/wireless/marvell/mwifiex/pcie.c     |  9 +++++++++
- drivers/net/wireless/marvell/mwifiex/sta_cmd.c  |  4 ++--
- .../net/wireless/marvell/mwifiex/sta_cmdresp.c  | 11 ++++++++---
- drivers/net/wireless/marvell/mwifiex/usb.c      |  2 ++
- scripts/leaking_addresses.pl                    |  0
- 11 files changed, 48 insertions(+), 16 deletions(-)
- mode change 100755 => 100644 scripts/leaking_addresses.pl
-
-diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
-index 042a1d07f686..fc9041f58e9f 100644
---- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
-+++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c
-@@ -200,8 +200,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
- 
- 	do {
- 		/* Check if AMSDU can accommodate this MSDU */
--		if ((skb_aggr->len + skb_src->len + LLC_SNAP_LEN) >
--		    adapter->tx_buf_size)
-+		if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN))
- 			break;
- 
- 		skb_src = skb_dequeue(&pra_list->skb_head);
-diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
-index 7b74ef71bef1..f0d1b0d48e07 100644
---- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
-+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
-@@ -437,7 +437,10 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
- 		mwifiex_dbg(priv->adapter, INFO,
- 			    "info: ignore timeout value for IEEE Power Save\n");
- 
--	ps_mode = enabled;
-+	//ps_mode = enabled;
-+
-+	mwifiex_dbg(priv->adapter, INFO, "overriding ps_mode to false\n");
-+	ps_mode = 0;
- 
- 	return mwifiex_drv_set_power(priv, &ps_mode);
- }
-diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
-index 60db2b969e20..efae99018c3c 100644
---- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
-+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
-@@ -1000,6 +1000,7 @@ mwifiex_cmd_timeout_func(struct timer_list *t)
- 		if (cmd_node->wait_q_enabled) {
- 			adapter->cmd_wait_q.status = -ETIMEDOUT;
- 			mwifiex_cancel_pending_ioctl(adapter);
-+			adapter->cmd_sent = false;
- 		}
- 	}
- 	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
-@@ -1007,11 +1008,11 @@ mwifiex_cmd_timeout_func(struct timer_list *t)
- 		return;
- 	}
- 
--	if (adapter->if_ops.device_dump)
--		adapter->if_ops.device_dump(adapter);
-+	//if (adapter->if_ops.device_dump)
-+	//	adapter->if_ops.device_dump(adapter);
- 
--	if (adapter->if_ops.card_reset)
--		adapter->if_ops.card_reset(adapter);
-+	//if (adapter->if_ops.card_reset)
-+	//	adapter->if_ops.card_reset(adapter);
- }
- 
- void
-@@ -1577,6 +1578,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
- 						    adapter->key_api_minor_ver);
- 					break;
- 				case FW_API_VER_ID:
-+				case FW_KEY_API_VER_ID:
- 					adapter->fw_api_ver =
- 							api_rev->major_ver;
- 					mwifiex_dbg(adapter, INFO,
-diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
-index 1fb76d2f5d3f..fb32379da99d 100644
---- a/drivers/net/wireless/marvell/mwifiex/fw.h
-+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
-@@ -1052,6 +1052,7 @@ struct host_cmd_ds_802_11_ps_mode_enh {
- enum API_VER_ID {
- 	KEY_API_VER_ID = 1,
- 	FW_API_VER_ID = 2,
-+	FW_KEY_API_VER_ID = 4,
- };
- 
- struct hw_spec_api_rev {
-diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
-index e48b47f42554..15bbcbf1420f 100644
---- a/drivers/net/wireless/marvell/mwifiex/main.c
-+++ b/drivers/net/wireless/marvell/mwifiex/main.c
-@@ -163,6 +163,7 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter)
- 	spin_lock_irqsave(&adapter->main_proc_lock, flags);
- 	if (adapter->mwifiex_processing) {
- 		adapter->more_task_flag = true;
-+		adapter->more_rx_task_flag = true;
- 		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
- 	} else {
- 		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
-@@ -171,18 +172,20 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter)
- }
- EXPORT_SYMBOL_GPL(mwifiex_queue_main_work);
- 
--static void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter)
-+void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter)
- {
- 	unsigned long flags;
- 
- 	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
- 	if (adapter->rx_processing) {
-+		adapter->more_rx_task_flag = true;
- 		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
- 	} else {
- 		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
- 		queue_work(adapter->rx_workqueue, &adapter->rx_work);
- 	}
- }
-+EXPORT_SYMBOL_GPL(mwifiex_queue_rx_work);
- 
- static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
- {
-@@ -192,6 +195,7 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
- 
- 	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
- 	if (adapter->rx_processing || adapter->rx_locked) {
-+		adapter->more_rx_task_flag = true;
- 		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
- 		goto exit_rx_proc;
- 	} else {
-@@ -199,6 +203,7 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
- 		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
- 	}
- 
-+rx_process_start:
- 	/* Check for Rx data */
- 	while ((skb = skb_dequeue(&adapter->rx_data_q))) {
- 		atomic_dec(&adapter->rx_pending);
-@@ -220,6 +225,11 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
- 		}
- 	}
- 	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
-+	if (adapter->more_rx_task_flag) {
-+		adapter->more_rx_task_flag = false;
-+		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
-+		goto rx_process_start;
-+	}
- 	adapter->rx_processing = false;
- 	spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
- 
-@@ -283,11 +293,10 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
- 				mwifiex_process_hs_config(adapter);
- 			if (adapter->if_ops.process_int_status)
- 				adapter->if_ops.process_int_status(adapter);
-+			if (adapter->rx_work_enabled && adapter->data_received)
-+				mwifiex_queue_rx_work(adapter);
- 		}
- 
--		if (adapter->rx_work_enabled && adapter->data_received)
--			mwifiex_queue_rx_work(adapter);
--
- 		/* Need to wake up the card ? */
- 		if ((adapter->ps_state == PS_STATE_SLEEP) &&
- 		    (adapter->pm_wakeup_card_req &&
-diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
-index e39bb5c42c9a..8ec3275dad6d 100644
---- a/drivers/net/wireless/marvell/mwifiex/main.h
-+++ b/drivers/net/wireless/marvell/mwifiex/main.h
-@@ -909,6 +909,7 @@ struct mwifiex_adapter {
- 	spinlock_t main_proc_lock;
- 	u32 mwifiex_processing;
- 	u8 more_task_flag;
-+	u8 more_rx_task_flag;
- 	u16 tx_buf_size;
- 	u16 curr_tx_buf_size;
- 	/* sdio single port rx aggregation capability */
-@@ -1695,6 +1696,7 @@ void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
- void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
- void mwifiex_fw_dump_event(struct mwifiex_private *priv);
- void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
-+void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter);
- int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
- 			      int cmd_type,
- 			      struct mwifiex_ds_wakeup_reason *wakeup_reason);
-diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
-index 3fe81b2a929a..6e734a83e6bf 100644
---- a/drivers/net/wireless/marvell/mwifiex/pcie.c
-+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
-@@ -1743,6 +1743,15 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
- 	}
- 
- 	rx_len = get_unaligned_le16(skb->data);
-+
-+	if (rx_len == 0) {
-+		mwifiex_dbg(adapter, ERROR,
-+				    "0 byte cmdrsp\n");
-+		mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
-+					   PCI_DMA_FROMDEVICE);
-+		return 0;
-+	}
-+
- 	skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
- 	skb_trim(skb, rx_len);
- 
-diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
-index 4ed10cf82f9a..485360e8534b 100644
---- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
-+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
-@@ -30,8 +30,8 @@ static bool drcs;
- module_param(drcs, bool, 0644);
- MODULE_PARM_DESC(drcs, "multi-channel operation:1, single-channel operation:0");
- 
--static bool disable_auto_ds;
--module_param(disable_auto_ds, bool, 0);
-+static bool disable_auto_ds = 1;
-+module_param(disable_auto_ds, bool, 0644);
- MODULE_PARM_DESC(disable_auto_ds,
- 		 "deepsleep enabled=0(default), deepsleep disabled=1");
- /*
-diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
-index 69e3b624adbb..884bad677cc3 100644
---- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
-+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
-@@ -48,9 +48,14 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
- 	struct host_cmd_ds_802_11_ps_mode_enh *pm;
- 	unsigned long flags;
- 
--	mwifiex_dbg(adapter, ERROR,
--		    "CMD_RESP: cmd %#x error, result=%#x\n",
--		    resp->command, resp->result);
-+	if (resp->command == 271 && resp->result == 2){
-+		// ignore this command as the firmware does not support it
-+	}
-+	else {
-+		mwifiex_dbg(adapter, ERROR,
-+				"CMD_RESP: cmd %#x error, result=%#x\n",
-+				resp->command, resp->result);
-+	}
- 
- 	if (adapter->curr_cmd->wait_q_enabled)
- 		adapter->cmd_wait_q.status = -1;
-diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
-index d445acc4786b..ae8e60cc17cb 100644
---- a/drivers/net/wireless/marvell/mwifiex/usb.c
-+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
-@@ -144,6 +144,8 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
- 		skb_queue_tail(&adapter->rx_data_q, skb);
- 		adapter->data_received = true;
- 		atomic_inc(&adapter->rx_pending);
-+		if (adapter->rx_work_enabled)
-+			mwifiex_queue_rx_work(adapter);
- 		break;
- 	default:
- 		mwifiex_dbg(adapter, ERROR,
-diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl
-old mode 100755
-new mode 100644
--- 
-2.24.1
-

+ 5 - 5
patches/4.19/0012-ioremap_uc.patch → patches/4.19/0009-ioremap_uc.patch

@@ -1,7 +1,7 @@
-From d63ae78ee99fb9c0684a1fb23fed472f0b9ea2b3 Mon Sep 17 00:00:00 2001
+From 30b3275ff57c77da523db26582675c74e0cceee1 Mon Sep 17 00:00:00 2001
 From: Tuowen Zhao <ztuowen@gmail.com>
 Date: Wed, 16 Oct 2019 15:06:28 -0600
-Subject: [PATCH 12/13] ioremap_uc
+Subject: [PATCH 09/10] ioremap_uc
 
 ---
  Documentation/driver-model/devres.txt |  1 +
@@ -23,7 +23,7 @@ index 43681ca0837f..7b1ee4190208 100644
    devm_ioremap_resource() : checks resource, requests memory region, ioremaps
    devm_iounmap()
 diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
-index ff3fba16e735..37a5bb09d228 100644
+index 95e217e6b6d7..7577afd42842 100644
 --- a/drivers/mfd/intel-lpss.c
 +++ b/drivers/mfd/intel-lpss.c
 @@ -397,7 +397,7 @@ int intel_lpss_probe(struct device *dev,
@@ -49,7 +49,7 @@ index 32e30e8fb9db..da39ff89df65 100644
  				   resource_size_t size);
  void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
 diff --git a/lib/devres.c b/lib/devres.c
-index faccf1a037d0..97c56f9893a4 100644
+index aa0f5308ac6b..75ea32d9b661 100644
 --- a/lib/devres.c
 +++ b/lib/devres.c
 @@ -9,6 +9,7 @@
@@ -93,5 +93,5 @@ index faccf1a037d0..97c56f9893a4 100644
   * devm_ioremap_nocache - Managed ioremap_nocache()
   * @dev: Generic device to remap IO address for
 -- 
-2.24.1
+2.25.0
 

+ 0 - 19755
patches/4.19/0010-mwlwifi.patch

@@ -1,19755 +0,0 @@
-From e256371ddeb11d23ca22a10fc14c00dd7ab8288c Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sat, 28 Sep 2019 18:01:27 +0200
-Subject: [PATCH 10/13] mwlwifi
-
----
- drivers/net/wireless/marvell/Kconfig          |    1 +
- drivers/net/wireless/marvell/Makefile         |    1 +
- drivers/net/wireless/marvell/mwlwifi/Kconfig  |   23 +
- drivers/net/wireless/marvell/mwlwifi/Makefile |   19 +
- .../wireless/marvell/mwlwifi/Makefile.module  |   28 +
- .../net/wireless/marvell/mwlwifi/README.md    |  142 +
- drivers/net/wireless/marvell/mwlwifi/core.c   | 1086 +++++
- drivers/net/wireless/marvell/mwlwifi/core.h   |  517 +++
- .../net/wireless/marvell/mwlwifi/debugfs.c    | 2201 ++++++++++
- .../net/wireless/marvell/mwlwifi/debugfs.h    |   24 +
- .../net/wireless/marvell/mwlwifi/hif/fwcmd.c  | 3852 +++++++++++++++++
- .../net/wireless/marvell/mwlwifi/hif/fwcmd.h  |  285 ++
- .../wireless/marvell/mwlwifi/hif/hif-ops.h    |  297 ++
- .../net/wireless/marvell/mwlwifi/hif/hif.h    |   81 +
- .../wireless/marvell/mwlwifi/hif/hostcmd.h    | 1285 ++++++
- .../wireless/marvell/mwlwifi/hif/pcie/dev.h   | 1032 +++++
- .../wireless/marvell/mwlwifi/hif/pcie/fwdl.c  |  274 ++
- .../wireless/marvell/mwlwifi/hif/pcie/fwdl.h  |   24 +
- .../wireless/marvell/mwlwifi/hif/pcie/pcie.c  | 1645 +++++++
- .../wireless/marvell/mwlwifi/hif/pcie/rx.c    |  540 +++
- .../wireless/marvell/mwlwifi/hif/pcie/rx.h    |   25 +
- .../marvell/mwlwifi/hif/pcie/rx_ndp.c         |  612 +++
- .../marvell/mwlwifi/hif/pcie/rx_ndp.h         |   26 +
- .../marvell/mwlwifi/hif/pcie/sc4_ddr.h        |  965 +++++
- .../wireless/marvell/mwlwifi/hif/pcie/tx.c    | 1396 ++++++
- .../wireless/marvell/mwlwifi/hif/pcie/tx.h    |   38 +
- .../marvell/mwlwifi/hif/pcie/tx_ndp.c         |  693 +++
- .../marvell/mwlwifi/hif/pcie/tx_ndp.h         |   30 +
- ...-workaround-for-80+80-and-160-MHz-channels |   32 +
- .../wireless/marvell/mwlwifi/hostapd/README   |   26 +
- .../net/wireless/marvell/mwlwifi/mac80211.c   |  933 ++++
- .../net/wireless/marvell/mwlwifi/mu_mimo.c    |   21 +
- .../net/wireless/marvell/mwlwifi/mu_mimo.h    |   23 +
- .../net/wireless/marvell/mwlwifi/sysadpt.h    |   86 +
- .../net/wireless/marvell/mwlwifi/thermal.c    |  182 +
- .../net/wireless/marvell/mwlwifi/thermal.h    |   42 +
- drivers/net/wireless/marvell/mwlwifi/utils.c  |  576 +++
- drivers/net/wireless/marvell/mwlwifi/utils.h  |  158 +
- .../net/wireless/marvell/mwlwifi/vendor_cmd.c |  136 +
- .../net/wireless/marvell/mwlwifi/vendor_cmd.h |   60 +
- 40 files changed, 19417 insertions(+)
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/Kconfig
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/Makefile
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/Makefile.module
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/README.md
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/core.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/core.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/debugfs.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/debugfs.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/hif-ops.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/hif.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/hostcmd.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/dev.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/pcie.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/sc4_ddr.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hostapd/700-interoperability-workaround-for-80+80-and-160-MHz-channels
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/hostapd/README
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/mac80211.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/mu_mimo.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/mu_mimo.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/sysadpt.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/thermal.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/thermal.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/utils.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/utils.h
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/vendor_cmd.c
- create mode 100644 drivers/net/wireless/marvell/mwlwifi/vendor_cmd.h
-
-diff --git a/drivers/net/wireless/marvell/Kconfig b/drivers/net/wireless/marvell/Kconfig
-index 27038901d3ee..3982c80f6df9 100644
---- a/drivers/net/wireless/marvell/Kconfig
-+++ b/drivers/net/wireless/marvell/Kconfig
-@@ -14,6 +14,7 @@ if WLAN_VENDOR_MARVELL
- source "drivers/net/wireless/marvell/libertas/Kconfig"
- source "drivers/net/wireless/marvell/libertas_tf/Kconfig"
- source "drivers/net/wireless/marvell/mwifiex/Kconfig"
-+source "drivers/net/wireless/marvell/mwlwifi/Kconfig"
- 
- config MWL8K
- 	tristate "Marvell 88W8xxx PCI/PCIe Wireless support"
-diff --git a/drivers/net/wireless/marvell/Makefile b/drivers/net/wireless/marvell/Makefile
-index 1b0a7d2bc8e6..04dff3388a41 100644
---- a/drivers/net/wireless/marvell/Makefile
-+++ b/drivers/net/wireless/marvell/Makefile
-@@ -2,5 +2,6 @@ obj-$(CONFIG_LIBERTAS)		+= libertas/
- 
- obj-$(CONFIG_LIBERTAS_THINFIRM)	+= libertas_tf/
- obj-$(CONFIG_MWIFIEX)	+= mwifiex/
-+obj-$(CONFIG_MWLWIFI)	+= mwlwifi/
- 
- obj-$(CONFIG_MWL8K)	+= mwl8k.o
-diff --git a/drivers/net/wireless/marvell/mwlwifi/Kconfig b/drivers/net/wireless/marvell/mwlwifi/Kconfig
-new file mode 100644
-index 000000000000..a9bcb9cd4100
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/Kconfig
-@@ -0,0 +1,23 @@
-+config MWLWIFI
-+	tristate "Marvell Avastar 88W8864/88W8897 PCIe driver (mac80211 compatible)"
-+	depends on PCI && MAC80211
-+	select FW_LOADER
-+	---help---
-+		Select to build the driver supporting the:
-+
-+		Marvell Wireless Wi-Fi 88W8864 modules
-+		Marvell Wireless Wi-Fi 88W8897 modules
-+
-+		This driver uses the kernel's mac80211 subsystem.
-+
-+		If you want to compile the driver as a module (= code which can be
-+		inserted in and removed from the running kernel whenever you want),
-+		say M here and read <file:Documentation/kbuild/modules.txt>.  The
-+		module will be called mwlwifi.
-+
-+		NOTE: Selecting this driver may cause conflict with MWIFIEX driver
-+		that also operates on the same part number 88W8897. Users should
-+		select either MWIFIEX or MWLWIFI, not both. MWIFIEX is fullmac,
-+		supporting more comprehensive client functions for laptops/embedded
-+		devices. MWLWIFI is mac80211-based for full AP/Wireless Bridge.
-+
-diff --git a/drivers/net/wireless/marvell/mwlwifi/Makefile b/drivers/net/wireless/marvell/mwlwifi/Makefile
-new file mode 100644
-index 000000000000..061833703c7f
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/Makefile
-@@ -0,0 +1,19 @@
-+obj-$(CONFIG_MWLWIFI)	+= mwlwifi.o
-+
-+mwlwifi-objs			+= core.o
-+mwlwifi-objs			+= mac80211.o
-+mwlwifi-objs			+= mu_mimo.o
-+mwlwifi-objs			+= vendor_cmd.o
-+mwlwifi-objs			+= utils.o
-+mwlwifi-$(CONFIG_THERMAL)	+= thermal.o
-+mwlwifi-$(CONFIG_DEBUG_FS)	+= debugfs.o
-+mwlwifi-objs			+= hif/fwcmd.o
-+mwlwifi-objs			+= hif/pcie/pcie.o
-+mwlwifi-objs			+= hif/pcie/fwdl.o
-+mwlwifi-objs			+= hif/pcie/tx.o
-+mwlwifi-objs			+= hif/pcie/rx.o
-+mwlwifi-objs			+= hif/pcie/tx_ndp.o
-+mwlwifi-objs			+= hif/pcie/rx_ndp.o
-+
-+ccflags-y += -I$(src)
-+ccflags-y += -D__CHECK_ENDIAN__
-diff --git a/drivers/net/wireless/marvell/mwlwifi/Makefile.module b/drivers/net/wireless/marvell/mwlwifi/Makefile.module
-new file mode 100644
-index 000000000000..d11a1b88cab6
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/Makefile.module
-@@ -0,0 +1,28 @@
-+obj-m += mwlwifi.o
-+
-+mwlwifi-objs			+= core.o
-+mwlwifi-objs			+= mac80211.o
-+mwlwifi-objs			+= mu_mimo.o
-+mwlwifi-objs			+= vendor_cmd.o
-+mwlwifi-objs			+= utils.o
-+mwlwifi-$(CONFIG_THERMAL)	+= thermal.o
-+mwlwifi-$(CONFIG_DEBUG_FS)	+= debugfs.o
-+mwlwifi-objs			+= hif/fwcmd.o
-+mwlwifi-objs			+= hif/pcie/pcie.o
-+mwlwifi-objs			+= hif/pcie/fwdl.o
-+mwlwifi-objs			+= hif/pcie/tx.o
-+mwlwifi-objs			+= hif/pcie/rx.o
-+mwlwifi-objs			+= hif/pcie/tx_ndp.o
-+mwlwifi-objs			+= hif/pcie/rx_ndp.o
-+
-+ccflags-y += -I$(src)
-+ccflags-y += -O2 -funroll-loops -D__CHECK_ENDIAN__
-+
-+all:
-+	$(MAKE) -C $(KDIR) M=$(PWD)
-+
-+clean:
-+	rm -f *.a *.s *.ko *.ko.cmd *.mod.* .mwlwifi.* modules.order Module.symvers
-+	rm -rf .tmp_versions
-+	find . -name ".*.o.cmd" -exec rm -f {} \;
-+	find . -name "*.o" -exec rm -f {} \;
-diff --git a/drivers/net/wireless/marvell/mwlwifi/README.md b/drivers/net/wireless/marvell/mwlwifi/README.md
-new file mode 100644
-index 000000000000..788c5d4dc80d
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/README.md
-@@ -0,0 +1,142 @@
-+# mwlwifi
-+mac80211 driver for the Marvell 88W8x64 802.11ac chip
-+
-+## Building mwlwifi With OpenWrt/LEDE
-+1. Modify `package/kernel/mwlwifi/Makefile`:
-+    ```
-+    PKG_VERSION:=10.3.0.17-20160601
-+    PKG_SOURCE_VERSION:=4bb95ba1aeccce506a95499b49b9b844ecfae8a1
-+    ```
-+
-+2. Rename `package/kernel/mwlwifi/patches` to `package/kernel/mwlwifi/patches.tmp`.
-+3. Run the following commands:
-+    ```sh
-+    make package/kernel/mwlwifi/clean
-+    make V=s (-jx)
-+    ```
-+
-+### Special Considerations
-+* After driver 10.3.0.17-20160603, [MAX-MPDU-7991] should be removed from vht_capab command of hostapd.
-+
-+* Hostpad must include the following commit for 160 MHz operation:
-+    ```
-+    commit 03a72eacda5d9a1837a74387081596a0d5466ec1
-+    Author: Jouni Malinen <jouni@qca.qualcomm.com>
-+    Date:   Thu Dec 17 18:39:19 2015 +0200
-+    
-+    VHT: Add an interoperability workaround for 80+80 and 160 MHz channels
-+
-+    Number of deployed 80 MHz capable VHT stations that do not support 80+80
-+    and 160 MHz bandwidths seem to misbehave when trying to connect to an AP
-+    that advertises 80+80 or 160 MHz channel bandwidth in the VHT Operation
-+    element. To avoid such issues with deployed devices, modify the design
-+    based on newly proposed IEEE 802.11 standard changes.
-+
-+    This allows poorly implemented VHT 80 MHz stations to connect with the
-+    AP in 80 MHz mode. 80+80 and 160 MHz capable stations need to support
-+    the new workaround mechanism to allow full bandwidth to be used.
-+    However, there are more or less no impacted station with 80+80/160
-+    capability deployed.
-+
-+    Signed-off-by: Jouni Malinen jouni@qca.qualcomm.com
-+
-+    Note: After hostapd package 2016-06-15, this commit is already included.
-+    ```
-+
-+* In order to let STA mode to support 160 MHz operation, mac80211 package should be 2016-10-08 or later.
-+
-+* WiFi device does not use HT rates when using TKIP as the encryption cipher. If you want to have good performance, please use AES only.
-+
-+* DTS parameters for mwlwifi driver (pcie@X,0):
-+    ```sh
-+    #Disable 2g band
-+    marvell,2ghz = <0>;
-+
-+    #Disable 5g band
-+    marvell,5ghz = <0>;
-+    
-+    #Specify antenna number, default is 4x4. For WRT1200AC, you must set these values to 2x2.
-+    marvell,chainmask = <4 4>;
-+    
-+    #Specify external power table. If your device needs external power table, you must provide the power table via this parameter, otherwise the Tx power will be pretty low.
-+    marvell,powertable
-+    ```
-+
-+    To see if your device needs/accepts an external power table or not, run the following:
-+    ```sh
-+    cat /sys/kernel/debug/ieee80211/phy0/mwlwifi/info
-+    ```
-+    
-+    You should see a line in the results which looks like the following:
-+    ```sh
-+    power table loaded from dts: no
-+    ```
-+
-+    If it is "no", it does not allow you to load external power table (for newer devices due to FCC regulations). If it is "yes", you must provide power table in DTS file (for older devices).
-+
-+* Changing interrupt to different CPU cores:
-+    ```sh
-+    #Use CPU0:
-+    echo 1 > /proc/irq/irq number of phy0 or phy1/smp_affinity
-+
-+    #Use CPU1:
-+    echo 2 > /proc/irq/irq number of phy0 or phy1/smp_affinity
-+    ```
-+
-+* Note for DFS of WRT3200ACM (88W8964):
-+
-+    All WRT3200ACM devices are programmed with device power table. Mwlwifi driver will base on region code to set country code for your device and it will not allow you to change country code. There are another wifi (phy2) on WRT3200ACM which is not mwlwifi. It will allow you to change country code. Under this case, country code setting will be conflicted and it will let DFS can't work.
-+
-+    There are two ways to resolve this problem:
-+    * Please don't change country code and let mwlwifi set it for you.
-+    * Remove phy2. Under this case, even though you change country code, mwlwifi will reject it. Because phy2 is not existed, country code setting won't be conflicted. To do this, run the following commands (for OpenWrt/LEDE):
-+    
-+        ```sh
-+        opkg remove kmod-mwifiex-sdio
-+        opkg remove mwifiex-sdio-firmware
-+        reboot
-+        ```
-+
-+    The better way is let mwlwifi set country code for you.
-+
-+## Replacing mwlwifi on a Current OpenWrt/LEDE Build
-+
-+1. Establish a symbolic link to your working mwlwifi directory with current mwlwifi package name under directory "dl":
-+    ```sh
-+    ls -l mwlwifi*
-+    ```
-+
-+    You should see something like the following:
-+    ```sh
-+    lrwxrwxrwx 1 dlin dlin      48  mwlwifi-10.3.2.0-20170110 -> /home/dlin/home2/projects/github/mwlwifi
-+
-+    -rw-r--r-- 1 dlin dlin 4175136  mwlwifi-10.3.2.0-20170110.tar.xz
-+    ```
-+
-+2. Back up original mwlwifi package and tar your working mwlwifi to replace original mwlwifi package:
-+
-+    ```sh
-+    tar Jcvf mwlwifi-10.3.2.0-20170110.tar.xz mwlwifi-10.3.2.0-20170110/.
-+    ```
-+
-+3. You can use `make V=s` to build the whole image or `make V=s package/kernel/mwlwifi/compile` to build mwlwifi package. The generated whole image or mwlwifi package can be found under directory "bin".
-+
-+Due to package version being the same as previous one, you need to add option `--force-reinstall` when you use `opkg` to update mwlwifi package on your device.
-+
-+## Monitor interface for debug
-+
-+1. Create moinitor interface mon0:
-+    ```sh
-+    iw wlan0/wlan1 interface add mon0 type monitor
-+    ifconfig mon0 up
-+    ```
-+
-+2. Use tcpdump to dump dhcp packets:
-+    ```sh
-+    tcpdump -vvvi mon0 -n port 67 and port 68
-+    ```
-+
-+3. Use tcpdump to dump icmp packets:
-+    ```sh
-+    tcpdump -vvvi mon0 icmp
-+    ```
-diff --git a/drivers/net/wireless/marvell/mwlwifi/core.c b/drivers/net/wireless/marvell/mwlwifi/core.c
-new file mode 100644
-index 000000000000..9d2b5511607e
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/core.c
-@@ -0,0 +1,1086 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements core layer related functions. */
-+
-+#include <linux/etherdevice.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "vendor_cmd.h"
-+#include "thermal.h"
-+#include "debugfs.h"
-+#include "hif/fwcmd.h"
-+#include "hif/hif-ops.h"
-+
-+#define CMD_BUF_SIZE     0x4000
-+#define INVALID_WATCHDOG 0xAA
-+
-+static const struct ieee80211_channel mwl_channels_24[] = {
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, },
-+	{ .band = NL80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, },
-+};
-+
-+static const struct ieee80211_rate mwl_rates_24[] = {
-+	{ .bitrate = 10, .hw_value = 2, },
-+	{ .bitrate = 20, .hw_value = 4, },
-+	{ .bitrate = 55, .hw_value = 11, },
-+	{ .bitrate = 110, .hw_value = 22, },
-+	{ .bitrate = 220, .hw_value = 44, },
-+	{ .bitrate = 60, .hw_value = 12, },
-+	{ .bitrate = 90, .hw_value = 18, },
-+	{ .bitrate = 120, .hw_value = 24, },
-+	{ .bitrate = 180, .hw_value = 36, },
-+	{ .bitrate = 240, .hw_value = 48, },
-+	{ .bitrate = 360, .hw_value = 72, },
-+	{ .bitrate = 480, .hw_value = 96, },
-+	{ .bitrate = 540, .hw_value = 108, },
-+};
-+
-+static const struct ieee80211_channel mwl_channels_50[] = {
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5260, .hw_value = 52, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5280, .hw_value = 56, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5300, .hw_value = 60, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5320, .hw_value = 64, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5500, .hw_value = 100, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5520, .hw_value = 104, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5540, .hw_value = 108, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5560, .hw_value = 112, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5580, .hw_value = 116, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5600, .hw_value = 120, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5620, .hw_value = 124, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5640, .hw_value = 128, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5660, .hw_value = 132, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5680, .hw_value = 136, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5700, .hw_value = 140, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5720, .hw_value = 144, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5745, .hw_value = 149, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5765, .hw_value = 153, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5785, .hw_value = 157, },
-+	{ .band = NL80211_BAND_5GHZ, .center_freq = 5805, .hw_value = 161, },
-+};
-+
-+static const struct ieee80211_rate mwl_rates_50[] = {
-+	{ .bitrate = 60, .hw_value = 12, },
-+	{ .bitrate = 90, .hw_value = 18, },
-+	{ .bitrate = 120, .hw_value = 24, },
-+	{ .bitrate = 180, .hw_value = 36, },
-+	{ .bitrate = 240, .hw_value = 48, },
-+	{ .bitrate = 360, .hw_value = 72, },
-+	{ .bitrate = 480, .hw_value = 96, },
-+	{ .bitrate = 540, .hw_value = 108, },
-+};
-+
-+static const struct ieee80211_iface_limit ap_if_limits[] = {
-+	{ .max = SYSADPT_NUM_OF_AP, .types = BIT(NL80211_IFTYPE_AP) },
-+#if defined(CPTCFG_MAC80211_MESH) || defined(CONFIG_MAC80211_MESH)
-+	{ .max = SYSADPT_NUM_OF_MESH, .types = BIT(NL80211_IFTYPE_MESH_POINT) },
-+#endif
-+	{ .max = SYSADPT_NUM_OF_CLIENT, .types = BIT(NL80211_IFTYPE_STATION) },
-+};
-+
-+static const struct ieee80211_iface_combination ap_if_comb = {
-+	.limits = ap_if_limits,
-+	.n_limits = ARRAY_SIZE(ap_if_limits),
-+	.max_interfaces = SYSADPT_NUM_OF_AP,
-+	.num_different_channels = 1,
-+	.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) |
-+				BIT(NL80211_CHAN_WIDTH_20) |
-+				BIT(NL80211_CHAN_WIDTH_40) |
-+				BIT(NL80211_CHAN_WIDTH_80) |
-+				BIT(NL80211_CHAN_WIDTH_160),
-+};
-+
-+struct region_code_mapping {
-+	const char *alpha2;
-+	u32 region_code;
-+};
-+
-+static const struct region_code_mapping regmap[] = {
-+	{"US", 0x10}, /* US FCC */
-+	{"CA", 0x20}, /* Canada */
-+	{"FR", 0x30}, /* France */
-+	{"ES", 0x31}, /* Spain  */
-+	{"FR", 0x32}, /* France */
-+	{"JP", 0x40}, /* Japan  */
-+	{"TW", 0x80}, /* Taiwan */
-+	{"AU", 0x81}, /* Australia */
-+	{"CN", 0x90}, /* China (Asia) */
-+};
-+
-+static int mwl_prepare_cmd_buf(struct mwl_priv *priv)
-+{
-+	priv->pcmd_buf =
-+		(unsigned short *)dmam_alloc_coherent(priv->dev,
-+						      CMD_BUF_SIZE,
-+						      &priv->pphys_cmd_buf,
-+						      GFP_KERNEL);
-+	if (!priv->pcmd_buf) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "cannot alloc memory for command buffer\n");
-+		goto err;
-+	}
-+	wiphy_debug(priv->hw->wiphy,
-+		    "priv->pcmd_buf = %p  priv->pphys_cmd_buf = %p\n",
-+		    priv->pcmd_buf,
-+		    (void *)priv->pphys_cmd_buf);
-+	memset(priv->pcmd_buf, 0x00, CMD_BUF_SIZE);
-+
-+	return 0;
-+
-+err:
-+	wiphy_err(priv->hw->wiphy, "command buffer alloc fail\n");
-+
-+	return -EIO;
-+}
-+
-+static int mwl_init_firmware(struct mwl_priv *priv, const char *fw_name,
-+			     const char *cal_name, const char *txpwrlmt_name)
-+{
-+	int rc = 0;
-+
-+	rc = request_firmware((const struct firmware **)&priv->fw_ucode,
-+			      fw_name, priv->dev);
-+
-+	if (rc) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "cannot find firmware image <%s>\n", fw_name);
-+		goto err_load_fw;
-+	}
-+
-+	rc = mwl_hif_download_firmware(priv->hw);
-+	if (rc) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "cannot download firmware image <%s>\n", fw_name);
-+		goto err_download_fw;
-+	}
-+
-+	if (cal_name) {
-+		if ((request_firmware((const struct firmware **)&priv->cal_data,
-+		     cal_name, priv->dev)) < 0)
-+			wiphy_debug(priv->hw->wiphy,
-+				    "cannot find calibtration data\n");
-+	}
-+
-+	if (txpwrlmt_name) {
-+		if ((request_firmware(
-+		     (const struct firmware **)&priv->txpwrlmt_file,
-+		     txpwrlmt_name, priv->dev)) < 0)
-+			wiphy_debug(priv->hw->wiphy,
-+				    "cannot find tx power limit data\n");
-+	}
-+
-+	return rc;
-+
-+err_download_fw:
-+
-+	release_firmware(priv->fw_ucode);
-+
-+err_load_fw:
-+
-+	wiphy_err(priv->hw->wiphy, "firmware init fail\n");
-+
-+	return rc;
-+}
-+
-+static void mwl_process_of_dts(struct mwl_priv *priv)
-+{
-+#ifdef CONFIG_OF
-+	struct property *prop;
-+	u32 prop_value;
-+
-+	priv->dt_node =
-+		of_find_node_by_name(mwl_hif_device_node(priv->hw),
-+				     "mwlwifi");
-+	if (!priv->dt_node)
-+		return;
-+
-+	/* look for all matching property names */
-+	for_each_property_of_node(priv->dt_node, prop) {
-+		if (strcmp(prop->name, "marvell,2ghz") == 0)
-+			priv->disable_2g = true;
-+		if (strcmp(prop->name, "marvell,5ghz") == 0)
-+			priv->disable_5g = true;
-+		if (strcmp(prop->name, "marvell,chainmask") == 0) {
-+			prop_value = be32_to_cpu(*((__be32 *)prop->value));
-+			if (prop_value == 2)
-+				priv->antenna_tx = ANTENNA_TX_2;
-+			else if (prop_value == 3)
-+				priv->antenna_tx = ANTENNA_TX_3;
-+
-+			prop_value = be32_to_cpu(*((__be32 *)
-+						 (prop->value + 4)));
-+			if (prop_value == 2)
-+				priv->antenna_rx = ANTENNA_RX_2;
-+			else if (prop_value == 3)
-+				priv->antenna_rx = ANTENNA_RX_3;
-+		}
-+	}
-+
-+	priv->pwr_node = of_find_node_by_name(priv->dt_node,
-+					      "marvell,powertable");
-+#endif
-+}
-+
-+static void mwl_reg_notifier(struct wiphy *wiphy,
-+			     struct regulatory_request *request)
-+{
-+	struct ieee80211_hw *hw;
-+	struct mwl_priv *priv;
-+#ifdef CONFIG_OF
-+	struct property *prop;
-+	struct property *fcc_prop = NULL;
-+	struct property *etsi_prop = NULL;
-+	struct property *specific_prop = NULL;
-+	u32 prop_value;
-+	int i, j, k;
-+#endif
-+
-+	hw = wiphy_to_ieee80211_hw(wiphy);
-+	priv = hw->priv;
-+
-+	if (priv->forbidden_setting) {
-+		if (!priv->regulatory_set) {
-+			regulatory_hint(wiphy, priv->fw_alpha2);
-+			priv->regulatory_set = true;
-+		} else {
-+			if (memcmp(priv->fw_alpha2, request->alpha2, 2))
-+				regulatory_hint(wiphy, priv->fw_alpha2);
-+		}
-+		return;
-+	}
-+
-+	priv->dfs_region = request->dfs_region;
-+
-+#ifdef CONFIG_OF
-+	if ((priv->chip_type != MWL8997) && (priv->pwr_node)) {
-+		for_each_property_of_node(priv->pwr_node, prop) {
-+			if (strcmp(prop->name, "FCC") == 0)
-+				fcc_prop = prop;
-+			if (strcmp(prop->name, "ETSI") == 0)
-+				etsi_prop = prop;
-+			if ((prop->name[0] == request->alpha2[0]) &&
-+			    (prop->name[1] == request->alpha2[1]))
-+				specific_prop = prop;
-+		}
-+
-+		prop = NULL;
-+
-+		if (specific_prop) {
-+			prop = specific_prop;
-+		} else {
-+			if (priv->dfs_region == NL80211_DFS_ETSI)
-+				prop = etsi_prop;
-+			else
-+				prop = fcc_prop;
-+		}
-+
-+		if (prop) {
-+			/* Reset the whole table */
-+			for (i = 0; i < SYSADPT_MAX_NUM_CHANNELS; i++)
-+				memset(&priv->tx_pwr_tbl[i], 0,
-+				       sizeof(struct mwl_tx_pwr_tbl));
-+
-+			/* Load related power table */
-+			i = 0;
-+			j = 0;
-+			while (i < prop->length) {
-+				prop_value =
-+					be32_to_cpu(*(__be32 *)
-+						    (prop->value + i));
-+				priv->tx_pwr_tbl[j].channel = prop_value;
-+				i += 4;
-+				prop_value =
-+					be32_to_cpu(*(__be32 *)
-+						    (prop->value + i));
-+				priv->tx_pwr_tbl[j].setcap = prop_value;
-+				i += 4;
-+				for (k = 0; k < SYSADPT_TX_POWER_LEVEL_TOTAL;
-+				     k++) {
-+					prop_value =
-+						be32_to_cpu(*(__be32 *)
-+							    (prop->value + i));
-+					priv->tx_pwr_tbl[j].tx_power[k] =
-+						prop_value;
-+					i += 4;
-+				}
-+				prop_value =
-+					be32_to_cpu(*(__be32 *)
-+						    (prop->value + i));
-+				priv->tx_pwr_tbl[j].cdd =
-+					(prop_value == 0) ? false : true;
-+				i += 4;
-+				prop_value =
-+					be32_to_cpu(*(__be32 *)
-+						    (prop->value + i));
-+				priv->tx_pwr_tbl[j].txantenna2 = prop_value;
-+				i += 4;
-+				j++;
-+			}
-+
-+			/* Dump loaded power tabel */
-+			wiphy_debug(hw->wiphy, "regdomain: %s\n", prop->name);
-+			for (i = 0; i < SYSADPT_MAX_NUM_CHANNELS; i++) {
-+				struct mwl_tx_pwr_tbl *pwr_tbl;
-+				char disp_buf[64];
-+				char *disp_ptr;
-+
-+				pwr_tbl = &priv->tx_pwr_tbl[i];
-+				if (pwr_tbl->channel == 0)
-+					break;
-+				wiphy_debug(hw->wiphy,
-+					    "Channel: %d: 0x%x 0x%x 0x%x\n",
-+					    pwr_tbl->channel,
-+					    pwr_tbl->setcap,
-+					    pwr_tbl->cdd,
-+					    pwr_tbl->txantenna2);
-+				disp_ptr = disp_buf;
-+				for (j = 0; j < SYSADPT_TX_POWER_LEVEL_TOTAL;
-+				     j++) {
-+					disp_ptr +=
-+						sprintf(disp_ptr, "%x ",
-+							pwr_tbl->tx_power[j]);
-+				}
-+				wiphy_debug(hw->wiphy, "%s\n", disp_buf);
-+			}
-+		}
-+	}
-+#endif
-+}
-+
-+static void mwl_regd_init(struct mwl_priv *priv)
-+{
-+	u8 region_code;
-+	int rc;
-+	int i;
-+
-+	/* hook regulatory domain change notification */
-+	priv->hw->wiphy->reg_notifier = mwl_reg_notifier;
-+
-+	if (priv->chip_type == MWL8964)
-+		rc = mwl_fwcmd_get_pwr_tbl_sc4(priv->hw,
-+					       &priv->device_pwr_tbl[0],
-+					       &region_code,
-+					       &priv->number_of_channels,
-+					       0);
-+	else
-+		rc = mwl_fwcmd_get_device_pwr_tbl(priv->hw,
-+						  &priv->device_pwr_tbl[0],
-+						  &region_code,
-+						  &priv->number_of_channels,
-+						  0);
-+	if (rc)
-+		return;
-+
-+	priv->forbidden_setting = true;
-+
-+	for (i = 1; i < priv->number_of_channels; i++) {
-+		if (priv->chip_type == MWL8964)
-+			mwl_fwcmd_get_pwr_tbl_sc4(priv->hw,
-+						  &priv->device_pwr_tbl[i],
-+						  &region_code,
-+						  &priv->number_of_channels,
-+						  i);
-+		else
-+			mwl_fwcmd_get_device_pwr_tbl(priv->hw,
-+						     &priv->device_pwr_tbl[i],
-+						     &region_code,
-+						     &priv->number_of_channels,
-+						     i);
-+	}
-+
-+	for (i = 0; i < ARRAY_SIZE(regmap); i++)
-+		if (regmap[i].region_code == priv->fw_region_code) {
-+			memcpy(priv->fw_alpha2, regmap[i].alpha2, 2);
-+			break;
-+		}
-+}
-+
-+static void mwl_set_ht_caps(struct mwl_priv *priv,
-+			    struct ieee80211_supported_band *band)
-+{
-+	struct ieee80211_hw *hw;
-+	const u8 ant_rx_no[ANTENNA_RX_MAX] = { 3, 1, 2, 3};
-+	int i;
-+
-+	hw = priv->hw;
-+
-+	band->ht_cap.ht_supported = 1;
-+	if (priv->chip_type == MWL8964)
-+		band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
-+	band->ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
-+	band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-+	band->ht_cap.cap |= IEEE80211_HT_CAP_SM_PS;
-+	band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
-+	band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
-+	band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
-+
-+	if ((priv->chip_type == MWL8997) &&
-+	    (priv->antenna_tx != ANTENNA_TX_1)) {
-+		band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
-+		band->ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-+	}
-+
-+	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
-+	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
-+	band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-+	band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
-+
-+	for (i = 0; i < ant_rx_no[priv->antenna_rx]; i++)
-+		band->ht_cap.mcs.rx_mask[i] = 0xff;
-+	band->ht_cap.mcs.rx_mask[4] = 0x01;
-+
-+	band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
-+}
-+
-+static void mwl_set_vht_caps(struct mwl_priv *priv,
-+			     struct ieee80211_supported_band *band)
-+{
-+	u32 antenna_num = 4;
-+
-+	band->vht_cap.vht_supported = 1;
-+
-+	if (priv->chip_type == MWL8964) {
-+		band->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
-+		band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
-+		band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
-+	} else
-+		band->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC;
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1;
-+	if (priv->antenna_tx != ANTENNA_TX_1) {
-+		band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
-+		if (priv->chip_type == MWL8964)
-+			band->vht_cap.cap |=
-+				IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
-+	}
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
-+	if (priv->chip_type == MWL8964)
-+		band->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
-+	band->vht_cap.cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
-+	if (priv->chip_type == MWL8997) {
-+		if (priv->antenna_tx != ANTENNA_TX_1)
-+			band->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC;
-+	}
-+
-+	if (priv->antenna_rx == ANTENNA_RX_1)
-+		band->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0xfffe);
-+	else if (priv->antenna_rx == ANTENNA_RX_2)
-+		band->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0xfffa);
-+	else
-+		band->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0xffea);
-+
-+	if (priv->antenna_tx == ANTENNA_TX_1) {
-+		band->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0xfffe);
-+		antenna_num = 1;
-+	} else if (priv->antenna_tx == ANTENNA_TX_2) {
-+		band->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0xfffa);
-+		antenna_num = 2;
-+	} else
-+		band->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0xffea);
-+
-+	if (band->vht_cap.cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
-+	    IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
-+		band->vht_cap.cap |=
-+			((antenna_num - 1) <<
-+			IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT) &
-+			IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
-+	}
-+
-+	if (band->vht_cap.cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
-+	    IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
-+		band->vht_cap.cap |=
-+			((antenna_num - 1) <<
-+			IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) &
-+			IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
-+	}
-+}
-+
-+static void mwl_set_caps(struct mwl_priv *priv)
-+{
-+	struct ieee80211_hw *hw;
-+
-+	hw = priv->hw;
-+
-+	/* set up band information for 2.4G */
-+	if (!priv->disable_2g) {
-+		BUILD_BUG_ON(sizeof(priv->channels_24) !=
-+			     sizeof(mwl_channels_24));
-+		memcpy(priv->channels_24, mwl_channels_24,
-+		       sizeof(mwl_channels_24));
-+
-+		BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl_rates_24));
-+		memcpy(priv->rates_24, mwl_rates_24, sizeof(mwl_rates_24));
-+
-+		priv->band_24.band = NL80211_BAND_2GHZ;
-+		priv->band_24.channels = priv->channels_24;
-+		priv->band_24.n_channels = ARRAY_SIZE(mwl_channels_24);
-+		priv->band_24.bitrates = priv->rates_24;
-+		priv->band_24.n_bitrates = ARRAY_SIZE(mwl_rates_24);
-+
-+		mwl_set_ht_caps(priv, &priv->band_24);
-+		mwl_set_vht_caps(priv, &priv->band_24);
-+
-+		hw->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band_24;
-+	}
-+
-+	/* set up band information for 5G */
-+	if (!priv->disable_5g) {
-+		BUILD_BUG_ON(sizeof(priv->channels_50) !=
-+			     sizeof(mwl_channels_50));
-+		memcpy(priv->channels_50, mwl_channels_50,
-+		       sizeof(mwl_channels_50));
-+
-+		BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl_rates_50));
-+		memcpy(priv->rates_50, mwl_rates_50, sizeof(mwl_rates_50));
-+
-+		priv->band_50.band = NL80211_BAND_5GHZ;
-+		priv->band_50.channels = priv->channels_50;
-+		priv->band_50.n_channels = ARRAY_SIZE(mwl_channels_50);
-+		priv->band_50.bitrates = priv->rates_50;
-+		priv->band_50.n_bitrates = ARRAY_SIZE(mwl_rates_50);
-+
-+		mwl_set_ht_caps(priv, &priv->band_50);
-+		mwl_set_vht_caps(priv, &priv->band_50);
-+
-+		hw->wiphy->bands[NL80211_BAND_5GHZ] = &priv->band_50;
-+	}
-+}
-+
-+static void mwl_heartbeat_handle(struct work_struct *work)
-+{
-+	struct mwl_priv *priv =
-+		container_of(work, struct mwl_priv, heartbeat_handle);
-+	u32 val;
-+
-+	mwl_fwcmd_get_addr_value(priv->hw, 0, 1, &val, 0);
-+	priv->heartbeating = false;
-+}
-+
-+static void mwl_watchdog_ba_events(struct work_struct *work)
-+{
-+	int rc;
-+	u8 bitmap = 0, stream_index;
-+	struct mwl_ampdu_stream *streams;
-+	struct mwl_priv *priv =
-+		container_of(work, struct mwl_priv, watchdog_ba_handle);
-+
-+	rc = mwl_fwcmd_get_watchdog_bitmap(priv->hw, &bitmap);
-+
-+	if (rc)
-+		return;
-+
-+	spin_lock_bh(&priv->stream_lock);
-+
-+	/* the bitmap is the hw queue number.  Map it to the ampdu queue. */
-+	if (bitmap != INVALID_WATCHDOG) {
-+		if (bitmap == priv->ampdu_num)
-+			stream_index = 0;
-+		else if (bitmap > priv->ampdu_num)
-+			stream_index = bitmap - priv->ampdu_num;
-+		else
-+			stream_index = bitmap + 3; /** queue 0 is stream 3*/
-+
-+		if (bitmap != 0xFF) {
-+			/* Check if the stream is in use before disabling it */
-+			streams = &priv->ampdu[stream_index];
-+
-+			if (streams->state == AMPDU_STREAM_ACTIVE)
-+				ieee80211_stop_tx_ba_session(streams->sta,
-+							     streams->tid);
-+		} else {
-+			for (stream_index = 0;
-+			     stream_index < priv->ampdu_num;
-+			     stream_index++) {
-+				streams = &priv->ampdu[stream_index];
-+
-+				if (streams->state != AMPDU_STREAM_ACTIVE)
-+					continue;
-+
-+				ieee80211_stop_tx_ba_session(streams->sta,
-+							     streams->tid);
-+			}
-+		}
-+	}
-+
-+	spin_unlock_bh(&priv->stream_lock);
-+}
-+
-+static void mwl_account_handle(struct work_struct *work)
-+{
-+	struct mwl_priv *priv =
-+		container_of(work, struct mwl_priv, account_handle);
-+
-+	mwl_hif_process_account(priv->hw);
-+}
-+
-+static void mwl_wds_check_handle(struct work_struct *work)
-+{
-+	struct mwl_priv *priv =
-+		container_of(work, struct mwl_priv, wds_check_handle);
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+	bool wds_sta = false;
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		if (sta_info->wds)
-+			continue;
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv);
-+		if (ether_addr_equal(sta->addr, priv->wds_check_sta)) {
-+			wds_sta = true;
-+			break;
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	if (wds_sta) {
-+		mwl_fwcmd_set_new_stn_wds_sc4(priv->hw, sta->addr);
-+		sta_info->wds = true;
-+	}
-+
-+	priv->wds_check = false;
-+}
-+
-+static void mwl_chnl_switch_event(struct work_struct *work)
-+{
-+	struct mwl_priv *priv =
-+		container_of(work, struct mwl_priv, chnl_switch_handle);
-+	struct mwl_vif *mwl_vif;
-+	struct ieee80211_vif *vif;
-+
-+	if (!priv->csa_active) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "csa is not active (got channel switch event)\n");
-+		return;
-+	}
-+
-+	spin_lock_bh(&priv->vif_lock);
-+	list_for_each_entry(mwl_vif, &priv->vif_list, list) {
-+		vif = container_of((void *)mwl_vif, struct ieee80211_vif,
-+				   drv_priv);
-+
-+		if (vif->csa_active)
-+			ieee80211_csa_finish(vif);
-+	}
-+	spin_unlock_bh(&priv->vif_lock);
-+
-+	wiphy_info(priv->hw->wiphy, "channel switch is done\n");
-+
-+	priv->csa_active = false;
-+}
-+
-+static irqreturn_t mwl_isr(int irq, void *dev_id)
-+{
-+	struct ieee80211_hw *hw = dev_id;
-+
-+	return mwl_hif_irq_handler(hw);
-+}
-+
-+#ifdef timer_setup
-+static void timer_routine(struct timer_list *t)
-+{
-+	struct mwl_priv *priv = from_timer(priv, t, period_timer);
-+	struct ieee80211_hw *hw = priv->hw;
-+#else
-+static void timer_routine(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+#endif
-+	if (priv->heartbeat) {
-+		if ((jiffies - priv->pre_jiffies) >=
-+		    msecs_to_jiffies(priv->heartbeat * 1000)) {
-+			if (!priv->heartbeating) {
-+				priv->heartbeating = true;
-+				ieee80211_queue_work(hw,
-+						     &priv->heartbeat_handle);
-+			}
-+			priv->pre_jiffies = jiffies;
-+		}
-+	}
-+
-+	mwl_hif_timer_routine(hw);
-+
-+	mod_timer(&priv->period_timer, jiffies +
-+		  msecs_to_jiffies(SYSADPT_TIMER_WAKEUP_TIME));
-+}
-+
-+static int mwl_wl_init(struct mwl_priv *priv)
-+{
-+	struct ieee80211_hw *hw = priv->hw;
-+	int rc;
-+	u16 addr_num;
-+	struct mac_address *mac_addr;
-+	u8 last_nibble;
-+
-+	hw->extra_tx_headroom = mwl_hif_get_tx_head_room(hw);
-+	hw->queues = SYSADPT_TX_WMM_QUEUES;
-+
-+	/* Set rssi values to dBm */
-+	ieee80211_hw_set(hw, SIGNAL_DBM);
-+	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
-+
-+	/* Ask mac80211 not to trigger PS mode
-+	 * based on PM bit of incoming frames.
-+	 */
-+	ieee80211_hw_set(hw, AP_LINK_PS);
-+
-+	ieee80211_hw_set(hw, SUPPORTS_PER_STA_GTK);
-+	ieee80211_hw_set(hw, MFP_CAPABLE);
-+
-+	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
-+	hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-+	hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
-+	hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
-+
-+	hw->vif_data_size = sizeof(struct mwl_vif);
-+	hw->sta_data_size = sizeof(struct mwl_sta);
-+
-+	priv->ap_macids_supported = 0x0000ffff;
-+	priv->sta_macids_supported = 0x00010000;
-+	priv->macids_used = 0;
-+	INIT_LIST_HEAD(&priv->vif_list);
-+	INIT_LIST_HEAD(&priv->sta_list);
-+
-+	/* Set default radio state, preamble and wmm */
-+	priv->noise = -104;
-+	priv->radio_on = false;
-+	priv->radio_short_preamble = false;
-+	priv->wmm_enabled = false;
-+	priv->powinited = 0;
-+	priv->wds_check = false;
-+	if (priv->chip_type == MWL8997)
-+		priv->pwr_level = SYSADPT_TX_GRP_PWR_LEVEL_TOTAL;
-+	else
-+		priv->pwr_level = SYSADPT_TX_POWER_LEVEL_TOTAL;
-+	priv->dfs_test = false;
-+	priv->csa_active = false;
-+	priv->dfs_chirp_count_min = 5;
-+	priv->dfs_chirp_time_interval = 1000;
-+	priv->dfs_pw_filter = 0;
-+	priv->dfs_min_num_radar = 5;
-+	priv->dfs_min_pri_count = 4;
-+	priv->bf_type = TXBF_MODE_AUTO;
-+
-+	/* Handle watchdog ba events */
-+	INIT_WORK(&priv->heartbeat_handle, mwl_heartbeat_handle);
-+	INIT_WORK(&priv->watchdog_ba_handle, mwl_watchdog_ba_events);
-+	INIT_WORK(&priv->account_handle, mwl_account_handle);
-+	INIT_WORK(&priv->wds_check_handle, mwl_wds_check_handle);
-+	INIT_WORK(&priv->chnl_switch_handle, mwl_chnl_switch_event);
-+
-+	mutex_init(&priv->fwcmd_mutex);
-+	spin_lock_init(&priv->vif_lock);
-+	spin_lock_init(&priv->sta_lock);
-+	spin_lock_init(&priv->stream_lock);
-+	spin_lock_init(&priv->stnid_lock);
-+
-+	rc = mwl_thermal_register(priv);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "fail to register thermal framework\n");
-+		goto err_thermal_register;
-+	}
-+
-+	rc = mwl_hif_init(hw);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "fail to initialize host interface\n");
-+		goto err_hif_init;
-+	}
-+
-+	SET_IEEE80211_PERM_ADDR(hw, priv->hw_data.mac_addr);
-+
-+	if (priv->chip_type == MWL8964) {
-+		addr_num = SYSADPT_NUM_OF_AP + SYSADPT_NUM_OF_CLIENT;
-+		hw->wiphy->n_addresses = addr_num;
-+		hw->wiphy->addresses =
-+			kzalloc(addr_num * sizeof(*mac_addr), GFP_KERNEL);
-+
-+		mac_addr = &hw->wiphy->addresses[0];
-+		ether_addr_copy(mac_addr->addr, priv->hw_data.mac_addr);
-+		last_nibble = mac_addr->addr[5] & 0x0F;
-+		for (addr_num = 0; addr_num < SYSADPT_NUM_OF_AP; addr_num++) {
-+			mac_addr = &hw->wiphy->addresses[addr_num + 1];
-+			ether_addr_copy(mac_addr->addr, priv->hw_data.mac_addr);
-+			if (!strcmp(wiphy_name(hw->wiphy), "phy0")) {
-+				last_nibble++;
-+				if (last_nibble == 0x10)
-+					last_nibble = 0;
-+			} else {
-+				last_nibble--;
-+				if (last_nibble == 0xFF)
-+					last_nibble = 0x0F;
-+			}
-+			mac_addr->addr[5] =
-+				(mac_addr->addr[5] & 0xF0) | last_nibble;
-+			mac_addr->addr[0] |= 0x2;
-+		}
-+	}
-+
-+	wiphy_info(hw->wiphy,
-+		   "firmware version: 0x%x\n", priv->hw_data.fw_release_num);
-+
-+	if (priv->chip_type == MWL8997) {
-+		mwl_fwcmd_set_cfg_data(hw, 2);
-+		mwl_fwcmd_set_txpwrlmt_cfg_data(hw);
-+		mwl_fwcmd_get_txpwrlmt_cfg_data(hw);
-+	}
-+
-+	if (priv->chip_type == MWL8964)
-+		rc = mwl_fwcmd_get_fw_region_code_sc4(hw,
-+						      &priv->fw_region_code);
-+	else
-+		rc = mwl_fwcmd_get_fw_region_code(hw, &priv->fw_region_code);
-+	if (!rc) {
-+		priv->fw_device_pwrtbl = true;
-+		mwl_regd_init(priv);
-+		wiphy_info(hw->wiphy,
-+			   "firmware region code: %x\n", priv->fw_region_code);
-+	}
-+
-+	if (priv->chip_type == MWL8997)
-+		mwl_fwcmd_dump_otp_data(hw);
-+
-+	mwl_fwcmd_radio_disable(hw);
-+	mwl_fwcmd_rf_antenna(hw, WL_ANTENNATYPE_TX, priv->antenna_tx);
-+	mwl_fwcmd_rf_antenna(hw, WL_ANTENNATYPE_RX, priv->antenna_rx);
-+
-+	hw->wiphy->interface_modes = 0;
-+	hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
-+#if defined(CPTCFG_MAC80211_MESH) || defined(CONFIG_MAC80211_MESH)
-+	hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT);
-+#endif
-+	hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
-+	hw->wiphy->iface_combinations = &ap_if_comb;
-+	hw->wiphy->n_iface_combinations = 1;
-+
-+	mwl_set_caps(priv);
-+
-+	priv->led_blink_enable = 1;
-+	priv->led_blink_rate = LED_BLINK_RATE_MID;
-+	mwl_fwcmd_led_ctrl(hw, priv->led_blink_enable, priv->led_blink_rate);
-+
-+	vendor_cmd_register(hw->wiphy);
-+
-+	rc = ieee80211_register_hw(hw);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "fail to register device\n");
-+		goto err_register_hw;
-+	}
-+
-+	priv->irq = mwl_hif_get_irq_num(hw);
-+	rc = request_irq(priv->irq, mwl_isr, IRQF_SHARED,
-+			 mwl_hif_get_driver_name(hw), hw);
-+	if (rc) {
-+		priv->irq = -1;
-+		wiphy_err(hw->wiphy, "fail to register IRQ handler\n");
-+		goto err_register_irq;
-+	}
-+#ifdef timer_setup
-+	timer_setup(&priv->period_timer, timer_routine, 0);
-+#else
-+	setup_timer(&priv->period_timer, timer_routine, (unsigned long)hw);
-+#endif
-+	mod_timer(&priv->period_timer, jiffies +
-+		  msecs_to_jiffies(SYSADPT_TIMER_WAKEUP_TIME));
-+
-+	return rc;
-+
-+err_register_hw:
-+err_register_irq:
-+	mwl_hif_deinit(hw);
-+
-+err_hif_init:
-+err_thermal_register:
-+
-+	wiphy_err(hw->wiphy, "init fail\n");
-+
-+	return rc;
-+}
-+
-+static void mwl_wl_deinit(struct mwl_priv *priv)
-+{
-+	struct ieee80211_hw *hw = priv->hw;
-+
-+	del_timer_sync(&priv->period_timer);
-+
-+	if (priv->irq != -1) {
-+		free_irq(priv->irq, hw);
-+		priv->irq = -1;
-+	}
-+
-+	if (priv->chip_type == MWL8964)
-+		kfree(hw->wiphy->addresses);
-+	ieee80211_unregister_hw(hw);
-+	mwl_thermal_unregister(priv);
-+	cancel_work_sync(&priv->chnl_switch_handle);
-+	cancel_work_sync(&priv->account_handle);
-+	cancel_work_sync(&priv->wds_check_handle);
-+	cancel_work_sync(&priv->watchdog_ba_handle);
-+	cancel_work_sync(&priv->heartbeat_handle);
-+	mwl_hif_deinit(hw);
-+}
-+
-+struct ieee80211_hw *mwl_alloc_hw(int bus_type,
-+				  int chip_type,
-+				  struct device *dev,
-+				  const struct mwl_hif_ops *ops,
-+				  size_t hif_data_len)
-+{
-+	struct ieee80211_hw *hw;
-+	struct mwl_priv *priv;
-+	int priv_size;
-+
-+	priv_size = ALIGN(sizeof(*priv), NETDEV_ALIGN) + hif_data_len;
-+
-+	hw = ieee80211_alloc_hw(priv_size, &mwl_mac80211_ops);
-+	if (!hw) {
-+		pr_err("ieee80211 alloc hw failed\n");
-+		return NULL;
-+	}
-+
-+	priv = hw->priv;
-+	priv->hw = hw;
-+	priv->dev = dev;
-+	priv->chip_type = chip_type;
-+	priv->fw_device_pwrtbl = false;
-+	priv->forbidden_setting = false;
-+	priv->regulatory_set = false;
-+	priv->use_short_slot = false;
-+	priv->use_short_preamble = false;
-+	priv->disable_2g = false;
-+	priv->disable_5g = false;
-+	priv->tx_amsdu = true;
-+	priv->hif.bus = bus_type;
-+	priv->hif.ops = ops;
-+	priv->hif.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN);
-+	priv->ampdu_num = mwl_hif_get_ampdu_num(hw);
-+	priv->ampdu =
-+		kzalloc(priv->ampdu_num * sizeof(*priv->ampdu), GFP_KERNEL);
-+	if (!priv->ampdu) {
-+		ieee80211_free_hw(hw);
-+		pr_err("alloc ampdu stream failed\n");
-+		return NULL;
-+	}
-+
-+	if (chip_type == MWL8964)
-+		priv->stnid_num = SYSADPT_MAX_STA_SC4;
-+	else
-+		priv->stnid_num = SYSADPT_MAX_STA;
-+	priv->stnid =
-+		kzalloc(priv->stnid_num * sizeof(struct mwl_stnid), GFP_KERNEL);
-+	if (!priv->stnid) {
-+		kfree(priv->ampdu);
-+		ieee80211_free_hw(hw);
-+		pr_err("alloc stnid failed\n");
-+		return NULL;
-+	}
-+	priv->available_stnid = 0;
-+
-+	SET_IEEE80211_DEV(hw, dev);
-+
-+	return hw;
-+}
-+
-+void mwl_free_hw(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	kfree(priv->stnid);
-+	kfree(priv->ampdu);
-+	ieee80211_free_hw(hw);
-+}
-+
-+int mwl_init_hw(struct ieee80211_hw *hw, const char *fw_name,
-+		const char *cal_name, const char *txpwrlmt_name)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc;
-+	int tx_num = 4, rx_num = 4;
-+
-+
-+	rc = mwl_prepare_cmd_buf(priv);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "fail to prepare command buffer\n");
-+		return -ENOMEM;
-+	}
-+
-+	rc = mwl_init_firmware(priv, fw_name, cal_name, txpwrlmt_name);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "fail to initialize firmware\n");
-+		return -EIO;
-+	}
-+
-+	/* firmware is loaded to H/W, it can be released now */
-+	release_firmware(priv->fw_ucode);
-+
-+	mwl_process_of_dts(priv);
-+
-+	rc = mwl_wl_init(priv);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "fail to initialize wireless lan\n");
-+		return -EIO;
-+	}
-+
-+	wiphy_info(priv->hw->wiphy, "2G %s, 5G %s\n",
-+		   priv->disable_2g ? "disabled" : "enabled",
-+		   priv->disable_5g ? "disabled" : "enabled");
-+
-+	if (priv->antenna_tx == ANTENNA_TX_2)
-+		tx_num = 2;
-+	else if (priv->antenna_tx == ANTENNA_TX_3)
-+		tx_num = 3;
-+	if (priv->antenna_rx == ANTENNA_RX_2)
-+		rx_num = 2;
-+	else if (priv->antenna_rx == ANTENNA_RX_3)
-+		rx_num = 3;
-+	wiphy_info(priv->hw->wiphy, "%d TX antennas, %d RX antennas\n",
-+		   tx_num, rx_num);
-+
-+#ifdef CONFIG_DEBUG_FS
-+	mwl_debugfs_init(hw);
-+#endif
-+
-+	return 0;
-+}
-+
-+void mwl_deinit_hw(struct ieee80211_hw *hw)
-+{
-+#ifdef CONFIG_DEBUG_FS
-+	mwl_debugfs_remove(hw);
-+#endif
-+
-+	mwl_wl_deinit(hw->priv);
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/core.h b/drivers/net/wireless/marvell/mwlwifi/core.h
-new file mode 100644
-index 000000000000..00069c4f0b44
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/core.h
-@@ -0,0 +1,517 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines core layer related functions. */
-+
-+#ifndef _CORE_H_
-+#define _CORE_H_
-+
-+#include <linux/interrupt.h>
-+#include <linux/firmware.h>
-+#include <linux/of.h>
-+#include <net/mac80211.h>
-+
-+#include "hif/hif.h"
-+
-+/* antenna control */
-+#define ANTENNA_TX_4_AUTO             0
-+#define ANTENNA_TX_1                  1
-+#define ANTENNA_TX_2                  3
-+#define ANTENNA_TX_3                  7
-+#define ANTENNA_RX_4_AUTO             0
-+#define ANTENNA_RX_1                  1
-+#define ANTENNA_RX_2                  2
-+#define ANTENNA_RX_3                  3
-+#define ANTENNA_RX_MAX                4
-+
-+/* band related constants */
-+#define BAND_24_CHANNEL_NUM           14
-+#define BAND_24_RATE_NUM              13
-+#define BAND_50_CHANNEL_NUM           24
-+#define BAND_50_RATE_NUM              8
-+
-+#define NUM_WEP_KEYS                  4
-+#define MWL_MAX_TID                   8
-+#define MWL_AMSDU_SIZE_4K             1
-+#define MWL_AMSDU_SIZE_8K             2
-+#define MWL_AMSDU_SIZE_11K            3
-+
-+/* power init */
-+#define MWL_POWER_INIT_1              1
-+#define MWL_POWER_INIT_2              2
-+
-+/* tx rate information constants */
-+#define TX_RATE_FORMAT_LEGACY         0
-+#define TX_RATE_FORMAT_11N            1
-+#define TX_RATE_FORMAT_11AC           2
-+
-+#define TX_RATE_BANDWIDTH_20          0
-+#define TX_RATE_BANDWIDTH_40          1
-+#define TX_RATE_BANDWIDTH_80          2
-+#define TX_RATE_BANDWIDTH_160         3
-+
-+#define TX_RATE_INFO_STD_GI           0
-+#define TX_RATE_INFO_SHORT_GI         1
-+
-+/* tx rate information */
-+/* 0: legacy format 1: 11n format 2: 11ac format */
-+#define MWL_TX_RATE_FORMAT_MASK       0x00000003
-+#define MWL_TX_RATE_STBC_MASK         0x00000004
-+#define MWL_TX_RATE_STBC_SHIFT        2
-+/* 0: 20 MHz 1: 40 MHz 2: 80 MHz 3: 160 MHz      */
-+#define MWL_TX_RATE_BANDWIDTH_MASK    0x00000030
-+#define MWL_TX_RATE_BANDWIDTH_SHIFT   4
-+/* 0: normal 1: short                            */
-+#define MWL_TX_RATE_SHORTGI_MASK      0x00000040
-+#define MWL_TX_RATE_SHORTGI_SHIFT     6
-+#define MWL_TX_RATE_RATEIDMCS_MASK    0x00007F00
-+#define MWL_TX_RATE_RATEIDMCS_SHIFT   8
-+/* 0: long   1: short                            */
-+#define MWL_TX_RATE_PREAMBLE_MASK     0x00008000
-+#define MWL_TX_RATE_PREAMBLE_SHIFT    15
-+#define MWL_TX_RATE_POWERID_MASK      0x003F0000
-+#define MWL_TX_RATE_POWERID_SHIFT     16
-+#define MWL_TX_RATE_ADVCODING_MASK    0x00400000
-+#define MWL_TX_RATE_ADVCODING_SHIFT   22
-+/* 0: beam forming off 1: beam forming on        */
-+#define MWL_TX_RATE_BF_MASK           0x00800000
-+#define MWL_TX_RATE_BF_SHIFT          23
-+#define MWL_TX_RATE_ANTSELECT_MASK    0xFF000000
-+#define MWL_TX_RATE_ANTSELECT_SHIFT   24
-+
-+#define ACNT_BA_SIZE                  1000
-+
-+/* Q stats */
-+#define QS_MAX_DATA_RATES_G           14
-+#define QS_NUM_SUPPORTED_11N_BW       2
-+#define QS_NUM_SUPPORTED_GI           2
-+#define QS_NUM_SUPPORTED_MCS          24
-+#define QS_NUM_SUPPORTED_11AC_NSS     3
-+#define QS_NUM_SUPPORTED_11AC_BW      4
-+#define QS_NUM_SUPPORTED_11AC_MCS     10
-+#define TX_RATE_HISTO_CUSTOM_CNT      1
-+#define TX_RATE_HISTO_PER_CNT         5
-+#define MAX_DATA_RATES_G              14
-+#define MAX_SUPPORTED_MCS             24
-+#define MAX_SUPPORTED_11AC_RATES      20
-+/* MAX_DATA_RATES_G + MAX_SUPPORTED_MCS + MAX_SUPPORTED_11AC_RATES */
-+#define MAX_SUPPORTED_RATES           58
-+#define SU_MIMO                       0
-+#define MU_MIMO                       1
-+#define SU_MU_TYPE_CNT                2 /* traffic type, SU and MU */
-+
-+/* BF operation mode */
-+#define TXBF_MODE_OFF                 0x05
-+#define TXBF_MODE_AUTO                0x06
-+#define TXBF_MODE_BFMER_AUTO          0x07
-+
-+static const u8 TX_HISTO_PER_THRES[TX_RATE_HISTO_PER_CNT - 1] = {6, 12, 20, 30};
-+
-+enum {
-+	MWL8864 = 0,
-+	MWL8897,
-+	MWL8964,
-+	MWL8997,
-+	MWLUNKNOWN,
-+};
-+
-+enum mwl_bus {
-+	MWL_BUS_PCIE,
-+	MWL_BUS_SDIO,
-+};
-+
-+enum {
-+	AP_MODE_11AC = 0x10,         /* generic 11ac indication mode */
-+	AP_MODE_2_4GHZ_11AC_MIXED = 0x17,
-+};
-+
-+enum {
-+	AMPDU_NO_STREAM = 0,
-+	AMPDU_STREAM_NEW,
-+	AMPDU_STREAM_IN_PROGRESS,
-+	AMPDU_STREAM_ACTIVE,
-+};
-+
-+enum {
-+	LED_BLINK_RATE_LOW = 0x1,
-+	LED_BLINK_RATE_MID,
-+	LED_BLINK_RATE_HIGH,
-+};
-+
-+struct mwl_chip_info {
-+	const char *part_name;
-+	const char *fw_image;
-+	const char *cal_file;
-+	const char *txpwrlmt_file;
-+	int antenna_tx;
-+	int antenna_rx;
-+};
-+
-+struct mwl_device_pwr_tbl {
-+	u8 channel;
-+	u8 tx_pwr[SYSADPT_TX_PWR_LEVEL_TOTAL_SC4];
-+	u8 dfs_capable;
-+	u8 ax_ant;
-+	u8 cdd;
-+};
-+
-+struct mwl_tx_pwr_tbl {
-+	u8 channel;
-+	u8 setcap;
-+	u16 txantenna2;
-+	u16 tx_power[SYSADPT_TX_POWER_LEVEL_TOTAL];
-+	bool cdd;
-+};
-+
-+struct mwl_hw_data {
-+	u32 fw_release_num;          /* MajNbr:MinNbr:SubMin:PatchLevel */
-+	u8 hw_version;               /* plain number indicating version */
-+	unsigned char mac_addr[ETH_ALEN]; /* well known -> AA:BB:CC:DD:EE:FF */
-+};
-+
-+struct mwl_ampdu_stream {
-+	struct ieee80211_sta *sta;
-+	u8 tid;
-+	u8 state;
-+	int idx;
-+};
-+
-+struct mwl_stnid {
-+	int macid;                  /* keep macid for related stnid */
-+	u16 aid;                    /* keep aid for related stnid   */
-+};
-+
-+struct otp_data {
-+	u8 buf[SYSADPT_OTP_BUF_SIZE];
-+	u32 len; /* Actual size of data in buf[] */
-+};
-+
-+struct txpwrlmt_cfg_data {
-+	u8 buf[SYSADPT_TXPWRLMT_CFG_BUF_SIZE];
-+	u32 len; /* Actual size of data in buf[] */
-+};
-+
-+struct mwl_priv {
-+	struct ieee80211_hw *hw;
-+	struct device *dev;
-+	struct firmware *fw_ucode;
-+	struct firmware *cal_data;
-+	struct firmware *txpwrlmt_file;
-+	struct otp_data otp_data;
-+	struct txpwrlmt_cfg_data txpwrlmt_data;
-+	bool fw_device_pwrtbl;
-+	bool forbidden_setting;
-+	bool regulatory_set;
-+	u32 fw_region_code;
-+	char fw_alpha2[2];
-+	u8 number_of_channels;
-+	struct mwl_device_pwr_tbl device_pwr_tbl[SYSADPT_MAX_NUM_CHANNELS];
-+	int chip_type;
-+
-+	bool use_short_slot;
-+	bool use_short_preamble;
-+
-+	struct {
-+		enum mwl_bus bus;
-+		const struct mwl_hif_ops *ops;
-+		void *priv;
-+	} hif;
-+
-+	struct device_node *dt_node;
-+	struct device_node *pwr_node;
-+	bool disable_2g;
-+	bool disable_5g;
-+	int antenna_tx;
-+	int antenna_rx;
-+	bool tx_amsdu;
-+	bool dump_hostcmd;
-+	bool dump_probe;
-+
-+	struct mwl_tx_pwr_tbl tx_pwr_tbl[SYSADPT_MAX_NUM_CHANNELS];
-+	bool cdd;
-+	u16 txantenna2;
-+	u8 powinited;
-+	u8 pwr_level;
-+	u16 max_tx_pow[SYSADPT_TX_GRP_PWR_LEVEL_TOTAL]; /* max tx power (dBm) */
-+	u16 target_powers[SYSADPT_TX_GRP_PWR_LEVEL_TOTAL]; /* target powers   */
-+
-+	struct mutex fwcmd_mutex;    /* for firmware command         */
-+	unsigned short *pcmd_buf;    /* pointer to CmdBuf (virtual)  */
-+	dma_addr_t pphys_cmd_buf;    /* pointer to CmdBuf (physical) */
-+	bool in_send_cmd;
-+	bool cmd_timeout;
-+	bool rmmod;
-+	int heartbeat;
-+	u32 pre_jiffies;
-+	bool heartbeating;
-+	struct work_struct heartbeat_handle;
-+
-+	int irq;
-+	struct mwl_hw_data hw_data;  /* Adapter HW specific info     */
-+
-+	struct timer_list period_timer;
-+
-+	/* keep survey information */
-+	bool sw_scanning;
-+	int survey_info_idx;
-+	struct mwl_survey_info survey_info[SYSADPT_MAX_NUM_CHANNELS];
-+	struct mwl_survey_info cur_survey_info;
-+
-+	s8 noise;                    /* Most recently reported noise in dBm */
-+
-+	struct ieee80211_supported_band band_24;
-+	struct ieee80211_channel channels_24[BAND_24_CHANNEL_NUM];
-+	struct ieee80211_rate rates_24[BAND_24_RATE_NUM];
-+	struct ieee80211_supported_band band_50;
-+	struct ieee80211_channel channels_50[BAND_50_CHANNEL_NUM];
-+	struct ieee80211_rate rates_50[BAND_50_RATE_NUM];
-+
-+	u32 ap_macids_supported;
-+	u32 sta_macids_supported;
-+	u32 macids_used;
-+	u32 running_bsses;           /* bitmap of running BSSes             */
-+
-+	struct {
-+		spinlock_t vif_lock;         /* for private interface info  */
-+		struct list_head vif_list;   /* List of interfaces.         */
-+	} ____cacheline_aligned_in_smp;
-+
-+	struct {
-+		spinlock_t sta_lock;         /* for private sta info        */
-+		struct list_head sta_list;   /* List of stations            */
-+	} ____cacheline_aligned_in_smp;
-+
-+	/* ampdu stream information */
-+	/* for ampdu stream */
-+	int ampdu_num;
-+	struct {
-+		spinlock_t stream_lock;      /* for BA stream               */
-+		struct mwl_ampdu_stream *ampdu;
-+	} ____cacheline_aligned_in_smp;
-+	struct work_struct watchdog_ba_handle;
-+
-+	/* station id */
-+	int stnid_num;
-+	struct {
-+		spinlock_t stnid_lock;      /* for station id              */
-+		struct mwl_stnid *stnid;
-+		u16 available_stnid;
-+	} ____cacheline_aligned_in_smp;
-+
-+	bool radio_on;
-+	bool radio_short_preamble;
-+	bool wmm_enabled;
-+	struct ieee80211_tx_queue_params wmm_params[SYSADPT_TX_WMM_QUEUES];
-+
-+	struct work_struct account_handle;
-+
-+	bool wds_check;
-+	struct work_struct wds_check_handle;
-+	u8 wds_check_sta[ETH_ALEN];
-+
-+	bool dfs_test;
-+	bool csa_active;
-+	struct work_struct chnl_switch_handle;
-+	enum nl80211_dfs_regions dfs_region;
-+	u16 dfs_chirp_count_min;
-+	u16 dfs_chirp_time_interval;
-+	u16 dfs_pw_filter;
-+	u16 dfs_min_num_radar;
-+	u16 dfs_min_pri_count;
-+
-+	u8 bf_type;
-+
-+	struct thermal_cooling_device *cdev;
-+	u32 throttle_state;
-+	u32 quiet_period;
-+	int temperature;
-+
-+	u8 led_blink_enable;
-+	u8 led_blink_rate;
-+
-+	struct dentry *debugfs_phy;
-+	u32 reg_type;
-+	u32 reg_offset;
-+	u32 reg_value;
-+	int ra_aid;
-+	int ba_aid;
-+	int fixed_rate;
-+	bool coredump_text;
-+	u32 ra_tx_attempt[2][6];
-+};
-+
-+struct beacon_info {
-+	bool valid;
-+	u16 cap_info;
-+	u8 power_constraint;
-+	u8 b_rate_set[SYSADPT_MAX_DATA_RATES_G];
-+	u8 op_rate_set[SYSADPT_MAX_DATA_RATES_G];
-+	u8 ie_list_ht[148];
-+	u8 ie_list_vht[24];
-+	u8 *ie_wmm_ptr;
-+	u8 *ie_wsc_ptr;
-+	u8 *ie_rsn_ptr;
-+	u8 *ie_rsn48_ptr;
-+	u8 *ie_mde_ptr;
-+	u8 *ie_ht_ptr;
-+	u8 *ie_vht_ptr;
-+	u8 *ie_country_ptr;
-+	u8 *ie_meshid_ptr;
-+	u8 *ie_meshcfg_ptr;
-+	u8 *ie_meshchsw_ptr;
-+	u8 ie_wmm_len;
-+	u8 ie_wsc_len;
-+	u8 ie_rsn_len;
-+	u8 ie_rsn48_len;
-+	u8 ie_mde_len;
-+	u8 ie_ht_len;
-+	u8 ie_vht_len;
-+	u8 ie_country_len;
-+	u8 ie_meshid_len;
-+	u8 ie_meshcfg_len;
-+	u8 ie_meshchsw_len;
-+};
-+
-+struct mwl_vif {
-+	struct list_head list;
-+	enum nl80211_iftype type;
-+	int macid;       /* Firmware macid for this vif.  */
-+	u16 seqno;       /* Non AMPDU sequence number assigned by driver.  */
-+	struct {         /* Saved WEP keys */
-+		u8 enabled;
-+		u8 key[sizeof(struct ieee80211_key_conf) + WLAN_KEY_LEN_WEP104];
-+	} wep_key_conf[NUM_WEP_KEYS];
-+	u8 bssid[ETH_ALEN];          /* BSSID */
-+	u8 sta_mac[ETH_ALEN];        /* Station mac address */
-+	/* A flag to indicate is HW crypto is enabled for this bssid */
-+	bool is_hw_crypto_enabled;
-+	/* Indicate if this is station mode */
-+	struct beacon_info beacon_info;
-+	bool set_beacon;
-+	int basic_rate_idx;
-+	u8 broadcast_ssid;
-+	u16 iv16;
-+	u32 iv32;
-+	s8 keyidx;
-+};
-+
-+struct mwl_tx_info {
-+	unsigned long start_time;
-+	u32 pkts;
-+};
-+
-+struct mwl_amsdu_frag {
-+	struct sk_buff *skb;
-+	u8 *cur_pos;
-+	unsigned long jiffies;
-+	u8 pad;
-+	u8 num;
-+};
-+
-+struct mwl_amsdu_ctrl {
-+	struct mwl_amsdu_frag frag[SYSADPT_TX_WMM_QUEUES];
-+	u8 cap;
-+};
-+
-+struct mwl_tx_ba_stats {
-+	u8 ba_hole;     /* Total pkt not acked in a BA bitmap */
-+	u8 ba_expected; /* Total Tx pkt expected to be acked  */
-+	u8 no_ba;       /* No BA is received                  */
-+	u8 pad;         /* Unused                             */
-+};
-+
-+struct mwl_tx_ba_hist {
-+	u16 index;      /* Current buffer index               */
-+	u8 type;        /* 0:SU, 1: MU                        */
-+	bool enable;
-+	struct mwl_tx_ba_stats *ba_stats;
-+};
-+
-+struct mwl_tx_hist_data {
-+	u32 rateinfo;
-+	u32 cnt;
-+	/* store according to TX_HISTO_PER_THRES threshold    */
-+	u32 per[TX_RATE_HISTO_PER_CNT];
-+};
-+
-+struct mwl_tx_hist {
-+	struct mwl_tx_hist_data su_rate[MAX_SUPPORTED_RATES];
-+	struct mwl_tx_hist_data mu_rate
-+		[QS_NUM_SUPPORTED_11AC_NSS - 1][QS_NUM_SUPPORTED_11AC_BW]
-+		[QS_NUM_SUPPORTED_GI][QS_NUM_SUPPORTED_11AC_MCS];
-+	struct mwl_tx_hist_data custom_rate[TX_RATE_HISTO_CUSTOM_CNT];
-+	/* Current rate for 0:SU, 1:MU         */
-+	u32 cur_rate_info[SU_MU_TYPE_CNT];
-+	/* Total tx attempt cnt for 0:SU, 1:MU */
-+	u32 total_tx_cnt[SU_MU_TYPE_CNT];
-+};
-+
-+struct mwl_sta {
-+	struct list_head list;
-+	struct mwl_vif *mwl_vif;
-+	u16 stnid;
-+	u16 sta_stnid;
-+	bool wds;
-+	bool is_mesh_node;
-+	bool is_ampdu_allowed;
-+	struct mwl_tx_info tx_stats[MWL_MAX_TID];
-+	u32 check_ba_failed[MWL_MAX_TID];
-+	struct mwl_tx_ba_hist ba_hist;
-+	bool is_amsdu_allowed;
-+	bool is_key_set;
-+	/* for amsdu aggregation */
-+	struct {
-+		spinlock_t amsdu_lock;   /* for amsdu */
-+		struct mwl_amsdu_ctrl amsdu_ctrl;
-+	} ____cacheline_aligned_in_smp;
-+	struct mwl_tx_hist tx_hist;
-+	u32 tx_rate_info;
-+	u16 rx_format;
-+	u16 rx_nss;
-+	u16 rx_bw;
-+	u16 rx_gi;
-+	u16 rx_rate_mcs;
-+	u8 rx_signal;
-+	u16 iv16;
-+	u32 iv32;
-+};
-+
-+static inline struct mwl_vif *mwl_dev_get_vif(const struct ieee80211_vif *vif)
-+{
-+	return (struct mwl_vif *)&vif->drv_priv;
-+}
-+
-+static inline struct mwl_sta *mwl_dev_get_sta(const struct ieee80211_sta *sta)
-+{
-+	return (struct mwl_sta *)&sta->drv_priv;
-+}
-+
-+struct ieee80211_hw *mwl_alloc_hw(int bus_type,
-+				  int chip_type,
-+				  struct device *dev,
-+				  const struct mwl_hif_ops *ops,
-+				  size_t hif_data_len);
-+
-+void mwl_free_hw(struct ieee80211_hw *hw);
-+
-+int mwl_init_hw(struct ieee80211_hw *hw, const char *fw_name,
-+		const char *cal_name, const char *txpwrlmt_name);
-+
-+void mwl_deinit_hw(struct ieee80211_hw *hw);
-+
-+/* Defined in mac80211.c. */
-+extern const struct ieee80211_ops mwl_mac80211_ops;
-+
-+#endif /* _CORE_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/debugfs.c b/drivers/net/wireless/marvell/mwlwifi/debugfs.c
-new file mode 100644
-index 000000000000..e375806a7111
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/debugfs.c
-@@ -0,0 +1,2201 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements debug fs related functions. */
-+
-+#include <linux/debugfs.h>
-+#include <linux/etherdevice.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "thermal.h"
-+#include "hif/fwcmd.h"
-+#include "hif/hif-ops.h"
-+#include "debugfs.h"
-+
-+#define MWLWIFI_DEBUGFS_ADD_FILE(name) do { \
-+	if (!debugfs_create_file(#name, 0644, priv->debugfs_phy, \
-+				 priv, &mwl_debugfs_##name##_fops)) \
-+		return; \
-+} while (0)
-+
-+#define MWLWIFI_DEBUGFS_FILE_OPS(name) \
-+static const struct file_operations mwl_debugfs_##name##_fops = { \
-+	.read = mwl_debugfs_##name##_read, \
-+	.write = mwl_debugfs_##name##_write, \
-+	.open = simple_open, \
-+}
-+
-+#define MWLWIFI_DEBUGFS_FILE_READ_OPS(name) \
-+static const struct file_operations mwl_debugfs_##name##_fops = { \
-+	.read = mwl_debugfs_##name##_read, \
-+	.open = simple_open, \
-+}
-+
-+#define MWLWIFI_DEBUGFS_FILE_WRITE_OPS(name) \
-+static const struct file_operations mwl_debugfs_##name##_fops = { \
-+	.write = mwl_debugfs_##name##_write, \
-+	.open = simple_open, \
-+}
-+
-+static const char chipname[MWLUNKNOWN][8] = {
-+	"88W8864",
-+	"88W8897",
-+	"88W8964",
-+	"88W8997"
-+};
-+
-+static void dump_data(char *p, int size, int *len, u8 *data,
-+		      int data_len, char *title)
-+{
-+	int cur_byte = 0;
-+	int i;
-+
-+	*len += scnprintf(p + *len, size - *len, "%s\n", title);
-+
-+	for (cur_byte = 0; cur_byte < data_len; cur_byte += 8) {
-+		if ((cur_byte + 8) < data_len) {
-+			for (i = 0; i < 8; i++)
-+				*len += scnprintf(p + *len, size - *len,
-+						  "0x%02x ",
-+						  *(data + cur_byte + i));
-+			*len += scnprintf(p + *len, size - *len, "\n");
-+		} else {
-+			for (i = 0; i < (data_len - cur_byte); i++)
-+				*len += scnprintf(p + *len, size - *len,
-+						  "0x%02x ",
-+						  *(data + cur_byte + i));
-+			*len += scnprintf(p + *len, size - *len, "\n");
-+			break;
-+		}
-+	}
-+}
-+
-+static void _dump_tx_hist_mu(char *p, int size, int *len, bool *printed,
-+			     u32 *total, u8 nss, u8 bw, u8 mcs, u8 sgi,
-+			     struct mwl_sta *sta_info)
-+{
-+	char *bw_str[4] = {"ht20", "ht40", "ht80", "ht160"};
-+	char *sgi_str[2] = {"lgi", "sgi"};
-+	struct mwl_tx_hist_data *tx_hist_data;
-+	u32 cnt, rateinfo, per0, per1, per2, per3, per4, ratemask;
-+
-+	tx_hist_data = &sta_info->tx_hist.mu_rate[nss][bw][sgi][mcs];
-+	cnt = le32_to_cpu(tx_hist_data->cnt);
-+	rateinfo = le32_to_cpu(tx_hist_data->rateinfo);
-+	if (cnt && (rateinfo > 0)) {
-+		*total += cnt;
-+		per4 = le32_to_cpu(tx_hist_data->per[4]);
-+		per3 = le32_to_cpu(tx_hist_data->per[3]);
-+		per2 = le32_to_cpu(tx_hist_data->per[2]);
-+		per1 = le32_to_cpu(tx_hist_data->per[1]);
-+		per0 = le32_to_cpu(tx_hist_data->per[0]);
-+		if (!*printed) {
-+			*len += scnprintf(p + *len, size - *len,
-+				"%s %26s  <%2d %8s%2d%8s%2d%8s%2d%8s%2d\n",
-+				"MU_MIMO rate", " PER%", TX_HISTO_PER_THRES[0],
-+				">=", TX_HISTO_PER_THRES[0],
-+				">=", TX_HISTO_PER_THRES[1],
-+				">=", TX_HISTO_PER_THRES[2],
-+				">=", TX_HISTO_PER_THRES[3]);
-+			*len += scnprintf(p + *len, size - *len,
-+				"TOTAL MPDU tx pkt: %d\n",
-+				sta_info->tx_hist.total_tx_cnt[MU_MIMO]);
-+				*printed = true;
-+		}
-+		if ((rateinfo & 0x3) == 0)
-+			ratemask = 0xfff;
-+		else
-+			ratemask = 0xffff;
-+		if ((sta_info->tx_hist.cur_rate_info[MU_MIMO] & ratemask) ==
-+		    (rateinfo & ratemask))
-+			 /* mark as current rate */
-+			*len += scnprintf(p + *len, size - *len, "*");
-+		else
-+			*len += scnprintf(p + *len, size - *len, " ");
-+		*len += scnprintf(p + *len, size - *len,
-+			"%5s_%3s_%1dSS_MCS%2d: %10u, %9d, %9d, %9d, %9d, %9d\n",
-+			bw_str[bw], sgi_str[sgi], (nss + 1), mcs, cnt, per0,
-+			per1, per2, per3, per4);
-+	}
-+}
-+
-+static void dump_tx_hist_mu(char *p, int size, int *len, bool *printed,
-+			    u32 *total, struct mwl_sta *sta_info)
-+{
-+	u8 nss, bw, mcs, sgi;
-+
-+	for (nss = 0; nss < (QS_NUM_SUPPORTED_11AC_NSS - 1); nss++) {
-+		for (bw = 0; bw < QS_NUM_SUPPORTED_11AC_BW; bw++) {
-+			for (mcs = 0; mcs < QS_NUM_SUPPORTED_11AC_MCS; mcs++) {
-+				for (sgi = 0; sgi < QS_NUM_SUPPORTED_GI;
-+				     sgi++) {
-+					_dump_tx_hist_mu(p, size, len, printed,
-+							 total, nss, bw, mcs,
-+							 sgi, sta_info);
-+				}
-+			}
-+		}
-+	}
-+}
-+
-+
-+static void dump_tx_hist_su(char *p, int size, int *len, bool su, bool *printed,
-+			    u32 *total, struct mwl_sta *sta_info)
-+{
-+	int g_rate[14] = {1, 2, 5, 11, 22, 6, 9, 12, 18, 24, 36, 48, 54, 72};
-+	char *bw_str[4] = {"ht20", "ht40", "ht80", "ht160"};
-+	char *sgi_str[2] = {"lgi", "sgi"};
-+	char title_str[32];
-+	struct mwl_tx_hist *tx_hist;
-+	struct mwl_tx_hist_data *tx_hist_data;
-+	u32 j, loopcnt;
-+	u32 cnt, rateinfo, per0, per1, per2, per3, per4, ratemask;
-+	u8 format, bw, sgi, mcs, nss;
-+
-+	tx_hist = &sta_info->tx_hist;
-+	if (su) {
-+		loopcnt = MAX_SUPPORTED_RATES;
-+		tx_hist_data = &tx_hist->su_rate[0];
-+	} else {
-+		loopcnt = TX_RATE_HISTO_CUSTOM_CNT;
-+		tx_hist_data = &tx_hist->custom_rate[0];
-+	}
-+
-+	for (j = 0; j < loopcnt; j++) {
-+		cnt = le32_to_cpu(tx_hist_data[j].cnt);
-+		rateinfo = le32_to_cpu(tx_hist_data[j].rateinfo);
-+		if (cnt && (rateinfo > 0)) {
-+			*total += cnt;
-+			per4 = le32_to_cpu(tx_hist_data[j].per[4]);
-+			per3 = le32_to_cpu(tx_hist_data[j].per[3]);
-+			per2 = le32_to_cpu(tx_hist_data[j].per[2]);
-+			per1 = le32_to_cpu(tx_hist_data[j].per[1]);
-+			per0 = le32_to_cpu(tx_hist_data[j].per[0]);
-+			if (!*printed) {
-+				*len += scnprintf(p + *len, size - *len,
-+				"%s %26s  <%2d %8s%2d%8s%2d%8s%2d%8s%2d\n",
-+				su ? "SU_MIMO rate" : " Custom rate",
-+				" PER%", TX_HISTO_PER_THRES[0],
-+				">=", TX_HISTO_PER_THRES[0],
-+				">=", TX_HISTO_PER_THRES[1],
-+				">=", TX_HISTO_PER_THRES[2],
-+				">=", TX_HISTO_PER_THRES[3]);
-+			*len += scnprintf(p + *len, size - *len,
-+				"TOTAL MPDU tx pkt: %d\n",
-+				tx_hist->total_tx_cnt[SU_MIMO]);
-+				*printed = true;
-+			}
-+			format = rateinfo & MWL_TX_RATE_FORMAT_MASK;
-+			bw = (rateinfo & MWL_TX_RATE_BANDWIDTH_MASK) >>
-+				MWL_TX_RATE_BANDWIDTH_SHIFT;
-+			sgi = (rateinfo & MWL_TX_RATE_SHORTGI_MASK) >>
-+				MWL_TX_RATE_SHORTGI_SHIFT;
-+			mcs = (rateinfo & MWL_TX_RATE_RATEIDMCS_MASK) >>
-+				MWL_TX_RATE_RATEIDMCS_SHIFT;
-+			if (format == TX_RATE_FORMAT_LEGACY)
-+				ratemask = 0xfff;
-+			else
-+				ratemask = 0xffff;
-+			if ((tx_hist->cur_rate_info[SU_MIMO] & ratemask) ==
-+			    (rateinfo & ratemask))
-+				/* mark as current rate */
-+				*len += scnprintf(p + *len, size - *len, "*");
-+			else
-+				*len += scnprintf(p + *len, size - *len, " ");
-+			if (format == TX_RATE_FORMAT_LEGACY) {
-+				if (mcs == 2) {
-+					*len += scnprintf(p + *len, size - *len,
-+					"%s %10u, %9d, %9d, %9d, %9d, %9d\n",
-+					"5.5Mbps             :", cnt, per0,
-+					per1, per2, per3, per4);
-+				} else {
-+					sprintf(title_str,
-+						"%-3dMbps             :",
-+						g_rate[mcs]);
-+					*len += scnprintf(p + *len, size - *len,
-+					"%s %10u, %9d, %9d, %9d, %9d, %9d\n",
-+					title_str, cnt, per0, per1, per2, per3,
-+					per4);
-+				}
-+			} else if (format ==  TX_RATE_FORMAT_11N) {
-+				sprintf(title_str, "%4s_%3s_MCS%2d	    :",
-+					bw_str[bw], sgi_str[sgi], mcs);
-+				*len += scnprintf(p + *len, size - *len,
-+					"%s %10u, %9d, %9d, %9d, %9d, %9d\n",
-+					title_str, cnt, per0, per1, per2, per3,
-+					per4);
-+			} else {
-+				nss = (mcs >> 4);
-+				sprintf(title_str, "%5s_%3s_%1dSS_MCS%2d :",
-+					bw_str[bw], sgi_str[sgi], (nss+1),
-+					(mcs & 0xf));
-+				*len += scnprintf(p + *len, size - *len,
-+					"%s %10u, %9d, %9d, %9d, %9d, %9d\n",
-+					title_str, cnt, per0, per1, per2, per3,
-+					per4);
-+			}
-+		}
-+	}
-+}
-+
-+static void dump_tx_hist(char *p, int size, int *len, struct mwl_sta *sta_info)
-+{
-+	int type;
-+	bool printed, su;
-+	u32 total;
-+
-+	for (type = 0; type <= SU_MU_TYPE_CNT; type++) {
-+		printed = false;
-+		total = 0;
-+		if (type == MU_MIMO) {
-+			dump_tx_hist_mu(p, size, len, &printed,
-+					&total, sta_info);
-+		} else {
-+			su = (type == SU_MIMO) ? true : false;
-+			dump_tx_hist_su(p, size, len, su, &printed,
-+					&total, sta_info);
-+		}
-+		if (printed)
-+			*len += scnprintf(p + *len, size - *len,
-+					  "  TOTAL              : %10u\n\n",
-+					  total);
-+	}
-+}
-+
-+static void core_dump_file(u8 *valbuf, u32 length, u32 region, u32 address,
-+			   u32 append, u32 totallen, bool textmode)
-+{
-+	struct file *filp_core = NULL;
-+	char file_name[40];
-+	u8 *buf = kmalloc(length * 3, GFP_KERNEL);
-+	u8 *data_p = buf;
-+	u32 i, j = 0;
-+
-+	if (!buf)
-+		return;
-+
-+	memset(file_name, 0, sizeof(file_name));
-+	sprintf(file_name, "/dev/shm/coredump-%x-%x",
-+		region, (region + totallen));
-+
-+	if (append)
-+		filp_core = filp_open(file_name, O_RDWR | O_APPEND, 0);
-+	else
-+		filp_core = filp_open(file_name, O_RDWR | O_CREAT | O_TRUNC, 0);
-+
-+	if (!IS_ERR(filp_core)) {
-+		if (textmode) {
-+			for (i = 0; i < length; i += 4) {
-+				u32 val = 0;
-+
-+				val = le32_to_cpu(*(__le32 *)(&valbuf[i]));
-+
-+				if (i % 16 == 0) {
-+					sprintf(buf + j, "\n0x%08x",
-+						(int)(address + i));
-+					j = strlen(buf);
-+				}
-+				sprintf(buf + j, "  %08x", val);
-+				j = strlen(buf);
-+			}
-+			data_p = buf + j;
-+			data_p += sprintf(data_p, "\n");
-+			__kernel_write(filp_core, buf, strlen(buf),
-+				       &filp_core->f_pos);
-+		} else
-+			__kernel_write(filp_core, valbuf, length,
-+				       &filp_core->f_pos);
-+
-+		filp_close(filp_core, current->files);
-+	}
-+
-+	kfree(buf);
-+}
-+
-+static ssize_t mwl_debugfs_info_read(struct file *file, char __user *ubuf,
-+				     size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	int tx_num = 4, rx_num = 4;
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len,
-+			 "driver name: %s\n",
-+			 mwl_hif_get_driver_name(priv->hw));
-+	len += scnprintf(p + len, size - len, "chip type: %s\n",
-+			 chipname[priv->chip_type]);
-+	len += scnprintf(p + len, size - len,
-+			 "hw version: %X\n", priv->hw_data.hw_version);
-+	len += scnprintf(p + len, size - len,
-+			 "driver version: %s\n",
-+			 mwl_hif_get_driver_version(priv->hw));
-+	len += scnprintf(p + len, size - len, "firmware version: 0x%08x\n",
-+			 priv->hw_data.fw_release_num);
-+	len += scnprintf(p + len, size - len,
-+			 "power table loaded from dts: %s\n",
-+			 priv->forbidden_setting ? "no" : "yes");
-+	len += scnprintf(p + len, size - len, "firmware region code: 0x%x\n",
-+			 priv->fw_region_code);
-+	len += scnprintf(p + len, size - len,
-+			 "mac address: %pM\n", priv->hw_data.mac_addr);
-+	len += scnprintf(p + len, size - len,
-+			 "2g: %s\n", priv->disable_2g ? "disable" : "enable");
-+	len += scnprintf(p + len, size - len,
-+			 "5g: %s\n", priv->disable_5g ? "disable" : "enable");
-+	if (priv->antenna_tx == ANTENNA_TX_2)
-+		tx_num = 2;
-+	else if (priv->antenna_tx == ANTENNA_TX_3)
-+		tx_num = 3;
-+	if (priv->antenna_rx == ANTENNA_RX_2)
-+		rx_num = 2;
-+	else if (priv->antenna_rx == ANTENNA_RX_3)
-+		rx_num = 3;
-+	len += scnprintf(p + len, size - len, "antenna: %d %d\n",
-+			 tx_num, rx_num);
-+	len += scnprintf(p + len, size - len, "irq number: %d\n", priv->irq);
-+	len += scnprintf(p + len, size - len, "ap macid support: %08x\n",
-+			 priv->ap_macids_supported);
-+	len += scnprintf(p + len, size - len, "sta macid support: %08x\n",
-+			 priv->sta_macids_supported);
-+	len += scnprintf(p + len, size - len,
-+			 "macid used: %08x\n", priv->macids_used);
-+	len += scnprintf(p + len, size - len,
-+			 "radio: %s\n", priv->radio_on ? "enable" : "disable");
-+	len += mwl_hif_get_info(priv->hw, p + len, size - len);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_tx_status_read(struct file *file, char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += mwl_hif_get_tx_status(priv->hw, p + len, size - len);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_rx_status_read(struct file *file, char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += mwl_hif_get_rx_status(priv->hw, p + len, size - len);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_vif_read(struct file *file, char __user *ubuf,
-+				    size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct mwl_vif *mwl_vif;
-+	struct ieee80211_vif *vif;
-+	char ssid[IEEE80211_MAX_SSID_LEN + 1];
-+	struct cfg80211_chan_def *chan_def;
-+	struct beacon_info *beacon_info;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	spin_lock_bh(&priv->vif_lock);
-+	list_for_each_entry(mwl_vif, &priv->vif_list, list) {
-+		vif = container_of((void *)mwl_vif, struct ieee80211_vif,
-+				   drv_priv);
-+		len += scnprintf(p + len, size - len,
-+				 "macid: %d\n", mwl_vif->macid);
-+		switch (vif->type) {
-+		case NL80211_IFTYPE_AP:
-+			len += scnprintf(p + len, size - len, "type: ap\n");
-+			memcpy(ssid, vif->bss_conf.ssid,
-+			       vif->bss_conf.ssid_len);
-+			ssid[vif->bss_conf.ssid_len] = 0;
-+			len += scnprintf(p + len, size - len,
-+					 "ssid: %s\n", ssid);
-+			len += scnprintf(p + len, size - len,
-+					 "mac address: %pM\n", mwl_vif->bssid);
-+			break;
-+		case NL80211_IFTYPE_MESH_POINT:
-+			len += scnprintf(p + len, size - len, "type: mesh\n");
-+			len += scnprintf(p + len, size - len,
-+					 "mac address: %pM\n", mwl_vif->bssid);
-+			break;
-+		case NL80211_IFTYPE_STATION:
-+			len += scnprintf(p + len, size - len, "type: sta\n");
-+			len += scnprintf(p + len, size - len,
-+					 "mac address: %pM\n",
-+					 mwl_vif->sta_mac);
-+			break;
-+		default:
-+			len += scnprintf(p + len, size - len,
-+					 "type: unknown\n");
-+			break;
-+		}
-+		if (vif->chanctx_conf) {
-+			chan_def = &vif->chanctx_conf->def;
-+			len += scnprintf(p + len, size - len,
-+					 "channel: %d: width: %d\n",
-+					 chan_def->chan->hw_value,
-+					 chan_def->width);
-+			len += scnprintf(p + len, size - len,
-+					 "freq: %d freq1: %d freq2: %d\n",
-+					 chan_def->chan->center_freq,
-+					 chan_def->center_freq1,
-+					 chan_def->center_freq2);
-+		}
-+		len += scnprintf(p + len, size - len, "hw_crypto_enabled: %s\n",
-+				 mwl_vif->is_hw_crypto_enabled ?
-+				 "true" : "false");
-+		len += scnprintf(p + len, size - len,
-+				 "key idx: %d\n", mwl_vif->keyidx);
-+		len += scnprintf(p + len, size - len,
-+				 "IV: %08x%04x\n", mwl_vif->iv32,
-+				 mwl_vif->iv16);
-+		beacon_info = &mwl_vif->beacon_info;
-+		dump_data(p, size, &len, beacon_info->ie_wmm_ptr,
-+			  beacon_info->ie_wmm_len, "WMM:");
-+		dump_data(p, size, &len, beacon_info->ie_rsn_ptr,
-+			  beacon_info->ie_rsn_len, "RSN:");
-+		dump_data(p, size, &len, beacon_info->ie_rsn48_ptr,
-+			  beacon_info->ie_rsn48_len, "RSN48:");
-+		dump_data(p, size, &len, beacon_info->ie_mde_ptr,
-+			  beacon_info->ie_mde_len, "MDE:");
-+		dump_data(p, size, &len, beacon_info->ie_ht_ptr,
-+			  beacon_info->ie_ht_len, "HT:");
-+		dump_data(p, size, &len, beacon_info->ie_vht_ptr,
-+			  beacon_info->ie_vht_len, "VHT:");
-+		if (vif->type == NL80211_IFTYPE_MESH_POINT) {
-+			dump_data(p, size, &len, beacon_info->ie_meshid_ptr,
-+				  beacon_info->ie_meshid_len, "MESHID:");
-+			dump_data(p, size, &len, beacon_info->ie_meshcfg_ptr,
-+				  beacon_info->ie_meshcfg_len, "MESHCFG:");
-+			dump_data(p, size, &len, beacon_info->ie_meshchsw_ptr,
-+				  beacon_info->ie_meshchsw_len, "MESHCHSW:");
-+		}
-+		len += scnprintf(p + len, size - len, "\n");
-+	}
-+	spin_unlock_bh(&priv->vif_lock);
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_sta_read(struct file *file, char __user *ubuf,
-+				    size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv);
-+		len += scnprintf(p + len, size - len,
-+				 "mac address: %pM\n", sta->addr);
-+		len += scnprintf(p + len, size - len, "aid: %u\n", sta->aid);
-+		len += scnprintf(p + len, size - len, "ampdu: %s\n",
-+				 sta_info->is_ampdu_allowed ? "true" : "false");
-+		len += scnprintf(p + len, size - len, "amsdu: %s\n",
-+				 sta_info->is_amsdu_allowed ? "true" : "false");
-+		len += scnprintf(p + len, size - len, "wds: %s\n",
-+				 sta_info->wds ? "true" : "false");
-+		len += scnprintf(p + len, size - len, "ba_hist: %s\n",
-+				 sta_info->ba_hist.enable ?
-+				 "enable" : "disable");
-+		if (sta_info->is_amsdu_allowed) {
-+			len += scnprintf(p + len, size - len,
-+					 "amsdu cap: 0x%02x\n",
-+					 sta_info->amsdu_ctrl.cap);
-+		}
-+		if (sta->ht_cap.ht_supported) {
-+			len += scnprintf(p + len, size - len,
-+					 "ht_cap: 0x%04x, ampdu: %02x, %02x\n",
-+					 sta->ht_cap.cap,
-+					 sta->ht_cap.ampdu_factor,
-+					 sta->ht_cap.ampdu_density);
-+			len += scnprintf(p + len, size - len,
-+					 "rx_mask: 0x%02x, %02x, %02x, %02x\n",
-+					 sta->ht_cap.mcs.rx_mask[0],
-+					 sta->ht_cap.mcs.rx_mask[1],
-+					 sta->ht_cap.mcs.rx_mask[2],
-+					 sta->ht_cap.mcs.rx_mask[3]);
-+		}
-+		if (sta->vht_cap.vht_supported) {
-+			len += scnprintf(p + len, size - len,
-+					 "vht_cap: 0x%08x, mcs: %02x, %02x\n",
-+					 sta->vht_cap.cap,
-+					 sta->vht_cap.vht_mcs.rx_mcs_map,
-+					 sta->vht_cap.vht_mcs.tx_mcs_map);
-+		}
-+		len += scnprintf(p + len, size - len, "rx_bw: %d, rx_nss: %d\n",
-+				 sta->bandwidth, sta->rx_nss);
-+		len += scnprintf(p + len, size - len,
-+				 "tdls: %d, tdls_init: %d\n",
-+				 sta->tdls, sta->tdls_initiator);
-+		len += scnprintf(p + len, size - len, "wme: %d, mfp: %d\n",
-+				 sta->wme, sta->mfp);
-+		len += scnprintf(p + len, size - len, "IV: %08x%04x\n",
-+				 sta_info->iv32, sta_info->iv16);
-+		len += scnprintf(p + len, size - len, "\n");
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_ampdu_read(struct file *file, char __user *ubuf,
-+				      size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct mwl_ampdu_stream *stream;
-+	int i;
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	spin_lock_bh(&priv->stream_lock);
-+	for (i = 0; i < priv->ampdu_num; i++) {
-+		stream = &priv->ampdu[i];
-+		if (!stream->state)
-+			continue;
-+		len += scnprintf(p + len, size - len, "stream: %d\n", i);
-+		len += scnprintf(p + len, size - len, "idx: %u\n", stream->idx);
-+		len += scnprintf(p + len, size - len,
-+				 "state: %u\n", stream->state);
-+		if (stream->sta) {
-+			len += scnprintf(p + len, size - len,
-+					 "mac address: %pM\n",
-+					 stream->sta->addr);
-+			len += scnprintf(p + len, size - len,
-+					 "tid: %u\n", stream->tid);
-+		}
-+	}
-+	spin_unlock_bh(&priv->stream_lock);
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		for (i = 0; i < MWL_MAX_TID; i++) {
-+			if (sta_info->check_ba_failed[i]) {
-+				sta = container_of((void *)sta_info,
-+						   struct ieee80211_sta,
-+						   drv_priv);
-+				len += scnprintf(p + len, size - len,
-+						 "%pM(%d): %d\n",
-+						 sta->addr, i,
-+						 sta_info->check_ba_failed[i]);
-+			}
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_stnid_read(struct file *file, char __user *ubuf,
-+				      size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct mwl_stnid *stnid;
-+	int i;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	spin_lock_bh(&priv->stnid_lock);
-+	for (i = 0; i < priv->stnid_num; i++) {
-+		stnid = &priv->stnid[i];
-+		if (!stnid->aid)
-+			continue;
-+		len += scnprintf(p + len, size - len,
-+				 "stnid: %d macid: %d aid: %d\n",
-+				 i + 1, stnid->macid, stnid->aid);
-+	}
-+	spin_unlock_bh(&priv->stnid_lock);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_device_pwrtbl_read(struct file *file,
-+					      char __user *ubuf,
-+					      size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	int i, j;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len,
-+			 "power table loaded from dts: %s\n",
-+			 priv->forbidden_setting ? "no" : "yes");
-+	len += scnprintf(p + len, size - len, "firmware region code: 0x%x\n",
-+			 priv->fw_region_code);
-+	len += scnprintf(p + len, size - len, "number of channel: %d\n",
-+			 priv->number_of_channels);
-+	for (i = 0; i < priv->number_of_channels; i++) {
-+		len += scnprintf(p + len, size - len, "%3d ",
-+				 priv->device_pwr_tbl[i].channel);
-+		for (j = 0; j < SYSADPT_TX_POWER_LEVEL_TOTAL; j++)
-+			len += scnprintf(p + len, size - len, "%3d ",
-+					 priv->device_pwr_tbl[i].tx_pwr[j]);
-+		len += scnprintf(p + len, size - len, "%3d ",
-+				 priv->device_pwr_tbl[i].dfs_capable);
-+		len += scnprintf(p + len, size - len, "%3d ",
-+				 priv->device_pwr_tbl[i].ax_ant);
-+		len += scnprintf(p + len, size - len, "%3d\n",
-+				 priv->device_pwr_tbl[i].cdd);
-+	}
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_txpwrlmt_read(struct file *file,
-+					 char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+
-+	return simple_read_from_buffer(ubuf, count, ppos,
-+				       priv->txpwrlmt_data.buf,
-+				       priv->txpwrlmt_data.len);
-+}
-+
-+static ssize_t mwl_debugfs_tx_amsdu_read(struct file *file,
-+					 char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "tx amsdu: %s\n",
-+			 priv->tx_amsdu ? "enable" : "disable");
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_tx_amsdu_write(struct file *file,
-+					  const char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int value;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &value)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	priv->tx_amsdu = value ? true : false;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dump_hostcmd_read(struct file *file,
-+					     char __user *ubuf,
-+					     size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "dump_hostcmd: %s\n",
-+			 priv->dump_hostcmd ? "enable" : "disable");
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dump_hostcmd_write(struct file *file,
-+					      const char __user *ubuf,
-+					      size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int value;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &value)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	priv->dump_hostcmd = value ? true : false;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dump_probe_read(struct file *file,
-+					   char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "dump_probe: %s\n",
-+			 priv->dump_probe ? "enable" : "disable");
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dump_probe_write(struct file *file,
-+					    const char __user *ubuf,
-+					    size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int value;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &value)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	priv->dump_probe = value ? true : false;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_heartbeat_read(struct file *file,
-+					  char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "heartbeat: %d\n",
-+			 priv->heartbeat);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_heartbeat_write(struct file *file,
-+					   const char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &priv->heartbeat)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+	priv->pre_jiffies = jiffies;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dfs_test_read(struct file *file,
-+					 char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "dfs_test: %s\n",
-+			 priv->dfs_test ? "enable" : "disable");
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dfs_test_write(struct file *file,
-+					  const char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int value;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &value)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	priv->dfs_test = value ? true : false;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dfs_channel_read(struct file *file,
-+					    char __user *ubuf,
-+					    size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct ieee80211_supported_band *sband;
-+	struct ieee80211_channel *channel;
-+	int i;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	sband = priv->hw->wiphy->bands[NL80211_BAND_5GHZ];
-+	if (!sband) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	for (i = 0; i < sband->n_channels; i++) {
-+		channel = &sband->channels[i];
-+		if (channel->flags & IEEE80211_CHAN_RADAR) {
-+			len += scnprintf(p + len, size - len,
-+					 "%d(%d): flags: %08x dfs_state: %d\n",
-+					 channel->hw_value,
-+					 channel->center_freq,
-+					 channel->flags, channel->dfs_state);
-+			len += scnprintf(p + len, size - len,
-+					 "cac timer: %d ms\n",
-+					 channel->dfs_cac_ms);
-+		}
-+	}
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+
-+err:
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dfs_channel_write(struct file *file,
-+					     const char __user *ubuf,
-+					     size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	struct ieee80211_supported_band *sband;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int dfs_state = 0;
-+	int cac_time = -1;
-+	struct ieee80211_channel *channel;
-+	int i;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	sband = priv->hw->wiphy->bands[NL80211_BAND_5GHZ];
-+	if (!sband) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	ret = sscanf(buf, "%d %d", &dfs_state, &cac_time);
-+
-+	if ((ret < 1) || (ret > 2)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	for (i = 0; i < sband->n_channels; i++) {
-+		channel = &sband->channels[i];
-+		if (channel->flags & IEEE80211_CHAN_RADAR) {
-+			channel->dfs_state = dfs_state;
-+			if (cac_time != -1)
-+				channel->dfs_cac_ms = cac_time * 1000;
-+		}
-+	}
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dfs_radar_read(struct file *file, char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len,
-+			 "csa_active: %d\n", priv->csa_active);
-+	len += scnprintf(p + len, size - len,
-+			 "dfs_region: %d\n", priv->dfs_region);
-+	len += scnprintf(p + len, size - len,
-+			 "chirp_count_min: %d\n", priv->dfs_chirp_count_min);
-+	len += scnprintf(p + len, size - len, "chirp_time_interval: %d\n",
-+			 priv->dfs_chirp_time_interval);
-+	len += scnprintf(p + len, size - len,
-+			 "pw_filter: %d\n", priv->dfs_pw_filter);
-+	len += scnprintf(p + len, size - len,
-+			 "min_num_radar: %d\n", priv->dfs_min_num_radar);
-+	len += scnprintf(p + len, size - len,
-+			 "min_pri_count: %d\n", priv->dfs_min_pri_count);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_dfs_radar_write(struct file *file,
-+					   const char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+
-+	wiphy_info(priv->hw->wiphy, "simulate radar detected\n");
-+	ieee80211_radar_detected(priv->hw);
-+
-+	return count;
-+}
-+
-+static ssize_t mwl_debugfs_thermal_read(struct file *file,
-+					char __user *ubuf,
-+					size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	mwl_fwcmd_get_temp(priv->hw, &priv->temperature);
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "quiet period: %d\n",
-+			 priv->quiet_period);
-+	len += scnprintf(p + len, size - len, "throttle state: %d\n",
-+			 priv->throttle_state);
-+	len += scnprintf(p + len, size - len, "temperature: %d\n",
-+			 priv->temperature);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_thermal_write(struct file *file,
-+					 const char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int throttle_state;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &throttle_state)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if (throttle_state > SYSADPT_THERMAL_THROTTLE_MAX) {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "throttle state %d is exceeding the limit %d\n",
-+			   throttle_state, SYSADPT_THERMAL_THROTTLE_MAX);
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	priv->throttle_state = throttle_state;
-+	mwl_thermal_set_throttling(priv);
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_led_ctrl_read(struct file *file,
-+					 char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "led blink %s\n",
-+			 priv->led_blink_enable ? "enable" : "disable");
-+	len += scnprintf(p + len, size - len, "led blink rate: %d\n",
-+			 priv->led_blink_rate);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_led_ctrl_write(struct file *file,
-+					  const char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int enable, rate;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	ret = sscanf(buf, "%x %x", &enable, &rate);
-+
-+	if ((ret != 1) && (ret != 2)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if (enable && (ret != 2)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	ret = mwl_fwcmd_led_ctrl(priv->hw, enable, rate);
-+
-+	if (ret)
-+		goto err;
-+
-+	priv->led_blink_enable = enable;
-+	if (enable)
-+		priv->led_blink_rate = rate;
-+	else
-+		priv->led_blink_rate = 0;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_regrdwr_read(struct file *file, char __user *ubuf,
-+					size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (*ppos)
-+		return len;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	if (!priv->reg_type) {
-+		/* No command has been given */
-+		len += scnprintf(p + len, size - len, "0");
-+		ret = -EINVAL;
-+		goto none;
-+	}
-+
-+	/* Set command has been given */
-+	if (priv->reg_value != UINT_MAX) {
-+		ret = mwl_hif_reg_access(priv->hw, true);
-+		goto done;
-+	}
-+	/* Get command has been given */
-+	ret = mwl_hif_reg_access(priv->hw, false);
-+
-+done:
-+	if (!ret)
-+		len += scnprintf(p + len, size - len, "%u 0x%08x 0x%08x\n",
-+				 priv->reg_type, priv->reg_offset,
-+				 priv->reg_value);
-+	else
-+		len += scnprintf(p + len, size - len,
-+				 "error: %d(%u 0x%08x 0x%08x)\n",
-+				 ret, priv->reg_type, priv->reg_offset,
-+				 priv->reg_value);
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+
-+none:
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_regrdwr_write(struct file *file,
-+					 const char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	ssize_t ret;
-+	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	ret = sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
-+
-+	if (!reg_type) {
-+		ret = -EINVAL;
-+		goto err;
-+	} else {
-+		priv->reg_type = reg_type;
-+		priv->reg_offset = reg_offset;
-+		priv->reg_value = reg_value;
-+		ret = count;
-+	}
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_ratetable_read(struct file *file, char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+	u8 addr[ETH_ALEN];
-+	int table_size = (sizeof(__le32) * 2 * SYSADPT_MAX_RATE_ADAPT_RATES);
-+	u8 *rate_table, *rate_idx;
-+	u32 rate_info;
-+	u8 fmt, stbc, bw, sgi, mcs, preamble_gf, power_id, ldpc, bf, ant;
-+	int idx, rate, nss;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	if (!priv->ra_aid) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv);
-+		if (priv->ra_aid == sta->aid) {
-+			ether_addr_copy(addr, sta->addr);
-+			break;
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	rate_table = kzalloc(size, GFP_KERNEL);
-+	if (!rate_table) {
-+		ret = -ENOMEM;
-+		goto err;
-+	}
-+
-+	ret = mwl_fwcmd_get_ratetable(priv->hw, addr, rate_table,
-+				      table_size, 0);
-+	if (ret) {
-+		kfree(rate_table);
-+		goto err;
-+	}
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len,
-+		"%3s %6s %5s %5s %5s %5s %5s %4s %2s %5s %4s %5s %5s\n",
-+		"Num", "Fmt", "STBC", "BW", "SGI", "Nss", "RateId",
-+		"GF/Pre", "PId", "LDPC", "BF", "TxAnt", "Rate");
-+	idx = 0;
-+	rate_idx = rate_table;
-+	rate_info = le32_to_cpu(*(__le32 *)rate_idx);
-+	while (rate_info) {
-+		fmt = rate_info & MWL_TX_RATE_FORMAT_MASK;
-+		stbc = (rate_info & MWL_TX_RATE_STBC_MASK) >>
-+			MWL_TX_RATE_STBC_SHIFT;
-+		bw = (rate_info & MWL_TX_RATE_BANDWIDTH_MASK) >>
-+			MWL_TX_RATE_BANDWIDTH_SHIFT;
-+		sgi = (rate_info & MWL_TX_RATE_SHORTGI_MASK) >>
-+			MWL_TX_RATE_SHORTGI_SHIFT;
-+		mcs = (rate_info & MWL_TX_RATE_RATEIDMCS_MASK) >>
-+			MWL_TX_RATE_RATEIDMCS_SHIFT;
-+		preamble_gf = (rate_info & MWL_TX_RATE_PREAMBLE_MASK) >>
-+			MWL_TX_RATE_PREAMBLE_SHIFT;
-+		power_id = (rate_info & MWL_TX_RATE_POWERID_MASK) >>
-+			MWL_TX_RATE_POWERID_SHIFT;
-+		ldpc = (rate_info & MWL_TX_RATE_ADVCODING_MASK) >>
-+			MWL_TX_RATE_ADVCODING_SHIFT;
-+		bf = (rate_info & MWL_TX_RATE_BF_MASK) >>
-+			MWL_TX_RATE_BF_SHIFT;
-+		ant = (rate_info & MWL_TX_RATE_ANTSELECT_MASK) >>
-+			MWL_TX_RATE_ANTSELECT_SHIFT;
-+
-+		if (fmt == TX_RATE_FORMAT_11AC) {
-+			rate = mcs & 0xf; /* 11ac, mcs[3:0]: rate      */
-+			nss = mcs >> 4;   /* 11ac, mcs[6:4] = nss code */
-+			nss++;  /* ddd 1 to correct Nss representation */
-+		} else {
-+			rate = mcs;
-+			nss = 0;
-+			if (fmt == TX_RATE_FORMAT_11N) {
-+				if ((mcs >= 0) && (mcs < 8))
-+					nss = 1;
-+				else if ((mcs >= 8) && (mcs < 16))
-+					nss = 2;
-+				else if ((mcs >= 16) && (mcs < 24))
-+					nss = 3;
-+			}
-+		}
-+
-+		len += scnprintf(p + len, size - len,
-+			"%3d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
-+			idx, (int)fmt, (int)stbc, (int)bw, (int)sgi, nss, rate,
-+			(int)preamble_gf, (int)power_id, (int)ldpc, (int)bf,
-+			(int)ant,
-+			utils_get_phy_rate(fmt, bw, sgi, mcs));
-+
-+		idx++;
-+		rate_idx += (2 * sizeof(__le32));
-+		rate_info = le32_to_cpu(*(__le32 *)rate_idx);
-+	}
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	kfree(rate_table);
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+
-+err:
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_ratetable_write(struct file *file,
-+					   const char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int sta_aid;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &sta_aid)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if ((sta_aid <= 0) || (sta_aid > SYSADPT_MAX_STA_SC4)) {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "station aid is exceeding the limit %d\n", sta_aid);
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	priv->ra_aid = sta_aid;
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_tx_hist_read(struct file *file, char __user *ubuf,
-+					size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct ieee80211_sta *sta;
-+	struct mwl_sta *sta_info;
-+	ssize_t ret;
-+
-+	if (priv->chip_type != MWL8964)
-+		return -EPERM;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len,
-+			 "SU: <4:%d >=4:%d >=15:%d >=50:%d >=100:%d >=250:%d\n",
-+			 priv->ra_tx_attempt[SU_MIMO][0],
-+			 priv->ra_tx_attempt[SU_MIMO][1],
-+			 priv->ra_tx_attempt[SU_MIMO][2],
-+			 priv->ra_tx_attempt[SU_MIMO][3],
-+			 priv->ra_tx_attempt[SU_MIMO][4],
-+			 priv->ra_tx_attempt[SU_MIMO][5]);
-+	len += scnprintf(p + len, size - len,
-+			 "MU: <4:%d >=4:%d >=15:%d >=50:%d >=100:%d >=250:%d\n",
-+			 priv->ra_tx_attempt[MU_MIMO][0],
-+			 priv->ra_tx_attempt[MU_MIMO][1],
-+			 priv->ra_tx_attempt[MU_MIMO][2],
-+			 priv->ra_tx_attempt[MU_MIMO][3],
-+			 priv->ra_tx_attempt[MU_MIMO][4],
-+			 priv->ra_tx_attempt[MU_MIMO][5]);
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv);
-+		len += scnprintf(p + len, size - len, "\nSTA %pM\n", sta->addr);
-+		len += scnprintf(p + len, size - len,
-+				 "============================\n");
-+		dump_tx_hist(p, size, &len, sta_info);
-+		len += scnprintf(p + len, size - len,
-+				 "============================\n");
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_tx_hist_write(struct file *file,
-+					 const char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int reset;
-+	struct mwl_sta *sta_info;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &reset)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if (!reset) {
-+		memset(&priv->ra_tx_attempt, 0, 2 * 6 * sizeof(u32));
-+		spin_lock_bh(&priv->sta_lock);
-+		list_for_each_entry(sta_info, &priv->sta_list, list) {
-+			memset(&sta_info->tx_hist, 0,
-+			       sizeof(sta_info->tx_hist));
-+		}
-+		spin_unlock_bh(&priv->sta_lock);
-+	}
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_ba_hist_read(struct file *file, char __user *ubuf,
-+					size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct mwl_sta *sta_info;
-+	struct mwl_tx_ba_stats *ba_stats;
-+	u32 i, data;
-+	u32 baholecnt, baexpcnt, bmap0cnt, nobacnt;
-+	u8 bmap0flag, nobaflag;
-+	char buff[500], file_location[20];
-+	struct file *filp_bahisto;
-+	u8 *data_p = buff;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	if (!priv->ba_aid) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	memset(buff, 0, sizeof(buff));
-+	memset(file_location, 0, sizeof(file_location));
-+	sprintf(file_location, "/tmp/ba_histo-%d", priv->ba_aid);
-+
-+	filp_bahisto = filp_open(file_location,
-+				 O_RDWR | O_CREAT | O_TRUNC, 0);
-+
-+	if (IS_ERR(filp_bahisto)) {
-+		ret = -EIO;
-+		goto err;
-+	}
-+
-+	sta_info = utils_find_sta_by_aid(priv, priv->ba_aid);
-+	if (sta_info && sta_info->ba_hist.enable &&
-+	    sta_info->ba_hist.ba_stats) {
-+		ba_stats = sta_info->ba_hist.ba_stats;
-+		len += scnprintf(p + len, size - len,
-+				 "BA histogram aid: %d, stnid: %d type: %s\n",
-+				 priv->ba_aid, sta_info->stnid,
-+				 sta_info->ba_hist.type ? "MU" : "SU");
-+		data_p += sprintf(data_p,
-+				  "BA histogram aid: %d, stnid: %d type: %s\n",
-+				  priv->ba_aid, sta_info->stnid,
-+				  sta_info->ba_hist.type ? "MU" : "SU");
-+		data_p += sprintf(data_p, "%8s,%8s,%8s,%8s\n",
-+				  "BAhole", "Expect", "Bmap0", "NoBA");
-+		data = *(u32 *)&ba_stats[0];
-+		baholecnt = 0;
-+		baexpcnt = 0;
-+		bmap0cnt = 0;
-+		nobacnt = 0;
-+		for (i = 0; i < ACNT_BA_SIZE && data; i++) {
-+			data = *(u32 *)&ba_stats[i];
-+			if (data == 0)
-+				break;
-+
-+			/* If no BA event does not happen, check BA hole and BA
-+			 * expected to mark BA bitmap all 0 event
-+			 */
-+			if (!ba_stats[i].no_ba)
-+				bmap0flag = (ba_stats[i].ba_hole ==
-+					     ba_stats[i].ba_expected) ? 1 : 0;
-+			else
-+				bmap0flag = 0;
-+			nobaflag = ba_stats[i].no_ba;
-+
-+			/* Buffer is full. Write to file and reset buf */
-+			if ((strlen(buff) + 36) >= 500) {
-+				__kernel_write(filp_bahisto, buff, strlen(buff),
-+					       &filp_bahisto->f_pos);
-+				mdelay(2);
-+				memset(buff, 0, sizeof(buff));
-+				data_p = buff;
-+			}
-+
-+			data_p += sprintf(data_p, "%8d,%8d,",
-+					  ba_stats[i].ba_hole,
-+					  ba_stats[i].ba_expected);
-+
-+			baholecnt += ba_stats[i].ba_hole;
-+			baexpcnt += ba_stats[i].ba_expected;
-+			if (bmap0flag) {
-+				data_p += sprintf(data_p, "       #,");
-+				bmap0cnt++;
-+			} else
-+				data_p += sprintf(data_p, "%8d,", bmap0flag);
-+			if (nobaflag) {
-+				data_p += sprintf(data_p, "       *\n");
-+				nobacnt++;
-+			} else
-+				data_p += sprintf(data_p, "%8d\n", nobaflag);
-+		}
-+
-+		__kernel_write(filp_bahisto, buff, strlen(buff),
-+			       &filp_bahisto->f_pos);
-+		len += scnprintf(p + len, size - len,
-+				 "hole: %d, expect: %d, bmap0: %d, noba: %d\n",
-+				 baholecnt, baexpcnt, bmap0cnt, nobacnt);
-+		len += scnprintf(p + len, size - len,
-+				 "BA histogram data written to %s\n",
-+				 file_location);
-+	} else
-+		len += scnprintf(p + len, size - len,
-+				 "No BA histogram for sta aid: %d\n",
-+				 priv->ba_aid);
-+
-+	filp_close(filp_bahisto, current->files);
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+
-+err:
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_ba_hist_write(struct file *file,
-+					 const char __user *ubuf,
-+					 size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int sta_aid;
-+	struct mwl_sta *sta_info;
-+	int size;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &sta_aid)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if ((sta_aid <= 0) || (sta_aid > SYSADPT_MAX_STA_SC4)) {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "station aid is exceeding the limit %d\n", sta_aid);
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if (priv->ba_aid) {
-+		sta_info = utils_find_sta_by_aid(priv, priv->ba_aid);
-+		if (sta_info) {
-+			sta_info->ba_hist.enable = false;
-+			kfree(sta_info->ba_hist.ba_stats);
-+		}
-+	}
-+	priv->ba_aid = 0;
-+	sta_info = utils_find_sta_by_aid(priv, sta_aid);
-+	if (sta_info) {
-+		sta_info->ba_hist.enable = true;
-+		sta_info->ba_hist.index = 0;
-+		size = sizeof(struct mwl_tx_ba_stats) * ACNT_BA_SIZE;
-+		sta_info->ba_hist.ba_stats = kmalloc(size, GFP_KERNEL);
-+		if (sta_info->ba_hist.ba_stats) {
-+			memset(sta_info->ba_hist.ba_stats, 0, size);
-+			priv->ba_aid = sta_aid;
-+		}
-+		ret = count;
-+	} else
-+		ret = -EINVAL;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_fixed_rate_read(struct file *file, char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	ssize_t ret;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "fixed rate: 0x%08x\n",
-+			 priv->fixed_rate);
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_fixed_rate_write(struct file *file,
-+					    const char __user *ubuf,
-+					    size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	ssize_t ret;
-+	int fixed_rate = 0, fwcmd_ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	ret = sscanf(buf, "%08x", &fixed_rate);
-+	if (!ret) {
-+		ret = -EIO;
-+		goto err;
-+	}
-+
-+	priv->fixed_rate = fixed_rate;
-+
-+	if (fixed_rate != 0)
-+		fwcmd_ret = mwl_fwcmd_set_rate_drop(priv->hw, 3,
-+						    priv->fixed_rate, 0);
-+	else
-+		fwcmd_ret = mwl_fwcmd_set_rate_drop(priv->hw, 1,
-+						    priv->fixed_rate, 0);
-+	if (fwcmd_ret)
-+		ret = -EIO;
-+	else
-+		ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_core_dump_read(struct file *file, char __user *ubuf,
-+					  size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long page = get_zeroed_page(GFP_KERNEL);
-+	char *p = (char *)page;
-+	int len = 0, size = PAGE_SIZE;
-+	struct coredump_cmd *core_dump = NULL;
-+	struct coredump *cd = NULL;
-+	char  *buff = NULL;
-+	u32 i, offset;
-+	u32 address, length;
-+	ssize_t ret;
-+
-+	if (priv->chip_type != MWL8964)
-+		return -EPERM;
-+
-+	if (*ppos)
-+		return len;
-+
-+	if (!p)
-+		return -ENOMEM;
-+
-+	core_dump = kmalloc(sizeof(*core_dump), GFP_ATOMIC);
-+	if (!core_dump) {
-+		ret = -ENOMEM;
-+		goto err;
-+	}
-+
-+	buff = kmalloc(MAX_CORE_DUMP_BUFFER, GFP_ATOMIC);
-+	if (!buff) {
-+		ret = -ENOMEM;
-+		goto err;
-+	}
-+	memset((char *)buff, 0, MAX_CORE_DUMP_BUFFER);
-+
-+	cd = kmalloc(sizeof(*cd), GFP_ATOMIC);
-+	if (!cd) {
-+		ret = -ENOMEM;
-+		goto err;
-+	}
-+
-+	core_dump->context = 0;
-+	core_dump->flags = 0;
-+	core_dump->size_kb = 0;
-+	if (mwl_fwcmd_get_fw_core_dump(priv->hw, core_dump, buff)) {
-+		ret = -EIO;
-+		goto err;
-+	}
-+	memcpy(cd, buff, sizeof(*cd));
-+
-+	len += scnprintf(p + len, size - len, "\n");
-+	len += scnprintf(p + len, size - len, "Major Version : %d\n",
-+			 cd->version_major);
-+	len += scnprintf(p + len, size - len, "Minor Version : %d\n",
-+			 cd->version_minor);
-+	len += scnprintf(p + len, size - len, "Patch Version : %d\n",
-+			 cd->version_patch);
-+	len += scnprintf(p + len, size - len, "Num of Regions: %d\n",
-+			 cd->num_regions);
-+	len += scnprintf(p + len, size - len, "Num of Symbols: %d\n",
-+			 cd->num_symbols);
-+
-+	for (i = 0; i < cd->num_regions; i++) {
-+		address = le32_to_cpu(cd->region[i].address);
-+		length = le32_to_cpu(cd->region[i].length);
-+		len += scnprintf(p + len, size - len,
-+				 "\ncd.region[%d]: address=%x, length=%x\n",
-+				 i, address, length);
-+
-+		for (offset = 0; offset < length;
-+		     offset += MAX_CORE_DUMP_BUFFER) {
-+			core_dump->context = cpu_to_le32((i << 28) | offset);
-+			core_dump->flags = 0;
-+			core_dump->size_kb = 0;
-+			if (mwl_fwcmd_get_fw_core_dump(priv->hw,
-+			    core_dump, buff)) {
-+				wiphy_info(priv->hw->wiphy,
-+					   "region:%d offset:%x\n", i, offset);
-+				break;
-+			}
-+			core_dump_file(buff, MAX_CORE_DUMP_BUFFER,
-+				       address, address + offset,
-+				       offset, length, priv->coredump_text);
-+		}
-+	}
-+	len += scnprintf(p + len, size - len, "\n");
-+
-+	ret = simple_read_from_buffer(ubuf, count, ppos, p, len);
-+
-+err:
-+	kfree(core_dump);
-+	kfree(buff);
-+	kfree(cd);
-+	free_page(page);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_core_dump_write(struct file *file,
-+					   const char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int text_mode;
-+	ssize_t ret;
-+
-+	if (priv->chip_type != MWL8964)
-+		return -EPERM;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &text_mode)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	if ((text_mode < 0) || (text_mode > 1)) {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "text mode should be 0 (false) or 1 (true): %d\n",
-+			   text_mode);
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	mwl_fwcmd_core_dump_diag_mode(priv->hw, 1);
-+	priv->coredump_text = text_mode ? true : false;
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_mcast_cts_write(struct file *file,
-+					   const char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	int cts_enable = 0;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	if (kstrtoint(buf, 0, &cts_enable)) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+
-+	ret = mwl_hif_mcast_cts(priv->hw, cts_enable ? true : false);
-+	if (ret)
-+		goto err;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+static ssize_t mwl_debugfs_wmmedcaap_write(struct file *file,
-+					   const char __user *ubuf,
-+					   size_t count, loff_t *ppos)
-+{
-+	struct mwl_priv *priv = (struct mwl_priv *)file->private_data;
-+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-+	char *buf = (char *)addr;
-+	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
-+	u32 index = 0, cw_min = 0, cw_max = 0, aifsn = 0, txop = 0;
-+	ssize_t ret;
-+
-+	if (!buf)
-+		return -ENOMEM;
-+
-+	if (copy_from_user(buf, ubuf, buf_size)) {
-+		ret = -EFAULT;
-+		goto err;
-+	}
-+
-+	ret = sscanf(buf, "%u %x %x %u %x", &index, &cw_min,
-+			&cw_max, &aifsn, &txop);
-+	if (ret != 5) {
-+		ret = -EINVAL;
-+		goto err;
-+	}
-+	wiphy_info(priv->hw->wiphy, "set TCQ%d wmm edca with:\n", index);
-+	wiphy_info(priv->hw->wiphy,
-+		   "cw_min=0x%x, cw_max=0x%x, aifs_num=%d, txop=0x%x\n",
-+		   cw_min, cw_max, aifsn, txop);
-+
-+	ret = mwl_fwcmd_set_edca_params(priv->hw, index,
-+			cw_min, cw_max, aifsn, txop);
-+	if (ret)
-+		goto err;
-+
-+	ret = count;
-+
-+err:
-+	free_page(addr);
-+	return ret;
-+}
-+
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(info);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(tx_status);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(rx_status);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(vif);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(sta);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(ampdu);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(stnid);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(device_pwrtbl);
-+MWLWIFI_DEBUGFS_FILE_READ_OPS(txpwrlmt);
-+MWLWIFI_DEBUGFS_FILE_OPS(tx_amsdu);
-+MWLWIFI_DEBUGFS_FILE_OPS(dump_hostcmd);
-+MWLWIFI_DEBUGFS_FILE_OPS(dump_probe);
-+MWLWIFI_DEBUGFS_FILE_OPS(heartbeat);
-+MWLWIFI_DEBUGFS_FILE_OPS(dfs_test);
-+MWLWIFI_DEBUGFS_FILE_OPS(dfs_channel);
-+MWLWIFI_DEBUGFS_FILE_OPS(dfs_radar);
-+MWLWIFI_DEBUGFS_FILE_OPS(thermal);
-+MWLWIFI_DEBUGFS_FILE_OPS(led_ctrl);
-+MWLWIFI_DEBUGFS_FILE_OPS(regrdwr);
-+MWLWIFI_DEBUGFS_FILE_OPS(ratetable);
-+MWLWIFI_DEBUGFS_FILE_OPS(tx_hist);
-+MWLWIFI_DEBUGFS_FILE_OPS(ba_hist);
-+MWLWIFI_DEBUGFS_FILE_OPS(fixed_rate);
-+MWLWIFI_DEBUGFS_FILE_OPS(core_dump);
-+MWLWIFI_DEBUGFS_FILE_WRITE_OPS(mcast_cts);
-+MWLWIFI_DEBUGFS_FILE_WRITE_OPS(wmmedcaap);
-+
-+void mwl_debugfs_init(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (!priv->debugfs_phy)
-+		priv->debugfs_phy = debugfs_create_dir("mwlwifi",
-+						       hw->wiphy->debugfsdir);
-+
-+	if (!priv->debugfs_phy)
-+		return;
-+
-+	MWLWIFI_DEBUGFS_ADD_FILE(info);
-+	MWLWIFI_DEBUGFS_ADD_FILE(tx_status);
-+	MWLWIFI_DEBUGFS_ADD_FILE(rx_status);
-+	MWLWIFI_DEBUGFS_ADD_FILE(vif);
-+	MWLWIFI_DEBUGFS_ADD_FILE(sta);
-+	MWLWIFI_DEBUGFS_ADD_FILE(ampdu);
-+	MWLWIFI_DEBUGFS_ADD_FILE(stnid);
-+	MWLWIFI_DEBUGFS_ADD_FILE(device_pwrtbl);
-+	MWLWIFI_DEBUGFS_ADD_FILE(txpwrlmt);
-+	MWLWIFI_DEBUGFS_ADD_FILE(tx_amsdu);
-+	MWLWIFI_DEBUGFS_ADD_FILE(dump_hostcmd);
-+	MWLWIFI_DEBUGFS_ADD_FILE(dump_probe);
-+	MWLWIFI_DEBUGFS_ADD_FILE(heartbeat);
-+	MWLWIFI_DEBUGFS_ADD_FILE(dfs_test);
-+	MWLWIFI_DEBUGFS_ADD_FILE(dfs_channel);
-+	MWLWIFI_DEBUGFS_ADD_FILE(dfs_radar);
-+	MWLWIFI_DEBUGFS_ADD_FILE(thermal);
-+	MWLWIFI_DEBUGFS_ADD_FILE(led_ctrl);
-+	MWLWIFI_DEBUGFS_ADD_FILE(regrdwr);
-+	MWLWIFI_DEBUGFS_ADD_FILE(ratetable);
-+	MWLWIFI_DEBUGFS_ADD_FILE(tx_hist);
-+	MWLWIFI_DEBUGFS_ADD_FILE(ba_hist);
-+	MWLWIFI_DEBUGFS_ADD_FILE(fixed_rate);
-+	MWLWIFI_DEBUGFS_ADD_FILE(core_dump);
-+	MWLWIFI_DEBUGFS_ADD_FILE(mcast_cts);
-+	MWLWIFI_DEBUGFS_ADD_FILE(wmmedcaap);
-+}
-+
-+void mwl_debugfs_remove(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	debugfs_remove(priv->debugfs_phy);
-+	priv->debugfs_phy = NULL;
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/debugfs.h b/drivers/net/wireless/marvell/mwlwifi/debugfs.h
-new file mode 100644
-index 000000000000..e7595f563348
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/debugfs.h
-@@ -0,0 +1,24 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines debug fs related functions. */
-+
-+#ifndef _MWL_DEBUGFS_H_
-+#define _MWL_DEBUGFS_H_
-+
-+void mwl_debugfs_init(struct ieee80211_hw *hw);
-+void mwl_debugfs_remove(struct ieee80211_hw *hw);
-+
-+#endif /* _MWL_DEBUGFS_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.c b/drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.c
-new file mode 100644
-index 000000000000..ff943d6fe447
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.c
-@@ -0,0 +1,3852 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements firmware host command related
-+ * functions.
-+ */
-+
-+#include <linux/etherdevice.h>
-+#include <linux/ctype.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/fwcmd.h"
-+#include "hif/hif-ops.h"
-+
-+#define MAX_WAIT_GET_HW_SPECS_ITERATONS         3
-+
-+struct cmd_header {
-+	__le16 command;
-+	__le16 len;
-+} __packed;
-+
-+char *mwl_fwcmd_get_cmd_string(unsigned short cmd)
-+{
-+	int max_entries = 0;
-+	int curr_cmd = 0;
-+
-+	static const struct {
-+		u16 cmd;
-+		char *cmd_string;
-+	} cmds[] = {
-+		{ HOSTCMD_CMD_GET_HW_SPEC, "GetHwSpecifications" },
-+		{ HOSTCMD_CMD_SET_HW_SPEC, "SetHwSepcifications" },
-+		{ HOSTCMD_CMD_802_11_GET_STAT, "80211GetStat" },
-+		{ HOSTCMD_CMD_BBP_REG_ACCESS, "BBPRegAccess" },
-+		{ HOSTCMD_CMD_RF_REG_ACCESS, "RFRegAccess" },
-+		{ HOSTCMD_CMD_802_11_RADIO_CONTROL, "80211RadioControl" },
-+		{ HOSTCMD_CMD_MEM_ADDR_ACCESS, "MEMAddrAccess" },
-+		{ HOSTCMD_CMD_802_11_TX_POWER, "80211TxPower" },
-+		{ HOSTCMD_CMD_802_11_RF_ANTENNA, "80211RfAntenna" },
-+		{ HOSTCMD_CMD_BROADCAST_SSID_ENABLE, "BroadcastSsidEnable" },
-+		{ HOSTCMD_CMD_SET_CFG, "SetCfg" },
-+		{ HOSTCMD_CMD_SET_RF_CHANNEL, "SetRfChannel" },
-+		{ HOSTCMD_CMD_SET_AID, "SetAid" },
-+		{ HOSTCMD_CMD_SET_INFRA_MODE, "SetInfraMode" },
-+		{ HOSTCMD_CMD_802_11_RTS_THSD, "80211RtsThreshold" },
-+		{ HOSTCMD_CMD_SET_EDCA_PARAMS, "SetEDCAParams" },
-+		{ HOSTCMD_CMD_802_11H_DETECT_RADAR, "80211hDetectRadar" },
-+		{ HOSTCMD_CMD_SET_WMM_MODE, "SetWMMMode" },
-+		{ HOSTCMD_CMD_HT_GUARD_INTERVAL, "HtGuardInterval" },
-+		{ HOSTCMD_CMD_SET_FIXED_RATE, "SetFixedRate" },
-+		{ HOSTCMD_CMD_SET_IES, "SetInformationElements" },
-+		{ HOSTCMD_CMD_SET_LINKADAPT_CS_MODE, "LinkAdaptCsMode" },
-+		{ HOSTCMD_CMD_DUMP_OTP_DATA, "DumpOtpData" },
-+		{ HOSTCMD_CMD_SET_MAC_ADDR, "SetMacAddr" },
-+		{ HOSTCMD_CMD_SET_RATE_ADAPT_MODE, "SetRateAdaptationMode" },
-+		{ HOSTCMD_CMD_GET_WATCHDOG_BITMAP, "GetWatchdogBitMap" },
-+		{ HOSTCMD_CMD_DEL_MAC_ADDR, "DelMacAddr" },
-+		{ HOSTCMD_CMD_BSS_START, "BssStart" },
-+		{ HOSTCMD_CMD_AP_BEACON, "SetApBeacon" },
-+		{ HOSTCMD_CMD_SET_NEW_STN, "SetNewStation" },
-+		{ HOSTCMD_CMD_SET_APMODE, "SetApMode" },
-+		{ HOSTCMD_CMD_SET_SWITCH_CHANNEL, "SetSwitchChannel" },
-+		{ HOSTCMD_CMD_UPDATE_ENCRYPTION, "UpdateEncryption" },
-+		{ HOSTCMD_CMD_BASTREAM, "BAStream" },
-+		{ HOSTCMD_CMD_SET_SPECTRUM_MGMT, "SetSpectrumMgmt" },
-+		{ HOSTCMD_CMD_SET_POWER_CONSTRAINT, "SetPowerConstraint" },
-+		{ HOSTCMD_CMD_SET_COUNTRY_CODE, "SetCountryCode" },
-+		{ HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL, "SetOptimizationLevel" },
-+		{ HOSTCMD_CMD_SET_WSC_IE, "SetWscIE" },
-+		{ HOSTCMD_CMD_GET_RATETABLE, "GetRateTable" },
-+		{ HOSTCMD_CMD_GET_SEQNO, "GetSeqno" },
-+		{ HOSTCMD_CMD_DWDS_ENABLE, "DwdsEnable" },
-+		{ HOSTCMD_CMD_FW_FLUSH_TIMER, "FwFlushTimer" },
-+		{ HOSTCMD_CMD_SET_CDD, "SetCDD" },
-+		{ HOSTCMD_CMD_SET_BFTYPE, "SetBFType" },
-+		{ HOSTCMD_CMD_CAU_REG_ACCESS, "CAURegAccess" },
-+		{ HOSTCMD_CMD_GET_TEMP, "GetTemp" },
-+		{ HOSTCMD_CMD_LED_CTRL, "LedCtrl" },
-+		{ HOSTCMD_CMD_GET_FW_REGION_CODE, "GetFwRegionCode" },
-+		{ HOSTCMD_CMD_GET_DEVICE_PWR_TBL, "GetDevicePwrTbl" },
-+		{ HOSTCMD_CMD_SET_RATE_DROP, "SetRateDrop" },
-+		{ HOSTCMD_CMD_NEWDP_DMATHREAD_START, "NewdpDMAThreadStart" },
-+		{ HOSTCMD_CMD_GET_FW_REGION_CODE_SC4, "GetFwRegionCodeSC4" },
-+		{ HOSTCMD_CMD_GET_DEVICE_PWR_TBL_SC4, "GetDevicePwrTblSC4" },
-+		{ HOSTCMD_CMD_QUIET_MODE, "QuietMode" },
-+		{ HOSTCMD_CMD_CORE_DUMP_DIAG_MODE, "CoreDumpDiagMode" },
-+		{ HOSTCMD_CMD_802_11_SLOT_TIME, "80211SlotTime" },
-+		{ HOSTCMD_CMD_GET_FW_CORE_DUMP, "GetFwCoreDump" },
-+		{ HOSTCMD_CMD_EDMAC_CTRL, "EDMACCtrl" },
-+		{ HOSTCMD_CMD_TXPWRLMT_CFG, "TxpwrlmtCfg" },
-+		{ HOSTCMD_CMD_MCAST_CTS, "McastCts" },
-+	};
-+
-+	max_entries = ARRAY_SIZE(cmds);
-+
-+	for (curr_cmd = 0; curr_cmd < max_entries; curr_cmd++)
-+		if ((cmd & 0x7fff) == cmds[curr_cmd].cmd)
-+			return cmds[curr_cmd].cmd_string;
-+
-+	return "unknown";
-+}
-+
-+static int mwl_fwcmd_802_11_radio_control(struct mwl_priv *priv,
-+					  bool enable, bool force)
-+{
-+	struct hostcmd_cmd_802_11_radio_control *pcmd;
-+
-+	if (enable == priv->radio_on && !force)
-+		return 0;
-+
-+	pcmd = (struct hostcmd_cmd_802_11_radio_control *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_RADIO_CONTROL);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(WL_SET);
-+	pcmd->control = cpu_to_le16(priv->radio_short_preamble ?
-+		WL_AUTO_PREAMBLE : WL_LONG_PREAMBLE);
-+	pcmd->radio_on = cpu_to_le16(enable ? WL_ENABLE : WL_DISABLE);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_802_11_RADIO_CONTROL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	priv->radio_on = enable;
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+static int mwl_fwcmd_get_tx_powers(struct mwl_priv *priv, u16 *powlist,
-+				   u8 action, u16 ch, u16 band,
-+				   u16 width, u16 sub_ch)
-+{
-+	struct hostcmd_cmd_802_11_tx_power *pcmd;
-+	int i;
-+
-+	pcmd = (struct hostcmd_cmd_802_11_tx_power *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	if (priv->chip_type == MWL8997) {
-+		memset(pcmd, 0x00,
-+		       sizeof(struct hostcmd_cmd_802_11_tx_power_kf2));
-+		pcmd->cmd_hdr.len = cpu_to_le16(
-+			sizeof(struct hostcmd_cmd_802_11_tx_power_kf2));
-+	} else {
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	}
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_TX_POWER);
-+	pcmd->action = cpu_to_le16(action);
-+	pcmd->ch = cpu_to_le16(ch);
-+	pcmd->bw = cpu_to_le16(width);
-+	pcmd->band = cpu_to_le16(band);
-+	pcmd->sub_ch = cpu_to_le16(sub_ch);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_802_11_TX_POWER)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	for (i = 0; i < priv->pwr_level; i++)
-+		powlist[i] = le16_to_cpu(pcmd->power_level_list[i]);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+static int mwl_fwcmd_set_tx_powers(struct mwl_priv *priv, u16 txpow[],
-+				   u8 action, u16 ch, u16 band,
-+				   u16 width, u16 sub_ch)
-+{
-+	struct hostcmd_cmd_802_11_tx_power *pcmd;
-+	int i;
-+
-+	pcmd = (struct hostcmd_cmd_802_11_tx_power *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	if (priv->chip_type == MWL8997) {
-+		memset(pcmd, 0x00,
-+		       sizeof(struct hostcmd_cmd_802_11_tx_power_kf2));
-+		pcmd->cmd_hdr.len = cpu_to_le16(
-+			sizeof(struct hostcmd_cmd_802_11_tx_power_kf2));
-+	} else {
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	}
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_TX_POWER);
-+	pcmd->action = cpu_to_le16(action);
-+	pcmd->ch = cpu_to_le16(ch);
-+	pcmd->bw = cpu_to_le16(width);
-+	pcmd->band = cpu_to_le16(band);
-+	pcmd->sub_ch = cpu_to_le16(sub_ch);
-+
-+	for (i = 0; i < priv->pwr_level; i++)
-+		pcmd->power_level_list[i] = cpu_to_le16(txpow[i]);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_802_11_TX_POWER)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+static u8 mwl_fwcmd_get_80m_pri_chnl(u8 channel)
-+{
-+	u8 act_primary = ACT_PRIMARY_CHAN_0;
-+
-+	switch (channel) {
-+	case 36:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 40:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 44:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 48:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 52:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 56:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 60:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 64:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 100:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 104:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 108:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 112:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 116:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 120:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 124:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 128:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 132:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 136:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 140:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 144:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 149:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 153:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 157:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 161:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	}
-+
-+	return act_primary;
-+}
-+
-+static u8 mwl_fwcmd_get_160m_pri_chnl(u8 channel)
-+{
-+	u8 act_primary = ACT_PRIMARY_CHAN_0;
-+
-+	switch (channel) {
-+	case 36:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 40:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 44:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 48:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 52:
-+		act_primary = ACT_PRIMARY_CHAN_4;
-+		break;
-+	case 56:
-+		act_primary = ACT_PRIMARY_CHAN_5;
-+		break;
-+	case 60:
-+		act_primary = ACT_PRIMARY_CHAN_6;
-+		break;
-+	case 64:
-+		act_primary = ACT_PRIMARY_CHAN_7;
-+		break;
-+	case 100:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 104:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 108:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 112:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 116:
-+		act_primary = ACT_PRIMARY_CHAN_4;
-+		break;
-+	case 120:
-+		act_primary = ACT_PRIMARY_CHAN_5;
-+		break;
-+	case 124:
-+		act_primary = ACT_PRIMARY_CHAN_6;
-+		break;
-+	case 128:
-+		act_primary = ACT_PRIMARY_CHAN_7;
-+		break;
-+	case 149:
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case 153:
-+		act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case 157:
-+		act_primary = ACT_PRIMARY_CHAN_2;
-+		break;
-+	case 161:
-+		act_primary = ACT_PRIMARY_CHAN_3;
-+		break;
-+	case 165:
-+		act_primary = ACT_PRIMARY_CHAN_4;
-+		break;
-+	case 169:
-+		act_primary = ACT_PRIMARY_CHAN_5;
-+		break;
-+	case 173:
-+		act_primary = ACT_PRIMARY_CHAN_6;
-+		break;
-+	case 177:
-+		act_primary = ACT_PRIMARY_CHAN_7;
-+		break;
-+	}
-+
-+	return act_primary;
-+}
-+
-+static void mwl_fwcmd_parse_beacon(struct mwl_priv *priv,
-+				   struct mwl_vif *vif, u8 *beacon, int len)
-+{
-+	struct ieee80211_mgmt *mgmt;
-+	struct beacon_info *beacon_info;
-+	int baselen;
-+	u8 *pos;
-+	size_t left;
-+	bool elem_parse_failed;
-+
-+	mgmt = (struct ieee80211_mgmt *)beacon;
-+
-+	baselen = (u8 *)mgmt->u.beacon.variable - (u8 *)mgmt;
-+	if (baselen > len)
-+		return;
-+
-+	beacon_info = &vif->beacon_info;
-+	memset(beacon_info, 0, sizeof(struct beacon_info));
-+	beacon_info->valid = false;
-+	beacon_info->ie_ht_ptr = &beacon_info->ie_list_ht[0];
-+	beacon_info->ie_vht_ptr = &beacon_info->ie_list_vht[0];
-+
-+	beacon_info->cap_info = le16_to_cpu(mgmt->u.beacon.capab_info);
-+	beacon_info->power_constraint = 0;
-+
-+	pos = (u8 *)mgmt->u.beacon.variable;
-+	left = len - baselen;
-+
-+	elem_parse_failed = false;
-+
-+	while (left >= 2) {
-+		u8 id, elen;
-+
-+		id = *pos++;
-+		elen = *pos++;
-+		left -= 2;
-+
-+		if (elen > left) {
-+			elem_parse_failed = true;
-+			break;
-+		}
-+
-+		switch (id) {
-+		case WLAN_EID_COUNTRY:
-+			beacon_info->ie_country_len = (elen + 2);
-+			beacon_info->ie_country_ptr = (pos - 2);
-+			break;
-+		case WLAN_EID_SUPP_RATES:
-+		case WLAN_EID_EXT_SUPP_RATES:
-+			{
-+			int idx, bi, oi;
-+			u8 rate;
-+
-+			for (bi = 0; bi < SYSADPT_MAX_DATA_RATES_G;
-+			     bi++) {
-+				if (beacon_info->b_rate_set[bi] == 0)
-+					break;
-+			}
-+
-+			for (oi = 0; oi < SYSADPT_MAX_DATA_RATES_G;
-+			     oi++) {
-+				if (beacon_info->op_rate_set[oi] == 0)
-+					break;
-+			}
-+
-+			for (idx = 0; idx < elen; idx++) {
-+				rate = pos[idx];
-+				if ((rate & 0x80) != 0) {
-+					if (bi < SYSADPT_MAX_DATA_RATES_G)
-+						beacon_info->b_rate_set[bi++]
-+							= rate & 0x7f;
-+					else {
-+						elem_parse_failed = true;
-+						break;
-+					}
-+				}
-+				if (oi < SYSADPT_MAX_DATA_RATES_G)
-+					beacon_info->op_rate_set[oi++] =
-+						rate & 0x7f;
-+				else {
-+					elem_parse_failed = true;
-+					break;
-+				}
-+			}
-+			}
-+			break;
-+		case WLAN_EID_PWR_CONSTRAINT:
-+			if (elen == 1)
-+				beacon_info->power_constraint = *pos;
-+			break;
-+		case WLAN_EID_RSN:
-+			beacon_info->ie_rsn48_len = (elen + 2);
-+			beacon_info->ie_rsn48_ptr = (pos - 2);
-+			break;
-+		case WLAN_EID_MOBILITY_DOMAIN:
-+			beacon_info->ie_mde_len = (elen + 2);
-+			beacon_info->ie_mde_ptr = (pos - 2);
-+			break;
-+		case WLAN_EID_HT_CAPABILITY:
-+		case WLAN_EID_HT_OPERATION:
-+		case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
-+		case WLAN_EID_EXT_CAPABILITY:
-+			beacon_info->ie_ht_len += (elen + 2);
-+			if (beacon_info->ie_ht_len >
-+			    sizeof(beacon_info->ie_list_ht)) {
-+				elem_parse_failed = true;
-+			} else {
-+				*beacon_info->ie_ht_ptr++ = id;
-+				*beacon_info->ie_ht_ptr++ = elen;
-+				memcpy(beacon_info->ie_ht_ptr, pos, elen);
-+				beacon_info->ie_ht_ptr += elen;
-+			}
-+			break;
-+		case WLAN_EID_MESH_CONFIG:
-+			beacon_info->ie_meshcfg_len = (elen + 2);
-+			beacon_info->ie_meshcfg_ptr = (pos - 2);
-+			break;
-+		case WLAN_EID_MESH_ID:
-+			beacon_info->ie_meshid_len = (elen + 2);
-+			beacon_info->ie_meshid_ptr = (pos - 2);
-+			break;
-+		case WLAN_EID_CHAN_SWITCH_PARAM:
-+			beacon_info->ie_meshchsw_len = (elen + 2);
-+			beacon_info->ie_meshchsw_ptr = (pos - 2);
-+			break;
-+		case WLAN_EID_VHT_CAPABILITY:
-+		case WLAN_EID_VHT_OPERATION:
-+		case WLAN_EID_OPMODE_NOTIF:
-+			beacon_info->ie_vht_len += (elen + 2);
-+			if (beacon_info->ie_vht_len >
-+			    sizeof(beacon_info->ie_list_vht)) {
-+				elem_parse_failed = true;
-+			} else {
-+				*beacon_info->ie_vht_ptr++ = id;
-+				*beacon_info->ie_vht_ptr++ = elen;
-+				memcpy(beacon_info->ie_vht_ptr, pos, elen);
-+				beacon_info->ie_vht_ptr += elen;
-+			}
-+			break;
-+		case WLAN_EID_VENDOR_SPECIFIC:
-+			if ((pos[0] == 0x00) && (pos[1] == 0x50) &&
-+			    (pos[2] == 0xf2)) {
-+				if (pos[3] == 0x01) {
-+					beacon_info->ie_rsn_len = (elen + 2);
-+					beacon_info->ie_rsn_ptr = (pos - 2);
-+				}
-+
-+				if (pos[3] == 0x02) {
-+					beacon_info->ie_wmm_len = (elen + 2);
-+					beacon_info->ie_wmm_ptr = (pos - 2);
-+				}
-+
-+				if (pos[3] == 0x04) {
-+					beacon_info->ie_wsc_len = (elen + 2);
-+					beacon_info->ie_wsc_ptr = (pos - 2);
-+				}
-+			}
-+			break;
-+		default:
-+			break;
-+		}
-+
-+		left -= elen;
-+		pos += elen;
-+	}
-+
-+	if (!elem_parse_failed) {
-+		beacon_info->ie_ht_ptr = &beacon_info->ie_list_ht[0];
-+		beacon_info->ie_vht_ptr = &beacon_info->ie_list_vht[0];
-+		beacon_info->valid = true;
-+	}
-+}
-+
-+static int mwl_fwcmd_set_ies(struct mwl_priv *priv, struct mwl_vif *mwl_vif)
-+{
-+	struct hostcmd_cmd_set_ies *pcmd;
-+	struct beacon_info *beacon = &mwl_vif->beacon_info;
-+	u16 ie_list_len_proprietary = 0;
-+
-+	if (beacon->ie_ht_len > sizeof(pcmd->ie_list_ht))
-+		goto einval;
-+
-+	if (beacon->ie_vht_len > sizeof(pcmd->ie_list_vht))
-+		goto einval;
-+
-+	pcmd = (struct hostcmd_cmd_set_ies *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_IES);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_GEN_SET);
-+
-+	memcpy(pcmd->ie_list_ht, beacon->ie_ht_ptr, beacon->ie_ht_len);
-+	pcmd->ie_list_len_ht = cpu_to_le16(beacon->ie_ht_len);
-+
-+	memcpy(pcmd->ie_list_vht, beacon->ie_vht_ptr, beacon->ie_vht_len);
-+	pcmd->ie_list_len_vht = cpu_to_le16(beacon->ie_vht_len);
-+
-+	memcpy(pcmd->ie_list_proprietary, beacon->ie_meshid_ptr,
-+	       beacon->ie_meshid_len);
-+	ie_list_len_proprietary = beacon->ie_meshid_len;
-+
-+	memcpy(pcmd->ie_list_proprietary + ie_list_len_proprietary,
-+	       beacon->ie_meshcfg_ptr, beacon->ie_meshcfg_len);
-+	ie_list_len_proprietary += beacon->ie_meshcfg_len;
-+
-+	memcpy(pcmd->ie_list_proprietary + ie_list_len_proprietary,
-+	       beacon->ie_meshchsw_ptr, beacon->ie_meshchsw_len);
-+	ie_list_len_proprietary += beacon->ie_meshchsw_len;
-+
-+	if (priv->chip_type == MWL8897) {
-+		memcpy(pcmd->ie_list_proprietary + ie_list_len_proprietary,
-+		       beacon->ie_wmm_ptr, beacon->ie_wmm_len);
-+		ie_list_len_proprietary += mwl_vif->beacon_info.ie_wmm_len;
-+	}
-+
-+	memcpy(pcmd->ie_list_proprietary + ie_list_len_proprietary,
-+	       beacon->ie_mde_ptr, beacon->ie_mde_len);
-+	ie_list_len_proprietary += mwl_vif->beacon_info.ie_mde_len;
-+
-+	pcmd->ie_list_len_proprietary = cpu_to_le16(ie_list_len_proprietary);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_SET_IES)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+
-+einval:
-+
-+	wiphy_err(priv->hw->wiphy, "length of IE is too long\n");
-+
-+	return -EINVAL;
-+}
-+
-+static int mwl_fwcmd_set_ap_beacon(struct mwl_priv *priv,
-+				   struct mwl_vif *mwl_vif,
-+				   struct ieee80211_bss_conf *bss_conf)
-+{
-+	struct hostcmd_cmd_ap_beacon *pcmd;
-+	struct ds_params *phy_ds_param_set;
-+
-+	/* wmm structure of start command is defined less one byte,
-+	 * due to following field country is not used, add byte one
-+	 * to bypass the check.
-+	 */
-+	if (mwl_vif->beacon_info.ie_wmm_len >
-+	    (sizeof(pcmd->start_cmd.wmm_param) + 1))
-+		goto ielenerr;
-+
-+	if (mwl_vif->beacon_info.ie_rsn_len > sizeof(pcmd->start_cmd.rsn_ie))
-+		goto ielenerr;
-+
-+	if (mwl_vif->beacon_info.ie_rsn48_len >
-+	    sizeof(pcmd->start_cmd.rsn48_ie))
-+		goto ielenerr;
-+
-+	pcmd = (struct hostcmd_cmd_ap_beacon *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_AP_BEACON);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	ether_addr_copy(pcmd->start_cmd.sta_mac_addr, mwl_vif->bssid);
-+	memcpy(pcmd->start_cmd.ssid, bss_conf->ssid, bss_conf->ssid_len);
-+	if (priv->chip_type == MWL8997)
-+		ether_addr_copy(pcmd->start_cmd.bssid, mwl_vif->bssid);
-+	pcmd->start_cmd.bss_type = 1;
-+	pcmd->start_cmd.bcn_period  = cpu_to_le16(bss_conf->beacon_int);
-+	pcmd->start_cmd.dtim_period = bss_conf->dtim_period; /* 8bit */
-+
-+	phy_ds_param_set = &pcmd->start_cmd.phy_param_set.ds_param_set;
-+	phy_ds_param_set->elem_id = WLAN_EID_DS_PARAMS;
-+	phy_ds_param_set->len = sizeof(phy_ds_param_set->current_chnl);
-+	phy_ds_param_set->current_chnl = bss_conf->chandef.chan->hw_value;
-+
-+	pcmd->start_cmd.probe_delay = cpu_to_le16(10);
-+	pcmd->start_cmd.cap_info = cpu_to_le16(mwl_vif->beacon_info.cap_info);
-+
-+	memcpy(&pcmd->start_cmd.wmm_param, mwl_vif->beacon_info.ie_wmm_ptr,
-+	       mwl_vif->beacon_info.ie_wmm_len);
-+
-+	memcpy(&pcmd->start_cmd.rsn_ie, mwl_vif->beacon_info.ie_rsn_ptr,
-+	       mwl_vif->beacon_info.ie_rsn_len);
-+
-+	memcpy(&pcmd->start_cmd.rsn48_ie, mwl_vif->beacon_info.ie_rsn48_ptr,
-+	       mwl_vif->beacon_info.ie_rsn48_len);
-+
-+	memcpy(pcmd->start_cmd.b_rate_set, mwl_vif->beacon_info.b_rate_set,
-+	       SYSADPT_MAX_DATA_RATES_G);
-+
-+	memcpy(pcmd->start_cmd.op_rate_set, mwl_vif->beacon_info.op_rate_set,
-+	       SYSADPT_MAX_DATA_RATES_G);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_AP_BEACON)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+
-+ielenerr:
-+
-+	wiphy_err(priv->hw->wiphy, "length of IE is too long\n");
-+
-+	return -EINVAL;
-+}
-+
-+static int mwl_fwcmd_set_spectrum_mgmt(struct mwl_priv *priv, bool enable)
-+{
-+	struct hostcmd_cmd_set_spectrum_mgmt *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_spectrum_mgmt *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_SPECTRUM_MGMT);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->spectrum_mgmt = cpu_to_le32(enable);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_SET_SPECTRUM_MGMT)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+static int mwl_fwcmd_set_power_constraint(struct mwl_priv *priv,
-+					  u32 power_constraint)
-+{
-+	struct hostcmd_cmd_set_power_constraint *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_power_constraint *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_POWER_CONSTRAINT);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->power_constraint = cpu_to_le32(power_constraint);
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_SET_POWER_CONSTRAINT)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+static int mwl_fwcmd_set_country_code(struct mwl_priv *priv,
-+				      struct mwl_vif *mwl_vif,
-+				      struct ieee80211_bss_conf *bss_conf)
-+{
-+	struct hostcmd_cmd_set_country_code *pcmd;
-+	struct beacon_info *b_inf = &mwl_vif->beacon_info;
-+	u8 chnl_len;
-+	bool a_band;
-+	bool enable = false;
-+
-+	if (b_inf->ie_country_ptr) {
-+		if (bss_conf->chandef.chan->band == NL80211_BAND_2GHZ)
-+			a_band = false;
-+		else if (bss_conf->chandef.chan->band == NL80211_BAND_5GHZ)
-+			a_band = true;
-+		else
-+			return -EINVAL;
-+
-+		chnl_len = b_inf->ie_country_len - 5;
-+		if (a_band) {
-+			if (chnl_len > sizeof(pcmd->domain_info.domain_entry_a))
-+				return -EINVAL;
-+		} else {
-+			if (chnl_len > sizeof(pcmd->domain_info.domain_entry_g))
-+				return -EINVAL;
-+		}
-+
-+		enable = true;
-+	}
-+
-+	pcmd = (struct hostcmd_cmd_set_country_code *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_COUNTRY_CODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le32(enable);
-+	if (enable) {
-+		memcpy(pcmd->domain_info.country_string,
-+		       b_inf->ie_country_ptr + 2, 3);
-+		if (a_band) {
-+			pcmd->domain_info.g_chnl_len = 0;
-+			pcmd->domain_info.a_chnl_len = chnl_len;
-+			memcpy(pcmd->domain_info.domain_entry_a,
-+			       b_inf->ie_country_ptr + 5, chnl_len);
-+		} else {
-+			pcmd->domain_info.a_chnl_len = 0;
-+			pcmd->domain_info.g_chnl_len = chnl_len;
-+			memcpy(pcmd->domain_info.domain_entry_g,
-+			       b_inf->ie_country_ptr + 5, chnl_len);
-+		}
-+	}
-+
-+	if (mwl_hif_exec_cmd(priv->hw, HOSTCMD_CMD_SET_COUNTRY_CODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+static int mwl_fwcmd_encryption_set_cmd_info(struct hostcmd_cmd_set_key *cmd,
-+					     u8 *addr,
-+					     struct ieee80211_key_conf *key)
-+{
-+	cmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_UPDATE_ENCRYPTION);
-+	cmd->cmd_hdr.len = cpu_to_le16(sizeof(*cmd));
-+	cmd->key_param.length = cpu_to_le16(sizeof(*cmd) -
-+		offsetof(struct hostcmd_cmd_set_key, key_param));
-+	cmd->key_param.key_index = cpu_to_le32(key->keyidx);
-+	cmd->key_param.key_len = cpu_to_le16(key->keylen);
-+	ether_addr_copy(cmd->key_param.mac_addr, addr);
-+
-+	switch (key->cipher) {
-+	case WLAN_CIPHER_SUITE_WEP40:
-+	case WLAN_CIPHER_SUITE_WEP104:
-+		cmd->key_param.key_type_id = cpu_to_le16(KEY_TYPE_ID_WEP);
-+		if (key->keyidx == 0)
-+			cmd->key_param.key_info =
-+				cpu_to_le32(ENCR_KEY_FLAG_WEP_TXKEY);
-+		break;
-+	case WLAN_CIPHER_SUITE_TKIP:
-+		cmd->key_param.key_type_id = cpu_to_le16(KEY_TYPE_ID_TKIP);
-+		cmd->key_param.key_info =
-+			(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ?
-+			cpu_to_le32(ENCR_KEY_FLAG_PAIRWISE) :
-+			cpu_to_le32(ENCR_KEY_FLAG_TXGROUPKEY);
-+		cmd->key_param.key_info |=
-+			cpu_to_le32(ENCR_KEY_FLAG_MICKEY_VALID |
-+				      ENCR_KEY_FLAG_TSC_VALID);
-+		break;
-+	case WLAN_CIPHER_SUITE_CCMP:
-+		cmd->key_param.key_type_id = cpu_to_le16(KEY_TYPE_ID_AES);
-+		cmd->key_param.key_info =
-+			(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ?
-+			cpu_to_le32(ENCR_KEY_FLAG_PAIRWISE) :
-+			cpu_to_le32(ENCR_KEY_FLAG_TXGROUPKEY);
-+		break;
-+	case WLAN_CIPHER_SUITE_AES_CMAC:
-+		return 1;
-+	default:
-+		return -ENOTSUPP;
-+	}
-+
-+	return 0;
-+}
-+
-+static __le16 mwl_fwcmd_parse_cal_cfg(const u8 *src, size_t len, u8 *dst)
-+{
-+	const u8 *ptr;
-+	u8 *dptr;
-+	char byte_str[3];
-+	long res;
-+
-+	ptr = src;
-+	dptr = dst;
-+	byte_str[2] = '\0';
-+
-+	while (ptr - src < len) {
-+		if (*ptr && (isspace(*ptr) || iscntrl(*ptr))) {
-+			ptr++;
-+			continue;
-+		}
-+
-+		if (isxdigit(*ptr)) {
-+			byte_str[0] = *ptr++;
-+			byte_str[1] = *ptr++;
-+			kstrtol(byte_str, 16, &res);
-+			*dptr++ = res;
-+		} else {
-+			ptr++;
-+		}
-+	}
-+
-+	return cpu_to_le16(dptr - dst);
-+}
-+
-+static u16 mwl_fwcmd_parse_txpwrlmt_cfg(const u8 *src, size_t len,
-+					u16 parse_len, u8 *dst)
-+{
-+	const u8 *ptr;
-+	u8 *dptr;
-+	char byte_str[3];
-+	long res;
-+
-+	ptr = src;
-+	dptr = dst;
-+	byte_str[2] = '\0';
-+
-+	while ((ptr - src < len) && (dptr - dst < parse_len)) {
-+		if (*ptr && (isspace(*ptr) || iscntrl(*ptr))) {
-+			ptr++;
-+			continue;
-+		}
-+
-+		if (isxdigit(*ptr)) {
-+			byte_str[0] = *ptr++;
-+			byte_str[1] = *ptr++;
-+			kstrtol(byte_str, 16, &res);
-+			*dptr++ = res;
-+		} else {
-+			ptr++;
-+		}
-+	}
-+
-+	return (ptr - src);
-+}
-+
-+const struct hostcmd_get_hw_spec
-+*mwl_fwcmd_get_hw_specs(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_hw_spec *pcmd;
-+	int retry;
-+
-+	pcmd = (struct hostcmd_cmd_get_hw_spec *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	wiphy_debug(hw->wiphy, "pcmd = %p\n", pcmd);
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	eth_broadcast_addr(pcmd->hw_spec.permanent_addr);
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_HW_SPEC);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->hw_spec.fw_awake_cookie = cpu_to_le32(priv->pphys_cmd_buf + 2048);
-+
-+	retry = 0;
-+	while (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_GET_HW_SPEC)) {
-+		if (retry++ > MAX_WAIT_GET_HW_SPECS_ITERATONS) {
-+			wiphy_err(hw->wiphy, "can't get hw specs\n");
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return NULL;
-+		}
-+
-+		msleep(1000);
-+		wiphy_debug(hw->wiphy,
-+			    "repeat command = %p\n", pcmd);
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return &pcmd->hw_spec;
-+}
-+
-+int mwl_fwcmd_set_hw_specs(struct ieee80211_hw *hw,
-+			   struct hostcmd_set_hw_spec *spec)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_hw_spec *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_hw_spec *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_HW_SPEC);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	memcpy(&pcmd->hw_spec, spec, sizeof(*spec));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_HW_SPEC)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_stat(struct ieee80211_hw *hw,
-+		       struct ieee80211_low_level_stats *stats)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_802_11_get_stat *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_802_11_get_stat *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_GET_STAT);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_802_11_GET_STAT)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	stats->dot11ACKFailureCount =
-+		le32_to_cpu(pcmd->ack_failures);
-+	stats->dot11RTSFailureCount =
-+		le32_to_cpu(pcmd->rts_failures);
-+	stats->dot11FCSErrorCount =
-+		le32_to_cpu(pcmd->rx_fcs_errors);
-+	stats->dot11RTSSuccessCount =
-+		le32_to_cpu(pcmd->rts_successes);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_reg_bb(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_bbp_reg_access *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_bbp_reg_access *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BBP_REG_ACCESS);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->offset = cpu_to_le16(reg);
-+	pcmd->action = cpu_to_le16(flag);
-+	pcmd->value = *val;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_BBP_REG_ACCESS)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	*val = pcmd->value;
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_reg_rf(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_rf_reg_access *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_rf_reg_access *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_RF_REG_ACCESS);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->offset = cpu_to_le16(reg);
-+	pcmd->action = cpu_to_le16(flag);
-+	pcmd->value = *val;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_RF_REG_ACCESS)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	*val = pcmd->value;
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_radio_enable(struct ieee80211_hw *hw)
-+{
-+	return mwl_fwcmd_802_11_radio_control(hw->priv, true, false);
-+}
-+
-+int mwl_fwcmd_radio_disable(struct ieee80211_hw *hw)
-+{
-+	return mwl_fwcmd_802_11_radio_control(hw->priv, false, false);
-+}
-+
-+int mwl_fwcmd_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc;
-+
-+	priv->radio_short_preamble = short_preamble;
-+	rc = mwl_fwcmd_802_11_radio_control(priv, true, true);
-+
-+	return rc;
-+}
-+
-+int mwl_fwcmd_get_addr_value(struct ieee80211_hw *hw, u32 addr, u32 len,
-+			     u32 *val, u16 set)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_mem_addr_access *pcmd;
-+	int i;
-+
-+	pcmd = (struct hostcmd_cmd_mem_addr_access *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_MEM_ADDR_ACCESS);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->address = cpu_to_le32(addr);
-+	pcmd->length = cpu_to_le16(len);
-+	pcmd->value[0] = cpu_to_le32(*val);
-+	pcmd->reserved = cpu_to_le16(set);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_MEM_ADDR_ACCESS)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	for (i = 0; i < len; i++)
-+		val[i] = le32_to_cpu(pcmd->value[i]);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_max_tx_power(struct ieee80211_hw *hw,
-+			   struct ieee80211_conf *conf, u8 fraction)
-+{
-+	struct ieee80211_channel *channel = conf->chandef.chan;
-+	struct mwl_priv *priv = hw->priv;
-+	int reduce_val = 0;
-+	u16 band = 0, width = 0, sub_ch = 0;
-+	u16 maxtxpow[SYSADPT_TX_GRP_PWR_LEVEL_TOTAL];
-+	int i, tmp;
-+	int rc = 0;
-+
-+	if ((priv->chip_type != MWL8997) && (priv->forbidden_setting))
-+		return rc;
-+
-+	switch (fraction) {
-+	case 0:
-+		reduce_val = 0;    /* Max */
-+		break;
-+	case 1:
-+		reduce_val = 2;    /* 75% -1.25db */
-+		break;
-+	case 2:
-+		reduce_val = 3;    /* 50% -3db */
-+		break;
-+	case 3:
-+		reduce_val = 6;    /* 25% -6db */
-+		break;
-+	default:
-+		/* larger than case 3,  pCmd->MaxPowerLevel is min */
-+		reduce_val = 0xff;
-+		break;
-+	}
-+
-+	if (channel->band == NL80211_BAND_2GHZ)
-+		band = FREQ_BAND_2DOT4GHZ;
-+	else if (channel->band == NL80211_BAND_5GHZ)
-+		band = FREQ_BAND_5GHZ;
-+
-+	switch (conf->chandef.width) {
-+	case NL80211_CHAN_WIDTH_20_NOHT:
-+	case NL80211_CHAN_WIDTH_20:
-+		width = CH_20_MHZ_WIDTH;
-+		sub_ch = NO_EXT_CHANNEL;
-+		break;
-+	case NL80211_CHAN_WIDTH_40:
-+		width = CH_40_MHZ_WIDTH;
-+		if (conf->chandef.center_freq1 > channel->center_freq)
-+			sub_ch = EXT_CH_ABOVE_CTRL_CH;
-+		else
-+			sub_ch = EXT_CH_BELOW_CTRL_CH;
-+		break;
-+	case NL80211_CHAN_WIDTH_80:
-+		width = CH_80_MHZ_WIDTH;
-+		if (conf->chandef.center_freq1 > channel->center_freq)
-+			sub_ch = EXT_CH_ABOVE_CTRL_CH;
-+		else
-+			sub_ch = EXT_CH_BELOW_CTRL_CH;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	if (priv->chip_type == MWL8997) {
-+		mwl_fwcmd_get_tx_powers(priv, priv->max_tx_pow,
-+					HOSTCMD_ACT_GET_MAX_TX_PWR,
-+					channel->hw_value, band, width, sub_ch);
-+
-+		for (i = 0; i < priv->pwr_level; i++) {
-+			tmp = priv->max_tx_pow[i];
-+			maxtxpow[i] = ((tmp - reduce_val) > 0) ?
-+				(tmp - reduce_val) : 0;
-+		}
-+
-+		rc = mwl_fwcmd_set_tx_powers(priv, maxtxpow,
-+					     HOSTCMD_ACT_SET_MAX_TX_PWR,
-+					     channel->hw_value, band,
-+					     width, sub_ch);
-+		return rc;
-+	}
-+
-+	if ((priv->powinited & MWL_POWER_INIT_2) == 0) {
-+		mwl_fwcmd_get_tx_powers(priv, priv->max_tx_pow,
-+					HOSTCMD_ACT_GEN_GET_LIST,
-+					channel->hw_value, band, width, sub_ch);
-+		priv->powinited |= MWL_POWER_INIT_2;
-+	}
-+
-+	if ((priv->powinited & MWL_POWER_INIT_1) == 0) {
-+		mwl_fwcmd_get_tx_powers(priv, priv->target_powers,
-+					HOSTCMD_ACT_GEN_GET_LIST,
-+					channel->hw_value, band, width, sub_ch);
-+		priv->powinited |= MWL_POWER_INIT_1;
-+	}
-+
-+	for (i = 0; i < priv->pwr_level; i++) {
-+		if (priv->target_powers[i] > priv->max_tx_pow[i])
-+			tmp = priv->max_tx_pow[i];
-+		else
-+			tmp = priv->target_powers[i];
-+		maxtxpow[i] = ((tmp - reduce_val) > 0) ? (tmp - reduce_val) : 0;
-+	}
-+
-+	rc = mwl_fwcmd_set_tx_powers(priv, maxtxpow, HOSTCMD_ACT_GEN_SET,
-+				     channel->hw_value, band, width, sub_ch);
-+
-+	return rc;
-+}
-+
-+int mwl_fwcmd_tx_power(struct ieee80211_hw *hw,
-+		       struct ieee80211_conf *conf, u8 fraction)
-+{
-+	struct ieee80211_channel *channel = conf->chandef.chan;
-+	struct mwl_priv *priv = hw->priv;
-+	int reduce_val = 0;
-+	u16 band = 0, width = 0, sub_ch = 0;
-+	u16 txpow[SYSADPT_TX_GRP_PWR_LEVEL_TOTAL];
-+	int index, found = 0;
-+	int i, tmp;
-+	int rc = 0;
-+
-+	if ((priv->chip_type != MWL8997) && (priv->forbidden_setting))
-+		return rc;
-+
-+	switch (fraction) {
-+	case 0:
-+		reduce_val = 0;    /* Max */
-+		break;
-+	case 1:
-+		reduce_val = 2;    /* 75% -1.25db */
-+		break;
-+	case 2:
-+		reduce_val = 3;    /* 50% -3db */
-+		break;
-+	case 3:
-+		reduce_val = 6;    /* 25% -6db */
-+		break;
-+	default:
-+		/* larger than case 3,  pCmd->MaxPowerLevel is min */
-+		reduce_val = 0xff;
-+		break;
-+	}
-+
-+	if (channel->band == NL80211_BAND_2GHZ)
-+		band = FREQ_BAND_2DOT4GHZ;
-+	else if (channel->band == NL80211_BAND_5GHZ)
-+		band = FREQ_BAND_5GHZ;
-+
-+	switch (conf->chandef.width) {
-+	case NL80211_CHAN_WIDTH_20_NOHT:
-+	case NL80211_CHAN_WIDTH_20:
-+		width = CH_20_MHZ_WIDTH;
-+		sub_ch = NO_EXT_CHANNEL;
-+		break;
-+	case NL80211_CHAN_WIDTH_40:
-+		width = CH_40_MHZ_WIDTH;
-+		if (conf->chandef.center_freq1 > channel->center_freq)
-+			sub_ch = EXT_CH_ABOVE_CTRL_CH;
-+		else
-+			sub_ch = EXT_CH_BELOW_CTRL_CH;
-+		break;
-+	case NL80211_CHAN_WIDTH_80:
-+		width = CH_80_MHZ_WIDTH;
-+		if (conf->chandef.center_freq1 > channel->center_freq)
-+			sub_ch = EXT_CH_ABOVE_CTRL_CH;
-+		else
-+			sub_ch = EXT_CH_BELOW_CTRL_CH;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	if (priv->chip_type == MWL8997) {
-+		mwl_fwcmd_get_tx_powers(priv, priv->target_powers,
-+					HOSTCMD_ACT_GET_TARGET_TX_PWR,
-+					channel->hw_value, band, width, sub_ch);
-+
-+		for (i = 0; i < priv->pwr_level; i++) {
-+			tmp = priv->target_powers[i];
-+			txpow[i] = ((tmp - reduce_val) > 0) ?
-+				(tmp - reduce_val) : 0;
-+		}
-+
-+		rc = mwl_fwcmd_set_tx_powers(priv, txpow,
-+					     HOSTCMD_ACT_SET_TARGET_TX_PWR,
-+					     channel->hw_value, band,
-+					     width, sub_ch);
-+
-+		return rc;
-+	}
-+
-+	/* search tx power table if exist */
-+	for (index = 0; index < SYSADPT_MAX_NUM_CHANNELS; index++) {
-+		struct mwl_tx_pwr_tbl *tx_pwr;
-+
-+		tx_pwr = &priv->tx_pwr_tbl[index];
-+
-+		/* do nothing if table is not loaded */
-+		if (tx_pwr->channel == 0)
-+			break;
-+
-+		if (tx_pwr->channel == channel->hw_value) {
-+			priv->cdd = tx_pwr->cdd;
-+			priv->txantenna2 = tx_pwr->txantenna2;
-+
-+			if (tx_pwr->setcap)
-+				priv->powinited = MWL_POWER_INIT_1;
-+			else
-+				priv->powinited = MWL_POWER_INIT_2;
-+
-+			for (i = 0; i < priv->pwr_level; i++) {
-+				if (tx_pwr->setcap)
-+					priv->max_tx_pow[i] =
-+						tx_pwr->tx_power[i];
-+				else
-+					priv->target_powers[i] =
-+						tx_pwr->tx_power[i];
-+			}
-+
-+			found = 1;
-+			break;
-+		}
-+	}
-+
-+	if ((priv->powinited & MWL_POWER_INIT_2) == 0) {
-+		mwl_fwcmd_get_tx_powers(priv, priv->max_tx_pow,
-+					HOSTCMD_ACT_GEN_GET_LIST,
-+					channel->hw_value, band, width, sub_ch);
-+
-+		priv->powinited |= MWL_POWER_INIT_2;
-+	}
-+
-+	if ((priv->powinited & MWL_POWER_INIT_1) == 0) {
-+		mwl_fwcmd_get_tx_powers(priv, priv->target_powers,
-+					HOSTCMD_ACT_GEN_GET_LIST,
-+					channel->hw_value, band, width, sub_ch);
-+
-+		priv->powinited |= MWL_POWER_INIT_1;
-+	}
-+
-+	for (i = 0; i < priv->pwr_level; i++) {
-+		if (found) {
-+			if ((priv->tx_pwr_tbl[index].setcap) &&
-+			    (priv->tx_pwr_tbl[index].tx_power[i] >
-+			    priv->max_tx_pow[i]))
-+				tmp = priv->max_tx_pow[i];
-+			else
-+				tmp = priv->tx_pwr_tbl[index].tx_power[i];
-+		} else {
-+			if (priv->target_powers[i] > priv->max_tx_pow[i])
-+				tmp = priv->max_tx_pow[i];
-+			else
-+				tmp = priv->target_powers[i];
-+		}
-+
-+		txpow[i] = ((tmp - reduce_val) > 0) ? (tmp - reduce_val) : 0;
-+	}
-+
-+	rc = mwl_fwcmd_set_tx_powers(priv, txpow, HOSTCMD_ACT_GEN_SET_LIST,
-+				     channel->hw_value, band, width, sub_ch);
-+
-+	return rc;
-+}
-+
-+int mwl_fwcmd_rf_antenna(struct ieee80211_hw *hw, int dir, int antenna)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_802_11_rf_antenna *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_802_11_rf_antenna *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_RF_ANTENNA);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	pcmd->action = cpu_to_le16(dir);
-+
-+	if (dir == WL_ANTENNATYPE_RX) {
-+		u8 rx_antenna;
-+
-+		if (priv->chip_type == MWL8964) {
-+			if (antenna == ANTENNA_RX_4_AUTO)
-+				rx_antenna = 0xf;
-+			else if (antenna == ANTENNA_RX_3)
-+				rx_antenna = 7;
-+			else if (antenna == ANTENNA_RX_2)
-+				rx_antenna = 4;
-+			else
-+				rx_antenna = 1;
-+
-+			pcmd->antenna_mode = cpu_to_le16(rx_antenna);
-+		} else {
-+			rx_antenna = 4;
-+
-+			if (antenna != 0)
-+				pcmd->antenna_mode = cpu_to_le16(antenna);
-+			else
-+				pcmd->antenna_mode = cpu_to_le16(rx_antenna);
-+		}
-+	} else {
-+		u8 tx_antenna = 0xf;
-+
-+		if (antenna != 0)
-+			pcmd->antenna_mode = cpu_to_le16(antenna);
-+		else
-+			pcmd->antenna_mode = cpu_to_le16(tx_antenna);
-+	}
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_802_11_RF_ANTENNA)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_broadcast_ssid_enable(struct ieee80211_hw *hw,
-+				    struct ieee80211_vif *vif, bool enable)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_broadcast_ssid_enable *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_broadcast_ssid_enable *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BROADCAST_SSID_ENABLE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+	pcmd->enable = cpu_to_le32(enable);
-+	if (priv->chip_type == MWL8997)
-+		pcmd->hidden_ssid_info = enable ? 0 : 2;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_BROADCAST_SSID_ENABLE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_cfg_data(struct ieee80211_hw *hw, u16 type)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_cfg *pcmd;
-+
-+	if (!priv->cal_data)
-+		return 0;
-+
-+	pcmd = (struct hostcmd_cmd_set_cfg *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->data_len = mwl_fwcmd_parse_cal_cfg(priv->cal_data->data,
-+						 priv->cal_data->size,
-+						 pcmd->data);
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_CFG);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd) +
-+		le16_to_cpu(pcmd->data_len) - sizeof(pcmd->data));
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_GEN_SET);
-+	pcmd->type = cpu_to_le16(type);
-+
-+	utils_dump_data_debug("CalData:", pcmd->data,
-+			      le16_to_cpu(pcmd->data_len));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_CFG)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		release_firmware(priv->cal_data);
-+		priv->cal_data = NULL;
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	release_firmware(priv->cal_data);
-+	priv->cal_data = NULL;
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_rf_channel(struct ieee80211_hw *hw,
-+			     struct ieee80211_conf *conf)
-+{
-+	struct ieee80211_channel *channel = conf->chandef.chan;
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_rf_channel *pcmd;
-+	u32 chnl_flags, freq_band, chnl_width, act_primary;
-+
-+	pcmd = (struct hostcmd_cmd_set_rf_channel *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	if (priv->chip_type == MWL8997) {
-+		memset(pcmd, 0x00,
-+		       sizeof(struct hostcmd_cmd_set_rf_channel_kf2));
-+		pcmd->cmd_hdr.len = cpu_to_le16(
-+			sizeof(struct hostcmd_cmd_set_rf_channel_kf2));
-+	} else {
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	}
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_RF_CHANNEL);
-+	pcmd->action = cpu_to_le16(WL_SET);
-+	pcmd->curr_chnl = channel->hw_value;
-+
-+	if (channel->band == NL80211_BAND_2GHZ) {
-+		freq_band = FREQ_BAND_2DOT4GHZ;
-+	} else if (channel->band == NL80211_BAND_5GHZ) {
-+		freq_band = FREQ_BAND_5GHZ;
-+	} else {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EINVAL;
-+	}
-+
-+	switch (conf->chandef.width) {
-+	case NL80211_CHAN_WIDTH_20_NOHT:
-+	case NL80211_CHAN_WIDTH_20:
-+		chnl_width = CH_20_MHZ_WIDTH;
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		break;
-+	case NL80211_CHAN_WIDTH_40:
-+		chnl_width = CH_40_MHZ_WIDTH;
-+		if (conf->chandef.center_freq1 > channel->center_freq)
-+			act_primary = ACT_PRIMARY_CHAN_0;
-+		else
-+			act_primary = ACT_PRIMARY_CHAN_1;
-+		break;
-+	case NL80211_CHAN_WIDTH_80:
-+		chnl_width = CH_80_MHZ_WIDTH;
-+		act_primary =
-+			mwl_fwcmd_get_80m_pri_chnl(pcmd->curr_chnl);
-+		break;
-+	case NL80211_CHAN_WIDTH_160:
-+		chnl_width = CH_160_MHZ_WIDTH;
-+		act_primary =
-+			mwl_fwcmd_get_160m_pri_chnl(pcmd->curr_chnl);
-+		break;
-+	default:
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EINVAL;
-+	}
-+
-+	chnl_flags = (freq_band & FREQ_BAND_MASK) |
-+		((chnl_width << CHNL_WIDTH_SHIFT) & CHNL_WIDTH_MASK) |
-+		((act_primary << ACT_PRIMARY_SHIFT) & ACT_PRIMARY_MASK);
-+
-+	pcmd->chnl_flags = cpu_to_le32(chnl_flags);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_RF_CHANNEL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (pcmd->cmd_hdr.result != 0) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EINVAL;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	if (priv->sw_scanning) {
-+		priv->survey_info_idx++;
-+		mwl_fwcmd_get_survey(hw, priv->survey_info_idx);
-+	} else {
-+		mwl_fwcmd_get_survey(hw, 0);
-+		memset(&priv->cur_survey_info, 0,
-+		       sizeof(struct mwl_survey_info));
-+	}
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_aid(struct ieee80211_hw *hw,
-+		      struct ieee80211_vif *vif, u8 *bssid, u16 aid)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_aid *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_aid *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_AID);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+	pcmd->aid = cpu_to_le16(aid);
-+	ether_addr_copy(pcmd->mac_addr, bssid);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_AID)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_infra_mode(struct ieee80211_hw *hw,
-+			     struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_infra_mode *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_infra_mode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_INFRA_MODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_INFRA_MODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_rts_threshold(struct ieee80211_hw *hw, int threshold)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_802_11_rts_thsd *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_802_11_rts_thsd *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_RTS_THSD);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action  = cpu_to_le16(WL_SET);
-+	pcmd->threshold = cpu_to_le16(threshold);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_802_11_RTS_THSD)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_edca_params(struct ieee80211_hw *hw, u8 index,
-+			      u16 cw_min, u16 cw_max, u8 aifs, u16 txop)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_edca_params *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_edca_params *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_EDCA_PARAMS);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	pcmd->action = cpu_to_le16(0xffff);
-+	pcmd->txop = cpu_to_le16(txop);
-+	pcmd->cw_max = cpu_to_le32(cw_max);
-+	pcmd->cw_min = cpu_to_le32(cw_min);
-+	pcmd->aifsn = aifs;
-+	pcmd->txq_num = index;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_EDCA_PARAMS)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_radar_detect(struct ieee80211_hw *hw, u16 action)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_802_11h_detect_radar *pcmd;
-+	u16 radar_type = RADAR_TYPE_CODE_0;
-+	u8 channel = hw->conf.chandef.chan->hw_value;
-+
-+	pcmd = (struct hostcmd_cmd_802_11h_detect_radar *)&priv->pcmd_buf[0];
-+
-+	if (priv->dfs_region == NL80211_DFS_JP) {
-+		if (channel >= 52 && channel <= 64)
-+			radar_type = RADAR_TYPE_CODE_53;
-+		else if (channel >= 100 && channel <= 140)
-+			radar_type = RADAR_TYPE_CODE_56;
-+		else
-+			radar_type = RADAR_TYPE_CODE_0;
-+	} else if (priv->dfs_region == NL80211_DFS_ETSI) {
-+		radar_type = RADAR_TYPE_CODE_ETSI;
-+	}
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11H_DETECT_RADAR);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(action);
-+	pcmd->radar_type_code = cpu_to_le16(radar_type);
-+	pcmd->min_chirp_cnt = cpu_to_le16(priv->dfs_chirp_count_min);
-+	pcmd->chirp_time_intvl = cpu_to_le16(priv->dfs_chirp_time_interval);
-+	pcmd->pw_filter = cpu_to_le16(priv->dfs_pw_filter);
-+	pcmd->min_num_radar = cpu_to_le16(priv->dfs_min_num_radar);
-+	pcmd->pri_min_num = cpu_to_le16(priv->dfs_min_pri_count);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_802_11H_DETECT_RADAR)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_wmm_mode *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_wmm_mode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_WMM_MODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(enable ? WL_ENABLE : WL_DISABLE);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_WMM_MODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_ht_guard_interval(struct ieee80211_hw *hw, u32 gi_type)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_ht_guard_interval *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_ht_guard_interval *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_HT_GUARD_INTERVAL);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le32(WL_SET);
-+	pcmd->gi_type = cpu_to_le32(gi_type);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_HT_GUARD_INTERVAL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_use_fixed_rate(struct ieee80211_hw *hw, int mcast, int mgmt)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_fixed_rate *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_fixed_rate *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_FIXED_RATE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	pcmd->action = cpu_to_le32(HOSTCMD_ACT_NOT_USE_FIXED_RATE);
-+	pcmd->multicast_rate = mcast;
-+	pcmd->management_rate = mgmt;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_FIXED_RATE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_linkadapt_cs_mode(struct ieee80211_hw *hw, u16 cs_mode)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_linkadapt_cs_mode *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_linkadapt_cs_mode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_LINKADAPT_CS_MODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action  = cpu_to_le16(HOSTCMD_ACT_GEN_SET);
-+	pcmd->cs_mode = cpu_to_le16(cs_mode);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_LINKADAPT_CS_MODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_dump_otp_data(struct ieee80211_hw *hw)
-+{
-+	int otp_data_len;
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_dump_otp_data *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_dump_otp_data *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_DUMP_OTP_DATA);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_DUMP_OTP_DATA)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	otp_data_len = pcmd->cmd_hdr.len - cpu_to_le16(sizeof(*pcmd));
-+
-+	if (otp_data_len <= SYSADPT_OTP_BUF_SIZE) {
-+		wiphy_info(hw->wiphy, "OTP data len = %d\n", otp_data_len);
-+		priv->otp_data.len = otp_data_len;
-+		memcpy(priv->otp_data.buf, pcmd->pload, otp_data_len);
-+	} else {
-+		wiphy_err(hw->wiphy, "Driver OTP buf size is less\n");
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_rate_adapt_mode(struct ieee80211_hw *hw, u16 mode)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_rate_adapt_mode *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_rate_adapt_mode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_RATE_ADAPT_MODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(WL_SET);
-+	pcmd->rate_adapt_mode = cpu_to_le16(mode);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_RATE_ADAPT_MODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_mac_addr_client(struct ieee80211_hw *hw,
-+				  struct ieee80211_vif *vif, u8 *mac_addr)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_mac_addr *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_mac_addr *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_MAC_ADDR);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+	pcmd->mac_type = cpu_to_le16(WL_MAC_TYPE_SECONDARY_CLIENT);
-+	ether_addr_copy(pcmd->mac_addr, mac_addr);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_MAC_ADDR)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_watchdog_bitmap *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_watchdog_bitmap *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_WATCHDOG_BITMAP);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_GET_WATCHDOG_BITMAP)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	*bitmap = pcmd->watchdog_bitmap;
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_remove_mac_addr(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif, u8 *mac_addr)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_mac_addr *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_mac_addr *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_DEL_MAC_ADDR);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+	ether_addr_copy(pcmd->mac_addr, mac_addr);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_DEL_MAC_ADDR)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_bss_start(struct ieee80211_hw *hw,
-+			struct ieee80211_vif *vif, bool enable)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_bss_start *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	if (enable && (priv->running_bsses & (1 << mwl_vif->macid)))
-+		return 0;
-+
-+	if (!enable && !(priv->running_bsses & (1 << mwl_vif->macid)))
-+		return 0;
-+
-+	pcmd = (struct hostcmd_cmd_bss_start *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BSS_START);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	if (enable) {
-+		pcmd->enable = cpu_to_le32(WL_ENABLE);
-+	} else {
-+		if (mwl_vif->macid == 0)
-+			pcmd->enable = cpu_to_le32(WL_DISABLE);
-+		else
-+			pcmd->enable = cpu_to_le32(WL_DISABLE_VMAC);
-+	}
-+	if (priv->chip_type == MWL8964)
-+		pcmd->amsdu = MWL_AMSDU_SIZE_11K;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_BSS_START)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (enable)
-+		priv->running_bsses |= (1 << mwl_vif->macid);
-+	else
-+		priv->running_bsses &= ~(1 << mwl_vif->macid);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_beacon(struct ieee80211_hw *hw,
-+			 struct ieee80211_vif *vif, u8 *beacon, int len)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct beacon_info *b_inf;
-+	int rc;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	b_inf = &mwl_vif->beacon_info;
-+
-+	mwl_fwcmd_parse_beacon(priv, mwl_vif, beacon, len);
-+
-+	if (!b_inf->valid)
-+		goto err;
-+
-+	if (mwl_fwcmd_set_ies(priv, mwl_vif))
-+		goto err;
-+
-+	if (mwl_fwcmd_set_wsc_ie(hw, b_inf->ie_wsc_len, b_inf->ie_wsc_ptr))
-+		goto err;
-+
-+	if (mwl_fwcmd_set_ap_beacon(priv, mwl_vif, &vif->bss_conf))
-+		goto err;
-+
-+	if (b_inf->cap_info & WLAN_CAPABILITY_SPECTRUM_MGMT)
-+		rc = mwl_fwcmd_set_spectrum_mgmt(priv, true);
-+	else
-+		rc = mwl_fwcmd_set_spectrum_mgmt(priv, false);
-+	if (rc)
-+		goto err;
-+
-+	if (b_inf->power_constraint)
-+		rc = mwl_fwcmd_set_power_constraint(priv,
-+						    b_inf->power_constraint);
-+	if (rc)
-+		goto err;
-+
-+	if (mwl_fwcmd_set_country_code(priv, mwl_vif, &vif->bss_conf))
-+		goto err;
-+
-+	b_inf->valid = false;
-+
-+	return 0;
-+
-+err:
-+
-+	b_inf->valid = false;
-+
-+	return -EIO;
-+}
-+
-+int mwl_fwcmd_set_new_stn_add(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif,
-+			      struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct mwl_sta *sta_info;
-+	struct hostcmd_cmd_set_new_stn *pcmd;
-+	u32 rates;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	sta_info = mwl_dev_get_sta(sta);
-+
-+	pcmd = (struct hostcmd_cmd_set_new_stn *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_NEW_STN);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_STA_ACTION_ADD);
-+	pcmd->aid = cpu_to_le16(sta->aid);
-+	pcmd->stn_id = cpu_to_le16(sta_info->stnid);
-+	if (priv->chip_type == MWL8997)
-+		pcmd->if_type = cpu_to_le16(vif->type);
-+	else
-+		pcmd->if_type = cpu_to_le16(1);
-+	ether_addr_copy(pcmd->mac_addr, sta->addr);
-+
-+	if (hw->conf.chandef.chan->band == NL80211_BAND_2GHZ)
-+		rates = sta->supp_rates[NL80211_BAND_2GHZ];
-+	else
-+		rates = sta->supp_rates[NL80211_BAND_5GHZ] << 5;
-+	pcmd->peer_info.legacy_rate_bitmap = cpu_to_le32(rates);
-+
-+	if (sta->ht_cap.ht_supported) {
-+		int i;
-+
-+		for (i = 0; i < 4; i++) {
-+			if (i < sta->rx_nss) {
-+				pcmd->peer_info.ht_rates[i] =
-+					sta->ht_cap.mcs.rx_mask[i];
-+			} else {
-+				pcmd->peer_info.ht_rates[i] = 0;
-+			}
-+		}
-+		pcmd->peer_info.ht_cap_info = cpu_to_le16(sta->ht_cap.cap);
-+		pcmd->peer_info.mac_ht_param_info =
-+			(sta->ht_cap.ampdu_factor & 3) |
-+			((sta->ht_cap.ampdu_density & 7) << 2);
-+	}
-+
-+	if (sta->vht_cap.vht_supported) {
-+		u32 rx_mcs_map_mask = 0;
-+
-+		rx_mcs_map_mask = ((0x0000FFFF) >> (sta->rx_nss * 2))
-+			<< (sta->rx_nss * 2);
-+		pcmd->peer_info.vht_max_rx_mcs =
-+			cpu_to_le32((*((u32 *)
-+			&sta->vht_cap.vht_mcs.rx_mcs_map)) | rx_mcs_map_mask);
-+		pcmd->peer_info.vht_cap = cpu_to_le32(sta->vht_cap.cap);
-+		pcmd->peer_info.vht_rx_channel_width = sta->bandwidth;
-+	}
-+
-+	pcmd->is_qos_sta = sta->wme;
-+	pcmd->qos_info = ((sta->uapsd_queues << 4) | (sta->max_sp << 1));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (vif->type == NL80211_IFTYPE_STATION) {
-+		ether_addr_copy(pcmd->mac_addr, mwl_vif->sta_mac);
-+		pcmd->aid = cpu_to_le16(sta->aid + 1);
-+		pcmd->stn_id = cpu_to_le16(sta_info->sta_stnid);
-+		pcmd->if_type = cpu_to_le16(0);
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EIO;
-+		}
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_new_stn_add_sc4(struct ieee80211_hw *hw,
-+				  struct ieee80211_vif *vif,
-+				  struct ieee80211_sta *sta,
-+				  u32 wds)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct mwl_sta *sta_info;
-+	struct hostcmd_cmd_set_new_stn_sc4 *pcmd;
-+	u32 rates;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	sta_info = mwl_dev_get_sta(sta);
-+
-+	pcmd = (struct hostcmd_cmd_set_new_stn_sc4 *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_NEW_STN);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_STA_ACTION_ADD);
-+	pcmd->aid = cpu_to_le16(sta->aid);
-+	pcmd->stn_id = cpu_to_le16(sta_info->stnid);
-+	ether_addr_copy(pcmd->mac_addr, sta->addr);
-+
-+	if (hw->conf.chandef.chan->band == NL80211_BAND_2GHZ)
-+		rates = sta->supp_rates[NL80211_BAND_2GHZ];
-+	else
-+		rates = sta->supp_rates[NL80211_BAND_5GHZ] << 5;
-+	pcmd->peer_info.legacy_rate_bitmap = cpu_to_le32(rates);
-+
-+	if (sta->ht_cap.ht_supported) {
-+		int i;
-+
-+		for (i = 0; i < 4; i++) {
-+			if (i < sta->rx_nss) {
-+				pcmd->peer_info.ht_rates[i] =
-+					sta->ht_cap.mcs.rx_mask[i];
-+			} else {
-+				pcmd->peer_info.ht_rates[i] = 0;
-+			}
-+		}
-+		pcmd->peer_info.ht_cap_info = cpu_to_le16(sta->ht_cap.cap);
-+		pcmd->peer_info.mac_ht_param_info =
-+			(sta->ht_cap.ampdu_factor & 3) |
-+			((sta->ht_cap.ampdu_density & 7) << 2);
-+	}
-+
-+	if (sta->vht_cap.vht_supported) {
-+		u32 rx_mcs_map_mask = 0;
-+
-+		rx_mcs_map_mask = ((0x0000FFFF) >> (sta->rx_nss * 2))
-+			<< (sta->rx_nss * 2);
-+		pcmd->peer_info.vht_max_rx_mcs =
-+			cpu_to_le32((*((u32 *)
-+			&sta->vht_cap.vht_mcs.rx_mcs_map)) | rx_mcs_map_mask);
-+		pcmd->peer_info.vht_cap = cpu_to_le32(sta->vht_cap.cap);
-+		pcmd->peer_info.vht_rx_channel_width = sta->bandwidth;
-+	}
-+
-+	pcmd->is_qos_sta = sta->wme;
-+	pcmd->qos_info = ((sta->uapsd_queues << 4) | (sta->max_sp << 1));
-+	pcmd->wds = cpu_to_le32(wds);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (vif->type == NL80211_IFTYPE_STATION) {
-+		ether_addr_copy(pcmd->mac_addr, mwl_vif->sta_mac);
-+		pcmd->aid = cpu_to_le16(sta->aid + 1);
-+		pcmd->stn_id = cpu_to_le16(sta_info->sta_stnid);
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EIO;
-+		}
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_new_stn_wds_sc4(struct ieee80211_hw *hw, u8 *addr)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_new_stn_sc4 *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_new_stn_sc4 *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_NEW_STN);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_STA_ACTION_MODIFY);
-+	ether_addr_copy(pcmd->mac_addr, addr);
-+	pcmd->wds = cpu_to_le32(WDS_MODE);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_new_stn_add_self(struct ieee80211_hw *hw,
-+				   struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_new_stn *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_new_stn *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	if (priv->chip_type == MWL8964) {
-+		memset(pcmd, 0x00, sizeof(struct hostcmd_cmd_set_new_stn_sc4));
-+		pcmd->cmd_hdr.len =
-+			cpu_to_le16(sizeof(struct hostcmd_cmd_set_new_stn_sc4));
-+	} else {
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	}
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_NEW_STN);
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_STA_ACTION_ADD);
-+	ether_addr_copy(pcmd->mac_addr, vif->addr);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_new_stn_del(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif, u8 *addr)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_new_stn *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_new_stn *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	if (priv->chip_type == MWL8964) {
-+		memset(pcmd, 0x00, sizeof(struct hostcmd_cmd_set_new_stn_sc4));
-+		pcmd->cmd_hdr.len =
-+			cpu_to_le16(sizeof(struct hostcmd_cmd_set_new_stn_sc4));
-+	} else {
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	}
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_NEW_STN);
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	pcmd->action = cpu_to_le16(HOSTCMD_ACT_STA_ACTION_REMOVE);
-+	ether_addr_copy(pcmd->mac_addr, addr);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (vif->type == NL80211_IFTYPE_STATION) {
-+		ether_addr_copy(pcmd->mac_addr, mwl_vif->sta_mac);
-+
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_NEW_STN)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EIO;
-+		}
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_apmode(struct ieee80211_hw *hw, u8 apmode)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_apmode *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_apmode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_APMODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->apmode = apmode;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_APMODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_switch_channel(struct ieee80211_hw *hw,
-+				 struct ieee80211_channel_switch *ch_switch)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_switch_channel *pcmd;
-+	struct cfg80211_chan_def *chandef = &ch_switch->chandef;
-+	struct ieee80211_channel *channel = chandef->chan;
-+	u32 chnl_flags, freq_band, chnl_width, act_primary, sec_chnl_offset;
-+
-+	if (priv->csa_active)
-+		return 0;
-+
-+	if (channel->band == NL80211_BAND_2GHZ)
-+		freq_band = FREQ_BAND_2DOT4GHZ;
-+	else if (channel->band == NL80211_BAND_5GHZ)
-+		freq_band = FREQ_BAND_5GHZ;
-+	else
-+		return -EINVAL;
-+
-+	switch (chandef->width) {
-+	case NL80211_CHAN_WIDTH_20_NOHT:
-+	case NL80211_CHAN_WIDTH_20:
-+		chnl_width = CH_20_MHZ_WIDTH;
-+		act_primary = ACT_PRIMARY_CHAN_0;
-+		sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
-+		break;
-+	case NL80211_CHAN_WIDTH_40:
-+		chnl_width = CH_40_MHZ_WIDTH;
-+		if (chandef->center_freq1 > channel->center_freq) {
-+			act_primary = ACT_PRIMARY_CHAN_0;
-+			sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-+		} else {
-+			act_primary = ACT_PRIMARY_CHAN_1;
-+			sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-+		}
-+		break;
-+	case NL80211_CHAN_WIDTH_80:
-+		chnl_width = CH_80_MHZ_WIDTH;
-+		act_primary =
-+			mwl_fwcmd_get_80m_pri_chnl(channel->hw_value);
-+		if ((act_primary == ACT_PRIMARY_CHAN_0) ||
-+		    (act_primary == ACT_PRIMARY_CHAN_2))
-+			sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-+		else
-+			sec_chnl_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	chnl_flags = (freq_band & FREQ_BAND_MASK) |
-+		((chnl_width << CHNL_WIDTH_SHIFT) & CHNL_WIDTH_MASK) |
-+		((act_primary << ACT_PRIMARY_SHIFT) & ACT_PRIMARY_MASK);
-+
-+	pcmd = (struct hostcmd_cmd_set_switch_channel *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_SWITCH_CHANNEL);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->next_11h_chnl = cpu_to_le32(channel->hw_value);
-+	pcmd->mode = cpu_to_le32(ch_switch->block_tx);
-+	pcmd->init_count = cpu_to_le32(ch_switch->count + 1);
-+	pcmd->chnl_flags = cpu_to_le32(chnl_flags);
-+	pcmd->next_ht_extchnl_offset = cpu_to_le32(sec_chnl_offset);
-+	pcmd->dfs_test_mode = cpu_to_le32(priv->dfs_test);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_SWITCH_CHANNEL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	priv->csa_active = true;
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_update_encryption_enable(struct ieee80211_hw *hw,
-+				       struct ieee80211_vif *vif,
-+				       u8 *addr, u8 encr_type)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_update_encryption *pcmd;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_update_encryption *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_UPDATE_ENCRYPTION);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	pcmd->action_type = cpu_to_le32(ENCR_ACTION_ENABLE_HW_ENCR);
-+	ether_addr_copy(pcmd->mac_addr, addr);
-+	pcmd->action_data[0] = encr_type;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_UPDATE_ENCRYPTION)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if ((vif->type == NL80211_IFTYPE_STATION) &&
-+	    (priv->chip_type != MWL8964)) {
-+		if (ether_addr_equal(mwl_vif->bssid, addr))
-+			ether_addr_copy(pcmd->mac_addr, mwl_vif->sta_mac);
-+		else
-+			ether_addr_copy(pcmd->mac_addr, mwl_vif->bssid);
-+
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_UPDATE_ENCRYPTION)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EIO;
-+		}
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_encryption_set_key(struct ieee80211_hw *hw,
-+				 struct ieee80211_vif *vif, u8 *addr,
-+				 struct ieee80211_key_conf *key)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_key *pcmd;
-+	int rc;
-+	int keymlen;
-+	u32 action;
-+	u8 idx;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_key *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_UPDATE_ENCRYPTION);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	rc = mwl_fwcmd_encryption_set_cmd_info(pcmd, addr, key);
-+	if (rc) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		if (rc != 1)
-+			wiphy_err(hw->wiphy, "encryption not support\n");
-+		return rc;
-+	}
-+
-+	idx = key->keyidx;
-+
-+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
-+		action = ENCR_ACTION_TYPE_SET_KEY;
-+	else {
-+		action = ENCR_ACTION_TYPE_SET_GROUP_KEY;
-+		if (vif->type == NL80211_IFTYPE_MESH_POINT &&
-+		    !ether_addr_equal(mwl_vif->bssid, addr))
-+			pcmd->key_param.key_info |=
-+				cpu_to_le32(ENCR_KEY_FLAG_RXGROUPKEY);
-+	}
-+
-+	switch (key->cipher) {
-+	case WLAN_CIPHER_SUITE_WEP40:
-+	case WLAN_CIPHER_SUITE_WEP104:
-+		if (!mwl_vif->wep_key_conf[idx].enabled) {
-+			memcpy(mwl_vif->wep_key_conf[idx].key, key,
-+			       sizeof(*key) + key->keylen);
-+			mwl_vif->wep_key_conf[idx].enabled = 1;
-+		}
-+
-+		keymlen = key->keylen;
-+		action = ENCR_ACTION_TYPE_SET_KEY;
-+		break;
-+	case WLAN_CIPHER_SUITE_TKIP:
-+		keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH;
-+		break;
-+	case WLAN_CIPHER_SUITE_CCMP:
-+		keymlen = key->keylen;
-+		break;
-+	default:
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		wiphy_err(hw->wiphy, "encryption not support\n");
-+		return -ENOTSUPP;
-+	}
-+
-+	memcpy((void *)&pcmd->key_param.key, key->key, keymlen);
-+	pcmd->action_type = cpu_to_le32(action);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_UPDATE_ENCRYPTION)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (vif->type == NL80211_IFTYPE_STATION) {
-+		if (ether_addr_equal(mwl_vif->bssid, addr))
-+			ether_addr_copy(pcmd->key_param.mac_addr,
-+					mwl_vif->sta_mac);
-+		else
-+			ether_addr_copy(pcmd->key_param.mac_addr,
-+					mwl_vif->bssid);
-+
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_UPDATE_ENCRYPTION)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EIO;
-+		}
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_encryption_remove_key(struct ieee80211_hw *hw,
-+				    struct ieee80211_vif *vif, u8 *addr,
-+				    struct ieee80211_key_conf *key)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_set_key *pcmd;
-+	int rc;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_set_key *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_UPDATE_ENCRYPTION);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+
-+	rc = mwl_fwcmd_encryption_set_cmd_info(pcmd, addr, key);
-+	if (rc) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		if (rc != 1)
-+			wiphy_err(hw->wiphy, "encryption not support\n");
-+		return rc;
-+	}
-+
-+	pcmd->action_type = cpu_to_le32(ENCR_ACTION_TYPE_REMOVE_KEY);
-+
-+	if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-+	    key->cipher == WLAN_CIPHER_SUITE_WEP104)
-+		mwl_vif->wep_key_conf[key->keyidx].enabled = 0;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_UPDATE_ENCRYPTION)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_check_ba(struct ieee80211_hw *hw,
-+		       struct mwl_ampdu_stream *stream,
-+		       struct ieee80211_vif *vif,
-+		       u32 direction)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_bastream *pcmd;
-+	u32 ba_flags, ba_type, ba_direction;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_bastream *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BASTREAM);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+	pcmd->cmd_hdr.result = cpu_to_le16(0xffff);
-+
-+	pcmd->action_type = cpu_to_le32(BA_CHECK_STREAM);
-+	ether_addr_copy(&pcmd->ba_info.create_params.peer_mac_addr[0],
-+			stream->sta->addr);
-+	pcmd->ba_info.create_params.tid = stream->tid;
-+	ba_type = BA_FLAG_IMMEDIATE_TYPE;
-+	ba_direction = direction;
-+	ba_flags = (ba_type & BA_TYPE_MASK) |
-+		((ba_direction << BA_DIRECTION_SHIFT) & BA_DIRECTION_MASK);
-+	pcmd->ba_info.create_params.flags = cpu_to_le32(ba_flags);
-+	pcmd->ba_info.create_params.queue_id = stream->idx;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_BASTREAM)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (pcmd->cmd_hdr.result != 0) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EINVAL;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_create_ba(struct ieee80211_hw *hw,
-+			struct mwl_ampdu_stream *stream,
-+			struct ieee80211_vif *vif,
-+			u32 direction, u8 buf_size, u16 seqno, bool amsdu)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	struct hostcmd_cmd_bastream *pcmd;
-+	u32 ba_flags, ba_type, ba_direction;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	pcmd = (struct hostcmd_cmd_bastream *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BASTREAM);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_hdr.macid = mwl_vif->macid;
-+	pcmd->cmd_hdr.result = cpu_to_le16(0xffff);
-+
-+	pcmd->action_type = cpu_to_le32(BA_CREATE_STREAM);
-+	pcmd->ba_info.create_params.bar_thrs = cpu_to_le32(buf_size);
-+	pcmd->ba_info.create_params.window_size = cpu_to_le32(buf_size);
-+	pcmd->ba_info.create_params.idle_thrs = cpu_to_le32(0x22000);
-+	ether_addr_copy(&pcmd->ba_info.create_params.peer_mac_addr[0],
-+			stream->sta->addr);
-+	pcmd->ba_info.create_params.tid = stream->tid;
-+	ba_direction = direction;
-+	if (priv->chip_type == MWL8964) {
-+		ba_type = amsdu ? MWL_AMSDU_SIZE_11K : 0;
-+		ba_flags = (ba_type & BA_TYPE_MASK_NDP) |
-+			((ba_direction << BA_DIRECTION_SHIFT_NDP) &
-+			BA_DIRECTION_MASK_NDP);
-+	} else {
-+		ba_type = BA_FLAG_IMMEDIATE_TYPE;
-+		ba_flags = (ba_type & BA_TYPE_MASK) |
-+			((ba_direction << BA_DIRECTION_SHIFT) &
-+			BA_DIRECTION_MASK);
-+	}
-+	pcmd->ba_info.create_params.flags = cpu_to_le32(ba_flags);
-+	pcmd->ba_info.create_params.queue_id = stream->idx;
-+	pcmd->ba_info.create_params.param_info =
-+		(stream->sta->ht_cap.ampdu_factor &
-+		 IEEE80211_HT_AMPDU_PARM_FACTOR) |
-+		((stream->sta->ht_cap.ampdu_density << 2) &
-+		 IEEE80211_HT_AMPDU_PARM_DENSITY);
-+	if (direction == BA_FLAG_DIRECTION_UP) {
-+		pcmd->ba_info.create_params.reset_seq_no = 0;
-+		pcmd->ba_info.create_params.current_seq = cpu_to_le16(seqno);
-+	} else {
-+		pcmd->ba_info.create_params.reset_seq_no = 1;
-+		pcmd->ba_info.create_params.current_seq = cpu_to_le16(0);
-+	}
-+	if (priv->chip_type == MWL8964 &&
-+	    stream->sta->vht_cap.vht_supported) {
-+		pcmd->ba_info.create_params.vht_rx_factor =
-+			cpu_to_le32((stream->sta->vht_cap.cap  &
-+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
-+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
-+	}
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_BASTREAM)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (pcmd->cmd_hdr.result != 0) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		wiphy_err(hw->wiphy, "create ba result error %d\n",
-+			  le16_to_cpu(pcmd->cmd_hdr.result));
-+		return -EINVAL;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_destroy_ba(struct ieee80211_hw *hw,
-+			 struct mwl_ampdu_stream *stream,
-+			 u32 direction)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_bastream *pcmd;
-+	u32 ba_flags, ba_type, ba_direction;
-+
-+	pcmd = (struct hostcmd_cmd_bastream *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_BASTREAM);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	pcmd->action_type = cpu_to_le32(BA_DESTROY_STREAM);
-+	ba_type = 0;
-+	ba_direction = direction;
-+	if (priv->chip_type == MWL8964)
-+		ba_flags = (ba_type & BA_TYPE_MASK_NDP) |
-+			((ba_direction << BA_DIRECTION_SHIFT_NDP) &
-+			BA_DIRECTION_MASK_NDP);
-+	else
-+		ba_flags = (ba_type & BA_TYPE_MASK) |
-+			((ba_direction << BA_DIRECTION_SHIFT) &
-+			BA_DIRECTION_MASK);
-+	pcmd->ba_info.destroy_params.flags = cpu_to_le32(ba_flags);
-+	pcmd->ba_info.destroy_params.fw_ba_context.context =
-+		cpu_to_le32(stream->idx);
-+	pcmd->ba_info.destroy_params.tid = stream->tid;
-+	ether_addr_copy(&pcmd->ba_info.destroy_params.peer_mac_addr[0],
-+			stream->sta->addr);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_BASTREAM)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+/* caller must hold priv->stream_lock when calling the stream functions */
-+struct mwl_ampdu_stream *mwl_fwcmd_add_stream(struct ieee80211_hw *hw,
-+					      struct ieee80211_sta *sta,
-+					      u8 tid)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_ampdu_stream *stream;
-+	struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
-+	int idx;
-+
-+	if (priv->chip_type == MWL8964) {
-+		idx = ((sta_info->stnid - 1) * SYSADPT_MAX_TID) + tid;
-+
-+		if (idx < priv->ampdu_num) {
-+			stream = &priv->ampdu[idx];
-+			stream->sta = sta;
-+			stream->state = AMPDU_STREAM_NEW;
-+			stream->tid = tid;
-+			stream->idx = idx;
-+			return stream;
-+		}
-+	} else {
-+		for (idx = 0; idx < priv->ampdu_num; idx++) {
-+			stream = &priv->ampdu[idx];
-+
-+			if (stream->state == AMPDU_NO_STREAM) {
-+				stream->sta = sta;
-+				stream->state = AMPDU_STREAM_NEW;
-+				stream->tid = tid;
-+				stream->idx = idx;
-+				return stream;
-+			}
-+		}
-+	}
-+
-+	return NULL;
-+}
-+
-+void mwl_fwcmd_del_sta_streams(struct ieee80211_hw *hw,
-+			       struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_ampdu_stream *stream;
-+	struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
-+	int i, idx;
-+
-+	spin_lock_bh(&priv->stream_lock);
-+	if (priv->chip_type == MWL8964) {
-+		idx = (sta_info->stnid - 1) * SYSADPT_MAX_TID;
-+		for (i = 0; i < SYSADPT_MAX_TID; i++) {
-+			stream = &priv->ampdu[idx + i];
-+
-+			if (stream->sta == sta) {
-+				spin_unlock_bh(&priv->stream_lock);
-+				mwl_fwcmd_destroy_ba(hw, stream,
-+						     BA_FLAG_DIRECTION_UP);
-+				spin_lock_bh(&priv->stream_lock);
-+				mwl_fwcmd_remove_stream(hw, stream);
-+			}
-+		}
-+	} else {
-+		for (idx = 0; idx < priv->ampdu_num; idx++) {
-+			stream = &priv->ampdu[idx];
-+
-+			if (stream->sta == sta) {
-+				spin_unlock_bh(&priv->stream_lock);
-+				mwl_fwcmd_destroy_ba(hw, stream,
-+						     BA_FLAG_DIRECTION_UP);
-+				spin_lock_bh(&priv->stream_lock);
-+				mwl_fwcmd_remove_stream(hw, stream);
-+			}
-+		}
-+	}
-+	spin_unlock_bh(&priv->stream_lock);
-+}
-+
-+int mwl_fwcmd_start_stream(struct ieee80211_hw *hw,
-+			   struct mwl_ampdu_stream *stream)
-+{
-+	/* if the stream has already been started, don't start it again */
-+	if (stream->state != AMPDU_STREAM_NEW)
-+		return 0;
-+
-+	return ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0);
-+}
-+
-+void mwl_fwcmd_remove_stream(struct ieee80211_hw *hw,
-+			     struct mwl_ampdu_stream *stream)
-+{
-+	memset(stream, 0, sizeof(*stream));
-+}
-+
-+struct mwl_ampdu_stream *mwl_fwcmd_lookup_stream(struct ieee80211_hw *hw,
-+						 struct ieee80211_sta *sta,
-+						 u8 tid)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_ampdu_stream *stream;
-+	struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
-+	int idx;
-+
-+	if (priv->chip_type == MWL8964) {
-+		idx = ((sta_info->stnid - 1) * SYSADPT_MAX_TID) + tid;
-+		if (idx < priv->ampdu_num)
-+			return &priv->ampdu[idx];
-+	} else {
-+		for (idx = 0; idx < priv->ampdu_num; idx++) {
-+			stream = &priv->ampdu[idx];
-+			if (stream->state == AMPDU_NO_STREAM)
-+				continue;
-+
-+			if ((stream->sta == sta) && (stream->tid == tid))
-+				return stream;
-+		}
-+	}
-+
-+	return NULL;
-+}
-+
-+bool mwl_fwcmd_ampdu_allowed(struct ieee80211_sta *sta, u8 tid)
-+{
-+	struct mwl_sta *sta_info;
-+	struct mwl_tx_info *tx_stats;
-+
-+	if (WARN_ON(tid >= SYSADPT_MAX_TID))
-+		return false;
-+
-+	sta_info = mwl_dev_get_sta(sta);
-+
-+	tx_stats = &sta_info->tx_stats[tid];
-+
-+	return (sta_info->is_ampdu_allowed &&
-+		tx_stats->pkts > SYSADPT_AMPDU_PACKET_THRESHOLD);
-+}
-+
-+int mwl_fwcmd_set_optimization_level(struct ieee80211_hw *hw, u8 opt_level)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_optimization_level *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_optimization_level *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->opt_level = opt_level;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_wsc_ie(struct ieee80211_hw *hw, u8 len, u8 *data)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_wsc_ie *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_wsc_ie *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_WSC_IE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->len = cpu_to_le16(len);
-+	memcpy(pcmd->data, data, len);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_WSC_IE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	pcmd->ie_type = cpu_to_le16(WSC_IE_SET_PROBE_RESPONSE);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_WSC_IE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_ratetable(struct ieee80211_hw *hw, u8 *addr, u8 *rate_table,
-+			    u32 size, u8 type)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_ratetable *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_ratetable *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_RATETABLE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->type = type;
-+	ether_addr_copy(pcmd->addr, addr);
-+	memset(rate_table, 0x00, size);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_GET_RATETABLE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	memcpy(rate_table, &pcmd->sorted_rates_idx_map, size);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_seqno(struct ieee80211_hw *hw,
-+			struct mwl_ampdu_stream *stream, u16 *start_seqno)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_seqno *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_seqno *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_SEQNO);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	ether_addr_copy(pcmd->mac_addr, stream->sta->addr);
-+	pcmd->tid = stream->tid;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_GET_SEQNO)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	*start_seqno = le16_to_cpu(pcmd->seq_no);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_dwds_stamode(struct ieee80211_hw *hw, bool enable)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_dwds_enable *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_dwds_enable *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_DWDS_ENABLE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->enable = cpu_to_le32(enable);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_DWDS_ENABLE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_fw_flush_timer(struct ieee80211_hw *hw, u32 value)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_fw_flush_timer *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_fw_flush_timer *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_FW_FLUSH_TIMER);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->value = cpu_to_le32(value);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_FW_FLUSH_TIMER)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_cdd *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_cdd *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_CDD);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->enable = cpu_to_le32(priv->cdd);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_CDD)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_bftype(struct ieee80211_hw *hw, int mode)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_bftype *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_bftype *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_BFTYPE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le32(WL_SET);
-+	pcmd->mode = cpu_to_le32(mode);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_BFTYPE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_reg_cau(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_bbp_reg_access *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_bbp_reg_access *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_CAU_REG_ACCESS);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->offset = cpu_to_le16(reg);
-+	pcmd->action = cpu_to_le16(flag);
-+	pcmd->value = *val;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_CAU_REG_ACCESS)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	*val = pcmd->value;
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_temp(struct ieee80211_hw *hw, u32 *temp)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_temp *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_temp *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_TEMP);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_GET_TEMP)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	*temp = le32_to_cpu(pcmd->celcius);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_led_ctrl(struct ieee80211_hw *hw, u8 enable, u8 rate)
-+{
-+	struct hostcmd_cmd_led_ctrl  *pcmd;
-+	struct mwl_priv *priv = hw->priv;
-+
-+	pcmd = (struct hostcmd_cmd_led_ctrl *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_LED_CTRL);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = 1; /* 1: set */
-+	pcmd->led_enable = enable;
-+	pcmd->led_control = 1; /* 1: SW */
-+
-+	switch (rate) {
-+	case LED_BLINK_RATE_LOW:
-+	case LED_BLINK_RATE_MID:
-+	case LED_BLINK_RATE_HIGH:
-+		pcmd->led_blink_rate = rate;
-+		break;
-+	default:
-+		if (enable) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EINVAL;
-+		}
-+		break;
-+	}
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_LED_CTRL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_fw_region_code(struct ieee80211_hw *hw,
-+				 u32 *fw_region_code)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_fw_region_code *pcmd;
-+	u16 cmd;
-+	int status;
-+
-+	pcmd = (struct hostcmd_cmd_get_fw_region_code *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	cmd = HOSTCMD_CMD_GET_FW_REGION_CODE;
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(cmd);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, cmd)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (pcmd->cmd_hdr.result != 0) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EINVAL;
-+	}
-+
-+	status = le32_to_cpu(pcmd->status);
-+
-+	if (!status)
-+		*fw_region_code = le32_to_cpu(pcmd->fw_region_code);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_device_pwr_tbl(struct ieee80211_hw *hw,
-+				 struct mwl_device_pwr_tbl *device_ch_pwrtbl,
-+				 u8 *region_code,
-+				 u8 *number_of_channels,
-+				 u32 channel_index)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_device_pwr_tbl *pcmd;
-+	int status;
-+	u16 cmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_device_pwr_tbl *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	cmd = HOSTCMD_CMD_GET_DEVICE_PWR_TBL;
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(cmd);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->status = cpu_to_le16(cmd);
-+	pcmd->current_channel_index = cpu_to_le32(channel_index);
-+
-+	if (mwl_hif_exec_cmd(hw, cmd)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	device_ch_pwrtbl->channel = pcmd->channel_pwr_tbl.channel;
-+	memcpy(device_ch_pwrtbl->tx_pwr, pcmd->channel_pwr_tbl.tx_pwr,
-+	       priv->pwr_level);
-+	device_ch_pwrtbl->dfs_capable = pcmd->channel_pwr_tbl.dfs_capable;
-+	device_ch_pwrtbl->ax_ant = pcmd->channel_pwr_tbl.ax_ant;
-+	device_ch_pwrtbl->cdd = pcmd->channel_pwr_tbl.cdd;
-+	*region_code = pcmd->region_code;
-+	*number_of_channels = pcmd->number_of_channels;
-+	status = le16_to_cpu(pcmd->status);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return status;
-+}
-+
-+int mwl_fwcmd_set_rate_drop(struct ieee80211_hw *hw, int enable,
-+			    int value, int staid)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_set_rate_drop *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_set_rate_drop *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_SET_RATE_DROP);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->enable = cpu_to_le32(enable);
-+	pcmd->rate_index = cpu_to_le32(value);
-+	pcmd->sta_index = cpu_to_le32(staid);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_SET_RATE_DROP)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_newdp_dmathread_start(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_newdp_dmathread_start *pcmd;
-+	u16 cmd;
-+
-+	pcmd = (struct hostcmd_cmd_newdp_dmathread_start *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	cmd = HOSTCMD_CMD_NEWDP_DMATHREAD_START;
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(cmd);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, cmd)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+
-+int mwl_fwcmd_get_fw_region_code_sc4(struct ieee80211_hw *hw,
-+				     u32 *fw_region_code)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_fw_region_code_sc4 *pcmd;
-+	u16 cmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_fw_region_code_sc4 *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	cmd = HOSTCMD_CMD_GET_FW_REGION_CODE_SC4;
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(cmd);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+	if (mwl_hif_exec_cmd(hw, cmd)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	if (pcmd->cmd_hdr.result != 0) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EINVAL;
-+	}
-+
-+	if (pcmd->status)
-+		*fw_region_code = (pcmd->status == 1) ? 0 : pcmd->status;
-+	else
-+		*fw_region_code = le32_to_cpu(pcmd->fw_region_code);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_pwr_tbl_sc4(struct ieee80211_hw *hw,
-+			      struct mwl_device_pwr_tbl *device_ch_pwrtbl,
-+			      u8 *region_code,
-+			      u8 *number_of_channels,
-+			      u32 channel_index)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_device_pwr_tbl_sc4 *pcmd;
-+	int status;
-+	u16 cmd;
-+
-+	pcmd = (struct hostcmd_cmd_get_device_pwr_tbl_sc4 *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	cmd = HOSTCMD_CMD_GET_DEVICE_PWR_TBL_SC4;
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(cmd);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->status = cpu_to_le16(cmd);
-+	pcmd->current_channel_index = cpu_to_le32(channel_index);
-+
-+	if (mwl_hif_exec_cmd(hw, cmd)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	device_ch_pwrtbl->channel = pcmd->channel_pwr_tbl.channel;
-+	memcpy(device_ch_pwrtbl->tx_pwr, pcmd->channel_pwr_tbl.tx_pwr,
-+	       SYSADPT_TX_PWR_LEVEL_TOTAL_SC4);
-+	device_ch_pwrtbl->dfs_capable = pcmd->channel_pwr_tbl.dfs_capable;
-+	device_ch_pwrtbl->ax_ant = pcmd->channel_pwr_tbl.ax_ant;
-+	device_ch_pwrtbl->cdd = pcmd->channel_pwr_tbl.cdd;
-+	*region_code = pcmd->region_code;
-+	*number_of_channels = pcmd->number_of_channels;
-+	status = le16_to_cpu(pcmd->status);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return status;
-+}
-+
-+int mwl_fwcmd_quiet_mode(struct ieee80211_hw *hw, bool enable, u32 period,
-+			 u32 duration, u32 next_offset)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_quiet_mode *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_quiet_mode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_QUIET_MODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(WL_SET);
-+	pcmd->enable = cpu_to_le32(enable);
-+	if (enable) {
-+		pcmd->period = cpu_to_le32(period);
-+		pcmd->duration = cpu_to_le32(duration);
-+		pcmd->next_offset = cpu_to_le32(next_offset);
-+	}
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_QUIET_MODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_core_dump_diag_mode(struct ieee80211_hw *hw, u16 status)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_core_dump_diag_mode *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_core_dump_diag_mode *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_CORE_DUMP_DIAG_MODE);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->status = cpu_to_le16(status);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_CORE_DUMP_DIAG_MODE)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_fw_core_dump(struct ieee80211_hw *hw,
-+			       struct coredump_cmd *core_dump, char *buff)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_get_fw_core_dump *pcmd;
-+
-+	if (priv->chip_type != MWL8964)
-+		return -EPERM;
-+
-+	pcmd = (struct hostcmd_cmd_get_fw_core_dump *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_GET_FW_CORE_DUMP);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->cmd_data.coredump.context = core_dump->context;
-+	pcmd->cmd_data.coredump.buffer = cpu_to_le32(priv->pphys_cmd_buf +
-+		sizeof(struct hostcmd_cmd_get_fw_core_dump) -
-+		sizeof(struct hostcmd_cmd_get_fw_core_dump_));
-+	pcmd->cmd_data.coredump.buffer_len = cpu_to_le32(MAX_CORE_DUMP_BUFFER);
-+	pcmd->cmd_data.coredump.size_kb = core_dump->size_kb;
-+	pcmd->cmd_data.coredump.flags = core_dump->flags;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_GET_FW_CORE_DUMP)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	/* update core dump buffer */
-+	core_dump->context = pcmd->cmd_data.coredump.context;
-+	core_dump->size_kb = pcmd->cmd_data.coredump.size_kb;
-+	core_dump->flags = pcmd->cmd_data.coredump.flags;
-+	memcpy(buff,
-+	       (const void *)((u32)pcmd +
-+	       sizeof(struct hostcmd_cmd_get_fw_core_dump) -
-+	       sizeof(struct hostcmd_cmd_get_fw_core_dump_)),
-+	       MAX_CORE_DUMP_BUFFER);
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_slot_time(struct ieee80211_hw *hw, bool short_slot)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_802_11_slot_time *pcmd;
-+
-+	wiphy_debug(priv->hw->wiphy, "%s(): short_slot_time=%d\n",
-+		    __func__, short_slot);
-+
-+	pcmd = (struct hostcmd_cmd_802_11_slot_time *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_802_11_SLOT_TIME);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(WL_SET);
-+	pcmd->short_slot = cpu_to_le16(short_slot ? 1 : 0);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_802_11_SLOT_TIME)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_config_EDMACCtrl(struct ieee80211_hw *hw, int EDMAC_Ctrl)
-+{
-+	struct hostcmd_cmd_edmac_ctrl *pcmd;
-+	struct mwl_priv *priv = hw->priv;
-+
-+	pcmd = (struct hostcmd_cmd_edmac_ctrl *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_EDMAC_CTRL);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->action = cpu_to_le16(WL_SET);
-+	pcmd->ed_ctrl_2g = cpu_to_le16((EDMAC_Ctrl & EDMAC_2G_ENABLE_MASK)
-+				       >> EDMAC_2G_ENABLE_SHIFT);
-+	pcmd->ed_ctrl_5g = cpu_to_le16((EDMAC_Ctrl & EDMAC_5G_ENABLE_MASK)
-+				       >> EDMAC_5G_ENABLE_SHIFT);
-+	pcmd->ed_offset_2g = cpu_to_le16((EDMAC_Ctrl &
-+					 EDMAC_2G_THRESHOLD_OFFSET_MASK)
-+					 >> EDMAC_2G_THRESHOLD_OFFSET_SHIFT);
-+	pcmd->ed_offset_5g = cpu_to_le16((EDMAC_Ctrl &
-+					 EDMAC_5G_THRESHOLD_OFFSET_MASK)
-+					 >> EDMAC_5G_THRESHOLD_OFFSET_SHIFT);
-+	pcmd->ed_bitmap_txq_lock = cpu_to_le16((EDMAC_Ctrl &
-+					       EDMAC_QLOCK_BITMAP_MASK)
-+					       >> EDMAC_QLOCK_BITMAP_SHIFT);
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_EDMAC_CTRL)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_set_txpwrlmt_cfg_data(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_txpwrlmt_cfg *pcmd;
-+	struct mwl_txpwrlmt_cfg_entry_hdr hdr;
-+	u16 id, parsed_len, size;
-+	__le32 txpwr_cfg_sig;
-+	u8 version[TXPWRLMT_CFG_VERSION_INFO_LEN];
-+	const u8 *ptr;
-+
-+	if (!priv->txpwrlmt_file)
-+		return 0;
-+
-+	ptr = priv->txpwrlmt_file->data;
-+	size = priv->txpwrlmt_file->size;
-+
-+	/* Parsing TxPwrLmit Conf file Signature */
-+	parsed_len = mwl_fwcmd_parse_txpwrlmt_cfg(ptr, size,
-+						  TXPWRLMT_CFG_SIG_LEN,
-+						  (u8 *)&txpwr_cfg_sig);
-+	ptr += parsed_len;
-+	size -= parsed_len;
-+
-+	if (le32_to_cpu(txpwr_cfg_sig) != TXPWRLMT_CFG_SIGNATURE) {
-+		wiphy_err(hw->wiphy,
-+			  "txpwrlmt config signature mismatch\n");
-+		release_firmware(priv->txpwrlmt_file);
-+		priv->txpwrlmt_file = NULL;
-+		return 0;
-+	}
-+
-+	/* Parsing TxPwrLmit Conf file Version */
-+	parsed_len = mwl_fwcmd_parse_txpwrlmt_cfg(ptr, size,
-+						  TXPWRLMT_CFG_VERSION_INFO_LEN,
-+						  version);
-+	ptr += parsed_len;
-+	size -= parsed_len;
-+
-+	for (id = 0; id < TXPWRLMT_CFG_MAX_SUBBAND_INFO; id++) {
-+		u16 data_len;
-+
-+		/*Parsing tx pwr cfg subband header info*/
-+		parsed_len = sizeof(struct mwl_txpwrlmt_cfg_entry_hdr);
-+		parsed_len = mwl_fwcmd_parse_txpwrlmt_cfg(ptr, size,
-+							  parsed_len,
-+							  (u8 *)&hdr);
-+		ptr += parsed_len;
-+		size -= parsed_len;
-+		data_len = le16_to_cpu(hdr.len) -
-+			sizeof(struct mwl_txpwrlmt_cfg_entry_hdr);
-+
-+		pcmd = (struct hostcmd_cmd_txpwrlmt_cfg *)&priv->pcmd_buf[0];
-+
-+		mutex_lock(&priv->fwcmd_mutex);
-+
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->action = cpu_to_le16(HOSTCMD_ACT_GEN_SET);
-+		pcmd->subband_id = hdr.id;
-+		pcmd->data_len = cpu_to_le16(data_len);
-+		pcmd->num_entries = hdr.num_entries;
-+
-+		/* Parsing tx pwr cfg subband header info */
-+		parsed_len = mwl_fwcmd_parse_txpwrlmt_cfg(ptr, size,
-+							  data_len, pcmd->data);
-+		ptr += parsed_len;
-+		size -= parsed_len;
-+
-+		pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_TXPWRLMT_CFG);
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd) +
-+			data_len - sizeof(pcmd->data));
-+
-+		if (size < sizeof(struct mwl_txpwrlmt_cfg_entry_hdr))
-+			pcmd->cfgComplete = 1;
-+
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_TXPWRLMT_CFG)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			release_firmware(priv->txpwrlmt_file);
-+			priv->txpwrlmt_file = NULL;
-+			return -EIO;
-+		}
-+
-+		mutex_unlock(&priv->fwcmd_mutex);
-+	}
-+
-+	release_firmware(priv->txpwrlmt_file);
-+	priv->txpwrlmt_file = NULL;
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_get_txpwrlmt_cfg_data(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_txpwrlmt_cfg *pcmd;
-+	u16 subband_len, total_len = 0;
-+	u8 id;
-+
-+	for (id = 0; id < TXPWRLMT_CFG_MAX_SUBBAND_INFO; id++) {
-+		pcmd = (struct hostcmd_cmd_txpwrlmt_cfg *)&priv->pcmd_buf[0];
-+
-+		mutex_lock(&priv->fwcmd_mutex);
-+
-+		memset(pcmd, 0x00, sizeof(*pcmd));
-+		pcmd->action = 0;
-+		pcmd->subband_id = id;
-+		pcmd->data_len = 0;
-+		pcmd->num_entries = 0;
-+
-+		pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_TXPWRLMT_CFG);
-+		pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+
-+		if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_TXPWRLMT_CFG)) {
-+			mutex_unlock(&priv->fwcmd_mutex);
-+			return -EIO;
-+		}
-+
-+		mutex_unlock(&priv->fwcmd_mutex);
-+
-+		subband_len = le16_to_cpu(pcmd->cmd_hdr.len) -
-+			sizeof(struct hostcmd_header) - 2;
-+		if (total_len <= SYSADPT_TXPWRLMT_CFG_BUF_SIZE) {
-+			wiphy_debug(hw->wiphy, "Subband len = %d\n",
-+				    subband_len);
-+			memcpy(priv->txpwrlmt_data.buf + total_len,
-+			       &pcmd->subband_id, subband_len);
-+			total_len += subband_len;
-+			priv->txpwrlmt_data.buf[total_len] = '\n';
-+			total_len++;
-+			priv->txpwrlmt_data.len = total_len;
-+		} else {
-+			wiphy_err(hw->wiphy,
-+				  "TxPwrLmt cfg buf size is not enough\n");
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+int mwl_fwcmd_mcast_cts(struct ieee80211_hw *hw, u8 enable)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct hostcmd_cmd_mcast_cts *pcmd;
-+
-+	pcmd = (struct hostcmd_cmd_mcast_cts *)&priv->pcmd_buf[0];
-+
-+	mutex_lock(&priv->fwcmd_mutex);
-+
-+	memset(pcmd, 0x00, sizeof(*pcmd));
-+	pcmd->cmd_hdr.cmd = cpu_to_le16(HOSTCMD_CMD_MCAST_CTS);
-+	pcmd->cmd_hdr.len = cpu_to_le16(sizeof(*pcmd));
-+	pcmd->enable = enable;
-+
-+	if (mwl_hif_exec_cmd(hw, HOSTCMD_CMD_MCAST_CTS)) {
-+		mutex_unlock(&priv->fwcmd_mutex);
-+		return -EIO;
-+	}
-+
-+	mutex_unlock(&priv->fwcmd_mutex);
-+
-+	return 0;
-+}
-+
-+void mwl_fwcmd_get_survey(struct ieee80211_hw *hw, int idx)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct ieee80211_conf *conf = &hw->conf;
-+	struct mwl_survey_info *survey_info;
-+
-+	if (idx)
-+		survey_info = &priv->survey_info[idx - 1];
-+	else
-+		survey_info = &priv->cur_survey_info;
-+
-+	memcpy(&survey_info->channel, conf->chandef.chan,
-+	       sizeof(struct ieee80211_channel));
-+	mwl_hif_get_survey(hw, survey_info);
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.h b/drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.h
-new file mode 100644
-index 000000000000..9565cc447dc6
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/fwcmd.h
-@@ -0,0 +1,285 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines firmware host command related
-+ * functions.
-+ */
-+
-+#ifndef _FWCMD_H_
-+#define _FWCMD_H_
-+
-+#include "hif/hostcmd.h"
-+
-+/*  Define OpMode for SoftAP/Station mode
-+ *
-+ *  The following mode signature has to be written to PCI scratch register#0
-+ *  right after successfully downloading the last block of firmware and
-+ *  before waiting for firmware ready signature
-+ */
-+
-+#define HOSTCMD_STA_MODE                0x5A
-+#define HOSTCMD_SOFTAP_MODE             0xA5
-+
-+#define HOSTCMD_STA_FWRDY_SIGNATURE     0xF0F1F2F4
-+#define HOSTCMD_SOFTAP_FWRDY_SIGNATURE  0xF1F2F4A5
-+
-+#define GUARD_INTERVAL_STANDARD         1
-+#define GUARD_INTERVAL_SHORT            2
-+#define GUARD_INTERVAL_AUTO             3
-+
-+#define	LINK_CS_STATE_CONSERV           0
-+#define	LINK_CS_STATE_AGGR              1
-+#define	LINK_CS_STATE_AUTO              2
-+#define	LINK_CS_STATE_AUTO_DISABLED     3
-+
-+#define STOP_DETECT_RADAR               0
-+#define CAC_START                       1
-+#define MONITOR_START                   3
-+
-+#define WDS_MODE                        4
-+
-+enum {
-+	WL_ANTENNATYPE_RX = 1,
-+	WL_ANTENNATYPE_TX = 2,
-+};
-+
-+enum encr_type {
-+	ENCR_TYPE_WEP = 0,
-+	ENCR_TYPE_DISABLE = 1,
-+	ENCR_TYPE_TKIP = 4,
-+	ENCR_TYPE_AES = 6,
-+	ENCR_TYPE_MIX = 7,
-+};
-+
-+char *mwl_fwcmd_get_cmd_string(unsigned short cmd);
-+
-+const struct hostcmd_get_hw_spec
-+*mwl_fwcmd_get_hw_specs(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_set_hw_specs(struct ieee80211_hw *hw,
-+			   struct hostcmd_set_hw_spec *spec);
-+
-+int mwl_fwcmd_get_stat(struct ieee80211_hw *hw,
-+		       struct ieee80211_low_level_stats *stats);
-+
-+int mwl_fwcmd_reg_bb(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val);
-+
-+int mwl_fwcmd_reg_rf(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val);
-+
-+int mwl_fwcmd_radio_enable(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_radio_disable(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_set_radio_preamble(struct ieee80211_hw *hw,
-+				 bool short_preamble);
-+
-+int mwl_fwcmd_get_addr_value(struct ieee80211_hw *hw, u32 addr, u32 len,
-+			     u32 *val, u16 set);
-+
-+int mwl_fwcmd_max_tx_power(struct ieee80211_hw *hw,
-+			   struct ieee80211_conf *conf, u8 fraction);
-+
-+int mwl_fwcmd_tx_power(struct ieee80211_hw *hw,
-+		       struct ieee80211_conf *conf, u8 fraction);
-+
-+int mwl_fwcmd_rf_antenna(struct ieee80211_hw *hw, int dir, int antenna);
-+
-+int mwl_fwcmd_broadcast_ssid_enable(struct ieee80211_hw *hw,
-+				    struct ieee80211_vif *vif, bool enable);
-+
-+int mwl_fwcmd_set_cfg_data(struct ieee80211_hw *hw, u16 type);
-+
-+int mwl_fwcmd_set_rf_channel(struct ieee80211_hw *hw,
-+			     struct ieee80211_conf *conf);
-+
-+int mwl_fwcmd_set_aid(struct ieee80211_hw *hw,
-+		      struct ieee80211_vif *vif, u8 *bssid, u16 aid);
-+
-+int mwl_fwcmd_set_infra_mode(struct ieee80211_hw *hw,
-+			     struct ieee80211_vif *vif);
-+
-+int mwl_fwcmd_set_rts_threshold(struct ieee80211_hw *hw,
-+				int threshold);
-+
-+int mwl_fwcmd_set_edca_params(struct ieee80211_hw *hw, u8 index,
-+			      u16 cw_min, u16 cw_max, u8 aifs, u16 txop);
-+
-+int mwl_fwcmd_set_radar_detect(struct ieee80211_hw *hw, u16 action);
-+
-+int mwl_fwcmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable);
-+
-+int mwl_fwcmd_ht_guard_interval(struct ieee80211_hw *hw, u32 gi_type);
-+
-+int mwl_fwcmd_use_fixed_rate(struct ieee80211_hw *hw,
-+			     int mcast, int mgmt);
-+
-+int mwl_fwcmd_set_linkadapt_cs_mode(struct ieee80211_hw *hw,
-+				    u16 cs_mode);
-+
-+int mwl_fwcmd_dump_otp_data(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_set_rate_adapt_mode(struct ieee80211_hw *hw,
-+				  u16 mode);
-+
-+int mwl_fwcmd_set_mac_addr_client(struct ieee80211_hw *hw,
-+				  struct ieee80211_vif *vif, u8 *mac_addr);
-+
-+int mwl_fwcmd_get_watchdog_bitmap(struct ieee80211_hw *hw,
-+				  u8 *bitmap);
-+
-+int mwl_fwcmd_remove_mac_addr(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif, u8 *mac_addr);
-+
-+int mwl_fwcmd_bss_start(struct ieee80211_hw *hw,
-+			struct ieee80211_vif *vif, bool enable);
-+
-+int mwl_fwcmd_set_beacon(struct ieee80211_hw *hw,
-+			 struct ieee80211_vif *vif, u8 *beacon, int len);
-+
-+int mwl_fwcmd_set_new_stn_add(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif,
-+			      struct ieee80211_sta *sta);
-+
-+int mwl_fwcmd_set_new_stn_add_sc4(struct ieee80211_hw *hw,
-+				  struct ieee80211_vif *vif,
-+				  struct ieee80211_sta *sta,
-+				  u32 wds);
-+
-+int mwl_fwcmd_set_new_stn_wds_sc4(struct ieee80211_hw *hw, u8 *addr);
-+
-+int mwl_fwcmd_set_new_stn_add_self(struct ieee80211_hw *hw,
-+				   struct ieee80211_vif *vif);
-+
-+int mwl_fwcmd_set_new_stn_del(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif, u8 *addr);
-+
-+int mwl_fwcmd_set_apmode(struct ieee80211_hw *hw, u8 apmode);
-+
-+int mwl_fwcmd_set_switch_channel(struct ieee80211_hw *hw,
-+				 struct ieee80211_channel_switch *ch_switch);
-+
-+int mwl_fwcmd_update_encryption_enable(struct ieee80211_hw *hw,
-+				       struct ieee80211_vif *vif,
-+				       u8 *addr, u8 encr_type);
-+
-+int mwl_fwcmd_encryption_set_key(struct ieee80211_hw *hw,
-+				 struct ieee80211_vif *vif, u8 *addr,
-+				 struct ieee80211_key_conf *key);
-+
-+int mwl_fwcmd_encryption_remove_key(struct ieee80211_hw *hw,
-+				    struct ieee80211_vif *vif, u8 *addr,
-+				    struct ieee80211_key_conf *key);
-+
-+int mwl_fwcmd_check_ba(struct ieee80211_hw *hw,
-+		       struct mwl_ampdu_stream *stream,
-+		       struct ieee80211_vif *vif,
-+		       u32 direction);
-+
-+int mwl_fwcmd_create_ba(struct ieee80211_hw *hw,
-+			struct mwl_ampdu_stream *stream,
-+			struct ieee80211_vif *vif,
-+			u32 direction, u8 buf_size, u16 seqno, bool amsdu);
-+
-+int mwl_fwcmd_destroy_ba(struct ieee80211_hw *hw,
-+			 struct mwl_ampdu_stream *stream,
-+			 u32 direction);
-+
-+struct mwl_ampdu_stream *mwl_fwcmd_add_stream(struct ieee80211_hw *hw,
-+					      struct ieee80211_sta *sta,
-+					      u8 tid);
-+
-+void mwl_fwcmd_del_sta_streams(struct ieee80211_hw *hw,
-+			       struct ieee80211_sta *sta);
-+
-+int mwl_fwcmd_start_stream(struct ieee80211_hw *hw,
-+			   struct mwl_ampdu_stream *stream);
-+
-+void mwl_fwcmd_remove_stream(struct ieee80211_hw *hw,
-+			     struct mwl_ampdu_stream *stream);
-+
-+struct mwl_ampdu_stream *mwl_fwcmd_lookup_stream(struct ieee80211_hw *hw,
-+						 struct ieee80211_sta *sta,
-+						 u8 tid);
-+
-+bool mwl_fwcmd_ampdu_allowed(struct ieee80211_sta *sta, u8 tid);
-+
-+int mwl_fwcmd_set_optimization_level(struct ieee80211_hw *hw, u8 opt_level);
-+
-+int mwl_fwcmd_set_wsc_ie(struct ieee80211_hw *hw, u8 len, u8 *data);
-+
-+int mwl_fwcmd_get_ratetable(struct ieee80211_hw *hw, u8 *addr, u8 *rate_table,
-+			    u32 size, u8 type);
-+
-+int mwl_fwcmd_get_seqno(struct ieee80211_hw *hw,
-+			struct mwl_ampdu_stream *stream, u16 *start_seqno);
-+
-+int mwl_fwcmd_set_dwds_stamode(struct ieee80211_hw *hw, bool enable);
-+
-+int mwl_fwcmd_set_fw_flush_timer(struct ieee80211_hw *hw, u32 value);
-+
-+int mwl_fwcmd_set_cdd(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_set_bftype(struct ieee80211_hw *hw, int mode);
-+
-+int mwl_fwcmd_reg_cau(struct ieee80211_hw *hw, u8 flag, u32 reg, u32 *val);
-+
-+int mwl_fwcmd_get_temp(struct ieee80211_hw *hw, u32 *temp);
-+
-+int mwl_fwcmd_led_ctrl(struct ieee80211_hw *hw, u8 enable, u8 rate);
-+
-+int mwl_fwcmd_get_fw_region_code(struct ieee80211_hw *hw,
-+				 u32 *fw_region_code);
-+
-+int mwl_fwcmd_get_device_pwr_tbl(struct ieee80211_hw *hw,
-+				 struct mwl_device_pwr_tbl *device_ch_pwrtbl,
-+				 u8 *region_code,
-+				 u8 *number_of_channels,
-+				 u32 channel_index);
-+
-+int mwl_fwcmd_set_rate_drop(struct ieee80211_hw *hw, int enable,
-+			    int value, int staid);
-+
-+int mwl_fwcmd_newdp_dmathread_start(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_get_fw_region_code_sc4(struct ieee80211_hw *hw,
-+				     u32 *fw_region_code);
-+
-+int mwl_fwcmd_get_pwr_tbl_sc4(struct ieee80211_hw *hw,
-+			      struct mwl_device_pwr_tbl *device_ch_pwrtbl,
-+			      u8 *region_code,
-+			      u8 *number_of_channels,
-+			      u32 channel_index);
-+
-+int mwl_fwcmd_quiet_mode(struct ieee80211_hw *hw, bool enable, u32 period,
-+			 u32 duration, u32 next_offset);
-+
-+int mwl_fwcmd_core_dump_diag_mode(struct ieee80211_hw *hw, u16 status);
-+
-+int mwl_fwcmd_get_fw_core_dump(struct ieee80211_hw *hw,
-+			       struct coredump_cmd *core_dump, char *buff);
-+
-+int mwl_fwcmd_set_slot_time(struct ieee80211_hw *hw, bool short_slot);
-+
-+int mwl_fwcmd_config_EDMACCtrl(struct ieee80211_hw *hw, int EDMAC_Ctrl);
-+
-+int mwl_fwcmd_set_txpwrlmt_cfg_data(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_get_txpwrlmt_cfg_data(struct ieee80211_hw *hw);
-+
-+int mwl_fwcmd_mcast_cts(struct ieee80211_hw *hw, u8 enable);
-+
-+void mwl_fwcmd_get_survey(struct ieee80211_hw *hw, int idx);
-+
-+#endif /* _FWCMD_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/hif-ops.h b/drivers/net/wireless/marvell/mwlwifi/hif/hif-ops.h
-new file mode 100644
-index 000000000000..f5c7144b3c1b
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/hif-ops.h
-@@ -0,0 +1,297 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines host interface related operations. */
-+
-+#ifndef _HIF_OPS_H_
-+#define _HIF_OPS_H_
-+static inline const char *mwl_hif_get_driver_name(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	return priv->hif.ops->driver_name;
-+}
-+
-+static inline const char *mwl_hif_get_driver_version(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	return priv->hif.ops->driver_version;
-+}
-+
-+static inline unsigned int mwl_hif_get_tx_head_room(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	return priv->hif.ops->tx_head_room;
-+}
-+
-+static inline unsigned int mwl_hif_get_ampdu_num(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	return priv->hif.ops->ampdu_num;
-+}
-+
-+static inline void mwl_hif_reset(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->reset)
-+		priv->hif.ops->reset(hw);
-+}
-+
-+static inline int mwl_hif_init(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->init)
-+		return priv->hif.ops->init(hw);
-+	else
-+		return -ENOTSUPP;
-+}
-+
-+static inline void mwl_hif_deinit(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->deinit)
-+		priv->hif.ops->deinit(hw);
-+}
-+
-+static inline int mwl_hif_get_info(struct ieee80211_hw *hw,
-+				   char *buf, size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->get_info)
-+		return priv->hif.ops->get_info(hw, buf, size);
-+	else
-+		return 0;
-+}
-+
-+static inline int mwl_hif_get_tx_status(struct ieee80211_hw *hw,
-+					char *buf, size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->get_tx_status)
-+		return priv->hif.ops->get_tx_status(hw, buf, size);
-+	else
-+		return 0;
-+}
-+
-+static inline int mwl_hif_get_rx_status(struct ieee80211_hw *hw,
-+					char *buf, size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->get_rx_status)
-+		return priv->hif.ops->get_rx_status(hw, buf, size);
-+	else
-+		return 0;
-+}
-+
-+static inline void mwl_hif_enable_data_tasks(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->enable_data_tasks)
-+		priv->hif.ops->enable_data_tasks(hw);
-+}
-+
-+static inline void mwl_hif_disable_data_tasks(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->disable_data_tasks)
-+		priv->hif.ops->disable_data_tasks(hw);
-+}
-+
-+static inline int mwl_hif_exec_cmd(struct ieee80211_hw *hw, unsigned short cmd)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->exec_cmd)
-+		return priv->hif.ops->exec_cmd(hw, cmd);
-+	else
-+		return -ENOTSUPP;
-+}
-+
-+static inline int mwl_hif_get_irq_num(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->get_irq_num)
-+		return priv->hif.ops->get_irq_num(hw);
-+	else
-+		return -ENOTSUPP;
-+}
-+
-+static inline irqreturn_t mwl_hif_irq_handler(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->irq_handler)
-+		return priv->hif.ops->irq_handler(hw);
-+	else
-+		return -ENOTSUPP;
-+}
-+
-+static inline void mwl_hif_irq_enable(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->irq_enable)
-+		priv->hif.ops->irq_enable(hw);
-+}
-+
-+static inline void mwl_hif_irq_disable(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->irq_disable)
-+		priv->hif.ops->irq_disable(hw);
-+}
-+
-+static inline int mwl_hif_download_firmware(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->download_firmware)
-+		return priv->hif.ops->download_firmware(hw);
-+	else
-+		return -ENOTSUPP;
-+}
-+
-+static inline void mwl_hif_timer_routine(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->timer_routine)
-+		priv->hif.ops->timer_routine(hw);
-+}
-+
-+static inline void mwl_hif_tx_xmit(struct ieee80211_hw *hw,
-+				   struct ieee80211_tx_control *control,
-+				   struct sk_buff *skb)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->tx_xmit)
-+		priv->hif.ops->tx_xmit(hw, control, skb);
-+}
-+
-+static inline void mwl_hif_tx_del_pkts_via_vif(struct ieee80211_hw *hw,
-+					       struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->tx_del_pkts_via_vif)
-+		priv->hif.ops->tx_del_pkts_via_vif(hw, vif);
-+}
-+
-+static inline void mwl_hif_tx_del_pkts_via_sta(struct ieee80211_hw *hw,
-+					       struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->tx_del_pkts_via_sta)
-+		priv->hif.ops->tx_del_pkts_via_sta(hw, sta);
-+}
-+
-+static inline void mwl_hif_tx_del_ampdu_pkts(struct ieee80211_hw *hw,
-+					     struct ieee80211_sta *sta, u8 tid)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->tx_del_ampdu_pkts)
-+		priv->hif.ops->tx_del_ampdu_pkts(hw, sta, tid);
-+}
-+
-+static inline void mwl_hif_tx_del_sta_amsdu_pkts(struct ieee80211_hw *hw,
-+						 struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->tx_del_sta_amsdu_pkts)
-+		priv->hif.ops->tx_del_sta_amsdu_pkts(hw, sta);
-+}
-+
-+static inline void mwl_hif_tx_return_pkts(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->tx_return_pkts)
-+		priv->hif.ops->tx_return_pkts(hw);
-+}
-+
-+static inline struct device_node *mwl_hif_device_node(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->get_device_node)
-+		return priv->hif.ops->get_device_node(hw);
-+	else
-+		return NULL;
-+}
-+
-+static inline void mwl_hif_get_survey(struct ieee80211_hw *hw,
-+				      struct mwl_survey_info *survey_info)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->get_survey)
-+		priv->hif.ops->get_survey(hw, survey_info);
-+}
-+
-+static inline int mwl_hif_reg_access(struct ieee80211_hw *hw, bool write)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->reg_access)
-+		return priv->hif.ops->reg_access(hw, write);
-+	else
-+		return -ENOTSUPP;
-+}
-+
-+static inline void mwl_hif_set_sta_id(struct ieee80211_hw *hw,
-+				      struct ieee80211_sta *sta,
-+				      bool sta_mode, bool set)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->set_sta_id)
-+		priv->hif.ops->set_sta_id(hw, sta, sta_mode, set);
-+}
-+
-+static inline void mwl_hif_process_account(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->process_account)
-+		priv->hif.ops->process_account(hw);
-+}
-+
-+static inline int mwl_hif_mcast_cts(struct ieee80211_hw *hw, bool enable)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->hif.ops->mcast_cts)
-+		return priv->hif.ops->mcast_cts(hw, enable);
-+	else
-+		return -ENOTSUPP;
-+}
-+#endif /* _HIF_OPS_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/hif.h b/drivers/net/wireless/marvell/mwlwifi/hif/hif.h
-new file mode 100644
-index 000000000000..6ea6192ac5e0
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/hif.h
-@@ -0,0 +1,81 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines host interface data structure. */
-+
-+#ifndef _HIF_H_
-+#define _HIF_H_
-+
-+/* memory/register access */
-+#define MWL_ACCESS_MAC        1
-+#define MWL_ACCESS_RF         2
-+#define MWL_ACCESS_BBP        3
-+#define MWL_ACCESS_CAU        4
-+#define MWL_ACCESS_ADDR0      5
-+#define MWL_ACCESS_ADDR1      6
-+#define MWL_ACCESS_ADDR       7
-+
-+struct mwl_survey_info {
-+	struct ieee80211_channel channel;
-+	u32 filled;
-+	u32 time_period;
-+	u32 time_busy;
-+	u32 time_tx;
-+	s8 noise;
-+};
-+
-+struct mwl_hif_ops {
-+	const char *driver_name;
-+	const char *driver_version;
-+	unsigned int tx_head_room;
-+	int ampdu_num;
-+	void (*reset)(struct ieee80211_hw *hw);
-+	int (*init)(struct ieee80211_hw *hw);
-+	void (*deinit)(struct ieee80211_hw *hw);
-+	int (*get_info)(struct ieee80211_hw *hw, char *buf, size_t size);
-+	int (*get_tx_status)(struct ieee80211_hw *hw, char *buf, size_t size);
-+	int (*get_rx_status)(struct ieee80211_hw *hw, char *buf, size_t size);
-+	void (*enable_data_tasks)(struct ieee80211_hw *hw);
-+	void (*disable_data_tasks)(struct ieee80211_hw *hw);
-+	int (*exec_cmd)(struct ieee80211_hw *hw, unsigned short cmd);
-+	int (*get_irq_num)(struct ieee80211_hw *hw);
-+	irqreturn_t (*irq_handler)(struct ieee80211_hw *hw);
-+	void (*irq_enable)(struct ieee80211_hw *hw);
-+	void (*irq_disable)(struct ieee80211_hw *hw);
-+	int (*download_firmware)(struct ieee80211_hw *hw);
-+	void (*timer_routine)(struct ieee80211_hw *hw);
-+	void (*tx_xmit)(struct ieee80211_hw *hw,
-+			struct ieee80211_tx_control *control,
-+			struct sk_buff *skb);
-+	void (*tx_del_pkts_via_vif)(struct ieee80211_hw *hw,
-+				    struct ieee80211_vif *vif);
-+	void (*tx_del_pkts_via_sta)(struct ieee80211_hw *hw,
-+				    struct ieee80211_sta *sta);
-+	void (*tx_del_ampdu_pkts)(struct ieee80211_hw *hw,
-+				  struct ieee80211_sta *sta, u8 tid);
-+	void (*tx_del_sta_amsdu_pkts)(struct ieee80211_hw *hw,
-+				      struct ieee80211_sta *sta);
-+	void (*tx_return_pkts)(struct ieee80211_hw *hw);
-+	struct device_node *(*get_device_node)(struct ieee80211_hw *hw);
-+	void (*get_survey)(struct ieee80211_hw *hw,
-+			   struct mwl_survey_info *survey_info);
-+	int (*reg_access)(struct ieee80211_hw *hw, bool write);
-+	void (*set_sta_id)(struct ieee80211_hw *hw,
-+			   struct ieee80211_sta *sta,
-+			   bool sta_mode, bool set);
-+	void (*process_account)(struct ieee80211_hw *hw);
-+	int (*mcast_cts)(struct ieee80211_hw *hw, bool enable);
-+};
-+#endif /* _HIF_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/hostcmd.h b/drivers/net/wireless/marvell/mwlwifi/hif/hostcmd.h
-new file mode 100644
-index 000000000000..b14f161f1410
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/hostcmd.h
-@@ -0,0 +1,1285 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines firmware host command related
-+ * structure.
-+ */
-+
-+#ifndef _HOSTCMD_H_
-+#define _HOSTCMD_H_
-+
-+/* 16 bit host command code */
-+#define HOSTCMD_CMD_GET_HW_SPEC                 0x0003
-+#define HOSTCMD_CMD_SET_HW_SPEC                 0x0004
-+#define HOSTCMD_CMD_802_11_GET_STAT             0x0014
-+#define HOSTCMD_CMD_BBP_REG_ACCESS              0x001a
-+#define HOSTCMD_CMD_RF_REG_ACCESS               0x001b
-+#define HOSTCMD_CMD_802_11_RADIO_CONTROL        0x001c
-+#define HOSTCMD_CMD_MEM_ADDR_ACCESS             0x001d
-+#define HOSTCMD_CMD_802_11_TX_POWER             0x001f
-+#define HOSTCMD_CMD_802_11_RF_ANTENNA           0x0020
-+#define HOSTCMD_CMD_BROADCAST_SSID_ENABLE       0x0050 /* per-vif */
-+#define HOSTCMD_CMD_SET_CFG                     0x008f
-+#define HOSTCMD_CMD_SET_RF_CHANNEL              0x010a
-+#define HOSTCMD_CMD_SET_AID                     0x010d /* per-vif */
-+#define HOSTCMD_CMD_SET_INFRA_MODE              0x010e /* per-vif */
-+#define HOSTCMD_CMD_802_11_RTS_THSD             0x0113
-+#define HOSTCMD_CMD_SET_EDCA_PARAMS             0x0115
-+#define HOSTCMD_CMD_802_11H_DETECT_RADAR        0x0120
-+#define HOSTCMD_CMD_SET_WMM_MODE                0x0123
-+#define HOSTCMD_CMD_HT_GUARD_INTERVAL           0x0124
-+#define HOSTCMD_CMD_SET_FIXED_RATE              0x0126
-+#define HOSTCMD_CMD_SET_IES                     0x0127
-+#define HOSTCMD_CMD_SET_LINKADAPT_CS_MODE       0x0129
-+#define HOSTCMD_CMD_DUMP_OTP_DATA               0x0142
-+#define HOSTCMD_CMD_SET_MAC_ADDR                0x0202 /* per-vif */
-+#define HOSTCMD_CMD_SET_RATE_ADAPT_MODE         0x0203
-+#define HOSTCMD_CMD_GET_WATCHDOG_BITMAP         0x0205
-+#define HOSTCMD_CMD_DEL_MAC_ADDR                0x0206 /* per-vif */
-+#define HOSTCMD_CMD_BSS_START                   0x1100 /* per-vif */
-+#define HOSTCMD_CMD_AP_BEACON                   0x1101 /* per-vif */
-+#define HOSTCMD_CMD_SET_NEW_STN                 0x1111 /* per-vif */
-+#define HOSTCMD_CMD_SET_APMODE                  0x1114
-+#define HOSTCMD_CMD_SET_SWITCH_CHANNEL          0x1121
-+#define HOSTCMD_CMD_UPDATE_ENCRYPTION           0x1122 /* per-vif */
-+#define HOSTCMD_CMD_BASTREAM                    0x1125
-+#define HOSTCMD_CMD_SET_SPECTRUM_MGMT           0x1128
-+#define HOSTCMD_CMD_SET_POWER_CONSTRAINT        0x1129
-+#define HOSTCMD_CMD_SET_COUNTRY_CODE            0x1130
-+#define HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL      0x1133
-+#define HOSTCMD_CMD_SET_WSC_IE                  0x1136 /* per-vif */
-+#define HOSTCMD_CMD_GET_RATETABLE               0x1137
-+#define HOSTCMD_CMD_GET_SEQNO                   0x1143
-+#define HOSTCMD_CMD_DWDS_ENABLE                 0x1144
-+#define HOSTCMD_CMD_FW_FLUSH_TIMER              0x1148
-+#define HOSTCMD_CMD_SET_CDD                     0x1150
-+#define HOSTCMD_CMD_SET_BFTYPE                  0x1155
-+#define HOSTCMD_CMD_CAU_REG_ACCESS              0x1157
-+#define HOSTCMD_CMD_GET_TEMP                    0x1159
-+#define HOSTCMD_CMD_LED_CTRL                    0x1169
-+#define HOSTCMD_CMD_GET_FW_REGION_CODE          0x116A
-+#define HOSTCMD_CMD_GET_DEVICE_PWR_TBL          0x116B
-+#define HOSTCMD_CMD_SET_RATE_DROP               0x1172
-+#define HOSTCMD_CMD_NEWDP_DMATHREAD_START       0x1189
-+#define HOSTCMD_CMD_GET_FW_REGION_CODE_SC4      0x118A
-+#define HOSTCMD_CMD_GET_DEVICE_PWR_TBL_SC4      0x118B
-+#define HOSTCMD_CMD_QUIET_MODE                  0x1201
-+#define HOSTCMD_CMD_CORE_DUMP_DIAG_MODE         0x1202
-+#define HOSTCMD_CMD_802_11_SLOT_TIME            0x1203
-+#define HOSTCMD_CMD_GET_FW_CORE_DUMP            0x1203
-+#define HOSTCMD_CMD_EDMAC_CTRL                  0x1204
-+#define HOSTCMD_CMD_TXPWRLMT_CFG                0x1211
-+#define HOSTCMD_CMD_MCAST_CTS                   0x4001
-+
-+/* Define general result code for each command */
-+#define HOSTCMD_RESULT_OK                       0x0000
-+/* General error */
-+#define HOSTCMD_RESULT_ERROR                    0x0001
-+/* Command is not valid */
-+#define HOSTCMD_RESULT_NOT_SUPPORT              0x0002
-+/* Command is pending (will be processed) */
-+#define HOSTCMD_RESULT_PENDING                  0x0003
-+/* System is busy (command ignored) */
-+#define HOSTCMD_RESULT_BUSY                     0x0004
-+/* Data buffer is not big enough */
-+#define HOSTCMD_RESULT_PARTIAL_DATA             0x0005
-+
-+/* Define channel related constants */
-+#define FREQ_BAND_2DOT4GHZ                      0x1
-+#define FREQ_BAND_4DOT9GHZ                      0x2
-+#define FREQ_BAND_5GHZ                          0x4
-+#define FREQ_BAND_5DOT2GHZ                      0x8
-+#define CH_AUTO_WIDTH	                        0
-+#define CH_10_MHZ_WIDTH                         0x1
-+#define CH_20_MHZ_WIDTH                         0x2
-+#define CH_40_MHZ_WIDTH                         0x4
-+#define CH_80_MHZ_WIDTH                         0x5
-+#define CH_160_MHZ_WIDTH                        0x6
-+#define EXT_CH_ABOVE_CTRL_CH                    0x1
-+#define EXT_CH_AUTO                             0x2
-+#define EXT_CH_BELOW_CTRL_CH                    0x3
-+#define NO_EXT_CHANNEL                          0x0
-+
-+#define ACT_PRIMARY_CHAN_0                      0
-+#define ACT_PRIMARY_CHAN_1                      1
-+#define ACT_PRIMARY_CHAN_2                      2
-+#define ACT_PRIMARY_CHAN_3                      3
-+#define ACT_PRIMARY_CHAN_4                      4
-+#define ACT_PRIMARY_CHAN_5                      5
-+#define ACT_PRIMARY_CHAN_6                      6
-+#define ACT_PRIMARY_CHAN_7                      7
-+
-+/* Define rate related constants */
-+#define HOSTCMD_ACT_NOT_USE_FIXED_RATE          0x0002
-+
-+/* Define station related constants */
-+#define HOSTCMD_ACT_STA_ACTION_ADD              0
-+#define HOSTCMD_ACT_STA_ACTION_MODIFY           1
-+#define HOSTCMD_ACT_STA_ACTION_REMOVE           2
-+
-+/* Define key related constants */
-+#define MAX_ENCR_KEY_LENGTH                     16
-+#define MIC_KEY_LENGTH                          8
-+
-+#define KEY_TYPE_ID_WEP                         0x00
-+#define KEY_TYPE_ID_TKIP                        0x01
-+#define KEY_TYPE_ID_AES	                        0x02
-+
-+/* Group key for RX only */
-+#define ENCR_KEY_FLAG_RXGROUPKEY                0x00000002
-+#define ENCR_KEY_FLAG_TXGROUPKEY                0x00000004
-+#define ENCR_KEY_FLAG_PAIRWISE                  0x00000008
-+#define ENCR_KEY_FLAG_TSC_VALID                 0x00000040
-+#define ENCR_KEY_FLAG_WEP_TXKEY                 0x01000000
-+#define ENCR_KEY_FLAG_MICKEY_VALID              0x02000000
-+
-+/* Define block ack related constants */
-+#define BA_FLAG_IMMEDIATE_TYPE                  1
-+#define BA_FLAG_DIRECTION_UP                    0
-+#define BA_FLAG_DIRECTION_DOWN                  1
-+
-+/* Define general purpose action */
-+#define HOSTCMD_ACT_GEN_SET                     0x0001
-+#define HOSTCMD_ACT_GEN_SET_LIST                0x0002
-+#define HOSTCMD_ACT_GEN_GET_LIST                0x0003
-+
-+/* Define TXPower control action*/
-+#define HOSTCMD_ACT_GET_TARGET_TX_PWR           0x0000
-+#define HOSTCMD_ACT_GET_MAX_TX_PWR              0x0001
-+#define HOSTCMD_ACT_SET_TARGET_TX_PWR           0x0002
-+#define HOSTCMD_ACT_SET_MAX_TX_PWR              0x0003
-+
-+/* Misc */
-+#define WSC_IE_MAX_LENGTH                       251
-+#define WSC_IE_SET_BEACON                       0
-+#define WSC_IE_SET_PROBE_RESPONSE               1
-+
-+#define HW_SET_PARMS_FEATURES_HOST_PROBE_RESP   0x00000020
-+
-+#define EDMAC_2G_ENABLE_MASK                    0x00000001
-+#define EDMAC_2G_ENABLE_SHIFT                   0x0
-+#define EDMAC_5G_ENABLE_MASK                    0x00000002
-+#define EDMAC_5G_ENABLE_SHIFT                   0x1
-+#define EDMAC_2G_THRESHOLD_OFFSET_MASK          0x00000FF0
-+#define EDMAC_2G_THRESHOLD_OFFSET_SHIFT         0x4
-+#define EDMAC_5G_THRESHOLD_OFFSET_MASK          0x000FF000
-+#define EDMAC_5G_THRESHOLD_OFFSET_SHIFT         0xC
-+#define EDMAC_QLOCK_BITMAP_MASK                 0x0FF00000
-+#define EDMAC_QLOCK_BITMAP_SHIFT                0x14
-+
-+enum {
-+	WL_DISABLE = 0,
-+	WL_ENABLE = 1,
-+	WL_DISABLE_VMAC = 0x80,
-+};
-+
-+enum {
-+	WL_GET = 0,
-+	WL_SET = 1,
-+	WL_RESET = 2,
-+};
-+
-+enum {
-+	WL_LONG_PREAMBLE = 1,
-+	WL_SHORT_PREAMBLE = 3,
-+	WL_AUTO_PREAMBLE = 5,
-+};
-+
-+enum encr_action_type {
-+	/* request to enable/disable HW encryption */
-+	ENCR_ACTION_ENABLE_HW_ENCR,
-+	/* request to set encryption key */
-+	ENCR_ACTION_TYPE_SET_KEY,
-+	/* request to remove one or more keys */
-+	ENCR_ACTION_TYPE_REMOVE_KEY,
-+	ENCR_ACTION_TYPE_SET_GROUP_KEY,
-+};
-+
-+enum ba_action_type {
-+	BA_CREATE_STREAM,
-+	BA_UPDATE_STREAM,
-+	BA_DESTROY_STREAM,
-+	BA_FLUSH_STREAM,
-+	BA_CHECK_STREAM,
-+};
-+
-+enum mac_type {
-+	WL_MAC_TYPE_PRIMARY_CLIENT,
-+	WL_MAC_TYPE_SECONDARY_CLIENT,
-+	WL_MAC_TYPE_PRIMARY_AP,
-+	WL_MAC_TYPE_SECONDARY_AP,
-+};
-+
-+/* General host command header */
-+struct hostcmd_header {
-+	__le16 cmd;
-+	__le16 len;
-+	u8 seq_num;
-+	u8 macid;
-+	__le16 result;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_HW_SPEC */
-+struct hostcmd_get_hw_spec {
-+	u8 version;                  /* version of the HW                    */
-+	u8 host_if;                  /* host interface                       */
-+	__le16 num_wcb;              /* Max. number of WCB FW can handle     */
-+	__le16 num_mcast_addr;       /* MaxNbr of MC addresses FW can handle */
-+	u8 permanent_addr[ETH_ALEN]; /* MAC address programmed in HW         */
-+	__le16 region_code;
-+	__le16 num_antenna;          /* Number of antenna used      */
-+	__le32 fw_release_num;       /* 4 byte of FW release number */
-+	__le32 wcb_base0;
-+	__le32 rxpd_wr_ptr;
-+	__le32 rxpd_rd_ptr;
-+	__le32 fw_awake_cookie;
-+	__le32 wcb_base[SYSADPT_TOTAL_TX_QUEUES - 1];
-+} __packed;
-+
-+struct hostcmd_cmd_get_hw_spec {
-+	struct hostcmd_header cmd_hdr;
-+	struct hostcmd_get_hw_spec hw_spec;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_HW_SPEC */
-+struct hostcmd_set_hw_spec {
-+	/* HW revision */
-+	u8 version;
-+	/* Host interface */
-+	u8 host_if;
-+	/* Max. number of Multicast address FW can handle */
-+	__le16 num_mcast_addr;
-+	/* MAC address */
-+	u8 permanent_addr[ETH_ALEN];
-+	/* Region Code */
-+	__le16 region_code;
-+	/* 4 byte of FW release number, example 0x1234=1.2.3.4 */
-+	__le32 fw_release_num;
-+	/* Firmware awake cookie - used to ensure that the device
-+	 * is not in sleep mode
-+	 */
-+	__le32 fw_awake_cookie;
-+	/* Device capabilities (see above) */
-+	__le32 device_caps;
-+	/* Rx shared memory queue */
-+	__le32 rxpd_wr_ptr;
-+	/* Actual number of TX queues in WcbBase array */
-+	__le32 num_tx_queues;
-+	/* TX WCB Rings */
-+	__le32 wcb_base[4 + SYSADPT_NUM_OF_AP];
-+	/* Max AMSDU size (00 - AMSDU Disabled,
-+	 * 01 - 4K, 10 - 8K, 11 - not defined)
-+	 */
-+	__le32 features;
-+	__le32 tx_wcb_num_per_queue;
-+	__le32 total_rx_wcb;
-+	__le32 acnt_buf_size;
-+	__le32 acnt_base_addr;
-+} __packed;
-+
-+struct hostcmd_cmd_set_hw_spec {
-+	struct hostcmd_header cmd_hdr;
-+	struct hostcmd_set_hw_spec hw_spec;
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11_GET_STAT */
-+struct hostcmd_cmd_802_11_get_stat {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 tx_retry_successes;
-+	__le32 tx_multiple_retry_successes;
-+	__le32 tx_failures;
-+	__le32 rts_successes;
-+	__le32 rts_failures;
-+	__le32 ack_failures;
-+	__le32 rx_duplicate_frames;
-+	__le32 rx_fcs_errors;
-+	__le32 tx_watchdog_timeouts;
-+	__le32 rx_overflows;
-+	__le32 rx_frag_errors;
-+	__le32 rx_mem_errors;
-+	__le32 pointer_errors;
-+	__le32 tx_underflows;
-+	__le32 tx_done;
-+	__le32 tx_done_buf_try_put;
-+	__le32 tx_done_buf_put;
-+	/* Put size of requested buffer in here */
-+	__le32 wait_for_tx_buf;
-+	__le32 tx_attempts;
-+	__le32 tx_successes;
-+	__le32 tx_fragments;
-+	__le32 tx_multicasts;
-+	__le32 rx_non_ctl_pkts;
-+	__le32 rx_multicasts;
-+	__le32 rx_undecryptable_frames;
-+	__le32 rx_icv_errors;
-+	__le32 rx_excluded_frames;
-+	__le32 rx_weak_iv_count;
-+	__le32 rx_unicasts;
-+	__le32 rx_bytes;
-+	__le32 rx_errors;
-+	__le32 rx_rts_count;
-+	__le32 tx_cts_count;
-+} __packed;
-+
-+/* HOSTCMD_CMD_BBP_REG_ACCESS */
-+struct hostcmd_cmd_bbp_reg_access {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 offset;
-+	u8 value;
-+	u8 reserverd[3];
-+} __packed;
-+
-+/* HOSTCMD_CMD_RF_REG_ACCESS */
-+struct hostcmd_cmd_rf_reg_access {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 offset;
-+	u8 value;
-+	u8 reserverd[3];
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11_RADIO_CONTROL */
-+struct hostcmd_cmd_802_11_radio_control {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	/* @bit0: 1/0,on/off, @bit1: 1/0, long/short @bit2: 1/0,auto/fix */
-+	__le16 control;
-+	__le16 radio_on;
-+} __packed;
-+
-+/* HOSTCMD_CMD_MEM_ADDR_ACCESS */
-+struct hostcmd_cmd_mem_addr_access {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 address;
-+	__le16 length;
-+	__le16 reserved;
-+	__le32 value[64];
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11_TX_POWER */
-+struct hostcmd_cmd_802_11_tx_power {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 band;
-+	__le16 ch;
-+	__le16 bw;
-+	__le16 sub_ch;
-+	__le16 power_level_list[SYSADPT_TX_POWER_LEVEL_TOTAL];
-+} __packed;
-+
-+struct hostcmd_cmd_802_11_tx_power_kf2 {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 band;
-+	__le16 ch;
-+	__le16 bw;
-+	__le16 sub_ch;
-+	__le16 power_level_list[SYSADPT_TX_GRP_PWR_LEVEL_TOTAL];
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11_RF_ANTENNA */
-+struct hostcmd_cmd_802_11_rf_antenna {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 antenna_mode;     /* Number of antennas or 0xffff(diversity) */
-+} __packed;
-+
-+/* HOSTCMD_CMD_BROADCAST_SSID_ENABLE */
-+struct hostcmd_cmd_broadcast_ssid_enable {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 enable;
-+	__le32 hidden_ssid_info;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_CFG */
-+struct hostcmd_cmd_set_cfg {
-+	struct hostcmd_header cmd_hdr;
-+	/* Action */
-+	__le16 action;
-+	/* Type */
-+	__le16 type;
-+	/* Data length */
-+	__le16 data_len;
-+	/* Data */
-+	u8 data[1];
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_RF_CHANNEL */
-+#define FREQ_BAND_MASK     0x0000003f
-+#define CHNL_WIDTH_MASK    0x000007c0
-+#define CHNL_WIDTH_SHIFT   6
-+#define ACT_PRIMARY_MASK   0x00003800
-+#define ACT_PRIMARY_SHIFT  11
-+
-+struct hostcmd_cmd_set_rf_channel {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	u8 curr_chnl;
-+	__le32 chnl_flags;
-+} __packed;
-+
-+struct hostcmd_cmd_set_rf_channel_kf2 {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	u8 curr_chnl;
-+	__le32 chnl_flags;
-+	u8 remain_on_chan;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_AID */
-+struct hostcmd_cmd_set_aid {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 aid;
-+	u8 mac_addr[ETH_ALEN];       /* AP's Mac Address(BSSID) */
-+	__le32 gprotect;
-+	u8 ap_rates[SYSADPT_MAX_DATA_RATES_G];
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_INFRA_MODE */
-+struct hostcmd_cmd_set_infra_mode {
-+	struct hostcmd_header cmd_hdr;
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11_RTS_THSD */
-+struct hostcmd_cmd_802_11_rts_thsd {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16	threshold;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_EDCA_PARAMS */
-+struct hostcmd_cmd_set_edca_params {
-+	struct hostcmd_header cmd_hdr;
-+	/* 0 = get all, 0x1 =set CWMin/Max,  0x2 = set TXOP , 0x4 =set AIFSN */
-+	__le16 action;
-+	__le16 txop;                 /* in unit of 32 us */
-+	__le32 cw_max;               /* 0~15 */
-+	__le32 cw_min;               /* 0~15 */
-+	u8 aifsn;
-+	u8 txq_num;                  /* Tx Queue number. */
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11H_DETECT_RADAR */
-+#define RADAR_TYPE_CODE_0    0
-+#define RADAR_TYPE_CODE_53   53
-+#define RADAR_TYPE_CODE_56   56
-+#define RADAR_TYPE_CODE_ETSI 151
-+
-+struct hostcmd_cmd_802_11h_detect_radar {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 radar_type_code;
-+	__le16 min_chirp_cnt;
-+	__le16 chirp_time_intvl;
-+	__le16 pw_filter;
-+	__le16 min_num_radar;
-+	__le16 pri_min_num;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_WMM_MODE */
-+struct hostcmd_cmd_set_wmm_mode {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;               /* 0->unset, 1->set */
-+} __packed;
-+
-+/* HOSTCMD_CMD_HT_GUARD_INTERVAL */
-+struct hostcmd_cmd_ht_guard_interval {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 action;
-+	__le32 gi_type;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_FIXED_RATE */
-+struct fix_rate_flag {           /* lower rate after the retry count */
-+	/* 0: legacy, 1: HT */
-+	__le32 fix_rate_type;
-+	/* 0: retry count is not valid, 1: use retry count specified */
-+	__le32 retry_count_valid;
-+} __packed;
-+
-+struct fix_rate_entry {
-+	struct fix_rate_flag fix_rate_type_flags;
-+	/* depending on the flags above, this can be either a legacy
-+	 * rate(not index) or an MCS code.
-+	 */
-+	__le32 fixed_rate;
-+	__le32 retry_count;
-+} __packed;
-+
-+struct hostcmd_cmd_set_fixed_rate {
-+	struct hostcmd_header cmd_hdr;
-+	/* HOSTCMD_ACT_NOT_USE_FIXED_RATE 0x0002 */
-+	__le32 action;
-+	/* use fixed rate specified but firmware can drop to */
-+	__le32 allow_rate_drop;
-+	__le32 entry_count;
-+	struct fix_rate_entry fixed_rate_table[4];
-+	u8 multicast_rate;
-+	u8 multi_rate_tx_type;
-+	u8 management_rate;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_IES */
-+struct hostcmd_cmd_set_ies {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;               /* 0->unset, 1->set */
-+	__le16 ie_list_len_ht;
-+	__le16 ie_list_len_vht;
-+	__le16 ie_list_len_proprietary;
-+	/*Buffer size same as Generic_Beacon*/
-+	u8 ie_list_ht[148];
-+	u8 ie_list_vht[24];
-+	u8 ie_list_proprietary[112];
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_LINKADAPT_CS_MODE */
-+struct hostcmd_cmd_set_linkadapt_cs_mode {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 cs_mode;
-+} __packed;
-+
-+/* HOSTCMD_CMD_DUMP_OTP_DATA */
-+struct hostcmd_cmd_dump_otp_data {
-+	struct hostcmd_header cmd_hdr;
-+	u8 pload[0];
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_MAC_ADDR, HOSTCMD_CMD_DEL_MAC_ADDR */
-+struct hostcmd_cmd_set_mac_addr {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 mac_type;
-+	u8 mac_addr[ETH_ALEN];
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_RATE_ADAPT_MODE */
-+struct hostcmd_cmd_set_rate_adapt_mode {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 rate_adapt_mode;      /* 0:Indoor, 1:Outdoor */
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_WATCHDOG_BITMAP */
-+struct hostcmd_cmd_get_watchdog_bitmap {
-+	struct hostcmd_header cmd_hdr;
-+	u8 watchdog_bitmap;          /* for SW/BA */
-+} __packed;
-+
-+/* HOSTCMD_CMD_BSS_START */
-+struct hostcmd_cmd_bss_start {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 enable;                  /* FALSE: Disable or TRUE: Enable */
-+	u8 amsdu;
-+} __packed;
-+
-+/* HOSTCMD_CMD_AP_BEACON */
-+struct cf_params {
-+	u8 elem_id;
-+	u8 len;
-+	u8 cfp_cnt;
-+	u8 cfp_period;
-+	__le16 cfp_max_duration;
-+	__le16 cfp_duration_remaining;
-+} __packed;
-+
-+struct ibss_params {
-+	u8 elem_id;
-+	u8 len;
-+	__le16	atim_window;
-+} __packed;
-+
-+union ss_params {
-+	struct cf_params cf_param_set;
-+	struct ibss_params ibss_param_set;
-+} __packed;
-+
-+struct fh_params {
-+	u8 elem_id;
-+	u8 len;
-+	__le16 dwell_time;
-+	u8 hop_set;
-+	u8 hop_pattern;
-+	u8 hop_index;
-+} __packed;
-+
-+struct ds_params {
-+	u8 elem_id;
-+	u8 len;
-+	u8 current_chnl;
-+} __packed;
-+
-+union phy_params {
-+	struct fh_params fh_param_set;
-+	struct ds_params ds_param_set;
-+} __packed;
-+
-+struct rsn_ie {
-+	u8 elem_id;
-+	u8 len;
-+	u8 oui_type[4];              /* 00:50:f2:01 */
-+	u8 ver[2];
-+	u8 grp_key_cipher[4];
-+	u8 pws_key_cnt[2];
-+	u8 pws_key_cipher_list[4];
-+	u8 auth_key_cnt[2];
-+	u8 auth_key_list[4];
-+} __packed;
-+
-+struct rsn48_ie {
-+	u8 elem_id;
-+	u8 len;
-+	u8 ver[2];
-+	u8 grp_key_cipher[4];
-+	u8 pws_key_cnt[2];
-+	u8 pws_key_cipher_list[4];
-+	u8 auth_key_cnt[2];
-+	u8 auth_key_list[4];
-+	u8 rsn_cap[2];
-+	u8 pmk_id_cnt[2];
-+	u8 pmk_id_list[16];          /* Should modify to 16 * S */
-+	u8 reserved[8];
-+} __packed;
-+
-+struct ac_param_rcd {
-+	u8 aci_aifsn;
-+	u8 ecw_min_max;
-+	__le16 txop_lim;
-+} __packed;
-+
-+struct wmm_param_elem {
-+	u8 elem_id;
-+	u8 len;
-+	u8 oui[3];
-+	u8 type;
-+	u8 sub_type;
-+	u8 version;
-+	u8 qos_info;
-+	u8 rsvd;
-+	struct ac_param_rcd ac_be;
-+	struct ac_param_rcd ac_bk;
-+	struct ac_param_rcd ac_vi;
-+	struct ac_param_rcd ac_vo;
-+} __packed;
-+
-+struct channel_info {
-+	u8 first_channel_num;
-+	u8 num_channels;
-+	u8 max_tx_pwr_level;
-+} __packed;
-+
-+struct country {
-+	u8 elem_id;
-+	u8 len;
-+	u8 country_str[3];
-+	struct channel_info channel_info[40];
-+} __packed;
-+
-+struct start_cmd {
-+	u8 sta_mac_addr[ETH_ALEN];
-+	u8 ssid[IEEE80211_MAX_SSID_LEN];
-+	u8 bss_type;
-+	__le16 bcn_period;
-+	u8 dtim_period;
-+	union ss_params ss_param_set;
-+	union phy_params phy_param_set;
-+	__le16 probe_delay;
-+	__le16 cap_info;
-+	u8 b_rate_set[SYSADPT_MAX_DATA_RATES_G];
-+	u8 op_rate_set[SYSADPT_MAX_DATA_RATES_G];
-+	struct rsn_ie rsn_ie;
-+	struct rsn48_ie rsn48_ie;
-+	struct wmm_param_elem wmm_param;
-+	struct country country;
-+	__le32 ap_rf_type;           /* 0->B, 1->G, 2->Mixed, 3->A, 4->11J */
-+	u8 rsvd[3];
-+	u8 bssid[ETH_ALEN];          /* only for 88W8997                   */
-+} __packed;
-+
-+struct hostcmd_cmd_ap_beacon {
-+	struct hostcmd_header cmd_hdr;
-+	struct start_cmd start_cmd;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_NEW_STN */
-+struct add_ht_info {
-+	u8 control_chnl;
-+	u8 add_chnl;
-+	__le16 op_mode;
-+	__le16 stbc;
-+} __packed;
-+
-+struct peer_info {
-+	__le32 legacy_rate_bitmap;
-+	u8 ht_rates[4];
-+	__le16 cap_info;
-+	__le16 ht_cap_info;
-+	u8 mac_ht_param_info;
-+	u8 mrvl_sta;
-+	struct add_ht_info add_ht_info;
-+	__le32 tx_bf_capabilities;   /* EXBF_SUPPORT */
-+	__le32 vht_max_rx_mcs;
-+	__le32 vht_cap;
-+	/* 0:20Mhz, 1:40Mhz, 2:80Mhz, 3:160 or 80+80Mhz */
-+	u8 vht_rx_channel_width;
-+} __packed;
-+
-+struct hostcmd_cmd_set_new_stn {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 aid;
-+	u8 mac_addr[ETH_ALEN];
-+	__le16 stn_id;
-+	__le16 action;
-+	__le16 if_type;
-+	struct peer_info peer_info;
-+	/* UAPSD_SUPPORT */
-+	u8 qos_info;
-+	u8 is_qos_sta;
-+	__le32 fw_sta_ptr;
-+} __packed;
-+
-+struct retry_cnt_qos {
-+	u8 retry_cfg_enable;
-+	u8 retry_cnt_BK;
-+	u8 retry_cnt_BE;
-+	u8 retry_cnt_VI;
-+	u8 retry_cnt_VO;
-+} __packed;
-+
-+struct peer_info_sc4 {
-+	__le32 legacy_rate_bitmap;
-+	u8 ht_rates[4];
-+	__le16 cap_info;
-+	__le16 ht_cap_info;
-+	u8 mac_ht_param_info;
-+	u8 mrvl_sta;
-+	struct add_ht_info add_ht_info;
-+	__le32 tx_bf_capabilities;   /* EXBF_SUPPORT */
-+	__le32 vht_max_rx_mcs;
-+	__le32 vht_cap;
-+	/* 0:20Mhz, 1:40Mhz, 2:80Mhz, 3:160 or 80+80Mhz */
-+	u8 vht_rx_channel_width;
-+	struct retry_cnt_qos retry_cnt_qos;
-+	u8 assoc_rssi;
-+} __packed;
-+
-+struct hostcmd_cmd_set_new_stn_sc4 {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 aid;
-+	u8 mac_addr[ETH_ALEN];
-+	__le16 stn_id;
-+	__le16 action;
-+	__le16 reserved;
-+	struct peer_info_sc4 peer_info;
-+	/* UAPSD_SUPPORT */
-+	u8 qos_info;
-+	u8 is_qos_sta;
-+	__le32 fw_sta_ptr;
-+	__le32 wds;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_APMODE */
-+struct hostcmd_cmd_set_apmode {
-+	struct hostcmd_header cmd_hdr;
-+	u8 apmode;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_SWITCH_CHANNEL */
-+struct hostcmd_cmd_set_switch_channel {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 next_11h_chnl;
-+	__le32 mode;
-+	__le32 init_count;
-+	__le32 chnl_flags;
-+	__le32 next_ht_extchnl_offset;
-+	__le32 dfs_test_mode;
-+} __packed;
-+
-+/* HOSTCMD_CMD_UPDATE_ENCRYPTION */
-+struct hostcmd_cmd_update_encryption {
-+	struct hostcmd_header cmd_hdr;
-+	/* Action type - see encr_action_type */
-+	__le32 action_type;          /* encr_action_type */
-+	/* size of the data buffer attached. */
-+	__le32 data_length;
-+	u8 mac_addr[ETH_ALEN];
-+	u8 action_data[1];
-+} __packed;
-+
-+struct wep_type_key {
-+	/* WEP key material (max 128bit) */
-+	u8 key_material[MAX_ENCR_KEY_LENGTH];
-+} __packed;
-+
-+struct encr_tkip_seqcnt {
-+	__le16 low;
-+	__le32 high;
-+} __packed;
-+
-+struct tkip_type_key {
-+	/* TKIP Key material. Key type (group or pairwise key) is
-+	 * determined by flags
-+	 */
-+	/* in KEY_PARAM_SET structure. */
-+	u8 key_material[MAX_ENCR_KEY_LENGTH];
-+	/* MIC keys */
-+	u8 tkip_tx_mic_key[MIC_KEY_LENGTH];
-+	u8 tkip_rx_mic_key[MIC_KEY_LENGTH];
-+	struct encr_tkip_seqcnt	tkip_rsc;
-+	struct encr_tkip_seqcnt	tkip_tsc;
-+} __packed;
-+
-+struct aes_type_key {
-+	/* AES Key material */
-+	u8 key_material[MAX_ENCR_KEY_LENGTH];
-+} __packed;
-+
-+union mwl_key_type {
-+	struct wep_type_key  wep_key;
-+	struct tkip_type_key tkip_key;
-+	struct aes_type_key  aes_key;
-+} __packed;
-+
-+struct key_param_set {
-+	/* Total length of this structure (Key is variable size array) */
-+	__le16 length;
-+	/* Key type - WEP, TKIP or AES-CCMP. */
-+	/* See definitions above */
-+	__le16 key_type_id;
-+	/* key flags (ENCR_KEY_FLAG_XXX_ */
-+	__le32 key_info;
-+	/* For WEP only - actual key index */
-+	__le32 key_index;
-+	/* Size of the key */
-+	__le16 key_len;
-+	/* Key material (variable size array) */
-+	union mwl_key_type key;
-+	u8 mac_addr[ETH_ALEN];
-+} __packed;
-+
-+struct hostcmd_cmd_set_key {
-+	struct hostcmd_header cmd_hdr;
-+	/* Action type - see encr_action_type */
-+	__le32 action_type;          /* encr_action_type */
-+	/* size of the data buffer attached. */
-+	__le32 data_length;
-+	/* data buffer - maps to one KEY_PARAM_SET structure */
-+	struct key_param_set key_param;
-+} __packed;
-+
-+/* HOSTCMD_CMD_BASTREAM */
-+#define BA_TYPE_MASK           0x00000001
-+#define BA_DIRECTION_MASK      0x0000000e
-+#define BA_DIRECTION_SHIFT     1
-+
-+#define BA_TYPE_MASK_NDP       0x00000003
-+#define BA_DIRECTION_MASK_NDP  0x0000001c
-+#define BA_DIRECTION_SHIFT_NDP 2
-+
-+struct ba_context {
-+	__le32 context;
-+} __packed;
-+
-+/* parameters for block ack creation */
-+struct create_ba_params {
-+	/* BA Creation flags - see above */
-+	__le32 flags;
-+	/* idle threshold */
-+	__le32 idle_thrs;
-+	/* block ack transmit threshold (after how many pkts should we
-+	 * send BAR?)
-+	 */
-+	__le32 bar_thrs;
-+	/* receiver window size */
-+	__le32 window_size;
-+	/* MAC Address of the BA partner */
-+	u8 peer_mac_addr[ETH_ALEN];
-+	/* Dialog Token */
-+	u8 dialog_token;
-+	/* TID for the traffic stream in this BA */
-+	u8 tid;
-+	/* shared memory queue ID (not sure if this is required) */
-+	u8 queue_id;
-+	u8 param_info;
-+	/* returned by firmware - firmware context pointer. */
-+	/* this context pointer will be passed to firmware for all
-+	 * future commands.
-+	 */
-+	struct ba_context fw_ba_context;
-+	u8 reset_seq_no;             /** 0 or 1**/
-+	__le16 current_seq;
-+	__le32 vht_rx_factor;
-+	/* This is for virtual station in Sta proxy mode for V6FW */
-+	u8 sta_src_mac_addr[ETH_ALEN];
-+} __packed;
-+
-+/* new transmit sequence number information */
-+struct ba_update_seq_num {
-+	/* BA flags - see above */
-+	__le32 flags;
-+	/* returned by firmware in the create ba stream response */
-+	struct ba_context fw_ba_context;
-+	/* new sequence number for this block ack stream */
-+	__le16 ba_seq_num;
-+} __packed;
-+
-+struct ba_stream_context {
-+	/* BA Stream flags */
-+	__le32 flags;
-+	/* returned by firmware in the create ba stream response */
-+	struct ba_context fw_ba_context;
-+	u8 tid;
-+	u8 peer_mac_addr[ETH_ALEN];
-+} __packed;
-+
-+union ba_info {
-+	/* information required to create BA Stream... */
-+	struct create_ba_params	create_params;
-+	/* update starting/new sequence number etc. */
-+	struct ba_update_seq_num updt_seq_num;
-+	/* destroy an existing stream... */
-+	struct ba_stream_context destroy_params;
-+	/* destroy an existing stream... */
-+	struct ba_stream_context flush_params;
-+} __packed;
-+
-+struct hostcmd_cmd_bastream {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 action_type;
-+	union ba_info ba_info;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_SPECTRUM_MGMT */
-+struct hostcmd_cmd_set_spectrum_mgmt {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 spectrum_mgmt;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_POWER_CONSTRAINT */
-+struct hostcmd_cmd_set_power_constraint {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 power_constraint;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_COUNTRY_CODE */
-+struct domain_chnl_entry {
-+	u8 first_chnl_num;
-+	u8 chnl_num;
-+	u8 max_transmit_pw;
-+} __packed;
-+
-+struct domain_country_info {
-+	u8 country_string[3];
-+	u8 g_chnl_len;
-+	struct domain_chnl_entry domain_entry_g[1];
-+	u8 a_chnl_len;
-+	struct domain_chnl_entry domain_entry_a[20];
-+} __packed;
-+
-+struct hostcmd_cmd_set_country_code {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 action ; /* 0 -> unset, 1 ->set */
-+	struct domain_country_info domain_info;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_OPTIMIZATION_LEVEL */
-+struct hostcmd_cmd_set_optimization_level {
-+	struct hostcmd_header cmd_hdr;
-+	u8 opt_level;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_WSC_IE */
-+struct hostcmd_cmd_set_wsc_ie {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 ie_type;              /* 0 -- beacon. or 1 -- probe response. */
-+	__le16 len;
-+	u8 data[WSC_IE_MAX_LENGTH];
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_RATETABLE */
-+struct hostcmd_cmd_get_ratetable {
-+	struct hostcmd_header cmd_hdr;
-+	u8 addr[ETH_ALEN];
-+	u8 type;                     /* 0: SU, 1: MU */
-+	/* multiply 2 because 2 DWORD in rate info   */
-+	__le32 sorted_rates_idx_map[2 * SYSADPT_MAX_RATE_ADAPT_RATES];
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_SEQNO */
-+struct hostcmd_cmd_get_seqno {
-+	struct hostcmd_header cmd_hdr;
-+	u8 mac_addr[ETH_ALEN];
-+	u8 tid;
-+	__le16 seq_no;
-+	u8 reserved;
-+} __packed;
-+
-+/* HOSTCMD_CMD_DWDS_ENABLE */
-+struct hostcmd_cmd_dwds_enable {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 enable;               /* 0 -- Disable. or 1 -- Enable. */
-+} __packed;
-+
-+/* HOSTCMD_CMD_FW_FLUSH_TIMER */
-+struct hostcmd_cmd_fw_flush_timer {
-+	struct hostcmd_header cmd_hdr;
-+	/* 0 -- Disable. > 0 -- holds time value in usecs. */
-+	__le32 value;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_CDD */
-+struct hostcmd_cmd_set_cdd {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 enable;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_BFTYPE */
-+struct hostcmd_cmd_set_bftype {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 action;
-+	__le32 mode;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_TEMP */
-+struct hostcmd_cmd_get_temp {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 celcius;
-+	__le32 raw_data;
-+} __packed;
-+
-+/* HOSTCMD_CMD_LED_CTRL */
-+struct hostcmd_cmd_led_ctrl {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;     /* 0: GET, 1: SET (only SET is supported) */
-+	u8 led_enable;     /* 0: Disable, 1: Enable                  */
-+	u8 led_control;    /* 0: HW 1: SW (only SW is supported)     */
-+	u8 led_blink_rate; /* 1: Slow, 2: Medium, 3: Fast blink      */
-+	u8 reserved;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_FW_REGION_CODE */
-+struct hostcmd_cmd_get_fw_region_code {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 status; /* 0 = Found, 1 = Error */
-+	__le32 fw_region_code;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_DEVICE_PWR_TBL */
-+#define HAL_TRPC_ID_MAX    16
-+
-+struct channel_power_tbl {
-+	u8 channel;
-+	u8 tx_pwr[HAL_TRPC_ID_MAX];
-+	u8 dfs_capable;
-+	u8 ax_ant;
-+	u8 cdd;
-+} __packed;
-+
-+struct hostcmd_cmd_get_device_pwr_tbl {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 status; /* 0 = Found, 1 = Error */
-+	u8 region_code;
-+	u8 number_of_channels;
-+	__le32 current_channel_index;
-+	/* Only for 1 channel, so, 1 channel at a time */
-+	struct channel_power_tbl channel_pwr_tbl;
-+} __packed;
-+
-+/* HOSTCMD_CMD_SET_RATE_DROP */
-+struct hostcmd_cmd_set_rate_drop {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 enable;
-+	__le32 rate_index;
-+	__le32 sta_index;
-+} __packed;
-+
-+/* HOSTCMD_CMD_NEWDP_DMATHREAD_START */
-+struct hostcmd_cmd_newdp_dmathread_start {
-+	struct hostcmd_header cmd_hdr;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_FW_REGION_CODE_SC4 */
-+struct hostcmd_cmd_get_fw_region_code_sc4 {
-+	struct hostcmd_header cmd_hdr;
-+	__le32 status; /* 0 = Found, 1 = Error */
-+	__le32 fw_region_code;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_DEVICE_PWR_TBL_SC4 */
-+#define HAL_TRPC_ID_MAX_SC4        32
-+#define MAX_GROUP_PER_CHANNEL_5G   39
-+#define MAX_GROUP_PER_CHANNEL_2G   21
-+#define	MAX(a, b) (((a) > (b)) ? (a) : (b))
-+#define MAX_GROUP_PER_CHANNEL_RATE \
-+	MAX(MAX_GROUP_PER_CHANNEL_5G, MAX_GROUP_PER_CHANNEL_2G)
-+
-+struct channel_power_tbl_sc4 {
-+	u8 channel;
-+	u8 grp_pwr[MAX_GROUP_PER_CHANNEL_RATE];
-+	u8 tx_pwr[HAL_TRPC_ID_MAX_SC4];
-+	u8 dfs_capable;
-+	u8 ax_ant;
-+	u8 cdd;
-+	u8 rsvd;
-+} __packed;
-+
-+struct hostcmd_cmd_get_device_pwr_tbl_sc4 {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 status; /* 0 = Found, 1 = Error */
-+	u8 region_code;
-+	u8 number_of_channels;
-+	__le32 current_channel_index;
-+	/* Only for 1 channel, so, 1 channel at a time */
-+	struct channel_power_tbl_sc4 channel_pwr_tbl;
-+} __packed;
-+
-+/* HOSTCMD_CMD_QUIET_MODE */
-+struct hostcmd_cmd_quiet_mode {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le32 enable;
-+	__le32 period;
-+	__le32 duration;
-+	__le32 next_offset;
-+} __packed;
-+
-+/* HOSTCMD_CMD_CORE_DUMP_DIAG_MODE */
-+struct hostcmd_cmd_core_dump_diag_mode {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 status;
-+} __packed;
-+
-+/* HOSTCMD_CMD_GET_FW_CORE_DUMP */
-+#define MAX_CORE_REGIONS       20
-+#define MAX_CORE_SYMBOLS       30
-+#define MVL_COREDUMP_DIAG_MODE 0x00000001
-+#define MVL_COREDUMP_INCL_EXT  0x00000002
-+#define MAX_CORE_DUMP_BUFFER   2048
-+
-+struct core_region {
-+	__le32 address;
-+	__le32 length;
-+} __packed;
-+
-+struct core_symbol {
-+	u8 name[16];
-+	__le32 address;
-+	__le32 length;
-+	__le16 entries;
-+} __packed;
-+
-+struct coredump {
-+	u8 version_major;
-+	u8 version_minor;
-+	u8 version_patch;
-+	u8 hdr_version;
-+	u8 num_regions;
-+	u8 num_symbols;
-+	u8 fill[2];
-+	struct core_region region[MAX_CORE_REGIONS];
-+	struct core_symbol symbol[MAX_CORE_SYMBOLS];
-+	__le32 fill_end[40];
-+} __packed;
-+
-+struct coredump_cmd {
-+	__le32 context;
-+	__le32 buffer;
-+	__le32 buffer_len;
-+	__le16 size_kb;
-+	__le16 flags;
-+} __packed;
-+
-+struct debug_mem_cmd {
-+	__le32 set;
-+	__le32 type;
-+	__le32 addr;
-+	__le32 val;
-+} __packed;
-+
-+struct hostcmd_cmd_get_fw_core_dump {
-+	struct hostcmd_header cmd_hdr;
-+	union {
-+		struct coredump_cmd coredump;
-+		struct debug_mem_cmd debug_mem;
-+	} cmd_data;
-+	/*Buffer where F/W Copies the Core Dump*/
-+	char buffer[MAX_CORE_DUMP_BUFFER];
-+} __packed;
-+
-+struct hostcmd_cmd_get_fw_core_dump_ {
-+	struct hostcmd_header cmd_hdr;
-+	union {
-+		struct coredump_cmd coredump;
-+		struct debug_mem_cmd debug_mem;
-+	} cmd_data;
-+} __packed;
-+
-+/* HOSTCMD_CMD_802_11_SLOT_TIME */
-+struct hostcmd_cmd_802_11_slot_time {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	/* 0:long slot; 1:short slot */
-+	__le16 short_slot;
-+} __packed;
-+
-+/* HOSTCMD_CMD_EDMAC_CTRL */
-+struct hostcmd_cmd_edmac_ctrl {
-+	struct hostcmd_header cmd_hdr;
-+	__le16 action;
-+	__le16 ed_ctrl_2g;
-+	__le16 ed_offset_2g;
-+	__le16 ed_ctrl_5g;
-+	__le16 ed_offset_5g;
-+	__le16 ed_bitmap_txq_lock;
-+} __packed;
-+
-+/* HOSTCMD_CMD_TXPWRLMT_CFG */
-+#define TXPWRLMT_CFG_VERSION_INFO_LEN 0x4
-+#define TXPWRLMT_CFG_MAX_SUBBAND_INFO 0x5
-+#define TXPWRLMT_CFG_SIG_LEN          0x4
-+#define TXPWRLMT_CFG_SIGNATURE        0xA1240E01
-+
-+struct hostcmd_cmd_txpwrlmt_cfg {
-+	struct hostcmd_header cmd_hdr;
-+	/* Action */
-+	__le16 action;
-+	/*Sub band id*/
-+	u8 subband_id;
-+	/* Cfg Complete Info*/
-+	u8 cfgComplete;
-+	/* Data length */
-+	__le16 data_len;
-+	/*number of entries*/
-+	__le16 num_entries;
-+	/* Data */
-+	u8 data[1];
-+} __packed;
-+
-+struct mwl_txpwrlmt_cfg_entry_hdr {
-+	/* subband id */
-+	__le16 id;
-+	/* length */
-+	__le16 len;
-+	/* number of entries */
-+	__le16 num_entries;
-+} __packed;
-+
-+/* HOSTCMD_CMD_MCAST_CTS */
-+struct hostcmd_cmd_mcast_cts {
-+	struct hostcmd_header cmd_hdr;
-+	u8 enable;            /* 1:enable, 0:disable */
-+} __packed;
-+
-+#endif /* _HOSTCMD_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/dev.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/dev.h
-new file mode 100644
-index 000000000000..2c26bff80683
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/dev.h
-@@ -0,0 +1,1032 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines device related information. */
-+
-+#ifndef _DEV_H_
-+#define _DEV_H_
-+
-+#include <linux/version.h>
-+#include <linux/interrupt.h>
-+#include <linux/pci.h>
-+#include <linux/firmware.h>
-+#include <linux/delay.h>
-+#include <linux/bitops.h>
-+#include <net/mac80211.h>
-+
-+#define PCIE_DRV_NAME    KBUILD_MODNAME
-+#define PCIE_DRV_VERSION "10.3.8.0-20181210"
-+
-+#define PCIE_MIN_BYTES_HEADROOM   64
-+#define PCIE_MIN_TX_HEADROOM_KF2  96
-+#define PCIE_NUM_OF_DESC_DATA     SYSADPT_TOTAL_TX_QUEUES
-+#define PCIE_AMPDU_QUEUES         4
-+#define PCIE_MAX_NUM_TX_DESC      256
-+#define PCIE_TX_QUEUE_LIMIT       (3 * PCIE_MAX_NUM_TX_DESC)
-+#define PCIE_TX_WAKE_Q_THRESHOLD  (2 * PCIE_MAX_NUM_TX_DESC)
-+#define PCIE_DELAY_FREE_Q_LIMIT   PCIE_MAX_NUM_TX_DESC
-+#define PCIE_MAX_NUM_RX_DESC      256
-+#define PCIE_RECEIVE_LIMIT        64
-+
-+enum {
-+	IEEE_TYPE_MANAGEMENT = 0,
-+	IEEE_TYPE_CONTROL,
-+	IEEE_TYPE_DATA
-+};
-+
-+#define MAC_REG_ADDR(offset)      (offset)
-+#define MAC_REG_ADDR_PCI(offset)  ((pcie_priv->iobase1 + 0xA000) + offset)
-+
-+#define MCU_CCA_CNT               MAC_REG_ADDR(0x06A0)
-+#define MCU_TXPE_CNT              MAC_REG_ADDR(0x06A4)
-+#define MCU_LAST_READ             MAC_REG_ADDR(0x06A8)
-+
-+/* Map to 0x80000000 (Bus control) on BAR0 */
-+#define MACREG_REG_H2A_INTERRUPT_EVENTS      0x00000C18 /* (From host to ARM) */
-+#define MACREG_REG_H2A_INTERRUPT_CAUSE       0x00000C1C /* (From host to ARM) */
-+#define MACREG_REG_H2A_INTERRUPT_MASK        0x00000C20 /* (From host to ARM) */
-+#define MACREG_REG_H2A_INTERRUPT_CLEAR_SEL   0x00000C24 /* (From host to ARM) */
-+#define MACREG_REG_H2A_INTERRUPT_STATUS_MASK 0x00000C28 /* (From host to ARM) */
-+
-+#define MACREG_REG_A2H_INTERRUPT_EVENTS      0x00000C2C /* (From ARM to host) */
-+#define MACREG_REG_A2H_INTERRUPT_CAUSE       0x00000C30 /* (From ARM to host) */
-+#define MACREG_REG_A2H_INTERRUPT_MASK        0x00000C34 /* (From ARM to host) */
-+#define MACREG_REG_A2H_INTERRUPT_CLEAR_SEL   0x00000C38 /* (From ARM to host) */
-+#define MACREG_REG_A2H_INTERRUPT_STATUS_MASK 0x00000C3C /* (From ARM to host) */
-+
-+/* Map to 0x80000000 on BAR1 */
-+#define MACREG_REG_GEN_PTR                  0x00000C10
-+#define MACREG_REG_INT_CODE                 0x00000C14
-+
-+/* Bit definition for MACREG_REG_A2H_INTERRUPT_CAUSE (A2HRIC) */
-+#define MACREG_A2HRIC_BIT_TX_DONE           BIT(0)
-+#define MACREG_A2HRIC_BIT_RX_RDY            BIT(1)
-+#define MACREG_A2HRIC_BIT_OPC_DONE          BIT(2)
-+#define MACREG_A2HRIC_BIT_MAC_EVENT         BIT(3)
-+#define MACREG_A2HRIC_BIT_RX_PROBLEM        BIT(4)
-+#define MACREG_A2HRIC_BIT_RADIO_OFF         BIT(5)
-+#define MACREG_A2HRIC_BIT_RADIO_ON          BIT(6)
-+#define MACREG_A2HRIC_BIT_RADAR_DETECT      BIT(7)
-+#define MACREG_A2HRIC_BIT_ICV_ERROR         BIT(8)
-+#define MACREG_A2HRIC_BIT_WEAKIV_ERROR      BIT(9)
-+#define MACREG_A2HRIC_BIT_QUE_EMPTY         BIT(10)
-+#define MACREG_A2HRIC_BIT_QUE_FULL          BIT(11)
-+#define MACREG_A2HRIC_BIT_CHAN_SWITCH       BIT(12)
-+#define MACREG_A2HRIC_BIT_TX_WATCHDOG       BIT(13)
-+#define MACREG_A2HRIC_BA_WATCHDOG           BIT(14)
-+/* 15 taken by ISR_TXACK */
-+#define MACREG_A2HRIC_BIT_SSU_DONE          BIT(16)
-+#define MACREG_A2HRIC_CONSEC_TXFAIL         BIT(17)
-+
-+#define ISR_SRC_BITS        (MACREG_A2HRIC_BIT_RX_RDY | \
-+			     MACREG_A2HRIC_BIT_TX_DONE | \
-+			     MACREG_A2HRIC_BIT_OPC_DONE | \
-+			     MACREG_A2HRIC_BIT_MAC_EVENT | \
-+			     MACREG_A2HRIC_BIT_WEAKIV_ERROR | \
-+			     MACREG_A2HRIC_BIT_ICV_ERROR | \
-+			     MACREG_A2HRIC_BIT_SSU_DONE | \
-+			     MACREG_A2HRIC_BIT_RADAR_DETECT | \
-+			     MACREG_A2HRIC_BIT_CHAN_SWITCH | \
-+			     MACREG_A2HRIC_BIT_TX_WATCHDOG | \
-+			     MACREG_A2HRIC_BIT_QUE_EMPTY | \
-+			     MACREG_A2HRIC_BA_WATCHDOG | \
-+			     MACREG_A2HRIC_CONSEC_TXFAIL)
-+
-+#define MACREG_A2HRIC_BIT_MASK      ISR_SRC_BITS
-+
-+/* Bit definition for MACREG_REG_H2A_INTERRUPT_CAUSE (H2ARIC) */
-+#define MACREG_H2ARIC_BIT_PPA_READY         BIT(0)
-+#define MACREG_H2ARIC_BIT_DOOR_BELL         BIT(1)
-+#define MACREG_H2ARIC_BIT_PS                BIT(2)
-+#define MACREG_H2ARIC_BIT_PSPOLL            BIT(3)
-+#define ISR_RESET                           BIT(15)
-+#define ISR_RESET_AP33                      BIT(26)
-+
-+/* Data descriptor related constants */
-+#define EAGLE_RXD_CTRL_DRIVER_OWN           0x00
-+#define EAGLE_RXD_CTRL_DMA_OWN              0x80
-+
-+#define EAGLE_RXD_STATUS_OK                 0x01
-+
-+#define EAGLE_TXD_STATUS_IDLE               0x00000000
-+#define EAGLE_TXD_STATUS_OK                 0x00000001
-+#define EAGLE_TXD_STATUS_FW_OWNED           0x80000000
-+
-+struct pcie_tx_desc {
-+	u8 data_rate;
-+	u8 tx_priority;
-+	__le16 qos_ctrl;
-+	__le32 pkt_ptr;
-+	__le16 pkt_len;
-+	u8 dest_addr[ETH_ALEN];
-+	__le32 pphys_next;
-+	__le32 sap_pkt_info;
-+	__le32 rate_info;
-+	u8 type;
-+	u8 xmit_control;     /* bit 0: use rateinfo, bit 1: disable ampdu */
-+	__le16 reserved;
-+	__le32 tcpack_sn;
-+	__le32 tcpack_src_dst;
-+	__le32 reserved1;
-+	__le32 reserved2;
-+	u8 reserved3[2];
-+	u8 packet_info;
-+	u8 packet_id;
-+	__le16 packet_len_and_retry;
-+	__le16 packet_rate_info;
-+	__le32 flags;
-+	__le32 status;
-+} __packed;
-+
-+struct pcie_tx_hndl {
-+	struct sk_buff *psk_buff;
-+	struct pcie_tx_desc *pdesc;
-+	struct pcie_tx_hndl *pnext;
-+};
-+
-+/* Receive rate information constants */
-+#define RX_RATE_INFO_FORMAT_11A       0
-+#define RX_RATE_INFO_FORMAT_11B       1
-+#define RX_RATE_INFO_FORMAT_11N       2
-+#define RX_RATE_INFO_FORMAT_11AC      4
-+
-+#define RX_RATE_INFO_HT20             0
-+#define RX_RATE_INFO_HT40             1
-+#define RX_RATE_INFO_HT80             2
-+#define RX_RATE_INFO_HT160            3
-+
-+#define RX_RATE_INFO_LONG_INTERVAL    0
-+#define RX_RATE_INFO_SHORT_INTERVAL   1
-+
-+#define MWL_RX_RATE_FORMAT_MASK       0x0007
-+#define MWL_RX_RATE_NSS_MASK          0x0018
-+#define MWL_RX_RATE_NSS_SHIFT         3
-+#define MWL_RX_RATE_BW_MASK           0x0060
-+#define MWL_RX_RATE_BW_SHIFT          5
-+#define MWL_RX_RATE_GI_MASK           0x0080
-+#define MWL_RX_RATE_GI_SHIFT          7
-+#define MWL_RX_RATE_RT_MASK           0xFF00
-+#define MWL_RX_RATE_RT_SHIFT          8
-+
-+struct pcie_rx_desc {
-+	__le16 pkt_len;              /* total length of received data      */
-+	__le16 rate;                 /* receive rate information           */
-+	__le32 pphys_buff_data;      /* physical address of payload data   */
-+	__le32 pphys_next;           /* physical address of next RX desc   */
-+	__le16 qos_ctrl;             /* received QosCtrl field variable    */
-+	__le16 ht_sig2;              /* like name states                   */
-+	__le32 hw_rssi_info;
-+	__le32 hw_noise_floor_info;
-+	u8 noise_floor;
-+	u8 reserved[3];
-+	u8 rssi;                     /* received signal strengt indication */
-+	u8 status;                   /* status field containing USED bit   */
-+	u8 channel;                  /* channel this pkt was received on   */
-+	u8 rx_control;               /* the control element of the desc    */
-+	__le32 reserved1[3];
-+} __packed;
-+
-+struct pcie_rx_hndl {
-+	struct sk_buff *psk_buff;    /* associated sk_buff for Linux       */
-+	struct pcie_rx_desc *pdesc;
-+	struct pcie_rx_hndl *pnext;
-+};
-+
-+struct pcie_desc_data {
-+	dma_addr_t pphys_tx_ring;          /* ptr to first TX desc (phys.)    */
-+	struct pcie_tx_desc *ptx_ring;     /* ptr to first TX desc (virt.)    */
-+	struct pcie_tx_hndl *tx_hndl;
-+	struct pcie_tx_hndl *pnext_tx_hndl;/* next TX handle that can be used */
-+	struct pcie_tx_hndl *pstale_tx_hndl;/* the staled TX handle           */
-+	dma_addr_t pphys_rx_ring;          /* ptr to first RX desc (phys.)    */
-+	struct pcie_rx_desc *prx_ring;     /* ptr to first RX desc (virt.)    */
-+	struct pcie_rx_hndl *rx_hndl;
-+	struct pcie_rx_hndl *pnext_rx_hndl;/* next RX handle that can be used */
-+	u32 wcb_base;                      /* FW base offset for registers    */
-+	u32 rx_desc_write;                 /* FW descriptor write position    */
-+	u32 rx_desc_read;                  /* FW descriptor read position     */
-+	u32 rx_buf_size;                   /* length of the RX buffers        */
-+};
-+
-+/* DMA header used by firmware and hardware. */
-+struct pcie_dma_data {
-+	__le16 fwlen;
-+	struct ieee80211_hdr wh;
-+	char data[0];
-+} __packed;
-+
-+/* New Data Path */
-+#define MACREG_REG_SCRATCH3                0x00000C44
-+#define MACREG_REG_TXSENDHEAD              0x00000CD0
-+#define MACREG_REG_TXSEDNTAIL              0x00000CD4
-+#define MACREG_REG_TXDONEHEAD              0x00000CD8
-+#define MACREG_REG_TXDONETAIL              0x00000CDC
-+#define MACREG_REG_RXDESCHEAD              0x00000CE0
-+#define MACREG_REG_RXDESCTAIL              0x00000CE4
-+#define MACREG_REG_RXDONEHEAD              0x00000CE8
-+#define MACREG_REG_RXDONETAIL              0x00000CEC
-+#define MACREG_REG_ACNTHEAD                0x00000CF0
-+#define MACREG_REG_ACNTTAIL                0x00000CF4
-+
-+/* Buff removed from Tx Send Ring */
-+#define MACREG_A2HRIC_TX_DESC_TAIL_RDY     (1<<9)
-+/* Buff added to Tx Done Ring */
-+#define MACREG_A2HRIC_TX_DONE_HEAD_RDY     (1<<10)
-+/* Records added to Accounting Ring */
-+#define MACREG_A2HRIC_ACNT_HEAD_RDY        (1<<12)
-+/* Buff removed from Rx Desc Ring */
-+#define MACREG_A2HRIC_RX_DESC_TAIL_RDY     (1<<17)
-+/* Buff added to Rx Done Ring */
-+#define MACREG_A2HRIC_RX_DONE_HEAD_RDY     (1<<18)
-+#define MACREG_A2HRIC_NEWDP_DFS            (1<<19)
-+#define MACREG_A2HRIC_NEWDP_CHANNEL_SWITCH (1<<20)
-+
-+#define ISR_SRC_BITS_NDP     ((MACREG_A2HRIC_ACNT_HEAD_RDY) | \
-+			      (MACREG_A2HRIC_RX_DONE_HEAD_RDY) | \
-+			      (MACREG_A2HRIC_NEWDP_DFS)     | \
-+			      (MACREG_A2HRIC_NEWDP_CHANNEL_SWITCH))
-+
-+#define MACREG_A2HRIC_BIT_MASK_NDP ISR_SRC_BITS_NDP
-+
-+#define MIN_BYTES_RX_HEADROOM  (64 + 2)
-+#define AMPDU_QUEUES_NDP       (SYSADPT_MAX_STA_SC4 * \
-+				SYSADPT_MAX_TID)
-+#define MAX_NUM_TX_DESC        1024
-+#define MAX_NUM_RX_DESC        (1024 * 16)
-+#define MAX_TX_RING_SEND_SIZE  (4 * MAX_NUM_TX_DESC)
-+#define MAX_TX_RING_DONE_SIZE  MAX_NUM_TX_DESC
-+#define MAX_RX_RING_SEND_SIZE  MAX_NUM_RX_DESC
-+#define MAX_RX_RING_DONE_SIZE  MAX_NUM_RX_DESC
-+#define DEFAULT_ACNT_RING_SIZE 0x10000
-+#define MAX_AGGR_SIZE          1900
-+#define TX_QUEUE_LIMIT         MAX_NUM_TX_DESC
-+#define TX_WAKE_Q_THRESHOLD    (MAX_NUM_TX_DESC - 256)
-+
-+/* RateCode usage notes:
-+ * * General
-+ *     * No error checking is provided on RateCodes, so usage of invalid values
-+ *       or rates not supported by HW can result in undefined operation.
-+ *     * Some values are not allowed by Std, but are included to sanitize the
-+ *       table;
-+ *     * MaxPwr should only be used for rates that can be sent using Max Power,
-+ *       such as for TxEVM limits or regulatory. It is only valid for Host
-+ *       Generated frames, and not for DRA, etc.
-+ * * VHT
-+ *     * Need to reconsile MU.
-+ * * HT
-+ *     * MCS and SS are made to mimic 11ac, so MCS=mcs[2:0] and SS=mcs[4:3];
-+ *     * MCS32 is selected by providing MCS=10;
-+ * * Legacy
-+ *     * MCS0..7  = 6/9/12/18/24/36/48/54;
-+ *     * MCS8..15 = 1S/1L/2S/2L/5.5S/5.5L/11S/11L;
-+ *     * BW is used to request legacy duplicate modes;
-+ */
-+#define RATECODE_DEFAULT        0xFFFF  /* Don't override the Rate            */
-+#define RATECODE_TYPE_MASK      0xC000  /* Mask  to extract Type              */
-+#define RATECODE_TYPE_SHIFT     14      /* Shift to extract Type              */
-+#define RATECODE_TYPE_VHT       0x8000  /* Use VHT rates                      */
-+#define RATECODE_TYPE_HT        0x4000  /* Use HT rates                       */
-+#define RATECODE_TYPE_LEGACY    0x0000  /* Use Legacy (a/b/g) rates           */
-+#define RATECODE_MAXPWR         0x2000  /* Send at Max Power / Off Channel    */
-+#define RATECODE_RSVD           0x1000  /* Unused                             */
-+#define RATECODE_STBC           0x0800  /* Use Space Time Block Codes         */
-+#define RATECODE_BFMR           0x0400  /* Use Beamforming                    */
-+#define RATECODE_SS_MASK        0x0300  /* Mask  to extract nSS-1             */
-+#define RATECODE_SS_SHIFT       8       /* Shift to extract nSS-1             */
-+#define RATECODE_MCS_MASK       0x00F0  /* Mask  to extract MCS rate          */
-+#define RATECODE_MCS_SHIFT      4       /* Shift to extract MCS rate          */
-+#define RATECODE_BW_MASK        0x000C  /* Mask  to extract Channel BW        */
-+#define RATECODE_BW_SHIFT       2       /* Shift to extract Channel BW        */
-+#define RATECODE_BW_160MHZ      0x000C  /* Send 160M wide packet (or 80+80)   */
-+#define RATECODE_BW_80MHZ       0x0008  /* Send  80M wide packet              */
-+#define RATECODE_BW_40MHZ       0x0004  /* Send  40M wide packet              */
-+#define RATECODE_BW_20MHZ       0x0000  /* Send  20M wide packet              */
-+#define RATECODE_LDPC           0x0002  /* Use Low Density Parity Codes       */
-+#define RATECODE_SGI            0x0001  /* Use Short Guard Interval           */
-+
-+#define TXRING_CTRL_LEN_SHIFT   0      /* PCIe Payload size (Starts w/ SNAP)  */
-+#define TXRING_CTRL_LEN_MASK    0x3FFF /* PCIe Payload size (Starts w/ SNAP)  */
-+#define TXRING_CTRL_QID_SHIFT   14     /* Queue ID (STA*UP, Mcast, MC2UC, etc)*/
-+#define TXRING_CTRL_QID_MASK    0xFFF  /* Queue ID (STA*UP, Mcast, MC2UC, etc)*/
-+#define TXRING_CTRL_TAG_SHIFT   26     /* Tags for special Processing         */
-+#define TXRING_CTRL_TAG_MASK    0x3F   /* Tags for special Processing         */
-+#define TXRING_CTRL_TAG_MGMT    0x01   /* Has Host generated dot11 Header     */
-+#define TXRING_CTRL_TAG_EAP     0x02   /* Tag for EAPOL frames                */
-+#define TXRING_CTRL_TAG_TCP_ACK 0x4
-+#define TXRING_CTRL_TAG_RSVD    0x3C   /* Unused                              */
-+
-+struct tx_info { /* Tx INFO used by MAC HW */
-+	__le32 reserved0[10];
-+	__le32 rate_info;
-+	__le32 reserved1[14];
-+} __packed;
-+
-+struct pcie_tx_desc_ndp {
-+	union { /* Union for Tx DA/SA or Mgmt Overrides */
-+		struct { /* Fields for Data frames     */
-+			u8 da[ETH_ALEN];  /* L2 Destination Address         */
-+			u8 sa[ETH_ALEN];  /* L2 Source Address              */
-+		};
-+		struct { /* Fields when marked as Mgmt */
-+			__le16 rate_code; /* Rate Code: Table + Index       */
-+			u8 max_retry;
-+			u8 pad[5];        /* Unused                         */
-+			__le32 call_back; /* Used for Packet returned to FW */
-+		};
-+	} u;
-+	__le32 ctrl; /* Bit fields (TXRING_CTRL_*)            */
-+	__le32 data; /* PCIe Payload Pointer (Starts w/ SNAP) */
-+	__le32 user; /* Value returned to Host when done      */
-+	__le32 tcp_dst_src;
-+	__le32 tcp_sn;
-+} __packed;
-+
-+struct tx_ring_done {
-+	__le32 user;
-+} __packed;
-+
-+#define RXRING_CTRL_CASE_SHIFT  0     /* What is in the buffer(RXRING_CASE_*) */
-+#define RXRING_CTRL_CASE_MASK   0x1F  /* What is in the buffer(RXRING_CASE_*) */
-+#define RXRING_CTRL_STA_SHIFT   5     /* STA information (or Mcast group)     */
-+#define RXRING_CTRL_STA_MASK    0x1FF /* STA information (or Mcast group)     */
-+#define RXRING_CTRL_STA_UNKNOWN 0x1FF /* STA Idx for packets from Unknown STA */
-+#define RXRING_CTRL_STA_FROMDS  0x1FE /* STA Idx for packets from DS          */
-+#define RXRING_CTRL_TID_SHIFT   14    /* TID/UP for QoS Data frames           */
-+#define RXRING_CTRL_TID_MASK    0xF   /* TID/UP for QoS Data frames           */
-+#define RXRING_CTRL_KEY_SHIFT   18    /* Key Type used (KEY_TYPE_*)           */
-+#define RXRING_CTRL_KEY_MASK    0xF   /* Key Type used (KEY_TYPE_*)           */
-+#define RXRING_CTRL_TRUNC       (1UL<<31) /* Packet Truncated                 */
-+
-+/* Rx Buffer Formats
-+ *    Each Case listed above will indicate the format used, and each format will
-+ *    carry their length in the packet buffer. Should the packet be too big for
-+ *    the buffer, it will be truncated, but the full length will still be
-+ *    indicated. Currently only a single, fixed size Rx Pool is envisioned.
-+ *
-+ * Fmt0 is used for Slow path, when some processing of dot11 headers may still
-+ * be required, or for promiscuous mode captures. It is in the HW RxINFO
-+ * (rx_info_t) format including dot11_t followed by Payload. The Length field in
-+ * the dot11_t is updated to only include Payload bytes, and is in Little Endian
-+ * format. If the frame is too big, it is truncated to the buffer size, and
-+ * promiscuous packets may also be configured for truncation to reduce load. The
-+ * mark field is replaced with software status, and the RSSI will be updated to
-+ * apply Rx calibration.
-+ *
-+ * Fmt1 is used for fast path Data packets in the run state, where all rx
-+ * processing of dot11 headers is performed from radio FW. It has an AMSDU
-+ * centric format of DA/SA/Len followed by SNAP, with the Length in Big Endian
-+ * Format. In most cases conversion to Ethernet format is accomplished by
-+ * copying 12 bytes to drop 8 bytes in the middle.
-+ *
-+ * Fmt2 is used for fast path AMSDU packets that are malformed. They just
-+ * contain the dot11 header (dot11_t) containing the residual Len (Little
-+ * Endian) after any valid MSDU have been extracted. The header is followed by
-+ * the first invalid MSDU which will be truncated to 64 bytes.
-+ */
-+enum { /* What is in Rx Buffer and why it was delivered */
-+	/* Data for Assoc Clients in Run State on Channel [Fmt1]              */
-+	RXRING_CASE_FAST_DATA,
-+	RXRING_CASE_FAST_BAD_AMSDU, /* Fast Data with bad AMSDU Header [Fmt2] */
-+	/* Data for Assoc Clients using unconfigured queue [Fmt0]             */
-+	RXRING_CASE_SLOW_NOQUEUE,
-+	/* Data for Assoc Clients not matching Run State [Fmt0]               */
-+	RXRING_CASE_SLOW_NORUN,
-+	/* Data for filtered Multicast groups [Fmt0]                          */
-+	RXRING_CASE_SLOW_MCAST,
-+	RXRING_CASE_SLOW_BAD_STA,   /* Data for Unassoc Clients [Fmt0]        */
-+	RXRING_CASE_SLOW_BAD_MIC,   /* Decrypt failure [Fmt0]                 */
-+	RXRING_CASE_SLOW_BAD_PN,    /* Decrypt PN replay [Fmt0]               */
-+	RXRING_CASE_SLOW_MGMT,      /* Mgmt traffic to this AP or Bcast [Fmt0]*/
-+	RXRING_CASE_SLOW_PROMISC,   /* Packets captured promiscuously [Fmt0]  */
-+	RXRING_CASE_SLOW_DEL_DONE,  /* Client has been deleted [N/A]          */
-+	RXRING_CASE_DROP,           /* Buffer returned to Host [N/A]          */
-+};
-+
-+enum { /* Type of Key */
-+	KEY_TYPE_NONE,      /* Bypass (never stored in real keys)     */
-+	KEY_TYPE_WEP40,     /* WEP with  40 bit key + 24 bit IV =  64 */
-+	KEY_TYPE_WEP104,    /* WEP with 104 bit key + 24 bit IV = 128 */
-+	KEY_TYPE_TKIP,      /* TKIP                                   */
-+	KEY_TYPE_CCMP128,   /* CCMP with 128 bit Key                  */
-+	KEY_TYPE_CCMP256,   /* CCMP with 256 bit Key + 16 byte MIC    */
-+	KEY_TYPE_WAPI,      /* WAPI                                   */
-+	KEY_TYPE_UNKNOWN,   /* Not known what key was used (Rx Only)  */
-+	KEY_TYPE_GCMP128,   /* GCMP with 128 bit Key                  */
-+	KEY_TYPE_GCMP256,   /* GCMP with 256 bit Key + 16 byte MIC    */
-+};
-+
-+#define RXINFO_RSSI_X_SHIFT     24
-+#define RXINFO_RSSI_X_MASK      0xFF
-+#define RXINFO_HT_SIG1_SHIFT    0
-+#define RXINFO_HT_SIG1_MASK     0xFFFFFF
-+#define RXINFO_HT_SIG2_SHIFT    0
-+#define RXINFO_HT_SIG2_MASK     0x3FFFF
-+#define RXINFO_RATE_SHIFT       24
-+#define RXINFO_RATE_MASK        0xFF
-+#define RXINFO_NF_A_SHIFT       12
-+#define RXINFO_NF_A_MASK        0xFFF
-+#define RXINFO_NF_B_SHIFT       0
-+#define RXINFO_NF_B_MASK        0xFFF
-+#define RXINFO_NF_C_SHIFT       12
-+#define RXINFO_NF_C_MASK        0xFFF
-+#define RXINFO_NF_D_SHIFT       0
-+#define RXINFO_NF_D_MASK        0xFFF
-+#define RXINFO_PARAM_SHIFT      0
-+#define RXINFO_PARAM_MASK       0xFFFFFF
-+
-+struct rx_info { /* HW Rx buffer */
-+	__le32 reserved0[2];
-+	__le32 rssi_x;
-+	__le32 reserved1[2];
-+	__le32 ht_sig1;
-+	__le32 ht_sig2_rate;
-+	__le32 reserved2[6];
-+	__le32 nf_a_b;
-+	__le32 nf_c_d;
-+	__le32 reserved3[6];
-+	__le32 param;
-+	__le32 reserved4[2];
-+	__le32 hdr[0]; /* Len from HW includes rx_info w/ hdr */
-+} __packed;
-+
-+struct pcie_rx_desc_ndp { /* ToNIC Rx Empty Buffer Ring Entry */
-+	__le32 data; /* PCIe Payload Pointer               */
-+	__le32 user; /* Value returned to Host when done   */
-+} __packed;
-+
-+struct rx_ring_done { /* FromNIC Rx Done Ring Entry */
-+	__le32 user; /* Value returned to Host when done   */
-+	__le32 tsf;  /* Rx Radio Timestamp from MAC        */
-+	__le32 ctrl; /* Bit fields (RXRING_CTRL_*)         */
-+} __packed;
-+
-+struct pcie_desc_data_ndp {
-+	dma_addr_t pphys_tx_ring;         /* ptr to first TX desc (phys.)    */
-+	struct pcie_tx_desc_ndp *ptx_ring;/* ptr to first TX desc (virt.)    */
-+	dma_addr_t pphys_rx_ring;         /* ptr to first RX desc (phys.)    */
-+	struct pcie_rx_desc_ndp *prx_ring;/* ptr to first RX desc (virt.)    */
-+	u32 wcb_base;                     /* FW base offset for registers    */
-+	u32 rx_buf_size;                  /* length of the RX buffers        */
-+	u32 tx_sent_tail;                 /* index to the TX desc FW used    */
-+	u32 tx_sent_head;                 /* index to next TX desc to be used*/
-+	u32 tx_done_tail;                 /* index to Tx Done queue tail     */
-+	/* keept the skb owned by fw */
-+	dma_addr_t pphys_tx_buflist[MAX_TX_RING_SEND_SIZE];
-+	struct sk_buff *tx_vbuflist[MAX_TX_RING_SEND_SIZE];
-+	u32 tx_vbuflist_idx;              /* idx to empty slot in tx_vbuflist*/
-+	struct sk_buff *rx_vbuflist[MAX_NUM_RX_DESC];
-+	struct tx_ring_done *ptx_ring_done;
-+	dma_addr_t pphys_tx_ring_done; /* ptr to first TX done desc (phys.)  */
-+	struct rx_ring_done *prx_ring_done;
-+	dma_addr_t pphys_rx_ring_done; /* ptr to first RX done desc (phys.)  */
-+	dma_addr_t pphys_acnt_ring;    /* ptr to first account record (phys.)*/
-+	u8 *pacnt_ring;                /* ptr to first accounting record     */
-+	u32 tx_desc_busy_cnt;
-+	u8 *pacnt_buf;
-+	u32 acnt_ring_size;
-+};
-+
-+struct ndp_rx_counter {
-+	u32 fast_data_cnt;
-+	u32 fast_bad_amsdu_cnt;
-+	u32 slow_noqueue_cnt;
-+	u32 slow_norun_cnt;
-+	u32 slow_mcast_cnt;
-+	u32 slow_bad_sta_cnt;
-+	u32 slow_bad_mic_cnt;
-+	u32 slow_bad_pn_cnt;
-+	u32 slow_mgmt_cnt;
-+	u32 slow_promisc_cnt;
-+	u32 drop_cnt;
-+	u32 offch_promisc_cnt;
-+	u32 mu_pkt_cnt;
-+};
-+
-+/* KF2 - 88W8997 */
-+#define PCIE_MAX_TXRX_BD                0x20
-+/* PCIE read data pointer for queue 0 and 1 */
-+#define PCIE_RD_DATA_PTR_Q0_Q1          0xC1A4  /* 0x8000C1A4          */
-+/* PCIE read data pointer for queue 2 and 3 */
-+#define PCIE_RD_DATA_PTR_Q2_Q3          0xC1A8  /* 0x8000C1A8          */
-+/* PCIE write data pointer for queue 0 and 1 */
-+#define PCIE_WR_DATA_PTR_Q0_Q1          0xC174  /* 0x8000C174          */
-+/* PCIE write data pointer for queue 2 and 3 */
-+#define PCIE_WR_DATA_PTR_Q2_Q3          0xC178  /* 0x8000C178          */
-+
-+/* TX buffer description read pointer */
-+#define REG_TXBD_RDPTR                  PCIE_RD_DATA_PTR_Q0_Q1
-+/* TX buffer description write pointer */
-+#define REG_TXBD_WRPTR                  PCIE_WR_DATA_PTR_Q0_Q1
-+
-+#define PCIE_TX_START_PTR               16
-+
-+#define PCIE_TXBD_MASK                  0x0FFF0000
-+#define PCIE_TXBD_WRAP_MASK             0x1FFF0000
-+
-+#define PCIE_BD_FLAG_RX_ROLLOVER_IND    BIT(12)
-+#define PCIE_BD_FLAG_TX_START_PTR       BIT(16)
-+#define PCIE_BD_FLAG_TX_ROLLOVER_IND    BIT(28)
-+#define PCIE_BD_FLAG_TX2_START_PTR      BIT(0)
-+#define PCIE_BD_FLAG_TX2_ROLLOVER_IND   BIT(12)
-+
-+#define PCIE_BD_FLAG_FIRST_DESC         BIT(0)
-+#define PCIE_BD_FLAG_LAST_DESC          BIT(1)
-+
-+#define PCIE_TX_WCB_FLAGS_DONT_ENCRYPT  0x00000001
-+#define PCIE_TX_WCB_FLAGS_NO_CCK_RATE   0x00000002
-+
-+#define PCIE_TXBD_NOT_FULL(wrptr, rdptr) \
-+	(((wrptr & PCIE_TXBD_MASK) != (rdptr & PCIE_TXBD_MASK)) \
-+	 || ((wrptr & PCIE_BD_FLAG_TX_ROLLOVER_IND) ==          \
-+	     (rdptr & PCIE_BD_FLAG_TX_ROLLOVER_IND)))
-+
-+struct pcie_data_buf {
-+	/* Buffer descriptor flags */
-+	__le16 flags;
-+	/* Offset of fragment/pkt to start of ip header */
-+	__le16 offset;
-+	/* Fragment length of the buffer */
-+	__le16 frag_len;
-+	/* Length of the buffer */
-+	__le16 len;
-+	/* Physical address of the buffer */
-+	__le64 paddr;
-+	/* Reserved */
-+	__le32 reserved;
-+} __packed;
-+
-+struct pcie_pfu_dma_data {
-+	struct pcie_tx_desc tx_desc;
-+	struct pcie_dma_data dma_data;
-+} __packed;
-+
-+struct pcie_priv {
-+	struct mwl_priv *mwl_priv;
-+	struct pci_dev *pdev;
-+	void __iomem *iobase0; /* MEM Base Address Register 0  */
-+	void __iomem *iobase1; /* MEM Base Address Register 1  */
-+	u32 next_bar_num;
-+
-+	struct sk_buff_head txq[PCIE_NUM_OF_DESC_DATA];
-+
-+	spinlock_t int_mask_lock ____cacheline_aligned_in_smp;
-+	struct tasklet_struct tx_task;
-+	struct tasklet_struct tx_done_task;
-+	struct tasklet_struct rx_task;
-+	struct tasklet_struct qe_task;
-+	unsigned int tx_head_room;
-+	int txq_limit;
-+	int txq_wake_threshold;
-+	bool is_tx_schedule;
-+	bool is_tx_done_schedule;
-+	int recv_limit;
-+	bool is_rx_schedule;
-+	bool is_qe_schedule;
-+	u32 qe_trig_num;
-+	unsigned long qe_trig_time;
-+
-+	/* various descriptor data */
-+	/* for tx descriptor data  */
-+	spinlock_t tx_desc_lock ____cacheline_aligned_in_smp;
-+	struct pcie_desc_data desc_data[PCIE_NUM_OF_DESC_DATA];
-+	int delay_q_idx;
-+	struct sk_buff *delay_q[PCIE_DELAY_FREE_Q_LIMIT];
-+	/* number of descriptors owned by fw at any one time */
-+	int fw_desc_cnt[PCIE_NUM_OF_DESC_DATA];
-+
-+	/* new data path */
-+	struct pcie_desc_data_ndp desc_data_ndp;
-+	int tx_done_cnt;
-+	struct ieee80211_sta *sta_link[SYSADPT_MAX_STA_SC4 + 1];
-+	struct sk_buff_head rx_skb_trace;
-+	struct ndp_rx_counter rx_cnts;
-+	u32 rx_skb_unlink_err;
-+	u32 signature_err;
-+	u32 recheck_rxringdone;
-+	u32 acnt_busy;
-+	u32 acnt_wrap;
-+	u32 acnt_drop;
-+
-+	/* KF2 - 88W8997 */
-+	struct firmware *cal_data;
-+	/* Write pointer for TXBD ring */
-+	u32 txbd_wrptr;
-+	/* Shadow copy of TXBD read pointer */
-+	u32 txbd_rdptr;
-+	/* TXBD ring size */
-+	u32 txbd_ring_size;
-+	/* Virtual base address of txbd_ring */
-+	u8 *txbd_ring_vbase;
-+	/* Physical base address of txbd_ring */
-+	dma_addr_t txbd_ring_pbase;
-+	/* Ring of buffer descriptors for TX */
-+	struct pcie_data_buf *txbd_ring[PCIE_MAX_TXRX_BD];
-+	struct sk_buff *tx_buf_list[PCIE_MAX_TXRX_BD];
-+};
-+
-+enum { /* Definition of accounting record codes */
-+	ACNT_CODE_BUSY = 0,   /* Marked busy until filled in                  */
-+	ACNT_CODE_WRAP,       /* Used to pad when wrapping                    */
-+	ACNT_CODE_DROP,       /* Count of dropped records                     */
-+	ACNT_CODE_TX_ENQUEUE, /* TXINFO when added to TCQ (acnt_tx_s)         */
-+	ACNT_CODE_RX_PPDU,    /* RXINFO for each PPDu (acnt_rx_s)             */
-+	ACNT_CODE_TX_FLUSH,   /* Flush Tx Queue                               */
-+	ACNT_CODE_RX_RESET,   /* Channel Change / Rx Reset                    */
-+	ACNT_CODE_TX_RESET,   /* TCQ reset                                    */
-+	ACNT_CODE_QUOTE_LEVEL,/* Quota Level changes                          */
-+	ACNT_CODE_TX_DONE,    /* Tx status when done                          */
-+	ACNT_CODE_RA_STATS,   /* rateinfo PER (acnt_ra_s)                     */
-+	ACNT_CODE_BA_STATS,   /* BA stats (acnt_ba_s)                         */
-+	ACNT_CODE_BF_MIMO_CTRL,/* BF Mimo Ctrl Field Log (acnt_bf_mimo_ctrl_s)*/
-+};
-+
-+struct acnt_s { /* Baseline Accounting Record format */
-+	__le16 code;          /* Unique code for each type                    */
-+	u8 len;               /* Length in DWORDS, including header           */
-+	u8 pad;               /* Alignment for generic, but specific can reuse*/
-+	__le32 tsf;           /* Timestamp for Entry (when len>1)             */
-+} __packed;
-+
-+struct acnt_tx_s { /* Accounting Record For Tx (at Enqueue time) */
-+	__le16 code;          /* Unique code for each type                    */
-+	u8 len;               /* Length in DWORDS, including header           */
-+	u8 tcq;               /* Which TCQ was used                           */
-+	__le32 tsf;           /* Timestamp for Entry (when len>1)             */
-+	__le64 bitmap;        /* Map of SeqNr when AMPDU                      */
-+	__le16 air_time;      /* Air Time used by PPDU                        */
-+	__le16 npkts;         /* Number of Descriptors sent (AMPDU&AMSDU)     */
-+	__le16 qid;           /* Transmit Queue ID                            */
-+	__le16 latency;       /* Latency of oldest frame in AMPDU (128us)     */
-+	__le16 rate1;         /* Rate Code for sending data                   */
-+	__le16 rate2;         /* Rate Code for sending RTS/CTS protection     */
-+	u8 rate_tbl_index;    /* Rate table index for this TxInfo rate        */
-+	u8 type;              /* SU:0 or MU:1                                 */
-+	u8 pad[1];            /* Unused                                       */
-+	u8 retries;           /* Number of retries of oldest frame in AMPDU   */
-+	__le32 tx_cnt;        /* No. of pkt sent                              */
-+	struct tx_info tx_info;/* Transmit parameters used for 1st MPDU/AMPDU */
-+	struct pcie_dma_data hdr;/* Dot11 header used for 1st MPDU in AMPDU   */
-+	u8 payload[0];        /* Variable Payload by use case                 */
-+} __packed;
-+
-+struct acnt_rx_s { /* Accounting Record for Rx PPDU */
-+	__le16 code;          /* Unique code for each type                    */
-+	u8 len;               /* Length in DWORDS, including header           */
-+	u8 flags;             /* Flags (ACNTRX_*)                             */
-+	__le32 tsf;           /* Timestamp for Entry (when len>1)             */
-+	__le64 bitmap;        /* Map of SeqNr when AMPDU                      */
-+	__le16 air_time;      /* Air Time used by PPDU (no CSMA overhead)     */
-+	__le16 rate;          /* Rate Code for receiving data                 */
-+	struct rx_info rx_info;/* Receive parameters from 1st valid MPDU/AMPDU*/
-+} __packed;
-+
-+struct acnt_ra_s { /* Accounting Record w/ rateinfo PER */
-+	__le16 code;          /* Unique code for each type                    */
-+	u8 len;               /* Length in DWORDS, including header           */
-+	u8 per;               /* PER for this rateinfo                        */
-+	__le32 tsf;           /* Timestamp for Entry (when len>1)             */
-+	__le16 stn_id;        /* sta index this rateinfo is tied to           */
-+	u8 type;              /* SU:0 or MU:1                                 */
-+	u8 rate_tbl_index;    /* ratetbl index                                */
-+	__le32 rate_info;     /* rateinfo for this ratetbl index              */
-+	__le32 tx_attempt_cnt;/* Total tx pkt during rate adapt interval      */
-+} __packed;
-+
-+struct acnt_ba_s { /* Accounting Record w/ rateinfo PER */
-+	__le16 code;          /* Unique code for each type                    */
-+	u8 len;               /* Length in DWORDS, including header           */
-+	u8 ba_hole;           /* Total missing pkt in a BA                    */
-+	__le32 tsf;           /* Timestamp for Entry (when len>1)             */
-+	__le16 stnid;         /* sta index for this BA                        */
-+	u8 no_ba;             /* No BA received                               */
-+	u8 ba_expected;       /* Total expected pkt to be BA'd                */
-+	u8 type;              /* SU:0 or MU:1                                 */
-+	u8 pad[3];            /* Unused                                       */
-+} __packed;
-+
-+struct acnt_bf_mimo_ctrl_s {/* Accounting Record w/ BF MIMO Control Field Data*/
-+	__le16 code;          /* Unique code for each type                    */
-+	u8 len;               /* Length in DWORDS, including header           */
-+	u8 type;              /* SU:0, MU:1                                   */
-+	__le32 tsf;           /* Timestamp for Entry (when len>1)             */
-+	u8 rec_mac[6];        /* Received Packet Source MAC Address           */
-+	__le16 pad;           /* Padding                                      */
-+	__le32 mimo_ctrl;     /* BF MIMO Control Field Data                   */
-+	__le64 comp_bf_rep;   /* First 8 bytes of Compressed BF Report        */
-+} __packed;
-+
-+static inline void pcie_tx_add_dma_header(struct mwl_priv *priv,
-+					 struct sk_buff *skb,
-+					 int head_pad,
-+					 int tail_pad)
-+{
-+	struct ieee80211_hdr *wh;
-+	int dma_hdrlen;
-+	int hdrlen;
-+	int reqd_hdrlen;
-+	int needed_room;
-+	struct pcie_dma_data *dma_data;
-+
-+	dma_hdrlen = (priv->chip_type == MWL8997) ?
-+		sizeof(struct pcie_pfu_dma_data) :
-+		sizeof(struct pcie_dma_data);
-+
-+	/* Add a firmware DMA header; the firmware requires that we
-+	 * present a 2-byte payload length followed by a 4-address
-+	 * header (without QoS field), followed (optionally) by any
-+	 * WEP/ExtIV header (but only filled in for CCMP).
-+	 */
-+	wh = (struct ieee80211_hdr *)skb->data;
-+
-+	hdrlen = ieee80211_hdrlen(wh->frame_control);
-+
-+	reqd_hdrlen = dma_hdrlen + head_pad;
-+
-+	if (hdrlen != reqd_hdrlen) {
-+		needed_room = reqd_hdrlen - hdrlen;
-+		if (skb_headroom(skb) < needed_room) {
-+			wiphy_debug(priv->hw->wiphy, "headroom is short: %d %d",
-+				    skb_headroom(skb), needed_room);
-+			skb_cow(skb, needed_room);
-+		}
-+		skb_push(skb, needed_room);
-+	}
-+
-+	if (ieee80211_is_data_qos(wh->frame_control))
-+		hdrlen -= IEEE80211_QOS_CTL_LEN;
-+
-+	if (priv->chip_type == MWL8997)
-+		dma_data = &((struct pcie_pfu_dma_data *)skb->data)->dma_data;
-+	else
-+		dma_data = (struct pcie_dma_data *)skb->data;
-+
-+	if (wh != &dma_data->wh)
-+		memmove(&dma_data->wh, wh, hdrlen);
-+
-+	if (hdrlen != sizeof(dma_data->wh))
-+		memset(((void *)&dma_data->wh) + hdrlen, 0,
-+		       sizeof(dma_data->wh) - hdrlen);
-+
-+	/* Firmware length is the length of the fully formed "802.11
-+	 * payload".  That is, everything except for the 802.11 header.
-+	 * This includes all crypto material including the MIC.
-+	 */
-+	dma_data->fwlen =
-+		cpu_to_le16(skb->len - dma_hdrlen + tail_pad);
-+}
-+
-+static inline void pcie_tx_encapsulate_frame(struct mwl_priv *priv,
-+					     struct sk_buff *skb,
-+					     struct ieee80211_key_conf *k_conf,
-+					     bool *ccmp)
-+{
-+	int head_pad = 0;
-+	int data_pad = 0;
-+
-+	/* Make sure the packet header is in the DMA header format (4-address
-+	 * without QoS), and add head & tail padding when HW crypto is enabled.
-+	 *
-+	 * We have the following trailer padding requirements:
-+	 * - WEP: 4 trailer bytes (ICV)
-+	 * - TKIP: 12 trailer bytes (8 MIC + 4 ICV)
-+	 * - CCMP: 8 trailer bytes (MIC)
-+	 */
-+
-+	if (k_conf) {
-+		head_pad = k_conf->iv_len;
-+
-+		switch (k_conf->cipher) {
-+		case WLAN_CIPHER_SUITE_WEP40:
-+		case WLAN_CIPHER_SUITE_WEP104:
-+			data_pad = 4;
-+			break;
-+		case WLAN_CIPHER_SUITE_TKIP:
-+			data_pad = 12;
-+			break;
-+		case WLAN_CIPHER_SUITE_CCMP:
-+			data_pad = 8;
-+			if (ccmp)
-+				*ccmp = true;
-+			break;
-+		}
-+	}
-+
-+	pcie_tx_add_dma_header(priv, skb, head_pad, data_pad);
-+}
-+
-+static inline void pcie_tx_prepare_info(struct mwl_priv *priv, u32 rate,
-+					struct ieee80211_tx_info *info)
-+{
-+	u32 format, bandwidth, short_gi, rate_id;
-+
-+	ieee80211_tx_info_clear_status(info);
-+
-+	info->status.rates[0].idx = -1;
-+	info->status.rates[0].count = 0;
-+	info->status.rates[0].flags = 0;
-+	info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-+	info->flags |= IEEE80211_TX_STAT_ACK;
-+
-+	if (rate) {
-+		/* Prepare rate information */
-+		format = rate & MWL_TX_RATE_FORMAT_MASK;
-+		bandwidth =
-+			(rate & MWL_TX_RATE_BANDWIDTH_MASK) >>
-+			MWL_TX_RATE_BANDWIDTH_SHIFT;
-+		short_gi = (rate & MWL_TX_RATE_SHORTGI_MASK) >>
-+			MWL_TX_RATE_SHORTGI_SHIFT;
-+		rate_id = (rate & MWL_TX_RATE_RATEIDMCS_MASK) >>
-+			MWL_TX_RATE_RATEIDMCS_SHIFT;
-+
-+		info->status.rates[0].idx = rate_id;
-+		if (format == TX_RATE_FORMAT_LEGACY) {
-+			if (priv->hw->conf.chandef.chan->hw_value >
-+			    BAND_24_CHANNEL_NUM) {
-+				info->status.rates[0].idx -= 5;
-+			}
-+		}
-+		if (format == TX_RATE_FORMAT_11N)
-+			info->status.rates[0].flags |=
-+				IEEE80211_TX_RC_MCS;
-+		if (format == TX_RATE_FORMAT_11AC)
-+			info->status.rates[0].flags |=
-+				IEEE80211_TX_RC_VHT_MCS;
-+		if (bandwidth == TX_RATE_BANDWIDTH_40)
-+			info->status.rates[0].flags |=
-+				IEEE80211_TX_RC_40_MHZ_WIDTH;
-+		if (bandwidth == TX_RATE_BANDWIDTH_80)
-+			info->status.rates[0].flags |=
-+				IEEE80211_TX_RC_80_MHZ_WIDTH;
-+		if (bandwidth == TX_RATE_BANDWIDTH_160)
-+			info->status.rates[0].flags |=
-+				IEEE80211_TX_RC_160_MHZ_WIDTH;
-+		if (short_gi == TX_RATE_INFO_SHORT_GI)
-+			info->status.rates[0].flags |=
-+				IEEE80211_TX_RC_SHORT_GI;
-+		info->status.rates[0].count = 1;
-+		info->status.rates[1].idx = -1;
-+	}
-+}
-+
-+static inline void pcie_tx_count_packet(struct ieee80211_sta *sta, u8 tid)
-+{
-+	struct mwl_sta *sta_info;
-+	struct mwl_tx_info *tx_stats;
-+
-+	if (WARN_ON(tid >= SYSADPT_MAX_TID))
-+		return;
-+
-+	sta_info = mwl_dev_get_sta(sta);
-+
-+	tx_stats = &sta_info->tx_stats[tid];
-+
-+	if (tx_stats->start_time == 0)
-+		tx_stats->start_time = jiffies;
-+
-+	/* reset the packet count after each second elapses.  If the number of
-+	 * packets ever exceeds the ampdu_min_traffic threshold, we will allow
-+	 * an ampdu stream to be started.
-+	 */
-+	if (jiffies - tx_stats->start_time > HZ) {
-+		tx_stats->pkts = 0;
-+		tx_stats->start_time = jiffies;
-+	} else {
-+		tx_stats->pkts++;
-+	}
-+}
-+
-+static inline void pcie_rx_prepare_status(struct mwl_priv *priv, u16 format,
-+					  u16 nss, u16 bw, u16 gi, u16 rate,
-+					  struct ieee80211_rx_status *status)
-+{
-+#ifdef RX_ENC_FLAG_STBC_SHIFT
-+	switch (format) {
-+	case RX_RATE_INFO_FORMAT_11N:
-+		status->encoding = RX_ENC_HT;
-+		status->bw = RATE_INFO_BW_20;
-+		if (bw == RX_RATE_INFO_HT40)
-+			status->bw = RATE_INFO_BW_40;
-+		if (gi == RX_RATE_INFO_SHORT_INTERVAL)
-+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
-+		break;
-+	case RX_RATE_INFO_FORMAT_11AC:
-+		status->encoding = RX_ENC_VHT;
-+		status->bw = RATE_INFO_BW_20;
-+		if (bw == RX_RATE_INFO_HT40)
-+			status->bw = RATE_INFO_BW_40;
-+		if (bw == RX_RATE_INFO_HT80)
-+			status->bw = RATE_INFO_BW_80;
-+		if (bw == RX_RATE_INFO_HT160)
-+			status->bw = RATE_INFO_BW_160;
-+		if (gi == RX_RATE_INFO_SHORT_INTERVAL)
-+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
-+		status->nss = (nss + 1);
-+		break;
-+	}
-+#else
-+	switch (format) {
-+	case RX_RATE_INFO_FORMAT_11N:
-+		status->flag |= RX_FLAG_HT;
-+		if (bw == RX_RATE_INFO_HT40)
-+			status->flag |= RX_FLAG_40MHZ;
-+		if (gi == RX_RATE_INFO_SHORT_INTERVAL)
-+			status->flag |= RX_FLAG_SHORT_GI;
-+		break;
-+	case RX_RATE_INFO_FORMAT_11AC:
-+		status->flag |= RX_FLAG_VHT;
-+		if (bw == RX_RATE_INFO_HT40)
-+			status->flag |= RX_FLAG_40MHZ;
-+		if (bw == RX_RATE_INFO_HT80)
-+			status->vht_flag |= RX_VHT_FLAG_80MHZ;
-+		if (bw == RX_RATE_INFO_HT160)
-+			status->vht_flag |= RX_VHT_FLAG_160MHZ;
-+		if (gi == RX_RATE_INFO_SHORT_INTERVAL)
-+			status->flag |= RX_FLAG_SHORT_GI;
-+		status->vht_nss = (nss + 1);
-+		break;
-+	}
-+#endif
-+	status->rate_idx = rate;
-+
-+	if (priv->hw->conf.chandef.chan->hw_value >
-+	    BAND_24_CHANNEL_NUM) {
-+		status->band = NL80211_BAND_5GHZ;
-+#ifdef RX_ENC_FLAG_STBC_SHIFT
-+		if ((!(status->encoding == RX_ENC_HT)) &&
-+		    (!(status->encoding == RX_ENC_VHT))) {
-+#else
-+		if ((!(status->flag & RX_FLAG_HT)) &&
-+		    (!(status->flag & RX_FLAG_VHT))) {
-+#endif
-+			status->rate_idx -= 5;
-+			if (status->rate_idx >= BAND_50_RATE_NUM)
-+				status->rate_idx = BAND_50_RATE_NUM - 1;
-+		}
-+	} else {
-+		status->band = NL80211_BAND_2GHZ;
-+#ifdef RX_ENC_FLAG_STBC_SHIFT
-+		if ((!(status->encoding == RX_ENC_HT)) &&
-+		    (!(status->encoding == RX_ENC_VHT))) {
-+#else
-+		if ((!(status->flag & RX_FLAG_HT)) &&
-+		    (!(status->flag & RX_FLAG_VHT))) {
-+#endif
-+			if (status->rate_idx >= BAND_24_RATE_NUM)
-+				status->rate_idx = BAND_24_RATE_NUM - 1;
-+		}
-+	}
-+}
-+
-+static inline void pcie_rx_remove_dma_header(struct sk_buff *skb, __le16 qos)
-+{
-+	struct pcie_dma_data *dma_data;
-+	int hdrlen;
-+
-+	dma_data = (struct pcie_dma_data *)skb->data;
-+	hdrlen = ieee80211_hdrlen(dma_data->wh.frame_control);
-+
-+	if (hdrlen != sizeof(dma_data->wh)) {
-+		if (ieee80211_is_data_qos(dma_data->wh.frame_control)) {
-+			memmove(dma_data->data - hdrlen,
-+				&dma_data->wh, hdrlen - 2);
-+			*((__le16 *)(dma_data->data - 2)) = qos;
-+		} else {
-+			memmove(dma_data->data - hdrlen, &dma_data->wh, hdrlen);
-+		}
-+	}
-+
-+	if (hdrlen != sizeof(*dma_data))
-+		skb_pull(skb, sizeof(*dma_data) - hdrlen);
-+}
-+
-+static inline void pcie_mask_int(struct pcie_priv *pcie_priv,
-+				 u32 mask_bit, bool set)
-+{
-+	unsigned long flags;
-+	void __iomem *int_status_mask;
-+	u32 status;
-+
-+	spin_lock_irqsave(&pcie_priv->int_mask_lock, flags);
-+	int_status_mask = pcie_priv->iobase1 +
-+		MACREG_REG_A2H_INTERRUPT_STATUS_MASK;
-+	status = readl(int_status_mask);
-+	if (set)
-+		writel((status | mask_bit), int_status_mask);
-+	else
-+		writel((status & ~mask_bit), int_status_mask);
-+	spin_unlock_irqrestore(&pcie_priv->int_mask_lock, flags);
-+}
-+
-+#endif /* _DEV_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.c b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.c
-new file mode 100644
-index 000000000000..939ed54133c7
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.c
-@@ -0,0 +1,274 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements firmware download related
-+ * functions.
-+ */
-+
-+#include <linux/io.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "hif/fwcmd.h"
-+#include "hif/pcie/dev.h"
-+#include "hif/pcie/sc4_ddr.h"
-+#include "hif/pcie/fwdl.h"
-+
-+#define FW_DOWNLOAD_BLOCK_SIZE          256
-+#define FW_CHECK_MSECS                  3
-+
-+#define FW_MAX_NUM_CHECKS               0xffff
-+
-+static void pcie_trigger_pcicmd_bootcode(struct pcie_priv *pcie_priv)
-+{
-+	writel(pcie_priv->mwl_priv->pphys_cmd_buf,
-+	       pcie_priv->iobase1 + MACREG_REG_GEN_PTR);
-+	writel(0x00, pcie_priv->iobase1 + MACREG_REG_INT_CODE);
-+	writel(MACREG_H2ARIC_BIT_DOOR_BELL,
-+	       pcie_priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS);
-+}
-+
-+static bool pcie_download_ddr_init(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = (struct pcie_priv *)priv->hif.priv;
-+	u32 size_ddr_init = sizeof(sc4_ddr_init);
-+	u8 *p = (u8 *)&sc4_ddr_init[0];
-+	u32 curr_iteration = 0;
-+	u32 size_ddr_init_downloaded = 0;
-+	u32 int_code = 0;
-+	u32 len = 0;
-+
-+	/* download ddr init code */
-+	wiphy_debug(priv->hw->wiphy, "ddr init: download start\n");
-+
-+	while (size_ddr_init_downloaded < size_ddr_init) {
-+		len = readl(pcie_priv->iobase1 + 0xc40);
-+
-+		if (!len)
-+			break;
-+
-+		/* this copies the next chunk of fw binary to be delivered */
-+		memcpy((char *)&priv->pcmd_buf[0], p, len);
-+		/* this is arbitrary per your platform; we use 0xffff */
-+		curr_iteration = (FW_MAX_NUM_CHECKS * 500);
-+		/* this function writes pdata to c10, then write 2 to c18 */
-+		pcie_trigger_pcicmd_bootcode(pcie_priv);
-+
-+		/* NOTE: the following back to back checks on C1C is time
-+		 * sensitive, hence may need to be tweaked dependent on host
-+		 * processor. Time for SC2 to go from the write of event 2 to
-+		 * C1C == 2 is ~1300 nSec. Hence the checkings on host has to
-+		 * consider how efficient your code can be to meet this timing,
-+		 * or you can alternatively tweak this routines to fit your
-+		 * platform
-+		 */
-+		do {
-+			int_code = readl(pcie_priv->iobase1 + 0xc1c);
-+			if (int_code != 0)
-+				break;
-+			cond_resched();
-+			curr_iteration--;
-+		} while (curr_iteration);
-+
-+		do {
-+			int_code = readl(pcie_priv->iobase1 + 0xc1c);
-+			if ((int_code & MACREG_H2ARIC_BIT_DOOR_BELL) !=
-+			    MACREG_H2ARIC_BIT_DOOR_BELL)
-+				break;
-+			cond_resched();
-+			curr_iteration--;
-+		} while (curr_iteration);
-+
-+		if (curr_iteration == 0) {
-+			/* This limited loop check allows you to exit gracefully
-+			 * without locking up your entire system just because fw
-+			 * download failed
-+			 */
-+			wiphy_err(priv->hw->wiphy,
-+				  "Exhausted curr_iteration during download\n");
-+			return false;
-+		}
-+
-+		p += len;
-+		size_ddr_init_downloaded += len;
-+	}
-+
-+	wiphy_debug(priv->hw->wiphy, "ddr init: download complete\n");
-+
-+	return true;
-+}
-+
-+void pcie_reset(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	u32 regval;
-+
-+	regval = readl(pcie_priv->iobase1 + MACREG_REG_INT_CODE);
-+	if (regval == 0xffffffff) {
-+		wiphy_err(priv->hw->wiphy, "adapter does not exist\n");
-+		return;
-+	}
-+
-+	writel(ISR_RESET, pcie_priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS);
-+}
-+
-+int pcie_download_firmware(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	const struct firmware *fw = priv->fw_ucode;
-+	u32 curr_iteration = 0;
-+	u32 size_fw_downloaded = 0;
-+	u32 int_code = 0;
-+	u32 len = 0;
-+	u32 fwreadysignature = HOSTCMD_SOFTAP_FWRDY_SIGNATURE;
-+
-+	pcie_reset(hw);
-+
-+	/* FW before jumping to boot rom, it will enable PCIe transaction retry,
-+	 * wait for boot code to stop it.
-+	 */
-+	usleep_range(FW_CHECK_MSECS * 1000, FW_CHECK_MSECS * 2000);
-+
-+	if (priv->chip_type == MWL8964) {
-+		writel(MACREG_A2HRIC_BIT_MASK_NDP,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CLEAR_SEL);
-+	} else {
-+		writel(MACREG_A2HRIC_BIT_MASK,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CLEAR_SEL);
-+	}
-+	writel(0x00, pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE);
-+	writel(0x00, pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK);
-+	if (priv->chip_type == MWL8964) {
-+		writel(MACREG_A2HRIC_BIT_MASK_NDP,
-+		       pcie_priv->iobase1 +
-+		       MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
-+	} else {
-+		writel(MACREG_A2HRIC_BIT_MASK,
-+		       pcie_priv->iobase1 +
-+		       MACREG_REG_A2H_INTERRUPT_STATUS_MASK);
-+	}
-+
-+	/* this routine interacts with SC2 bootrom to download firmware binary
-+	 * to the device. After DMA'd to SC2, the firmware could be deflated to
-+	 * reside on its respective blocks such as ITCM, DTCM, SQRAM,
-+	 * (or even DDR, AFTER DDR is init'd before fw download
-+	 */
-+	wiphy_debug(hw->wiphy, "fw download start\n");
-+
-+	if (priv->chip_type != MWL8997)
-+		/* Disable PFU before FWDL */
-+		writel(0x100, pcie_priv->iobase1 + 0xE0E4);
-+
-+	/* make sure SCRATCH2 C40 is clear, in case we are too quick */
-+	while (readl(pcie_priv->iobase1 + 0xc40) == 0)
-+		cond_resched();
-+
-+	if (priv->chip_type == MWL8964) {
-+		if (!pcie_download_ddr_init(priv)) {
-+			wiphy_err(hw->wiphy,
-+				  "ddr init: code download failed\n");
-+			goto err_download;
-+		}
-+	}
-+
-+	while (size_fw_downloaded < fw->size) {
-+		len = readl(pcie_priv->iobase1 + 0xc40);
-+
-+		if (!len)
-+			break;
-+
-+		/* this copies the next chunk of fw binary to be delivered */
-+		memcpy((char *)&priv->pcmd_buf[0],
-+		       (fw->data + size_fw_downloaded), len);
-+
-+		/* this function writes pdata to c10, then write 2 to c18 */
-+		pcie_trigger_pcicmd_bootcode(pcie_priv);
-+
-+		/* this is arbitrary per your platform; we use 0xffff */
-+		curr_iteration = FW_MAX_NUM_CHECKS;
-+
-+		/* NOTE: the following back to back checks on C1C is time
-+		 * sensitive, hence may need to be tweaked dependent on host
-+		 * processor. Time for SC2 to go from the write of event 2 to
-+		 * C1C == 2 is ~1300 nSec. Hence the checkings on host has to
-+		 * consider how efficient your code can be to meet this timing,
-+		 * or you can alternatively tweak this routines to fit your
-+		 * platform
-+		 */
-+		do {
-+			int_code = readl(pcie_priv->iobase1 + 0xc1c);
-+			if ((int_code & MACREG_H2ARIC_BIT_DOOR_BELL) !=
-+			    MACREG_H2ARIC_BIT_DOOR_BELL)
-+				break;
-+			cond_resched();
-+			curr_iteration--;
-+		} while (curr_iteration);
-+
-+		if (curr_iteration == 0) {
-+			/* This limited loop check allows you to exit gracefully
-+			 * without locking up your entire system just because fw
-+			 * download failed
-+			 */
-+			wiphy_err(hw->wiphy,
-+				  "Exhausted curr_iteration for fw download\n");
-+			goto err_download;
-+		}
-+
-+		size_fw_downloaded += len;
-+	}
-+
-+	wiphy_debug(hw->wiphy,
-+		    "FwSize = %d downloaded Size = %d curr_iteration %d\n",
-+		    (int)fw->size, size_fw_downloaded, curr_iteration);
-+
-+	/* Now firware is downloaded successfully, so this part is to check
-+	 * whether fw can properly execute to an extent that write back
-+	 * signature to indicate its readiness to the host. NOTE: if your
-+	 * downloaded fw crashes, this signature checking will fail. This
-+	 * part is similar as SC1
-+	 */
-+	*((u32 *)&priv->pcmd_buf[1]) = 0;
-+	pcie_trigger_pcicmd_bootcode(pcie_priv);
-+	curr_iteration = FW_MAX_NUM_CHECKS;
-+	do {
-+		curr_iteration--;
-+		writel(HOSTCMD_SOFTAP_MODE,
-+		       pcie_priv->iobase1 + MACREG_REG_GEN_PTR);
-+		usleep_range(FW_CHECK_MSECS * 1000, FW_CHECK_MSECS * 2000);
-+		int_code = readl(pcie_priv->iobase1 + MACREG_REG_INT_CODE);
-+		if (!(curr_iteration % 0xff) && (int_code != 0))
-+			wiphy_err(hw->wiphy, "%x;", int_code);
-+	} while ((curr_iteration) &&
-+		 (int_code != fwreadysignature));
-+
-+	if (curr_iteration == 0) {
-+		wiphy_err(hw->wiphy,
-+			  "Exhausted curr_iteration for fw signature\n");
-+		goto err_download;
-+	}
-+
-+	wiphy_debug(hw->wiphy, "fw download complete\n");
-+	writel(0x00, pcie_priv->iobase1 + MACREG_REG_INT_CODE);
-+
-+	return 0;
-+
-+err_download:
-+
-+	pcie_reset(hw);
-+
-+	return -EIO;
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.h
-new file mode 100644
-index 000000000000..36a3311aa678
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/fwdl.h
-@@ -0,0 +1,24 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines firmware download related functions. */
-+
-+#ifndef _FWDL_H_
-+#define _FWDL_H_
-+
-+void pcie_reset(struct ieee80211_hw *hw);
-+int pcie_download_firmware(struct ieee80211_hw *hw);
-+
-+#endif /* _FWDL_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/pcie.c b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/pcie.c
-new file mode 100644
-index 000000000000..da55913c0570
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/pcie.c
-@@ -0,0 +1,1645 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements functions needed for PCIe module. */
-+
-+#include <linux/module.h>
-+#include <linux/etherdevice.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "vendor_cmd.h"
-+#include "hif/fwcmd.h"
-+#include "hif/pcie/dev.h"
-+#include "hif/pcie/fwdl.h"
-+#include "hif/pcie/tx.h"
-+#include "hif/pcie/rx.h"
-+#include "hif/pcie/tx_ndp.h"
-+#include "hif/pcie/rx_ndp.h"
-+
-+#define PCIE_DRV_DESC "Marvell Mac80211 Wireless PCIE Network Driver"
-+#define PCIE_DEV_NAME "Marvell 802.11ac PCIE Adapter"
-+
-+#define MAX_WAIT_FW_COMPLETE_ITERATIONS 2000
-+#define CHECK_BA_TRAFFIC_TIME           300 /* msec */
-+#define CHECK_TX_DONE_TIME              50  /* msec */
-+
-+static struct pci_device_id pcie_id_tbl[] = {
-+	{ PCI_VDEVICE(MARVELL, 0x2a55),     .driver_data = MWL8864, },
-+	{ PCI_VDEVICE(MARVELL, 0x2b38),     .driver_data = MWL8897, },
-+	{ PCI_VDEVICE(MARVELL, 0x2b40),     .driver_data = MWL8964, },
-+	{ PCI_VDEVICE(MARVELL_EXT, 0x2b42), .driver_data = MWL8997, },
-+	{ },
-+};
-+
-+static struct mwl_chip_info pcie_chip_tbl[] = {
-+	[MWL8864] = {
-+		.part_name	= "88W8864",
-+		.fw_image	= "mwlwifi/88W8864.bin",
-+		.cal_file	= NULL,
-+		.txpwrlmt_file  = NULL,
-+		.antenna_tx	= ANTENNA_TX_4_AUTO,
-+		.antenna_rx	= ANTENNA_RX_4_AUTO,
-+	},
-+	[MWL8897] = {
-+		.part_name	= "88W8897",
-+		.fw_image	= "mwlwifi/88W8897.bin",
-+		.cal_file	= NULL,
-+		.txpwrlmt_file  = NULL,
-+		.antenna_tx	= ANTENNA_TX_2,
-+		.antenna_rx	= ANTENNA_RX_2,
-+	},
-+	[MWL8964] = {
-+		.part_name	= "88W8964",
-+		.fw_image	= "mwlwifi/88W8964.bin",
-+		.cal_file	= NULL,
-+		.txpwrlmt_file  = NULL,
-+		.antenna_tx	= ANTENNA_TX_4_AUTO,
-+		.antenna_rx	= ANTENNA_RX_4_AUTO,
-+	},
-+	[MWL8997] = {
-+		.part_name	= "88W8997",
-+		.fw_image	= "mwlwifi/88W8997.bin",
-+		.cal_file	= "mwlwifi/WlanCalData_ext.conf",
-+		.txpwrlmt_file  = "mwlwifi/txpwrlmt_cfg.conf",
-+		.antenna_tx	= ANTENNA_TX_2,
-+		.antenna_rx	= ANTENNA_RX_2,
-+	},
-+};
-+
-+static int pcie_alloc_resource(struct pcie_priv *pcie_priv)
-+{
-+	struct pci_dev *pdev = pcie_priv->pdev;
-+	struct device *dev = &pdev->dev;
-+	void __iomem *addr;
-+
-+	pcie_priv->next_bar_num = 1;	/* 32-bit */
-+	if (pci_resource_flags(pdev, 0) & 0x04)
-+		pcie_priv->next_bar_num = 2;	/* 64-bit */
-+
-+	addr = devm_ioremap_resource(dev, &pdev->resource[0]);
-+	if (IS_ERR(addr)) {
-+		pr_err("%s: cannot reserve PCI memory region 0\n",
-+		       PCIE_DRV_NAME);
-+		goto err;
-+	}
-+	pcie_priv->iobase0 = addr;
-+	pr_debug("iobase0 = %p\n", pcie_priv->iobase0);
-+
-+	addr = devm_ioremap_resource(dev,
-+				     &pdev->resource[pcie_priv->next_bar_num]);
-+	if (IS_ERR(addr)) {
-+		pr_err("%s: cannot reserve PCI memory region 1\n",
-+		       PCIE_DRV_NAME);
-+		goto err;
-+	}
-+	pcie_priv->iobase1 = addr;
-+	pr_debug("iobase1 = %p\n", pcie_priv->iobase1);
-+
-+	return 0;
-+
-+err:
-+	pr_err("pci alloc fail\n");
-+
-+	return -EIO;
-+}
-+
-+static u32 pcie_read_mac_reg(struct pcie_priv *pcie_priv, u32 offset)
-+{
-+	struct mwl_priv *priv = pcie_priv->mwl_priv;
-+
-+	if (priv->chip_type == MWL8964) {
-+		u32 *addr_val = kmalloc(64 * sizeof(u32), GFP_ATOMIC);
-+		u32 val;
-+
-+		if (addr_val) {
-+			mwl_fwcmd_get_addr_value(priv->hw,
-+						 0x8000a000 + offset, 4,
-+						 addr_val, 0);
-+			val = addr_val[0];
-+			kfree(addr_val);
-+			return val;
-+		}
-+		return 0;
-+	} else
-+		return le32_to_cpu(*(__le32 *)
-+		       (MAC_REG_ADDR_PCI(offset)));
-+}
-+
-+static bool pcie_chk_adapter(struct pcie_priv *pcie_priv)
-+{
-+	struct mwl_priv *priv = pcie_priv->mwl_priv;
-+	u32 regval;
-+
-+	regval = readl(pcie_priv->iobase1 + MACREG_REG_INT_CODE);
-+
-+	if (regval == 0xffffffff) {
-+		wiphy_err(priv->hw->wiphy, "adapter does not exist\n");
-+		return false;
-+	}
-+
-+	if (priv->cmd_timeout)
-+		wiphy_debug(priv->hw->wiphy, "MACREG_REG_INT_CODE: 0x%04x\n",
-+			    regval);
-+
-+	return true;
-+}
-+
-+static void pcie_send_cmd(struct pcie_priv *pcie_priv)
-+{
-+	writel(pcie_priv->mwl_priv->pphys_cmd_buf,
-+	       pcie_priv->iobase1 + MACREG_REG_GEN_PTR);
-+	writel(MACREG_H2ARIC_BIT_DOOR_BELL,
-+	       pcie_priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS);
-+}
-+
-+static int pcie_wait_complete(struct mwl_priv *priv, unsigned short cmd)
-+{
-+	unsigned int curr_iteration = MAX_WAIT_FW_COMPLETE_ITERATIONS;
-+	unsigned short int_code = 0;
-+
-+	do {
-+		int_code = le16_to_cpu(*((__le16 *)&priv->pcmd_buf[0]));
-+		usleep_range(1000, 2000);
-+	} while ((int_code != cmd) && (--curr_iteration) && !priv->rmmod);
-+
-+	if (curr_iteration == 0) {
-+		wiphy_err(priv->hw->wiphy, "cmd 0x%04x=%s timed out\n",
-+			  cmd, mwl_fwcmd_get_cmd_string(cmd));
-+		wiphy_err(priv->hw->wiphy, "return code: 0x%04x\n", int_code);
-+		return -EIO;
-+	}
-+
-+	if (priv->chip_type != MWL8997)
-+		usleep_range(3000, 5000);
-+
-+	return 0;
-+}
-+
-+static int pcie_init(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	const struct hostcmd_get_hw_spec *get_hw_spec;
-+	struct hostcmd_set_hw_spec set_hw_spec;
-+	int rc, i;
-+
-+	spin_lock_init(&pcie_priv->int_mask_lock);
-+	tasklet_init(&pcie_priv->tx_task,
-+		     (void *)pcie_tx_skbs, (unsigned long)hw);
-+	tasklet_disable(&pcie_priv->tx_task);
-+	tasklet_init(&pcie_priv->tx_done_task,
-+		     (void *)pcie_tx_done, (unsigned long)hw);
-+	tasklet_disable(&pcie_priv->tx_done_task);
-+	spin_lock_init(&pcie_priv->tx_desc_lock);
-+	tasklet_init(&pcie_priv->rx_task,
-+		     (void *)pcie_rx_recv, (unsigned long)hw);
-+	tasklet_disable(&pcie_priv->rx_task);
-+	tasklet_init(&pcie_priv->qe_task,
-+		     (void *)pcie_tx_flush_amsdu, (unsigned long)hw);
-+	tasklet_disable(&pcie_priv->qe_task);
-+	pcie_priv->txq_limit = PCIE_TX_QUEUE_LIMIT;
-+	pcie_priv->txq_wake_threshold = PCIE_TX_WAKE_Q_THRESHOLD;
-+	pcie_priv->is_tx_done_schedule = false;
-+	pcie_priv->recv_limit = PCIE_RECEIVE_LIMIT;
-+	pcie_priv->is_rx_schedule = false;
-+	pcie_priv->is_qe_schedule = false;
-+	pcie_priv->qe_trig_num = 0;
-+	pcie_priv->qe_trig_time = jiffies;
-+
-+	rc = pcie_tx_init(hw);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "%s: fail to initialize TX\n",
-+			  PCIE_DRV_NAME);
-+		goto err_mwl_tx_init;
-+	}
-+
-+	rc = pcie_rx_init(hw);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "%s: fail to initialize RX\n",
-+			  PCIE_DRV_NAME);
-+		goto err_mwl_rx_init;
-+	}
-+
-+	/* get and prepare HW specifications */
-+	get_hw_spec = mwl_fwcmd_get_hw_specs(hw);
-+	if (!get_hw_spec) {
-+		wiphy_err(hw->wiphy, "%s: fail to get HW specifications\n",
-+			  PCIE_DRV_NAME);
-+		goto err_get_hw_specs;
-+	}
-+	ether_addr_copy(&priv->hw_data.mac_addr[0],
-+			get_hw_spec->permanent_addr);
-+	pcie_priv->desc_data[0].wcb_base =
-+		le32_to_cpu(get_hw_spec->wcb_base0) & 0x0000ffff;
-+	for (i = 1; i < SYSADPT_TOTAL_TX_QUEUES; i++)
-+		pcie_priv->desc_data[i].wcb_base =
-+			le32_to_cpu(get_hw_spec->wcb_base[i - 1]) & 0x0000ffff;
-+	pcie_priv->desc_data[0].rx_desc_read =
-+		le32_to_cpu(get_hw_spec->rxpd_rd_ptr) & 0x0000ffff;
-+	pcie_priv->desc_data[0].rx_desc_write =
-+		le32_to_cpu(get_hw_spec->rxpd_wr_ptr) & 0x0000ffff;
-+	priv->hw_data.fw_release_num = le32_to_cpu(get_hw_spec->fw_release_num);
-+	priv->hw_data.hw_version = get_hw_spec->version;
-+	if (priv->chip_type != MWL8997) {
-+		writel(pcie_priv->desc_data[0].pphys_tx_ring,
-+		       pcie_priv->iobase0 + pcie_priv->desc_data[0].wcb_base);
-+		for (i = 1; i < SYSADPT_TOTAL_TX_QUEUES; i++)
-+			writel(pcie_priv->desc_data[i].pphys_tx_ring,
-+			       pcie_priv->iobase0 +
-+			       pcie_priv->desc_data[i].wcb_base);
-+	}
-+	writel(pcie_priv->desc_data[0].pphys_rx_ring,
-+	       pcie_priv->iobase0 + pcie_priv->desc_data[0].rx_desc_read);
-+	writel(pcie_priv->desc_data[0].pphys_rx_ring,
-+	       pcie_priv->iobase0 + pcie_priv->desc_data[0].rx_desc_write);
-+
-+	/* prepare and set HW specifications */
-+	memset(&set_hw_spec, 0, sizeof(set_hw_spec));
-+	if (priv->chip_type == MWL8997) {
-+		set_hw_spec.wcb_base[0] =
-+			cpu_to_le32(pcie_priv->txbd_ring_pbase);
-+		set_hw_spec.tx_wcb_num_per_queue =
-+			cpu_to_le32(PCIE_MAX_TXRX_BD);
-+		set_hw_spec.num_tx_queues = cpu_to_le32(1);
-+		set_hw_spec.features |= HW_SET_PARMS_FEATURES_HOST_PROBE_RESP;
-+	} else {
-+		set_hw_spec.wcb_base[0] =
-+			cpu_to_le32(pcie_priv->desc_data[0].pphys_tx_ring);
-+		for (i = 1; i < SYSADPT_TOTAL_TX_QUEUES; i++)
-+			set_hw_spec.wcb_base[i] = cpu_to_le32(
-+				pcie_priv->desc_data[i].pphys_tx_ring);
-+		set_hw_spec.tx_wcb_num_per_queue =
-+			cpu_to_le32(PCIE_MAX_NUM_TX_DESC);
-+		set_hw_spec.num_tx_queues = cpu_to_le32(PCIE_NUM_OF_DESC_DATA);
-+	}
-+	set_hw_spec.total_rx_wcb = cpu_to_le32(PCIE_MAX_NUM_RX_DESC);
-+	set_hw_spec.rxpd_wr_ptr =
-+		cpu_to_le32(pcie_priv->desc_data[0].pphys_rx_ring);
-+	rc = mwl_fwcmd_set_hw_specs(hw, &set_hw_spec);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "%s: fail to set HW specifications\n",
-+			  PCIE_DRV_NAME);
-+		goto err_set_hw_specs;
-+	}
-+
-+	return rc;
-+
-+err_set_hw_specs:
-+err_get_hw_specs:
-+
-+	pcie_rx_deinit(hw);
-+
-+err_mwl_rx_init:
-+
-+	pcie_tx_deinit(hw);
-+
-+err_mwl_tx_init:
-+
-+	wiphy_err(hw->wiphy, "%s: init fail\n", PCIE_DRV_NAME);
-+
-+	return rc;
-+}
-+
-+static void pcie_deinit(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	pcie_rx_deinit(hw);
-+	pcie_tx_deinit(hw);
-+	tasklet_kill(&pcie_priv->qe_task);
-+	tasklet_kill(&pcie_priv->rx_task);
-+	tasklet_kill(&pcie_priv->tx_done_task);
-+	tasklet_kill(&pcie_priv->tx_task);
-+	pcie_reset(hw);
-+}
-+
-+static int pcie_get_info(struct ieee80211_hw *hw, char *buf, size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	char *p = buf;
-+	int len = 0;
-+
-+	len += scnprintf(p + len, size - len, "iobase0: %p\n",
-+			 pcie_priv->iobase0);
-+	len += scnprintf(p + len, size - len, "iobase1: %p\n",
-+			 pcie_priv->iobase1);
-+	len += scnprintf(p + len, size - len,
-+			 "tx limit: %d\n", pcie_priv->txq_limit);
-+	len += scnprintf(p + len, size - len,
-+			 "rx limit: %d\n", pcie_priv->recv_limit);
-+	len += scnprintf(p + len, size - len,
-+			 "qe trigger number: %d\n", pcie_priv->qe_trig_num);
-+	return len;
-+}
-+
-+static void pcie_enable_data_tasks(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	tasklet_enable(&pcie_priv->tx_task);
-+	tasklet_enable(&pcie_priv->tx_done_task);
-+	tasklet_enable(&pcie_priv->rx_task);
-+	tasklet_enable(&pcie_priv->qe_task);
-+}
-+
-+static void pcie_disable_data_tasks(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	tasklet_disable(&pcie_priv->tx_task);
-+	tasklet_disable(&pcie_priv->tx_done_task);
-+	tasklet_disable(&pcie_priv->rx_task);
-+	tasklet_disable(&pcie_priv->qe_task);
-+}
-+
-+static int pcie_exec_cmd(struct ieee80211_hw *hw, unsigned short cmd)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	bool busy = false;
-+
-+	might_sleep();
-+
-+	if (!pcie_chk_adapter(pcie_priv)) {
-+		wiphy_err(priv->hw->wiphy, "adapter does not exist\n");
-+		priv->in_send_cmd = false;
-+		return -EIO;
-+	}
-+
-+	if (!priv->in_send_cmd && !priv->rmmod) {
-+		priv->in_send_cmd = true;
-+		if (priv->dump_hostcmd)
-+			wiphy_debug(priv->hw->wiphy, "send cmd 0x%04x=%s\n",
-+				    cmd, mwl_fwcmd_get_cmd_string(cmd));
-+		pcie_send_cmd(pcie_priv);
-+		if (pcie_wait_complete(priv, 0x8000 | cmd)) {
-+			wiphy_err(priv->hw->wiphy, "timeout: 0x%04x\n", cmd);
-+			priv->in_send_cmd = false;
-+			priv->cmd_timeout = true;
-+			if (priv->heartbeat)
-+				vendor_cmd_basic_event(
-+					hw->wiphy,
-+					MWL_VENDOR_EVENT_CMD_TIMEOUT);
-+			return -EIO;
-+		}
-+	} else {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "previous command is running or module removed\n");
-+		busy = true;
-+	}
-+
-+	if (!busy)
-+		priv->in_send_cmd = false;
-+
-+	return 0;
-+}
-+
-+static int pcie_get_irq_num(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	return pcie_priv->pdev->irq;
-+}
-+
-+static irqreturn_t pcie_isr(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	u32 int_status;
-+
-+	int_status = readl(pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE);
-+
-+	if (int_status == 0x00000000)
-+		return IRQ_NONE;
-+
-+	if (int_status == 0xffffffff) {
-+		wiphy_warn(hw->wiphy, "card unplugged?\n");
-+	} else {
-+		writel(~int_status,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE);
-+
-+		if (int_status & MACREG_A2HRIC_BIT_TX_DONE) {
-+			if (!pcie_priv->is_tx_done_schedule) {
-+				pcie_mask_int(pcie_priv,
-+					      MACREG_A2HRIC_BIT_TX_DONE, false);
-+				tasklet_schedule(&pcie_priv->tx_done_task);
-+				pcie_priv->is_tx_done_schedule = true;
-+			}
-+		}
-+
-+		if (int_status & MACREG_A2HRIC_BIT_RX_RDY) {
-+			if (!pcie_priv->is_rx_schedule) {
-+				pcie_mask_int(pcie_priv,
-+					      MACREG_A2HRIC_BIT_RX_RDY, false);
-+				tasklet_schedule(&pcie_priv->rx_task);
-+				pcie_priv->is_rx_schedule = true;
-+			}
-+		}
-+
-+		if (int_status & MACREG_A2HRIC_BIT_RADAR_DETECT) {
-+			wiphy_info(hw->wiphy, "radar detected by firmware\n");
-+			ieee80211_radar_detected(hw);
-+		}
-+
-+		if (int_status & MACREG_A2HRIC_BIT_QUE_EMPTY) {
-+			if (!pcie_priv->is_qe_schedule) {
-+				if (time_after(jiffies,
-+					       (pcie_priv->qe_trig_time + 1))) {
-+					pcie_mask_int(pcie_priv,
-+					      MACREG_A2HRIC_BIT_QUE_EMPTY,
-+					      false);
-+					tasklet_schedule(&pcie_priv->qe_task);
-+					pcie_priv->qe_trig_num++;
-+					pcie_priv->is_qe_schedule = true;
-+					pcie_priv->qe_trig_time = jiffies;
-+				}
-+			}
-+		}
-+
-+		if (int_status & MACREG_A2HRIC_BIT_CHAN_SWITCH)
-+			ieee80211_queue_work(hw, &priv->chnl_switch_handle);
-+
-+		if (int_status & MACREG_A2HRIC_BA_WATCHDOG)
-+			ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
-+	}
-+
-+	return IRQ_HANDLED;
-+}
-+
-+static void pcie_irq_enable(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	if (pcie_chk_adapter(pcie_priv)) {
-+		writel(0x00,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK);
-+		writel(MACREG_A2HRIC_BIT_MASK,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK);
-+	}
-+}
-+
-+static void pcie_irq_disable(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	if (pcie_chk_adapter(pcie_priv))
-+		writel(0x00,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK);
-+}
-+
-+static void pcie_timer_routine(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	static int cnt;
-+	struct mwl_ampdu_stream *stream;
-+	struct mwl_sta *sta_info;
-+	struct mwl_tx_info *tx_stats;
-+	struct mwl_ampdu_stream *rm_stream = NULL;
-+	u32 rm_pkts = 0;
-+	bool ba_full = true;
-+	int i;
-+
-+	if ((++cnt * SYSADPT_TIMER_WAKEUP_TIME) < CHECK_BA_TRAFFIC_TIME)
-+		return;
-+	cnt = 0;
-+	spin_lock_bh(&priv->stream_lock);
-+	for (i = 0; i < priv->ampdu_num; i++) {
-+		stream = &priv->ampdu[i];
-+
-+		if (stream->state == AMPDU_STREAM_ACTIVE) {
-+			sta_info = mwl_dev_get_sta(stream->sta);
-+			tx_stats = &sta_info->tx_stats[stream->tid];
-+
-+			if ((jiffies - tx_stats->start_time > HZ) &&
-+			    (tx_stats->pkts < SYSADPT_AMPDU_PACKET_THRESHOLD)) {
-+				if (rm_pkts) {
-+					if (tx_stats->pkts < rm_pkts) {
-+						rm_stream = stream;
-+						rm_pkts = tx_stats->pkts;
-+					}
-+				} else {
-+					rm_stream = stream;
-+					rm_pkts = tx_stats->pkts;
-+				}
-+			}
-+
-+			if (jiffies - tx_stats->start_time > HZ) {
-+				tx_stats->pkts = 0;
-+				tx_stats->start_time = jiffies;
-+			}
-+		} else
-+			ba_full = false;
-+	}
-+	if (ba_full && rm_stream) {
-+		ieee80211_stop_tx_ba_session(rm_stream->sta,
-+					     rm_stream->tid);
-+		wiphy_debug(hw->wiphy, "Stop BA %pM\n", rm_stream->sta->addr);
-+	}
-+	spin_unlock_bh(&priv->stream_lock);
-+}
-+
-+static void pcie_tx_return_pkts(struct ieee80211_hw *hw)
-+{
-+	pcie_tx_done((unsigned long)hw);
-+}
-+
-+static struct device_node *pcie_get_device_node(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct device_node *dev_node;
-+
-+	dev_node = pci_bus_to_OF_node(pcie_priv->pdev->bus);
-+	wiphy_info(priv->hw->wiphy, "device node: %s\n", dev_node->full_name);
-+
-+	return dev_node;
-+}
-+
-+static void pcie_get_survey(struct ieee80211_hw *hw,
-+			    struct mwl_survey_info *survey_info)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	survey_info->filled = SURVEY_INFO_TIME |
-+			      SURVEY_INFO_TIME_BUSY |
-+			      SURVEY_INFO_TIME_TX |
-+			      SURVEY_INFO_NOISE_DBM;
-+	survey_info->time_period += pcie_read_mac_reg(pcie_priv, MCU_LAST_READ);
-+	survey_info->time_busy += pcie_read_mac_reg(pcie_priv, MCU_CCA_CNT);
-+	survey_info->time_tx += pcie_read_mac_reg(pcie_priv, MCU_TXPE_CNT);
-+	survey_info->noise = priv->noise;
-+}
-+
-+static int pcie_reg_access(struct ieee80211_hw *hw, bool write)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	u8 set;
-+	u32 *addr_val;
-+	int ret = 0;
-+
-+	set = write ? WL_SET : WL_GET;
-+
-+	switch (priv->reg_type) {
-+	case MWL_ACCESS_RF:
-+		ret = mwl_fwcmd_reg_rf(hw, set, priv->reg_offset,
-+				       &priv->reg_value);
-+		break;
-+	case MWL_ACCESS_BBP:
-+		ret = mwl_fwcmd_reg_bb(hw, set, priv->reg_offset,
-+				       &priv->reg_value);
-+		break;
-+	case MWL_ACCESS_CAU:
-+		ret = mwl_fwcmd_reg_cau(hw, set, priv->reg_offset,
-+					&priv->reg_value);
-+		break;
-+	case MWL_ACCESS_ADDR0:
-+		if (set == WL_GET)
-+			priv->reg_value =
-+				readl(pcie_priv->iobase0 + priv->reg_offset);
-+		else
-+			writel(priv->reg_value,
-+			       pcie_priv->iobase0 + priv->reg_offset);
-+		break;
-+	case MWL_ACCESS_ADDR1:
-+		if (set == WL_GET)
-+			priv->reg_value =
-+				readl(pcie_priv->iobase1 + priv->reg_offset);
-+		else
-+			writel(priv->reg_value,
-+			       pcie_priv->iobase1 + priv->reg_offset);
-+		break;
-+	case MWL_ACCESS_ADDR:
-+		addr_val = kzalloc(64 * sizeof(u32), GFP_KERNEL);
-+		if (addr_val) {
-+			addr_val[0] = priv->reg_value;
-+			ret = mwl_fwcmd_get_addr_value(hw, priv->reg_offset,
-+						       4, addr_val, set);
-+			if ((!ret) && (set == WL_GET))
-+				priv->reg_value = addr_val[0];
-+			kfree(addr_val);
-+		} else {
-+			ret = -ENOMEM;
-+		}
-+		break;
-+	default:
-+		ret = -EINVAL;
-+		break;
-+	}
-+
-+	return ret;
-+}
-+
-+static struct mwl_hif_ops pcie_hif_ops = {
-+	.driver_name           = PCIE_DRV_NAME,
-+	.driver_version        = PCIE_DRV_VERSION,
-+	.tx_head_room          = PCIE_MIN_BYTES_HEADROOM,
-+	.ampdu_num             = PCIE_AMPDU_QUEUES,
-+	.reset                 = pcie_reset,
-+	.init                  = pcie_init,
-+	.deinit                = pcie_deinit,
-+	.get_info              = pcie_get_info,
-+	.enable_data_tasks     = pcie_enable_data_tasks,
-+	.disable_data_tasks    = pcie_disable_data_tasks,
-+	.exec_cmd              = pcie_exec_cmd,
-+	.get_irq_num           = pcie_get_irq_num,
-+	.irq_handler           = pcie_isr,
-+	.irq_enable            = pcie_irq_enable,
-+	.irq_disable           = pcie_irq_disable,
-+	.download_firmware     = pcie_download_firmware,
-+	.timer_routine         = pcie_timer_routine,
-+	.tx_xmit               = pcie_tx_xmit,
-+	.tx_del_pkts_via_vif   = pcie_tx_del_pkts_via_vif,
-+	.tx_del_pkts_via_sta   = pcie_tx_del_pkts_via_sta,
-+	.tx_del_ampdu_pkts     = pcie_tx_del_ampdu_pkts,
-+	.tx_del_sta_amsdu_pkts = pcie_tx_del_sta_amsdu_pkts,
-+	.tx_return_pkts        = pcie_tx_return_pkts,
-+	.get_device_node       = pcie_get_device_node,
-+	.get_survey            = pcie_get_survey,
-+	.reg_access            = pcie_reg_access,
-+};
-+
-+static int pcie_init_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	const struct hostcmd_get_hw_spec *get_hw_spec;
-+	struct hostcmd_set_hw_spec set_hw_spec;
-+	int rc;
-+
-+	spin_lock_init(&pcie_priv->int_mask_lock);
-+	tasklet_init(&pcie_priv->tx_task,
-+		     (void *)pcie_tx_skbs_ndp, (unsigned long)hw);
-+	tasklet_disable(&pcie_priv->tx_task);
-+	spin_lock_init(&pcie_priv->tx_desc_lock);
-+	tasklet_init(&pcie_priv->rx_task,
-+		     (void *)pcie_rx_recv_ndp, (unsigned long)hw);
-+	tasklet_disable(&pcie_priv->rx_task);
-+	pcie_priv->txq_limit = TX_QUEUE_LIMIT;
-+	pcie_priv->txq_wake_threshold = TX_WAKE_Q_THRESHOLD;
-+	pcie_priv->is_tx_schedule = false;
-+	pcie_priv->recv_limit = MAX_NUM_RX_DESC;
-+	pcie_priv->is_rx_schedule = false;
-+
-+	rc = pcie_tx_init_ndp(hw);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "%s: fail to initialize TX\n",
-+			  PCIE_DRV_NAME);
-+		goto err_mwl_tx_init;
-+	}
-+
-+	rc = pcie_rx_init_ndp(hw);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "%s: fail to initialize RX\n",
-+			  PCIE_DRV_NAME);
-+		goto err_mwl_rx_init;
-+	}
-+
-+	/* get and prepare HW specifications */
-+	get_hw_spec = mwl_fwcmd_get_hw_specs(hw);
-+	if (!get_hw_spec) {
-+		wiphy_err(hw->wiphy, "%s: fail to get HW specifications\n",
-+			  PCIE_DRV_NAME);
-+		goto err_get_hw_specs;
-+	}
-+	ether_addr_copy(&priv->hw_data.mac_addr[0],
-+			get_hw_spec->permanent_addr);
-+	priv->hw_data.fw_release_num = le32_to_cpu(get_hw_spec->fw_release_num);
-+	priv->hw_data.hw_version = get_hw_spec->version;
-+
-+	/* prepare and set HW specifications */
-+	memset(&set_hw_spec, 0, sizeof(set_hw_spec));
-+	set_hw_spec.wcb_base[0] =
-+		cpu_to_le32(pcie_priv->desc_data_ndp.pphys_tx_ring);
-+	set_hw_spec.wcb_base[1] =
-+		cpu_to_le32(pcie_priv->desc_data_ndp.pphys_tx_ring_done);
-+	set_hw_spec.wcb_base[2] =
-+		cpu_to_le32(pcie_priv->desc_data_ndp.pphys_rx_ring);
-+	set_hw_spec.wcb_base[3] =
-+		cpu_to_le32(pcie_priv->desc_data_ndp.pphys_rx_ring_done);
-+	set_hw_spec.acnt_base_addr =
-+		cpu_to_le32(pcie_priv->desc_data_ndp.pphys_acnt_ring);
-+	set_hw_spec.acnt_buf_size =
-+		cpu_to_le32(pcie_priv->desc_data_ndp.acnt_ring_size);
-+	rc = mwl_fwcmd_set_hw_specs(hw, &set_hw_spec);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "%s: fail to set HW specifications\n",
-+			  PCIE_DRV_NAME);
-+		goto err_set_hw_specs;
-+	}
-+
-+	return rc;
-+
-+err_set_hw_specs:
-+err_get_hw_specs:
-+
-+	pcie_rx_deinit_ndp(hw);
-+
-+err_mwl_rx_init:
-+
-+	pcie_tx_deinit_ndp(hw);
-+
-+err_mwl_tx_init:
-+
-+	wiphy_err(hw->wiphy, "%s: init fail\n", PCIE_DRV_NAME);
-+
-+	return rc;
-+}
-+
-+static void pcie_deinit_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	pcie_rx_deinit_ndp(hw);
-+	pcie_tx_deinit_ndp(hw);
-+	tasklet_kill(&pcie_priv->rx_task);
-+	tasklet_kill(&pcie_priv->tx_task);
-+	pcie_reset(hw);
-+}
-+
-+static int pcie_get_info_ndp(struct ieee80211_hw *hw, char *buf, size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	char *p = buf;
-+	int len = 0;
-+
-+	len += scnprintf(p + len, size - len, "iobase0: %p\n",
-+			 pcie_priv->iobase0);
-+	len += scnprintf(p + len, size - len, "iobase1: %p\n",
-+			 pcie_priv->iobase1);
-+	len += scnprintf(p + len, size - len,
-+			 "tx limit: %d\n", pcie_priv->txq_limit);
-+	len += scnprintf(p + len, size - len,
-+			 "rx limit: %d\n", pcie_priv->recv_limit);
-+	return len;
-+}
-+
-+static int pcie_get_tx_status_ndp(struct ieee80211_hw *hw, char *buf,
-+				  size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	char *p = buf;
-+	int len = 0;
-+
-+	len += scnprintf(p + len, size - len, "tx_done_cnt: %d\n",
-+			 pcie_priv->tx_done_cnt);
-+	len += scnprintf(p + len, size - len, "tx_desc_busy_cnt: %d\n",
-+			 pcie_priv->desc_data_ndp.tx_desc_busy_cnt);
-+	len += scnprintf(p + len, size - len, "tx_sent_head: %d\n",
-+			 pcie_priv->desc_data_ndp.tx_sent_head);
-+	len += scnprintf(p + len, size - len, "tx_sent_tail: %d\n",
-+			 pcie_priv->desc_data_ndp.tx_sent_tail);
-+	len += scnprintf(p + len, size - len, "tx_done_head: %d\n",
-+			 readl(pcie_priv->iobase1 + MACREG_REG_TXDONEHEAD));
-+	len += scnprintf(p + len, size - len, "tx_done_tail: %d\n",
-+			 pcie_priv->desc_data_ndp.tx_done_tail);
-+	len += scnprintf(p + len, size - len, "tx_vbuflist_idx: %d\n",
-+			 pcie_priv->desc_data_ndp.tx_vbuflist_idx);
-+	return len;
-+}
-+
-+static int pcie_get_rx_status_ndp(struct ieee80211_hw *hw, char *buf,
-+				  size_t size)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	char *p = buf;
-+	int len = 0;
-+
-+	len += scnprintf(p + len, size - len, "rx_done_head: %d\n",
-+			 readl(pcie_priv->iobase1 + MACREG_REG_RXDONEHEAD));
-+	len += scnprintf(p + len, size - len, "rx_done_tail: %d\n",
-+			 readl(pcie_priv->iobase1 + MACREG_REG_RXDONETAIL));
-+	len += scnprintf(p + len, size - len, "rx_desc_head: %d\n",
-+			 readl(pcie_priv->iobase1 + MACREG_REG_RXDESCHEAD));
-+	len += scnprintf(p + len, size - len, "rx_skb_trace: %d\n",
-+			 skb_queue_len(&pcie_priv->rx_skb_trace));
-+	len += scnprintf(p + len, size - len, "rx_skb_unlink_err: %d\n",
-+			 pcie_priv->rx_skb_unlink_err);
-+	len += scnprintf(p + len, size - len, "signature_err: %d\n",
-+			 pcie_priv->signature_err);
-+	len += scnprintf(p + len, size - len, "recheck_rxringdone: %d\n",
-+			 pcie_priv->recheck_rxringdone);
-+	len += scnprintf(p + len, size - len, "fast_data_cnt: %d\n",
-+			 pcie_priv->rx_cnts.fast_data_cnt);
-+	len += scnprintf(p + len, size - len, "fast_bad_amsdu_cnt: %d\n",
-+			 pcie_priv->rx_cnts.fast_bad_amsdu_cnt);
-+	len += scnprintf(p + len, size - len, "slow_noqueue_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_noqueue_cnt);
-+	len += scnprintf(p + len, size - len, "slow_norun_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_norun_cnt);
-+	len += scnprintf(p + len, size - len, "slow_mcast_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_mcast_cnt);
-+	len += scnprintf(p + len, size - len, "slow_bad_sta_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_bad_sta_cnt);
-+	len += scnprintf(p + len, size - len, "slow_bad_mic_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_bad_mic_cnt);
-+	len += scnprintf(p + len, size - len, "slow_bad_pn_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_bad_pn_cnt);
-+	len += scnprintf(p + len, size - len, "slow_mgmt_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_mgmt_cnt);
-+	len += scnprintf(p + len, size - len, "slow_promisc_cnt: %d\n",
-+			 pcie_priv->rx_cnts.slow_promisc_cnt);
-+	len += scnprintf(p + len, size - len, "drop_cnt: %d\n",
-+			 pcie_priv->rx_cnts.drop_cnt);
-+	len += scnprintf(p + len, size - len, "offch_promisc_cnt: %d\n",
-+			 pcie_priv->rx_cnts.offch_promisc_cnt);
-+	len += scnprintf(p + len, size - len, "mu_pkt_cnt: %d\n",
-+			 pcie_priv->rx_cnts.mu_pkt_cnt);
-+	return len;
-+}
-+
-+static void pcie_enable_data_tasks_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	tasklet_enable(&pcie_priv->tx_task);
-+	tasklet_enable(&pcie_priv->rx_task);
-+}
-+
-+static void pcie_disable_data_tasks_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	tasklet_disable(&pcie_priv->tx_task);
-+	tasklet_disable(&pcie_priv->rx_task);
-+}
-+
-+static irqreturn_t pcie_isr_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	u32 int_status;
-+
-+	int_status = readl(pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE);
-+
-+	if (int_status == 0x00000000)
-+		return IRQ_NONE;
-+
-+	if (int_status == 0xffffffff) {
-+		wiphy_warn(hw->wiphy, "card unplugged?\n");
-+	} else {
-+		writel(~int_status,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE);
-+
-+		if (int_status & MACREG_A2HRIC_ACNT_HEAD_RDY)
-+			ieee80211_queue_work(hw, &priv->account_handle);
-+
-+		if (int_status & MACREG_A2HRIC_RX_DONE_HEAD_RDY) {
-+			if (!pcie_priv->is_rx_schedule) {
-+				pcie_mask_int(pcie_priv,
-+					      MACREG_A2HRIC_RX_DONE_HEAD_RDY,
-+					      false);
-+				tasklet_schedule(&pcie_priv->rx_task);
-+				pcie_priv->is_rx_schedule = true;
-+			}
-+		}
-+
-+		if (int_status & MACREG_A2HRIC_NEWDP_DFS) {
-+			wiphy_info(hw->wiphy, "radar detected by firmware\n");
-+			ieee80211_radar_detected(hw);
-+		}
-+
-+		if (int_status & MACREG_A2HRIC_NEWDP_CHANNEL_SWITCH)
-+			ieee80211_queue_work(hw, &priv->chnl_switch_handle);
-+	}
-+
-+	return IRQ_HANDLED;
-+}
-+
-+static void pcie_irq_enable_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	if (pcie_chk_adapter(pcie_priv)) {
-+		writel(0x00,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK);
-+		writel(MACREG_A2HRIC_BIT_MASK_NDP,
-+		       pcie_priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK);
-+	}
-+}
-+
-+static void pcie_timer_routine_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num = SYSADPT_TX_WMM_QUEUES;
-+	static int cnt;
-+
-+	if (!pcie_priv->is_tx_schedule) {
-+		while (num--) {
-+			if (skb_queue_len(&pcie_priv->txq[num]) > 0) {
-+				tasklet_schedule(&pcie_priv->tx_task);
-+				pcie_priv->is_tx_schedule = true;
-+				break;
-+			}
-+		}
-+	}
-+
-+	if ((++cnt * SYSADPT_TIMER_WAKEUP_TIME) >= CHECK_TX_DONE_TIME) {
-+		pcie_tx_done_ndp(hw);
-+		cnt = 0;
-+	}
-+}
-+
-+static void pcie_tx_return_pkts_ndp(struct ieee80211_hw *hw)
-+{
-+	pcie_tx_done_ndp(hw);
-+}
-+
-+static void pcie_set_sta_id(struct ieee80211_hw *hw,
-+			    struct ieee80211_sta *sta,
-+			    bool sta_mode, bool set)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct mwl_sta *sta_info;
-+	u16 stnid;
-+
-+	sta_info = mwl_dev_get_sta(sta);
-+	stnid = sta_mode ? 0 : sta_info->stnid;
-+	pcie_priv->sta_link[stnid] = set ? sta : NULL;
-+}
-+
-+static void pcie_tx_account(struct mwl_priv *priv,
-+			    struct mwl_sta *sta_info,
-+			    struct acnt_tx_s *acnt_tx)
-+{
-+	u32 rate_info, tx_cnt;
-+	u8 index, type, rate_ac, format, bw, gi, mcs, nss;
-+	u16 ratemask;
-+	u8 i, found;
-+	struct mwl_tx_hist *tx_hist;
-+	struct mwl_tx_hist_data *tx_hist_data;
-+
-+	rate_info = le32_to_cpu(acnt_tx->tx_info.rate_info);
-+	tx_cnt = le32_to_cpu(acnt_tx->tx_cnt);
-+	index = acnt_tx->rate_tbl_index;
-+	type = acnt_tx->type;
-+
-+	if (!rate_info)
-+		return;
-+	sta_info->tx_rate_info = rate_info;
-+
-+	tx_hist = &sta_info->tx_hist;
-+	if (!tx_hist || (type >= SU_MU_TYPE_CNT))
-+		return;
-+
-+	format = rate_info & MWL_TX_RATE_FORMAT_MASK;
-+	bw = (rate_info & MWL_TX_RATE_BANDWIDTH_MASK) >>
-+		MWL_TX_RATE_BANDWIDTH_SHIFT;
-+	gi = (rate_info & MWL_TX_RATE_SHORTGI_MASK) >>
-+		MWL_TX_RATE_SHORTGI_SHIFT;
-+	mcs = (rate_info & MWL_TX_RATE_RATEIDMCS_MASK) >>
-+		MWL_TX_RATE_RATEIDMCS_SHIFT;
-+
-+	tx_hist->cur_rate_info[type] = rate_info;
-+
-+	/* Rate table index is valid */
-+	if (index != 0xff) {
-+		if (type == MU_MIMO) {
-+			rate_ac = mcs & 0xf;
-+			nss = mcs >> 4;
-+			if (nss < (QS_NUM_SUPPORTED_11AC_NSS - 1)) {
-+				tx_hist_data =
-+					&tx_hist->mu_rate[nss][bw][gi][rate_ac];
-+				tx_hist_data->rateinfo = rate_info;
-+				tx_hist_data->cnt++;
-+				tx_hist->total_tx_cnt[type] += tx_cnt;
-+			}
-+		} else {
-+			/* If legacy, skip legacy preamble bit 15 */
-+			if (format == TX_RATE_FORMAT_LEGACY)
-+				ratemask = 0xfff;
-+			else
-+				ratemask = 0xffff;
-+			tx_hist_data = &tx_hist->su_rate[0];
-+			if ((tx_hist_data[index].rateinfo & ratemask) ==
-+			    (rate_info & ratemask)) {
-+				tx_hist_data[index].cnt++;
-+				tx_hist->total_tx_cnt[type] += tx_cnt;
-+			}
-+		}
-+	} else {
-+		if (type == MU_MIMO) {
-+			rate_ac = mcs & 0xf;
-+			nss = mcs >> 4;
-+			if (nss < (QS_NUM_SUPPORTED_11AC_NSS - 1)) {
-+				tx_hist_data =
-+					&tx_hist->mu_rate[nss][bw][gi][rate_ac];
-+				tx_hist_data->rateinfo = rate_info;
-+				tx_hist_data->cnt++;
-+				tx_hist->total_tx_cnt[type] += tx_cnt;
-+			}
-+		} else {
-+			/* If legacy, skip legacy preamble bit 15 */
-+			if (format == TX_RATE_FORMAT_LEGACY)
-+				ratemask = 0xfff;
-+			else
-+				ratemask = 0xffff;
-+			tx_hist_data = &tx_hist->custom_rate[0];
-+			/* Go through non rate table buffer to see if any has
-+			 * been used. If all used up, recycle by using index 0
-+			 */
-+			for (i = 0; i < TX_RATE_HISTO_CUSTOM_CNT; i++) {
-+				if (!tx_hist_data[i].rateinfo ||
-+				    ((tx_hist_data[i].rateinfo & ratemask) ==
-+				    (rate_info & ratemask))) {
-+					found = 1;
-+					break;
-+				}
-+			}
-+			if (found)
-+				index = i;
-+			else
-+				index = 0; /* reuse index 0 buffer */
-+			tx_hist_data[index].rateinfo = rate_info;
-+			tx_hist_data[index].cnt++;
-+			tx_hist->total_tx_cnt[type] += tx_cnt;
-+		}
-+	}
-+}
-+
-+static void pcie_rx_account(struct mwl_priv *priv,
-+			    struct mwl_sta *sta_info,
-+			    struct acnt_rx_s *acnt_rx)
-+{
-+	u32 sig1, sig2, rate, param;
-+	u16 format, nss, bw, gi, rate_mcs;
-+
-+	sig1 = (le32_to_cpu(acnt_rx->rx_info.ht_sig1) >>
-+		RXINFO_HT_SIG1_SHIFT) & RXINFO_HT_SIG1_MASK;
-+	sig2 = (le32_to_cpu(acnt_rx->rx_info.ht_sig2_rate) >>
-+		RXINFO_HT_SIG2_SHIFT) & RXINFO_HT_SIG2_MASK;
-+	rate = (le32_to_cpu(acnt_rx->rx_info.ht_sig2_rate) >>
-+		RXINFO_RATE_SHIFT) & RXINFO_RATE_MASK;
-+	param = (le32_to_cpu(acnt_rx->rx_info.param) >>
-+		RXINFO_PARAM_SHIFT) & RXINFO_PARAM_MASK;
-+
-+	format = (param >> 3) & 0x7;
-+	nss = 0;
-+	bw = RX_RATE_INFO_HT20;
-+	switch (format) {
-+	case RX_RATE_INFO_FORMAT_11A:
-+		rate_mcs = rate & 0xF;
-+		if (rate_mcs == 10)
-+			rate_mcs = 7; /* 12 Mbps */
-+		else
-+			rate_mcs = utils_get_rate_id(rate_mcs);
-+		gi = RX_RATE_INFO_SHORT_INTERVAL;
-+		if ((rate_mcs == 5) || (rate_mcs == 7) || (rate_mcs == 9))
-+			return;
-+		break;
-+	case RX_RATE_INFO_FORMAT_11B:
-+		rate_mcs = utils_get_rate_id(rate & 0xF);
-+		gi = RX_RATE_INFO_LONG_INTERVAL;
-+		if ((rate_mcs == 0) || (rate_mcs == 1))
-+			return;
-+		break;
-+	case RX_RATE_INFO_FORMAT_11N:
-+		if ((sig1 & 0x3f) >= 16)
-+			return;
-+		bw = (sig1 >> 7) & 0x1;
-+		gi = (sig2 >> 7) & 0x1;
-+		rate_mcs = sig1 & 0x3F;
-+		if (rate_mcs > 76)
-+			return;
-+		break;
-+	case RX_RATE_INFO_FORMAT_11AC:
-+		if (((sig2 >> 4) & 0xf) >= 10)
-+			return;
-+		nss = (sig1 >> 10) & 0x3;
-+		if (!nss)
-+			return;
-+		bw = sig1 & 0x3;
-+		gi = sig2 & 0x1;
-+		rate_mcs = (sig2 >> 4) & 0xF;
-+		if (rate_mcs > 9)
-+			return;
-+		break;
-+	default:
-+		return;
-+	}
-+
-+	sta_info->rx_format = format;
-+	sta_info->rx_nss = nss;
-+	sta_info->rx_bw = bw;
-+	sta_info->rx_gi = gi;
-+	sta_info->rx_rate_mcs = rate_mcs;
-+	sta_info->rx_signal = ((le32_to_cpu(acnt_rx->rx_info.rssi_x) >>
-+		RXINFO_RSSI_X_SHIFT) & RXINFO_RSSI_X_MASK);
-+}
-+
-+static void pcie_tx_per(struct mwl_priv *priv, struct mwl_sta *sta_info,
-+			struct acnt_ra_s *acnt_ra)
-+{
-+	u32 rate_info;
-+	u8 index, per, type, rate_ac, per_index, format, bw, gi, mcs, nss;
-+	u16 ratemask;
-+	u8 i, found;
-+	struct mwl_tx_hist *tx_hist;
-+	struct mwl_tx_hist_data *tx_hist_data;
-+
-+	rate_info = le32_to_cpu(acnt_ra->rate_info);
-+	index = acnt_ra->rate_tbl_index;
-+	per = acnt_ra->per;
-+	type = acnt_ra->type;
-+
-+	tx_hist = &sta_info->tx_hist;
-+
-+	if (!tx_hist || !rate_info || (type >= SU_MU_TYPE_CNT))
-+		return;
-+
-+	if ((type == SU_MIMO) && (index >= MAX_SUPPORTED_RATES) &&
-+	    (index != 0xFF))
-+		return;
-+
-+	if (per >= TX_HISTO_PER_THRES[3])
-+		per_index = 4;
-+	else if (per >= TX_HISTO_PER_THRES[2])
-+		per_index = 3;
-+	else if (per >= TX_HISTO_PER_THRES[1])
-+		per_index = 2;
-+	else if (per >= TX_HISTO_PER_THRES[0])
-+		per_index = 1;
-+	else
-+		per_index = 0;
-+
-+	format = rate_info & MWL_TX_RATE_FORMAT_MASK;
-+	bw = (rate_info & MWL_TX_RATE_BANDWIDTH_MASK) >>
-+		MWL_TX_RATE_BANDWIDTH_SHIFT;
-+	gi = (rate_info & MWL_TX_RATE_SHORTGI_MASK) >>
-+		MWL_TX_RATE_SHORTGI_SHIFT;
-+	mcs = (rate_info & MWL_TX_RATE_RATEIDMCS_MASK) >>
-+		MWL_TX_RATE_RATEIDMCS_SHIFT;
-+
-+	/* Rate table index is valid */
-+	if (index != 0xff) {
-+		if (type == MU_MIMO) {
-+			rate_ac = mcs & 0xf;
-+			nss = mcs >> 4;
-+			if (nss < (QS_NUM_SUPPORTED_11AC_NSS - 1)) {
-+				tx_hist_data =
-+					&tx_hist->mu_rate[nss][bw][gi][rate_ac];
-+				tx_hist_data->rateinfo = rate_info;
-+				tx_hist_data->per[per_index]++;
-+			}
-+		} else {
-+			/* If legacy, skip legacy preamble bit 15 */
-+			if (format == TX_RATE_FORMAT_LEGACY)
-+				ratemask = 0xfff;
-+			else
-+				ratemask = 0xffff;
-+			tx_hist_data = &tx_hist->su_rate[0];
-+			if ((tx_hist_data[index].rateinfo & ratemask) ==
-+			    (rate_info & ratemask))
-+				tx_hist_data[index].per[per_index]++;
-+		}
-+	} else {
-+		if (type == MU_MIMO) {
-+			rate_ac = mcs & 0xf;
-+			nss = mcs >> 4;
-+			if (nss < (QS_NUM_SUPPORTED_11AC_NSS - 1)) {
-+				tx_hist_data =
-+					&tx_hist->mu_rate[nss][bw][gi][rate_ac];
-+				tx_hist_data->rateinfo = rate_info;
-+				tx_hist_data->per[per_index]++;
-+			}
-+		} else {
-+			/* If legacy, skip legacy preamble bit 15 */
-+			if (format == TX_RATE_FORMAT_LEGACY)
-+				ratemask = 0xfff;
-+			else
-+				ratemask = 0xffff;
-+			tx_hist_data = &tx_hist->custom_rate[0];
-+			/* Go through non rate table buffer to see if any has
-+			 * been used. If all used up, recycle by using index 0
-+			 */
-+			for (i = 0; i < TX_RATE_HISTO_CUSTOM_CNT; i++) {
-+				if (!tx_hist_data[i].rateinfo ||
-+				    ((tx_hist_data[i].rateinfo & ratemask) ==
-+				    (rate_info & ratemask))) {
-+					found = 1;
-+					break;
-+				}
-+			}
-+			if (found)
-+				index = i;
-+			else
-+				index = 0; /* reuse index 0 buffer */
-+			tx_hist_data[index].rateinfo = rate_info;
-+			tx_hist_data[index].per[per_index]++;
-+		}
-+	}
-+}
-+
-+static void pcie_ba_account(struct mwl_priv *priv,
-+			    struct mwl_sta *sta_info,
-+			    struct acnt_ba_s *acnt_ba)
-+{
-+	struct mwl_tx_ba_hist *ba_hist = &sta_info->ba_hist;
-+
-+	if (sta_info->stnid != le16_to_cpu(acnt_ba->stnid))
-+		return;
-+
-+	if (ba_hist->enable && ba_hist->ba_stats &&
-+	    (ba_hist->index < ACNT_BA_SIZE)) {
-+		ba_hist->type = acnt_ba->type;
-+		ba_hist->ba_stats[ba_hist->index].ba_hole = acnt_ba->ba_hole;
-+		ba_hist->ba_stats[ba_hist->index].ba_expected =
-+			acnt_ba->ba_expected;
-+		ba_hist->ba_stats[ba_hist->index].no_ba = acnt_ba->no_ba;
-+		ba_hist->index++;
-+		if (ba_hist->index == ACNT_BA_SIZE)
-+			wiphy_info(priv->hw->wiphy,
-+				   "Aid:%d BA histo collection done\n",
-+				   priv->ba_aid);
-+	}
-+}
-+
-+static void pcie_bf_mimo_ctrl_decode(struct mwl_priv *priv,
-+				     struct acnt_bf_mimo_ctrl_s *bf_mimo_ctrl)
-+{
-+	struct file *fp_data = NULL;
-+	const char filename[] = "/tmp/BF_MIMO_Ctrl_Field_Output.txt";
-+	char str_buf[256];
-+	char *buf = &str_buf[0];
-+	mm_segment_t oldfs;
-+
-+	oldfs = get_fs();
-+	set_fs(KERNEL_DS);
-+
-+	buf += sprintf(buf, "\nMAC: %pM\n", bf_mimo_ctrl->rec_mac);
-+	buf += sprintf(buf, "SU_0_MU_1: %d\n", bf_mimo_ctrl->type);
-+	buf += sprintf(buf, "MIMO_Ctrl_Field: 0x%x\n",
-+		       le32_to_cpu(bf_mimo_ctrl->mimo_ctrl));
-+	buf += sprintf(buf, "Comp_BF_Report_First_8Bytes: 0x%llx\n",
-+		       le64_to_cpu(bf_mimo_ctrl->comp_bf_rep));
-+
-+	fp_data = filp_open(filename, O_RDWR | O_CREAT | O_TRUNC, 0);
-+
-+	if (!IS_ERR(fp_data)) {
-+		__kernel_write(fp_data, str_buf, strlen(str_buf),
-+			       &fp_data->f_pos);
-+		filp_close(fp_data, current->files);
-+	} else {
-+		wiphy_err(priv->hw->wiphy, "Error opening %s! %x\n",
-+			  filename, (unsigned int)fp_data);
-+	}
-+
-+	set_fs(oldfs);
-+}
-+
-+static void pcie_process_account(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	u32 acnt_head, acnt_tail;
-+	u32 read_size;
-+	u8 *acnt_recds;
-+	u8 *pstart, *pend;
-+	struct acnt_s *acnt;
-+	struct acnt_tx_s *acnt_tx;
-+	struct acnt_rx_s *acnt_rx;
-+	struct acnt_ra_s *acnt_ra;
-+	struct acnt_ba_s *acnt_ba;
-+	struct acnt_bf_mimo_ctrl_s *acnt_bf_mimo_ctrl;
-+	struct pcie_dma_data *dma_data;
-+	struct mwl_sta *sta_info;
-+	u16 nf_a, nf_b, nf_c, nf_d;
-+	u16 stnid;
-+	u8 type;
-+
-+	acnt_head = readl(pcie_priv->iobase1 + MACREG_REG_ACNTHEAD);
-+	acnt_tail = readl(pcie_priv->iobase1 + MACREG_REG_ACNTTAIL);
-+
-+	if (acnt_tail == acnt_head)
-+		return;
-+
-+	if (acnt_tail > acnt_head) {
-+		read_size = desc->acnt_ring_size - acnt_tail + acnt_head;
-+		if (read_size > desc->acnt_ring_size) {
-+			wiphy_err(hw->wiphy,
-+				  "account size overflow (%d %d %d)\n",
-+				  acnt_head, acnt_tail, read_size);
-+			goto process_next;
-+		}
-+		memset(desc->pacnt_buf, 0, desc->acnt_ring_size);
-+		memcpy(desc->pacnt_buf, desc->pacnt_ring + acnt_tail,
-+		       desc->acnt_ring_size - acnt_tail);
-+		memcpy(desc->pacnt_buf + desc->acnt_ring_size - acnt_tail,
-+		       desc->pacnt_ring, acnt_head);
-+		acnt_recds = desc->pacnt_buf;
-+	} else {
-+		read_size = acnt_head - acnt_tail;
-+		if (read_size > desc->acnt_ring_size) {
-+			wiphy_err(hw->wiphy,
-+				  "account size overflow (%d %d %d)\n",
-+				  acnt_head, acnt_tail, read_size);
-+			goto process_next;
-+		}
-+		acnt_recds = desc->pacnt_ring + acnt_tail;
-+	}
-+
-+	pstart = acnt_recds;
-+	pend = pstart + read_size;
-+	while (pstart < pend) {
-+		acnt = (struct acnt_s *)pstart;
-+
-+		switch (le16_to_cpu(acnt->code)) {
-+		case ACNT_CODE_BUSY:
-+			pcie_priv->acnt_busy++;
-+			break;
-+		case ACNT_CODE_WRAP:
-+			pcie_priv->acnt_wrap++;
-+			break;
-+		case ACNT_CODE_DROP:
-+			pcie_priv->acnt_drop++;
-+			break;
-+		case ACNT_CODE_TX_ENQUEUE:
-+			acnt_tx = (struct acnt_tx_s *)pstart;
-+			sta_info = utils_find_sta(priv, acnt_tx->hdr.wh.addr1);
-+			if (sta_info) {
-+				spin_lock_bh(&priv->sta_lock);
-+				pcie_tx_account(priv, sta_info, acnt_tx);
-+				spin_unlock_bh(&priv->sta_lock);
-+			}
-+			break;
-+		case ACNT_CODE_RX_PPDU:
-+			acnt_rx = (struct acnt_rx_s *)pstart;
-+			nf_a = (le32_to_cpu(acnt_rx->rx_info.nf_a_b) >>
-+				RXINFO_NF_A_SHIFT) & RXINFO_NF_A_MASK;
-+			nf_b = (le32_to_cpu(acnt_rx->rx_info.nf_a_b) >>
-+				RXINFO_NF_B_SHIFT) & RXINFO_NF_B_MASK;
-+			nf_c = (le32_to_cpu(acnt_rx->rx_info.nf_c_d) >>
-+				RXINFO_NF_C_SHIFT) & RXINFO_NF_C_MASK;
-+			nf_d = (le32_to_cpu(acnt_rx->rx_info.nf_c_d) >>
-+				RXINFO_NF_D_SHIFT) & RXINFO_NF_D_MASK;
-+			if ((nf_a >= 2048) && (nf_b >= 2048) &&
-+			    (nf_c >= 2048) && (nf_d >= 2048)) {
-+				nf_a = ((4096 - nf_a) >> 4);
-+				nf_b = ((4096 - nf_b) >> 4);
-+				nf_c = ((4096 - nf_c) >> 4);
-+				nf_d = ((4096 - nf_d) >> 4);
-+				priv->noise =
-+					-((nf_a + nf_b + nf_c + nf_d) / 4);
-+			}
-+			dma_data = (struct pcie_dma_data *)
-+				&acnt_rx->rx_info.hdr[0];
-+			sta_info = utils_find_sta(priv, dma_data->wh.addr2);
-+			if (sta_info) {
-+				spin_lock_bh(&priv->sta_lock);
-+				pcie_rx_account(priv, sta_info, acnt_rx);
-+				spin_unlock_bh(&priv->sta_lock);
-+			}
-+			break;
-+		case ACNT_CODE_RA_STATS:
-+			acnt_ra = (struct acnt_ra_s *)pstart;
-+			stnid = le16_to_cpu(acnt_ra->stn_id);
-+			if ((stnid > 0) && (stnid <= priv->stnid_num)) {
-+				type = acnt_ra->type;
-+				if (type < 2) {
-+					if (acnt_ra->tx_attempt_cnt >= 250)
-+						priv->ra_tx_attempt[type][5]++;
-+					else if (acnt_ra->tx_attempt_cnt >= 100)
-+						priv->ra_tx_attempt[type][4]++;
-+					else if (acnt_ra->tx_attempt_cnt >= 50)
-+						priv->ra_tx_attempt[type][3]++;
-+					else if (acnt_ra->tx_attempt_cnt >= 15)
-+						priv->ra_tx_attempt[type][2]++;
-+					else if (acnt_ra->tx_attempt_cnt >= 4)
-+						priv->ra_tx_attempt[type][1]++;
-+					else
-+						priv->ra_tx_attempt[type][0]++;
-+				}
-+				sta_info = utils_find_sta_by_id(priv, stnid);
-+				if (sta_info) {
-+					spin_lock_bh(&priv->sta_lock);
-+					pcie_tx_per(priv, sta_info, acnt_ra);
-+					spin_unlock_bh(&priv->sta_lock);
-+				}
-+			}
-+			break;
-+		case ACNT_CODE_BA_STATS:
-+			acnt_ba = (struct acnt_ba_s *)pstart;
-+			if (priv->ba_aid) {
-+				sta_info = utils_find_sta_by_aid(priv,
-+								 priv->ba_aid);
-+				if (sta_info) {
-+					spin_lock_bh(&priv->sta_lock);
-+					pcie_ba_account(priv, sta_info,
-+							acnt_ba);
-+					spin_unlock_bh(&priv->sta_lock);
-+				}
-+			}
-+			break;
-+		case ACNT_CODE_BF_MIMO_CTRL:
-+			acnt_bf_mimo_ctrl =
-+				(struct acnt_bf_mimo_ctrl_s *)pstart;
-+			pcie_bf_mimo_ctrl_decode(priv, acnt_bf_mimo_ctrl);
-+			break;
-+		default:
-+			break;
-+		}
-+
-+		if (acnt->len)
-+			pstart += acnt->len * 4;
-+		else
-+			goto process_next;
-+	}
-+process_next:
-+	acnt_tail = acnt_head;
-+	writel(acnt_tail, pcie_priv->iobase1 + MACREG_REG_ACNTTAIL);
-+}
-+
-+static int pcie_mcast_cts(struct ieee80211_hw *hw, bool enable)
-+{
-+	return mwl_fwcmd_mcast_cts(hw, enable ? 1 : 0);
-+}
-+
-+static const struct mwl_hif_ops pcie_hif_ops_ndp = {
-+	.driver_name           = PCIE_DRV_NAME,
-+	.driver_version        = PCIE_DRV_VERSION,
-+	.tx_head_room          = PCIE_MIN_BYTES_HEADROOM,
-+	.ampdu_num             = AMPDU_QUEUES_NDP,
-+	.reset                 = pcie_reset,
-+	.init                  = pcie_init_ndp,
-+	.deinit                = pcie_deinit_ndp,
-+	.get_info              = pcie_get_info_ndp,
-+	.get_tx_status         = pcie_get_tx_status_ndp,
-+	.get_rx_status         = pcie_get_rx_status_ndp,
-+	.enable_data_tasks     = pcie_enable_data_tasks_ndp,
-+	.disable_data_tasks    = pcie_disable_data_tasks_ndp,
-+	.exec_cmd              = pcie_exec_cmd,
-+	.get_irq_num           = pcie_get_irq_num,
-+	.irq_handler           = pcie_isr_ndp,
-+	.irq_enable            = pcie_irq_enable_ndp,
-+	.irq_disable           = pcie_irq_disable,
-+	.download_firmware     = pcie_download_firmware,
-+	.timer_routine         = pcie_timer_routine_ndp,
-+	.tx_xmit               = pcie_tx_xmit_ndp,
-+	.tx_return_pkts        = pcie_tx_return_pkts_ndp,
-+	.get_device_node       = pcie_get_device_node,
-+	.get_survey            = pcie_get_survey,
-+	.reg_access            = pcie_reg_access,
-+	.set_sta_id            = pcie_set_sta_id,
-+	.process_account       = pcie_process_account,
-+	.mcast_cts             = pcie_mcast_cts,
-+};
-+
-+static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-+{
-+	static bool printed_version;
-+	struct ieee80211_hw *hw;
-+	struct mwl_priv *priv;
-+	struct pcie_priv *pcie_priv;
-+	const struct mwl_hif_ops *hif_ops;
-+	int rc = 0;
-+
-+	if (id->driver_data >= MWLUNKNOWN)
-+		return -ENODEV;
-+
-+	if (!printed_version) {
-+		pr_info("<<%s version %s>>\n",
-+			PCIE_DRV_DESC, PCIE_DRV_VERSION);
-+		printed_version = true;
-+	}
-+
-+	rc = pci_enable_device(pdev);
-+	if (rc) {
-+		pr_err("%s: cannot enable new PCI device\n",
-+		       PCIE_DRV_NAME);
-+		return rc;
-+	}
-+
-+	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-+	if (rc) {
-+		pr_err("%s: 32-bit PCI DMA not supported\n",
-+		       PCIE_DRV_NAME);
-+		goto err_pci_disable_device;
-+	}
-+
-+	pci_set_master(pdev);
-+
-+	if (id->driver_data == MWL8964)
-+		hif_ops = &pcie_hif_ops_ndp;
-+	else
-+		hif_ops = &pcie_hif_ops;
-+	hw = mwl_alloc_hw(MWL_BUS_PCIE, id->driver_data, &pdev->dev,
-+			  hif_ops, sizeof(*pcie_priv));
-+	if (!hw) {
-+		pr_err("%s: mwlwifi hw alloc failed\n",
-+		       PCIE_DRV_NAME);
-+		rc = -ENOMEM;
-+		goto err_pci_disable_device;
-+	}
-+
-+	pci_set_drvdata(pdev, hw);
-+
-+	priv = hw->priv;
-+	priv->antenna_tx = pcie_chip_tbl[priv->chip_type].antenna_tx;
-+	priv->antenna_rx = pcie_chip_tbl[priv->chip_type].antenna_rx;
-+	pcie_priv = priv->hif.priv;
-+	pcie_priv->mwl_priv = priv;
-+	pcie_priv->pdev = pdev;
-+	if (id->driver_data != MWL8964) {
-+		pcie_priv->tx_head_room = PCIE_MIN_BYTES_HEADROOM;
-+		if (id->driver_data == MWL8997) {
-+			if (NET_SKB_PAD < PCIE_MIN_TX_HEADROOM_KF2) {
-+				pcie_priv->tx_head_room =
-+					PCIE_MIN_TX_HEADROOM_KF2;
-+				pcie_hif_ops.tx_head_room =
-+					PCIE_MIN_TX_HEADROOM_KF2;
-+			}
-+		}
-+	}
-+
-+	rc = pcie_alloc_resource(pcie_priv);
-+	if (rc)
-+		goto err_alloc_pci_resource;
-+
-+	rc = mwl_init_hw(hw, pcie_chip_tbl[priv->chip_type].fw_image,
-+			 pcie_chip_tbl[priv->chip_type].cal_file,
-+			 pcie_chip_tbl[priv->chip_type].txpwrlmt_file);
-+	if (rc)
-+		goto err_wl_init;
-+
-+	vendor_cmd_basic_event(hw->wiphy, MWL_VENDOR_EVENT_DRIVER_READY);
-+
-+	return rc;
-+
-+err_wl_init:
-+
-+	pcie_reset(hw);
-+
-+err_alloc_pci_resource:
-+
-+	pci_set_drvdata(pdev, NULL);
-+	mwl_free_hw(hw);
-+
-+err_pci_disable_device:
-+
-+	pci_disable_device(pdev);
-+
-+	return rc;
-+}
-+
-+static void pcie_remove(struct pci_dev *pdev)
-+{
-+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-+	struct mwl_priv *priv = hw->priv;
-+
-+	priv->rmmod = true;
-+	while (priv->in_send_cmd)
-+		usleep_range(1000, 2000);
-+	vendor_cmd_basic_event(hw->wiphy, MWL_VENDOR_EVENT_DRIVER_START_REMOVE);
-+	mwl_deinit_hw(hw);
-+	pci_set_drvdata(pdev, NULL);
-+	mwl_free_hw(hw);
-+	pci_disable_device(pdev);
-+}
-+
-+static struct pci_driver mwl_pcie_driver = {
-+	.name     = PCIE_DRV_NAME,
-+	.id_table = pcie_id_tbl,
-+	.probe    = pcie_probe,
-+	.remove   = pcie_remove
-+};
-+
-+module_pci_driver(mwl_pcie_driver);
-+
-+MODULE_DESCRIPTION(PCIE_DRV_DESC);
-+MODULE_VERSION(PCIE_DRV_VERSION);
-+MODULE_AUTHOR("Marvell Semiconductor, Inc.");
-+MODULE_LICENSE("GPL v2");
-+MODULE_SUPPORTED_DEVICE(PCIE_DEV_NAME);
-+MODULE_DEVICE_TABLE(pci, pcie_id_tbl);
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.c b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.c
-new file mode 100644
-index 000000000000..25076c6d66df
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.c
-@@ -0,0 +1,540 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements receive related functions. */
-+
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/pcie/dev.h"
-+#include "hif/pcie/rx.h"
-+
-+#define MAX_NUM_RX_RING_BYTES  (PCIE_MAX_NUM_RX_DESC * \
-+				sizeof(struct pcie_rx_desc))
-+
-+#define MAX_NUM_RX_HNDL_BYTES  (PCIE_MAX_NUM_RX_DESC * \
-+				sizeof(struct pcie_rx_hndl))
-+
-+#define DECRYPT_ERR_MASK        0x80
-+#define GENERAL_DECRYPT_ERR     0xFF
-+#define TKIP_DECRYPT_MIC_ERR    0x02
-+#define WEP_DECRYPT_ICV_ERR     0x04
-+#define TKIP_DECRYPT_ICV_ERR    0x08
-+
-+#define W836X_RSSI_OFFSET       8
-+
-+static int pcie_rx_ring_alloc(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+
-+	desc = &pcie_priv->desc_data[0];
-+
-+	desc->prx_ring = (struct pcie_rx_desc *)
-+		dma_alloc_coherent(priv->dev,
-+				   MAX_NUM_RX_RING_BYTES,
-+				   &desc->pphys_rx_ring,
-+				   GFP_KERNEL);
-+
-+	if (!desc->prx_ring) {
-+		wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
-+		return -ENOMEM;
-+	}
-+
-+	memset(desc->prx_ring, 0x00, MAX_NUM_RX_RING_BYTES);
-+
-+	desc->rx_hndl = kzalloc(MAX_NUM_RX_HNDL_BYTES, GFP_KERNEL);
-+
-+	if (!desc->rx_hndl) {
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_RX_RING_BYTES,
-+				  desc->prx_ring,
-+				  desc->pphys_rx_ring);
-+		return -ENOMEM;
-+	}
-+
-+	return 0;
-+}
-+
-+static int pcie_rx_ring_init(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+	int i;
-+	struct pcie_rx_hndl *rx_hndl;
-+	dma_addr_t dma;
-+	u32 val;
-+
-+	desc = &pcie_priv->desc_data[0];
-+
-+	if (desc->prx_ring) {
-+		desc->rx_buf_size = SYSADPT_MAX_AGGR_SIZE;
-+
-+		for (i = 0; i < PCIE_MAX_NUM_RX_DESC; i++) {
-+			rx_hndl = &desc->rx_hndl[i];
-+			rx_hndl->psk_buff =
-+				dev_alloc_skb(desc->rx_buf_size);
-+
-+			if (!rx_hndl->psk_buff) {
-+				wiphy_err(priv->hw->wiphy,
-+					  "rxdesc %i: no skbuff available\n",
-+					  i);
-+				return -ENOMEM;
-+			}
-+
-+			skb_reserve(rx_hndl->psk_buff,
-+				    PCIE_MIN_BYTES_HEADROOM);
-+			desc->prx_ring[i].rx_control =
-+				EAGLE_RXD_CTRL_DRIVER_OWN;
-+			desc->prx_ring[i].status = EAGLE_RXD_STATUS_OK;
-+			desc->prx_ring[i].qos_ctrl = 0x0000;
-+			desc->prx_ring[i].channel = 0x00;
-+			desc->prx_ring[i].rssi = 0x00;
-+			desc->prx_ring[i].pkt_len =
-+				cpu_to_le16(SYSADPT_MAX_AGGR_SIZE);
-+			dma = pci_map_single(pcie_priv->pdev,
-+					     rx_hndl->psk_buff->data,
-+					     desc->rx_buf_size,
-+					     PCI_DMA_FROMDEVICE);
-+			if (pci_dma_mapping_error(pcie_priv->pdev, dma)) {
-+				wiphy_err(priv->hw->wiphy,
-+					  "failed to map pci memory!\n");
-+				return -ENOMEM;
-+			}
-+			desc->prx_ring[i].pphys_buff_data = cpu_to_le32(dma);
-+			val = (u32)desc->pphys_rx_ring +
-+			      ((i + 1) * sizeof(struct pcie_rx_desc));
-+			desc->prx_ring[i].pphys_next = cpu_to_le32(val);
-+			rx_hndl->pdesc = &desc->prx_ring[i];
-+			if (i < (PCIE_MAX_NUM_RX_DESC - 1))
-+				rx_hndl->pnext = &desc->rx_hndl[i + 1];
-+		}
-+		desc->prx_ring[PCIE_MAX_NUM_RX_DESC - 1].pphys_next =
-+			cpu_to_le32((u32)desc->pphys_rx_ring);
-+		desc->rx_hndl[PCIE_MAX_NUM_RX_DESC - 1].pnext =
-+			&desc->rx_hndl[0];
-+		desc->pnext_rx_hndl = &desc->rx_hndl[0];
-+
-+		return 0;
-+	}
-+
-+	wiphy_err(priv->hw->wiphy, "no valid RX mem\n");
-+
-+	return -ENOMEM;
-+}
-+
-+static void pcie_rx_ring_cleanup(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+	int i;
-+	struct pcie_rx_hndl *rx_hndl;
-+
-+	desc = &pcie_priv->desc_data[0];
-+
-+	if (desc->prx_ring) {
-+		for (i = 0; i < PCIE_MAX_NUM_RX_DESC; i++) {
-+			rx_hndl = &desc->rx_hndl[i];
-+			if (!rx_hndl->psk_buff)
-+				continue;
-+
-+			pci_unmap_single(pcie_priv->pdev,
-+					 le32_to_cpu
-+					 (rx_hndl->pdesc->pphys_buff_data),
-+					 desc->rx_buf_size,
-+					 PCI_DMA_FROMDEVICE);
-+
-+			dev_kfree_skb_any(rx_hndl->psk_buff);
-+
-+			wiphy_debug(priv->hw->wiphy,
-+				    "unmapped+free'd %i 0x%p 0x%x %i\n",
-+				    i, rx_hndl->psk_buff->data,
-+				    le32_to_cpu(
-+				    rx_hndl->pdesc->pphys_buff_data),
-+				    desc->rx_buf_size);
-+
-+			rx_hndl->psk_buff = NULL;
-+		}
-+	}
-+}
-+
-+static void pcie_rx_ring_free(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+
-+	desc = &pcie_priv->desc_data[0];
-+
-+	if (desc->prx_ring) {
-+		pcie_rx_ring_cleanup(priv);
-+
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_RX_RING_BYTES,
-+				  desc->prx_ring,
-+				  desc->pphys_rx_ring);
-+
-+		desc->prx_ring = NULL;
-+	}
-+
-+	kfree(desc->rx_hndl);
-+
-+	desc->pnext_rx_hndl = NULL;
-+}
-+
-+static inline void pcie_rx_status(struct mwl_priv *priv,
-+				  struct pcie_rx_desc *pdesc,
-+				  struct ieee80211_rx_status *status)
-+{
-+	u16 rx_rate;
-+
-+	memset(status, 0, sizeof(*status));
-+
-+	if (priv->chip_type == MWL8997)
-+		status->signal = (s8)pdesc->rssi;
-+	else
-+		status->signal = -(pdesc->rssi + W836X_RSSI_OFFSET);
-+
-+	rx_rate = le16_to_cpu(pdesc->rate);
-+	pcie_rx_prepare_status(priv,
-+			       rx_rate & MWL_RX_RATE_FORMAT_MASK,
-+			       (rx_rate & MWL_RX_RATE_NSS_MASK) >>
-+			       MWL_RX_RATE_NSS_SHIFT,
-+			       (rx_rate & MWL_RX_RATE_BW_MASK) >>
-+			       MWL_RX_RATE_BW_SHIFT,
-+			       (rx_rate & MWL_RX_RATE_GI_MASK) >>
-+			       MWL_RX_RATE_GI_SHIFT,
-+			       (rx_rate & MWL_RX_RATE_RT_MASK) >>
-+			       MWL_RX_RATE_RT_SHIFT,
-+			       status);
-+
-+	status->freq = ieee80211_channel_to_frequency(pdesc->channel,
-+						      status->band);
-+
-+	/* check if status has a specific error bit (bit 7) set or indicates
-+	 * a general decrypt error
-+	 */
-+	if ((pdesc->status == GENERAL_DECRYPT_ERR) ||
-+	    (pdesc->status & DECRYPT_ERR_MASK)) {
-+		/* check if status is not equal to 0xFF
-+		 * the 0xFF check is for backward compatibility
-+		 */
-+		if (pdesc->status != GENERAL_DECRYPT_ERR) {
-+			if (((pdesc->status & (~DECRYPT_ERR_MASK)) &
-+			    TKIP_DECRYPT_MIC_ERR) && !((pdesc->status &
-+			    (WEP_DECRYPT_ICV_ERR | TKIP_DECRYPT_ICV_ERR)))) {
-+				status->flag |= RX_FLAG_MMIC_ERROR;
-+			}
-+		}
-+	}
-+}
-+
-+static inline bool pcie_rx_process_mesh_amsdu(struct mwl_priv *priv,
-+					     struct sk_buff *skb,
-+					     struct ieee80211_rx_status *status)
-+{
-+	struct ieee80211_hdr *wh;
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+	u8 *qc;
-+	int wh_len;
-+	int len;
-+	u8 pad;
-+	u8 *data;
-+	u16 frame_len;
-+	struct sk_buff *newskb;
-+
-+	wh = (struct ieee80211_hdr *)skb->data;
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv[0]);
-+		if (ether_addr_equal(sta->addr, wh->addr2)) {
-+			if (!sta_info->is_mesh_node) {
-+				spin_unlock_bh(&priv->sta_lock);
-+				return false;
-+			}
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	qc = ieee80211_get_qos_ctl(wh);
-+	*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
-+
-+	wh_len = ieee80211_hdrlen(wh->frame_control);
-+	len = wh_len;
-+	data = skb->data;
-+
-+	while (len < skb->len) {
-+		frame_len = *(u8 *)(data + len + ETH_HLEN - 1) |
-+			(*(u8 *)(data + len + ETH_HLEN - 2) << 8);
-+
-+		if ((len + ETH_HLEN + frame_len) > skb->len)
-+			break;
-+
-+		newskb = dev_alloc_skb(wh_len + frame_len);
-+		if (!newskb)
-+			break;
-+
-+		ether_addr_copy(wh->addr3, data + len);
-+		ether_addr_copy(wh->addr4, data + len + ETH_ALEN);
-+		memcpy(newskb->data, wh, wh_len);
-+		memcpy(newskb->data + wh_len, data + len + ETH_HLEN, frame_len);
-+		skb_put(newskb, wh_len + frame_len);
-+
-+		pad = ((ETH_HLEN + frame_len) % 4) ?
-+			(4 - (ETH_HLEN + frame_len) % 4) : 0;
-+		len += (ETH_HLEN + frame_len + pad);
-+		if (len < skb->len)
-+			status->flag |= RX_FLAG_AMSDU_MORE;
-+		else
-+			status->flag &= ~RX_FLAG_AMSDU_MORE;
-+		memcpy(IEEE80211_SKB_RXCB(newskb), status, sizeof(*status));
-+		ieee80211_rx(priv->hw, newskb);
-+	}
-+
-+	dev_kfree_skb_any(skb);
-+
-+	return true;
-+}
-+
-+static inline int pcie_rx_refill(struct mwl_priv *priv,
-+				 struct pcie_rx_hndl *rx_hndl)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+	dma_addr_t dma;
-+
-+	desc = &pcie_priv->desc_data[0];
-+
-+	rx_hndl->psk_buff = dev_alloc_skb(desc->rx_buf_size);
-+
-+	if (!rx_hndl->psk_buff)
-+		return -ENOMEM;
-+
-+	skb_reserve(rx_hndl->psk_buff, PCIE_MIN_BYTES_HEADROOM);
-+
-+	rx_hndl->pdesc->status = EAGLE_RXD_STATUS_OK;
-+	rx_hndl->pdesc->qos_ctrl = 0x0000;
-+	rx_hndl->pdesc->channel = 0x00;
-+	rx_hndl->pdesc->rssi = 0x00;
-+	rx_hndl->pdesc->pkt_len = cpu_to_le16(desc->rx_buf_size);
-+
-+	dma = pci_map_single(pcie_priv->pdev,
-+			     rx_hndl->psk_buff->data,
-+			     desc->rx_buf_size,
-+			     PCI_DMA_FROMDEVICE);
-+	if (pci_dma_mapping_error(pcie_priv->pdev, dma)) {
-+		dev_kfree_skb_any(rx_hndl->psk_buff);
-+		wiphy_err(priv->hw->wiphy,
-+			  "failed to map pci memory!\n");
-+		return -ENOMEM;
-+	}
-+
-+	rx_hndl->pdesc->pphys_buff_data = cpu_to_le32(dma);
-+
-+	return 0;
-+}
-+
-+int pcie_rx_init(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc;
-+
-+	rc = pcie_rx_ring_alloc(priv);
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "allocating RX ring failed\n");
-+		return rc;
-+	}
-+
-+	rc = pcie_rx_ring_init(priv);
-+	if (rc) {
-+		pcie_rx_ring_free(priv);
-+		wiphy_err(hw->wiphy,
-+			  "initializing RX ring failed\n");
-+		return rc;
-+	}
-+
-+	return 0;
-+}
-+
-+void pcie_rx_deinit(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	pcie_rx_ring_cleanup(priv);
-+	pcie_rx_ring_free(priv);
-+}
-+
-+void pcie_rx_recv(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+	struct pcie_rx_hndl *curr_hndl;
-+	int work_done = 0;
-+	struct sk_buff *prx_skb = NULL;
-+	int pkt_len;
-+	struct ieee80211_rx_status *status;
-+	struct mwl_vif *mwl_vif = NULL;
-+	struct ieee80211_hdr *wh;
-+
-+	desc = &pcie_priv->desc_data[0];
-+	curr_hndl = desc->pnext_rx_hndl;
-+
-+	if (!curr_hndl) {
-+		pcie_mask_int(pcie_priv, MACREG_A2HRIC_BIT_RX_RDY, true);
-+		pcie_priv->is_rx_schedule = false;
-+		wiphy_warn(hw->wiphy, "busy or no receiving packets\n");
-+		return;
-+	}
-+
-+	while ((curr_hndl->pdesc->rx_control == EAGLE_RXD_CTRL_DMA_OWN) &&
-+	       (work_done < pcie_priv->recv_limit)) {
-+		prx_skb = curr_hndl->psk_buff;
-+		if (!prx_skb)
-+			goto out;
-+		pci_unmap_single(pcie_priv->pdev,
-+				 le32_to_cpu(curr_hndl->pdesc->pphys_buff_data),
-+				 desc->rx_buf_size,
-+				 PCI_DMA_FROMDEVICE);
-+		pkt_len = le16_to_cpu(curr_hndl->pdesc->pkt_len);
-+
-+		if (skb_tailroom(prx_skb) < pkt_len) {
-+			dev_kfree_skb_any(prx_skb);
-+			goto out;
-+		}
-+
-+		if (curr_hndl->pdesc->channel !=
-+		    hw->conf.chandef.chan->hw_value) {
-+			dev_kfree_skb_any(prx_skb);
-+			goto out;
-+		}
-+
-+		status = IEEE80211_SKB_RXCB(prx_skb);
-+		pcie_rx_status(priv, curr_hndl->pdesc, status);
-+
-+		if (priv->chip_type == MWL8997) {
-+			priv->noise = (s8)curr_hndl->pdesc->noise_floor;
-+			if (priv->noise > 0)
-+				priv->noise = -priv->noise;
-+		} else
-+			priv->noise = -curr_hndl->pdesc->noise_floor;
-+
-+		wh = &((struct pcie_dma_data *)prx_skb->data)->wh;
-+
-+		if (ieee80211_has_protected(wh->frame_control)) {
-+			/* Check if hw crypto has been enabled for
-+			 * this bss. If yes, set the status flags
-+			 * accordingly
-+			 */
-+			if (ieee80211_has_tods(wh->frame_control)) {
-+				mwl_vif = utils_find_vif_bss(priv, wh->addr1);
-+				if (!mwl_vif &&
-+				    ieee80211_has_a4(wh->frame_control))
-+					mwl_vif =
-+						utils_find_vif_bss(priv,
-+								   wh->addr2);
-+			} else {
-+				mwl_vif = utils_find_vif_bss(priv, wh->addr2);
-+			}
-+
-+			if  ((mwl_vif && mwl_vif->is_hw_crypto_enabled) ||
-+			     is_multicast_ether_addr(wh->addr1) ||
-+			     (ieee80211_is_mgmt(wh->frame_control) &&
-+			     !is_multicast_ether_addr(wh->addr1))) {
-+				/* When MMIC ERROR is encountered
-+				 * by the firmware, payload is
-+				 * dropped and only 32 bytes of
-+				 * mwlwifi Firmware header is sent
-+				 * to the host.
-+				 *
-+				 * We need to add four bytes of
-+				 * key information.  In it
-+				 * MAC80211 expects keyidx set to
-+				 * 0 for triggering Counter
-+				 * Measure of MMIC failure.
-+				 */
-+				if (status->flag & RX_FLAG_MMIC_ERROR) {
-+					struct pcie_dma_data *dma_data;
-+
-+					dma_data = (struct pcie_dma_data *)
-+					     prx_skb->data;
-+					memset((void *)&dma_data->data, 0, 4);
-+					pkt_len += 4;
-+				}
-+
-+				if (!ieee80211_is_auth(wh->frame_control)) {
-+					if (priv->chip_type != MWL8997)
-+						status->flag |=
-+							RX_FLAG_IV_STRIPPED |
-+							RX_FLAG_DECRYPTED |
-+							RX_FLAG_MMIC_STRIPPED;
-+					else
-+						status->flag |=
-+							RX_FLAG_DECRYPTED |
-+							RX_FLAG_MMIC_STRIPPED;
-+				}
-+			}
-+		}
-+
-+		skb_put(prx_skb, pkt_len);
-+		pcie_rx_remove_dma_header(prx_skb, curr_hndl->pdesc->qos_ctrl);
-+
-+		wh = (struct ieee80211_hdr *)prx_skb->data;
-+
-+		if (ieee80211_is_data_qos(wh->frame_control)) {
-+			const u8 eapol[] = {0x88, 0x8e};
-+			u8 *qc = ieee80211_get_qos_ctl(wh);
-+			u8 *data;
-+
-+			data = prx_skb->data +
-+				ieee80211_hdrlen(wh->frame_control) + 6;
-+
-+			if (!memcmp(data, eapol, sizeof(eapol)))
-+				*qc |= 7;
-+		}
-+
-+		if (ieee80211_is_data_qos(wh->frame_control) &&
-+		    ieee80211_has_a4(wh->frame_control)) {
-+			u8 *qc = ieee80211_get_qos_ctl(wh);
-+
-+			if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
-+				if (pcie_rx_process_mesh_amsdu(priv, prx_skb,
-+							      status))
-+					goto out;
-+		}
-+
-+		if (ieee80211_is_probe_req(wh->frame_control) &&
-+		    priv->dump_probe)
-+			wiphy_info(hw->wiphy, "Probe Req: %pM\n", wh->addr2);
-+
-+		ieee80211_rx(hw, prx_skb);
-+out:
-+		pcie_rx_refill(priv, curr_hndl);
-+		curr_hndl->pdesc->rx_control = EAGLE_RXD_CTRL_DRIVER_OWN;
-+		curr_hndl->pdesc->qos_ctrl = 0;
-+		curr_hndl = curr_hndl->pnext;
-+		work_done++;
-+	}
-+
-+	desc->pnext_rx_hndl = curr_hndl;
-+	pcie_mask_int(pcie_priv, MACREG_A2HRIC_BIT_RX_RDY, true);
-+	pcie_priv->is_rx_schedule = false;
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.h
-new file mode 100644
-index 000000000000..d2b580fceb0a
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx.h
-@@ -0,0 +1,25 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines receive related functions. */
-+
-+#ifndef _RX_H_
-+#define _RX_H_
-+
-+int pcie_rx_init(struct ieee80211_hw *hw);
-+void pcie_rx_deinit(struct ieee80211_hw *hw);
-+void pcie_rx_recv(unsigned long data);
-+
-+#endif /* _RX_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.c b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.c
-new file mode 100644
-index 000000000000..d1ede588b4c1
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.c
-@@ -0,0 +1,612 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements receive related functions for new data
-+ * path.
-+ */
-+
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/pcie/dev.h"
-+#include "hif/pcie/rx_ndp.h"
-+
-+#define MAX_NUM_RX_RING_BYTES   (MAX_NUM_RX_DESC * \
-+				sizeof(struct pcie_rx_desc_ndp))
-+#define MAX_NUM_RX_RING_DONE_BYTES (MAX_NUM_RX_DESC * \
-+				sizeof(struct rx_ring_done))
-+
-+static int pcie_rx_ring_alloc_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+
-+	desc->prx_ring = (struct pcie_rx_desc_ndp *)
-+		dma_alloc_coherent(priv->dev,
-+				   MAX_NUM_RX_RING_BYTES,
-+				   &desc->pphys_rx_ring,
-+				   GFP_KERNEL);
-+	if (!desc->prx_ring)
-+		goto err_no_mem;
-+	memset(desc->prx_ring, 0x00, MAX_NUM_RX_RING_BYTES);
-+
-+	desc->prx_ring_done = (struct rx_ring_done *)
-+		dma_alloc_coherent(priv->dev,
-+				   MAX_NUM_RX_RING_DONE_BYTES,
-+				   &desc->pphys_rx_ring_done,
-+				   GFP_KERNEL);
-+	if (!desc->prx_ring_done)
-+		goto err_no_mem;
-+	memset(desc->prx_ring_done, 0x00, MAX_NUM_RX_RING_DONE_BYTES);
-+	return 0;
-+
-+err_no_mem:
-+
-+	wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
-+	return -ENOMEM;
-+}
-+
-+static int pcie_rx_ring_init_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	int i;
-+	struct sk_buff *psk_buff;
-+	dma_addr_t dma;
-+
-+	skb_queue_head_init(&pcie_priv->rx_skb_trace);
-+	if (desc->prx_ring) {
-+		desc->rx_buf_size = MAX_AGGR_SIZE;
-+
-+		for (i = 0; i < MAX_NUM_RX_DESC; i++) {
-+			psk_buff = __alloc_skb(desc->rx_buf_size + NET_SKB_PAD,
-+					       GFP_ATOMIC, SKB_ALLOC_RX,
-+					       NUMA_NO_NODE);
-+			skb_reserve(psk_buff, NET_SKB_PAD);
-+			if (!psk_buff) {
-+				wiphy_err(priv->hw->wiphy,
-+					  "rxdesc %i: no skbuff available\n",
-+					  i);
-+				return -ENOMEM;
-+			}
-+			skb_reserve(psk_buff, MIN_BYTES_RX_HEADROOM);
-+
-+			dma = pci_map_single(pcie_priv->pdev,
-+					     psk_buff->data,
-+					     desc->rx_buf_size,
-+					     PCI_DMA_FROMDEVICE);
-+			if (pci_dma_mapping_error(pcie_priv->pdev, dma)) {
-+				wiphy_err(priv->hw->wiphy,
-+					  "failed to map pci memory!\n");
-+				return -ENOMEM;
-+			}
-+
-+			desc->rx_vbuflist[i] = psk_buff;
-+			desc->prx_ring[i].user = cpu_to_le32(i);
-+			desc->prx_ring[i].data = cpu_to_le32(dma);
-+			*((u32 *)&psk_buff->cb[16]) = 0xdeadbeef;
-+			skb_queue_tail(&pcie_priv->rx_skb_trace, psk_buff);
-+		}
-+
-+		writel(1023, pcie_priv->iobase1 + MACREG_REG_RXDESCHEAD);
-+		return 0;
-+	}
-+
-+	wiphy_err(priv->hw->wiphy, "no valid RX mem\n");
-+	return -ENOMEM;
-+}
-+
-+static void pcie_rx_ring_cleanup_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	int i;
-+
-+	if (desc->prx_ring) {
-+		for (i = 0; i < MAX_NUM_RX_DESC; i++) {
-+			if (desc->rx_vbuflist[i]) {
-+				pci_unmap_single(pcie_priv->pdev,
-+						 le32_to_cpu(
-+						 desc->prx_ring[i].data),
-+						 desc->rx_buf_size,
-+						 PCI_DMA_FROMDEVICE);
-+				desc->rx_vbuflist[i] = NULL;
-+			}
-+		}
-+		skb_queue_purge(&pcie_priv->rx_skb_trace);
-+	}
-+}
-+
-+static void pcie_rx_ring_free_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+
-+	if (desc->prx_ring) {
-+		pcie_rx_ring_cleanup_ndp(priv);
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_RX_RING_BYTES,
-+				  desc->prx_ring,
-+				  desc->pphys_rx_ring);
-+		desc->prx_ring = NULL;
-+	}
-+
-+	if (desc->prx_ring_done) {
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_RX_RING_DONE_BYTES,
-+				  desc->prx_ring_done,
-+				  desc->pphys_rx_ring_done);
-+		desc->prx_ring_done = NULL;
-+	}
-+}
-+
-+static inline void pcie_rx_update_ndp_cnts(struct mwl_priv *priv, u32 ctrl)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+
-+	switch (ctrl) {
-+	case RXRING_CASE_DROP:
-+		pcie_priv->rx_cnts.drop_cnt++;
-+		break;
-+	case RXRING_CASE_FAST_BAD_AMSDU:
-+		pcie_priv->rx_cnts.fast_bad_amsdu_cnt++;
-+		break;
-+	case RXRING_CASE_FAST_DATA:
-+		pcie_priv->rx_cnts.fast_data_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_BAD_MIC:
-+		pcie_priv->rx_cnts.slow_bad_mic_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_BAD_PN:
-+		pcie_priv->rx_cnts.slow_bad_pn_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_BAD_STA:
-+		pcie_priv->rx_cnts.slow_bad_sta_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_MCAST:
-+		pcie_priv->rx_cnts.slow_mcast_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_MGMT:
-+		pcie_priv->rx_cnts.slow_mgmt_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_NOQUEUE:
-+		pcie_priv->rx_cnts.slow_noqueue_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_NORUN:
-+		pcie_priv->rx_cnts.slow_norun_cnt++;
-+		break;
-+	case RXRING_CASE_SLOW_PROMISC:
-+		pcie_priv->rx_cnts.slow_promisc_cnt++;
-+		break;
-+	}
-+}
-+
-+static void pcie_rx_status_ndp(struct mwl_priv *priv,
-+			       struct mwl_sta *sta_info,
-+			       struct ieee80211_rx_status *status)
-+{
-+	memset(status, 0, sizeof(*status));
-+	pcie_rx_prepare_status(priv,
-+			       sta_info->rx_format,
-+			       sta_info->rx_nss,
-+			       sta_info->rx_bw,
-+			       sta_info->rx_gi,
-+			       sta_info->rx_rate_mcs,
-+			       status);
-+	status->signal = -sta_info->rx_signal;
-+	status->band = priv->hw->conf.chandef.chan->band;
-+	status->freq = ieee80211_channel_to_frequency(
-+		priv->hw->conf.chandef.chan->hw_value, status->band);
-+}
-+
-+static inline void pcie_rx_process_fast_data(struct mwl_priv *priv,
-+					     struct sk_buff *skb,
-+					     u16 stnid)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct ieee80211_sta *sta;
-+	struct mwl_sta *sta_info;
-+	struct mwl_vif *mwl_vif;
-+	struct ieee80211_hdr hdr;
-+	u16 hdrlen, ethertype;
-+	__le16 fc;
-+	struct ieee80211_rx_status *status;
-+
-+	if (stnid == RXRING_CTRL_STA_FROMDS)
-+		stnid = 0;
-+
-+	if (stnid > SYSADPT_MAX_STA_SC4)
-+		goto drop_packet;
-+
-+	sta = pcie_priv->sta_link[stnid];
-+	if (!sta)
-+		goto drop_packet;
-+
-+	sta_info = mwl_dev_get_sta(sta);
-+	mwl_vif = sta_info->mwl_vif;
-+	if (!mwl_vif)
-+		goto drop_packet;
-+
-+	ethertype = (skb->data[20] << 8) | skb->data[21];
-+	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
-+
-+	memset(&hdr, 0, sizeof(hdr));
-+	switch (mwl_vif->type) {
-+	case NL80211_IFTYPE_AP:
-+		if (sta_info->wds) {
-+			fc |= (cpu_to_le16(IEEE80211_FCTL_TODS) |
-+				cpu_to_le16(IEEE80211_FCTL_FROMDS));
-+			/* RA TA DA SA */
-+			ether_addr_copy(hdr.addr1, mwl_vif->bssid);
-+			ether_addr_copy(hdr.addr2, sta->addr);
-+			ether_addr_copy(hdr.addr3, skb->data);
-+			ether_addr_copy(hdr.addr4, skb->data + ETH_ALEN);
-+			hdrlen = 30;
-+		} else {
-+			fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
-+			/* BSSID SA DA */
-+			ether_addr_copy(hdr.addr1, mwl_vif->bssid);
-+			ether_addr_copy(hdr.addr2, skb->data + ETH_ALEN);
-+			ether_addr_copy(hdr.addr3, skb->data);
-+			hdrlen = 24;
-+		}
-+		break;
-+	case NL80211_IFTYPE_STATION:
-+		if (sta_info->wds) {
-+			fc |= (cpu_to_le16(IEEE80211_FCTL_TODS) |
-+				cpu_to_le16(IEEE80211_FCTL_FROMDS));
-+			/* RA TA DA SA */
-+			ether_addr_copy(hdr.addr1, mwl_vif->sta_mac);
-+			ether_addr_copy(hdr.addr2, mwl_vif->bssid);
-+			ether_addr_copy(hdr.addr3, skb->data);
-+			ether_addr_copy(hdr.addr4, skb->data + ETH_ALEN);
-+			hdrlen = 30;
-+		} else {
-+			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
-+			/* DA BSSID SA */
-+			ether_addr_copy(hdr.addr1, skb->data);
-+			ether_addr_copy(hdr.addr2, mwl_vif->bssid);
-+			ether_addr_copy(hdr.addr3, skb->data + ETH_ALEN);
-+			hdrlen = 24;
-+		}
-+		break;
-+	default:
-+		goto drop_packet;
-+	}
-+
-+	if (sta->wme) {
-+		fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
-+		hdrlen += 2;
-+	}
-+
-+	status = IEEE80211_SKB_RXCB(skb);
-+	pcie_rx_status_ndp(priv, sta_info, status);
-+	if (mwl_vif->is_hw_crypto_enabled) {
-+		fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-+		status->flag |= RX_FLAG_IV_STRIPPED |
-+				RX_FLAG_DECRYPTED |
-+				RX_FLAG_MMIC_STRIPPED;
-+	}
-+
-+	hdr.frame_control = fc;
-+	hdr.duration_id = 0;
-+
-+	skb_pull(skb, ETH_HLEN);
-+
-+	if (ieee80211_is_data_qos(fc)) {
-+		__le16 *qos_control;
-+
-+		qos_control = (__le16 *)skb_push(skb, 2);
-+		memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
-+		if (ethertype == ETH_P_PAE)
-+			*qos_control = cpu_to_le16(
-+				IEEE80211_QOS_CTL_ACK_POLICY_NOACK | 7);
-+		else
-+			*qos_control = cpu_to_le16(
-+				IEEE80211_QOS_CTL_ACK_POLICY_NOACK);
-+	} else
-+		memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
-+
-+	status->flag |= RX_FLAG_DUP_VALIDATED;
-+	ieee80211_rx(priv->hw, skb);
-+
-+	return;
-+drop_packet:
-+
-+	dev_kfree_skb_any(skb);
-+}
-+
-+static inline void pcie_rx_process_slow_data(struct mwl_priv *priv,
-+					     struct sk_buff *skb,
-+					     bool bad_mic, u8 signal)
-+{
-+	struct ieee80211_rx_status *status;
-+	struct ieee80211_hdr *wh;
-+	struct mwl_vif *mwl_vif = NULL;
-+
-+	pcie_rx_remove_dma_header(skb, 0);
-+	status = IEEE80211_SKB_RXCB(skb);
-+	memset(status, 0, sizeof(*status));
-+	status->signal = -signal;
-+	status->band = priv->hw->conf.chandef.chan->band;
-+	status->freq = ieee80211_channel_to_frequency(
-+		priv->hw->conf.chandef.chan->hw_value, status->band);
-+
-+	if (bad_mic)
-+		status->flag |= RX_FLAG_MMIC_ERROR;
-+	else {
-+		wh = (struct ieee80211_hdr *)skb->data;
-+
-+		if (ieee80211_has_protected(wh->frame_control)) {
-+			if (ieee80211_has_tods(wh->frame_control)) {
-+				mwl_vif = utils_find_vif_bss(priv, wh->addr1);
-+				if (!mwl_vif &&
-+				    ieee80211_has_a4(wh->frame_control))
-+					mwl_vif =
-+						utils_find_vif_bss(priv,
-+								   wh->addr2);
-+			} else {
-+				mwl_vif = utils_find_vif_bss(priv, wh->addr2);
-+			}
-+
-+			if ((mwl_vif && mwl_vif->is_hw_crypto_enabled) ||
-+			    is_multicast_ether_addr(wh->addr1) ||
-+			    (ieee80211_is_mgmt(wh->frame_control) &&
-+			    !is_multicast_ether_addr(wh->addr1))) {
-+				if (!ieee80211_is_auth(wh->frame_control))
-+					status->flag |= RX_FLAG_IV_STRIPPED |
-+							RX_FLAG_DECRYPTED |
-+							RX_FLAG_MMIC_STRIPPED;
-+			}
-+		}
-+
-+		if (ieee80211_has_a4(wh->frame_control) && !priv->wds_check) {
-+			ether_addr_copy(priv->wds_check_sta, wh->addr2);
-+			ieee80211_queue_work(priv->hw, &priv->wds_check_handle);
-+			priv->wds_check = true;
-+		}
-+	}
-+
-+	status->flag |= RX_FLAG_DUP_VALIDATED;
-+	ieee80211_rx(priv->hw, skb);
-+}
-+
-+static inline int pcie_rx_refill_ndp(struct mwl_priv *priv, u32 buf_idx)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	struct sk_buff *psk_buff;
-+	dma_addr_t dma;
-+
-+	psk_buff = __alloc_skb(desc->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC,
-+			       SKB_ALLOC_RX, NUMA_NO_NODE);
-+	skb_reserve(psk_buff, NET_SKB_PAD);
-+	if (!psk_buff)
-+		return -ENOMEM;
-+	skb_reserve(psk_buff, MIN_BYTES_RX_HEADROOM);
-+
-+	dma = pci_map_single(pcie_priv->pdev,
-+			     psk_buff->data,
-+			     desc->rx_buf_size,
-+			     PCI_DMA_FROMDEVICE);
-+	if (pci_dma_mapping_error(pcie_priv->pdev, dma)) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "refill: failed to map pci memory!\n");
-+		return -ENOMEM;
-+	}
-+
-+	desc->rx_vbuflist[buf_idx] = psk_buff;
-+	desc->prx_ring[buf_idx].data = cpu_to_le32(dma);
-+	*((u32 *)&psk_buff->cb[16]) = 0xdeadbeef;
-+	skb_queue_tail(&pcie_priv->rx_skb_trace, psk_buff);
-+
-+	return 0;
-+}
-+
-+int pcie_rx_init_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc;
-+
-+	rc = pcie_rx_ring_alloc_ndp(priv);
-+	if (rc) {
-+		pcie_rx_ring_free_ndp(priv);
-+		wiphy_err(hw->wiphy, "allocating RX ring failed\n");
-+		return rc;
-+	}
-+
-+	rc = pcie_rx_ring_init_ndp(priv);
-+	if (rc) {
-+		pcie_rx_ring_free_ndp(priv);
-+		wiphy_err(hw->wiphy,
-+			  "initializing RX ring failed\n");
-+		return rc;
-+	}
-+
-+	return 0;
-+}
-+
-+void pcie_rx_deinit_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	pcie_rx_ring_cleanup_ndp(priv);
-+	pcie_rx_ring_free_ndp(priv);
-+}
-+
-+void pcie_rx_recv_ndp(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	struct rx_ring_done *prx_ring_done;
-+	struct pcie_rx_desc_ndp *prx_desc;
-+	u32 rx_done_head;
-+	u32 rx_done_tail;
-+	u32 rx_desc_head;
-+	struct sk_buff *psk_buff;
-+	u32 buf_idx;
-+	u32 rx_cnt;
-+	u32 ctrl, ctrl_case;
-+	bool bad_mic;
-+	u16 stnid;
-+	u16 pktlen;
-+	struct rx_info *rx_info;
-+	struct pcie_dma_data *dma_data;
-+	u8 signal;
-+
-+	rx_done_head = readl(pcie_priv->iobase1 + MACREG_REG_RXDONEHEAD);
-+	rx_done_tail = readl(pcie_priv->iobase1 + MACREG_REG_RXDONETAIL);
-+	rx_desc_head = readl(pcie_priv->iobase1 + MACREG_REG_RXDESCHEAD);
-+	rx_cnt = 0;
-+
-+	while ((rx_done_tail != rx_done_head) &&
-+	       (rx_cnt < pcie_priv->recv_limit)) {
-+recheck:
-+		prx_ring_done = &desc->prx_ring_done[rx_done_tail];
-+		wmb(); /*Data Memory Barrier*/
-+		if (le32_to_cpu(prx_ring_done->user) == 0xdeadbeef) {
-+			pcie_priv->recheck_rxringdone++;
-+			udelay(1);
-+			goto recheck;
-+		}
-+		buf_idx = le32_to_cpu(prx_ring_done->user) & 0x3fff;
-+		prx_ring_done->user = cpu_to_le32(0xdeadbeef);
-+		rx_done_tail++;
-+		prx_desc = &desc->prx_ring[buf_idx];
-+		if (!prx_desc->data)
-+			wiphy_err(hw->wiphy, "RX desc data is NULL\n");
-+		psk_buff = desc->rx_vbuflist[buf_idx];
-+		if (!psk_buff) {
-+			wiphy_err(hw->wiphy, "RX socket buffer is NULL\n");
-+			goto out;
-+		}
-+		if (*((u32 *)&psk_buff->cb[16]) != 0xdeadbeef) {
-+			pcie_priv->signature_err++;
-+			break;
-+		}
-+		if (psk_buff->next && psk_buff->prev) {
-+			skb_unlink(psk_buff, &pcie_priv->rx_skb_trace);
-+			*((u32 *)&psk_buff->cb[16]) = 0xbeefdead;
-+		} else {
-+			pcie_priv->rx_skb_unlink_err++;
-+			break;
-+		}
-+
-+		pci_unmap_single(pcie_priv->pdev,
-+				 le32_to_cpu(prx_desc->data),
-+				 desc->rx_buf_size,
-+				 PCI_DMA_FROMDEVICE);
-+
-+		bad_mic = false;
-+		ctrl = le32_to_cpu(prx_ring_done->ctrl);
-+		ctrl_case = ctrl & RXRING_CTRL_CASE_MASK;
-+		stnid = (ctrl >> RXRING_CTRL_STA_SHIFT) & RXRING_CTRL_STA_MASK;
-+		pcie_rx_update_ndp_cnts(priv, ctrl_case);
-+
-+		switch (ctrl_case) {
-+		case RXRING_CASE_FAST_DATA:
-+			if (stnid == RXRING_CTRL_STA_UNKNOWN) {
-+				dev_kfree_skb_any(psk_buff);
-+				break;
-+			}
-+			pktlen = psk_buff->data[12] << 8 | psk_buff->data[13];
-+			pktlen += ETH_HLEN;
-+
-+			if (skb_tailroom(psk_buff) >= pktlen) {
-+				skb_put(psk_buff, pktlen);
-+				pcie_rx_process_fast_data(priv, psk_buff,
-+							  stnid);
-+			} else {
-+				wiphy_err(hw->wiphy,
-+					  "fast: space %d(%d) is not enough\n",
-+					  skb_tailroom(psk_buff), pktlen);
-+				dev_kfree_skb_any(psk_buff);
-+			}
-+			break;
-+		case RXRING_CASE_FAST_BAD_AMSDU:
-+		case RXRING_CASE_SLOW_BAD_STA:
-+		case RXRING_CASE_SLOW_DEL_DONE:
-+		case RXRING_CASE_DROP:
-+		case RXRING_CASE_SLOW_BAD_PN:
-+			if (ctrl_case == RXRING_CASE_SLOW_DEL_DONE) {
-+				wiphy_debug(hw->wiphy,
-+					    "staid %d deleted\n",
-+					    stnid);
-+				utils_free_stnid(priv, stnid);
-+			}
-+			dev_kfree_skb_any(psk_buff);
-+			break;
-+		case RXRING_CASE_SLOW_BAD_MIC:
-+			bad_mic = true;
-+		case RXRING_CASE_SLOW_NOQUEUE:
-+		case RXRING_CASE_SLOW_NORUN:
-+		case RXRING_CASE_SLOW_MGMT:
-+		case RXRING_CASE_SLOW_MCAST:
-+		case RXRING_CASE_SLOW_PROMISC:
-+			rx_info = (struct rx_info *)psk_buff->data;
-+			dma_data = (struct pcie_dma_data *)&rx_info->hdr[0];
-+			pktlen = le16_to_cpu(dma_data->fwlen);
-+			pktlen += sizeof(*rx_info);
-+			pktlen += sizeof(struct pcie_dma_data);
-+			if (bad_mic) {
-+				memset((void *)&dma_data->data, 0, 4);
-+				pktlen += 4;
-+			}
-+			if (skb_tailroom(psk_buff) >= pktlen) {
-+				skb_put(psk_buff, pktlen);
-+				skb_pull(psk_buff, sizeof(*rx_info));
-+				signal = ((le32_to_cpu(rx_info->rssi_x) >>
-+					RXINFO_RSSI_X_SHIFT) &
-+					RXINFO_RSSI_X_MASK);
-+				pcie_rx_process_slow_data(priv, psk_buff,
-+							  bad_mic, signal);
-+			} else {
-+				wiphy_err(hw->wiphy,
-+					  "slow: space %d(%d) is not enough\n",
-+					  skb_tailroom(psk_buff), pktlen);
-+				dev_kfree_skb_any(psk_buff);
-+			}
-+			break;
-+		default:
-+			wiphy_err(hw->wiphy, "unknown control case: %d\n",
-+				  ctrl_case);
-+			dev_kfree_skb_any(psk_buff);
-+			break;
-+		}
-+out:
-+		pcie_rx_refill_ndp(priv, buf_idx);
-+
-+		if (rx_done_tail >= MAX_RX_RING_DONE_SIZE)
-+			rx_done_tail = 0;
-+
-+		rx_done_head =
-+			readl(pcie_priv->iobase1 + MACREG_REG_RXDONEHEAD);
-+		rx_cnt++;
-+	}
-+
-+	rx_desc_head += rx_cnt;
-+	if (rx_desc_head >= MAX_RX_RING_SEND_SIZE)
-+		rx_desc_head = rx_desc_head - MAX_RX_RING_SEND_SIZE;
-+	writel(rx_done_tail, pcie_priv->iobase1 + MACREG_REG_RXDONETAIL);
-+	writel(rx_desc_head, pcie_priv->iobase1 + MACREG_REG_RXDESCHEAD);
-+
-+	pcie_mask_int(pcie_priv, MACREG_A2HRIC_RX_DONE_HEAD_RDY, true);
-+	pcie_priv->is_rx_schedule = false;
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.h
-new file mode 100644
-index 000000000000..7e83cedf4351
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/rx_ndp.h
-@@ -0,0 +1,26 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines receive related functions for new data path.
-+ */
-+
-+#ifndef _RX_NDP_H_
-+#define _RX_NDP_H_
-+
-+int pcie_rx_init_ndp(struct ieee80211_hw *hw);
-+void pcie_rx_deinit_ndp(struct ieee80211_hw *hw);
-+void pcie_rx_recv_ndp(unsigned long data);
-+
-+#endif /* _RX_NDP_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/sc4_ddr.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/sc4_ddr.h
-new file mode 100644
-index 000000000000..2da0257accba
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/sc4_ddr.h
-@@ -0,0 +1,965 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+static unsigned char sc4_ddr_init[] = {
-+0x05,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0xa4,
-+0x03,
-+0x00,
-+0x00,
-+0x2a,
-+0xbe,
-+0xad,
-+0x7e,
-+0x00,
-+0x00,
-+0x00,
-+0xa8,
-+0x01,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x5c,
-+0x48,
-+0x5b,
-+0x49,
-+0x04,
-+0x00,
-+0x00,
-+0x00,
-+0x10,
-+0xb5,
-+0xc0,
-+0xf8,
-+0x08,
-+0x00,
-+0x00,
-+0x00,
-+0xe0,
-+0x12,
-+0xef,
-+0x21,
-+0x0c,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0x20,
-+0x13,
-+0x10,
-+0x00,
-+0x00,
-+0x00,
-+0x02,
-+0x21,
-+0xc0,
-+0xf8,
-+0x14,
-+0x00,
-+0x00,
-+0x00,
-+0x24,
-+0x13,
-+0x02,
-+0x01,
-+0x18,
-+0x00,
-+0x00,
-+0x00,
-+0x57,
-+0x49,
-+0x0a,
-+0x60,
-+0x1c,
-+0x00,
-+0x00,
-+0x00,
-+0x00,
-+0x21,
-+0x56,
-+0x4b,
-+0x20,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0x3b,
-+0x19,
-+0x60,
-+0x24,
-+0x00,
-+0x00,
-+0x00,
-+0x54,
-+0x4b,
-+0x1b,
-+0x1d,
-+0x28,
-+0x00,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x53,
-+0x4b,
-+0x2c,
-+0x00,
-+0x00,
-+0x00,
-+0xbc,
-+0x3b,
-+0x19,
-+0x60,
-+0x30,
-+0x00,
-+0x00,
-+0x00,
-+0x51,
-+0x4b,
-+0x08,
-+0x33,
-+0x34,
-+0x00,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x50,
-+0x4b,
-+0x38,
-+0x00,
-+0x00,
-+0x00,
-+0xb8,
-+0x3b,
-+0x19,
-+0x60,
-+0x3c,
-+0x00,
-+0x00,
-+0x00,
-+0x4e,
-+0x4b,
-+0x0c,
-+0x33,
-+0x40,
-+0x00,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x4d,
-+0x4b,
-+0x44,
-+0x00,
-+0x00,
-+0x00,
-+0xb4,
-+0x3b,
-+0x19,
-+0x60,
-+0x48,
-+0x00,
-+0x00,
-+0x00,
-+0x4b,
-+0x4b,
-+0x10,
-+0x33,
-+0x4c,
-+0x00,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x4a,
-+0x4b,
-+0x50,
-+0x00,
-+0x00,
-+0x00,
-+0xb0,
-+0x3b,
-+0x19,
-+0x60,
-+0x54,
-+0x00,
-+0x00,
-+0x00,
-+0x48,
-+0x4b,
-+0x80,
-+0x33,
-+0x58,
-+0x00,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x47,
-+0x4b,
-+0x5c,
-+0x00,
-+0x00,
-+0x00,
-+0x40,
-+0x3b,
-+0x19,
-+0x60,
-+0x60,
-+0x00,
-+0x00,
-+0x00,
-+0x47,
-+0x4c,
-+0x46,
-+0x4b,
-+0x64,
-+0x00,
-+0x00,
-+0x00,
-+0x23,
-+0x60,
-+0x24,
-+0x1d,
-+0x68,
-+0x00,
-+0x00,
-+0x00,
-+0x23,
-+0x60,
-+0x24,
-+0x1d,
-+0x6c,
-+0x00,
-+0x00,
-+0x00,
-+0x23,
-+0x60,
-+0x44,
-+0x4b,
-+0x70,
-+0x00,
-+0x00,
-+0x00,
-+0x40,
-+0x33,
-+0x19,
-+0x60,
-+0x74,
-+0x00,
-+0x00,
-+0x00,
-+0x1b,
-+0x1d,
-+0x19,
-+0x60,
-+0x78,
-+0x00,
-+0x00,
-+0x00,
-+0x1b,
-+0x1d,
-+0x19,
-+0x60,
-+0x7c,
-+0x00,
-+0x00,
-+0x00,
-+0x41,
-+0x4b,
-+0xc0,
-+0xf8,
-+0x80,
-+0x00,
-+0x00,
-+0x00,
-+0xe0,
-+0x31,
-+0x41,
-+0x4b,
-+0x84,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0xf0,
-+0x31,
-+0x88,
-+0x00,
-+0x00,
-+0x00,
-+0x03,
-+0x04,
-+0xc0,
-+0xf8,
-+0x8c,
-+0x00,
-+0x00,
-+0x00,
-+0xf0,
-+0x32,
-+0x40,
-+0xf2,
-+0x90,
-+0x00,
-+0x00,
-+0x00,
-+0x55,
-+0x13,
-+0xc0,
-+0xf8,
-+0x94,
-+0x00,
-+0x00,
-+0x00,
-+0x60,
-+0x33,
-+0x3d,
-+0x4b,
-+0x98,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0x64,
-+0x33,
-+0x9c,
-+0x00,
-+0x00,
-+0x00,
-+0x13,
-+0x1d,
-+0xc0,
-+0xf8,
-+0xa0,
-+0x00,
-+0x00,
-+0x00,
-+0x68,
-+0x33,
-+0x3b,
-+0x4b,
-+0xa4,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0x6c,
-+0x33,
-+0xa8,
-+0x00,
-+0x00,
-+0x00,
-+0x3a,
-+0x4b,
-+0xc0,
-+0xf8,
-+0xac,
-+0x00,
-+0x00,
-+0x00,
-+0x70,
-+0x33,
-+0x3a,
-+0x4b,
-+0xb0,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0x74,
-+0x33,
-+0xb4,
-+0x00,
-+0x00,
-+0x00,
-+0x39,
-+0x4b,
-+0xc0,
-+0xf8,
-+0xb8,
-+0x00,
-+0x00,
-+0x00,
-+0x78,
-+0x33,
-+0xc4,
-+0x23,
-+0xbc,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0x7c,
-+0x33,
-+0xc0,
-+0x00,
-+0x00,
-+0x00,
-+0x37,
-+0x4b,
-+0xc0,
-+0xf8,
-+0xc4,
-+0x00,
-+0x00,
-+0x00,
-+0x80,
-+0x33,
-+0x37,
-+0x4b,
-+0xc8,
-+0x00,
-+0x00,
-+0x00,
-+0xc0,
-+0xf8,
-+0x84,
-+0x33,
-+0xcc,
-+0x00,
-+0x00,
-+0x00,
-+0x36,
-+0x4b,
-+0xc0,
-+0xf8,
-+0xd0,
-+0x00,
-+0x00,
-+0x00,
-+0x88,
-+0x33,
-+0x42,
-+0xf2,
-+0xd4,
-+0x00,
-+0x00,
-+0x00,
-+0x44,
-+0x23,
-+0xc0,
-+0xf8,
-+0xd8,
-+0x00,
-+0x00,
-+0x00,
-+0x8c,
-+0x33,
-+0xc0,
-+0xf8,
-+0xdc,
-+0x00,
-+0x00,
-+0x00,
-+0x90,
-+0x13,
-+0x4f,
-+0xf4,
-+0xe0,
-+0x00,
-+0x00,
-+0x00,
-+0x60,
-+0x43,
-+0xc0,
-+0xf8,
-+0xe4,
-+0x00,
-+0x00,
-+0x00,
-+0xa0,
-+0x32,
-+0xc0,
-+0xf8,
-+0xe8,
-+0x00,
-+0x00,
-+0x00,
-+0xa4,
-+0x22,
-+0xc0,
-+0xf8,
-+0xec,
-+0x00,
-+0x00,
-+0x00,
-+0xa8,
-+0x12,
-+0x44,
-+0xf2,
-+0xf0,
-+0x00,
-+0x00,
-+0x00,
-+0x40,
-+0x02,
-+0x2e,
-+0x4b,
-+0xf4,
-+0x00,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x1b,
-+0x1d,
-+0xf8,
-+0x00,
-+0x00,
-+0x00,
-+0x2d,
-+0x4a,
-+0x1a,
-+0x60,
-+0xfc,
-+0x00,
-+0x00,
-+0x00,
-+0x1b,
-+0x1d,
-+0x2d,
-+0x4a,
-+0x00,
-+0x01,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x1b,
-+0x1d,
-+0x04,
-+0x01,
-+0x00,
-+0x00,
-+0x2c,
-+0x4a,
-+0x1a,
-+0x60,
-+0x08,
-+0x01,
-+0x00,
-+0x00,
-+0x1b,
-+0x1d,
-+0x2c,
-+0x4a,
-+0x0c,
-+0x01,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x1b,
-+0x1d,
-+0x10,
-+0x01,
-+0x00,
-+0x00,
-+0x4f,
-+0xf4,
-+0x60,
-+0x12,
-+0x14,
-+0x01,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x25,
-+0x4a,
-+0x18,
-+0x01,
-+0x00,
-+0x00,
-+0x28,
-+0x32,
-+0x11,
-+0x60,
-+0x1c,
-+0x01,
-+0x00,
-+0x00,
-+0x23,
-+0x4a,
-+0x30,
-+0x32,
-+0x20,
-+0x01,
-+0x00,
-+0x00,
-+0x11,
-+0x60,
-+0x12,
-+0x1d,
-+0x24,
-+0x01,
-+0x00,
-+0x00,
-+0x11,
-+0x60,
-+0x03,
-+0x22,
-+0x28,
-+0x01,
-+0x00,
-+0x00,
-+0x20,
-+0x4b,
-+0x38,
-+0x33,
-+0x2c,
-+0x01,
-+0x00,
-+0x00,
-+0x1a,
-+0x60,
-+0x20,
-+0x22,
-+0x30,
-+0x01,
-+0x00,
-+0x00,
-+0x1b,
-+0x1d,
-+0x1a,
-+0x60,
-+0x34,
-+0x01,
-+0x00,
-+0x00,
-+0x1b,
-+0x1d,
-+0x4f,
-+0xf0,
-+0x38,
-+0x01,
-+0x00,
-+0x00,
-+0x04,
-+0x22,
-+0x1a,
-+0x60,
-+0x3c,
-+0x01,
-+0x00,
-+0x00,
-+0x03,
-+0x06,
-+0x1b,
-+0x4a,
-+0x40,
-+0x01,
-+0x00,
-+0x00,
-+0x20,
-+0x32,
-+0x13,
-+0x60,
-+0x44,
-+0x01,
-+0x00,
-+0x00,
-+0x43,
-+0x06,
-+0x13,
-+0x60,
-+0x48,
-+0x01,
-+0x00,
-+0x00,
-+0x83,
-+0x06,
-+0x13,
-+0x60,
-+0x4c,
-+0x01,
-+0x00,
-+0x00,
-+0x0c,
-+0x4b,
-+0x1c,
-+0x4a,
-+0x50,
-+0x01,
-+0x00,
-+0x00,
-+0x70,
-+0x33,
-+0x1a,
-+0x60,
-+0x54,
-+0x01,
-+0x00,
-+0x00,
-+0x41,
-+0x62,
-+0x4f,
-+0xf4,
-+0x58,
-+0x01,
-+0x00,
-+0x00,
-+0x7f,
-+0x22,
-+0x82,
-+0x62,
-+0x5c,
-+0x01,
-+0x00,
-+0x00,
-+0x19,
-+0x4a,
-+0x82,
-+0x66,
-+0x60,
-+0x01,
-+0x00,
-+0x00,
-+0xc1,
-+0x66,
-+0x40,
-+0xf2,
-+0x64,
-+0x01,
-+0x00,
-+0x00,
-+0x63,
-+0x42,
-+0x42,
-+0x63,
-+0x68,
-+0x01,
-+0x00,
-+0x00,
-+0x01,
-+0x64,
-+0x17,
-+0x49,
-+0x6c,
-+0x01,
-+0x00,
-+0x00,
-+0x01,
-+0x60,
-+0x10,
-+0xbd,
-+0x70,
-+0x01,
-+0x00,
-+0x00,
-+0x22,
-+0x76,
-+0x30,
-+0x00,
-+0x74,
-+0x01,
-+0x00,
-+0x00,
-+0x20,
-+0x00,
-+0x00,
-+0xf0,
-+0x78,
-+0x01,
-+0x00,
-+0x00,
-+0x40,
-+0x06,
-+0x00,
-+0xf0,
-+0x7c,
-+0x01,
-+0x00,
-+0x00,
-+0x04,
-+0x00,
-+0x15,
-+0x15,
-+0x80,
-+0x01,
-+0x00,
-+0x00,
-+0x00,
-+0x05,
-+0x00,
-+0xf0,
-+0x84,
-+0x01,
-+0x00,
-+0x00,
-+0x01,
-+0x00,
-+0x0d,
-+0x00,
-+0x88,
-+0x01,
-+0x00,
-+0x00,
-+0x32,
-+0x05,
-+0x00,
-+0x04,
-+0x8c,
-+0x01,
-+0x00,
-+0x00,
-+0xa9,
-+0x02,
-+0xb8,
-+0x00,
-+0x90,
-+0x01,
-+0x00,
-+0x00,
-+0x00,
-+0x01,
-+0x40,
-+0x00,
-+0x94,
-+0x01,
-+0x00,
-+0x00,
-+0xeb,
-+0x06,
-+0x77,
-+0x00,
-+0x98,
-+0x01,
-+0x00,
-+0x00,
-+0x00,
-+0x52,
-+0x7b,
-+0x50,
-+0x9c,
-+0x01,
-+0x00,
-+0x00,
-+0x0b,
-+0x06,
-+0x04,
-+0x10,
-+0xa0,
-+0x01,
-+0x00,
-+0x00,
-+0x10,
-+0x07,
-+0x17,
-+0x13,
-+0xa4,
-+0x01,
-+0x00,
-+0x00,
-+0x07,
-+0x74,
-+0x70,
-+0x00,
-+0xa8,
-+0x01,
-+0x00,
-+0x00,
-+0x40,
-+0x00,
-+0x70,
-+0x50,
-+0xac,
-+0x01,
-+0x00,
-+0x00,
-+0x00,
-+0x04,
-+0x00,
-+0xf0,
-+0xb0,
-+0x01,
-+0x00,
-+0x00,
-+0x79,
-+0x07,
-+0x70,
-+0x17,
-+0xb4,
-+0x01,
-+0x00,
-+0x00,
-+0x70,
-+0x07,
-+0xf0,
-+0x0f,
-+0xb8,
-+0x01,
-+0x00,
-+0x00,
-+0x77,
-+0xfc,
-+0x03,
-+0x3f,
-+0xbc,
-+0x01,
-+0x00,
-+0x00,
-+0x00,
-+0x31,
-+0x10,
-+0x00,
-+0xc0,
-+0x01,
-+0x00,
-+0x00,
-+0x01,
-+0x00,
-+0x00,
-+0xc0,
-+0xc4,
-+0x01,
-+0x00,
-+0x00,
-+0x66,
-+0x66,
-+0x66,
-+0x00,
-+0xc8,
-+0x01,
-+0x00,
-+0x00,
-+0x01,
-+0x00,
-+0x00,
-+0x11,
-+0x37,
-+0x3e,
-+0xfc,
-+0xdc,
-+};
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.c b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.c
-new file mode 100644
-index 000000000000..dd77589ef5a6
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.c
-@@ -0,0 +1,1396 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements transmit related functions. */
-+
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/fwcmd.h"
-+#include "hif/pcie/dev.h"
-+#include "hif/pcie/tx.h"
-+
-+#define MAX_NUM_TX_RING_BYTES  (PCIE_MAX_NUM_TX_DESC * \
-+				sizeof(struct pcie_tx_desc))
-+
-+#define MAX_NUM_TX_HNDL_BYTES  (PCIE_MAX_NUM_TX_DESC * \
-+				sizeof(struct pcie_tx_hndl))
-+
-+#define TOTAL_HW_QUEUES        (SYSADPT_TX_WMM_QUEUES + \
-+				PCIE_AMPDU_QUEUES)
-+
-+#define EAGLE_TXD_XMITCTRL_USE_MC_RATE     0x8     /* Use multicast data rate */
-+
-+#define MWL_QOS_ACK_POLICY_MASK	           0x0060
-+#define MWL_QOS_ACK_POLICY_NORMAL          0x0000
-+#define MWL_QOS_ACK_POLICY_BLOCKACK        0x0060
-+
-+#define EXT_IV                             0x20
-+#define INCREASE_IV(iv16, iv32) \
-+{ \
-+	(iv16)++; \
-+	if ((iv16) == 0) \
-+		(iv32)++; \
-+}
-+
-+/* Transmission information to transmit a socket buffer. */
-+struct pcie_tx_ctrl {
-+	void *vif;
-+	void *sta;
-+	void *k_conf;
-+	void *amsdu_pkts;
-+	u8 tx_priority;
-+	u8 type;
-+	u16 qos_ctrl;
-+	u8 xmit_control;
-+};
-+
-+struct ccmp_hdr {
-+	__le16 iv16;
-+	u8 rsvd;
-+	u8 key_id;
-+	__le32 iv32;
-+} __packed;
-+
-+static int pcie_tx_ring_alloc(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data *desc;
-+	int num;
-+	u8 *mem;
-+
-+	desc = &pcie_priv->desc_data[0];
-+
-+	mem = dma_alloc_coherent(priv->dev,
-+				 MAX_NUM_TX_RING_BYTES *
-+				 PCIE_NUM_OF_DESC_DATA,
-+				 &desc->pphys_tx_ring,
-+				 GFP_KERNEL);
-+
-+	if (!mem) {
-+		wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
-+		return -ENOMEM;
-+	}
-+
-+	for (num = 0; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		desc = &pcie_priv->desc_data[num];
-+
-+		desc->ptx_ring = (struct pcie_tx_desc *)
-+			(mem + num * MAX_NUM_TX_RING_BYTES);
-+
-+		desc->pphys_tx_ring = (dma_addr_t)
-+			((u32)pcie_priv->desc_data[0].pphys_tx_ring +
-+			num * MAX_NUM_TX_RING_BYTES);
-+
-+		memset(desc->ptx_ring, 0x00,
-+		       MAX_NUM_TX_RING_BYTES);
-+	}
-+
-+	mem = kzalloc(MAX_NUM_TX_HNDL_BYTES * PCIE_NUM_OF_DESC_DATA,
-+		      GFP_KERNEL);
-+
-+	if (!mem) {
-+		wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_TX_RING_BYTES *
-+				  PCIE_NUM_OF_DESC_DATA,
-+				  pcie_priv->desc_data[0].ptx_ring,
-+				  pcie_priv->desc_data[0].pphys_tx_ring);
-+		return -ENOMEM;
-+	}
-+
-+	for (num = 0; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		desc = &pcie_priv->desc_data[num];
-+
-+		desc->tx_hndl = (struct pcie_tx_hndl *)
-+			(mem + num * MAX_NUM_TX_HNDL_BYTES);
-+	}
-+
-+	return 0;
-+}
-+
-+static int pcie_txbd_ring_create(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num;
-+	u8 *mem;
-+
-+	/* driver maintaines the write pointer and firmware maintaines the read
-+	 * pointer.
-+	 */
-+	pcie_priv->txbd_wrptr = 0;
-+	pcie_priv->txbd_rdptr = 0;
-+
-+	/* allocate shared memory for the BD ring and divide the same in to
-+	 * several descriptors
-+	 */
-+	pcie_priv->txbd_ring_size =
-+		sizeof(struct pcie_data_buf) * PCIE_MAX_TXRX_BD;
-+	wiphy_info(priv->hw->wiphy, "TX ring: allocating %d bytes\n",
-+		   pcie_priv->txbd_ring_size);
-+
-+	mem = dma_alloc_coherent(priv->dev,
-+				 pcie_priv->txbd_ring_size,
-+				 &pcie_priv->txbd_ring_pbase,
-+				 GFP_KERNEL);
-+
-+	if (!mem) {
-+		wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
-+		return -ENOMEM;
-+	}
-+	pcie_priv->txbd_ring_vbase = mem;
-+	wiphy_info(priv->hw->wiphy,
-+		   "TX ring: - base: %p, pbase: 0x%x, len: %d\n",
-+		   pcie_priv->txbd_ring_vbase,
-+		   pcie_priv->txbd_ring_pbase,
-+		   pcie_priv->txbd_ring_size);
-+
-+	for (num = 0; num < PCIE_MAX_TXRX_BD; num++) {
-+		pcie_priv->txbd_ring[num] =
-+			(struct pcie_data_buf *)(pcie_priv->txbd_ring_vbase +
-+			(sizeof(struct pcie_data_buf) * num));
-+		pcie_priv->txbd_ring[num]->flags = 0;
-+		pcie_priv->txbd_ring[num]->offset = 0;
-+		pcie_priv->txbd_ring[num]->frag_len = 0;
-+		pcie_priv->txbd_ring[num]->len = 0;
-+		pcie_priv->txbd_ring[num]->paddr = 0;
-+		pcie_priv->tx_buf_list[num] = NULL;
-+	}
-+
-+	return 0;
-+}
-+
-+static int pcie_tx_ring_init(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num, i;
-+	struct pcie_desc_data *desc;
-+
-+	for (num = 0; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		skb_queue_head_init(&pcie_priv->txq[num]);
-+		pcie_priv->fw_desc_cnt[num] = 0;
-+
-+		if (priv->chip_type == MWL8997)
-+			continue;
-+
-+		desc = &pcie_priv->desc_data[num];
-+
-+		if (desc->ptx_ring) {
-+			for (i = 0; i < PCIE_MAX_NUM_TX_DESC; i++) {
-+				desc->ptx_ring[i].status =
-+					cpu_to_le32(EAGLE_TXD_STATUS_IDLE);
-+				desc->ptx_ring[i].pphys_next =
-+					cpu_to_le32((u32)desc->pphys_tx_ring +
-+					((i + 1) *
-+					sizeof(struct pcie_tx_desc)));
-+				desc->tx_hndl[i].pdesc =
-+					&desc->ptx_ring[i];
-+				if (i < PCIE_MAX_NUM_TX_DESC - 1)
-+					desc->tx_hndl[i].pnext =
-+						&desc->tx_hndl[i + 1];
-+			}
-+			desc->ptx_ring[PCIE_MAX_NUM_TX_DESC - 1].pphys_next =
-+				cpu_to_le32((u32)desc->pphys_tx_ring);
-+			desc->tx_hndl[PCIE_MAX_NUM_TX_DESC - 1].pnext =
-+				&desc->tx_hndl[0];
-+
-+			desc->pstale_tx_hndl = &desc->tx_hndl[0];
-+			desc->pnext_tx_hndl  = &desc->tx_hndl[0];
-+		} else {
-+			wiphy_err(priv->hw->wiphy, "no valid TX mem\n");
-+			return -ENOMEM;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static void pcie_tx_ring_cleanup(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int cleaned_tx_desc = 0;
-+	int num, i;
-+	struct pcie_desc_data *desc;
-+
-+	for (num = 0; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		skb_queue_purge(&pcie_priv->txq[num]);
-+		pcie_priv->fw_desc_cnt[num] = 0;
-+
-+		if (priv->chip_type == MWL8997)
-+			continue;
-+
-+		desc = &pcie_priv->desc_data[num];
-+
-+		if (desc->ptx_ring) {
-+			for (i = 0; i < PCIE_MAX_NUM_TX_DESC; i++) {
-+				if (!desc->tx_hndl[i].psk_buff)
-+					continue;
-+
-+				wiphy_debug(priv->hw->wiphy,
-+					    "unmapped and free'd %i %p %x\n",
-+					    i,
-+					    desc->tx_hndl[i].psk_buff->data,
-+					    le32_to_cpu(
-+					    desc->ptx_ring[i].pkt_ptr));
-+				pci_unmap_single(pcie_priv->pdev,
-+						 le32_to_cpu(
-+						 desc->ptx_ring[i].pkt_ptr),
-+						 desc->tx_hndl[i].psk_buff->len,
-+						 PCI_DMA_TODEVICE);
-+				dev_kfree_skb_any(desc->tx_hndl[i].psk_buff);
-+				desc->ptx_ring[i].status =
-+					cpu_to_le32(EAGLE_TXD_STATUS_IDLE);
-+				desc->ptx_ring[i].pkt_ptr = 0;
-+				desc->ptx_ring[i].pkt_len = 0;
-+				desc->tx_hndl[i].psk_buff = NULL;
-+				cleaned_tx_desc++;
-+			}
-+		}
-+	}
-+
-+	wiphy_info(priv->hw->wiphy, "cleaned %i TX descr\n", cleaned_tx_desc);
-+}
-+
-+static void pcie_tx_ring_free(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num;
-+
-+	if (pcie_priv->desc_data[0].ptx_ring) {
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_TX_RING_BYTES *
-+				  PCIE_NUM_OF_DESC_DATA,
-+				  pcie_priv->desc_data[0].ptx_ring,
-+				  pcie_priv->desc_data[0].pphys_tx_ring);
-+	}
-+
-+	for (num = 0; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		if (pcie_priv->desc_data[num].ptx_ring)
-+			pcie_priv->desc_data[num].ptx_ring = NULL;
-+		pcie_priv->desc_data[num].pstale_tx_hndl = NULL;
-+		pcie_priv->desc_data[num].pnext_tx_hndl = NULL;
-+	}
-+
-+	kfree(pcie_priv->desc_data[0].tx_hndl);
-+}
-+
-+static void pcie_txbd_ring_delete(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct sk_buff *skb;
-+	struct pcie_tx_desc *tx_desc;
-+	int num;
-+
-+	if (pcie_priv->txbd_ring_vbase) {
-+		dma_free_coherent(priv->dev,
-+				  pcie_priv->txbd_ring_size,
-+				  pcie_priv->txbd_ring_vbase,
-+				  pcie_priv->txbd_ring_pbase);
-+	}
-+
-+	for (num = 0; num < PCIE_MAX_TXRX_BD; num++) {
-+		pcie_priv->txbd_ring[num] = NULL;
-+		if (pcie_priv->tx_buf_list[num]) {
-+			skb = pcie_priv->tx_buf_list[num];
-+			tx_desc = (struct pcie_tx_desc *)skb->data;
-+
-+			pci_unmap_single(pcie_priv->pdev,
-+					 le32_to_cpu(tx_desc->pkt_ptr),
-+					 skb->len,
-+					 PCI_DMA_TODEVICE);
-+			dev_kfree_skb_any(skb);
-+		}
-+		pcie_priv->tx_buf_list[num] = NULL;
-+	}
-+
-+	pcie_priv->txbd_wrptr = 0;
-+	pcie_priv->txbd_rdptr = 0;
-+	pcie_priv->txbd_ring_size = 0;
-+	pcie_priv->txbd_ring_vbase = NULL;
-+	pcie_priv->txbd_ring_pbase = 0;
-+}
-+
-+static inline void pcie_tx_add_ccmp_hdr(u8 *pccmp_hdr,
-+					u8 key_id, u16 iv16, u32 iv32)
-+{
-+	struct ccmp_hdr *ccmp_h = (struct ccmp_hdr *)pccmp_hdr;
-+
-+	ccmp_h->iv16 = cpu_to_le16(iv16);
-+	ccmp_h->rsvd = 0;
-+	ccmp_h->key_id = EXT_IV | (key_id << 6);
-+	ccmp_h->iv32 = cpu_to_le32(iv32);
-+}
-+
-+static inline bool pcie_tx_available(struct mwl_priv *priv, int desc_num)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_tx_hndl *tx_hndl;
-+
-+	if (priv->chip_type == MWL8997)
-+		return PCIE_TXBD_NOT_FULL(pcie_priv->txbd_wrptr,
-+					  pcie_priv->txbd_rdptr);
-+
-+	tx_hndl = pcie_priv->desc_data[desc_num].pnext_tx_hndl;
-+
-+	if (!tx_hndl->pdesc)
-+		return false;
-+
-+	if (tx_hndl->pdesc->status != EAGLE_TXD_STATUS_IDLE) {
-+		/* Interrupt F/W anyway */
-+		if (tx_hndl->pdesc->status &
-+		    cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED))
-+			writel(MACREG_H2ARIC_BIT_PPA_READY,
-+			       pcie_priv->iobase1 +
-+			       MACREG_REG_H2A_INTERRUPT_EVENTS);
-+		return false;
-+	}
-+
-+	return true;
-+}
-+
-+static inline void pcie_tx_skb(struct mwl_priv *priv, int desc_num,
-+			       struct sk_buff *tx_skb)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct pcie_tx_hndl *tx_hndl = NULL;
-+	struct pcie_tx_desc *tx_desc;
-+	struct ieee80211_sta *sta;
-+	struct ieee80211_vif *vif;
-+	struct mwl_vif *mwl_vif;
-+	struct ieee80211_key_conf *k_conf;
-+	bool ccmp = false;
-+	struct pcie_pfu_dma_data *pfu_dma_data;
-+	struct pcie_dma_data *dma_data;
-+	struct ieee80211_hdr *wh;
-+	dma_addr_t dma;
-+
-+	if (WARN_ON(!tx_skb))
-+		return;
-+
-+	tx_info = IEEE80211_SKB_CB(tx_skb);
-+	tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+	sta = (struct ieee80211_sta *)tx_ctrl->sta;
-+	vif = (struct ieee80211_vif *)tx_ctrl->vif;
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	k_conf = (struct ieee80211_key_conf *)tx_ctrl->k_conf;
-+
-+	pcie_tx_encapsulate_frame(priv, tx_skb, k_conf, &ccmp);
-+
-+	if (priv->chip_type == MWL8997) {
-+		pfu_dma_data = (struct pcie_pfu_dma_data *)tx_skb->data;
-+		tx_desc = &pfu_dma_data->tx_desc;
-+		dma_data = &pfu_dma_data->dma_data;
-+	} else {
-+		tx_hndl = pcie_priv->desc_data[desc_num].pnext_tx_hndl;
-+		tx_hndl->psk_buff = tx_skb;
-+		tx_desc = tx_hndl->pdesc;
-+		dma_data = (struct pcie_dma_data *)tx_skb->data;
-+	}
-+	wh = &dma_data->wh;
-+
-+	if (ieee80211_is_probe_resp(wh->frame_control) &&
-+	    priv->dump_probe)
-+		wiphy_info(priv->hw->wiphy,
-+			  "Probe Resp: %pM\n", wh->addr1);
-+
-+	if (ieee80211_is_data(wh->frame_control) ||
-+	    (ieee80211_is_mgmt(wh->frame_control) &&
-+	    ieee80211_has_protected(wh->frame_control) &&
-+	    !is_multicast_ether_addr(wh->addr1))) {
-+		if (is_multicast_ether_addr(wh->addr1)) {
-+			if (ccmp) {
-+				pcie_tx_add_ccmp_hdr(dma_data->data,
-+						     mwl_vif->keyidx,
-+						     mwl_vif->iv16,
-+						     mwl_vif->iv32);
-+				INCREASE_IV(mwl_vif->iv16, mwl_vif->iv32);
-+			}
-+		} else {
-+			if (ccmp) {
-+				if (vif->type == NL80211_IFTYPE_STATION) {
-+					pcie_tx_add_ccmp_hdr(dma_data->data,
-+							     mwl_vif->keyidx,
-+							     mwl_vif->iv16,
-+							     mwl_vif->iv32);
-+					INCREASE_IV(mwl_vif->iv16,
-+						    mwl_vif->iv32);
-+				} else {
-+					struct mwl_sta *sta_info;
-+
-+					sta_info = mwl_dev_get_sta(sta);
-+
-+					pcie_tx_add_ccmp_hdr(dma_data->data,
-+							     0,
-+							     sta_info->iv16,
-+							     sta_info->iv32);
-+					INCREASE_IV(sta_info->iv16,
-+						    sta_info->iv32);
-+				}
-+			}
-+		}
-+	}
-+
-+	if (tx_info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)
-+		tx_desc->flags |= PCIE_TX_WCB_FLAGS_DONT_ENCRYPT;
-+	if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
-+		tx_desc->flags |= PCIE_TX_WCB_FLAGS_NO_CCK_RATE;
-+	tx_desc->tx_priority = tx_ctrl->tx_priority;
-+	tx_desc->qos_ctrl = cpu_to_le16(tx_ctrl->qos_ctrl);
-+	tx_desc->pkt_len = cpu_to_le16(tx_skb->len);
-+	tx_desc->packet_info = 0;
-+	tx_desc->data_rate = 0;
-+	tx_desc->type = tx_ctrl->type;
-+	tx_desc->xmit_control = tx_ctrl->xmit_control;
-+	tx_desc->sap_pkt_info = 0;
-+	dma = pci_map_single(pcie_priv->pdev, tx_skb->data,
-+			     tx_skb->len, PCI_DMA_TODEVICE);
-+	if (pci_dma_mapping_error(pcie_priv->pdev, dma)) {
-+		dev_kfree_skb_any(tx_skb);
-+		wiphy_err(priv->hw->wiphy,
-+			  "failed to map pci memory!\n");
-+		return;
-+	}
-+	if (priv->chip_type == MWL8997)
-+		tx_desc->pkt_ptr = cpu_to_le32(sizeof(struct pcie_tx_desc));
-+	else
-+		tx_desc->pkt_ptr = cpu_to_le32(dma);
-+	tx_desc->status = cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED);
-+	/* make sure all the memory transactions done by cpu were completed */
-+	wmb();	/*Data Memory Barrier*/
-+
-+	if (priv->chip_type == MWL8997) {
-+		u32 wrindx;
-+		struct pcie_data_buf *data_buf;
-+		const u32 num_tx_buffs = PCIE_MAX_TXRX_BD << PCIE_TX_START_PTR;
-+
-+		wrindx = (pcie_priv->txbd_wrptr & PCIE_TXBD_MASK) >>
-+			PCIE_TX_START_PTR;
-+		pcie_priv->tx_buf_list[wrindx] = tx_skb;
-+		data_buf = pcie_priv->txbd_ring[wrindx];
-+		data_buf->paddr = cpu_to_le64(dma);
-+		data_buf->len = cpu_to_le16(tx_skb->len);
-+		data_buf->flags = cpu_to_le16(PCIE_BD_FLAG_FIRST_DESC |
-+					      PCIE_BD_FLAG_LAST_DESC);
-+		data_buf->frag_len = cpu_to_le16(tx_skb->len);
-+		data_buf->offset = 0;
-+		pcie_priv->txbd_wrptr += PCIE_BD_FLAG_TX_START_PTR;
-+
-+		if ((pcie_priv->txbd_wrptr & PCIE_TXBD_MASK) == num_tx_buffs)
-+			pcie_priv->txbd_wrptr = ((pcie_priv->txbd_wrptr &
-+			PCIE_BD_FLAG_TX_ROLLOVER_IND) ^
-+			PCIE_BD_FLAG_TX_ROLLOVER_IND);
-+
-+		/* Write the TX ring write pointer in to REG_TXBD_WRPTR */
-+		writel(pcie_priv->txbd_wrptr,
-+		       pcie_priv->iobase1 + REG_TXBD_WRPTR);
-+	} else {
-+		writel(MACREG_H2ARIC_BIT_PPA_READY,
-+		       pcie_priv->iobase1 + MACREG_REG_H2A_INTERRUPT_EVENTS);
-+		pcie_priv->desc_data[desc_num].pnext_tx_hndl = tx_hndl->pnext;
-+		pcie_priv->fw_desc_cnt[desc_num]++;
-+	}
-+}
-+
-+static inline
-+struct sk_buff *pcie_tx_do_amsdu(struct mwl_priv *priv,
-+				 int desc_num,
-+				 struct sk_buff *tx_skb,
-+				 struct ieee80211_tx_info *tx_info)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct ieee80211_sta *sta;
-+	struct mwl_sta *sta_info;
-+	struct pcie_tx_ctrl *tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+	struct ieee80211_tx_info *amsdu_info;
-+	struct sk_buff_head *amsdu_pkts;
-+	struct mwl_amsdu_frag *amsdu;
-+	int amsdu_allow_size;
-+	struct ieee80211_hdr *wh;
-+	int wh_len;
-+	u16 len;
-+	u8 *data;
-+
-+	sta = (struct ieee80211_sta *)tx_ctrl->sta;
-+	sta_info = mwl_dev_get_sta(sta);
-+
-+	if (!sta_info->is_amsdu_allowed)
-+		return tx_skb;
-+
-+	wh = (struct ieee80211_hdr *)tx_skb->data;
-+	if (sta_info->is_mesh_node && is_multicast_ether_addr(wh->addr3))
-+		return tx_skb;
-+
-+	if (ieee80211_is_qos_nullfunc(wh->frame_control))
-+		return tx_skb;
-+
-+	if (sta_info->amsdu_ctrl.cap == MWL_AMSDU_SIZE_4K)
-+		amsdu_allow_size = SYSADPT_AMSDU_4K_MAX_SIZE;
-+	else if (sta_info->amsdu_ctrl.cap == MWL_AMSDU_SIZE_8K)
-+		amsdu_allow_size = SYSADPT_AMSDU_8K_MAX_SIZE;
-+	else
-+		return tx_skb;
-+
-+	spin_lock_bh(&sta_info->amsdu_lock);
-+	amsdu = &sta_info->amsdu_ctrl.frag[desc_num];
-+
-+	if ((tx_skb->len > SYSADPT_AMSDU_ALLOW_SIZE) ||
-+	    utils_is_non_amsdu_packet(tx_skb->data, true)) {
-+		if (amsdu->num) {
-+			pcie_tx_skb(priv, desc_num, amsdu->skb);
-+			amsdu->num = 0;
-+			amsdu->cur_pos = NULL;
-+		}
-+		spin_unlock_bh(&sta_info->amsdu_lock);
-+		return tx_skb;
-+	}
-+
-+	/* potential amsdu size, should add amsdu header 14 bytes +
-+	 * maximum padding 3.
-+	 */
-+	wh_len = ieee80211_hdrlen(wh->frame_control);
-+	len = tx_skb->len - wh_len + 17;
-+
-+	if (amsdu->num) {
-+		if ((amsdu->skb->len + len) > amsdu_allow_size) {
-+			pcie_tx_skb(priv, desc_num, amsdu->skb);
-+			amsdu->num = 0;
-+			amsdu->cur_pos = NULL;
-+		}
-+	}
-+
-+	amsdu->jiffies = jiffies;
-+	len = tx_skb->len - wh_len;
-+
-+	if (amsdu->num == 0) {
-+		struct sk_buff *newskb;
-+		int headroom;
-+
-+		amsdu_pkts = (struct sk_buff_head *)
-+			kmalloc(sizeof(*amsdu_pkts), GFP_ATOMIC);
-+		if (!amsdu_pkts) {
-+			spin_unlock_bh(&sta_info->amsdu_lock);
-+			return tx_skb;
-+		}
-+		newskb = dev_alloc_skb(amsdu_allow_size +
-+				       pcie_priv->tx_head_room);
-+		if (!newskb) {
-+			spin_unlock_bh(&sta_info->amsdu_lock);
-+			kfree(amsdu_pkts);
-+			return tx_skb;
-+		}
-+
-+		headroom = skb_headroom(newskb);
-+		if (headroom < pcie_priv->tx_head_room)
-+			skb_reserve(newskb,
-+				    (pcie_priv->tx_head_room - headroom));
-+
-+		data = newskb->data;
-+		memcpy(data, tx_skb->data, wh_len);
-+		if (sta_info->is_mesh_node) {
-+			ether_addr_copy(data + wh_len, wh->addr3);
-+			ether_addr_copy(data + wh_len + ETH_ALEN, wh->addr4);
-+		} else {
-+			ether_addr_copy(data + wh_len,
-+					ieee80211_get_DA(wh));
-+			ether_addr_copy(data + wh_len + ETH_ALEN,
-+					ieee80211_get_SA(wh));
-+		}
-+		*(u8 *)(data + wh_len + ETH_HLEN - 1) = len & 0xff;
-+		*(u8 *)(data + wh_len + ETH_HLEN - 2) = (len >> 8) & 0xff;
-+		memcpy(data + wh_len + ETH_HLEN, tx_skb->data + wh_len, len);
-+
-+		skb_put(newskb, tx_skb->len + ETH_HLEN);
-+		tx_ctrl->qos_ctrl |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
-+		amsdu_info = IEEE80211_SKB_CB(newskb);
-+		memcpy(amsdu_info, tx_info, sizeof(*tx_info));
-+		skb_queue_head_init(amsdu_pkts);
-+		((struct pcie_tx_ctrl *)&amsdu_info->status)->amsdu_pkts =
-+			(void *)amsdu_pkts;
-+		amsdu->skb = newskb;
-+	} else {
-+		amsdu->cur_pos += amsdu->pad;
-+		data = amsdu->cur_pos;
-+
-+		if (sta_info->is_mesh_node) {
-+			ether_addr_copy(data, wh->addr3);
-+			ether_addr_copy(data + ETH_ALEN, wh->addr4);
-+		} else {
-+			ether_addr_copy(data, ieee80211_get_DA(wh));
-+			ether_addr_copy(data + ETH_ALEN, ieee80211_get_SA(wh));
-+		}
-+		*(u8 *)(data + ETH_HLEN - 1) = len & 0xff;
-+		*(u8 *)(data + ETH_HLEN - 2) = (len >> 8) & 0xff;
-+		memcpy(data + ETH_HLEN, tx_skb->data + wh_len, len);
-+
-+		skb_put(amsdu->skb, len + ETH_HLEN + amsdu->pad);
-+		amsdu_info = IEEE80211_SKB_CB(amsdu->skb);
-+		amsdu_pkts = (struct sk_buff_head *)
-+			((struct pcie_tx_ctrl *)
-+			&amsdu_info->status)->amsdu_pkts;
-+	}
-+
-+	amsdu->num++;
-+	amsdu->pad = ((len + ETH_HLEN) % 4) ? (4 - (len + ETH_HLEN) % 4) : 0;
-+	amsdu->cur_pos = amsdu->skb->data + amsdu->skb->len;
-+	skb_queue_tail(amsdu_pkts, tx_skb);
-+
-+	if (amsdu->num > SYSADPT_AMSDU_PACKET_THRESHOLD) {
-+		amsdu->num = 0;
-+		amsdu->cur_pos = NULL;
-+		spin_unlock_bh(&sta_info->amsdu_lock);
-+		return amsdu->skb;
-+	}
-+
-+	spin_unlock_bh(&sta_info->amsdu_lock);
-+	return NULL;
-+}
-+
-+static inline void pcie_tx_ack_amsdu_pkts(struct ieee80211_hw *hw, u32 rate,
-+					  struct sk_buff_head *amsdu_pkts)
-+{
-+	struct sk_buff *amsdu_pkt;
-+	struct ieee80211_tx_info *info;
-+
-+	while (skb_queue_len(amsdu_pkts) > 0) {
-+		amsdu_pkt = skb_dequeue(amsdu_pkts);
-+		info = IEEE80211_SKB_CB(amsdu_pkt);
-+		pcie_tx_prepare_info(hw->priv, rate, info);
-+		ieee80211_tx_status(hw, amsdu_pkt);
-+	}
-+
-+	kfree(amsdu_pkts);
-+}
-+
-+static void pcie_pfu_tx_done(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	u32 wrdoneidx, rdptr;
-+	const u32 num_tx_buffs = PCIE_MAX_TXRX_BD << PCIE_TX_START_PTR;
-+	struct pcie_data_buf *data_buf;
-+	struct sk_buff *done_skb;
-+	struct pcie_pfu_dma_data *pfu_dma;
-+	struct pcie_tx_desc *tx_desc;
-+	struct pcie_dma_data *dma_data;
-+	struct ieee80211_hdr *wh;
-+	struct ieee80211_tx_info *info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct ieee80211_sta *sta;
-+	struct mwl_sta *sta_info;
-+	u32 rate = 0;
-+	struct sk_buff_head *amsdu_pkts;
-+	int hdrlen;
-+
-+	spin_lock_bh(&pcie_priv->tx_desc_lock);
-+	/* Read the TX ring read pointer set by firmware */
-+	rdptr = readl(pcie_priv->iobase1 + REG_TXBD_RDPTR);
-+	/* free from previous txbd_rdptr to current txbd_rdptr */
-+	while (((pcie_priv->txbd_rdptr & PCIE_TXBD_MASK) !=
-+	       (rdptr & PCIE_TXBD_MASK)) ||
-+	       ((pcie_priv->txbd_rdptr & PCIE_BD_FLAG_TX_ROLLOVER_IND) !=
-+	       (rdptr & PCIE_BD_FLAG_TX_ROLLOVER_IND))) {
-+		wrdoneidx = pcie_priv->txbd_rdptr & PCIE_TXBD_MASK;
-+		wrdoneidx >>= PCIE_TX_START_PTR;
-+
-+		data_buf = pcie_priv->txbd_ring[wrdoneidx];
-+		done_skb = pcie_priv->tx_buf_list[wrdoneidx];
-+		if (done_skb) {
-+			pfu_dma = (struct pcie_pfu_dma_data *)done_skb->data;
-+			tx_desc = &pfu_dma->tx_desc;
-+			dma_data = &pfu_dma->dma_data;
-+			pci_unmap_single(pcie_priv->pdev,
-+					 le32_to_cpu(data_buf->paddr),
-+					 le16_to_cpu(data_buf->len),
-+					 PCI_DMA_TODEVICE);
-+			tx_desc->pkt_ptr = 0;
-+			tx_desc->pkt_len = 0;
-+			tx_desc->status = cpu_to_le32(EAGLE_TXD_STATUS_IDLE);
-+			wmb(); /* memory barrier */
-+
-+			wh = &dma_data->wh;
-+			if (ieee80211_is_nullfunc(wh->frame_control) ||
-+			    ieee80211_is_qos_nullfunc(wh->frame_control)) {
-+				dev_kfree_skb_any(done_skb);
-+				done_skb = NULL;
-+				goto next;
-+			}
-+
-+			info = IEEE80211_SKB_CB(done_skb);
-+			tx_ctrl = (struct pcie_tx_ctrl *)&info->status;
-+			sta = (struct ieee80211_sta *)tx_ctrl->sta;
-+			if (sta) {
-+				sta_info = mwl_dev_get_sta(sta);
-+				rate = sta_info->tx_rate_info;
-+			}
-+
-+			if (ieee80211_is_data(wh->frame_control) ||
-+			    ieee80211_is_data_qos(wh->frame_control)) {
-+				amsdu_pkts = (struct sk_buff_head *)
-+					tx_ctrl->amsdu_pkts;
-+				if (amsdu_pkts) {
-+					pcie_tx_ack_amsdu_pkts(priv->hw, rate,
-+							       amsdu_pkts);
-+					dev_kfree_skb_any(done_skb);
-+					done_skb = NULL;
-+				} else {
-+					pcie_tx_prepare_info(priv, rate, info);
-+				}
-+			} else {
-+				pcie_tx_prepare_info(priv, 0, info);
-+			}
-+
-+			if (done_skb) {
-+				/* Remove H/W dma header */
-+				hdrlen = ieee80211_hdrlen(
-+					dma_data->wh.frame_control);
-+				memmove(dma_data->data - hdrlen,
-+					&dma_data->wh, hdrlen);
-+				skb_pull(done_skb, sizeof(*pfu_dma) - hdrlen);
-+				ieee80211_tx_status(priv->hw, done_skb);
-+			}
-+		}
-+next:
-+		memset(data_buf, 0, sizeof(*data_buf));
-+		pcie_priv->tx_buf_list[wrdoneidx] = NULL;
-+
-+		pcie_priv->txbd_rdptr += PCIE_BD_FLAG_TX_START_PTR;
-+		if ((pcie_priv->txbd_rdptr & PCIE_TXBD_MASK) == num_tx_buffs)
-+			pcie_priv->txbd_rdptr = ((pcie_priv->txbd_rdptr &
-+				PCIE_BD_FLAG_TX_ROLLOVER_IND) ^
-+				PCIE_BD_FLAG_TX_ROLLOVER_IND);
-+	}
-+	spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+
-+	if (pcie_priv->is_tx_done_schedule) {
-+		pcie_mask_int(pcie_priv, MACREG_A2HRIC_BIT_TX_DONE, true);
-+		tasklet_schedule(&pcie_priv->tx_task);
-+		pcie_priv->is_tx_done_schedule = false;
-+	}
-+}
-+
-+static void pcie_non_pfu_tx_done(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num;
-+	struct pcie_desc_data *desc;
-+	struct pcie_tx_hndl *tx_hndl;
-+	struct pcie_tx_desc *tx_desc;
-+	struct sk_buff *done_skb;
-+	int idx;
-+	u32 rate;
-+	struct pcie_dma_data *dma_data;
-+	struct ieee80211_hdr *wh;
-+	struct ieee80211_tx_info *info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct sk_buff_head *amsdu_pkts;
-+	int hdrlen;
-+
-+	spin_lock_bh(&pcie_priv->tx_desc_lock);
-+	for (num = 0; num < SYSADPT_TX_WMM_QUEUES; num++) {
-+		desc = &pcie_priv->desc_data[num];
-+		tx_hndl = desc->pstale_tx_hndl;
-+		tx_desc = tx_hndl->pdesc;
-+
-+		if ((tx_desc->status &
-+		    cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED)) &&
-+		    (tx_hndl->pnext->pdesc->status &
-+		    cpu_to_le32(EAGLE_TXD_STATUS_OK)))
-+			tx_desc->status = cpu_to_le32(EAGLE_TXD_STATUS_OK);
-+
-+		while (tx_hndl &&
-+		       (tx_desc->status & cpu_to_le32(EAGLE_TXD_STATUS_OK)) &&
-+		       (!(tx_desc->status &
-+		       cpu_to_le32(EAGLE_TXD_STATUS_FW_OWNED)))) {
-+			pci_unmap_single(pcie_priv->pdev,
-+					 le32_to_cpu(tx_desc->pkt_ptr),
-+					 le16_to_cpu(tx_desc->pkt_len),
-+					 PCI_DMA_TODEVICE);
-+			done_skb = tx_hndl->psk_buff;
-+			rate = le32_to_cpu(tx_desc->rate_info);
-+			tx_desc->pkt_ptr = 0;
-+			tx_desc->pkt_len = 0;
-+			tx_desc->status =
-+				cpu_to_le32(EAGLE_TXD_STATUS_IDLE);
-+			tx_hndl->psk_buff = NULL;
-+			wmb(); /*Data Memory Barrier*/
-+
-+			skb_get(done_skb);
-+			idx = pcie_priv->delay_q_idx;
-+			if (pcie_priv->delay_q[idx])
-+				dev_kfree_skb_any(pcie_priv->delay_q[idx]);
-+			pcie_priv->delay_q[idx] = done_skb;
-+			idx++;
-+			if (idx >= PCIE_DELAY_FREE_Q_LIMIT)
-+				idx = 0;
-+			pcie_priv->delay_q_idx = idx;
-+
-+			dma_data = (struct pcie_dma_data *)done_skb->data;
-+			wh = &dma_data->wh;
-+			if (ieee80211_is_nullfunc(wh->frame_control) ||
-+			    ieee80211_is_qos_nullfunc(wh->frame_control)) {
-+				dev_kfree_skb_any(done_skb);
-+				done_skb = NULL;
-+				goto next;
-+			}
-+
-+			info = IEEE80211_SKB_CB(done_skb);
-+			if (ieee80211_is_data(wh->frame_control) ||
-+			    ieee80211_is_data_qos(wh->frame_control)) {
-+				tx_ctrl = (struct pcie_tx_ctrl *)&info->status;
-+				amsdu_pkts = (struct sk_buff_head *)
-+					tx_ctrl->amsdu_pkts;
-+				if (amsdu_pkts) {
-+					pcie_tx_ack_amsdu_pkts(priv->hw, rate,
-+							       amsdu_pkts);
-+					dev_kfree_skb_any(done_skb);
-+					done_skb = NULL;
-+				} else {
-+					pcie_tx_prepare_info(priv, rate, info);
-+				}
-+			} else {
-+				pcie_tx_prepare_info(priv, 0, info);
-+			}
-+
-+			if (done_skb) {
-+				/* Remove H/W dma header */
-+				hdrlen = ieee80211_hdrlen(
-+					dma_data->wh.frame_control);
-+				memmove(dma_data->data - hdrlen,
-+					&dma_data->wh, hdrlen);
-+				skb_pull(done_skb, sizeof(*dma_data) - hdrlen);
-+				ieee80211_tx_status(priv->hw, done_skb);
-+			}
-+next:
-+			tx_hndl = tx_hndl->pnext;
-+			tx_desc = tx_hndl->pdesc;
-+			pcie_priv->fw_desc_cnt[num]--;
-+		}
-+
-+		desc->pstale_tx_hndl = tx_hndl;
-+	}
-+	spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+
-+	if (pcie_priv->is_tx_done_schedule) {
-+		pcie_mask_int(pcie_priv, MACREG_A2HRIC_BIT_TX_DONE, true);
-+		tasklet_schedule(&pcie_priv->tx_task);
-+		pcie_priv->is_tx_done_schedule = false;
-+	}
-+}
-+
-+int pcie_tx_init(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int rc;
-+	int i;
-+
-+	if (priv->chip_type == MWL8997)
-+		rc = pcie_txbd_ring_create(priv);
-+	else
-+		rc = pcie_tx_ring_alloc(priv);
-+
-+	if (rc) {
-+		wiphy_err(hw->wiphy, "allocating TX ring failed\n");
-+		return rc;
-+	}
-+
-+	rc = pcie_tx_ring_init(priv);
-+	if (rc) {
-+		pcie_tx_ring_free(priv);
-+		wiphy_err(hw->wiphy, "initializing TX ring failed\n");
-+		return rc;
-+	}
-+
-+	pcie_priv->delay_q_idx = 0;
-+	for (i = 0; i < PCIE_DELAY_FREE_Q_LIMIT; i++)
-+		pcie_priv->delay_q[i] = NULL;
-+
-+	return 0;
-+}
-+
-+void pcie_tx_deinit(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int i;
-+
-+	for (i = 0; i < PCIE_DELAY_FREE_Q_LIMIT; i++)
-+		if (pcie_priv->delay_q[i])
-+			dev_kfree_skb_any(pcie_priv->delay_q[i]);
-+
-+	pcie_tx_ring_cleanup(priv);
-+
-+	if (priv->chip_type == MWL8997)
-+		pcie_txbd_ring_delete(priv);
-+	else
-+		pcie_tx_ring_free(priv);
-+}
-+
-+void pcie_tx_skbs(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num = SYSADPT_TX_WMM_QUEUES;
-+	struct sk_buff *tx_skb;
-+
-+	spin_lock_bh(&pcie_priv->tx_desc_lock);
-+	while (num--) {
-+		while (skb_queue_len(&pcie_priv->txq[num]) > 0) {
-+			struct ieee80211_tx_info *tx_info;
-+			struct pcie_tx_ctrl *tx_ctrl;
-+
-+			if (!pcie_tx_available(priv, num))
-+				break;
-+
-+			tx_skb = skb_dequeue(&pcie_priv->txq[num]);
-+			if (!tx_skb)
-+				continue;
-+			tx_info = IEEE80211_SKB_CB(tx_skb);
-+			tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+
-+			if (tx_ctrl->tx_priority >= SYSADPT_TX_WMM_QUEUES)
-+				tx_skb = pcie_tx_do_amsdu(priv, num,
-+							  tx_skb, tx_info);
-+
-+			if (tx_skb) {
-+				if (pcie_tx_available(priv, num))
-+					pcie_tx_skb(priv, num, tx_skb);
-+				else
-+					skb_queue_head(&pcie_priv->txq[num],
-+						       tx_skb);
-+			}
-+		}
-+
-+		if (skb_queue_len(&pcie_priv->txq[num]) <
-+		    pcie_priv->txq_wake_threshold) {
-+			int queue;
-+
-+			queue = SYSADPT_TX_WMM_QUEUES - num - 1;
-+			if (ieee80211_queue_stopped(hw, queue))
-+				ieee80211_wake_queue(hw, queue);
-+		}
-+	}
-+	spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+}
-+
-+void pcie_tx_flush_amsdu(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct mwl_sta *sta_info;
-+	int i;
-+	struct mwl_amsdu_frag *amsdu_frag;
-+
-+	spin_lock(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		spin_lock(&pcie_priv->tx_desc_lock);
-+		spin_lock(&sta_info->amsdu_lock);
-+		for (i = 0; i < SYSADPT_TX_WMM_QUEUES; i++) {
-+			amsdu_frag = &sta_info->amsdu_ctrl.frag[i];
-+			if (amsdu_frag->num) {
-+				if (time_after(jiffies,
-+					       (amsdu_frag->jiffies + 1))) {
-+					if (pcie_tx_available(priv, i)) {
-+						pcie_tx_skb(priv, i,
-+							    amsdu_frag->skb);
-+						amsdu_frag->num = 0;
-+						amsdu_frag->cur_pos = NULL;
-+					}
-+				}
-+			}
-+		}
-+		spin_unlock(&sta_info->amsdu_lock);
-+		spin_unlock(&pcie_priv->tx_desc_lock);
-+	}
-+	spin_unlock(&priv->sta_lock);
-+
-+	pcie_mask_int(pcie_priv, MACREG_A2HRIC_BIT_QUE_EMPTY, true);
-+	pcie_priv->is_qe_schedule = false;
-+}
-+
-+void pcie_tx_done(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (priv->chip_type == MWL8997)
-+		pcie_pfu_tx_done(priv);
-+	else
-+		pcie_non_pfu_tx_done(priv);
-+}
-+
-+void pcie_tx_xmit(struct ieee80211_hw *hw,
-+		  struct ieee80211_tx_control *control,
-+		  struct sk_buff *skb)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int index;
-+	struct ieee80211_sta *sta;
-+	struct ieee80211_tx_info *tx_info;
-+	struct mwl_vif *mwl_vif;
-+	struct ieee80211_hdr *wh;
-+	u8 xmitcontrol;
-+	u16 qos;
-+	int txpriority;
-+	u8 tid = 0;
-+	struct mwl_ampdu_stream *stream = NULL;
-+	bool start_ba_session = false;
-+	bool mgmtframe = false;
-+	struct ieee80211_mgmt *mgmt;
-+	bool eapol_frame = false;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct ieee80211_key_conf *k_conf = NULL;
-+	int rc;
-+
-+	index = skb_get_queue_mapping(skb);
-+	sta = control->sta;
-+
-+	wh = (struct ieee80211_hdr *)skb->data;
-+	tx_info = IEEE80211_SKB_CB(skb);
-+	mwl_vif = mwl_dev_get_vif(tx_info->control.vif);
-+
-+	if (ieee80211_is_data_qos(wh->frame_control))
-+		qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
-+	else
-+		qos = 0;
-+
-+	if (ieee80211_is_mgmt(wh->frame_control)) {
-+		mgmtframe = true;
-+		mgmt = (struct ieee80211_mgmt *)skb->data;
-+	} else {
-+		u16 pkt_type;
-+		struct mwl_sta *sta_info;
-+
-+		pkt_type = be16_to_cpu(*((__be16 *)
-+			&skb->data[ieee80211_hdrlen(wh->frame_control) + 6]));
-+		if (pkt_type == ETH_P_PAE) {
-+			index = IEEE80211_AC_VO;
-+			eapol_frame = true;
-+		}
-+		if (sta) {
-+			if (mwl_vif->is_hw_crypto_enabled) {
-+				sta_info = mwl_dev_get_sta(sta);
-+				if (!sta_info->is_key_set && !eapol_frame) {
-+					dev_kfree_skb_any(skb);
-+					return;
-+				}
-+			}
-+		}
-+	}
-+
-+	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-+		wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-+		wh->seq_ctrl |= cpu_to_le16(mwl_vif->seqno);
-+		mwl_vif->seqno += 0x10;
-+	}
-+
-+	/* Setup firmware control bit fields for each frame type. */
-+	xmitcontrol = 0;
-+
-+	if (mgmtframe || ieee80211_is_ctl(wh->frame_control)) {
-+		qos = 0;
-+	} else if (ieee80211_is_data(wh->frame_control)) {
-+		qos &= ~MWL_QOS_ACK_POLICY_MASK;
-+
-+		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-+			xmitcontrol &= 0xfb;
-+			qos |= MWL_QOS_ACK_POLICY_BLOCKACK;
-+		} else {
-+			xmitcontrol |= 0x4;
-+			qos |= MWL_QOS_ACK_POLICY_NORMAL;
-+		}
-+
-+		if (is_multicast_ether_addr(wh->addr1) || eapol_frame)
-+			xmitcontrol |= EAGLE_TXD_XMITCTRL_USE_MC_RATE;
-+	}
-+
-+	k_conf = tx_info->control.hw_key;
-+
-+	/* Queue ADDBA request in the respective data queue.  While setting up
-+	 * the ampdu stream, mac80211 queues further packets for that
-+	 * particular ra/tid pair.  However, packets piled up in the hardware
-+	 * for that ra/tid pair will still go out. ADDBA request and the
-+	 * related data packets going out from different queues asynchronously
-+	 * will cause a shift in the receiver window which might result in
-+	 * ampdu packets getting dropped at the receiver after the stream has
-+	 * been setup.
-+	 */
-+	if (mgmtframe) {
-+		u16 capab;
-+
-+		if (unlikely(ieee80211_is_action(wh->frame_control) &&
-+			     mgmt->u.action.category == WLAN_CATEGORY_BACK &&
-+			     mgmt->u.action.u.addba_req.action_code ==
-+			     WLAN_ACTION_ADDBA_REQ)) {
-+			capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
-+			tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-+			index = utils_tid_to_ac(tid);
-+		}
-+
-+		if (unlikely(ieee80211_is_assoc_req(wh->frame_control)))
-+			utils_add_basic_rates(hw->conf.chandef.chan->band, skb);
-+	}
-+
-+	index = SYSADPT_TX_WMM_QUEUES - index - 1;
-+	txpriority = index;
-+
-+	if (sta && sta->ht_cap.ht_supported && !eapol_frame &&
-+	    ieee80211_is_data_qos(wh->frame_control)) {
-+		tid = qos & 0xf;
-+		pcie_tx_count_packet(sta, tid);
-+
-+		spin_lock_bh(&priv->stream_lock);
-+		stream = mwl_fwcmd_lookup_stream(hw, sta, tid);
-+
-+		if (stream) {
-+			if (stream->state == AMPDU_STREAM_ACTIVE) {
-+				if (WARN_ON(!(qos &
-+					    MWL_QOS_ACK_POLICY_BLOCKACK))) {
-+					spin_unlock_bh(&priv->stream_lock);
-+					dev_kfree_skb_any(skb);
-+					return;
-+				}
-+
-+				txpriority =
-+					(SYSADPT_TX_WMM_QUEUES + stream->idx) %
-+					TOTAL_HW_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
-+				 * our ampdu_action routine has been called
-+				 * with IEEE80211_AMPDU_TX_START to get the SSN
-+				 * for the ADDBA request.  So this packet can
-+				 * go out with no risk of sequence number
-+				 * mismatch.  No special handling is required.
-+				 */
-+			} else {
-+				/* Drop packets that would go out after the
-+				 * ADDBA request was sent but before the ADDBA
-+				 * response is received.  If we don't do this,
-+				 * the recipient would probably receive it
-+				 * after the ADDBA request with SSN 0.  This
-+				 * will cause the recipient's BA receive window
-+				 * to shift, which would cause the subsequent
-+				 * packets in the BA stream to be discarded.
-+				 * mac80211 queues our packets for us in this
-+				 * case, so this is really just a safety check.
-+				 */
-+				wiphy_warn(hw->wiphy,
-+					   "can't send packet during ADDBA\n");
-+				spin_unlock_bh(&priv->stream_lock);
-+				dev_kfree_skb_any(skb);
-+				return;
-+			}
-+		} else {
-+			if (mwl_fwcmd_ampdu_allowed(sta, tid)) {
-+				stream = mwl_fwcmd_add_stream(hw, sta, tid);
-+
-+				if (stream)
-+					start_ba_session = true;
-+			}
-+		}
-+
-+		spin_unlock_bh(&priv->stream_lock);
-+	} else {
-+		qos &= ~MWL_QOS_ACK_POLICY_MASK;
-+		qos |= MWL_QOS_ACK_POLICY_NORMAL;
-+	}
-+
-+	tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+	tx_ctrl->vif = (void *)tx_info->control.vif;
-+	tx_ctrl->sta = (void *)sta;
-+	tx_ctrl->k_conf = (void *)k_conf;
-+	tx_ctrl->amsdu_pkts = NULL;
-+	tx_ctrl->tx_priority = txpriority;
-+	tx_ctrl->type = (mgmtframe ? IEEE_TYPE_MANAGEMENT : IEEE_TYPE_DATA);
-+	tx_ctrl->qos_ctrl = qos;
-+	tx_ctrl->xmit_control = xmitcontrol;
-+
-+	if (skb_queue_len(&pcie_priv->txq[index]) > pcie_priv->txq_limit)
-+		ieee80211_stop_queue(hw, SYSADPT_TX_WMM_QUEUES - index - 1);
-+
-+	skb_queue_tail(&pcie_priv->txq[index], skb);
-+
-+	tasklet_schedule(&pcie_priv->tx_task);
-+
-+	/* Initiate the ampdu session here */
-+	if (start_ba_session) {
-+		spin_lock_bh(&priv->stream_lock);
-+		rc = mwl_fwcmd_start_stream(hw, stream);
-+		if (rc)
-+			mwl_fwcmd_remove_stream(hw, stream);
-+		else
-+			wiphy_debug(hw->wiphy, "Mac80211 start BA %pM\n",
-+				    stream->sta->addr);
-+		spin_unlock_bh(&priv->stream_lock);
-+	}
-+}
-+
-+void pcie_tx_del_pkts_via_vif(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num;
-+	struct sk_buff *skb, *tmp;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct sk_buff_head *amsdu_pkts;
-+	unsigned long flags;
-+
-+	for (num = 1; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		spin_lock_irqsave(&pcie_priv->txq[num].lock, flags);
-+		skb_queue_walk_safe(&pcie_priv->txq[num], skb, tmp) {
-+			tx_info = IEEE80211_SKB_CB(skb);
-+			tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+			if (tx_ctrl->vif == vif) {
-+				amsdu_pkts = (struct sk_buff_head *)
-+					tx_ctrl->amsdu_pkts;
-+				if (amsdu_pkts) {
-+					skb_queue_purge(amsdu_pkts);
-+					kfree(amsdu_pkts);
-+				}
-+				__skb_unlink(skb, &pcie_priv->txq[num]);
-+				dev_kfree_skb_any(skb);
-+			}
-+		}
-+		spin_unlock_irqrestore(&pcie_priv->txq[num].lock, flags);
-+	}
-+}
-+
-+void pcie_tx_del_pkts_via_sta(struct ieee80211_hw *hw,
-+			      struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num;
-+	struct sk_buff *skb, *tmp;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct sk_buff_head *amsdu_pkts;
-+	unsigned long flags;
-+
-+	for (num = 1; num < PCIE_NUM_OF_DESC_DATA; num++) {
-+		spin_lock_irqsave(&pcie_priv->txq[num].lock, flags);
-+		skb_queue_walk_safe(&pcie_priv->txq[num], skb, tmp) {
-+			tx_info = IEEE80211_SKB_CB(skb);
-+			tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+			if (tx_ctrl->sta == sta) {
-+				amsdu_pkts = (struct sk_buff_head *)
-+					tx_ctrl->amsdu_pkts;
-+				if (amsdu_pkts) {
-+					skb_queue_purge(amsdu_pkts);
-+					kfree(amsdu_pkts);
-+				}
-+				__skb_unlink(skb, &pcie_priv->txq[num]);
-+				dev_kfree_skb_any(skb);
-+			}
-+		}
-+		spin_unlock_irqrestore(&pcie_priv->txq[num].lock, flags);
-+	}
-+}
-+
-+void pcie_tx_del_ampdu_pkts(struct ieee80211_hw *hw,
-+			    struct ieee80211_sta *sta, u8 tid)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
-+	int ac, desc_num;
-+	struct mwl_amsdu_frag *amsdu_frag;
-+	struct sk_buff *skb, *tmp;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct sk_buff_head *amsdu_pkts;
-+	unsigned long flags;
-+
-+	ac = utils_tid_to_ac(tid);
-+	desc_num = SYSADPT_TX_WMM_QUEUES - ac - 1;
-+	spin_lock_irqsave(&pcie_priv->txq[desc_num].lock, flags);
-+	skb_queue_walk_safe(&pcie_priv->txq[desc_num], skb, tmp) {
-+		tx_info = IEEE80211_SKB_CB(skb);
-+		tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+		if (tx_ctrl->sta == sta) {
-+			amsdu_pkts = (struct sk_buff_head *)
-+				tx_ctrl->amsdu_pkts;
-+			if (amsdu_pkts) {
-+				skb_queue_purge(amsdu_pkts);
-+				kfree(amsdu_pkts);
-+			}
-+			__skb_unlink(skb, &pcie_priv->txq[desc_num]);
-+			dev_kfree_skb_any(skb);
-+		}
-+	}
-+	spin_unlock_irqrestore(&pcie_priv->txq[desc_num].lock, flags);
-+
-+	spin_lock_bh(&sta_info->amsdu_lock);
-+	amsdu_frag = &sta_info->amsdu_ctrl.frag[desc_num];
-+	if (amsdu_frag->num) {
-+		amsdu_frag->num = 0;
-+		amsdu_frag->cur_pos = NULL;
-+		if (amsdu_frag->skb) {
-+			tx_info = IEEE80211_SKB_CB(amsdu_frag->skb);
-+			tx_ctrl = (struct pcie_tx_ctrl *)&tx_info->status;
-+			amsdu_pkts = (struct sk_buff_head *)
-+				tx_ctrl->amsdu_pkts;
-+			if (amsdu_pkts) {
-+				skb_queue_purge(amsdu_pkts);
-+				kfree(amsdu_pkts);
-+			}
-+			dev_kfree_skb_any(amsdu_frag->skb);
-+		}
-+	}
-+	spin_unlock_bh(&sta_info->amsdu_lock);
-+}
-+
-+void pcie_tx_del_sta_amsdu_pkts(struct ieee80211_hw *hw,
-+				struct ieee80211_sta *sta)
-+{
-+	struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
-+	int num;
-+	struct mwl_amsdu_frag *amsdu_frag;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl *tx_ctrl;
-+	struct sk_buff_head *amsdu_pkts;
-+
-+	spin_lock_bh(&sta_info->amsdu_lock);
-+	for (num = 0; num < SYSADPT_TX_WMM_QUEUES; num++) {
-+		amsdu_frag = &sta_info->amsdu_ctrl.frag[num];
-+		if (amsdu_frag->num) {
-+			amsdu_frag->num = 0;
-+			amsdu_frag->cur_pos = NULL;
-+			if (amsdu_frag->skb) {
-+				tx_info = IEEE80211_SKB_CB(amsdu_frag->skb);
-+				tx_ctrl = (struct pcie_tx_ctrl *)
-+					&tx_info->status;
-+				amsdu_pkts = (struct sk_buff_head *)
-+					tx_ctrl->amsdu_pkts;
-+				if (amsdu_pkts) {
-+					skb_queue_purge(amsdu_pkts);
-+					kfree(amsdu_pkts);
-+				}
-+				dev_kfree_skb_any(amsdu_frag->skb);
-+			}
-+		}
-+	}
-+	spin_unlock_bh(&sta_info->amsdu_lock);
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.h
-new file mode 100644
-index 000000000000..c233ba1aaa9d
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx.h
-@@ -0,0 +1,38 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines transmit related functions. */
-+
-+#ifndef _TX_H_
-+#define _TX_H_
-+
-+int pcie_tx_init(struct ieee80211_hw *hw);
-+void pcie_tx_deinit(struct ieee80211_hw *hw);
-+void pcie_tx_skbs(unsigned long data);
-+void pcie_tx_done(unsigned long data);
-+void pcie_tx_flush_amsdu(unsigned long data);
-+void pcie_tx_xmit(struct ieee80211_hw *hw,
-+		  struct ieee80211_tx_control *control,
-+		  struct sk_buff *skb);
-+void pcie_tx_del_pkts_via_vif(struct ieee80211_hw *hw,
-+			      struct ieee80211_vif *vif);
-+void pcie_tx_del_pkts_via_sta(struct ieee80211_hw *hw,
-+			      struct ieee80211_sta *sta);
-+void pcie_tx_del_ampdu_pkts(struct ieee80211_hw *hw,
-+			    struct ieee80211_sta *sta, u8 tid);
-+void pcie_tx_del_sta_amsdu_pkts(struct ieee80211_hw *hw,
-+				struct ieee80211_sta *sta);
-+
-+#endif /* _TX_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.c b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.c
-new file mode 100644
-index 000000000000..6758cde363c6
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.c
-@@ -0,0 +1,693 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements transmit related functions for new data
-+ * path.
-+ */
-+
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/fwcmd.h"
-+#include "hif/pcie/dev.h"
-+#include "hif/pcie/tx_ndp.h"
-+
-+#define MAX_NUM_TX_RING_BYTES   (MAX_NUM_TX_DESC * \
-+				sizeof(struct pcie_tx_desc_ndp))
-+#define MAX_NUM_TX_RING_DONE_BYTES (MAX_NUM_TX_DESC * \
-+				sizeof(struct tx_ring_done))
-+#define QUEUE_STAOFFSET         ((SYSADPT_NUM_OF_AP - 1) + \
-+				SYSADPT_NUM_OF_CLIENT)
-+#define PROBE_RESPONSE_TXQNUM   ((SYSADPT_MAX_STA_SC4 + SYSADPT_NUM_OF_AP + \
-+				SYSADPT_NUM_OF_CLIENT) * SYSADPT_MAX_TID)
-+#define MGMT_TXQNUM             ((PROBE_RESPONSE_TXQNUM + 1))
-+#define TXDONE_THRESHOLD        4
-+
-+#define TX_CTRL_TYPE_DATA       BIT(0)
-+#define TX_CTRL_EAPOL           BIT(1)
-+#define TX_CTRL_TCP_ACK         BIT(2)
-+
-+/* Transmission information to transmit a socket buffer.
-+ */
-+struct pcie_tx_ctrl_ndp {
-+	u16 tx_que_priority;
-+	u8 hdrlen;
-+	u8 flags;
-+	u32 rate;
-+	u32 tcp_dst_src;
-+	u32 tcp_sn;
-+} __packed;
-+
-+static int pcie_tx_ring_alloc_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	u8 *mem;
-+
-+	mem = dma_alloc_coherent(priv->dev,
-+				 MAX_NUM_TX_RING_BYTES,
-+				 &desc->pphys_tx_ring,
-+				 GFP_KERNEL);
-+	if (!mem)
-+		goto err_no_mem;
-+	desc->ptx_ring = (struct pcie_tx_desc_ndp *)mem;
-+	memset(desc->ptx_ring, 0x00, MAX_NUM_TX_RING_BYTES);
-+
-+	mem = dma_alloc_coherent(priv->dev,
-+				 MAX_NUM_TX_RING_DONE_BYTES,
-+				 &desc->pphys_tx_ring_done,
-+				 GFP_KERNEL);
-+	if (!mem)
-+		goto err_no_mem;
-+	desc->ptx_ring_done = (struct tx_ring_done *)mem;
-+	memset(desc->ptx_ring_done, 0x00, MAX_NUM_TX_RING_DONE_BYTES);
-+
-+	mem = dma_alloc_coherent(priv->dev,
-+				 DEFAULT_ACNT_RING_SIZE,
-+				 &desc->pphys_acnt_ring,
-+				 GFP_KERNEL);
-+	if (!mem)
-+		goto err_no_mem;
-+	desc->pacnt_ring = (u8 *)mem;
-+	memset(desc->pacnt_ring, 0x00, DEFAULT_ACNT_RING_SIZE);
-+
-+	desc->pacnt_buf = kzalloc(DEFAULT_ACNT_RING_SIZE, GFP_KERNEL);
-+	if (!desc->pacnt_buf)
-+		goto err_no_mem;
-+	desc->acnt_ring_size = DEFAULT_ACNT_RING_SIZE;
-+
-+	return 0;
-+
-+err_no_mem:
-+
-+	wiphy_err(priv->hw->wiphy, "cannot alloc mem\n");
-+
-+	return -ENOMEM;
-+}
-+
-+static int pcie_tx_ring_init_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	int i;
-+
-+	for (i = 0; i < PCIE_NUM_OF_DESC_DATA; i++)
-+		skb_queue_head_init(&pcie_priv->txq[i]);
-+
-+	if (!desc->ptx_ring) {
-+		for (i = 0; i < MAX_NUM_TX_DESC; i++)
-+			desc->ptx_ring[i].user = cpu_to_le32(i);
-+		desc->tx_desc_busy_cnt = 0;
-+	}
-+
-+	return 0;
-+}
-+
-+static void pcie_tx_ring_cleanup_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	struct sk_buff *tx_skb;
-+	int i;
-+
-+	for (i = 0; i < PCIE_NUM_OF_DESC_DATA; i++)
-+		skb_queue_purge(&pcie_priv->txq[i]);
-+
-+	for (i = 0; i < MAX_TX_RING_SEND_SIZE; i++) {
-+		tx_skb = desc->tx_vbuflist[i];
-+		if (tx_skb) {
-+			pci_unmap_single(pcie_priv->pdev,
-+					 desc->pphys_tx_buflist[i],
-+					 tx_skb->len,
-+					 PCI_DMA_TODEVICE);
-+			dev_kfree_skb_any(tx_skb);
-+			desc->pphys_tx_buflist[i] = 0;
-+			desc->tx_vbuflist[i] = NULL;
-+		}
-+	}
-+	desc->tx_sent_tail = 0;
-+	desc->tx_sent_head = 0;
-+	desc->tx_done_tail = 0;
-+	desc->tx_vbuflist_idx = 0;
-+	desc->tx_desc_busy_cnt = 0;
-+}
-+
-+static void pcie_tx_ring_free_ndp(struct mwl_priv *priv)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+
-+	if (desc->ptx_ring) {
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_TX_RING_BYTES,
-+				  desc->ptx_ring,
-+				  desc->pphys_tx_ring);
-+		desc->ptx_ring = NULL;
-+	}
-+
-+	if (desc->ptx_ring_done) {
-+		dma_free_coherent(priv->dev,
-+				  MAX_NUM_TX_RING_DONE_BYTES,
-+				  desc->ptx_ring_done,
-+				  desc->pphys_tx_ring_done);
-+		desc->prx_ring_done = NULL;
-+	}
-+
-+	if (desc->pacnt_ring) {
-+		dma_free_coherent(priv->dev,
-+				  DEFAULT_ACNT_RING_SIZE,
-+				  desc->pacnt_ring,
-+				  desc->pphys_acnt_ring);
-+		desc->pacnt_ring = NULL;
-+	}
-+
-+	kfree(desc->pacnt_buf);
-+}
-+
-+static inline u32 pcie_tx_set_skb(struct mwl_priv *priv, struct sk_buff *skb,
-+				  dma_addr_t dma)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	u32 index = desc->tx_vbuflist_idx;
-+
-+	while (desc->tx_vbuflist[index])
-+		index = (index + 1) % MAX_TX_RING_SEND_SIZE;
-+
-+	desc->tx_vbuflist_idx = (index + 1) % MAX_TX_RING_SEND_SIZE;
-+	desc->pphys_tx_buflist[index] = dma;
-+	desc->tx_vbuflist[index] = skb;
-+
-+	return index;
-+}
-+
-+static inline int pcie_tx_skb_ndp(struct mwl_priv *priv,
-+				  struct sk_buff *tx_skb)
-+{
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	u32 tx_send_tail;
-+	u32 tx_send_head_new;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl_ndp *tx_ctrl;
-+	struct pcie_tx_desc_ndp *pnext_tx_desc;
-+	struct ieee80211_hdr *wh;
-+	u32 ctrl = 0;
-+	dma_addr_t dma;
-+
-+	spin_lock_bh(&pcie_priv->tx_desc_lock);
-+
-+	tx_send_tail = desc->tx_sent_tail;
-+	tx_send_head_new = desc->tx_sent_head;
-+
-+	if (((tx_send_head_new + 1) & (MAX_NUM_TX_DESC-1)) == tx_send_tail) {
-+		/* Update the tx_send_tail */
-+		tx_send_tail = readl(pcie_priv->iobase1 +
-+				     MACREG_REG_TXSEDNTAIL);
-+		desc->tx_sent_tail = tx_send_tail;
-+
-+		if (((tx_send_head_new + 1) & (MAX_NUM_TX_DESC-1)) ==
-+		    tx_send_tail) {
-+			spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+			return -EAGAIN;
-+		}
-+	}
-+
-+	tx_info = IEEE80211_SKB_CB(tx_skb);
-+	tx_ctrl = (struct pcie_tx_ctrl_ndp *)tx_info->status.status_driver_data;
-+	pnext_tx_desc = &desc->ptx_ring[tx_send_head_new];
-+
-+	if (tx_ctrl->flags & TX_CTRL_TYPE_DATA) {
-+		wh = (struct ieee80211_hdr *)tx_skb->data;
-+
-+		skb_pull(tx_skb, tx_ctrl->hdrlen);
-+		ether_addr_copy(pnext_tx_desc->u.sa,
-+				ieee80211_get_SA(wh));
-+		ether_addr_copy(pnext_tx_desc->u.da,
-+				ieee80211_get_DA(wh));
-+
-+		if (tx_ctrl->flags & TX_CTRL_EAPOL)
-+			ctrl = TXRING_CTRL_TAG_EAP << TXRING_CTRL_TAG_SHIFT;
-+		if (tx_ctrl->flags & TX_CTRL_TCP_ACK) {
-+			pnext_tx_desc->tcp_dst_src =
-+				cpu_to_le32(tx_ctrl->tcp_dst_src);
-+			pnext_tx_desc->tcp_sn = cpu_to_le32(tx_ctrl->tcp_sn);
-+			ctrl = TXRING_CTRL_TAG_TCP_ACK << TXRING_CTRL_TAG_SHIFT;
-+		}
-+		ctrl |= (((tx_ctrl->tx_que_priority & TXRING_CTRL_QID_MASK) <<
-+			TXRING_CTRL_QID_SHIFT) |
-+			((tx_skb->len & TXRING_CTRL_LEN_MASK) <<
-+			TXRING_CTRL_LEN_SHIFT));
-+	} else {
-+		/* Assigning rate code; use legacy 6mbps rate. */
-+		pnext_tx_desc->u.rate_code = cpu_to_le16(RATECODE_TYPE_LEGACY +
-+			(0 << RATECODE_MCS_SHIFT) + RATECODE_BW_20MHZ);
-+		pnext_tx_desc->u.max_retry = 5;
-+
-+		ctrl = (((tx_ctrl->tx_que_priority & TXRING_CTRL_QID_MASK) <<
-+			TXRING_CTRL_QID_SHIFT) |
-+			(((tx_skb->len - sizeof(struct pcie_dma_data)) &
-+			TXRING_CTRL_LEN_MASK) << TXRING_CTRL_LEN_SHIFT) |
-+			(TXRING_CTRL_TAG_MGMT << TXRING_CTRL_TAG_SHIFT));
-+	}
-+
-+	dma = pci_map_single(pcie_priv->pdev, tx_skb->data,
-+			     tx_skb->len, PCI_DMA_TODEVICE);
-+	if (pci_dma_mapping_error(pcie_priv->pdev, dma)) {
-+		dev_kfree_skb_any(tx_skb);
-+		wiphy_err(priv->hw->wiphy,
-+			  "failed to map pci memory!\n");
-+		spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+		return -EIO;
-+	}
-+
-+	pnext_tx_desc->data = cpu_to_le32(dma);
-+	pnext_tx_desc->ctrl = cpu_to_le32(ctrl);
-+	pnext_tx_desc->user = cpu_to_le32(pcie_tx_set_skb(priv, tx_skb, dma));
-+
-+	if ((tx_ctrl->flags & TX_CTRL_TYPE_DATA) &&
-+	    (tx_ctrl->rate != 0)) {
-+		skb_push(tx_skb, tx_ctrl->hdrlen);
-+		skb_get(tx_skb);
-+		pcie_tx_prepare_info(priv, tx_ctrl->rate, tx_info);
-+		tx_ctrl->flags |= TX_CTRL_TYPE_DATA;
-+		ieee80211_tx_status(priv->hw, tx_skb);
-+	}
-+
-+	if (++tx_send_head_new >= MAX_NUM_TX_DESC)
-+		tx_send_head_new = 0;
-+	desc->tx_sent_head = tx_send_head_new;
-+	wmb(); /*Data Memory Barrier*/
-+	writel(tx_send_head_new, pcie_priv->iobase1 + MACREG_REG_TXSENDHEAD);
-+	desc->tx_desc_busy_cnt++;
-+
-+	spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+
-+	return 0;
-+}
-+
-+static inline void pcie_tx_check_tcp_ack(struct sk_buff *tx_skb,
-+					 struct pcie_tx_ctrl_ndp *tx_ctrl)
-+{
-+	struct iphdr *iph;
-+	struct tcphdr *tcph;
-+
-+	if (tx_ctrl->flags & TX_CTRL_TYPE_DATA) {
-+		iph = (struct iphdr *)(tx_skb->data + tx_ctrl->hdrlen + 8);
-+		tcph = (struct tcphdr *)((u8 *)iph + (iph->ihl * 4));
-+		if ((iph->protocol == IPPROTO_TCP) &&
-+		    (tx_skb->protocol == htons(ETH_P_IP))) {
-+			if ((tcph->ack == 1) && (ntohs(iph->tot_len) ==
-+			    (iph->ihl * 4 + tcph->doff * 4))) {
-+				if (tcph->syn || tcph->fin)
-+					return;
-+
-+				tx_ctrl->flags |= TX_CTRL_TCP_ACK;
-+				tx_ctrl->tcp_dst_src = ntohs(tcph->source) |
-+					(ntohs(tcph->dest) << 16);
-+				tx_ctrl->tcp_sn = ntohl(tcph->ack_seq);
-+			}
-+		}
-+	}
-+}
-+
-+int pcie_tx_init_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct sk_buff skb;
-+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(&skb);
-+	int rc;
-+
-+	if (sizeof(struct pcie_tx_ctrl_ndp) >
-+	    sizeof(tx_info->status.status_driver_data)) {
-+		wiphy_err(hw->wiphy, "driver data is not enough: %d (%d)\n",
-+			  sizeof(struct pcie_tx_ctrl_ndp),
-+			  sizeof(tx_info->status.status_driver_data));
-+		return -ENOMEM;
-+	}
-+
-+	rc = pcie_tx_ring_alloc_ndp(priv);
-+	if (rc) {
-+		pcie_tx_ring_free_ndp(priv);
-+		wiphy_err(hw->wiphy, "allocating TX ring failed\n");
-+		return rc;
-+	}
-+
-+	rc = pcie_tx_ring_init_ndp(priv);
-+	if (rc) {
-+		pcie_tx_ring_free_ndp(priv);
-+		wiphy_err(hw->wiphy, "initializing TX ring failed\n");
-+		return rc;
-+	}
-+
-+	return 0;
-+}
-+
-+void pcie_tx_deinit_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	pcie_tx_ring_cleanup_ndp(priv);
-+	pcie_tx_ring_free_ndp(priv);
-+}
-+
-+void pcie_tx_skbs_ndp(unsigned long data)
-+{
-+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	int num = SYSADPT_TX_WMM_QUEUES;
-+	struct sk_buff *tx_skb;
-+	int rc;
-+
-+	while (num--) {
-+		while (skb_queue_len(&pcie_priv->txq[num]) > 0) {
-+			if (pcie_priv->desc_data_ndp.tx_desc_busy_cnt >=
-+			    (MAX_TX_RING_SEND_SIZE - 1)) {
-+				pcie_tx_done_ndp(hw);
-+				break;
-+			}
-+
-+			tx_skb = skb_dequeue(&pcie_priv->txq[num]);
-+
-+			rc = pcie_tx_skb_ndp(priv, tx_skb);
-+			if (rc) {
-+				pcie_tx_done_ndp(hw);
-+				if (rc == -EAGAIN)
-+					skb_queue_head(&pcie_priv->txq[num],
-+						       tx_skb);
-+				break;
-+			}
-+
-+			if (++pcie_priv->tx_done_cnt > TXDONE_THRESHOLD) {
-+				pcie_tx_done_ndp(hw);
-+				pcie_priv->tx_done_cnt = 0;
-+			}
-+		}
-+
-+		if (skb_queue_len(&pcie_priv->txq[num]) <
-+		    pcie_priv->txq_wake_threshold) {
-+			int queue;
-+
-+			queue = SYSADPT_TX_WMM_QUEUES - num - 1;
-+			if (ieee80211_queue_stopped(hw, queue))
-+				ieee80211_wake_queue(hw, queue);
-+		}
-+	}
-+
-+	pcie_priv->is_tx_schedule = false;
-+}
-+
-+void pcie_tx_done_ndp(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct pcie_desc_data_ndp *desc = &pcie_priv->desc_data_ndp;
-+	u32 tx_done_head, tx_done_tail;
-+	struct tx_ring_done *ptx_ring_done;
-+	u32 index;
-+	struct sk_buff *skb;
-+	struct ieee80211_tx_info *tx_info;
-+	struct pcie_tx_ctrl_ndp *tx_ctrl;
-+	struct pcie_dma_data *dma_data;
-+	u16 hdrlen;
-+
-+	spin_lock_bh(&pcie_priv->tx_desc_lock);
-+
-+	tx_done_head = readl(pcie_priv->iobase1 +
-+			     MACREG_REG_TXDONEHEAD);
-+	tx_done_tail = desc->tx_done_tail & (MAX_TX_RING_DONE_SIZE - 1);
-+	tx_done_head &= (MAX_TX_RING_DONE_SIZE - 1);
-+
-+	while (tx_done_head != tx_done_tail) {
-+		ptx_ring_done = &desc->ptx_ring_done[tx_done_tail];
-+
-+		index = le32_to_cpu(ptx_ring_done->user);
-+		ptx_ring_done->user = 0;
-+		if (index >= MAX_TX_RING_SEND_SIZE) {
-+			wiphy_err(hw->wiphy,
-+				  "corruption for index of buffer\n");
-+			break;
-+		}
-+		skb = desc->tx_vbuflist[index];
-+		if (!skb) {
-+			wiphy_err(hw->wiphy,
-+				  "buffer is NULL for tx done ring\n");
-+			break;
-+		}
-+		pci_unmap_single(pcie_priv->pdev,
-+				 desc->pphys_tx_buflist[index],
-+				 skb->len,
-+				 PCI_DMA_TODEVICE);
-+		desc->pphys_tx_buflist[index] = 0;
-+		desc->tx_vbuflist[index] = NULL;
-+
-+		tx_info = IEEE80211_SKB_CB(skb);
-+		tx_ctrl = (struct pcie_tx_ctrl_ndp *)
-+			tx_info->status.status_driver_data;
-+
-+		if (tx_ctrl->flags & TX_CTRL_TYPE_DATA) {
-+			dev_kfree_skb_any(skb);
-+			goto bypass_ack;
-+		} else {
-+			/* Remove H/W dma header */
-+			dma_data = (struct pcie_dma_data *)skb->data;
-+
-+			if (ieee80211_is_assoc_resp(
-+			    dma_data->wh.frame_control) ||
-+			    ieee80211_is_reassoc_resp(
-+			    dma_data->wh.frame_control)) {
-+				dev_kfree_skb_any(skb);
-+				goto bypass_ack;
-+			}
-+			hdrlen = ieee80211_hdrlen(
-+				dma_data->wh.frame_control);
-+			memmove(dma_data->data - hdrlen,
-+				&dma_data->wh, hdrlen);
-+			skb_pull(skb, sizeof(*dma_data) - hdrlen);
-+		}
-+
-+		pcie_tx_prepare_info(priv, 0, tx_info);
-+		ieee80211_tx_status(hw, skb);
-+
-+bypass_ack:
-+		if (++tx_done_tail >= MAX_TX_RING_DONE_SIZE)
-+			tx_done_tail = 0;
-+		desc->tx_desc_busy_cnt--;
-+	}
-+
-+	writel(tx_done_tail, pcie_priv->iobase1 +
-+	       MACREG_REG_TXDONETAIL);
-+	desc->tx_done_tail = tx_done_tail;
-+
-+	spin_unlock_bh(&pcie_priv->tx_desc_lock);
-+}
-+
-+void pcie_tx_xmit_ndp(struct ieee80211_hw *hw,
-+		      struct ieee80211_tx_control *control,
-+		      struct sk_buff *skb)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct pcie_priv *pcie_priv = priv->hif.priv;
-+	struct ieee80211_tx_info *tx_info;
-+	struct ieee80211_key_conf *k_conf;
-+	struct mwl_vif *mwl_vif;
-+	int index;
-+	struct ieee80211_sta *sta;
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_hdr *wh;
-+	u8 *da;
-+	u16 qos;
-+	u8 tid = 0;
-+	struct mwl_ampdu_stream *stream = NULL;
-+	u16 tx_que_priority;
-+	bool mgmtframe = false;
-+	struct ieee80211_mgmt *mgmt;
-+	bool eapol_frame = false;
-+	bool start_ba_session = false;
-+	struct pcie_tx_ctrl_ndp *tx_ctrl;
-+
-+	tx_info = IEEE80211_SKB_CB(skb);
-+	k_conf = tx_info->control.hw_key;
-+	mwl_vif = mwl_dev_get_vif(tx_info->control.vif);
-+	index = skb_get_queue_mapping(skb);
-+	sta = control->sta;
-+	sta_info = sta ? mwl_dev_get_sta(sta) : NULL;
-+
-+	wh = (struct ieee80211_hdr *)skb->data;
-+
-+	if (ieee80211_is_data_qos(wh->frame_control))
-+		qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
-+	else
-+		qos = 0xFFFF;
-+
-+	if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
-+		index = IEEE80211_AC_VO;
-+		eapol_frame = true;
-+	}
-+
-+	if (ieee80211_is_mgmt(wh->frame_control)) {
-+		mgmtframe = true;
-+		mgmt = (struct ieee80211_mgmt *)skb->data;
-+	}
-+
-+	if (mgmtframe) {
-+		u16 capab;
-+
-+		if (unlikely(ieee80211_is_action(wh->frame_control) &&
-+			     mgmt->u.action.category == WLAN_CATEGORY_BACK &&
-+			     mgmt->u.action.u.addba_req.action_code ==
-+			     WLAN_ACTION_ADDBA_REQ)) {
-+			capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
-+			tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-+			index = utils_tid_to_ac(tid);
-+		}
-+
-+		if (unlikely(ieee80211_is_assoc_req(wh->frame_control)))
-+			utils_add_basic_rates(hw->conf.chandef.chan->band, skb);
-+
-+		if (ieee80211_is_probe_req(wh->frame_control) ||
-+		    ieee80211_is_probe_resp(wh->frame_control))
-+			tx_que_priority = PROBE_RESPONSE_TXQNUM;
-+		else {
-+			if ((
-+			    (mwl_vif->macid == SYSADPT_NUM_OF_AP) &&
-+			    (!ieee80211_has_protected(wh->frame_control) ||
-+			    (ieee80211_has_protected(wh->frame_control) &&
-+			    ieee80211_is_auth(wh->frame_control)))
-+			    ) ||
-+			    !sta ||
-+			    ieee80211_is_auth(wh->frame_control) ||
-+			    ieee80211_is_assoc_req(wh->frame_control) ||
-+			    ieee80211_is_assoc_resp(wh->frame_control))
-+				tx_que_priority = MGMT_TXQNUM;
-+			else {
-+				if (is_multicast_ether_addr(wh->addr1) &&
-+				    (mwl_vif->macid != SYSADPT_NUM_OF_AP))
-+					tx_que_priority = mwl_vif->macid *
-+						SYSADPT_MAX_TID;
-+				else
-+					tx_que_priority = SYSADPT_MAX_TID *
-+						(sta_info->stnid +
-+						QUEUE_STAOFFSET) + 6;
-+			}
-+		}
-+
-+		if (ieee80211_is_assoc_resp(wh->frame_control) ||
-+		    ieee80211_is_reassoc_resp(wh->frame_control)) {
-+			struct sk_buff *ack_skb;
-+			struct ieee80211_tx_info *ack_info;
-+
-+			ack_skb = skb_copy(skb, GFP_ATOMIC);
-+			ack_info = IEEE80211_SKB_CB(ack_skb);
-+			pcie_tx_prepare_info(priv, 0, ack_info);
-+			ieee80211_tx_status(hw, ack_skb);
-+		}
-+
-+		pcie_tx_encapsulate_frame(priv, skb, k_conf, NULL);
-+	} else {
-+		tid = qos & 0x7;
-+		if (sta && sta->ht_cap.ht_supported && !eapol_frame &&
-+		    qos != 0xFFFF) {
-+			pcie_tx_count_packet(sta, tid);
-+			spin_lock_bh(&priv->stream_lock);
-+			stream = mwl_fwcmd_lookup_stream(hw, sta, tid);
-+			if (!stream ||
-+			    stream->state == AMPDU_STREAM_IN_PROGRESS) {
-+				wiphy_warn(hw->wiphy,
-+					   "can't send packet during ADDBA\n");
-+				spin_unlock_bh(&priv->stream_lock);
-+				dev_kfree_skb_any(skb);
-+				return;
-+			}
-+			if ((stream->state == AMPDU_NO_STREAM) &&
-+			    mwl_fwcmd_ampdu_allowed(sta, tid)) {
-+				stream = mwl_fwcmd_add_stream(hw, sta, tid);
-+				if (stream)
-+					start_ba_session = true;
-+			}
-+			spin_unlock_bh(&priv->stream_lock);
-+		}
-+
-+		da = ieee80211_get_DA(wh);
-+
-+		if (is_multicast_ether_addr(da)
-+		    && (mwl_vif->macid != SYSADPT_NUM_OF_AP)) {
-+
-+			tx_que_priority = mwl_vif->macid * SYSADPT_MAX_TID;
-+
-+			if (da[ETH_ALEN - 1] == 0xff)
-+				tx_que_priority += 7;
-+
-+			if (ieee80211_has_a4(wh->frame_control)) {
-+				if (sta && sta_info->wds)
-+					tx_que_priority = SYSADPT_MAX_TID *
-+						(sta_info->stnid +
-+						QUEUE_STAOFFSET) + 6;
-+			}
-+		} else {
-+			if (sta) {
-+				if (!eapol_frame)
-+					tx_que_priority = SYSADPT_MAX_TID *
-+						(sta_info->stnid +
-+						QUEUE_STAOFFSET) +
-+						((qos == 0xFFFF) ? 0 : tid);
-+				else
-+					tx_que_priority = SYSADPT_MAX_TID *
-+						(sta_info->stnid +
-+						QUEUE_STAOFFSET) +
-+						((qos == 0xFFFF) ? 0 : 6);
-+			} else
-+				tx_que_priority = 0;
-+		}
-+	}
-+
-+	index = SYSADPT_TX_WMM_QUEUES - index - 1;
-+
-+	tx_ctrl = (struct pcie_tx_ctrl_ndp *)tx_info->status.status_driver_data;
-+	tx_ctrl->tx_que_priority = tx_que_priority;
-+	tx_ctrl->hdrlen = ieee80211_hdrlen(wh->frame_control);
-+	tx_ctrl->flags = 0;
-+	if (!mgmtframe)
-+		tx_ctrl->flags |= TX_CTRL_TYPE_DATA;
-+	if (eapol_frame)
-+		tx_ctrl->flags |= TX_CTRL_EAPOL;
-+	tx_ctrl->rate = sta ? sta_info->tx_rate_info : 0;
-+	if (ieee80211_is_nullfunc(wh->frame_control) ||
-+	    ieee80211_is_qos_nullfunc(wh->frame_control))
-+		tx_ctrl->rate = 0;
-+	pcie_tx_check_tcp_ack(skb, tx_ctrl);
-+
-+	if (skb_queue_len(&pcie_priv->txq[index]) > pcie_priv->txq_limit)
-+		ieee80211_stop_queue(hw, SYSADPT_TX_WMM_QUEUES - index - 1);
-+
-+	skb_queue_tail(&pcie_priv->txq[index], skb);
-+
-+	if (!pcie_priv->is_tx_schedule) {
-+		tasklet_schedule(&pcie_priv->tx_task);
-+		pcie_priv->is_tx_schedule = true;
-+	}
-+
-+	/* Initiate the ampdu session here */
-+	if (start_ba_session) {
-+		spin_lock_bh(&priv->stream_lock);
-+		if (mwl_fwcmd_start_stream(hw, stream))
-+			mwl_fwcmd_remove_stream(hw, stream);
-+		spin_unlock_bh(&priv->stream_lock);
-+	}
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.h b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.h
-new file mode 100644
-index 000000000000..2ad5f381b9ee
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hif/pcie/tx_ndp.h
-@@ -0,0 +1,30 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines transmit related functions for new data path.
-+ */
-+
-+#ifndef _TX_NDP_H_
-+#define _TX_NDP_H_
-+
-+int pcie_tx_init_ndp(struct ieee80211_hw *hw);
-+void pcie_tx_deinit_ndp(struct ieee80211_hw *hw);
-+void pcie_tx_skbs_ndp(unsigned long data);
-+void pcie_tx_done_ndp(struct ieee80211_hw *hw);
-+void pcie_tx_xmit_ndp(struct ieee80211_hw *hw,
-+		      struct ieee80211_tx_control *control,
-+		      struct sk_buff *skb);
-+
-+#endif /* _TX_NDP_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hostapd/700-interoperability-workaround-for-80+80-and-160-MHz-channels b/drivers/net/wireless/marvell/mwlwifi/hostapd/700-interoperability-workaround-for-80+80-and-160-MHz-channels
-new file mode 100644
-index 000000000000..adadd2e4d8d4
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hostapd/700-interoperability-workaround-for-80+80-and-160-MHz-channels
-@@ -0,0 +1,32 @@
-+diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
-+index 3236016..e923094 100644
-+--- a/src/ap/ieee802_11_vht.c
-++++ b/src/ap/ieee802_11_vht.c
-+@@ -82,6 +82,27 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
-+ 
-+ 	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
-+ 
-++	if (hapd->iconf->vht_oper_chwidth == 2) {
-++		/*
-++		 * Convert 160 MHz channel width to new style as interop
-++		 * workaround.
-++		 */
-++		oper->vht_op_info_chwidth = 1;
-++		oper->vht_op_info_chan_center_freq_seg1_idx =
-++			oper->vht_op_info_chan_center_freq_seg0_idx;
-++		if (hapd->iconf->channel <
-++		    hapd->iconf->vht_oper_centr_freq_seg0_idx)
-++				oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
-++			else
-++				oper->vht_op_info_chan_center_freq_seg0_idx += 8;
-++	} else if (hapd->iconf->vht_oper_chwidth == 3) {
-++		/*
-++		 * Convert 80+80 MHz channel width to new style as interop
-++		 * workaround.
-++		 */
-++		oper->vht_op_info_chwidth = 1;
-++	}
-++
-+ 	/* VHT Basic MCS set comes from hw */
-+ 	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
-+ 	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
-diff --git a/drivers/net/wireless/marvell/mwlwifi/hostapd/README b/drivers/net/wireless/marvell/mwlwifi/hostapd/README
-new file mode 100644
-index 000000000000..a5fb2b68d3d3
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/hostapd/README
-@@ -0,0 +1,26 @@
-+700-interoperability-workaround-for-80+80-and-160-MHz-channels: 
-+
-+patch for OpenWrt hostapd package 2016-01-15 for following commit
-+(move it to package/network/services/hostapd/patches).
-+
-+Note: After hostapd package 2016-06-15, this commit is already included.
-+
-+commit 03a72eacda5d9a1837a74387081596a0d5466ec1
-+Author: Jouni Malinen <jouni@qca.qualcomm.com>
-+Date:   Thu Dec 17 18:39:19 2015 +0200
-+
-+    VHT: Add an interoperability workaround for 80+80 and 160 MHz channels
-+
-+    Number of deployed 80 MHz capable VHT stations that do not support 80+80
-+    and 160 MHz bandwidths seem to misbehave when trying to connect to an AP
-+    that advertises 80+80 or 160 MHz channel bandwidth in the VHT Operation
-+    element. To avoid such issues with deployed devices, modify the design
-+    based on newly proposed IEEE 802.11 standard changes.
-+
-+    This allows poorly implemented VHT 80 MHz stations to connect with the
-+    AP in 80 MHz mode. 80+80 and 160 MHz capable stations need to support
-+    the new workaround mechanism to allow full bandwidth to be used.
-+    However, there are more or less no impacted station with 80+80/160
-+    capability deployed.
-+
-+    Signed-off-by: Jouni Malinen jouni@qca.qualcomm.com
-diff --git a/drivers/net/wireless/marvell/mwlwifi/mac80211.c b/drivers/net/wireless/marvell/mwlwifi/mac80211.c
-new file mode 100644
-index 000000000000..725dec0f604b
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/mac80211.c
-@@ -0,0 +1,933 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements mac80211 related functions. */
-+
-+#include <linux/etherdevice.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/fwcmd.h"
-+#include "hif/hif-ops.h"
-+
-+#define MAX_AMPDU_ATTEMPTS  5
-+
-+static const struct ieee80211_rate mwl_rates_24[] = {
-+	{ .bitrate = 10, .hw_value = 2, },
-+	{ .bitrate = 20, .hw_value = 4, },
-+	{ .bitrate = 55, .hw_value = 11, },
-+	{ .bitrate = 110, .hw_value = 22, },
-+	{ .bitrate = 220, .hw_value = 44, },
-+	{ .bitrate = 60, .hw_value = 12, },
-+	{ .bitrate = 90, .hw_value = 18, },
-+	{ .bitrate = 120, .hw_value = 24, },
-+	{ .bitrate = 180, .hw_value = 36, },
-+	{ .bitrate = 240, .hw_value = 48, },
-+	{ .bitrate = 360, .hw_value = 72, },
-+	{ .bitrate = 480, .hw_value = 96, },
-+	{ .bitrate = 540, .hw_value = 108, },
-+};
-+
-+static const struct ieee80211_rate mwl_rates_50[] = {
-+	{ .bitrate = 60, .hw_value = 12, },
-+	{ .bitrate = 90, .hw_value = 18, },
-+	{ .bitrate = 120, .hw_value = 24, },
-+	{ .bitrate = 180, .hw_value = 36, },
-+	{ .bitrate = 240, .hw_value = 48, },
-+	{ .bitrate = 360, .hw_value = 72, },
-+	{ .bitrate = 480, .hw_value = 96, },
-+	{ .bitrate = 540, .hw_value = 108, },
-+};
-+
-+static void mwl_get_rateinfo(struct mwl_priv *priv, u8 *addr,
-+			     struct mwl_sta *sta_info)
-+{
-+	int table_size = (sizeof(__le32) * 2 * SYSADPT_MAX_RATE_ADAPT_RATES);
-+	u8 *rate_table, *rate_idx;
-+	u32 rate_info;
-+	struct mwl_tx_hist_data *tx_hist_data;
-+	int ret, idx;
-+
-+	rate_table = kzalloc(table_size, GFP_KERNEL);
-+	if (!rate_table)
-+		return;
-+
-+	ret = mwl_fwcmd_get_ratetable(priv->hw, addr, rate_table,
-+				      table_size, 0);
-+	if (ret) {
-+		kfree(rate_table);
-+		return;
-+	}
-+
-+	idx = 0;
-+	rate_idx = rate_table;
-+	rate_info = le32_to_cpu(*(__le32 *)rate_idx);
-+	tx_hist_data = &sta_info->tx_hist.su_rate[0];
-+	while (rate_info) {
-+		if (idx < SYSADPT_MAX_RATE_ADAPT_RATES)
-+			tx_hist_data[idx].rateinfo = rate_info;
-+		idx++;
-+		rate_idx += (2 * sizeof(__le32));
-+		rate_info = le32_to_cpu(*(__le32 *)rate_idx);
-+	}
-+
-+	kfree(rate_table);
-+}
-+
-+static void mwl_mac80211_tx(struct ieee80211_hw *hw,
-+			    struct ieee80211_tx_control *control,
-+			    struct sk_buff *skb)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if (!priv->radio_on) {
-+		wiphy_warn(hw->wiphy,
-+			   "dropped TX frame since radio is disabled\n");
-+		dev_kfree_skb_any(skb);
-+		return;
-+	}
-+
-+	mwl_hif_tx_xmit(hw, control, skb);
-+}
-+
-+static int mwl_mac80211_start(struct ieee80211_hw *hw)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc;
-+
-+	/* Enable TX and RX tasklets. */
-+	mwl_hif_enable_data_tasks(hw);
-+
-+	/* Enable interrupts */
-+	mwl_hif_irq_enable(hw);
-+
-+	rc = mwl_fwcmd_radio_enable(hw);
-+	if (rc)
-+		goto fwcmd_fail;
-+	rc = mwl_fwcmd_set_rate_adapt_mode(hw, 0);
-+	if (rc)
-+		goto fwcmd_fail;
-+	rc = mwl_fwcmd_set_wmm_mode(hw, true);
-+	if (rc)
-+		goto fwcmd_fail;
-+	rc = mwl_fwcmd_ht_guard_interval(hw, GUARD_INTERVAL_AUTO);
-+	if (rc)
-+		goto fwcmd_fail;
-+	rc = mwl_fwcmd_set_dwds_stamode(hw, true);
-+	if (rc)
-+		goto fwcmd_fail;
-+	rc = mwl_fwcmd_set_fw_flush_timer(hw, SYSADPT_AMSDU_FLUSH_TIME);
-+	if (rc)
-+		goto fwcmd_fail;
-+	rc = mwl_fwcmd_set_optimization_level(hw, 1);
-+	if (rc)
-+		goto fwcmd_fail;
-+	if (priv->chip_type == MWL8997) {
-+		rc = mwl_fwcmd_config_EDMACCtrl(hw, 0);
-+		if (rc)
-+			goto fwcmd_fail;
-+	}
-+	if (priv->chip_type == MWL8964) {
-+		rc = mwl_fwcmd_newdp_dmathread_start(hw);
-+		if (rc)
-+			goto fwcmd_fail;
-+		rc = mwl_fwcmd_set_bftype(hw, priv->bf_type);
-+		if (rc)
-+			goto fwcmd_fail;
-+	}
-+
-+	ieee80211_wake_queues(hw);
-+	return 0;
-+
-+fwcmd_fail:
-+	mwl_hif_irq_disable(hw);
-+	mwl_hif_disable_data_tasks(hw);
-+
-+	return rc;
-+}
-+
-+static void mwl_mac80211_stop(struct ieee80211_hw *hw)
-+{
-+	mwl_fwcmd_radio_disable(hw);
-+
-+	ieee80211_stop_queues(hw);
-+
-+	/* Disable interrupts */
-+	mwl_hif_irq_disable(hw);
-+
-+	/* Disable TX and RX tasklets. */
-+	mwl_hif_disable_data_tasks(hw);
-+
-+	/* Return all skbs to mac80211 */
-+	mwl_hif_tx_return_pkts(hw);
-+}
-+
-+static int mwl_mac80211_add_interface(struct ieee80211_hw *hw,
-+				      struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+	u32 macids_supported;
-+	int macid;
-+
-+	switch (vif->type) {
-+	case NL80211_IFTYPE_AP:
-+	case NL80211_IFTYPE_MESH_POINT:
-+		if (vif->type == NL80211_IFTYPE_MESH_POINT)
-+			if (priv->chip_type != MWL8997)
-+				return -EPERM;
-+		macids_supported = priv->ap_macids_supported;
-+		break;
-+	case NL80211_IFTYPE_STATION:
-+		macids_supported = priv->sta_macids_supported;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	macid = ffs(macids_supported & ~priv->macids_used);
-+
-+	if (!macid) {
-+		wiphy_warn(hw->wiphy, "no macid can be allocated\n");
-+		return -EBUSY;
-+	}
-+	macid--;
-+
-+	/* Setup driver private area. */
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	memset(mwl_vif, 0, sizeof(*mwl_vif));
-+	mwl_vif->type = vif->type;
-+	mwl_vif->macid = macid;
-+	mwl_vif->seqno = 0;
-+	mwl_vif->is_hw_crypto_enabled = false;
-+	mwl_vif->beacon_info.valid = false;
-+	mwl_vif->set_beacon = false;
-+	mwl_vif->basic_rate_idx = 0;
-+	mwl_vif->broadcast_ssid = 0xFF;
-+	mwl_vif->iv16 = 1;
-+	mwl_vif->iv32 = 0;
-+	mwl_vif->keyidx = 0;
-+
-+	switch (vif->type) {
-+	case NL80211_IFTYPE_AP:
-+		ether_addr_copy(mwl_vif->bssid, vif->addr);
-+		mwl_fwcmd_set_new_stn_add_self(hw, vif);
-+		if (priv->chip_type == MWL8964) {
-+			/* allow firmware to really set channel */
-+			mwl_fwcmd_bss_start(hw, vif, true);
-+			mwl_fwcmd_bss_start(hw, vif, false);
-+		}
-+		break;
-+	case NL80211_IFTYPE_MESH_POINT:
-+		ether_addr_copy(mwl_vif->bssid, vif->addr);
-+		mwl_fwcmd_set_new_stn_add_self(hw, vif);
-+		break;
-+	case NL80211_IFTYPE_STATION:
-+		ether_addr_copy(mwl_vif->sta_mac, vif->addr);
-+		mwl_fwcmd_bss_start(hw, vif, true);
-+		mwl_fwcmd_set_infra_mode(hw, vif);
-+		mwl_fwcmd_set_mac_addr_client(hw, vif, vif->addr);
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+
-+	priv->macids_used |= 1 << mwl_vif->macid;
-+	spin_lock_bh(&priv->vif_lock);
-+	list_add_tail(&mwl_vif->list, &priv->vif_list);
-+	spin_unlock_bh(&priv->vif_lock);
-+
-+	return 0;
-+}
-+
-+static void mwl_mac80211_remove_vif(struct mwl_priv *priv,
-+				    struct ieee80211_vif *vif)
-+{
-+	struct mwl_vif *mwl_vif = mwl_dev_get_vif(vif);
-+
-+	if (!priv->macids_used)
-+		return;
-+
-+	mwl_hif_tx_del_pkts_via_vif(priv->hw, vif);
-+
-+	priv->macids_used &= ~(1 << mwl_vif->macid);
-+	spin_lock_bh(&priv->vif_lock);
-+	list_del(&mwl_vif->list);
-+	spin_unlock_bh(&priv->vif_lock);
-+}
-+
-+static void mwl_mac80211_remove_interface(struct ieee80211_hw *hw,
-+					  struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	switch (vif->type) {
-+	case NL80211_IFTYPE_AP:
-+	case NL80211_IFTYPE_MESH_POINT:
-+		mwl_fwcmd_set_new_stn_del(hw, vif, vif->addr);
-+		break;
-+	case NL80211_IFTYPE_STATION:
-+		mwl_fwcmd_remove_mac_addr(hw, vif, vif->addr);
-+		break;
-+	default:
-+		break;
-+	}
-+
-+	mwl_mac80211_remove_vif(priv, vif);
-+}
-+
-+static int mwl_mac80211_config(struct ieee80211_hw *hw,
-+			       u32 changed)
-+{
-+	struct ieee80211_conf *conf = &hw->conf;
-+	int rc;
-+
-+	wiphy_debug(hw->wiphy, "change: 0x%x\n", changed);
-+
-+	if (conf->flags & IEEE80211_CONF_IDLE)
-+		rc = mwl_fwcmd_radio_disable(hw);
-+	else
-+		rc = mwl_fwcmd_radio_enable(hw);
-+
-+	if (rc)
-+		goto out;
-+
-+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-+		int rate = 0;
-+
-+		if (conf->chandef.chan->band == NL80211_BAND_2GHZ) {
-+			mwl_fwcmd_set_apmode(hw, AP_MODE_2_4GHZ_11AC_MIXED);
-+			mwl_fwcmd_set_linkadapt_cs_mode(hw,
-+							LINK_CS_STATE_CONSERV);
-+			rate = mwl_rates_24[0].hw_value;
-+		} else if (conf->chandef.chan->band == NL80211_BAND_5GHZ) {
-+			mwl_fwcmd_set_apmode(hw, AP_MODE_11AC);
-+			mwl_fwcmd_set_linkadapt_cs_mode(hw,
-+							LINK_CS_STATE_AUTO);
-+			rate = mwl_rates_50[0].hw_value;
-+
-+			if (conf->radar_enabled)
-+				mwl_fwcmd_set_radar_detect(hw, MONITOR_START);
-+			else
-+				mwl_fwcmd_set_radar_detect(hw,
-+							   STOP_DETECT_RADAR);
-+		}
-+
-+		rc = mwl_fwcmd_set_rf_channel(hw, conf);
-+		if (rc)
-+			goto out;
-+		rc = mwl_fwcmd_use_fixed_rate(hw, rate, rate);
-+		if (rc)
-+			goto out;
-+		rc = mwl_fwcmd_max_tx_power(hw, conf, 0);
-+		if (rc)
-+			goto out;
-+		rc = mwl_fwcmd_tx_power(hw, conf, 0);
-+		if (rc)
-+			goto out;
-+		rc = mwl_fwcmd_set_cdd(hw);
-+	}
-+
-+out:
-+
-+	return rc;
-+}
-+
-+static void mwl_mac80211_bss_info_changed_sta(struct ieee80211_hw *hw,
-+					      struct ieee80211_vif *vif,
-+					      struct ieee80211_bss_conf *info,
-+					      u32 changed)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	if ((changed & BSS_CHANGED_ERP_SLOT) && (priv->chip_type == MWL8997)) {
-+		if (priv->use_short_slot != vif->bss_conf.use_short_slot) {
-+			mwl_fwcmd_set_slot_time(hw,
-+						vif->bss_conf.use_short_slot);
-+			priv->use_short_slot = vif->bss_conf.use_short_slot;
-+		}
-+	}
-+
-+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-+		if (priv->use_short_preamble !=
-+		    vif->bss_conf.use_short_preamble) {
-+			mwl_fwcmd_set_radio_preamble(
-+				hw, vif->bss_conf.use_short_preamble);
-+			priv->use_short_preamble =
-+				vif->bss_conf.use_short_preamble;
-+		}
-+	}
-+
-+	if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc)
-+		mwl_fwcmd_set_aid(hw, vif, (u8 *)vif->bss_conf.bssid,
-+				  vif->bss_conf.aid);
-+}
-+
-+static void mwl_mac80211_bss_info_changed_ap(struct ieee80211_hw *hw,
-+					     struct ieee80211_vif *vif,
-+					     struct ieee80211_bss_conf *info,
-+					     u32 changed)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_vif *mwl_vif;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+
-+	if ((changed & BSS_CHANGED_ERP_SLOT) && (priv->chip_type == MWL8997)) {
-+		if (priv->use_short_slot != vif->bss_conf.use_short_slot) {
-+			mwl_fwcmd_set_slot_time(hw,
-+						vif->bss_conf.use_short_slot);
-+			priv->use_short_slot = vif->bss_conf.use_short_slot;
-+		}
-+	}
-+
-+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-+		if (priv->use_short_preamble !=
-+		    vif->bss_conf.use_short_preamble) {
-+			mwl_fwcmd_set_radio_preamble(
-+				hw, vif->bss_conf.use_short_preamble);
-+			priv->use_short_preamble =
-+				vif->bss_conf.use_short_preamble;
-+		}
-+	}
-+
-+	if (changed & BSS_CHANGED_BASIC_RATES) {
-+		int idx;
-+		int rate;
-+
-+		/* Use lowest supported basic rate for multicasts
-+		 * and management frames (such as probe responses --
-+		 * beacons will always go out at 1 Mb/s).
-+		 */
-+		idx = ffs(vif->bss_conf.basic_rates);
-+		if (idx)
-+			idx--;
-+		if (mwl_vif->basic_rate_idx != idx) {
-+			if (hw->conf.chandef.chan->band == NL80211_BAND_2GHZ)
-+				rate = mwl_rates_24[idx].hw_value;
-+			else
-+				rate = mwl_rates_50[idx].hw_value;
-+
-+			mwl_fwcmd_use_fixed_rate(hw, rate, rate);
-+			mwl_vif->basic_rate_idx = idx;
-+		}
-+	}
-+
-+	if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
-+		struct sk_buff *skb;
-+
-+		if ((info->ssid[0] != '\0') &&
-+		    (info->ssid_len != 0) &&
-+		    (!info->hidden_ssid)) {
-+			if (mwl_vif->broadcast_ssid != true) {
-+				mwl_fwcmd_broadcast_ssid_enable(hw, vif, true);
-+				mwl_vif->broadcast_ssid = true;
-+			}
-+		} else {
-+			if (mwl_vif->broadcast_ssid != false) {
-+				mwl_fwcmd_broadcast_ssid_enable(hw, vif, false);
-+				mwl_vif->broadcast_ssid = false;
-+			}
-+		}
-+
-+		if (!mwl_vif->set_beacon) {
-+			skb = ieee80211_beacon_get(hw, vif);
-+
-+			if (skb) {
-+				mwl_fwcmd_set_beacon(hw, vif, skb->data, skb->len);
-+				dev_kfree_skb_any(skb);
-+			}
-+			mwl_vif->set_beacon = true;
-+		}
-+	}
-+
-+	if (changed & BSS_CHANGED_BEACON_ENABLED)
-+		mwl_fwcmd_bss_start(hw, vif, info->enable_beacon);
-+}
-+
-+static void mwl_mac80211_bss_info_changed(struct ieee80211_hw *hw,
-+					  struct ieee80211_vif *vif,
-+					  struct ieee80211_bss_conf *info,
-+					  u32 changed)
-+{
-+	switch (vif->type) {
-+	case NL80211_IFTYPE_AP:
-+	case NL80211_IFTYPE_MESH_POINT:
-+		mwl_mac80211_bss_info_changed_ap(hw, vif, info, changed);
-+		break;
-+	case NL80211_IFTYPE_STATION:
-+		mwl_mac80211_bss_info_changed_sta(hw, vif, info, changed);
-+		break;
-+	default:
-+		break;
-+	}
-+}
-+
-+static void mwl_mac80211_configure_filter(struct ieee80211_hw *hw,
-+					  unsigned int changed_flags,
-+					  unsigned int *total_flags,
-+					  u64 multicast)
-+{
-+	/* AP firmware doesn't allow fine-grained control over
-+	 * the receive filter.
-+	 */
-+	*total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC;
-+}
-+
-+static int mwl_mac80211_set_key(struct ieee80211_hw *hw,
-+				enum set_key_cmd cmd_param,
-+				struct ieee80211_vif *vif,
-+				struct ieee80211_sta *sta,
-+				struct ieee80211_key_conf *key)
-+{
-+	struct mwl_vif *mwl_vif;
-+	struct mwl_sta *sta_info;
-+	int rc = 0;
-+	u8 encr_type;
-+	u8 *addr;
-+
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	addr = sta ? sta->addr : vif->addr;
-+
-+	if (cmd_param == SET_KEY) {
-+		if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) ||
-+		    (key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
-+			encr_type = ENCR_TYPE_WEP;
-+		} else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
-+			encr_type = ENCR_TYPE_AES;
-+			if ((key->flags & IEEE80211_KEY_FLAG_PAIRWISE) == 0) {
-+				if (vif->type != NL80211_IFTYPE_STATION)
-+					mwl_vif->keyidx = key->keyidx;
-+			}
-+		} else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-+			encr_type = ENCR_TYPE_TKIP;
-+		} else {
-+			encr_type = ENCR_TYPE_DISABLE;
-+		}
-+
-+		rc = mwl_fwcmd_update_encryption_enable(hw, vif, addr,
-+							encr_type);
-+		if (rc)
-+			goto out;
-+		rc = mwl_fwcmd_encryption_set_key(hw, vif, addr, key);
-+		if (rc)
-+			goto out;
-+
-+		mwl_vif->is_hw_crypto_enabled = true;
-+		if (sta) {
-+			sta_info = mwl_dev_get_sta(sta);
-+			sta_info->is_key_set = true;
-+		}
-+	} else {
-+		rc = mwl_fwcmd_encryption_remove_key(hw, vif, addr, key);
-+		if (rc)
-+			goto out;
-+	}
-+
-+out:
-+
-+	return rc;
-+}
-+
-+static int mwl_mac80211_set_rts_threshold(struct ieee80211_hw *hw,
-+					  u32 value)
-+{
-+	return mwl_fwcmd_set_rts_threshold(hw, value);
-+}
-+
-+static int mwl_mac80211_sta_add(struct ieee80211_hw *hw,
-+				struct ieee80211_vif *vif,
-+				struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	u16 stnid, sta_stnid = 0;
-+	struct mwl_vif *mwl_vif;
-+	struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
-+	bool use_4addr = wdev->use_4addr;
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_key_conf *key;
-+	int rc;
-+	int i;
-+
-+	if (vif->type == NL80211_IFTYPE_STATION)
-+		sta->aid = 1;
-+	mwl_vif = mwl_dev_get_vif(vif);
-+	stnid = utils_assign_stnid(priv, mwl_vif->macid, sta->aid);
-+	if (!stnid)
-+		return -EPERM;
-+	if (vif->type == NL80211_IFTYPE_STATION) {
-+		sta_stnid = utils_assign_stnid(priv, mwl_vif->macid,
-+					       sta->aid + 1);
-+		if (!sta_stnid) {
-+			utils_free_stnid(priv, stnid);
-+			return -EPERM;
-+		}
-+		ether_addr_copy(mwl_vif->bssid, sta->addr);
-+	}
-+	sta_info = mwl_dev_get_sta(sta);
-+	memset(sta_info, 0, sizeof(*sta_info));
-+
-+	if (vif->type == NL80211_IFTYPE_MESH_POINT)
-+		sta_info->is_mesh_node = true;
-+
-+	if (sta->ht_cap.ht_supported) {
-+		sta_info->is_ampdu_allowed = true;
-+		sta_info->is_amsdu_allowed = false;
-+		if (sta->ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
-+			sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_8K;
-+		else
-+			sta_info->amsdu_ctrl.cap = MWL_AMSDU_SIZE_4K;
-+		if ((sta->tdls) && (!sta->wme))
-+			sta->wme = true;
-+	}
-+	sta_info->mwl_vif = mwl_vif;
-+	sta_info->stnid = stnid;
-+	if (vif->type == NL80211_IFTYPE_STATION)
-+		sta_info->sta_stnid = sta_stnid;
-+	sta_info->tx_rate_info = utils_get_init_tx_rate(priv, &hw->conf, sta);
-+	sta_info->iv16 = 1;
-+	sta_info->iv32 = 0;
-+	spin_lock_init(&sta_info->amsdu_lock);
-+	spin_lock_bh(&priv->sta_lock);
-+	list_add_tail(&sta_info->list, &priv->sta_list);
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	if (vif->type == NL80211_IFTYPE_STATION)
-+		mwl_fwcmd_set_new_stn_del(hw, vif, sta->addr);
-+
-+	if (priv->chip_type == MWL8964) {
-+		if (use_4addr) {
-+			sta_info->wds = true;
-+			rc = mwl_fwcmd_set_new_stn_add_sc4(hw, vif, sta,
-+							   WDS_MODE);
-+		} else
-+			rc = mwl_fwcmd_set_new_stn_add_sc4(hw, vif, sta, 0);
-+	} else
-+		rc = mwl_fwcmd_set_new_stn_add(hw, vif, sta);
-+
-+	if ((vif->type == NL80211_IFTYPE_STATION) && !use_4addr)
-+		mwl_hif_set_sta_id(hw, sta, true, true);
-+	else
-+		mwl_hif_set_sta_id(hw, sta, false, true);
-+
-+	for (i = 0; i < NUM_WEP_KEYS; i++) {
-+		key = (struct ieee80211_key_conf *)mwl_vif->wep_key_conf[i].key;
-+
-+		if (mwl_vif->wep_key_conf[i].enabled)
-+			mwl_mac80211_set_key(hw, SET_KEY, vif, sta, key);
-+	}
-+
-+	mwl_get_rateinfo(priv, sta->addr, sta_info);
-+
-+	return rc;
-+}
-+
-+static int mwl_mac80211_sta_remove(struct ieee80211_hw *hw,
-+				   struct ieee80211_vif *vif,
-+				   struct ieee80211_sta *sta)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc;
-+	struct mwl_sta *sta_info = mwl_dev_get_sta(sta);
-+
-+	mwl_hif_tx_del_sta_amsdu_pkts(hw, sta);
-+	mwl_fwcmd_del_sta_streams(hw, sta);
-+	mwl_hif_tx_del_pkts_via_sta(hw, sta);
-+
-+	rc = mwl_fwcmd_set_new_stn_del(hw, vif, sta->addr);
-+
-+	if (vif->type == NL80211_IFTYPE_STATION)
-+		mwl_hif_set_sta_id(hw, sta, true, false);
-+	else
-+		mwl_hif_set_sta_id(hw, sta, false, false);
-+
-+	if (priv->chip_type != MWL8964)
-+		utils_free_stnid(priv, sta_info->stnid);
-+	if (vif->type == NL80211_IFTYPE_STATION)
-+		utils_free_stnid(priv, sta_info->sta_stnid);
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_del(&sta_info->list);
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	return rc;
-+}
-+
-+static int mwl_mac80211_conf_tx(struct ieee80211_hw *hw,
-+				struct ieee80211_vif *vif,
-+				u16 queue,
-+				const struct ieee80211_tx_queue_params *params)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	int rc = 0;
-+
-+	if (WARN_ON(queue > SYSADPT_TX_WMM_QUEUES - 1))
-+		return -EINVAL;
-+
-+	memcpy(&priv->wmm_params[queue], params, sizeof(*params));
-+
-+	if (!priv->wmm_enabled) {
-+		rc = mwl_fwcmd_set_wmm_mode(hw, true);
-+		priv->wmm_enabled = true;
-+	}
-+
-+	if (!rc) {
-+		int q = SYSADPT_TX_WMM_QUEUES - 1 - queue;
-+
-+		rc = mwl_fwcmd_set_edca_params(hw, q,
-+					       params->cw_min, params->cw_max,
-+					       params->aifs, params->txop);
-+	}
-+
-+	return rc;
-+}
-+
-+static int mwl_mac80211_get_stats(struct ieee80211_hw *hw,
-+				  struct ieee80211_low_level_stats *stats)
-+{
-+	return mwl_fwcmd_get_stat(hw, stats);
-+}
-+
-+static int mwl_mac80211_get_survey(struct ieee80211_hw *hw,
-+				   int idx,
-+				   struct survey_info *survey)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_survey_info *survey_info;
-+
-+	if (priv->survey_info_idx) {
-+		if (idx >= priv->survey_info_idx) {
-+			priv->survey_info_idx = 0;
-+			return -ENOENT;
-+		}
-+		survey_info = &priv->survey_info[idx];
-+	} else {
-+		if (idx != 0)
-+			return -ENOENT;
-+		mwl_fwcmd_get_survey(hw, 0);
-+		survey_info = &priv->cur_survey_info;
-+		if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
-+			survey->filled |= SURVEY_INFO_IN_USE;
-+	}
-+
-+	survey->channel = &survey_info->channel;
-+	survey->filled |= survey_info->filled;
-+	survey->time = survey_info->time_period / 1000;
-+	survey->time_busy = survey_info->time_busy / 1000;
-+	survey->time_tx = survey_info->time_tx / 1000;
-+	survey->noise = survey_info->noise;
-+
-+	return 0;
-+}
-+
-+static int mwl_mac80211_ampdu_action(struct ieee80211_hw *hw,
-+				     struct ieee80211_vif *vif,
-+				     struct ieee80211_ampdu_params *params)
-+{
-+	int rc = 0;
-+	struct mwl_priv *priv = hw->priv;
-+	struct mwl_ampdu_stream *stream;
-+	enum ieee80211_ampdu_mlme_action action = params->action;
-+	struct ieee80211_sta *sta = params->sta;
-+	u16 tid = params->tid;
-+	u8 buf_size = params->buf_size;
-+	u8 *addr = sta->addr;
-+	struct mwl_sta *sta_info;
-+
-+	sta_info = mwl_dev_get_sta(sta);
-+
-+	spin_lock_bh(&priv->stream_lock);
-+
-+	stream = mwl_fwcmd_lookup_stream(hw, sta, tid);
-+
-+	switch (action) {
-+	case IEEE80211_AMPDU_RX_START:
-+		if (priv->chip_type == MWL8964) {
-+			struct mwl_ampdu_stream tmp;
-+
-+			tmp.sta = sta;
-+			tmp.tid = tid;
-+			spin_unlock_bh(&priv->stream_lock);
-+			mwl_fwcmd_create_ba(hw, &tmp, vif,
-+					    BA_FLAG_DIRECTION_DOWN,
-+					    buf_size, params->ssn,
-+					    params->amsdu);
-+			spin_lock_bh(&priv->stream_lock);
-+			break;
-+		}
-+	case IEEE80211_AMPDU_RX_STOP:
-+		if (priv->chip_type == MWL8964) {
-+			struct mwl_ampdu_stream tmp;
-+
-+			tmp.sta = sta;
-+			tmp.tid = tid;
-+			spin_unlock_bh(&priv->stream_lock);
-+			mwl_fwcmd_destroy_ba(hw, &tmp,
-+					     BA_FLAG_DIRECTION_DOWN);
-+			spin_lock_bh(&priv->stream_lock);
-+		}
-+		break;
-+	case IEEE80211_AMPDU_TX_START:
-+		if (!sta_info->is_ampdu_allowed) {
-+			wiphy_warn(hw->wiphy, "ampdu not allowed\n");
-+			rc = -EPERM;
-+			break;
-+		}
-+
-+		if (!stream) {
-+			stream = mwl_fwcmd_add_stream(hw, sta, tid);
-+			if (!stream) {
-+				wiphy_warn(hw->wiphy, "no stream found\n");
-+				rc = -EPERM;
-+				break;
-+			}
-+		}
-+
-+		if (priv->chip_type != MWL8964) {
-+			spin_unlock_bh(&priv->stream_lock);
-+			rc = mwl_fwcmd_check_ba(hw, stream, vif,
-+					BA_FLAG_DIRECTION_UP);
-+			spin_lock_bh(&priv->stream_lock);
-+			if (rc) {
-+				mwl_fwcmd_remove_stream(hw, stream);
-+				sta_info->check_ba_failed[tid]++;
-+				break;
-+			}
-+		}
-+		stream->state = AMPDU_STREAM_IN_PROGRESS;
-+		spin_unlock_bh(&priv->stream_lock);
-+		rc = mwl_fwcmd_get_seqno(hw, stream, &params->ssn);
-+		spin_lock_bh(&priv->stream_lock);
-+		if (rc)
-+			break;
-+		ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
-+		break;
-+	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) {
-+				stream->state = AMPDU_STREAM_IN_PROGRESS;
-+				mwl_hif_tx_del_ampdu_pkts(hw, sta, tid);
-+				spin_unlock_bh(&priv->stream_lock);
-+				mwl_fwcmd_destroy_ba(hw, stream,
-+						     BA_FLAG_DIRECTION_UP);
-+				spin_lock_bh(&priv->stream_lock);
-+				sta_info->is_amsdu_allowed = false;
-+			}
-+
-+			mwl_fwcmd_remove_stream(hw, stream);
-+			ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
-+		} else {
-+			rc = -EPERM;
-+		}
-+		break;
-+	case IEEE80211_AMPDU_TX_OPERATIONAL:
-+		if (stream) {
-+			if (WARN_ON(stream->state !=
-+				    AMPDU_STREAM_IN_PROGRESS)) {
-+				rc = -EPERM;
-+				break;
-+			}
-+			spin_unlock_bh(&priv->stream_lock);
-+			rc = mwl_fwcmd_create_ba(hw, stream, vif,
-+						 BA_FLAG_DIRECTION_UP,
-+						 buf_size, params->ssn,
-+						 params->amsdu);
-+			spin_lock_bh(&priv->stream_lock);
-+
-+			if (!rc) {
-+				stream->state = AMPDU_STREAM_ACTIVE;
-+				sta_info->check_ba_failed[tid] = 0;
-+				if (priv->tx_amsdu)
-+					sta_info->is_amsdu_allowed =
-+						params->amsdu;
-+				else
-+					sta_info->is_amsdu_allowed = false;
-+			} else {
-+				spin_unlock_bh(&priv->stream_lock);
-+				mwl_fwcmd_destroy_ba(hw, stream,
-+						     BA_FLAG_DIRECTION_UP);
-+				spin_lock_bh(&priv->stream_lock);
-+				mwl_fwcmd_remove_stream(hw, stream);
-+				wiphy_err(hw->wiphy,
-+					  "ampdu operation error code: %d\n",
-+					  rc);
-+			}
-+		} else {
-+			rc = -EPERM;
-+		}
-+		break;
-+	default:
-+		rc = -ENOTSUPP;
-+		break;
-+	}
-+
-+	spin_unlock_bh(&priv->stream_lock);
-+
-+	return rc;
-+}
-+
-+static int mwl_mac80211_chnl_switch(struct ieee80211_hw *hw,
-+				    struct ieee80211_vif *vif,
-+				    struct ieee80211_channel_switch *ch_switch)
-+{
-+	int rc = 0;
-+
-+	rc = mwl_fwcmd_set_switch_channel(hw, ch_switch);
-+
-+	return rc;
-+}
-+
-+static void mwl_mac80211_sw_scan_start(struct ieee80211_hw *hw,
-+				       struct ieee80211_vif *vif,
-+				       const u8 *mac_addr)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	priv->sw_scanning = true;
-+	priv->survey_info_idx = 0;
-+}
-+
-+static void mwl_mac80211_sw_scan_complete(struct ieee80211_hw *hw,
-+					  struct ieee80211_vif *vif)
-+{
-+	struct mwl_priv *priv = hw->priv;
-+
-+	priv->sw_scanning = false;
-+}
-+
-+const struct ieee80211_ops mwl_mac80211_ops = {
-+	.tx                 = mwl_mac80211_tx,
-+	.start              = mwl_mac80211_start,
-+	.stop               = mwl_mac80211_stop,
-+	.add_interface      = mwl_mac80211_add_interface,
-+	.remove_interface   = mwl_mac80211_remove_interface,
-+	.config             = mwl_mac80211_config,
-+	.bss_info_changed   = mwl_mac80211_bss_info_changed,
-+	.configure_filter   = mwl_mac80211_configure_filter,
-+	.set_key            = mwl_mac80211_set_key,
-+	.set_rts_threshold  = mwl_mac80211_set_rts_threshold,
-+	.sta_add            = mwl_mac80211_sta_add,
-+	.sta_remove         = mwl_mac80211_sta_remove,
-+	.conf_tx            = mwl_mac80211_conf_tx,
-+	.get_stats          = mwl_mac80211_get_stats,
-+	.get_survey         = mwl_mac80211_get_survey,
-+	.ampdu_action       = mwl_mac80211_ampdu_action,
-+	.pre_channel_switch = mwl_mac80211_chnl_switch,
-+	.sw_scan_start      = mwl_mac80211_sw_scan_start,
-+	.sw_scan_complete   = mwl_mac80211_sw_scan_complete,
-+};
-diff --git a/drivers/net/wireless/marvell/mwlwifi/mu_mimo.c b/drivers/net/wireless/marvell/mwlwifi/mu_mimo.c
-new file mode 100644
-index 000000000000..74ab054f947e
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/mu_mimo.c
-@@ -0,0 +1,21 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements MU-MIMO functions. */
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "mu_mimo.h"
-+
-diff --git a/drivers/net/wireless/marvell/mwlwifi/mu_mimo.h b/drivers/net/wireless/marvell/mwlwifi/mu_mimo.h
-new file mode 100644
-index 000000000000..24179f404774
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/mu_mimo.h
-@@ -0,0 +1,23 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines MU-MIMO functions. */
-+
-+#ifndef _MU_MIMO_H_
-+#define _MU_MIMO_H_
-+
-+
-+
-+#endif /* _MU_MIMO_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/sysadpt.h b/drivers/net/wireless/marvell/mwlwifi/sysadpt.h
-new file mode 100644
-index 000000000000..1194e5271870
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/sysadpt.h
-@@ -0,0 +1,86 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines system adaptation related information. */
-+
-+#ifndef _SYSADPT_H_
-+#define _SYSADPT_H_
-+
-+#define SYSADPT_MAX_STA                64
-+
-+#define SYSADPT_MAX_STA_SC4            300
-+
-+#define SYSADPT_MAX_NUM_CHANNELS       64
-+
-+#define SYSADPT_MAX_DATA_RATES_G       14
-+
-+#define SYSADPT_MAX_MCS_RATES          24
-+
-+#define SYSADPT_MAX_11AC_RATES         20
-+
-+#define SYSADPT_MAX_RATE_ADAPT_RATES   (SYSADPT_MAX_DATA_RATES_G + \
-+					SYSADPT_MAX_MCS_RATES + \
-+					SYSADPT_MAX_11AC_RATES)
-+
-+#define SYSADPT_TX_POWER_LEVEL_TOTAL   16  /* SC3 */
-+
-+#define SYSADPT_TX_GRP_PWR_LEVEL_TOTAL 28  /* KF2 */
-+
-+#define SYSADPT_TX_PWR_LEVEL_TOTAL_SC4 32  /* SC4 */
-+
-+#define SYSADPT_TX_WMM_QUEUES          4
-+
-+#define SYSADPT_NUM_OF_CLIENT          1
-+
-+#define SYSADPT_NUM_OF_AP              16
-+
-+#define SYSADPT_NUM_OF_MESH            1
-+
-+#define SYSADPT_TOTAL_TX_QUEUES        (SYSADPT_TX_WMM_QUEUES + \
-+					SYSADPT_NUM_OF_AP)
-+
-+#define SYSADPT_MAX_AGGR_SIZE          4096
-+
-+#define SYSADPT_AMPDU_PACKET_THRESHOLD 64
-+
-+#define SYSADPT_AMSDU_FW_MAX_SIZE      3300
-+
-+#define SYSADPT_AMSDU_4K_MAX_SIZE      SYSADPT_AMSDU_FW_MAX_SIZE
-+
-+#define SYSADPT_AMSDU_8K_MAX_SIZE      SYSADPT_AMSDU_FW_MAX_SIZE
-+
-+#define SYSADPT_AMSDU_ALLOW_SIZE       1600
-+
-+#define SYSADPT_AMSDU_FLUSH_TIME       500
-+
-+#define SYSADPT_AMSDU_PACKET_THRESHOLD 10
-+
-+#define SYSADPT_MAX_TID                8
-+
-+#define SYSADPT_QUIET_PERIOD_DEFAULT   100
-+
-+#define SYSADPT_QUIET_PERIOD_MIN       25
-+
-+#define SYSADPT_QUIET_START_OFFSET     10
-+
-+#define SYSADPT_THERMAL_THROTTLE_MAX   100
-+
-+#define SYSADPT_TIMER_WAKEUP_TIME      10 /* ms */
-+
-+#define SYSADPT_OTP_BUF_SIZE           (256*8) /* 258 lines * 8 bytes */
-+
-+#define SYSADPT_TXPWRLMT_CFG_BUF_SIZE  (3650)
-+
-+#endif /* _SYSADPT_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/thermal.c b/drivers/net/wireless/marvell/mwlwifi/thermal.c
-new file mode 100644
-index 000000000000..7c59def51e7f
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/thermal.c
-@@ -0,0 +1,182 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements thermal framework related functions. */
-+
-+#include <linux/device.h>
-+#include <linux/sysfs.h>
-+#include <linux/thermal.h>
-+#include <linux/hwmon.h>
-+#include <linux/hwmon-sysfs.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "hif/fwcmd.h"
-+#include "thermal.h"
-+
-+static int
-+mwl_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
-+				   unsigned long *state)
-+{
-+	*state = SYSADPT_THERMAL_THROTTLE_MAX;
-+
-+	return 0;
-+}
-+
-+static int
-+mwl_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
-+				   unsigned long *state)
-+{
-+	struct mwl_priv *priv = cdev->devdata;
-+
-+	*state = priv->throttle_state;
-+
-+	return 0;
-+}
-+
-+static int
-+mwl_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
-+				   unsigned long throttle_state)
-+{
-+	struct mwl_priv *priv = cdev->devdata;
-+
-+	if (throttle_state > SYSADPT_THERMAL_THROTTLE_MAX) {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "throttle state %ld is exceeding the limit %d\n",
-+			   throttle_state, SYSADPT_THERMAL_THROTTLE_MAX);
-+		return -EINVAL;
-+	}
-+	priv->throttle_state = throttle_state;
-+	mwl_thermal_set_throttling(priv);
-+
-+	return 0;
-+}
-+
-+static struct thermal_cooling_device_ops mwl_thermal_ops = {
-+	.get_max_state = mwl_thermal_get_max_throttle_state,
-+	.get_cur_state = mwl_thermal_get_cur_throttle_state,
-+	.set_cur_state = mwl_thermal_set_cur_throttle_state,
-+};
-+
-+static ssize_t mwl_thermal_show_temp(struct device *dev,
-+				     struct device_attribute *attr,
-+				     char *buf)
-+{
-+	struct mwl_priv *priv = dev_get_drvdata(dev);
-+	int ret, temperature;
-+
-+	ret = mwl_fwcmd_get_temp(priv->hw, &priv->temperature);
-+	if (ret) {
-+		wiphy_warn(priv->hw->wiphy, "failed: can't get temperature\n");
-+		goto out;
-+	}
-+
-+	temperature = priv->temperature;
-+
-+	/* display in millidegree celcius */
-+	ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
-+out:
-+	return ret;
-+}
-+
-+static SENSOR_DEVICE_ATTR(temp1_input, 0444, mwl_thermal_show_temp,
-+			  NULL, 0);
-+
-+static struct attribute *mwl_hwmon_attrs[] = {
-+	&sensor_dev_attr_temp1_input.dev_attr.attr,
-+	NULL,
-+};
-+ATTRIBUTE_GROUPS(mwl_hwmon);
-+
-+void mwl_thermal_set_throttling(struct mwl_priv *priv)
-+{
-+	u32 period, duration, enabled;
-+	int ret;
-+
-+	period = priv->quiet_period;
-+	duration = (period * priv->throttle_state) / 100;
-+	enabled = duration ? 1 : 0;
-+
-+	ret = mwl_fwcmd_quiet_mode(priv->hw, enabled, period,
-+				   duration, SYSADPT_QUIET_START_OFFSET);
-+	if (ret) {
-+		wiphy_warn(priv->hw->wiphy,
-+			   "failed: period %u duarion %u enabled %u ret %d\n",
-+			    period, duration, enabled, ret);
-+	}
-+}
-+
-+int mwl_thermal_register(struct mwl_priv *priv)
-+{
-+	struct thermal_cooling_device *cdev;
-+	struct device *hwmon_dev;
-+	int ret;
-+
-+	if (priv->chip_type != MWL8897)
-+		return 0;
-+
-+	cdev = thermal_cooling_device_register("mwlwifi_thermal", priv,
-+					       &mwl_thermal_ops);
-+	if (IS_ERR(cdev)) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "failed to setup thermal device result: %ld\n",
-+			  PTR_ERR(cdev));
-+		return -EINVAL;
-+	}
-+
-+	ret = sysfs_create_link(&priv->dev->kobj, &cdev->device.kobj,
-+				"cooling_device");
-+	if (ret) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "failed to create cooling device symlink\n");
-+		goto err_cooling_destroy;
-+	}
-+
-+	priv->cdev = cdev;
-+	priv->quiet_period = SYSADPT_QUIET_PERIOD_DEFAULT;
-+
-+	if (!IS_ENABLED(CONFIG_HWMON))
-+		return 0;
-+
-+	hwmon_dev =
-+		devm_hwmon_device_register_with_groups(priv->dev,
-+						       "mwlwifi_hwmon", priv,
-+						       mwl_hwmon_groups);
-+	if (IS_ERR(hwmon_dev)) {
-+		wiphy_err(priv->hw->wiphy,
-+			  "failed to register hwmon device: %ld\n",
-+			  PTR_ERR(hwmon_dev));
-+		ret = -EINVAL;
-+		goto err_remove_link;
-+	}
-+
-+	return 0;
-+
-+err_remove_link:
-+	sysfs_remove_link(&priv->dev->kobj, "cooling_device");
-+err_cooling_destroy:
-+	thermal_cooling_device_unregister(cdev);
-+
-+	return ret;
-+}
-+
-+void mwl_thermal_unregister(struct mwl_priv *priv)
-+{
-+	if (priv->chip_type != MWL8897)
-+		return;
-+
-+	sysfs_remove_link(&priv->dev->kobj, "cooling_device");
-+	thermal_cooling_device_unregister(priv->cdev);
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/thermal.h b/drivers/net/wireless/marvell/mwlwifi/thermal.h
-new file mode 100644
-index 000000000000..c7f0ad2b87eb
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/thermal.h
-@@ -0,0 +1,42 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines Linux thermal framework related functions. */
-+
-+#ifndef _THERMAL_H_
-+#define _THERMAL_H_
-+
-+#include <linux/kconfig.h>
-+
-+#if IS_ENABLED(CONFIG_THERMAL)
-+int mwl_thermal_register(struct mwl_priv *priv);
-+void mwl_thermal_unregister(struct mwl_priv *priv);
-+void mwl_thermal_set_throttling(struct mwl_priv *priv);
-+#else
-+static inline int mwl_thermal_register(struct mwl_priv *priv)
-+{
-+	return 0;
-+}
-+
-+static inline void mwl_thermal_unregister(struct mwl_priv *priv)
-+{
-+}
-+
-+static inline void mwl_thermal_set_throttling(struct mwl_priv *priv)
-+{
-+}
-+#endif
-+
-+#endif /* _THERMAL_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/utils.c b/drivers/net/wireless/marvell/mwlwifi/utils.c
-new file mode 100644
-index 000000000000..b73054a3f55e
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/utils.c
-@@ -0,0 +1,576 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements common utility functions. */
-+
-+#include <linux/etherdevice.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+
-+static unsigned short phy_rate[][5] = {
-+	{2,   13,  15,  27,  30},   /* 0  */
-+	{4,   26,  29,  54,  60},   /* 1  */
-+	{11,  39,  43,  81,  90},   /* 2  */
-+	{22,  52,  58,  108, 120},  /* 3  */
-+	{44,  78,  87,  162, 180},  /* 4  */
-+	{12,  104, 115, 216, 240},  /* 5  */
-+	{18,  117, 130, 243, 270},  /* 6  */
-+	{24,  130, 144, 270, 300},  /* 7  */
-+	{36,  26,  29,  54,  60},   /* 8  */
-+	{48,  52,  58,  108, 120},  /* 9  */
-+	{72,  78,  87,  162, 180},  /* 10 */
-+	{96,  104, 116, 216, 240},  /* 11 */
-+	{108, 156, 173, 324, 360},  /* 12 */
-+	{0,   208, 231, 432, 480},  /* 13 */
-+	{0,   234, 260, 486, 540},  /* 14 */
-+	{0,   260, 289, 540, 600},  /* 15 */
-+	{0,   39,  43,  81,  90},   /* 16 */
-+	{0,   78,  87,  162, 180},  /* 17 */
-+	{0,   117, 130, 243, 270},  /* 18 */
-+	{0,   156, 173, 324, 360},  /* 19 */
-+	{0,   234, 260, 486, 540},  /* 20 */
-+	{0,   312, 347, 648, 720},  /* 21 */
-+	{0,   351, 390, 729, 810},  /* 22 */
-+	{0,   390, 433, 810, 900},  /* 23 */
-+};
-+
-+/* 20Mhz: Nss1_LGI, Nss1_SGI, Nss2_LGI, Nss2_SGI, Nss3_LGI, Nss3_SGI */
-+static unsigned short phy_rate_11ac20M[][6] = {
-+	{13,  15,  26,  29,  39,  44},   /* 0 */
-+	{26,  29,  52,  58,  78,  87},   /* 1 */
-+	{39,  44,  78,  87,  117, 130},  /* 2 */
-+	{52,  58,  104, 116, 156, 174},  /* 3 */
-+	{78,  87,  156, 174, 234, 260},  /* 4 */
-+	{104, 116, 208, 231, 312, 347},  /* 5 */
-+	{117, 130, 234, 260, 351, 390},  /* 6 */
-+	{130, 145, 260, 289, 390, 434},  /* 7 */
-+	{156, 174, 312, 347, 468, 520},  /* 8 */
-+	/* Nss 1 and Nss 2 mcs9 not valid */
-+	{2,   2,   2,   2,   520, 578},  /* 9 */
-+};
-+
-+/* 40Mhz: Nss1_LGI, Nss1_SGI, Nss2_LGI, Nss2_SGI, Nss3_LGI, Nss3_SGI */
-+static unsigned short phy_rate_11ac40M[][6] = {
-+	{27,  30,  54,  60,  81,   90},   /* 0 */
-+	{54,  60,  108, 120, 162,  180},  /* 1 */
-+	{81,  90,  162, 180, 243,  270},  /* 2 */
-+	{108, 120, 216, 240, 324,  360},  /* 3 */
-+	{162, 180, 324, 360, 486,  540},  /* 4 */
-+	{216, 240, 432, 480, 648,  720},  /* 5 */
-+	{243, 270, 486, 540, 729,  810},  /* 6 */
-+	{270, 300, 540, 600, 810,  900},  /* 7 */
-+	{324, 360, 648, 720, 972,  1080}, /* 8 */
-+	{360, 400, 720, 800, 1080, 1200}, /* 9 */
-+};
-+
-+/* 80Mhz: Nss1_LGI, Nss1_SGI, Nss2_LGI, Nss2_SGI, Nss3_LGI, Nss3_SGI */
-+static unsigned short phy_rate_11ac80M[][6] = {
-+	{59,  65,  117,  130,  175,  195},  /* 0 */
-+	{117, 130, 234,  260,  351,  390},  /* 1 */
-+	{175, 195, 351,  390,  527,  585},  /* 2 */
-+	{234, 260, 468,  520,  702,  780},  /* 3 */
-+	{351, 390, 702,  780,  1053, 1170}, /* 4 */
-+	{468, 520, 936,  1040, 1404, 1560}, /* 5 */
-+	{527, 585, 1053, 1170, 2,    2},    /* 6, Nss 3 mcs6 not valid */
-+	{585, 650, 1170, 1300, 1755, 1950}, /* 7 */
-+	{702, 780, 1404, 1560, 2106, 2340}, /* 8 */
-+	{780, 867, 1560, 1733, 2340, 2600}, /* 9 */
-+};
-+
-+/* 160Mhz: Nss1_LGI, Nss1_SGI, Nss2_LGI, Nss2_SGI, Nss3_LGI, Nss3_SGI */
-+static unsigned short phy_rate_11ac160M[][6] = {
-+	{117,   130,  234,  260,  351,  390},  /* 0 */
-+	{234,   260,  468,  520,  702,  780},  /* 1 */
-+	{351,   390,  702,  780,  1053, 1170}, /* 2 */
-+	{468,   520,  936,  1040, 1404, 1560}, /* 3 */
-+	{702,   780,  1404, 1560, 2106, 2340}, /* 4 */
-+	{936,   1040, 1872, 2080, 2808, 3120}, /* 5 */
-+	{1053,  1170, 2106, 2340, 3159, 3510}, /* 6 */
-+	{1170,  1300, 2340, 2600, 3510, 3900}, /* 7 */
-+	{1404,  1560, 2808, 3120, 4212, 4680}, /* 8 */
-+	{1560,  1733, 2130, 3467, 4680, 5200}, /* 9 */
-+};
-+
-+int utils_get_phy_rate(u8 format, u8 bandwidth, u8 short_gi, u8 mcs_id)
-+{
-+	u8 index = 0;
-+	u8 nss_11ac = 0;
-+	u8 rate_11ac = 0;
-+
-+	if (format == TX_RATE_FORMAT_11N) {
-+		index = (bandwidth << 1) | short_gi;
-+		index++;
-+	} else if (format == TX_RATE_FORMAT_11AC) {
-+		rate_11ac = mcs_id & 0xf; /* 11ac, mcs_id[3:0]: rate     */
-+		nss_11ac = mcs_id >> 4;	  /* 11ac, mcs_id[6:4]: nss code */
-+		index = (nss_11ac << 1) | short_gi;
-+	}
-+
-+	if (format != TX_RATE_FORMAT_11AC)
-+		return (phy_rate[mcs_id][index] / 2);
-+
-+	if (bandwidth == TX_RATE_BANDWIDTH_20)
-+		return (phy_rate_11ac20M[rate_11ac][index] / 2);
-+	else if (bandwidth == TX_RATE_BANDWIDTH_40)
-+		return (phy_rate_11ac40M[rate_11ac][index] / 2);
-+	else if (bandwidth == TX_RATE_BANDWIDTH_80)
-+		return (phy_rate_11ac80M[rate_11ac][index] / 2);
-+	else
-+		return (phy_rate_11ac160M[rate_11ac][index] / 2);
-+}
-+
-+u8 utils_get_rate_id(u8 rate)
-+{
-+	switch (rate) {
-+	case 10:   /* 1 Mbit/s or 12 Mbit/s */
-+		return 0;
-+	case 20:   /* 2 Mbit/s */
-+		return 1;
-+	case 55:   /* 5.5 Mbit/s */
-+		return 2;
-+	case 110:  /* 11 Mbit/s */
-+		return 3;
-+	case 220:  /* 22 Mbit/s */
-+		return 4;
-+	case 0xb:  /* 6 Mbit/s */
-+		return 5;
-+	case 0xf:  /* 9 Mbit/s */
-+		return 6;
-+	case 0xe:  /* 18 Mbit/s */
-+		return 8;
-+	case 0x9:  /* 24 Mbit/s */
-+		return 9;
-+	case 0xd:  /* 36 Mbit/s */
-+		return 10;
-+	case 0x8:  /* 48 Mbit/s */
-+		return 11;
-+	case 0xc:  /* 54 Mbit/s */
-+		return 12;
-+	case 0x7:  /* 72 Mbit/s */
-+		return 13;
-+	}
-+
-+	return 0;
-+}
-+
-+u32 utils_get_init_tx_rate(struct mwl_priv *priv, struct ieee80211_conf *conf,
-+			   struct ieee80211_sta *sta)
-+{
-+	u32 tx_rate;
-+	u16 format, nss, bw, rate_mcs;
-+
-+	if (sta->vht_cap.vht_supported)
-+		format = TX_RATE_FORMAT_11AC;
-+	else if (sta->ht_cap.ht_supported)
-+		format = TX_RATE_FORMAT_11N;
-+	else
-+		format = TX_RATE_FORMAT_LEGACY;
-+
-+	switch (priv->antenna_tx) {
-+	case ANTENNA_TX_1:
-+		nss = 1;
-+		break;
-+	case ANTENNA_TX_2:
-+		nss = 2;
-+		break;
-+	case ANTENNA_TX_3:
-+	case ANTENNA_TX_4_AUTO:
-+		nss = 3;
-+		break;
-+	default:
-+		nss = sta->rx_nss;
-+		break;
-+	}
-+	if (nss > sta->rx_nss)
-+		nss = sta->rx_nss;
-+
-+	switch (conf->chandef.width) {
-+	case NL80211_CHAN_WIDTH_20_NOHT:
-+	case NL80211_CHAN_WIDTH_20:
-+		bw = TX_RATE_BANDWIDTH_20;
-+		break;
-+	case NL80211_CHAN_WIDTH_40:
-+		bw = TX_RATE_BANDWIDTH_40;
-+		break;
-+	case NL80211_CHAN_WIDTH_80:
-+		bw = TX_RATE_BANDWIDTH_80;
-+		break;
-+	case NL80211_CHAN_WIDTH_160:
-+		bw = TX_RATE_BANDWIDTH_160;
-+		break;
-+	default:
-+		bw = sta->bandwidth;
-+		break;
-+	}
-+	if (bw > sta->bandwidth)
-+		bw = sta->bandwidth;
-+
-+	switch (format) {
-+	case TX_RATE_FORMAT_LEGACY:
-+		rate_mcs = 12; /* ignore 11b */
-+		break;
-+	case TX_RATE_FORMAT_11N:
-+		rate_mcs = (nss * 8) - 1;
-+		break;
-+	default:
-+		rate_mcs = ((nss - 1) << 4) | 8;
-+		break;
-+	}
-+
-+	tx_rate = (format | (bw << MWL_TX_RATE_BANDWIDTH_SHIFT) |
-+		(TX_RATE_INFO_SHORT_GI << MWL_TX_RATE_SHORTGI_SHIFT) |
-+		(rate_mcs << MWL_TX_RATE_RATEIDMCS_SHIFT));
-+
-+	return tx_rate;
-+}
-+
-+struct mwl_vif *utils_find_vif_bss(struct mwl_priv *priv, u8 *bssid)
-+{
-+	struct mwl_vif *mwl_vif;
-+
-+	spin_lock_bh(&priv->vif_lock);
-+	list_for_each_entry(mwl_vif, &priv->vif_list, list) {
-+		if (ether_addr_equal(bssid, mwl_vif->bssid)) {
-+			spin_unlock_bh(&priv->vif_lock);
-+			return mwl_vif;
-+		}
-+	}
-+	spin_unlock_bh(&priv->vif_lock);
-+
-+	return NULL;
-+}
-+
-+struct mwl_sta *utils_find_sta(struct mwl_priv *priv, u8 *addr)
-+{
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv);
-+		if (ether_addr_equal(addr, sta->addr)) {
-+			spin_unlock_bh(&priv->sta_lock);
-+			return sta_info;
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	return NULL;
-+}
-+
-+struct mwl_sta *utils_find_sta_by_aid(struct mwl_priv *priv, u16 aid)
-+{
-+	struct mwl_sta *sta_info;
-+	struct ieee80211_sta *sta;
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		sta = container_of((void *)sta_info, struct ieee80211_sta,
-+				   drv_priv);
-+		if (sta->aid == aid) {
-+			spin_unlock_bh(&priv->sta_lock);
-+			return sta_info;
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	return NULL;
-+}
-+
-+struct mwl_sta *utils_find_sta_by_id(struct mwl_priv *priv, u16 stnid)
-+{
-+	struct mwl_sta *sta_info;
-+
-+	spin_lock_bh(&priv->sta_lock);
-+	list_for_each_entry(sta_info, &priv->sta_list, list) {
-+		if (sta_info->stnid == stnid) {
-+			spin_unlock_bh(&priv->sta_lock);
-+			return sta_info;
-+		}
-+	}
-+	spin_unlock_bh(&priv->sta_lock);
-+
-+	return NULL;
-+}
-+
-+void utils_dump_data_info(const char *prefix_str, const void *buf, size_t len)
-+{
-+	print_hex_dump(KERN_INFO, prefix_str, DUMP_PREFIX_OFFSET,
-+		       16, 1, buf, len, true);
-+}
-+
-+void utils_dump_data_debug(const char *prefix_str, const void *buf, size_t len)
-+{
-+	print_hex_dump(KERN_DEBUG, prefix_str, DUMP_PREFIX_OFFSET,
-+		       16, 1, buf, len, true);
-+}
-+
-+bool utils_is_non_amsdu_packet(const void *packet, bool mac80211)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct iphdr *iph;
-+	struct udphdr *udph;
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == cpu_to_be16(ETH_P_PAE))
-+		return true;
-+
-+	if (*protocol == htons(ETH_P_ARP))
-+		return true;
-+
-+	if (*protocol == htons(ETH_P_IP)) {
-+		data += sizeof(__be16);
-+		iph = (struct iphdr *)data;
-+		if (iph->protocol == IPPROTO_ICMP)
-+			return true;
-+		if (iph->protocol == IPPROTO_UDP) {
-+			data += (iph->ihl * 4);
-+			udph = (struct udphdr *)data;
-+			if (((udph->source == htons(68)) &&
-+			    (udph->dest == htons(67))) ||
-+			    ((udph->source == htons(67)) &&
-+			    (udph->dest == htons(68))))
-+				return true;
-+		}
-+	}
-+
-+	return false;
-+}
-+
-+bool utils_is_arp(const void *packet, bool mac80211, u16 *arp_op)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct arphdr *arph;
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == htons(ETH_P_ARP)) {
-+		data += sizeof(__be16);
-+		arph = (struct arphdr *)data;
-+		*arp_op = ntohs(arph->ar_op);
-+		return true;
-+	}
-+
-+	return false;
-+}
-+
-+bool utils_is_icmp_echo(const void *packet, bool mac80211, u8 *type)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct iphdr *iph;
-+	struct icmphdr *icmph;
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == htons(ETH_P_IP)) {
-+		data += sizeof(__be16);
-+		iph = (struct iphdr *)data;
-+		if (iph->protocol == IPPROTO_ICMP) {
-+			data += (iph->ihl * 4);
-+			icmph = (struct icmphdr *)data;
-+			*type = icmph->type;
-+			return true;
-+		}
-+	}
-+
-+	return false;
-+}
-+
-+bool utils_is_dhcp(const void *packet, bool mac80211, u8 *op, u8 *dhcp_client)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct iphdr *iph;
-+	struct udphdr *udph;
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == htons(ETH_P_IP)) {
-+		data += sizeof(__be16);
-+		iph = (struct iphdr *)data;
-+		if (iph->protocol == IPPROTO_UDP) {
-+			data += (iph->ihl * 4);
-+			udph = (struct udphdr *)data;
-+			if (((udph->source == htons(68)) &&
-+			    (udph->dest == htons(67))) ||
-+			    ((udph->source == htons(67)) &&
-+			    (udph->dest == htons(68)))) {
-+				data += sizeof(struct udphdr);
-+				*op = *data;
-+				ether_addr_copy(dhcp_client, data + 28);
-+				return true;
-+			}
-+		}
-+	}
-+
-+	return false;
-+}
-+
-+void utils_dump_arp(const void *packet, bool mac80211, size_t len)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct arphdr *arph;
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == htons(ETH_P_ARP)) {
-+		data += sizeof(__be16);
-+		arph = (struct arphdr *)data;
-+		if (arph->ar_op == htons(ARPOP_REQUEST))
-+			utils_dump_data_info("ARP REQUEST: ", packet, len);
-+		else if (arph->ar_op == htons(ARPOP_REPLY))
-+			utils_dump_data_info("ARP REPLY: ", packet, len);
-+	}
-+}
-+
-+void utils_dump_icmp_echo(const void *packet, bool mac80211, size_t len)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct iphdr *iph;
-+	struct icmphdr *icmph;
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == htons(ETH_P_IP)) {
-+		data += sizeof(__be16);
-+		iph = (struct iphdr *)data;
-+		if (iph->protocol == IPPROTO_ICMP) {
-+			data += (iph->ihl * 4);
-+			icmph = (struct icmphdr *)data;
-+			if (icmph->type == ICMP_ECHO)
-+				utils_dump_data_info("ECHO REQUEST: ",
-+						     packet, len);
-+			else if (icmph->type == ICMP_ECHOREPLY)
-+				utils_dump_data_info("ECHO REPLY: ",
-+						     packet, len);
-+		}
-+	}
-+}
-+
-+void utils_dump_dhcp(const void *packet, bool mac80211, size_t len)
-+{
-+	const u8 *data = packet;
-+	struct ieee80211_hdr *wh;
-+	__be16 *protocol;
-+	struct iphdr *iph;
-+	struct udphdr *udph;
-+	const char *dhcp_op[8] = {
-+		"DHCPDISCOVER",
-+		"DHCPOFFER",
-+		"DHCPREQUEST",
-+		"DHCPDECLINE",
-+		"DHCPACK",
-+		"DHCPNAK",
-+		"DHCPRELEASE",
-+		"DHCPINFORM"
-+	};
-+
-+	if (mac80211) {
-+		/* mac80211 packet */
-+		wh = (struct ieee80211_hdr *)data;
-+		data += ieee80211_hdrlen(wh->frame_control) + 6;
-+		protocol = (__be16 *)data;
-+	} else {
-+		/* mac802.3 packet */
-+		data += (2 * ETH_ALEN);
-+		protocol = (__be16 *)data;
-+	}
-+
-+	if (*protocol == htons(ETH_P_IP)) {
-+		data += sizeof(__be16);
-+		iph = (struct iphdr *)data;
-+		if (iph->protocol == IPPROTO_UDP) {
-+			data += (iph->ihl * 4);
-+			udph = (struct udphdr *)data;
-+			if (((udph->source == htons(68)) &&
-+			    (udph->dest == htons(67))) ||
-+			    ((udph->source == htons(67)) &&
-+			    (udph->dest == htons(68)))) {
-+				data += sizeof(struct udphdr);
-+				utils_dump_data_info(dhcp_op[*data - 1],
-+						     packet, len);
-+			}
-+		}
-+	}
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/utils.h b/drivers/net/wireless/marvell/mwlwifi/utils.h
-new file mode 100644
-index 000000000000..4a292e990412
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/utils.h
-@@ -0,0 +1,158 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines common utility functions. */
-+
-+#ifndef _UTILS_H_
-+#define _UTILS_H_
-+
-+#include <net/arp.h>
-+#include <net/ip.h>
-+#include <net/udp.h>
-+#include <net/icmp.h>
-+
-+/* DHCP message types */
-+#define DHCPDISCOVER    1
-+#define DHCPOFFER       2
-+#define DHCPREQUEST     3
-+#define DHCPDECLINE     4
-+#define DHCPACK         5
-+#define DHCPNAK         6
-+#define DHCPRELEASE     7
-+#define DHCPINFORM      8
-+
-+static inline int utils_tid_to_ac(u8 tid)
-+{
-+	switch (tid) {
-+	case 0:
-+	case 3:
-+		return IEEE80211_AC_BE;
-+	case 1:
-+	case 2:
-+		return IEEE80211_AC_BK;
-+	case 4:
-+	case 5:
-+		return IEEE80211_AC_VI;
-+	case 6:
-+	case 7:
-+		return IEEE80211_AC_VO;
-+	default:
-+		break;
-+	}
-+
-+	return -1;
-+}
-+
-+static inline void utils_add_basic_rates(int band, struct sk_buff *skb)
-+{
-+	struct ieee80211_mgmt *mgmt;
-+	int len;
-+	u8 *pos;
-+
-+	mgmt = (struct ieee80211_mgmt *)skb->data;
-+	len = skb->len - ieee80211_hdrlen(mgmt->frame_control);
-+	len -= 4;
-+	pos = (u8 *)cfg80211_find_ie(WLAN_EID_SUPP_RATES,
-+				     mgmt->u.assoc_req.variable,
-+				     len);
-+	if (pos) {
-+		pos++;
-+		len = *pos++;
-+		while (len) {
-+			if (band == NL80211_BAND_2GHZ) {
-+				if ((*pos == 2) || (*pos == 4) ||
-+				    (*pos == 11) || (*pos == 22))
-+					*pos |= 0x80;
-+			} else {
-+				if ((*pos == 12) || (*pos == 24) ||
-+				    (*pos == 48))
-+					*pos |= 0x80;
-+			}
-+			pos++;
-+			len--;
-+		}
-+	}
-+}
-+
-+static inline int utils_assign_stnid(struct mwl_priv *priv, int macid, u16 aid)
-+{
-+	int stnid;
-+	int i;
-+
-+	spin_lock_bh(&priv->stnid_lock);
-+	stnid = priv->available_stnid;
-+	if (stnid >= priv->stnid_num) {
-+		spin_unlock_bh(&priv->stnid_lock);
-+		return 0;
-+	}
-+	priv->stnid[stnid].macid = macid;
-+	priv->stnid[stnid].aid = aid;
-+	stnid++;
-+	for (i = stnid; i < priv->stnid_num; i++) {
-+		if (!priv->stnid[i].aid)
-+			break;
-+	}
-+	priv->available_stnid = i;
-+	spin_unlock_bh(&priv->stnid_lock);
-+	return stnid;
-+}
-+
-+static inline void utils_free_stnid(struct mwl_priv *priv, u16 stnid)
-+{
-+	spin_lock_bh(&priv->stnid_lock);
-+	if (stnid && (stnid <= priv->stnid_num)) {
-+		stnid--;
-+		priv->stnid[stnid].macid = 0;
-+		priv->stnid[stnid].aid = 0;
-+		if (priv->available_stnid > stnid)
-+			priv->available_stnid = stnid;
-+	}
-+	spin_unlock_bh(&priv->stnid_lock);
-+}
-+
-+int utils_get_phy_rate(u8 format, u8 bandwidth, u8 short_gi, u8 mcs_id);
-+
-+u8 utils_get_rate_id(u8 rate);
-+
-+u32 utils_get_init_tx_rate(struct mwl_priv *priv, struct ieee80211_conf *conf,
-+			   struct ieee80211_sta *sta);
-+
-+struct mwl_vif *utils_find_vif_bss(struct mwl_priv *priv, u8 *bssid);
-+
-+struct mwl_sta *utils_find_sta(struct mwl_priv *priv, u8 *addr);
-+
-+struct mwl_sta *utils_find_sta_by_aid(struct mwl_priv *priv, u16 aid);
-+
-+struct mwl_sta *utils_find_sta_by_id(struct mwl_priv *priv, u16 stnid);
-+
-+void utils_dump_data_info(const char *prefix_str, const void *buf, size_t len);
-+
-+void utils_dump_data_debug(const char *prefix_str, const void *buf, size_t len);
-+
-+bool utils_is_non_amsdu_packet(const void *packet, bool mac80211);
-+
-+bool utils_is_arp(const void *packet, bool mac80211, u16 *arp_op);
-+
-+bool utils_is_icmp_echo(const void *packet, bool mac80211, u8 *type);
-+
-+bool utils_is_dhcp(const void *packet, bool mac80211, u8 *op, u8 *dhcp_client);
-+
-+void utils_dump_arp(const void *packet, bool mac80211, size_t len);
-+
-+void utils_dump_icmp_echo(const void *packet, bool mac80211, size_t len);
-+
-+void utils_dump_dhcp(const void *packet, bool mac80211, size_t len);
-+
-+#endif /* _UTILS_H_ */
-diff --git a/drivers/net/wireless/marvell/mwlwifi/vendor_cmd.c b/drivers/net/wireless/marvell/mwlwifi/vendor_cmd.c
-new file mode 100644
-index 000000000000..3e26fc42c225
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/vendor_cmd.c
-@@ -0,0 +1,136 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file implements vendor spcific functions. */
-+
-+#include <net/mac80211.h>
-+#include <net/netlink.h>
-+#include <linux/version.h>
-+
-+#include "sysadpt.h"
-+#include "core.h"
-+#include "utils.h"
-+#include "hif/fwcmd.h"
-+#include "vendor_cmd.h"
-+
-+static const struct nla_policy mwl_vendor_attr_policy[NUM_MWL_VENDOR_ATTR] = {
-+	[MWL_VENDOR_ATTR_BF_TYPE] = { .type = NLA_U8 },
-+};
-+
-+static int mwl_vendor_cmd_set_bf_type(struct wiphy *wiphy,
-+				      struct wireless_dev *wdev,
-+				      const void *data, int data_len)
-+{
-+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+	struct mwl_priv *priv = hw->priv;
-+	struct nlattr *tb[NUM_MWL_VENDOR_ATTR];
-+	int rc;
-+	u8 val;
-+
-+	if (priv->chip_type != MWL8964)
-+		return -EPERM;
-+
-+	rc = nla_parse(tb, MWL_VENDOR_ATTR_MAX, data, data_len,
-+		       mwl_vendor_attr_policy
-+#if (defined(LINUX_BACKPORT) || (LINUX_VERSION_CODE >=KERNEL_VERSION(4,12,0)))
-+               , NULL
-+#endif
-+               );
-+	if (rc)
-+		return rc;
-+
-+	if (!tb[MWL_VENDOR_ATTR_BF_TYPE])
-+		return -EINVAL;
-+
-+	val = nla_get_u8(tb[MWL_VENDOR_ATTR_BF_TYPE]);
-+	if ((val < TXBF_MODE_OFF) || (val > TXBF_MODE_BFMER_AUTO))
-+		return -EINVAL;
-+	wiphy_debug(wiphy, "set bf_type: 0x%x\n", val);
-+
-+	rc = mwl_fwcmd_set_bftype(hw, val);
-+	if (!rc)
-+		priv->bf_type = val;
-+
-+	return rc;
-+}
-+
-+static int mwl_vendor_cmd_get_bf_type(struct wiphy *wiphy,
-+				      struct wireless_dev *wdev,
-+				      const void *data, int data_len)
-+{
-+	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+	struct mwl_priv *priv = hw->priv;
-+	struct sk_buff *skb;
-+
-+	if (priv->chip_type != MWL8964)
-+		return -EPERM;
-+
-+	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 8);
-+	if (!skb)
-+		return -ENOMEM;
-+
-+	nla_put_u8(skb, MWL_VENDOR_ATTR_BF_TYPE, priv->bf_type);
-+
-+	return cfg80211_vendor_cmd_reply(skb);
-+}
-+
-+static const struct wiphy_vendor_command mwl_vendor_commands[] = {
-+	{
-+		.info = { .vendor_id = MRVL_OUI,
-+			  .subcmd = MWL_VENDOR_CMD_SET_BF_TYPE},
-+		.flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
-+		.doit = mwl_vendor_cmd_set_bf_type,
-+	},
-+	{
-+		.info = { .vendor_id = MRVL_OUI,
-+			  .subcmd = MWL_VENDOR_CMD_GET_BF_TYPE},
-+		.flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
-+		.doit = mwl_vendor_cmd_get_bf_type,
-+	}
-+};
-+
-+static const struct nl80211_vendor_cmd_info mwl_vendor_events[] = {
-+	{
-+		.vendor_id = MRVL_OUI,
-+		.subcmd =  MWL_VENDOR_EVENT_DRIVER_READY,
-+	},
-+	{
-+		.vendor_id = MRVL_OUI,
-+		.subcmd =  MWL_VENDOR_EVENT_DRIVER_START_REMOVE,
-+	},
-+	{
-+		.vendor_id = MRVL_OUI,
-+		.subcmd =  MWL_VENDOR_EVENT_CMD_TIMEOUT,
-+	}
-+};
-+
-+void vendor_cmd_register(struct wiphy *wiphy)
-+{
-+	wiphy->vendor_commands = mwl_vendor_commands;
-+	wiphy->n_vendor_commands = ARRAY_SIZE(mwl_vendor_commands);
-+	wiphy->vendor_events = mwl_vendor_events;
-+	wiphy->n_vendor_events = ARRAY_SIZE(mwl_vendor_events);
-+}
-+
-+void vendor_cmd_basic_event(struct wiphy *wiphy, int event_idx)
-+{
-+	struct sk_buff *skb;
-+
-+	skb = cfg80211_vendor_event_alloc(wiphy, NULL, 0,
-+					  event_idx, GFP_KERNEL);
-+
-+	if (skb)
-+		cfg80211_vendor_event(skb, GFP_KERNEL);
-+}
-diff --git a/drivers/net/wireless/marvell/mwlwifi/vendor_cmd.h b/drivers/net/wireless/marvell/mwlwifi/vendor_cmd.h
-new file mode 100644
-index 000000000000..b6fdf70c22fb
---- /dev/null
-+++ b/drivers/net/wireless/marvell/mwlwifi/vendor_cmd.h
-@@ -0,0 +1,60 @@
-+/*
-+ * Copyright (C) 2006-2018, 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.
-+ *
-+ * 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.
-+ */
-+
-+/* Description:  This file defines vendor constants and register function. */
-+
-+#ifndef _VENDOR_CMD_H_
-+#define _VENDOR_CMD_H_
-+
-+#ifdef __KERNEL__
-+void vendor_cmd_register(struct wiphy *wiphy);
-+void vendor_cmd_basic_event(struct wiphy *wiphy, int event_idx);
-+#endif
-+
-+#define MRVL_OUI        0x005043
-+
-+enum mwl_vendor_commands {
-+	MWL_VENDOR_CMD_SET_BF_TYPE,
-+	MWL_VENDOR_CMD_GET_BF_TYPE,
-+
-+	/* add commands here, update the command in vendor_cmd.c */
-+
-+	__MWL_VENDOR_CMD_AFTER_LAST,
-+	NUM_MWL_VENDOR_CMD = __MWL_VENDOR_CMD_AFTER_LAST,
-+	MWL_VENDOR_CMD_MAX = __MWL_VENDOR_CMD_AFTER_LAST - 1
-+};
-+
-+enum mwl_vendor_attributes {
-+	MWL_VENDOR_ATTR_NOT_USE,
-+	MWL_VENDOR_ATTR_BF_TYPE,
-+
-+	/* add attributes here, update the policy in vendor_cmd.c */
-+
-+	__MWL_VENDOR_ATTR_AFTER_LAST,
-+	NUM_MWL_VENDOR_ATTR = __MWL_VENDOR_ATTR_AFTER_LAST,
-+	MWL_VENDOR_ATTR_MAX = __MWL_VENDOR_ATTR_AFTER_LAST - 1
-+};
-+
-+enum mwl_vendor_events {
-+	MWL_VENDOR_EVENT_DRIVER_READY,
-+	MWL_VENDOR_EVENT_DRIVER_START_REMOVE,
-+	MWL_VENDOR_EVENT_CMD_TIMEOUT,
-+
-+	__MWL_VENDOR_EVENT_AFTER_LAST,
-+	NUM_MWL_VENDOR_EVENT = __MWL_VENDOR_EVENT_AFTER_LAST,
-+	MWL_VENDOR_EVENT_MAX = __MWL_VENDOR_EVENT_AFTER_LAST - 1
-+};
-+
-+#endif /* _VENDOR_CMD_H_ */
--- 
-2.24.1
-

+ 171 - 0
patches/4.19/0010-wifi.patch

@@ -0,0 +1,171 @@
+From 9715bc9a94fa7b9f30b3b12a6a09160a9aca43ec Mon Sep 17 00:00:00 2001
+From: sebanc <22224731+sebanc@users.noreply.github.com>
+Date: Mon, 4 Nov 2019 09:30:57 +0100
+Subject: [PATCH 10/10] wifi
+
+---
+ drivers/net/wireless/marvell/mwifiex/pcie.c   | 75 ++++++++++---------
+ .../net/wireless/marvell/mwifiex/sta_cmd.c    | 15 +---
+ 2 files changed, 40 insertions(+), 50 deletions(-)
+
+diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
+index 991b9cc18000..4549359ee19b 100644
+--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
+@@ -149,37 +149,39 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
+  */
+ static int mwifiex_pcie_suspend(struct device *dev)
+ {
+-	struct mwifiex_adapter *adapter;
+-	struct pcie_service_card *card;
+ 	struct pci_dev *pdev = to_pci_dev(dev);
++	struct pcie_service_card *card = pci_get_drvdata(pdev);
++	struct mwifiex_adapter *adapter;
++	struct mwifiex_private *priv;
++	const struct mwifiex_pcie_card_reg *reg;
++	u32 fw_status;
++	int ret;
+ 
+-	card = pci_get_drvdata(pdev);
+ 
+ 	/* Might still be loading firmware */
+ 	wait_for_completion(&card->fw_done);
+ 
+ 	adapter = card->adapter;
+-	if (!adapter) {
+-		dev_err(dev, "adapter is not valid\n");
++	if (!adapter || !adapter->priv_num)
+ 		return 0;
+-	}
+ 
+-	mwifiex_enable_wake(adapter);
++	reg = card->pcie.reg;
++	if (reg)
++		ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
++	else
++		fw_status = -1;
++
++	if (fw_status == FIRMWARE_READY_PCIE && !adapter->mfg_mode) {
++		mwifiex_deauthenticate_all(adapter);
+ 
+-	/* Enable the Host Sleep */
+-	if (!mwifiex_enable_hs(adapter)) {
+-		mwifiex_dbg(adapter, ERROR,
+-			    "cmd: failed to suspend\n");
+-		clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
+-		mwifiex_disable_wake(adapter);
+-		return -EFAULT;
+-	}
++		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ 
+-	flush_workqueue(adapter->workqueue);
++		mwifiex_disable_auto_ds(priv);
++
++		mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
++	}
+ 
+-	/* Indicate device suspended */
+-	set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
+-	clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
++	mwifiex_remove_card(adapter);
+ 
+ 	return 0;
+ }
+@@ -194,30 +196,29 @@ static int mwifiex_pcie_suspend(struct device *dev)
+  */
+ static int mwifiex_pcie_resume(struct device *dev)
+ {
+-	struct mwifiex_adapter *adapter;
+-	struct pcie_service_card *card;
+ 	struct pci_dev *pdev = to_pci_dev(dev);
++	struct pcie_service_card *card = pci_get_drvdata(pdev);
++	int ret;
+ 
+-	card = pci_get_drvdata(pdev);
++	pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
++		 pdev->vendor, pdev->device, pdev->revision);
+ 
+-	if (!card->adapter) {
+-		dev_err(dev, "adapter structure is not valid\n");
+-		return 0;
+-	}
++	init_completion(&card->fw_done);
+ 
+-	adapter = card->adapter;
++	card->dev = pdev;
+ 
+-	if (!test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) {
+-		mwifiex_dbg(adapter, WARN,
+-			    "Device already resumed\n");
+-		return 0;
++	/* device tree node parsing and platform specific configuration */
++	if (pdev->dev.of_node) {
++		ret = mwifiex_pcie_probe_of(&pdev->dev);
++		if (ret)
++			return ret;
+ 	}
+ 
+-	clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
+-
+-	mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+-			  MWIFIEX_ASYNC_CMD);
+-	mwifiex_disable_wake(adapter);
++	if (mwifiex_add_card(card, &card->fw_done, &pcie_ops,
++			MWIFIEX_PCIE, &pdev->dev)) {
++		pr_err("%s failed\n", __func__);
++		return -1;
++	}
+ 
+ 	return 0;
+ }
+@@ -271,6 +272,8 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
+ 		return -1;
+ 	}
+ 
++	pdev->bus->self->bridge_d3 = false;
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+index 4ed10cf82f9a..013db4386c39 100644
+--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+@@ -2265,14 +2265,13 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
+ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
+ {
+ 	struct mwifiex_adapter *adapter = priv->adapter;
+-	int ret;
+ 	struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+-	struct mwifiex_ds_auto_ds auto_ds;
+ 	enum state_11d_t state_11d;
+ 	struct mwifiex_ds_11n_tx_cfg tx_cfg;
+ 	u8 sdio_sp_rx_aggr_enable;
+ 	u16 packet_aggr_enable;
+ 	int data;
++	int ret;
+ 
+ 	if (first_sta) {
+ 		if (priv->adapter->iface_type == MWIFIEX_PCIE) {
+@@ -2395,18 +2394,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
+ 	if (ret)
+ 		return -1;
+ 
+-	if (!disable_auto_ds && first_sta &&
+-	    priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
+-		/* Enable auto deep sleep */
+-		auto_ds.auto_ds = DEEP_SLEEP_ON;
+-		auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
+-		ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+-				       EN_AUTO_PS, BITMAP_AUTO_DS,
+-				       &auto_ds, true);
+-		if (ret)
+-			return -1;
+-	}
+-
+ 	if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
+ 		/* Send cmd to FW to enable/disable 11D function */
+ 		state_11d = ENABLE_11D;
+-- 
+2.25.0
+