Project import generated by Copybara.

GitOrigin-RevId: a92375ebc2f1e14ddd0baf546636cf1edb5dac21
diff --git a/arch/arm/configs/ipq5018_sirocco_defconfig b/arch/arm/configs/ipq5018_sirocco_defconfig
index 1d1cb53..26ef7e2 100644
--- a/arch/arm/configs/ipq5018_sirocco_defconfig
+++ b/arch/arm/configs/ipq5018_sirocco_defconfig
@@ -4469,7 +4469,7 @@
 # CONFIG_SQUASHFS_DECOMP_SINGLE is not set
 # CONFIG_SQUASHFS_DECOMP_MULTI is not set
 CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
-# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_XATTR=y
 # CONFIG_SQUASHFS_ZLIB is not set
 # CONFIG_SQUASHFS_LZ4 is not set
 # CONFIG_SQUASHFS_LZO is not set
diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
index 33450fa..5b1387c 100644
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
@@ -814,7 +814,7 @@
 			<0 309 1>,
 			<0 310 1>,
 			<0 311 1>,
-			<0 312 1>,
+			<0 334 1>,
 			<0 313 1>, /* o_wcss_apps_intr[25] */
 
 			<0 314 1>,
@@ -840,7 +840,7 @@
 			<0 332 1>,
 
 			<0 333 1>,
-			<0 334 1>,
+			<0 312 1>,
 			<0 335 1>,
 			<0 336 1>,
 			<0 337 1>,
diff --git a/arch/arm64/boot/dts/qcom/sirocco-p0.dts b/arch/arm64/boot/dts/qcom/sirocco-p0.dts
index 6909b0d..cd7ec02 100644
--- a/arch/arm64/boot/dts/qcom/sirocco-p0.dts
+++ b/arch/arm64/boot/dts/qcom/sirocco-p0.dts
@@ -421,6 +421,7 @@
 &i2c_0 {
 	pinctrl-0 = <&i2c_pins>;
 	pinctrl-names = "default";
+	force-dma-mode;
 	status = "ok";
 
 	ina231: ina231@40 {
diff --git a/arch/arm64/configs/ipq5018_sirocco_defconfig b/arch/arm64/configs/ipq5018_sirocco_defconfig
index 21ae20c..99fcac2 100644
--- a/arch/arm64/configs/ipq5018_sirocco_defconfig
+++ b/arch/arm64/configs/ipq5018_sirocco_defconfig
@@ -4446,7 +4446,7 @@
 # CONFIG_SQUASHFS_DECOMP_SINGLE is not set
 # CONFIG_SQUASHFS_DECOMP_MULTI is not set
 CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
-# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_XATTR=y
 # CONFIG_SQUASHFS_ZLIB is not set
 # CONFIG_SQUASHFS_LZ4 is not set
 # CONFIG_SQUASHFS_LZO is not set
diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c
index db6da21..74ad8bf 100644
--- a/drivers/hid/hid-bigbenff.c
+++ b/drivers/hid/hid-bigbenff.c
@@ -191,7 +191,7 @@
 		struct bigben_device, worker);
 	struct hid_field *report_field = bigben->report->field[0];
 
-	if (bigben->removed)
+	if (bigben->removed || !report_field)
 		return;
 
 	if (bigben->work_led) {
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
index 3f0ed6a..e19e2b5 100644
--- a/drivers/hid/hid-chicony.c
+++ b/drivers/hid/hid-chicony.c
@@ -58,8 +58,12 @@
 static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	
+	struct usb_interface *intf;
+
+	if (!hid_is_usb(hdev))
+		return rdesc;
+
+	intf = to_usb_interface(hdev->dev.parent);
 	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
 		/* Change usage maximum and logical maximum from 0x7fff to
 		 * 0x2fff, so they don't exceed HID_MAX_USAGES */
diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c
index 902a60e..8c895c8 100644
--- a/drivers/hid/hid-corsair.c
+++ b/drivers/hid/hid-corsair.c
@@ -553,7 +553,12 @@
 	int ret;
 	unsigned long quirks = id->driver_data;
 	struct corsair_drvdata *drvdata;
-	struct usb_interface *usbif = to_usb_interface(dev->dev.parent);
+	struct usb_interface *usbif;
+
+	if (!hid_is_usb(dev))
+		return -EINVAL;
+
+	usbif = to_usb_interface(dev->dev.parent);
 
 	drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata),
 			       GFP_KERNEL);
diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c
index dae1937..0e8f424 100644
--- a/drivers/hid/hid-elan.c
+++ b/drivers/hid/hid-elan.c
@@ -50,7 +50,7 @@
 
 static int is_not_elan_touchpad(struct hid_device *hdev)
 {
-	if (hdev->bus == BUS_USB) {
+	if (hid_is_usb(hdev)) {
 		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
 		return (intf->altsetting->desc.bInterfaceNumber !=
diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c
index 0d22713..2876cb6 100644
--- a/drivers/hid/hid-elo.c
+++ b/drivers/hid/hid-elo.c
@@ -229,6 +229,9 @@
 	struct elo_priv *priv;
 	int ret;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c
index 0a38e8e..403506b 100644
--- a/drivers/hid/hid-holtek-kbd.c
+++ b/drivers/hid/hid-holtek-kbd.c
@@ -140,12 +140,17 @@
 static int holtek_kbd_probe(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	int ret = hid_parse(hdev);
+	struct usb_interface *intf;
+	int ret;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	ret = hid_parse(hdev);
 	if (!ret)
 		ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 
+	intf = to_usb_interface(hdev->dev.parent);
 	if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) {
 		struct hid_input *hidinput;
 		list_for_each_entry(hidinput, &hdev->inputs, list) {
diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c
index 195b735..b7172c4 100644
--- a/drivers/hid/hid-holtek-mouse.c
+++ b/drivers/hid/hid-holtek-mouse.c
@@ -62,6 +62,14 @@
 	return rdesc;
 }
 
+static int holtek_mouse_probe(struct hid_device *hdev,
+			      const struct hid_device_id *id)
+{
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+	return 0;
+}
+
 static const struct hid_device_id holtek_mouse_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
 			USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
@@ -83,6 +91,7 @@
 	.name = "holtek_mouse",
 	.id_table = holtek_mouse_devices,
 	.report_fixup = holtek_mouse_report_fixup,
+	.probe = holtek_mouse_probe,
 };
 
 module_hid_driver(holtek_mouse_driver);
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 0dc7cdf..2c7e7c0 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -769,12 +769,18 @@
 
 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
-	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_interface *iface;
+	__u8 iface_num;
 	unsigned int connect_mask = HID_CONNECT_DEFAULT;
 	struct lg_drv_data *drv_data;
 	int ret;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	iface = to_usb_interface(hdev->dev.parent);
+	iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
 	/* G29 only work with the 1st interface */
 	if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
 	    (iface_num != 0)) {
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 54d811f..f3cdb19 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -1680,7 +1680,7 @@
 	case recvr_type_27mhz:		no_dj_interfaces = 2; break;
 	case recvr_type_bluetooth:	no_dj_interfaces = 2; break;
 	}
-	if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+	if (hid_is_usb(hdev)) {
 		intf = to_usb_interface(hdev->dev.parent);
 		if (intf && intf->altsetting->desc.bInterfaceNumber >=
 							no_dj_interfaces) {
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 2666af0..e4e9471 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -798,12 +798,18 @@
 static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret;
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	struct usb_interface *intf;
+	unsigned short ifnum;
 	unsigned long quirks = id->driver_data;
 	struct pk_device *pk;
 	struct pcmidi_snd *pm = NULL;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
+	intf = to_usb_interface(hdev->dev.parent);
+	ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
 	pk = kzalloc(sizeof(*pk), GFP_KERNEL);
 	if (pk == NULL) {
 		hid_err(hdev, "can't alloc descriptor\n");
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index ffcd444..4b18e1a 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -344,6 +344,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index ce5f225..e95d59c 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -324,6 +324,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 509b9bb..6cf59b5 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -749,6 +749,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 0316edf..1896c69 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -431,6 +431,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
index 5248b3c..cf8eeb3 100644
--- a/drivers/hid/hid-roccat-konepure.c
+++ b/drivers/hid/hid-roccat-konepure.c
@@ -133,6 +133,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index 9600128..6fb9b95 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -501,6 +501,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c
index 4a88a76..d5ddf0d 100644
--- a/drivers/hid/hid-roccat-lua.c
+++ b/drivers/hid/hid-roccat-lua.c
@@ -160,6 +160,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 989927d..4fcc8e7 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -449,6 +449,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c
index 3956a6c..5bf1971 100644
--- a/drivers/hid/hid-roccat-ryos.c
+++ b/drivers/hid/hid-roccat-ryos.c
@@ -141,6 +141,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
index 818701f..a784bb4 100644
--- a/drivers/hid/hid-roccat-savu.c
+++ b/drivers/hid/hid-roccat-savu.c
@@ -113,6 +113,9 @@
 {
 	int retval;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	retval = hid_parse(hdev);
 	if (retval) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 2e1c311..cf5992e 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -152,6 +152,9 @@
 	int ret;
 	unsigned int cmask = HID_CONNECT_DEFAULT;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	ret = hid_parse(hdev);
 	if (ret) {
 		hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c
index 95e0807..6f107e3 100644
--- a/drivers/hid/hid-u2fzero.c
+++ b/drivers/hid/hid-u2fzero.c
@@ -286,7 +286,7 @@
 	unsigned int minor;
 	int ret;
 
-	if (!hid_is_using_ll_driver(hdev, &usb_hid_driver))
+	if (!hid_is_usb(hdev))
 		return -EINVAL;
 
 	dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index 8e9c9e6..4edb241 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -164,6 +164,9 @@
 	struct uclogic_drvdata *drvdata = NULL;
 	bool params_initialized = false;
 
+	if (!hid_is_usb(hdev))
+		return -EINVAL;
+
 	/*
 	 * libinput requires the pad interface to be on a different node
 	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index e80c812..ed4ede5 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -841,8 +841,7 @@
 	struct uclogic_params p = {0, };
 
 	/* Check arguments */
-	if (params == NULL || hdev == NULL ||
-	    !hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+	if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
 		rc = -EINVAL;
 		goto cleanup;
 	}
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index cd71e71..a54a177 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -726,7 +726,7 @@
 	 * Skip the query for this type and modify defaults based on
 	 * interface number.
 	 */
-	if (features->type == WIRELESS) {
+	if (features->type == WIRELESS && intf) {
 		if (intf->cur_altsetting->desc.bInterfaceNumber == 0)
 			features->device_type = WACOM_DEVICETYPE_WL_MONITOR;
 		else
@@ -2185,7 +2185,7 @@
 	if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
 		char *product_name = wacom->hdev->name;
 
-		if (hid_is_using_ll_driver(wacom->hdev, &usb_hid_driver)) {
+		if (hid_is_usb(wacom->hdev)) {
 			struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
 			struct usb_device *dev = interface_to_usbdev(intf);
 			product_name = dev->product;
@@ -2416,6 +2416,9 @@
 
 	wacom_destroy_battery(wacom);
 
+	if (!usbdev)
+		return;
+
 	/* Stylus interface */
 	hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
 	wacom1 = hid_get_drvdata(hdev1);
@@ -2695,8 +2698,6 @@
 static int wacom_probe(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
-	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-	struct usb_device *dev = interface_to_usbdev(intf);
 	struct wacom *wacom;
 	struct wacom_wac *wacom_wac;
 	struct wacom_features *features;
@@ -2731,8 +2732,14 @@
 	wacom_wac->hid_data.inputmode = -1;
 	wacom_wac->mode_report = -1;
 
-	wacom->usbdev = dev;
-	wacom->intf = intf;
+	if (hid_is_usb(hdev)) {
+		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+		struct usb_device *dev = interface_to_usbdev(intf);
+
+		wacom->usbdev = dev;
+		wacom->intf = intf;
+	}
+
 	mutex_init(&wacom->lock);
 	INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
 	INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 3417f7d..65831d9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -280,6 +280,7 @@
 	void (*read_rx_fifo)(struct qup_i2c_dev *qup);
 	/* function to write tags in tx fifo for i2c read transfer */
 	void (*write_rx_tags)(struct qup_i2c_dev *qup);
+	bool			force_dma;
 };
 
 static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
@@ -1529,8 +1530,8 @@
 		total_len += msgs[idx].len;
 	}
 
-	if (!no_dma && qup->is_dma &&
-	    (total_len > qup->out_fifo_sz || total_len > qup->in_fifo_sz)) {
+	if (!no_dma && qup->is_dma && (qup->force_dma ||
+	    (total_len > qup->out_fifo_sz || total_len > qup->in_fifo_sz))) {
 		qup->use_dma = true;
 	} else {
 		qup->blk.is_tx_blk_mode = max_tx_len > qup->out_fifo_sz -
@@ -1884,6 +1885,9 @@
 		qup->in_blk_sz, qup->in_fifo_sz,
 		qup->out_blk_sz, qup->out_fifo_sz);
 
+	qup->force_dma = of_property_read_bool(pdev->dev.of_node,
+						"force-dma-mode");
+
 	i2c_set_adapdata(&qup->adap, qup);
 	qup->adap.dev.parent = qup->dev;
 	qup->adap.dev.of_node = pdev->dev.of_node;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 8a537fe..48784f8 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -2107,8 +2107,6 @@
 	int err = 0;
 	size_t dma_buf_size = 0;
 
-	dev = qdev;
-
 	sec_kobj = kobject_create_and_add("sec_key", NULL);
 
 	if (!sec_kobj) {
@@ -2329,8 +2327,6 @@
 	if (!buf) {
 		pr_err("Failed to allocate page\n");
 		return -ENOMEM;
-	} else {
-               printk("\n memory allocated at physical address 0x%x\n",dma_buf);
 	}
 
 	/*
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index b569b05..8be4c50 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1653,32 +1653,32 @@
 	struct mmc_card *card = mq->card;
 	struct mmc_host *host = card->host;
 	blk_status_t error = BLK_STS_OK;
-	int retries = 0;
 
 	do {
 		u32 status;
 		int err;
+		int retries = 0;
 
-		mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
+		while (retries++ <= MMC_READ_SINGLE_RETRIES) {
+			mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
 
-		mmc_wait_for_req(host, mrq);
+			mmc_wait_for_req(host, mrq);
 
-		err = mmc_send_status(card, &status);
-		if (err)
-			goto error_exit;
-
-		if (!mmc_host_is_spi(host) &&
-		    !mmc_blk_in_tran_state(status)) {
-			err = mmc_blk_fix_state(card, req);
+			err = mmc_send_status(card, &status);
 			if (err)
 				goto error_exit;
+
+			if (!mmc_host_is_spi(host) &&
+			    !mmc_blk_in_tran_state(status)) {
+				err = mmc_blk_fix_state(card, req);
+				if (err)
+					goto error_exit;
+			}
+
+			if (!mrq->cmd->error)
+				break;
 		}
 
-		if (mrq->cmd->error && retries++ < MMC_READ_SINGLE_RETRIES)
-			continue;
-
-		retries = 0;
-
 		if (mrq->cmd->error ||
 		    mrq->data->error ||
 		    (!mmc_host_is_spi(host) &&
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
index 1bffe3f..1764069 100644
--- a/drivers/net/wireless/ath/ath10k/testmode.c
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -89,7 +89,7 @@
 		goto out;
 	}
 
-	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+	cfg80211_testmode_event(nl_skb, GFP_ATOMIC, false);
 
 out:
 	spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 11ed515..1415509 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -688,7 +688,7 @@
 		if (ret < 0)
 			return ret;
 
-		vector = (i % num_vectors) + base_vector;
+		vector = (i % num_vectors);
 
 		if (i >= ATH11K_EXT_IRQ_GRP_NUM_MAX)
 			break;
diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c
index ce4a689..54c9b1b 100644
--- a/drivers/net/wireless/ath/ath11k/ce.c
+++ b/drivers/net/wireless/ath/ath11k/ce.c
@@ -431,6 +431,11 @@
 
 		ATH11K_MEMORY_STATS_DEC(ab, ce_rx_pipe, skb->truesize);
 
+		if (!ATH11K_SKB_RXCB(skb)->paddr) {
+			ath11k_warn(ab, "Invalid paddr in skb received in CE\n");
+			continue;
+		}
+
 		dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
 				 max_nbytes, DMA_FROM_DEVICE);
 
@@ -512,6 +517,11 @@
 		if (!skb)
 			continue;
 
+		if (!ATH11K_SKB_CB(skb)->paddr) {
+			ath11k_warn(ab, "Invalid padd in Tx skb in CE\n");
+			continue;
+		}
+
 		dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len,
 				 DMA_TO_DEVICE);
 		if ((!pipe->send_cb) || ab->hw_params.credit_flow) {
@@ -622,6 +632,7 @@
 {
 	struct ath11k_ce_ring *ce_ring;
 	dma_addr_t base_addr;
+	unsigned long off;
 
 	ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL);
 	if (ce_ring == NULL)
@@ -650,12 +661,13 @@
 
 	ce_ring->base_addr_ce_space_unaligned = base_addr;
 
-	ce_ring->base_addr_owner_space = PTR_ALIGN(
-			ce_ring->base_addr_owner_space_unaligned,
+	ce_ring->base_addr_ce_space = (dma_addr_t) ALIGN(
+			(unsigned long)ce_ring->base_addr_ce_space_unaligned,
 			CE_DESC_RING_ALIGN);
-	ce_ring->base_addr_ce_space = ALIGN(
-			ce_ring->base_addr_ce_space_unaligned,
-			CE_DESC_RING_ALIGN);
+	off = (unsigned long)ce_ring->base_addr_ce_space -
+		(unsigned long)ce_ring->base_addr_ce_space_unaligned;
+	ce_ring->base_addr_owner_space = (void *)
+			((unsigned long)ce_ring->base_addr_owner_space_unaligned + off);
 
 	return ce_ring;
 }
@@ -1007,8 +1019,8 @@
 			dma_free_coherent(ab->dev,
 					  pipe->src_ring->nentries * desc_sz +
 					  CE_DESC_RING_ALIGN,
-					  pipe->src_ring->base_addr_owner_space,
-					  pipe->src_ring->base_addr_ce_space);
+					  pipe->src_ring->base_addr_owner_space_unaligned,
+					  pipe->src_ring->base_addr_ce_space_unaligned);
 			ATH11K_MEMORY_STATS_DEC(ab, ce_ring_alloc,
 						pipe->src_ring->nentries * desc_sz +
 						CE_DESC_RING_ALIGN);
@@ -1021,8 +1033,8 @@
 			dma_free_coherent(ab->dev,
 					  pipe->dest_ring->nentries * desc_sz +
 					  CE_DESC_RING_ALIGN,
-					  pipe->dest_ring->base_addr_owner_space,
-					  pipe->dest_ring->base_addr_ce_space);
+					  pipe->dest_ring->base_addr_owner_space_unaligned,
+					  pipe->dest_ring->base_addr_ce_space_unaligned);
 			ATH11K_MEMORY_STATS_DEC(ab, ce_ring_alloc,
 						pipe->dest_ring->nentries * desc_sz +
 						CE_DESC_RING_ALIGN);
@@ -1036,8 +1048,8 @@
 			dma_free_coherent(ab->dev,
 					  pipe->status_ring->nentries * desc_sz +
 					  CE_DESC_RING_ALIGN,
-					  pipe->status_ring->base_addr_owner_space,
-					  pipe->status_ring->base_addr_ce_space);
+					  pipe->status_ring->base_addr_owner_space_unaligned,
+					  pipe->status_ring->base_addr_ce_space_unaligned);
 			ATH11K_MEMORY_STATS_DEC(ab, ce_ring_alloc,
 						pipe->status_ring->nentries * desc_sz +
 						CE_DESC_RING_ALIGN);
diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h
index c586847..a82285d 100644
--- a/drivers/net/wireless/ath/ath11k/ce.h
+++ b/drivers/net/wireless/ath/ath11k/ce.h
@@ -141,7 +141,7 @@
 	/* Host address space */
 	void *base_addr_owner_space_unaligned;
 	/* CE address space */
-	u32 base_addr_ce_space_unaligned;
+	dma_addr_t base_addr_ce_space_unaligned;
 
 	/* Actual start of descriptors.
 	 * Aligned to descriptor-size boundary.
@@ -151,7 +151,7 @@
 	void *base_addr_owner_space;
 
 	/* CE address space */
-	u32 base_addr_ce_space;
+	dma_addr_t base_addr_ce_space;
 
 	/* HAL ring id */
 	u32 hal_ring_id;
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 00a5994..b5c4c1d 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -325,7 +326,7 @@
 		.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
 		.hw_ops = &ipq5018_ops,
 		.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074,
-		.ring_mask = &ath11k_hw_ring_mask_ipq5018,
+		.ring_mask = &ath11k_hw_ring_mask_qcn6122,
 		.regs = &ipq5018_regs,
 		.m3_addr = ATH11K_QMI_IPQ5018_M3_DUMP_ADDRESS,
 		.spectral_fft_sz = 2,
@@ -363,7 +364,7 @@
 		.is_qdss_support = false,
 		.max_tx_ring = 1,
 		.wakeup_mhi = false,
-		.reo_status_poll = true,
+		.reo_status_poll = false,
 		.cfr_support = true,
 		.cfr_dma_hdr_size = sizeof(struct ath11k_cfir_dma_hdr),
 		.cfr_num_stream_bufs = 255,
@@ -389,7 +390,7 @@
 		.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
 		.hw_ops = &qcn6122_ops,
 		.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122,
-		.ring_mask = &ath11k_hw_ring_mask_ipq5018,
+		.ring_mask = &ath11k_hw_ring_mask_qcn6122,
 		.regs = &qcn6122_regs,
 		.m3_addr = ATH11K_QMI_QCN6122_M3_DUMP_ADDRESS,
 		.spectral_fft_sz = 2,
@@ -427,7 +428,7 @@
  		.is_qdss_support = true,
 		.max_tx_ring = 1,
 		.wakeup_mhi = false,
-		.reo_status_poll = true,
+		.reo_status_poll = false,
 		.cfr_support = true,
 		.cfr_dma_hdr_size = sizeof(struct ath11k_cfir_dma_hdr),
 		.cfr_num_stream_bufs = 255,
@@ -899,7 +900,8 @@
 	ab->bd_api = 2;
 
 	if (country_code && strlen(country_code) == 2) {
-		strcpy(cc, country_code);
+		memcpy(cc, country_code, 2);
+		cc[2] = 0;
 		ath11k_country_str_tolower(cc);
 		scnprintf(filename, sizeof(filename),
 			  "board-2-%s.bin", cc);
@@ -1052,7 +1054,7 @@
 err_nss_tear:
 	ath11k_nss_teardown(ab);
 err_dp_pdev_free:
-	ath11k_dp_pdev_free(ab);
+	ath11k_dp_pdev_free(ab, true);
 err_pdev_debug:
 	ath11k_debugfs_pdev_destroy(ab);
 
@@ -1070,7 +1072,7 @@
 	ath11k_nss_set_enabled(ab, false);
 
 	ath11k_hif_irq_disable(ab);
-	ath11k_dp_pdev_free(ab);
+	ath11k_dp_pdev_free(ab, true);
 	ath11k_debugfs_pdev_destroy(ab);
 }
 
@@ -1369,7 +1371,7 @@
 	ath11k_spectral_deinit(ab);
 	ath11k_thermal_unregister(ab);
 	ath11k_hif_irq_disable(ab);
-	ath11k_dp_pdev_free(ab);
+	ath11k_dp_pdev_free(ab, false);
 	ath11k_hif_stop(ab);
 	ath11k_wmi_detach(ab);
 	ath11k_dp_pdev_reo_cleanup(ab);
@@ -1449,6 +1451,7 @@
 		ath11k_mac_drain_tx(ar);
 		complete(&ar->scan.started);
 		complete(&ar->scan.completed);
+		complete(&ar->scan.on_channel);
 		complete(&ar->peer_assoc_done);
 		complete(&ar->peer_delete_done);
 		complete(&ar->install_key_done);
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 09293d0..e135162 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -127,7 +127,7 @@
 	bool is_last_msdu;
 	bool is_continuation;
 	bool is_mcbc;
-	bool is_eapol;
+	bool is_eapol_tkip;
 	struct hal_rx_desc *rx_desc;
 	u8 err_rel_src;
 	u8 err_code;
@@ -363,6 +363,8 @@
 	u32 tid_conf_changed[ATH11K_TID_MAX];
 	struct ath11k_tid_qos_config tid_cfg[ATH11K_TID_MAX];
 	u32 tids_rst;
+	u64 tbtt_offset;
+	struct work_struct update_bcn_template_work;
 	DECLARE_BITMAP(free_groupidx_map, ATH11K_GROUP_KEYS_NUM_MAX);
 };
 
@@ -529,6 +531,7 @@
 	u64 tx_duration;
 	u32 tx_rts_retry_count;
 	u8 rssi_comb;
+	u32 tx_retry_count;
 	struct ewma_avg_rssi avg_rssi;
 	struct ath11k_htt_tx_stats *tx_stats;
 	struct ath11k_rx_peer_stats *rx_stats;
@@ -559,6 +562,7 @@
 	struct ewma_sta_per per;
 	u64 fail_pkts;
 	u64 succ_pkts;
+	u64 drop_pkts;
 	u64 msdu_cnt[ATH11K_TID_MAX];
 	u64 mpdu_cnt[ATH11K_TID_MAX];
 	u64 ppdu_cnt[ATH11K_TID_MAX];
@@ -568,9 +572,11 @@
 	struct ewma_sta_ber ber;
 	u64 succ_bytes;
 	u64 fail_bytes;
+	u64 drop_bytes;
 	/*bytes count for bit error rate computation*/
 	u32 ber_succ_bytes;
 	u32 ber_fail_bytes;
+	u32 last_tx_pkt_bw;
 
 	u8 sta_kickout;
 	unsigned long sta_kickout_timeout;
@@ -582,6 +588,9 @@
 	struct ath11k_per_peer_cfr_capture cfr_capture;
 #endif
 	struct ath11k_smart_ant_sta *smart_ant_sta;
+	struct completion disassoc_comp;
+	bool tx_disassoc;
+	u32 bw_last;
 };
 
 #define ATH11K_HALF_20MHZ_BW 10
@@ -802,10 +811,17 @@
 	u32 afc_wfa_version;
 	bool is_6g_afc_expiry_event_received;
 	bool is_6g_afc_power_event_received;
+	bool switch_to_lpi_indication_received;
 	struct ath11k_afc_sp_reg_info *afc_reg_info;
 	bool afc_regdom_configured;
 };
 
+enum mon_status_buf_done {
+	MON_STATUS_BUF_DONE = 0,
+	MON_STATUS_NO_BUF_DONE = 1,
+	MON_STATUS_BUF_DONE_NEXT = 2,
+};
+
 struct ath11k {
 	struct ath11k_base *ab;
 	struct ath11k_pdev *pdev;
@@ -845,9 +861,11 @@
 	u32 max_tx_power;
 	u32 txpower_limit_2g;
 	u32 txpower_limit_5g;
+	u32 txpower_limit_6g;
 	u32 txpower_scale;
 	u32 power_scale;
 	u32 chan_tx_pwr;
+	s32 chan_noise_floor;
 	u32 num_stations;
 	u32 max_num_stations;
 	bool monitor_conf_enabled;
@@ -972,11 +990,16 @@
 	u32 chan_bw_interference_bitmap;
 	bool awgn_intf_handling_in_prog;
 	struct ath11k_rx_buf_id rx_buf_id;
+	u8 mgmt_retry_limit;
 
 	/* fw pdev_stats can be requested by get_txpower mac ops too */
 	struct list_head fw_stats_pdevs;
 	struct completion fw_stats_complete;
 	bool fw_stats_done;
+	u16 rts_threshold[NUM_NL80211_IFTYPES];
+	struct completion ani_status_event;
+	bool mon_status_skb_zero;
+	enum mon_status_buf_done mon_status_no_buf_done;
 };
 
 struct ath11k_band_cap {
@@ -1065,7 +1088,9 @@
 	u32 err_ring_pkts;
 	u32 invalid_rbm;
 	u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX];
+	u32 rxdma_error_drop[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX];
 	u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX];
+	u32 reo_error_drop[HAL_REO_DEST_RING_ERROR_CODE_MAX];
 	u32 hal_reo_error[DP_REO_DST_RING_MAX];
 	struct ath11k_soc_dp_tx_err_stats tx_err;
 	struct ath11k_dp_ring_bp_stats bp_stats;
@@ -1159,6 +1184,18 @@
 	struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS];
 	struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS];
 	unsigned long long free_vdev_map;
+
+	/*
+	 * The rhashtable containing struct ath11k_peer keyed by mac addr
+	 * protected under ab->base_lock spin lock
+	 */
+	struct rhashtable *rhead_peer_addr;
+	struct rhashtable_params rhash_peer_addr_param;
+
+	/* The rhashtable containing struct ath11k_peer keyed by id  */
+	struct rhashtable *rhead_peer_id;
+	struct rhashtable_params rhash_peer_id_param;
+
 	struct list_head peers;
 	wait_queue_head_t peer_mapping_wq;
 	u8 mac_addr[ETH_ALEN];
@@ -1256,6 +1293,8 @@
 	struct mutex base_ast_lock;
 	struct work_struct wmi_ast_work;
 	struct list_head wmi_ast_list;
+	u32 napi_poll_budget;
+	bool gro_support_enabled;
 
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
diff --git a/drivers/net/wireless/ath/ath11k/debug_nss.c b/drivers/net/wireless/ath/ath11k/debug_nss.c
index 74f2131..2899859 100644
--- a/drivers/net/wireless/ath/ath11k/debug_nss.c
+++ b/drivers/net/wireless/ath/ath11k/debug_nss.c
@@ -11,6 +11,8 @@
 #include "debug.h"
 #include "debug_nss.h"
 
+extern struct dentry *debugfs_debug_infra;
+
 static unsigned int
 debug_nss_fill_mpp_dump(struct ath11k_vif *arvif, char *buf, ssize_t size)
 {
@@ -1007,16 +1009,17 @@
 
 void ath11k_debugfs_nss_soc_create(struct ath11k_base *ab)
 {
-	struct dentry *debugfs_dbg_infra;
+	if (debugfs_debug_infra)
+		return;
 
-	debugfs_dbg_infra = debugfs_create_dir("dbg_infra", debugfs_ath11k);
+	debugfs_debug_infra = debugfs_create_dir("dbg_infra", debugfs_ath11k);
 
 	debugfs_create_file("links", 0200,
-			debugfs_dbg_infra, ab,
+			debugfs_debug_infra, ab,
 			&fops_nss_links);
 
 	debugfs_create_file("mpp_mode", 0600,
-			debugfs_dbg_infra, ab,
+			debugfs_debug_infra, ab,
 			&fops_nss_mpp_mode);
 }
 
diff --git a/drivers/net/wireless/ath/ath11k/debug_smart_ant.c b/drivers/net/wireless/ath/ath11k/debug_smart_ant.c
index 808f836..8fa98f2 100644
--- a/drivers/net/wireless/ath/ath11k/debug_smart_ant.c
+++ b/drivers/net/wireless/ath/ath11k/debug_smart_ant.c
@@ -56,6 +56,12 @@
 		return count;
 
 	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
 	if (enable) {
 		ret = ath11k_wmi_pdev_enable_smart_ant(ar,
 						       ATH11K_SMART_ANT_ENABLE,
@@ -113,6 +119,14 @@
 	if (len < ATH11K_SA_TX_ANT_MIN_LEN)
 		return -EINVAL;
 
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+	mutex_unlock(&ar->conf_mutex);
+
 	buf[len] = '\0';
 	sptr = buf;
 	for (i = 0; i < ETH_ALEN - 1; i++) {
@@ -198,6 +212,11 @@
 		   "Setting Rx antenna to %d\n", rxant);
 
 	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
 	ret = ath11k_wmi_pdev_set_rx_ant(ar, rxant);
 	mutex_unlock(&ar->conf_mutex);
 
@@ -245,6 +264,14 @@
 	char *token, *sptr;
 	char buf[128];
 
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+	mutex_unlock(&ar->conf_mutex);
+
 	if (!ath11k_smart_ant_enabled(ar))
 		return -ENOTSUPP;
 
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c
index 2562397..eb15353 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -17,6 +17,7 @@
 #include "qmi.h"
 
 struct dentry *debugfs_ath11k;
+struct dentry *debugfs_debug_infra;
 
 static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
 	"REO2SW1_RING",
@@ -258,9 +259,18 @@
 {
 	struct ath11k_vif *arvif = file->private_data;
 	struct wmi_ctrl_path_stats_cmd_param param = {0};
+	struct ath11k *ar = arvif->ar;
 	u8 buf[128] = {0};
 	int ret;
 
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+	mutex_unlock(&ar->conf_mutex);
+
 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
 	if (ret < 0) {
 		return ret;
@@ -709,10 +719,19 @@
 {
 	struct ath11k_vif *arvif = file->private_data;
 	struct ath11k_base *ab = arvif->ar->ab;
+	struct ath11k *ar = arvif->ar;
 	unsigned int tx_aggr_size = 0;
 	int ret;
 	struct set_custom_aggr_size_params params = {0};
 
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+	mutex_unlock(&ar->conf_mutex);
+
 	if (kstrtouint_from_user(ubuf, count, 0, &tx_aggr_size))
 		return -EINVAL;
 
@@ -1543,13 +1562,15 @@
 			 soc_stats->invalid_rbm);
 	len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
 	for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
-		len += scnprintf(buf + len, size - len, "%s: %u\n",
-				 rxdma_err[i], soc_stats->rxdma_error[i]);
+		len += scnprintf(buf + len, size - len, "%s: handled %u dropped %u\n",
+				 rxdma_err[i], soc_stats->rxdma_error[i],
+				 soc_stats->rxdma_error_drop[i]);
 
 	len += scnprintf(buf + len, size - len, "\nREO errors:\n");
 	for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
-		len += scnprintf(buf + len, size - len, "%s: %u\n",
-				 reo_err[i], soc_stats->reo_error[i]);
+		len += scnprintf(buf + len, size - len, "%s: handled %u dropped %u\n",
+				 reo_err[i], soc_stats->reo_error[i],
+				 soc_stats->reo_error_drop[i]);
 
 	len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
 	len += scnprintf(buf + len, size - len,
@@ -2176,7 +2197,7 @@
 		goto exit;
 	}
 
-	ret = ath11k_wmi_pdev_set_param(ar, ATH11K_AGGR_SW_RETRY_THRESHOLD,
+	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_AGG_SW_RETRY_TH,
 					retry_thold, pdev->pdev_id);
 
 	if (ret) {
@@ -2268,6 +2289,12 @@
 	debugfs_create_file("set_fw_recovery", 0600, ab->debugfs_soc, ab,
 			    &fops_fw_recovery);
 
+	debugfs_create_file("enable_memory_stats", 0600, ab->debugfs_soc,
+			    ab, &fops_enable_memory_stats);
+
+	debugfs_create_file("memory_stats", 0600, ab->debugfs_soc, ab,
+			    &fops_memory_stats);
+
 	debugfs_create_file("ce_latency_stats", 0600, ab->debugfs_soc, ab,
 			    &fops_ce_latency_stats);
 	debugfs_create_file("fw_dbglog_config", 0600, ab->debugfs_soc, ab,
@@ -2342,6 +2369,7 @@
 {
 	debugfs_remove_recursive(debugfs_ath11k);
 	debugfs_ath11k = NULL;
+	debugfs_debug_infra = NULL;
 }
 
 void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
@@ -2654,12 +2682,6 @@
 		}
 	}
 
-	debugfs_create_file("enable_memory_stats", 0600, ab->debugfs_soc,
-			    ab, &fops_enable_memory_stats);
-
-	debugfs_create_file("memory_stats", 0600, ab->debugfs_soc, ab,
-			    &fops_memory_stats);
-
 #define HTT_RX_FILTER_TLV_LITE_MODE \
 			(HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
 			HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
@@ -2765,6 +2787,12 @@
 	struct ath11k *ar = file->private_data;
 	int ret;
 
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
 	ret = ath11k_wmi_simulate_radar(ar);
 	if (ret)
 		return ret;
@@ -2848,10 +2876,6 @@
 
 	mutex_lock(&ar->conf_mutex);
 	arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
-	if (!arvif->is_started) {
-		ret = -EINVAL;
-		goto exit;
-	}
 
 	if(coex == 1 && !test_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags))
 		set_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags);
@@ -2941,11 +2965,6 @@
 
 	mutex_lock(&ar->conf_mutex);
 	arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
-	if (!arvif->is_started) {
-		ret = -EINVAL;
-		goto exit;
-	}
-
 	coex_config.vdev_id = arvif->vdev_id;
 	coex_config.config_type = WMI_COEX_CONFIG_AP_TDM;
 	coex_config.duty_cycle = duty_cycle;
@@ -3009,11 +3028,6 @@
 	mutex_lock(&ar->conf_mutex);
 
 	arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
-	if (!arvif->is_started) {
-		ret = -EINVAL;
-		goto exit;
-	}
-
 	ar->coex.coex_algo_type = coex_algo;
 	coex_config.vdev_id = arvif->vdev_id;
 	coex_config.config_type = WMI_COEX_CONFIG_FORCED_ALGO;
@@ -3198,6 +3212,12 @@
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
 	if (ar->ps_state_enable == ps_state_enable) {
 		ret = count;
 		goto exit;
@@ -3464,6 +3484,14 @@
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
+	mutex_unlock(&ar->conf_mutex);
+
 	buf = vmalloc(count);
 	if (!buf) {
 		ret = -ENOMEM;
@@ -4345,11 +4373,35 @@
 				      size_t count, loff_t *ppos)
 {
 	struct ath11k *ar = file->private_data;
-	int len = 0;
-	char buf[32];
+	unsigned long time_left;
+	int ret;
+	int len;
+	char buf[128];
 
-	len = scnprintf(buf, sizeof(buf) - len, "%d\n",ar->ani_enabled);
+	mutex_lock(&ar->conf_mutex);
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto unlock;
+	}
+	reinit_completion(&ar->ani_status_event);
+	ret = ath11k_wmi_pdev_get_ani_status(ar);
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to get ani status: %d\n", ret);
+		goto unlock;
+	}
+	time_left = wait_for_completion_timeout(&ar->ani_status_event,
+						1 * HZ);
+	if (time_left == 0) {
+		ret = -ETIMEDOUT;
+		goto unlock;
+	}
+	len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled);
+	mutex_unlock(&ar->conf_mutex);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+unlock:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
 }
 
 static ssize_t ath11k_write_ani_enable(struct file *file,
@@ -4365,6 +4417,12 @@
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d is not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
 	if (ar->ani_enabled == enable) {
 		ret = count;
 		goto exit;
@@ -4376,7 +4434,9 @@
 		ath11k_warn(ar->ab, "ani_enable failed from debugfs: %d\n", ret);
 		goto exit;
 	}
+	spin_lock_bh(&ar->data_lock);
 	ar->ani_enabled = enable;
+	spin_unlock_bh(&ar->data_lock);
 	ret = count;
 
 exit:
@@ -4420,6 +4480,12 @@
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
 	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ANI_POLL_PERIOD,
 			ani_poll_period, ar->pdev->pdev_id);
 	if (ret) {
@@ -4470,6 +4536,12 @@
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
 	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ANI_LISTEN_PERIOD,
 					ani_listen_period, ar->pdev->pdev_id);
 	if (ret) {
@@ -4893,22 +4965,26 @@
 						  size_t count, loff_t *ppos)
 {
 	struct ath11k *ar = file->private_data;
-	int rts_threshold, ret = 0;
+	int rts_threshold, ret = 0, vif_type;
 	struct ath11k_vif *arvif;
 	struct ieee80211_vif *vif;
+	char buf[128] = {0};
 
-	ret = kstrtoint_from_user(user_buf, count, 0, &rts_threshold);
-	if (ret)
+	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+	if (ret < 0)
+		return ret;
+
+	ret = sscanf(buf, "%d %d", &rts_threshold, &vif_type);
+	if (ret || vif_type >= NUM_NL80211_IFTYPES)
 		return ret;
 
 	mutex_lock(&ar->conf_mutex);
 	list_for_each_entry(arvif, &ar->arvifs, list) {
 		vif = arvif->vif;
-		if (vif->type != NL80211_IFTYPE_MESH_POINT) {
-			ar->hw->wiphy->rts_threshold = rts_threshold;
+		if (vif->type == vif_type) {
 			ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 							WMI_VDEV_PARAM_RTS_THRESHOLD,
-							ar->hw->wiphy->rts_threshold);
+							rts_threshold);
 			if (ret) {
 				ath11k_warn(ar->ab,
 					    "Failed to set rts threshold for vdev %d: %d\n",
@@ -4918,6 +4994,7 @@
 		}
 	}
 
+	ar->rts_threshold[vif_type] = rts_threshold;
 	mutex_unlock(&ar->conf_mutex);
 	return count;
 }
@@ -4927,12 +5004,15 @@
 						 size_t count, loff_t *ppos)
 {
 	struct ath11k *ar = file->private_data;
-	char buf[32] = {0};
-	int len = 0;
+	char buf[2048] = {0};
+	int len = 0, i;
 
 	mutex_lock(&ar->conf_mutex);
-	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
-			ar->hw->wiphy->rts_threshold);
+	len += scnprintf(buf, sizeof(buf) - len, "VIF type\tRTS threshold\n");
+	for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
+		if (ar->rts_threshold[i])
+			len += scnprintf(buf + len, sizeof(buf) - len, "%d\t\t%d\n", i, ar->rts_threshold[i]);
+	}
 	mutex_unlock(&ar->conf_mutex);
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -5064,6 +5144,159 @@
 	.llseek = default_llseek,
 };
 
+static ssize_t ath11k_read_napi_poll_budget(struct file *file,
+					     char __user *user_buf,
+					     size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	int len = 0;
+	char buf[32];
+
+	len = scnprintf(buf, sizeof(buf) - len, "%u\n", ar->ab->napi_poll_budget);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath11k_write_napi_poll_budget(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	int ret;
+	u32 napi_poll_budget = 0;
+
+	if (kstrtou32_from_user(user_buf, count, 0, &napi_poll_budget))
+		return -EINVAL;
+
+	if(napi_poll_budget > NAPI_POLL_WEIGHT)
+		return -EINVAL;
+
+	if(napi_poll_budget < 4)
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+	ar->ab->napi_poll_budget = napi_poll_budget;
+	ret = count;
+
+exit:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static const struct file_operations fops_napi_poll_budget = {
+	.read = ath11k_read_napi_poll_budget,
+	.write = ath11k_write_napi_poll_budget,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath11k_read_gro_support(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	int len = 0;
+	char buf[32];
+
+	len = scnprintf(buf, sizeof(buf) - len, "%u\n",
+			ar->ab->gro_support_enabled);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath11k_write_gro_support(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	int ret;
+	bool gro_support = false;
+
+	if (kstrtobool_from_user(user_buf, count, &gro_support))
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+	ar->ab->gro_support_enabled = gro_support;
+	ret = count;
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static const struct file_operations fops_gro_support = {
+	.read = ath11k_read_gro_support,
+	.write = ath11k_write_gro_support,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t ath11k_write_mgmt_retry_limit(struct file *file,
+					     const char __user *user_buf,
+					     size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	struct ath11k_pdev *pdev = ar->pdev;
+	u8 retry_limit;
+	int ret;
+
+	if (kstrtou8_from_user(user_buf, count, 0, &retry_limit))
+		return -EINVAL;
+
+	if (retry_limit < ATH11K_MIN_MGMT_RETRY_LIMIT_COUNT ||
+	    retry_limit > ATH11K_MAX_MGMT_RETRY_LIMIT_COUNT)
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->mgmt_retry_limit == retry_limit) {
+		ret = count;
+		goto exit;
+	}
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ret = -ENETDOWN;
+		goto exit;
+	}
+
+	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_MGMT_RETRY_LIMIT,
+					retry_limit, pdev->pdev_id);
+
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to set mgmt retry limit: %d\n", ret);
+		goto exit;
+	}
+
+	ar->mgmt_retry_limit = retry_limit;
+	ret = count;
+
+exit:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static ssize_t ath11k_read_mgmt_retry_limit(struct file *file,
+						char __user *user_buf,
+						size_t count, loff_t *ppos)
+{
+	struct ath11k *ar = file->private_data;
+	int len = 0;
+	char buf[8];
+
+	mutex_lock(&ar->conf_mutex);
+	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+			ar->mgmt_retry_limit);
+	mutex_unlock(&ar->conf_mutex);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_mgmt_retry_limit = {
+	.read = ath11k_read_mgmt_retry_limit,
+	.write = ath11k_write_mgmt_retry_limit,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath11k_debugfs_register(struct ath11k *ar)
 {
 	struct ath11k_base *ab = ar->ab;
@@ -5106,8 +5339,9 @@
 	ath11k_init_pktlog(ar);
 	ath11k_smart_ant_debugfs_init(ar);
 	init_completion(&ar->tpc_complete);
-        init_completion(&ab->ani_ofdm_event);
-        init_completion(&ab->ani_cck_event);
+	init_completion(&ab->ani_ofdm_event);
+	init_completion(&ab->ani_cck_event);
+	init_completion(&ar->ani_status_event);
 
 	debugfs_create_file("ext_tx_stats", 0644,
 			    ar->debug.debugfs_pdev, ar,
@@ -5137,6 +5371,12 @@
 	debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar,
 			    &fops_ps_state_enable);
 
+	debugfs_create_file("napi_poll_budget", 0644, ar->debug.debugfs_pdev, ar,
+			    &fops_napi_poll_budget);
+
+	debugfs_create_file("gro_support_enabled", 0644, ar->debug.debugfs_pdev,
+			    ar, &fops_gro_support);
+
 	if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
 		     ar->ab->wmi_ab.svc_map)) {
 		debugfs_create_file("ps_timekeeper_enable", 0600,
@@ -5207,6 +5447,9 @@
 	debugfs_create_file("ftm_resp", 0600,
 			    ar->debug.debugfs_pdev,
 			    ar, &fops_ftm_resp);
+	debugfs_create_file("mgmt_retry_limit", 0600,
+			    ar->debug.debugfs_pdev,
+			    ar, &fops_mgmt_retry_limit);
 
 	if (!ab->userpd_id) {
 		debugfs_create_file("tx_wmi_mgmt", 0600,
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h
index bb6ad4c..59d9f5b 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs.h
@@ -240,6 +240,9 @@
 #define ATH11K_MAX_AGGR_RETRY_COUNT 255
 #define ATH11K_AGGR_SW_RETRY_THRESHOLD 50
 
+#define ATH11K_MIN_MGMT_RETRY_LIMIT_COUNT 1
+#define ATH11K_MAX_MGMT_RETRY_LIMIT_COUNT 16
+
 #ifdef CONFIG_ATH11K_DEBUGFS
 int ath11k_debugfs_create(void);
 void ath11k_debugfs_destroy(void);
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
index 19c03e0..c2dea31 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
@@ -6338,6 +6338,13 @@
 		return -E2BIG;
 
 	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH11K_STATE_ON) {
+		ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id);
+		mutex_unlock(&ar->conf_mutex);
+		return -ENETDOWN;
+	}
+
 	cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET;
 	cfg_params.cfg1 = 1 << (cfg_params.cfg0 + type);
 	ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
index 71201e7..2daa806 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -324,9 +324,6 @@
 			  [HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY] = "MEC notify pkt count"};
 	int idx;
 
-	if (!arsta->tx_stats || !arsta->wbm_tx_stats)
-		return -ENOENT;
-
 	buf = kzalloc(size, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
@@ -334,6 +331,12 @@
 	mutex_lock(&ar->conf_mutex);
 
 	spin_lock_bh(&ar->data_lock);
+
+	if (!arsta->tx_stats || !arsta->wbm_tx_stats) {
+		retval = -ENOENT;
+		goto end;
+	}
+
 	for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
 		for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
 			stats = &arsta->tx_stats->stats[k];
@@ -477,6 +480,12 @@
 
 	mutex_unlock(&ar->conf_mutex);
 	return retval;
+
+end:
+	spin_unlock_bh(&ar->data_lock);
+	mutex_unlock(&ar->conf_mutex);
+	kfree(buf);
+	return retval;
 }
 
 static const struct file_operations fops_tx_stats = {
@@ -1287,15 +1296,18 @@
 	const int size = ATH11K_DRV_TX_STATS_SIZE;
 	char *buf;
 
-	if (!arsta->tx_stats)
-		return -ENOENT;
-
 	buf = kzalloc(ATH11K_DRV_TX_STATS_SIZE, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
 	mutex_lock(&ar->conf_mutex);
 	spin_lock_bh(&ar->ab->base_lock);
+
+	if (!arsta->tx_stats) {
+		ret_val = -ENOENT;
+		goto end;
+	}
+
 	len += scnprintf(buf + len, size - len,
 			 "Tx packets inflow from mac80211: %u\n",
 			 atomic_read(&arsta->drv_tx_pkts.pkts_in));
@@ -1312,6 +1324,11 @@
 
 	mutex_unlock(&ar->conf_mutex);
 	return ret_val;
+end:
+	spin_unlock_bh(&ar->ab->base_lock);
+	mutex_unlock(&ar->conf_mutex);
+	kfree(buf);
+	return ret_val;
 }
 
 static const struct file_operations fops_driver_tx_pkts_flow = {
@@ -1330,9 +1347,6 @@
 	struct ath11k *ar = arsta->arvif->ar;
 	int ret, reset;
 
-	if (!arsta->tx_stats || !arsta->wbm_tx_stats)
-		return -ENOENT;
-
 	ret = kstrtoint_from_user(buf, count, 0, &reset);
 	if (ret)
 		return ret;
@@ -1341,6 +1355,12 @@
 		return -EINVAL;
 
 	spin_lock_bh(&ar->ab->base_lock);
+
+	if (!arsta->tx_stats || !arsta->wbm_tx_stats) {
+		spin_unlock_bh(&ar->ab->base_lock);
+		return -ENOENT;
+	}
+
 	memset(arsta->tx_stats, 0, sizeof(*arsta->tx_stats));
 	atomic_set(&arsta->drv_tx_pkts.pkts_in, 0);
 	atomic_set(&arsta->drv_tx_pkts.pkts_out, 0);
@@ -1586,12 +1606,16 @@
 			 arsta->fail_pkts);
 	len += scnprintf(buf + len, size - len, "succ_pkts    : %llu\n",
 			 arsta->succ_pkts);
+	len += scnprintf(buf + len, size - len, "drop_pkts    : %llu\n",
+			 arsta->drop_pkts);
 	len += scnprintf(buf + len, size - len, "PER          : %lu\n",
 			 ewma_sta_per_read(&arsta->per));
 	len += scnprintf(buf + len, size - len, "fail_bytes   : %llu\n",
 			 arsta->fail_bytes);
 	len += scnprintf(buf + len, size - len, "succ_bytes   : %llu\n",
 			 arsta->succ_bytes);
+	len += scnprintf(buf + len, size - len, "drop_bytes   : %llu\n",
+			 arsta->drop_bytes);
 	len += scnprintf(buf + len, size - len,
 			 "BER          : %lu\n", ewma_sta_ber_read(&arsta->ber));
 
@@ -1668,17 +1692,24 @@
 	int len = 0, i, retval = 0;
 	u64 total_succ_bytes;
 
-	if (!arsta->tx_stats || !arsta->wbm_tx_stats) {
-		ath11k_warn(ar->ab, "failed to get tx success bytes");
-		return -EINVAL;
-	}
-
 	mutex_lock(&ar->conf_mutex);
 
 	spin_lock_bh(&ar->data_lock);
 
+	if (!arsta->tx_stats || !arsta->wbm_tx_stats) {
+		ath11k_warn(ar->ab, "failed to get tx success bytes");
+		retval = -EINVAL;
+		goto end;
+	}
+
 	stats = &arsta->tx_stats->stats[ATH11K_STATS_TYPE_SUCC];
 
+	if (!stats) {
+		ath11k_warn(ar->ab, "Stats not present to read Tx success bytes\n");
+		retval = -EINVAL;
+		goto end;
+	}
+
 	total_succ_bytes = stats->gi[ATH11K_COUNTER_TYPE_BYTES][0] +
 			   stats->gi[ATH11K_COUNTER_TYPE_BYTES][1] +
 			   stats->gi[ATH11K_COUNTER_TYPE_BYTES][2] +
@@ -1697,6 +1728,11 @@
 	mutex_unlock(&ar->conf_mutex);
 
 	return retval;
+
+end:
+	spin_unlock_bh(&ar->data_lock);
+	mutex_unlock(&ar->conf_mutex);
+	return retval;
 }
 
 static const struct file_operations fops_tx_success_bytes = {
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index bcbc612..9879795 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -251,6 +251,8 @@
 	int max_entries = ath11k_hal_srng_get_max_entries(ab, type);
 	int ret;
 	bool cached;
+	unsigned long off;
+	u8 align = HAL_RING_BASE_ALIGN;
 
 	if (max_entries < 0 || entry_sz < 0)
 		return -EINVAL;
@@ -258,6 +260,9 @@
 	if (num_entries > max_entries)
 		num_entries = max_entries;
 
+	if (type == HAL_RXDMA_DIR_BUF)
+		align = HAL_RXDMA_DIR_BUF_RING_BASE_ALIGN;
+
 	/* Allocate the reo dst and tx completion rings from cacheable memory */
 	switch (type) {
 	case HAL_REO_DST:
@@ -273,7 +278,7 @@
 	if (ath11k_nss_offload_enabled(ab))
 		cached = false;
 
-	ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1;
+	ring->size = (num_entries * entry_sz) + align - 1;
 
 	if (!cached) {
 		ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size,
@@ -289,9 +294,10 @@
 
 	ATH11K_MEMORY_STATS_INC(ab, dma_alloc, ring->size);
 
-	ring->vaddr = PTR_ALIGN(ring->vaddr_unaligned, HAL_RING_BASE_ALIGN);
-	ring->paddr = ring->paddr_unaligned + ((unsigned long)ring->vaddr -
-		      (unsigned long)ring->vaddr_unaligned);
+	ring->paddr = (dma_addr_t) ALIGN((unsigned long)ring->paddr_unaligned,
+					 align);
+	off = (unsigned long)ring->paddr - (unsigned long)ring->paddr_unaligned;
+	ring->vaddr = (u32 *) ((unsigned long)ring->vaddr_unaligned + off);
 
 	params.ring_base_vaddr = ring->vaddr;
 	params.ring_base_paddr = ring->paddr;
@@ -390,27 +396,7 @@
 	struct ath11k_dp *dp = from_timer(dp, timer, reo_status_timer);
 	struct ath11k_base *ab = dp->ab;
 
-	spin_lock_bh(&dp->reo_cmd_lock);
-	dp->reo_status_timer_running = false;
-	spin_unlock_bh(&dp->reo_cmd_lock);
-
 	ath11k_dp_process_reo_status(ab);
-}
-
-void ath11k_dp_start_reo_status_timer(struct ath11k_base *ab)
-{
-	struct ath11k_dp *dp = &ab->dp;
-
-	if (!ab->hw_params.reo_status_poll)
-		return;
-
-	spin_lock_bh(&dp->reo_cmd_lock);
-	if (dp->reo_status_timer_running) {
-		spin_unlock_bh(&dp->reo_cmd_lock);
-		return;
-	}
-	dp->reo_status_timer_running = true;
-	spin_unlock_bh(&dp->reo_cmd_lock);
 
 	mod_timer(&dp->reo_status_timer, jiffies +
 		  msecs_to_jiffies(ATH11K_REO_STATUS_POLL_TIMEOUT_MS));
@@ -424,7 +410,6 @@
 		return;
 
 	del_timer_sync(&dp->reo_status_timer);
-	dp->reo_status_timer_running = false;
 }
 
 static void ath11k_dp_init_reo_status_timer(struct ath11k_base *ab)
@@ -436,6 +421,10 @@
 
 	timer_setup(&dp->reo_status_timer,
 		    ath11k_dp_handle_reo_status_timer, 0);
+
+	/* Trigger reo status polling periodically */
+	mod_timer(&dp->reo_status_timer, jiffies +
+		  msecs_to_jiffies(ATH11K_REO_STATUS_POLL_TIMEOUT_MS));
 }
 
 static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab)
@@ -898,6 +887,10 @@
 	int i = 0, j;
 	int tot_work_done = 0;
 	bool nss_offload;
+	int original_budget = budget;
+
+	if (budget != ab->napi_poll_budget)
+		budget = ab->napi_poll_budget;
 
 	/* Processing of offloaded rings are not required */
 	nss_offload = ath11k_nss_offload_enabled(ab);
@@ -988,11 +981,14 @@
 	/* TODO: Implement handler for other interrupts */
 
 done:
+	// Don't call napi_complete_done() if there is more work to do
+	if (tot_work_done >= ab->napi_poll_budget)
+		tot_work_done = original_budget;
 	return tot_work_done;
 }
 EXPORT_SYMBOL(ath11k_dp_service_srng);
 
-void ath11k_dp_pdev_free(struct ath11k_base *ab)
+void ath11k_dp_pdev_free(struct ath11k_base *ab, bool ureg_dbgfs)
 {
 	struct ath11k *ar;
 	int i;
@@ -1002,7 +998,8 @@
 	for (i = 0; i < ab->num_radios; i++) {
 		ar = ab->pdevs[i].ar;
 		ath11k_dp_rx_pdev_free(ab, i);
-		ath11k_debugfs_unregister(ar);
+		if (ureg_dbgfs)
+			ath11k_debugfs_unregister(ar);
 		ath11k_dp_rx_pdev_mon_detach(ar);
 	}
 }
@@ -1057,7 +1054,7 @@
 	return 0;
 
 err:
-	ath11k_dp_pdev_free(ab);
+	ath11k_dp_pdev_free(ab, true);
 
 	return ret;
 }
@@ -1243,6 +1240,7 @@
 	for (i = 0; i < ab->hw_params.num_dscp_tid_map_tbl; i++)
 		ath11k_hal_tx_set_dscp_tid_map(ab, i);
 
+	ab->napi_poll_budget = NAPI_POLL_WEIGHT;
 	/* Init any SOC level resource for DP */
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
index 46a9ad6..5dc9061 100644
--- a/drivers/net/wireless/ath/ath11k/dp.h
+++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -45,7 +45,7 @@
 #define DP_MON_PURGE_TIMEOUT_MS     100
 #define DP_MON_SERVICE_BUDGET       128
 
-#define ATH11K_REO_STATUS_POLL_TIMEOUT_MS 10
+#define ATH11K_REO_STATUS_POLL_TIMEOUT_MS 50
 
 struct dp_reo_cache_flush_elem {
 	struct list_head list;
@@ -307,7 +307,6 @@
 
 	/* reo status timer and flags */
 	struct timer_list reo_status_timer;
-	bool reo_status_timer_running;
 };
 
 /* HTT definitions */
@@ -1960,7 +1959,7 @@
 int ath11k_dp_alloc(struct ath11k_base *ab);
 int ath11k_dp_pdev_alloc(struct ath11k_base *ab);
 void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab);
-void ath11k_dp_pdev_free(struct ath11k_base *ab);
+void ath11k_dp_pdev_free(struct ath11k_base *ab, bool ureg_dbgfs);
 int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id,
 				int mac_id, enum hal_ring_type ring_type);
 int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr);
@@ -1985,6 +1984,5 @@
 				 struct ath11k_hp_update_timer *update_timer,
 				 u32 interval, u32 ring_id);
 void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab);
-void ath11k_dp_start_reo_status_timer(struct ath11k_base *ab);
 
 #endif
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 56f7ce6..6a8809c 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -434,12 +434,12 @@
 			buf_id = buf_ids[buf_id_index];
 			idr_replace(&rx_ring->bufs_idr, skb, buf_id);
 		} else {
-			buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0,
-					   rx_ring->bufs_max * 3, GFP_ATOMIC);
+			buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 1,
+					   (rx_ring->bufs_max * 3) + 1, GFP_ATOMIC);
 		}
 		spin_unlock_bh(&rx_ring->idr_lock);
 
-		if (buf_id < 0)
+		if (buf_id <= 0)
 			goto fail_free_skb;
 
 		desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
@@ -767,7 +767,7 @@
 	}
 }
 
-static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
+static int ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
 				      struct dp_rx_tid *rx_tid)
 {
 	struct ath11k_hal_reo_cmd cmd = {0};
@@ -786,8 +786,15 @@
 						NULL);
 		if (ret)
 			ath11k_warn(ab,
-				    "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n",
-				    rx_tid->tid, ret);
+				    "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d) desc_sz(%ld)\n",
+				    rx_tid->tid, ret, desc_sz);
+
+		/* If this fails with ring full condition, then
+		 * no need to retry below as it is expected to
+		 * fail within short time
+		 */
+		if (ret == -ENOBUFS)
+			goto exit;
 	}
 
 	memset(&cmd, 0, sizeof(cmd));
@@ -797,14 +804,12 @@
 	ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid,
 					HAL_REO_CMD_FLUSH_CACHE,
 					&cmd, ath11k_dp_reo_cmd_free);
-	if (ret) {
+	if (ret)
 		ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
 			   rx_tid->tid, ret);
-		dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
-				 DMA_BIDIRECTIONAL);
-		kfree(rx_tid->vaddr);
-		rx_tid->vaddr = NULL;
-	}
+
+exit:
+	return ret;
 }
 
 static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
@@ -843,13 +848,22 @@
 		if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
 		    time_after(jiffies, elem->ts +
 			       msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) {
+			spin_unlock_bh(&dp->reo_cmd_lock);
+			if (ath11k_dp_reo_cache_flush(ab, &elem->data)) {
+				/* In failure case, just update the timestamp
+				 * for flush cache elem and continue
+				 */
+				spin_lock_bh(&dp->reo_cmd_lock);
+				elem->ts = jiffies +
+					msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS);
+				ath11k_err(ab, "Failed to send HAL_REO_CMD_FLUSH_CACHE cmd"
+					   "Updating timestamp (%ld) in the list\n", elem->ts);
+				continue;
+			}
+			spin_lock_bh(&dp->reo_cmd_lock);
 			list_del(&elem->list);
 			dp->reo_cmd_cache_flush_count--;
-			spin_unlock_bh(&dp->reo_cmd_lock);
-
-			ath11k_dp_reo_cache_flush(ab, &elem->data);
 			kfree(elem);
-			spin_lock_bh(&dp->reo_cmd_lock);
 		}
 	}
 	spin_unlock_bh(&dp->reo_cmd_lock);
@@ -1573,95 +1587,96 @@
 	ru_start = user_rate->ru_start;
 	ru_tone = user_rate->ru_end;
 
-	/* Note: If host configured fixed rates and in some other special
-	 * cases, the broadcast/management frames are sent in different rates.
-	 * Firmware rate's control to be skipped for this?
-	 */
-
-	if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) {
-		ath11k_warn(ab, "Invalid HE mcs %d peer stats",  mcs);
-		return;
-	}
-
-	if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) {
-		ath11k_warn(ab, "Invalid HE mcs %d peer stats",  mcs);
-		return;
-	}
-
-	if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) {
-		ath11k_warn(ab, "Invalid VHT mcs %d peer stats",  mcs);
-		return;
-	}
-
-	if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) {
-		ath11k_warn(ab, "Invalid HT mcs %d nss %d peer stats",
-			    mcs, nss);
-		return;
-	}
-
-	if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) {
-		ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
-							    flags,
-							    &rate_idx,
-							    &rate);
-		if (ret < 0)
-			return;
-	}
-
-	rcu_read_lock();
-	spin_lock_bh(&ab->base_lock);
-	peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id);
-
-	if (!peer || !peer->sta) {
-		spin_unlock_bh(&ab->base_lock);
-		rcu_read_unlock();
-		return;
-	}
-
-	sta = peer->sta;
-	arsta = (struct ath11k_sta *)sta->drv_priv;
-
-	memset(&arsta->txrate, 0, sizeof(arsta->txrate));
-
-	switch (flags) {
-	case WMI_RATE_PREAMBLE_OFDM:
-		arsta->txrate.legacy = rate;
-		break;
-	case WMI_RATE_PREAMBLE_CCK:
-		arsta->txrate.legacy = rate;
-		break;
-	case WMI_RATE_PREAMBLE_HT:
-		arsta->txrate.mcs = mcs + 8 * (nss - 1);
-		arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
-		if (sgi)
-			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-		break;
-	case WMI_RATE_PREAMBLE_VHT:
-		arsta->txrate.mcs = mcs;
-		arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
-		if (sgi)
-			arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-		break;
-	case WMI_RATE_PREAMBLE_HE:
-		arsta->txrate.mcs = mcs;
-		arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
-		arsta->txrate.he_dcm = dcm;
-		arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi);
-		arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(
-						(user_rate->ru_end -
-						 user_rate->ru_start) + 1);
-		break;
-	}
-
-	arsta->txrate.nss = nss;
-	arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
-	arsta->tx_duration += tx_duration;
-	memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info));
-
 	/* PPDU stats reported for mgmt packet doesn't have valid tx bytes.
 	 * So skip peer stats update for mgmt packets.
 	 */
+
 	if (tid < HTT_PPDU_STATS_NON_QOS_TID) {
+		/* Note: If host configured fixed rates and in some other special
+		 * cases, the broadcast/management frames are sent in different rates.
+		 * Firmware rate's control to be skipped for this?
+		 */
+
+		if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) {
+			ath11k_warn(ab, "Invalid HE mcs %d peer stats",  mcs);
+			return;
+		}
+
+		if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) {
+			ath11k_warn(ab, "Invalid HE mcs %d peer stats",  mcs);
+			return;
+		}
+
+		if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) {
+			ath11k_warn(ab, "Invalid VHT mcs %d peer stats",  mcs);
+			return;
+		}
+
+		if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) {
+			ath11k_warn(ab, "Invalid HT mcs %d nss %d peer stats",
+				    mcs, nss);
+			return;
+		}
+
+		if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) {
+			ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
+								    flags,
+								    &rate_idx,
+								    &rate);
+			if (ret < 0)
+				return;
+		}
+
+		rcu_read_lock();
+		spin_lock_bh(&ab->base_lock);
+		peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id);
+
+		if (!peer || !peer->sta) {
+			spin_unlock_bh(&ab->base_lock);
+			rcu_read_unlock();
+			return;
+		}
+
+		sta = peer->sta;
+		arsta = (struct ath11k_sta *)sta->drv_priv;
+
+		memset(&arsta->txrate, 0, sizeof(arsta->txrate));
+
+		switch (flags) {
+		case WMI_RATE_PREAMBLE_OFDM:
+			arsta->txrate.legacy = rate;
+			break;
+		case WMI_RATE_PREAMBLE_CCK:
+			arsta->txrate.legacy = rate;
+			break;
+		case WMI_RATE_PREAMBLE_HT:
+			arsta->txrate.mcs = mcs + 8 * (nss - 1);
+			arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
+			if (sgi)
+				arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+			break;
+		case WMI_RATE_PREAMBLE_VHT:
+			arsta->txrate.mcs = mcs;
+			arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+			if (sgi)
+				arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+			break;
+		case WMI_RATE_PREAMBLE_HE:
+			arsta->txrate.mcs = mcs;
+			arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
+			arsta->txrate.he_dcm = dcm;
+			arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi);
+			arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(
+							(user_rate->ru_end -
+							 user_rate->ru_start) + 1);
+			break;
+		}
+
+		arsta->txrate.nss = nss;
+		arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
+		arsta->tx_duration += tx_duration;
+		memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info));
+
 		memset(peer_stats, 0, sizeof(*peer_stats));
 		peer_stats->succ_pkts = succ_pkts;
 		peer_stats->succ_bytes = succ_bytes;
@@ -1696,12 +1711,12 @@
 
 		if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar)))
 			ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
+
+		spin_unlock_bh(&ab->base_lock);
+		rcu_read_unlock();
 	}
 
 	usr_stats->rate_stats_updated = true;
-
-	spin_unlock_bh(&ab->base_lock);
-	rcu_read_unlock();
 }
 
 static void ath11k_htt_update_ppdu_stats(struct ath11k *ar,
@@ -2354,16 +2369,27 @@
 	size_t hdr_len, crypto_len;
 	struct ieee80211_hdr *hdr;
 	u16 fc, qos_ctl = 0;
+	int expand_by;
 	u8 *crypto_hdr;
 
 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
 		crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
+		if (skb_headroom(msdu) < crypto_len) {
+			expand_by = crypto_len - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		crypto_hdr = skb_push(msdu, crypto_len);
 		ath11k_dp_rx_desc_get_crypto_header(ab, rx_desc, crypto_hdr, enctype);
 	}
 
 	fc = ath11k_dp_rxdesc_get_mpdu_frame_ctrl(ab, rx_desc);
 	hdr_len = ieee80211_hdrlen(fc);
+	if (skb_headroom(msdu) < hdr_len) {
+		expand_by = hdr_len - skb_headroom(msdu);
+		if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+			return;
+	}
 	skb_push(msdu, hdr_len);
 	hdr = (struct ieee80211_hdr *)msdu->data;
 	hdr->frame_control = fc;
@@ -2399,6 +2425,7 @@
 	u8 da[ETH_ALEN];
 	u8 sa[ETH_ALEN];
 	u16 qos_ctl = 0;
+	int expand_by = 0;
 	u8 *qos, *crypto_hdr;
 	bool add_qos_ctrl = false;
 
@@ -2443,6 +2470,11 @@
 	}
 
 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+		if (skb_headroom(msdu) < ath11k_dp_rx_crypto_param_len(ar, enctype)) {
+			expand_by = ath11k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		if (first_hdr) {
 			memcpy(skb_push(msdu,
 					ath11k_dp_rx_crypto_param_len(ar, enctype)),
@@ -2456,13 +2488,28 @@
 	}
 
 	if (!rxcb->is_first_msdu || add_qos_ctrl) {
+		if (skb_headroom(msdu) < IEEE80211_QOS_CTL_LEN) {
+			expand_by = IEEE80211_QOS_CTL_LEN - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		memcpy(skb_push(msdu,
 				IEEE80211_QOS_CTL_LEN), &qos_ctl,
 				IEEE80211_QOS_CTL_LEN);
+		if (skb_headroom(msdu) < hdr_len) {
+			expand_by = hdr_len - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len);
 		return;
 	}
 
+	if (skb_headroom(msdu) < hdr_len) {
+		expand_by = hdr_len - skb_headroom(msdu);
+		if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+			return;
+	}
 	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 
 	/* original 802.11 header has a different DA and in
@@ -2571,6 +2618,7 @@
 	u8 da[ETH_ALEN];
 	u8 sa[ETH_ALEN];
 	void *rfc1042;
+	int expand_by;
 	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
 	struct ath11k_dp_rfc1042_hdr rfc = {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}};
 
@@ -2580,6 +2628,11 @@
 		ether_addr_copy(sa, eth->h_source);
 		rfc.snap_type = eth->h_proto;
 		skb_pull(msdu, sizeof(struct ethhdr));
+		if (skb_headroom(msdu) < sizeof(struct ath11k_dp_rfc1042_hdr)) {
+			expand_by = sizeof(struct ath11k_dp_rfc1042_hdr) - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), &rfc,
 		       sizeof(struct ath11k_dp_rfc1042_hdr));
 		ath11k_get_dot11_hdr_from_rx_desc(ar, msdu, rxcb, status, enctype);
@@ -2597,6 +2650,11 @@
 	skb_pull(msdu, sizeof(struct ethhdr));
 
 	/* push rfc1042/llc/snap */
+	if (skb_headroom(msdu) < sizeof(struct ath11k_dp_rfc1042_hdr)) {
+		expand_by = sizeof(struct ath11k_dp_rfc1042_hdr) - skb_headroom(msdu);
+		if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+			return;
+	}
 	memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), rfc1042,
 	       sizeof(struct ath11k_dp_rfc1042_hdr));
 
@@ -2605,12 +2663,22 @@
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
 
 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+		if (skb_headroom(msdu) < ath11k_dp_rx_crypto_param_len(ar, enctype)) {
+			expand_by = ath11k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		memcpy(skb_push(msdu,
 				ath11k_dp_rx_crypto_param_len(ar, enctype)),
 		       (void *)hdr + hdr_len,
 		       ath11k_dp_rx_crypto_param_len(ar, enctype));
 	}
 
+	if (skb_headroom(msdu) < hdr_len) {
+		expand_by = hdr_len - skb_headroom(msdu);
+		if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+			return;
+	}
 	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 
 exit:
@@ -2631,6 +2699,7 @@
 	struct ieee80211_hdr *hdr;
 	size_t hdr_len;
 	u8 l3_pad_bytes;
+	int expand_by;
 	struct hal_rx_desc *rx_desc;
 	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
 
@@ -2655,12 +2724,22 @@
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
 
 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+		if (skb_headroom(msdu) < ath11k_dp_rx_crypto_param_len(ar, enctype)) {
+			expand_by = ath11k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				return;
+		}
 		memcpy(skb_push(msdu,
 				ath11k_dp_rx_crypto_param_len(ar, enctype)),
 		       (void *)hdr + hdr_len,
 			ath11k_dp_rx_crypto_param_len(ar, enctype));
 	}
 
+	if (skb_headroom(msdu) < hdr_len) {
+		expand_by = hdr_len - skb_headroom(msdu);
+		if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+			return;
+	}
 	memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
 }
 
@@ -2689,11 +2768,14 @@
 	case DP_RX_DECAP_TYPE_ETHERNET2_DIX:
 		ehdr = (struct ethhdr *) msdu->data;
 
-		/* mac80211 allows fast path only for authorized STA */
-		if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) {
-			ATH11K_SKB_RXCB(msdu)->is_eapol = true;
+		/* mac80211 allows fast path only for authorized STA and
+                   also not supported for TKIP */
+		if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE) ||
+                    enctype == HAL_ENCRYPT_TYPE_TKIP_MIC) {
+			ATH11K_SKB_RXCB(msdu)->is_eapol_tkip = true;
 			ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr,
 						   enctype, status);
+			break;
 		}
 
 		/* PN for mcast packets will be validated in mac80211;
@@ -2824,6 +2906,9 @@
 
 	/* PN for multicast packets will be checked in mac80211 */
 	rxcb = ATH11K_SKB_RXCB(msdu);
+
+	rxcb->is_mcbc = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc);
+
 	fill_crypto_hdr = rxcb->is_mcbc;
 	if (rxcb->is_mcbc) {
 		rxcb->seq_no = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc);
@@ -3047,11 +3132,17 @@
 	u8 decap = DP_RX_DECAP_TYPE_RAW;
 	int len;
 	u8 index;
+	int expand_by;
 	bool is_mcbc = rxcb->is_mcbc;
-	bool is_eapol = rxcb->is_eapol;
+	bool is_eapol_tkip = rxcb->is_eapol_tkip;
 
 	if ((status->encoding == RX_ENC_HE) && !(status->flag & RX_FLAG_RADIOTAP_HE) &&
 	     !(status->flag & RX_FLAG_SKIP_MONITOR)) {
+		if (skb_headroom(msdu) < sizeof(known)) {
+			expand_by = sizeof(known) - skb_headroom(msdu);
+			if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC)))
+				goto exit;
+		}
 		he = skb_push(msdu, sizeof(known));
 		memcpy(he, &known, sizeof(known));
 		status->flag |= RX_FLAG_RADIOTAP_HE;
@@ -3103,7 +3194,7 @@
 	 * Also, fast_rx expectes the STA to be authorized, hence
 	 * eapol packets are sent in slow path.
 	 */
-	if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol &&
+	if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol_tkip &&
 	    !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) {
 		rx_status->flag |= RX_FLAG_8023;
 		goto exit;
@@ -3285,13 +3376,13 @@
 	int ret;
 	bool fast_rx;
 	LIST_HEAD(rx_list);
+	bool gro_support_enabled = ab->gro_support_enabled;
 
 	if (skb_queue_empty(msdu_list))
 		return;
 
 	rcu_read_lock();
 
-
 	ar = ab->pdevs[mac_id].ar;
 	if (unlikely(!rcu_dereference(ab->pdevs_active[mac_id]))) {
 		__skb_queue_purge(msdu_list);
@@ -3325,8 +3416,18 @@
 			ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status, &rx_list);
 	}
 
-	if (!fast_rx)
-		netif_receive_skb_list(&rx_list);
+	if (!fast_rx) {
+		struct sk_buff *skb, *tmp;
+
+		if (napi && gro_support_enabled) {
+			list_for_each_entry_safe(skb, tmp, &rx_list, list) {
+				skb_list_del_init(skb);
+				napi_gro_receive(napi, skb);
+			}
+		} else {
+			netif_receive_skb_list(&rx_list);
+		}
+	}
 
 	rcu_read_unlock();
 }
@@ -3397,6 +3498,17 @@
 	ath11k_hal_srng_access_begin(ab, srng);
 
 	while (likely(desc = (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
+
+		push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
+					desc->info0);
+
+		if (unlikely(push_reason ==
+			     HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED)) {
+			ath11k_warn(ab,"Received invalid desc\n");
+			ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++;
+			continue;
+		}
+
 		cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
 				   desc->buf_addr_info.info1);
 		buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
@@ -3429,8 +3541,6 @@
 
 		num_buffs_reaped[mac_id]++;
 
-		push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
-					desc->info0);
 		if (unlikely(push_reason !=
 		    HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) {
 			dev_kfree_skb_any(msdu);
@@ -3569,12 +3679,15 @@
 {
 	struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
 	u32 num_msdu;
+	u32 bw_offset;
 
 	if (!rx_stats)
 		return;
 
+	arsta->last_tx_pkt_bw = ppdu_info->bw;
+	bw_offset = arsta->last_tx_pkt_bw * 3;
 	arsta->rssi_comb = ppdu_info->rssi_comb;
-	ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb);
+	ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb + bw_offset);
 
 	if (!ath11k_debugfs_is_extd_rx_stats_enabled(ar))
 		return;
@@ -3974,6 +4087,14 @@
 		return DP_MON_STATUS_NO_DMA;
 
 	rxcb = ATH11K_SKB_RXCB(skb);
+
+	if (!rxcb->paddr) {
+		ath11k_warn(ab, "Invalid paddr at SKB cb \n");
+	} else if (paddr != rxcb->paddr) {
+		ath11k_warn(ab, "Invalid desc and skb fetch %pad rxcb %pad rbm %u cookie %u\n",
+			    &paddr, &(rxcb->paddr), rbm, cookie);
+	}
+
 	dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
 			skb->len + skb_tailroom(skb),
 			DMA_FROM_DEVICE);
@@ -4017,6 +4138,7 @@
 	ath11k_hal_srng_access_begin(ab, srng);
 	while (*budget) {
 		*budget -= 1;
+		ar->mon_status_no_buf_done = MON_STATUS_BUF_DONE;
 		rx_mon_status_desc = ath11k_hal_srng_src_peek(ab, srng);
 		if (!rx_mon_status_desc) {
 			pmon->mon_status_buf_state = DP_MON_STATUS_REPLINISH;
@@ -4046,6 +4168,18 @@
 
 			rxcb = ATH11K_SKB_RXCB(skb);
 
+			if (ar->mon_status_skb_zero) {
+				ath11k_warn(ab, "Previous mon status skb zero \n");
+				ar->mon_status_skb_zero = false;
+			}
+
+			if (!rxcb->paddr) {
+				ath11k_warn(ab, "NULL paddr at SKB cb \n");
+			} else if (paddr != rxcb->paddr) {
+				ath11k_warn(ab, "paddr mismatch desc %pad rxcb %pad rbm-%u cookie %u\n",
+					    &paddr, &(rxcb->paddr), rbm, cookie);
+			}
+
 			dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
 						skb->len + skb_tailroom(skb),
 						DMA_FROM_DEVICE);
@@ -4054,6 +4188,7 @@
 			if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) !=
 					HAL_RX_STATUS_BUFFER_DONE) {
 
+				ar->mon_status_no_buf_done = MON_STATUS_NO_BUF_DONE;
 				/* RxDMA status done bit might not be set even
 				 * though tp is moved by HW.
 				 */
@@ -4075,6 +4210,7 @@
 				if (reap_status == DP_MON_STATUS_NO_DMA) {
 					continue;
 				} else if (reap_status == DP_MON_STATUS_REPLINISH) {
+					ar->mon_status_no_buf_done = MON_STATUS_BUF_DONE_NEXT;
 					ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n",
 						    FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl),
 						    buf_id);
@@ -4117,6 +4253,9 @@
 							&buf_id);
 
 		if (!skb) {
+			ath11k_warn(ab, "failed to allocate skb no buf done %d\n",
+				    ar->mon_status_no_buf_done);
+			ar->mon_status_skb_zero = true;
 			ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0,
 							HAL_RX_BUF_RBM_SW3_BM);
 			num_buffs_reaped++;
@@ -5148,8 +5287,6 @@
 	struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
 	bool drop = false;
 
-	ar->ab->soc_stats.reo_error[rxcb->err_code]++;
-
 	switch (rxcb->err_code) {
 	case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO:
 		if (ath11k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list))
@@ -5169,10 +5306,15 @@
 		break;
 	}
 
+	if (drop)
+		ar->ab->soc_stats.reo_error_drop[rxcb->err_code]++;
+	else
+		ar->ab->soc_stats.reo_error[rxcb->err_code]++;
+
 	return drop;
 }
 
-static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
+static bool ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
 					struct ieee80211_rx_status *status)
 {
 	u16 msdu_len;
@@ -5186,6 +5328,14 @@
 
 	l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc);
 	msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc);
+
+	if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) {
+		ath11k_warn(ar->ab, "invalid msdu len in tkip mirc err %u\n", msdu_len);
+		ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", desc,
+				sizeof(struct hal_rx_desc));
+		return true;
+	}
+
 	skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
 	skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
 
@@ -5196,6 +5346,8 @@
 
 	ath11k_dp_rx_h_undecap(ar, msdu, desc,
 			       HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
+
+	return false;
 }
 
 static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar,  struct sk_buff *msdu,
@@ -5208,7 +5360,7 @@
 
 	switch (rxcb->err_code) {
 	case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
-		ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
+		drop = ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
 		break;
 	default:
 		/* TODO: Review other rxdma error code to check if anything is
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index bb64b76..d654f92 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -392,6 +392,8 @@
 		/* TODO: Take care of other encap modes as well */
 		ret = -EINVAL;
 		atomic_inc(&ab->soc_stats.tx_err.misc_fail);
+		arsta->drop_pkts++;
+		arsta->drop_bytes += skb->len;
 		goto fail_remove_idr;
 	}
 
@@ -831,6 +833,7 @@
 	status.info = info;
 	rate = arsta->last_txrate;
 	status.rate = &rate;
+	arsta->tx_retry_count += ts.try_cnt > 1 ? (ts.try_cnt - 1) : 0;
 
 	if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) {
 		if(arsta->wbm_tx_stats && wbm_status < HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX)
@@ -838,10 +841,19 @@
 	}
 
 	if (ts.status != HAL_WBM_TQM_REL_REASON_FRAME_ACKED) {
-		arsta->fail_pkts += 1;
-		arsta->per_fail_pkts += 1;
-		arsta->fail_bytes += msdu->len;
-		arsta->ber_fail_bytes += msdu->len;
+		if (ts.status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU) {
+			arsta->drop_pkts += 1;
+			arsta->drop_bytes += msdu->len;
+			spin_unlock_bh(&ab->base_lock);
+			dev_kfree_skb_any(msdu);
+			goto exit;
+		} else {
+			arsta->fail_pkts += 1;
+			arsta->per_fail_pkts += 1;
+			arsta->fail_bytes += msdu->len;
+			arsta->ber_fail_bytes += msdu->len;
+		}
+
 		if(arsta->per_fail_pkts + arsta->per_succ_pkts >=
 		   ATH11K_NUM_PKTS_THRSHLD_FOR_PER)
 			ath11k_sta_stats_update_per(arsta);
@@ -895,8 +907,7 @@
 
 	if (FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0) ==
 	    HAL_WBM_REL_SRC_MODULE_FW) {
-		status_desc = (struct htt_tx_wbm_completion *)((u8 *)desc) + HTT_TX_WBM_COMP_STATUS_OFFSET;
-
+		status_desc = (struct htt_tx_wbm_completion *)(((u8 *)desc) + HTT_TX_WBM_COMP_STATUS_OFFSET);
 		/* Dont consider HTT_TX_COMP_STATUS_MEC_NOTIFY */
 		if (FIELD_GET(HTT_TX_WBM_COMP_INFO0_STATUS, status_desc->info0) ==
 		    HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY)
@@ -1083,10 +1094,6 @@
 	if (cmd_num == 0)
 		return -EINVAL;
 
-	/* Trigger reo status polling if required */
-	if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
-		ath11k_dp_start_reo_status_timer(ab);
-
 	if (!cb)
 		return 0;
 
diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h
index 875efcb..2ef92cd 100644
--- a/drivers/net/wireless/ath/ath11k/hal.h
+++ b/drivers/net/wireless/ath/ath11k/hal.h
@@ -21,7 +21,8 @@
 #define HAL_NUM_MPDU_LINKS_PER_QUEUE_DESC	12
 #define HAL_MAX_AVAIL_BLK_RES			3
 
-#define HAL_RING_BASE_ALIGN	8
+#define HAL_RING_BASE_ALIGN	32
+#define HAL_RXDMA_DIR_BUF_RING_BASE_ALIGN	8
 
 #define HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX	32704
 /* TODO: Check with hw team on the supported scatter buf size */
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index 204d2e1..9741ccf 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -1450,39 +1450,6 @@
 	},
 };
 
-const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq5018 = {
-	.tx  = {
-		ATH11K_TX_RING_MASK_0,
-		ATH11K_TX_RING_MASK_1,
-		ATH11K_TX_RING_MASK_2,
-	},
-	.rx_mon_status = {
-		0, 0, 0,
-		ATH11K_RX_MON_STATUS_RING_MASK_0,
-	},
-	.rx = {
-		0, 0, 0, 0,
-		ATH11K_RX_RING_MASK_0,
-		ATH11K_RX_RING_MASK_1,
-		ATH11K_RX_RING_MASK_2,
-		ATH11K_RX_RING_MASK_3,
-	},
-	.rx_err = {
-		0, 0, 0, 0, 0, 0, 0, 0,
-		ATH11K_RX_ERR_RING_MASK_0,
-	},
-	.rx_wbm_rel = {
-		0, 0, 0, 0, 0, 0, 0, 0, 0,
-		ATH11K_RX_WBM_REL_RING_MASK_0,
-	},
-	.rxdma2host = {
-		ATH11K_RXDMA2HOST_RING_MASK_0,
-	},
-	.host2rxdma = {
-		ATH11K_HOST2RXDMA_RING_MASK_0,
-	},
-};
-
 /* Target firmware's Copy Engine configuration. */
 const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[] = {
 	/* CE0: host->target HTC control and raw streams */
@@ -2197,6 +2164,43 @@
 	},
 };
 
+const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122 = {
+	.tx  = {
+		ATH11K_TX_RING_MASK_0,
+		ATH11K_TX_RING_MASK_1,
+		ATH11K_TX_RING_MASK_2,
+	},
+	.rx_mon_status = {
+		0, 0, 0,
+		ATH11K_RX_MON_STATUS_RING_MASK_0,
+	},
+	.rx = {
+		0, 0, 0, 0,
+		ATH11K_RX_RING_MASK_0,
+		ATH11K_RX_RING_MASK_1,
+		ATH11K_RX_RING_MASK_2,
+		ATH11K_RX_RING_MASK_3,
+	},
+	.rx_err = {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		ATH11K_RX_ERR_RING_MASK_0,
+	},
+	.rx_wbm_rel = {
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		ATH11K_RX_WBM_REL_RING_MASK_0,
+	},
+	.reo_status = {
+		0, 0, 0,
+		ATH11K_REO_STATUS_RING_MASK_0,
+	},
+	.rxdma2host = {
+		ATH11K_RXDMA2HOST_RING_MASK_0,
+	},
+	.host2rxdma = {
+		ATH11K_HOST2RXDMA_RING_MASK_0,
+	},
+};
+
 /* Target firmware's Copy Engine configuration for IPQ5018 */
 const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq5018[] = {
 	/* CE0: host->target HTC control and raw streams */
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index bff8ea2..5a34b3b 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -291,7 +291,7 @@
 extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074;
 extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390;
 extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074;
-extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq5018;
+extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122;
 
 static inline
 int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw,
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index dd9825d..2203e83 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -615,6 +615,7 @@
 
 	ar->txpower_limit_2g = ar->max_tx_power;
 	ar->txpower_limit_5g = ar->max_tx_power;
+	ar->txpower_limit_6g = ar->max_tx_power;
 	ar->txpower_scale = WMI_HOST_TP_SCALE_MAX;
 }
 
@@ -785,6 +786,16 @@
 		ar->txpower_limit_5g = txpower;
 	}
 
+	if ((ar->hw->wiphy->bands[NL80211_BAND_6GHZ]) &&
+	    ar->txpower_limit_6g != txpower) {
+		param = WMI_PDEV_PARAM_TXPOWER_LIMIT5G;
+		ret = ath11k_wmi_pdev_set_param(ar, param,
+						txpower, ar->pdev->pdev_id);
+		if (ret)
+			goto fail;
+		ar->txpower_limit_6g = txpower;
+	}
+
 	return 0;
 
 fail:
@@ -887,6 +898,7 @@
 	spin_lock_bh(&ab->base_lock);
 	list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
 		ath11k_peer_rx_tid_cleanup(ar, peer);
+		ath11k_peer_rhash_delete(ab, peer);
 		list_del(&peer->list);
 		kfree(peer);
 	}
@@ -1229,6 +1241,7 @@
 	u8 *ies;
 	int ret;
 	const u8 *vht_cap_ie;
+	u64 adjusted_tsf;
 
 	ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn);
 	ies += sizeof(mgmt->u.beacon);
@@ -1266,6 +1279,15 @@
 			     WMI_BEACON_EMA_PARAM_LAST_TMPL_SHIFT;
 	}
 
+	/* Make the TSF offset negative so beacons in the same
+	 * staggered batch have the same TSF.
+	 */
+	if (arvif->tbtt_offset) {
+		adjusted_tsf = cpu_to_le64(0ULL - arvif->tbtt_offset);
+		mgmt = (void *)bcn->data;
+		memcpy(&mgmt->u.beacon.timestamp, &adjusted_tsf, sizeof(adjusted_tsf));
+	}
+
 	ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, ema_param);
 
 	if (ret)
@@ -1324,7 +1346,7 @@
 	return ret;
 }
 
-static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
+int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
 {
 	if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
 		return 0;
@@ -3183,7 +3205,7 @@
 
 static void ath11k_mac_op_nss_bss_info_changed(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif,
-					   u32 changed)
+					   u64 changed)
 {
 	struct ath11k *ar = hw->priv;
 	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
@@ -3221,7 +3243,7 @@
 static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif,
 					   struct ieee80211_bss_conf *info,
-					   u32 changed)
+					   u64 changed)
 {
 	struct ath11k *ar = hw->priv;
 	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
@@ -3239,6 +3261,24 @@
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (changed & BSS_CHANGED_6G_POWER_MODE) {
+		if (ar->supports_6ghz &&
+		    info->chandef.chan->band == NL80211_BAND_6GHZ &&
+		    arvif->vdev_type == WMI_VDEV_TYPE_AP &&
+		    test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) {
+			ath11k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
+			ret = ath11k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
+							   &arvif->reg_tpc_info);
+			if (ret)
+				ath11k_warn(ar->ab, "Failed to set 6GHZ power mode\n");
+			else
+				ieee80211_6ghz_power_mode_switch_done(arvif->vif);
+
+	        } else {
+			ath11k_warn(ar->ab, "Set 6GHZ power mode not applicable\n");
+		}
+	}
+
 	if (changed & BSS_CHANGED_FTM_RESPONDER &&
 	    arvif->ftm_responder != info->ftm_responder &&
 	    (vif->type == NL80211_IFTYPE_AP ||
@@ -3433,19 +3473,8 @@
 	if (changed & BSS_CHANGED_TXPOWER) {
 		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev_id %i txpower %d\n",
 			   arvif->vdev_id, info->txpower);
-
-		if (ar->supports_6ghz && info->chandef.chan &&
-		    info->chandef.chan->band == NL80211_BAND_6GHZ &&
-		    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
-		     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
-		    test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT,
-			     ar->ab->wmi_ab.svc_map)) {
-			ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
-				   "discard tx power, change to set TPC power\n");
-		} else {
-			arvif->txpower = info->txpower;
-			ath11k_mac_txpower_recalc(ar);
-		}
+		arvif->txpower = info->txpower;
+		ath11k_mac_txpower_recalc(ar);
 	}
 
 	if (changed & BSS_CHANGED_MCAST_RATE &&
@@ -4031,6 +4060,7 @@
 	const u8 *peer_addr;
 	int ret = 0;
 	u32 flags = 0;
+	unsigned long time_left;
 
 	/* BIP needs to be done in software */
 	if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
@@ -4108,6 +4138,14 @@
 	else
 		flags |= WMI_KEY_GROUP;
 
+	if (arsta && cmd == DISABLE_KEY && arsta->tx_disassoc) {
+		time_left = wait_for_completion_timeout(&arsta->disassoc_comp,
+							ATH11K_DISASSOC_TX_COMPLETION_TIMEOUT);
+		if (!time_left)
+			ath11k_warn(ab, "disassociation tx completion timeout %pM\n",
+				    sta->addr);
+	}
+
 	ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
 	if (ret) {
 		ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
@@ -4759,8 +4797,10 @@
 				   struct ieee80211_sta *sta)
 {
 	struct ath11k_vif *arvif = (void *)vif->drv_priv;
+	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 	bool peer_dbg_info;
 	int ret = 0;
+	unsigned long time_left;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
@@ -4776,6 +4816,14 @@
 			return ret;
 	}
 
+	if (arsta->tx_disassoc) {
+		time_left = wait_for_completion_timeout(&arsta->disassoc_comp,
+							ATH11K_DISASSOC_TX_COMPLETION_TIMEOUT);
+		if (!time_left)
+			ath11k_warn(ar->ab, "disassociation tx completion timeout sta %pM\n",
+				    sta->addr);
+	}
+
 	ret = ath11k_clear_peer_keys(arvif, sta->addr);
 	if (ret) {
 		ath11k_warn(ar->ab, "failed to clear all peer keys for vdev %i: %d\n",
@@ -4796,11 +4844,12 @@
 	const u8 *ht_mcs_mask;
 	const u16 *vht_mcs_mask;
 	const u16 *he_mcs_mask;
-	u32 changed, bw, nss, smps;
+	u32 changed, bw, nss, smps, bw_last;
 	int err, num_ht_rates, num_vht_rates,  num_he_rates;
 	const struct cfg80211_bitrate_mask *mask;
 	struct peer_assoc_params peer_arg;
 	bool peer_dbg_info, debug;
+	enum wmi_phy_mode peer_phymode;
 
 	arsta = container_of(wk, struct ath11k_sta, update_wk);
 	sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
@@ -4821,6 +4870,7 @@
 	arsta->changed = 0;
 
 	bw = arsta->bw;
+	bw_last = arsta->bw_last;
 	nss = arsta->nss;
 	smps = arsta->smps;
 
@@ -4836,11 +4886,59 @@
 			   ath11k_mac_max_he_nss(he_mcs_mask)));
 
 	if (changed & IEEE80211_RC_BW_CHANGED) {
-		err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
-						WMI_PEER_CHWIDTH, bw);
-		if (err)
-			ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
-				    sta->addr, bw, err);
+		/* Get the the peer phymode */
+		ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg);
+		peer_phymode = peer_arg.peer_phymode;
+
+		if (peer_dbg_info)
+			ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "mac update sta %pM peer bw %d phymode %d\n",
+				   sta->addr, bw, peer_phymode);
+
+		if (bw > bw_last) {
+			/* BW is upgraded. In this case we send WMI_PEER_PHYMODE
+			 * followed by WMI_PEER_CHWIDTH
+			 */
+			ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n",
+				   sta->addr, bw, bw_last);
+
+			err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+							WMI_PEER_PHYMODE, peer_phymode);
+
+			if (err) {
+				ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
+					    sta->addr, peer_phymode, err);
+				goto err_rc_update;
+			}
+
+			err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+							WMI_PEER_CHWIDTH, bw);
+
+			if (err)
+				ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
+					    sta->addr, bw, err);
+		} else {
+			/* BW is downgraded. In this case we send WMI_PEER_CHWIDTH
+			 * followed by WMI_PEER_PHYMODE
+			 */
+			ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d, old BW %d\n",
+				   sta->addr, bw, bw_last);
+
+			err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+							WMI_PEER_CHWIDTH, bw);
+
+			if (err) {
+				ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
+					    sta->addr, bw, err);
+				goto err_rc_update;
+			}
+
+			err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+							WMI_PEER_PHYMODE, peer_phymode);
+
+			if (err)
+				ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
+					    sta->addr, peer_phymode, err);
+		}
 	}
 
 	if (changed & IEEE80211_RC_NSS_CHANGED) {
@@ -4931,6 +5029,7 @@
 		}
 	}
 
+err_rc_update:
 	mutex_unlock(&ar->conf_mutex);
 }
 
@@ -5497,6 +5596,8 @@
 		INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
 		INIT_WORK(&arsta->use_4addr_wk, ath11k_sta_use_4addr_wk);
 		INIT_WORK(&arsta->tid_config_wk, ath11k_sta_tid_cfg_wk);
+		init_completion(&arsta->disassoc_comp);
+		arsta->tx_disassoc = false;
 
 		ret = ath11k_mac_station_add(ar, vif, sta);
 		if (ret)
@@ -5520,13 +5621,13 @@
 		if (peer && peer->sta == sta) {
 			ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
 				    vif->addr, arvif->vdev_id);
+			ath11k_peer_rhash_delete(ar->ab, peer);
 			peer->sta = NULL;
 			list_del(&peer->list);
 			kfree(peer);
 			ar->num_peers--;
 		}
 		spin_unlock_bh(&ar->ab->base_lock);
-
 		kfree(arsta->tx_stats);
 		arsta->tx_stats = NULL;
 		kfree(arsta->wbm_tx_stats);
@@ -5563,6 +5664,11 @@
 			peer->is_authorized = true;
 		spin_unlock_bh(&ar->ab->base_lock);
 
+		spin_lock_bh(&ar->data_lock);
+		/* Set arsta bw and last bw */
+		arsta->bw = arsta->bw_last = sta->bandwidth;
+		spin_unlock_bh(&ar->data_lock);
+
 		if (vif->type == NL80211_IFTYPE_STATION) {
 			ret = ath11k_wmi_set_peer_param(ar, sta->addr,
 							arvif->vdev_id,
@@ -5725,6 +5831,7 @@
 			break;
 		}
 
+		arsta->bw_last = arsta->bw;
 		arsta->bw = bw;
 	}
 
@@ -6501,6 +6608,8 @@
 	struct ath11k_base *ab = ar->ab;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct ieee80211_tx_info *info;
+	struct ath11k_peer *peer;
+	struct ath11k_sta *arsta;
 	dma_addr_t paddr;
 	bool tx_params_valid = false;
 	int buf_id;
@@ -6549,6 +6658,18 @@
 	    peer_is_in_cfr_unassoc_pool(ar, hdr->addr1))
 		tx_params_valid = true;
 
+	if (ieee80211_has_protected(hdr->frame_control) &&
+	    ieee80211_is_disassoc(hdr->frame_control)) {
+		spin_lock_bh(&ar->ab->base_lock);
+		peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr1);
+		if (peer && peer->sta) {
+			arsta = (struct ath11k_sta *)peer->sta->drv_priv;
+			reinit_completion(&arsta->disassoc_comp);
+			arsta->tx_disassoc = true;
+		}
+		spin_unlock_bh(&ar->ab->base_lock);
+	}
+
 	ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb,
 				   tx_params_valid);
 	if (ret) {
@@ -6666,11 +6787,13 @@
 	u32 info_flags = info->flags;
 	struct ieee80211_sta *sta = control->sta;
 	struct ath11k_sta *arsta = NULL;
+	struct ieee80211_mgmt *mgmt;
 	bool is_prb_rsp;
 	u16 frm_type = 0;
 	u8 tid, *qos_ctl;
 	bool noack = false;
 	int ret;
+	u64 adjusted_tsf;
 
 	if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))) {
 		ieee80211_free_txskb(ar->hw, skb);
@@ -6690,6 +6813,12 @@
 	} else if (ieee80211_is_mgmt(hdr->frame_control)) {
 		frm_type = FIELD_GET(IEEE80211_FCTL_STYPE, hdr->frame_control);
 		is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
+		if (is_prb_rsp && arvif->tbtt_offset) {
+			mgmt = (struct ieee80211_mgmt *)skb->data;
+			adjusted_tsf = cpu_to_le64(0ULL - arvif->tbtt_offset);
+			memcpy(&mgmt->u.probe_resp.timestamp, &adjusted_tsf,
+			       sizeof(adjusted_tsf));
+		}
 		ret = ath11k_mac_tx_over_wmi(ar, skb, is_prb_rsp);
 		if (ret) {
 			if (ret != -EBUSY)
@@ -6985,6 +7114,22 @@
 	return ret;
 }
 
+static void ath11k_update_bcn_template_work(struct work_struct *work)
+{
+	struct ath11k_vif *arvif = container_of(work, struct ath11k_vif,
+						update_bcn_template_work);
+	struct ath11k *ar = arvif->ar;
+	int ret = 0;
+
+	mutex_lock(&ar->conf_mutex);
+	if (arvif->is_up)
+		ret = ath11k_mac_setup_bcn_tmpl(arvif);
+	mutex_unlock(&ar->conf_mutex);
+	if (ret)
+		ath11k_warn(ar->ab, "failed to submit beacon template for vdev_id : %d ret : %d\n",
+			    arvif->vdev_id, ret);
+}
+
 static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
 {
 	struct ath11k *ar = hw->priv;
@@ -7207,6 +7352,7 @@
 
 	INIT_DELAYED_WORK(&arvif->connection_loss_work,
                           ath11k_mac_vif_sta_connection_loss_work);
+	INIT_WORK(&arvif->update_bcn_template_work, ath11k_update_bcn_template_work);
 
 	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
 		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
@@ -7238,8 +7384,12 @@
 		goto err;
 	}
 
-	ath11k_debugfs_dbg_mac_filter(arvif);
-	ath11k_debugfs_wbm_tx_comp_stats(arvif);
+	if (ar->state != ATH11K_STATE_RESTARTED) {
+		ath11k_debugfs_dbg_mac_filter(arvif);
+		ath11k_debugfs_wbm_tx_comp_stats(arvif);
+	} else {
+		INIT_LIST_HEAD(&arvif->mac_filters);
+	}
 
 	switch (vif->type) {
 	case NL80211_IFTYPE_UNSPECIFIED:
@@ -7408,6 +7558,14 @@
 
 	param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
 	param_value = ar->hw->wiphy->rts_threshold;
+
+	if (vif->type == NL80211_IFTYPE_MESH_POINT &&
+	    !ar->rts_threshold[vif->type])
+		ar->rts_threshold[vif->type] = 1;
+
+	if (ar->rts_threshold[vif->type])
+		param_value = ar->rts_threshold[vif->type];
+
 	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 					    param_id, param_value);
 	if (ret) {
@@ -7429,8 +7587,13 @@
 			goto err_peer_del;
 	}
 
-	ath11k_debug_aggr_size_config_init(arvif);
-	ath11k_debugfs_wmi_ctrl_stats(arvif);
+	if (ar->state != ATH11K_STATE_RESTARTED) {
+		ath11k_debug_aggr_size_config_init(arvif);
+		ath11k_debugfs_wmi_ctrl_stats(arvif);
+	} else {
+		INIT_LIST_HEAD(&arvif->ar->debug.wmi_list);
+		init_completion(&arvif->ar->debug.wmi_ctrl_path_stats_rcvd);
+	}
 
 	mutex_unlock(&ar->conf_mutex);
 
@@ -7508,6 +7671,7 @@
 	}
 
 	cancel_delayed_work_sync(&arvif->connection_loss_work);
+	cancel_work_sync(&arvif->update_bcn_template_work);
 
 	ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
 		   arvif->vdev_id);
@@ -8532,7 +8696,7 @@
 	bool is_psd_power = false, is_tpe_present = false;
 	s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
 		psd_power, tx_power = 0, eirp_power = 0;
-	u16 oper_freq = 0, start_freq = 0, center_freq = 0;
+	u16 oper_freq = 0, start_freq = 0, center_freq = 0, op_center_freq = 0;
 	u8 reg_6g_power_mode;
 	enum nl80211_chan_width bw;
 	int cfi;
@@ -8658,8 +8822,8 @@
 				psd_power = temp_chan->psd;
 				if (reg_6g_power_mode == IEEE80211_REG_SP_AP &&
 				    ar->afc.is_6g_afc_power_event_received) {
-					center_freq = ctx->def.center_freq1;
-					cfi = ieee80211_frequency_to_channel(center_freq);
+					op_center_freq = ctx->def.center_freq1;
+					cfi = ieee80211_frequency_to_channel(op_center_freq);
 					bw = ctx->def.width;
 					eirp_power = ath11k_reg_get_afc_eirp_power(ar,
 										   bw,
@@ -10448,6 +10612,7 @@
 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
 	struct ath11k *ar = hw->priv;
+	u32 bw_offset = 0;
 
 	sinfo->rx_duration = arsta->rx_duration;
 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
@@ -10460,6 +10625,11 @@
 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RTS_RETRIES);
 	}
 
+	if (arsta->tx_retry_count) {
+		sinfo->tx_retries = arsta->tx_retry_count;
+		 sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+	}
+
 	if (!arsta->txrate.legacy && !arsta->txrate.nss)
 		return;
 
@@ -10476,11 +10646,11 @@
 	sinfo->txrate.flags = arsta->txrate.flags;
 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
 
-	/* TODO: Use real NF instead of default one. */
-	sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR;
+	bw_offset = arsta->last_tx_pkt_bw * 3;
+	sinfo->signal = arsta->rssi_comb + ar->chan_noise_floor + bw_offset;
 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
 
-	sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi) + ATH11K_DEFAULT_NOISE_FLOOR;
+	sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi) + ar->chan_noise_floor;
 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
 
 	if (ath11k_nss_offload_enabled(ar->ab))
@@ -10629,7 +10799,7 @@
 
 static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw,
 				     struct ieee80211_vif *vif,
-				     int *dbm)
+				     int *mbm)
 {
 	struct ath11k *ar = hw->priv;
 	struct ath11k_base *ab = ar->ab;
@@ -10668,22 +10838,134 @@
 	}
 
 	/* tx power is set as 2 units per dBm in FW. */
-	*dbm = pdev->chan_tx_power/2;
+	*mbm = DBM_TO_MBM(pdev->chan_tx_power) / 2;
 
 	spin_unlock_bh(&ar->data_lock);
 	mutex_unlock(&ar->conf_mutex);
 
-	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from fw\n", __func__, *dbm);
+	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from fw\n", __func__, *mbm);
 	return 0;
 
 err_unlock:
 	mutex_unlock(&ar->conf_mutex);
 	/* We didn't get txpower from FW. Hence, relying on vif->bss_conf.txpower */
-	*dbm = vif->bss_conf.txpower;
+	*mbm = DBM_TO_MBM(vif->bss_conf.txpower);
 	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from bss_conf\n", __func__, vif->bss_conf.txpower);
 	return 0;
 }
 
+static int ath11k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
+						  struct ieee80211_vif *vif)
+{
+	struct ath11k *ar = hw->priv;
+
+	mutex_lock(&ar->conf_mutex);
+
+	spin_lock_bh(&ar->data_lock);
+	ar->scan.roc_notify = false;
+	spin_unlock_bh(&ar->data_lock);
+
+	ath11k_scan_abort(ar);
+
+	mutex_unlock(&ar->conf_mutex);
+
+	cancel_delayed_work_sync(&ar->scan.timeout);
+
+	return 0;
+}
+
+static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif,
+					   struct ieee80211_channel *chan,
+					   int duration,
+					   enum ieee80211_roc_type type)
+{
+	struct ath11k *ar = hw->priv;
+	struct ath11k_vif *arvif = (void *)vif->drv_priv;
+	struct scan_req_params *arg;
+	int ret;
+	u32 scan_time_msec;
+
+	mutex_lock(&ar->conf_mutex);
+
+	spin_lock_bh(&ar->data_lock);
+	switch (ar->scan.state) {
+	case ATH11K_SCAN_IDLE:
+		reinit_completion(&ar->scan.started);
+		reinit_completion(&ar->scan.completed);
+		reinit_completion(&ar->scan.on_channel);
+		ar->scan.state = ATH11K_SCAN_STARTING;
+		ar->scan.is_roc = true;
+		ar->scan.vdev_id = arvif->vdev_id;
+		ar->scan.roc_freq = chan->center_freq;
+		ar->scan.roc_notify = true;
+		ret = 0;
+		break;
+	case ATH11K_SCAN_STARTING:
+	case ATH11K_SCAN_RUNNING:
+	case ATH11K_SCAN_ABORTING:
+		ret = -EBUSY;
+		break;
+	}
+	spin_unlock_bh(&ar->data_lock);
+
+	if (ret)
+		goto exit;
+
+	scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
+
+	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ath11k_wmi_start_scan_init(ar, arg);
+	arg->chan_list.num_chan = 1;
+
+	arg->vdev_id = arvif->vdev_id;
+	arg->scan_id = ATH11K_SCAN_ID;
+	arg->chan_list.chan[0].freq = chan->center_freq;
+	arg->dwell_time_active = scan_time_msec;
+	arg->dwell_time_passive = scan_time_msec;
+	arg->max_scan_time = scan_time_msec;
+	arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE;
+	arg->scan_flags |= WMI_SCAN_FILTER_PROBE_REQ;
+	arg->burst_duration = duration;
+
+	ret = ath11k_start_scan(ar, arg);
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to start roc scan: %d\n", ret);
+
+		spin_lock_bh(&ar->data_lock);
+		ar->scan.state = ATH11K_SCAN_IDLE;
+		spin_unlock_bh(&ar->data_lock);
+		goto exit;
+	}
+
+	ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
+	if (ret == 0) {
+		ath11k_warn(ar->ab, "failed to switch to channel for roc scan\n");
+		ret = ath11k_scan_stop(ar);
+		if (ret)
+			ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret);
+		ret = -ETIMEDOUT;
+		goto exit;
+	}
+
+	ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+				     msecs_to_jiffies(duration));
+
+	ret = 0;
+
+exit:
+	if (arg)
+		kfree(arg);
+
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
 static const struct ieee80211_ops ath11k_ops = {
 	.tx				= ath11k_mac_op_tx,
 	.start                          = ath11k_mac_op_start,
@@ -10722,6 +11004,8 @@
 	.set_tid_config			= ath11k_mac_op_set_tid_config,
 	.reset_tid_config		= ath11k_mac_op_reset_tid_config,
 	.sta_set_mgmt_rts_cts		= ath11k_mac_op_sta_set_mgmt_rts_cts,
+	.remain_on_channel              = ath11k_mac_op_remain_on_channel,
+	.cancel_remain_on_channel       = ath11k_mac_op_cancel_remain_on_channel,
 	CFG80211_TESTMODE_CMD(ath11k_tm_cmd)
 #ifdef CONFIG_ATH11K_DEBUGFS
 	.sta_add_debugfs		= ath11k_debugfs_sta_op_add,
@@ -11113,6 +11397,8 @@
 
 		__ath11k_mac_unregister(ar);
 	}
+
+	ath11k_peer_rhash_tbl_destroy(ab);
 }
 
 static int __ath11k_mac_register(struct ath11k *ar)
@@ -11391,6 +11677,10 @@
 
 	ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
 
+	ret = ath11k_peer_rhash_tbl_init(ab);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < ab->num_radios; i++) {
 		pdev = &ab->pdevs[i];
 		ar = pdev->ar;
@@ -11421,6 +11711,8 @@
 		__ath11k_mac_unregister(ar);
 	}
 
+	ath11k_peer_rhash_tbl_destroy(ab);
+
 	return ret;
 }
 
@@ -11487,6 +11779,7 @@
 		init_completion(&ar->bss_survey_done);
 		init_completion(&ar->scan.started);
 		init_completion(&ar->scan.completed);
+		init_completion(&ar->scan.on_channel);
 		init_completion(&ar->thermal.wmi_sync);
 
 		INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work);
diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h
index 7076e56..475756a 100644
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -133,6 +133,8 @@
 #define IEEE80211_HE_DL_MU_SUPPORT_ENABLE        2
 #define IEEE80211_HE_DL_MU_SUPPORT_INVALID       3
 
+#define ATH11K_DISASSOC_TX_COMPLETION_TIMEOUT    (3 * HZ)
+
 extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default;
 
 int ath11k_mac_ap_ps_recalc(struct ath11k *ar);
@@ -174,4 +176,5 @@
 void ath11k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
 				     struct ieee80211_chanctx_conf *conf,
 				     void *data);
+int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif);
 #endif
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index a951b7d..d17dff5 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -937,7 +937,7 @@
 	for (j = 0; j < irq_grp->num_irq; j++) {
 
 		int irq_idx = irq_grp->irqs[j];
-		int vector = (i % num_vectors) + base_vector;
+		int vector = (i % num_vectors);
 
 		irq_set_status_flags(msi_desc->irq, IRQ_DISABLE_UNLAZY);
 		ret = devm_request_irq(&pdev->dev, msi_desc->irq,
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
index 81d3df4..b0cc6f8 100644
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -27,25 +27,6 @@
 	return NULL;
 }
 
-static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab,
-							u8 pdev_idx, const u8 *addr)
-{
-	struct ath11k_peer *peer;
-
-	lockdep_assert_held(&ab->base_lock);
-
-	list_for_each_entry(peer, &ab->peers, list) {
-		if (peer->pdev_idx != pdev_idx)
-			continue;
-		if (!ether_addr_equal(peer->addr, addr))
-			continue;
-
-		return peer;
-	}
-
-	return NULL;
-}
-
 struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
 					     const u8 *addr)
 {
@@ -53,14 +34,13 @@
 
 	lockdep_assert_held(&ab->base_lock);
 
-	list_for_each_entry(peer, &ab->peers, list) {
-		if (!ether_addr_equal(peer->addr, addr))
-			continue;
+	if (!ab->rhead_peer_addr)
+		return NULL;
 
-		return peer;
-	}
+	peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr,
+				      ab->rhash_peer_addr_param);
 
-	return NULL;
+	return peer;
 }
 
 struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
@@ -70,11 +50,13 @@
 
 	lockdep_assert_held(&ab->base_lock);
 
-	list_for_each_entry(peer, &ab->peers, list)
-		if (peer_id == peer->peer_id)
-			return peer;
+	if (!ab->rhead_peer_id)
+		return NULL;
 
-	return NULL;
+	peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id,
+				      ab->rhash_peer_id_param);
+
+	return peer;
 }
 
 struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
@@ -461,6 +443,7 @@
 	ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
 		   peer->vdev_id, peer->addr, peer_id);
 
+	ath11k_peer_rhash_delete(ab, peer);
 	list_del(&peer->list);
 	kfree(peer);
 	wake_up(&ab->peer_mapping_wq);
@@ -502,6 +485,7 @@
 		ar->bss_peer = NULL;
 free_peer:
 	rcu_read_unlock();
+	ath11k_peer_rhash_delete(ab, peer);
 	list_del(&peer->list);
 	kfree(peer);
 	wake_up(&ab->peer_mapping_wq);
@@ -607,6 +591,69 @@
 	return 0;
 }
 
+static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab,
+					   struct rhashtable *rtbl,
+					   struct rhash_head *rhead,
+					   struct rhashtable_params *params,
+					   void *key)
+{
+	struct ath11k_peer *tmp;
+
+	lockdep_assert_held(&ab->base_lock);
+
+	tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params);
+
+	if (!tmp)
+		return 0;
+	else if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
+	else
+		return -EEXIST;
+}
+
+static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab,
+					   struct rhashtable *rtbl,
+					   struct rhash_head *rhead,
+					   struct rhashtable_params *params)
+{
+	lockdep_assert_held(&ab->base_lock);
+
+	return rhashtable_remove_fast(rtbl, rhead, *params);
+}
+
+static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer)
+{
+	int ret;
+
+	lockdep_assert_held(&ab->base_lock);
+
+	if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
+		return -EPERM;
+
+	ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id,
+				       &ab->rhash_peer_id_param, &peer->peer_id);
+	if (ret) {
+		ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n",
+			    peer->addr, peer->peer_id, ret);
+		return ret;
+	}
+
+	ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr,
+				       &ab->rhash_peer_addr_param, &peer->addr);
+	if (ret) {
+		ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
+			    peer->addr, peer->peer_id, ret);
+		goto err_clean;
+	}
+
+	return 0;
+
+err_clean:
+	ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
+				 &ab->rhash_peer_id_param);
+	return ret;
+}
+
 void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
 {
 	struct ath11k_peer *peer, *tmp_peer;
@@ -634,6 +681,7 @@
 					 &peer->ast_entry_list, ase_list)
 			ath11k_peer_del_ast(ar, ast_entry);
 
+		ath11k_peer_rhash_delete(ab, peer);
 		list_del(&peer->list);
 		kfree(peer);
 		ar->num_peers--;
@@ -743,7 +791,7 @@
 	struct ath11k_peer *peer;
 	struct ieee80211_vif *vif = arvif->vif;
 	struct ath11k_sta *arsta;
-	int ret;
+	int ret, err_ret;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
@@ -754,7 +802,7 @@
 	}
 
 	spin_lock_bh(&ar->ab->base_lock);
-	peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr);
+	peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
 	if (peer) {
 		spin_unlock_bh(&ar->ab->base_lock);
 		return -EINVAL;
@@ -782,22 +830,14 @@
 		ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
 			    param->peer_addr, param->vdev_id);
 
-		reinit_completion(&ar->peer_delete_done);
+		ret = -ENOENT;
+		goto cleanup;
+	}
 
-		ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
-						      param->vdev_id);
-		if (ret) {
-			ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
-				    param->vdev_id, param->peer_addr);
-			return ret;
-		}
-
-		ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id,
-						       param->peer_addr);
-		if (ret)
-			return ret;
-
-		return -ENOENT;
+	ret = ath11k_peer_rhash_add(ar->ab, peer);
+	if (ret) {
+		spin_unlock_bh(&ar->ab->base_lock);
+		goto cleanup;
 	}
 
 	peer->pdev_idx = ar->pdev_idx;
@@ -831,4 +871,211 @@
 	spin_unlock_bh(&ar->ab->base_lock);
 
 	return 0;
+
+cleanup:
+	reinit_completion(&ar->peer_delete_done);
+
+	err_ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
+						  param->vdev_id);
+	if (err_ret) {
+		ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM ret %d\n",
+			    param->vdev_id, param->peer_addr, err_ret);
+		goto exit;
+	}
+
+	err_ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id,
+						   param->peer_addr);
+	if (err_ret)
+		ath11k_warn(ar->ab, "failed wait for peer %pM delete done id %d ret %d\n",
+			   param->peer_addr, param->vdev_id, err_ret);
+
+exit:
+	return ret;
+}
+
+int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer)
+{
+	int ret;
+
+	lockdep_assert_held(&ab->base_lock);
+
+	if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
+		return -EPERM;
+
+	ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
+				       &ab->rhash_peer_id_param);
+	if (ret) {
+		ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n",
+			    peer->addr, peer->peer_id, ret);
+		return ret;
+	}
+
+	ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr,
+				       &ab->rhash_peer_addr_param);
+	if (ret) {
+		ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n",
+			    peer->addr, peer->peer_id, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab)
+{
+	struct rhashtable_params *param;
+	struct rhashtable *rhash_id_tbl;
+	int ret;
+	size_t size;
+
+	if (ab->rhead_peer_id)
+		return 0;
+
+	size = sizeof(*ab->rhead_peer_id);
+	rhash_id_tbl = kzalloc(size, GFP_KERNEL);
+	if (!rhash_id_tbl) {
+		ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n",
+			    size);
+		return -ENOMEM;
+	}
+
+	param = &ab->rhash_peer_id_param;
+
+	param->key_offset = offsetof(struct ath11k_peer, peer_id);
+	param->head_offset = offsetof(struct ath11k_peer, rhash_id);
+	param->key_len = sizeof_field(struct ath11k_peer, peer_id);
+	param->automatic_shrinking = true;
+	param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV;
+
+	ret = rhashtable_init(rhash_id_tbl, param);
+	if (ret) {
+		ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret);
+		goto err_free;
+	}
+
+	spin_lock_bh(&ab->base_lock);
+
+	if (!ab->rhead_peer_id) {
+		ab->rhead_peer_id = rhash_id_tbl;
+	} else {
+		spin_unlock_bh(&ab->base_lock);
+		ath11k_warn(ab, "already peer rhash id init done id_tbl: %p\n",
+			    ab->rhead_peer_id);
+		goto cleanup_tbl;
+	}
+
+	spin_unlock_bh(&ab->base_lock);
+
+	return 0;
+
+cleanup_tbl:
+	rhashtable_destroy(rhash_id_tbl);
+err_free:
+	kfree(rhash_id_tbl);
+
+	return ret;
+}
+
+static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab)
+{
+	struct rhashtable_params *param;
+	struct rhashtable *rhash_addr_tbl;
+	int ret;
+	size_t size;
+
+	if (ab->rhead_peer_addr)
+		return 0;
+
+	size = sizeof(*ab->rhead_peer_addr);
+	rhash_addr_tbl = kzalloc(size, GFP_KERNEL);
+	if (!rhash_addr_tbl) {
+		ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n",
+			    size);
+		return -ENOMEM;
+	}
+
+	param = &ab->rhash_peer_addr_param;
+
+	param->key_offset = offsetof(struct ath11k_peer, addr);
+	param->head_offset = offsetof(struct ath11k_peer, rhash_addr);
+	param->key_len = sizeof_field(struct ath11k_peer, addr);
+	param->automatic_shrinking = true;
+	param->nelem_hint = TARGET_NUM_PEERS_PDEV;
+
+	ret = rhashtable_init(rhash_addr_tbl, param);
+	if (ret) {
+		ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
+		goto err_free;
+	}
+
+	spin_lock_bh(&ab->base_lock);
+
+	if (!ab->rhead_peer_addr) {
+		ab->rhead_peer_addr = rhash_addr_tbl;
+	} else {
+		spin_unlock_bh(&ab->base_lock);
+		ath11k_warn(ab, "already peer rhash addr init done\n");
+		goto cleanup_tbl;
+	}
+
+	spin_unlock_bh(&ab->base_lock);
+
+	return 0;
+
+cleanup_tbl:
+	rhashtable_destroy(rhash_addr_tbl);
+err_free:
+	kfree(rhash_addr_tbl);
+
+	return ret;
+}
+
+static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab)
+{
+	if (!ab->rhead_peer_id)
+		return;
+
+	rhashtable_destroy(ab->rhead_peer_id);
+	kfree(ab->rhead_peer_id);
+	ab->rhead_peer_id = NULL;
+}
+
+static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab)
+{
+	if (!ab->rhead_peer_addr)
+		return;
+
+	rhashtable_destroy(ab->rhead_peer_addr);
+	kfree(ab->rhead_peer_addr);
+	ab->rhead_peer_addr = NULL;
+}
+
+int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab)
+{
+	int ret;
+
+	ret = ath11k_peer_rhash_id_tbl_init(ab);
+	if (ret)
+		return ret;
+
+	ret = ath11k_peer_rhash_addr_tbl_init(ab);
+	if (ret)
+		goto cleanup_tbl;
+
+	return 0;
+
+cleanup_tbl:
+	ath11k_peer_rhash_id_tbl_destroy(ab);
+
+	return ret;
+}
+
+void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab)
+{
+	spin_lock_bh(&ab->base_lock);
+
+	ath11k_peer_rhash_id_tbl_destroy(ab);
+	ath11k_peer_rhash_addr_tbl_destroy(ab);
+
+	spin_unlock_bh(&ab->base_lock);
 }
diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h
index e54ced9..aa0835d 100644
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -75,6 +75,10 @@
 	/* protected by ab->data_lock */
 	struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
 	struct dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
+	/* peer id based rhashtable list pointer */
+	struct rhash_head rhash_id;
+	/* peer addr based rhashtable list pointer */
+	struct rhash_head rhash_addr;
 
 	/* Info used in MMIC verification of
 	 * RX fragments
@@ -113,6 +117,9 @@
 				     const u8 *addr);
 struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
 						int vdev_id);
+int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab);
+void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab);
+int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer);
 
 #ifdef CONFIG_ATH11K_NSS_SUPPORT
 struct ath11k_ast_entry *ath11k_peer_ast_find_by_addr(struct ath11k_base *ab,
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index c13bc82..cbcb031 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/elf.h>
@@ -4535,9 +4536,8 @@
 
 				ath11k_core_qmi_firmware_ready(ab);
 				set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
-				if (country_code) {
-					ath11k_reg_update_cc(ab);
-				}
+				if (country_code)
+					ath11k_reg_update_cc(ab, country_code);
 			}
 
 			break;
diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c
index 281f646..a45182a 100644
--- a/drivers/net/wireless/ath/ath11k/reg.c
+++ b/drivers/net/wireless/ath/ath11k/reg.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #include "core.h"
 #include "debug.h"
@@ -16,8 +17,6 @@
 #define ETSI_WEATHER_RADAR_BAND_HIGH		5650
 #define ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT	600000
 
-extern char *country_code;
-
 static const struct ieee80211_regdomain ath11k_world_regd = {
 	.n_reg_rules = 3,
 	.alpha2 =  "00",
@@ -128,22 +127,21 @@
 			    "INIT Country code set to fw failed : %d\n", ret);
 }
 
-void ath11k_reg_update_cc(struct ath11k_base *ab)
+void ath11k_reg_update_cc(struct ath11k_base *ab, const char *country_code)
 {
 	struct wmi_init_country_params init_country_param;
 	struct ath11k_pdev *pdev;
-	struct ath11k *ar;
 	int i, ret;
 
+	init_country_param.flags = ALPHA_IS_SET;
+	memcpy(&init_country_param.cc_info.alpha2, country_code, 2);
+	init_country_param.cc_info.alpha2[2] = 0;
+
 	for (i = 0; i < ab->num_radios; i++) {
 		pdev = &ab->pdevs[i];
-		ar = pdev->ar;
-		init_country_param.flags = ALPHA_IS_SET;
-		memcpy(&init_country_param.cc_info.alpha2, country_code, 2);
-		init_country_param.cc_info.alpha2[2] = 0;
-		ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param);
+		ret = ath11k_wmi_send_init_country_cmd(pdev->ar, init_country_param);
 		if (ret)
-			ath11k_warn(ar->ab,
+			ath11k_warn(pdev->ar->ab,
 				    "INIT Country code set to fw failed : %d\n", ret);
 	}
 }
@@ -216,6 +214,11 @@
 
 	rtnl_lock();
 	wiphy_lock(ar->hw->wiphy);
+	if (ar->afc.is_6g_afc_power_event_received || ar->afc.switch_to_lpi_indication_received)
+		ar->hw->wiphy->regulatory_flags |= REGULATORY_SET_BY_6GHZ_AFC;
+	else
+		ar->hw->wiphy->regulatory_flags &= ~REGULATORY_SET_BY_6GHZ_AFC;
+
 	ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy);
 	wiphy_unlock(ar->hw->wiphy);
 	rtnl_unlock();
@@ -884,6 +887,69 @@
 	*tx_power = ath11k_reg_get_afc_eirp_power(ar, bw, cfi);
 }
 
+int ath11k_reg_switch_to_lpi(struct ath11k_base *ab, struct ath11k_afc_info *afc)
+{
+	struct ieee80211_regdomain *regd = NULL;
+	struct ieee80211_regdomain *new_regd = NULL;
+	struct ieee80211_reg_rule *old_rule, *new_regd_rules;
+	struct ath11k *ar = container_of(afc, struct ath11k, afc);
+	int new_reg_rule_cnt = 0, num_regd_rules = 0, num_sp_rules = 0;
+	int i, k, pdev_idx, ret = 0;
+
+	pdev_idx = ar->pdev_idx;
+
+	if (ab->new_regd[pdev_idx]) {
+		regd = ab->new_regd[pdev_idx];
+	} else {
+		regd = ab->default_regd[pdev_idx];
+	}
+
+	if (!regd) {
+		ath11k_warn(ab, "Regulatory domain data not present\n");
+		return -EINVAL;
+	}
+
+	num_regd_rules = regd->n_reg_rules;
+	for (i = 0; i < num_regd_rules; i++) {
+		old_rule = regd->reg_rules + i;
+		if (old_rule->mode == NL80211_REG_AP_SP)
+			num_sp_rules++;
+	}
+
+	new_reg_rule_cnt = num_regd_rules  - num_sp_rules;
+
+	new_regd = kzalloc(sizeof(*new_regd) +
+			   (sizeof(*new_regd_rules) * new_reg_rule_cnt),
+			   GFP_KERNEL);
+	if (!new_regd)
+		return -ENOMEM;
+
+	new_regd->n_reg_rules = new_reg_rule_cnt;
+	memcpy(new_regd->alpha2, regd->alpha2, REG_ALPHA2_LEN + 1);
+	new_regd->dfs_region = ath11k_map_fw_dfs_region(regd->dfs_region);
+	k = 0;
+	for (i = 0; i < num_regd_rules; i++) {
+		old_rule = regd->reg_rules + i;
+
+		if (old_rule->mode == NL80211_REG_AP_SP) {
+			continue;
+		} else {
+			memcpy((new_regd->reg_rules + k), old_rule, sizeof(*new_regd_rules));
+			k++;
+		}
+	}
+
+	ar->afc.switch_to_lpi_indication_received = true;
+
+	spin_lock_bh(&ab->base_lock);
+	kfree(ab->new_regd[pdev_idx]);
+	ab->new_regd[pdev_idx] = new_regd;
+	spin_unlock_bh(&ab->base_lock);
+
+	ieee80211_queue_work(ar->hw, &ar->regd_update_work);
+	return ret;
+}
+
 int ath11k_reg_process_afc_power_event(struct ath11k *ar)
 {
 	struct ath11k_base *ab = ar->ab;
@@ -964,6 +1030,9 @@
 		}
 	}
 
+	if (num_new_sp_rules)
+		ar->afc.switch_to_lpi_indication_received = false;
+
 	/* Remove the old sp rule from regd and add the new intersected sp rules */
 	new_reg_rule_cnt = num_regd_rules  - num_old_sp_rules + num_new_sp_rules;
 	ath11k_dbg(ab, ATH11K_DBG_AFC,
@@ -972,7 +1041,7 @@
 
 	new_regd = kzalloc(sizeof(*new_regd) +
 			   (sizeof(*new_regd_rules) * new_reg_rule_cnt),
-			   GFP_KERNEL);
+			   GFP_ATOMIC);
 	if (!new_regd) {
 		ret = -ENOMEM;
 		goto end;
@@ -1060,8 +1129,15 @@
 	}
 
 	status[AFC_AUTH_STATUS_OFFSET] = cpu_to_le32(AFC_AUTH_ERROR);
-	memset(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE);
-	memcpy(mem + (slotid * AFC_SLOT_SIZE), afc_resp, len);
+
+	if (ab->userpd_id) {
+		memset_io(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE);
+		memcpy_toio(mem + (slotid * AFC_SLOT_SIZE), afc_resp, len);
+	} else {
+		memset(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE);
+		memcpy(mem + (slotid * AFC_SLOT_SIZE), afc_resp, len);
+	}
+
 	status[AFC_AUTH_STATUS_OFFSET] = cpu_to_le32(AFC_AUTH_SUCCESS);
 
 	return 0;
@@ -1073,7 +1149,7 @@
 	struct ath11k_afc_req_fixed_params *fixed_param = NULL;
 	int ret = 0;
 
-	fixed_param = kzalloc(sizeof(*fixed_param), GFP_KERNEL);
+	fixed_param = kzalloc(sizeof(*fixed_param), GFP_ATOMIC);
 	if (!fixed_param)
 		return -ENOMEM;
 
@@ -1105,8 +1181,9 @@
 		}
 		break;
 	case REG_AFC_EXPIRY_EVENT_SWITCH_TO_LPI:
-		/*TBH*/
-		break;
+		ath11k_dbg(ab, ATH11K_DBG_AFC, "AFC switch to LPI indication received\n");
+		ret = ath11k_reg_switch_to_lpi(ab, afc);
+		return ret;
 	default:
 		ath11k_dbg(ab, ATH11K_DBG_AFC, "Invalid AFC expiry event subtype %d\n",
 			   afc->event_subtype);
diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h
index a5dfb89..b4939a2 100644
--- a/drivers/net/wireless/ath/ath11k/reg.h
+++ b/drivers/net/wireless/ath/ath11k/reg.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef ATH11K_REG_H
@@ -65,6 +66,6 @@
 					  u16 *center_freq, int pwr_level,
 					  struct cfg80211_chan_def *chan_def,
 					  s8 *tx_power);
-void ath11k_reg_update_cc(struct ath11k_base *ab);
+void ath11k_reg_update_cc(struct ath11k_base *ab, const char *country_code);
 
 #endif
diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c
index bfba684..63edc6e 100644
--- a/drivers/net/wireless/ath/ath11k/testmode.c
+++ b/drivers/net/wireless/ath/ath11k/testmode.c
@@ -61,7 +61,7 @@
 		return;
 	}
 
-	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+	cfg80211_testmode_event(nl_skb, GFP_ATOMIC, true);
 }
 
 /* Returns true if callee consumes the skb and the skb should be discarded.
@@ -141,7 +141,7 @@
 		goto out;
 	}
 
-	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+	cfg80211_testmode_event(nl_skb, GFP_ATOMIC, false);
 
 out:
 	spin_unlock_bh(&ar->data_lock);
@@ -265,7 +265,7 @@
 		goto out;
 	}
 
-	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+	cfg80211_testmode_event(nl_skb, GFP_ATOMIC, false);
 
 out:
 	spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath11k/vendor.c b/drivers/net/wireless/ath/ath11k/vendor.c
index 6ba6a92..b1795b2 100644
--- a/drivers/net/wireless/ath/ath11k/vendor.c
+++ b/drivers/net/wireless/ath/ath11k/vendor.c
@@ -269,7 +269,7 @@
 	ath11k_dbg(ab, ATH11K_DBG_AFC,
 		   "Sending power update complete for afc request id %llu status code %d\n",
 		   fixed_param.req_id, fixed_param.status_code);
-	cfg80211_vendor_event(nl_skb, GFP_KERNEL);
+	cfg80211_vendor_event(nl_skb, GFP_ATOMIC);
 	return 0;
 }
 
@@ -305,7 +305,7 @@
 		goto out;
 	}
 
-	cfg80211_vendor_event(nl_skb, GFP_KERNEL);
+	cfg80211_vendor_event(nl_skb, GFP_ATOMIC);
 	ath11k_dbg(ar->ab, ATH11K_DBG_AFC,
 		   "Sending expiry event to higher layer of type %d\n",
 		   QCA_WLAN_VENDOR_AFC_EXPIRY_EVENT);
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index c6318d8..462acda 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -23,6 +23,8 @@
 #define ATH11K_WMI_STA_KICKOUT_TIMEOUT_MS	5000
 #define ATH11K_WMI_STA_KICKOUT_LIMIT		100
 
+#define ATH11K_TEST_CAL_STATUS(val, idx) ((val >> idx) & 1)
+
 struct wmi_tlv_policy {
 	size_t min_len;
 };
@@ -154,6 +156,9 @@
 		= { .min_len = sizeof(struct wmi_afc_event_fixed_param) },
 	[WMI_TAG_AFC_EXPIRY_EVENT_PARAM]
 		= { .min_len = sizeof(struct wmi_afc_expiry_event_param) },
+	[WMI_TAG_PDEV_CAL_STATUS_EVENT]
+		= { .min_len = sizeof(struct wmi_pdev_cal_status_event) },
+
 };
 
 #define PRIMAP(_hw_mode_) \
@@ -6347,6 +6352,8 @@
 	struct ieee80211_vif *vif;
 	struct ath11k_vif *arvif;
 	struct ath11k_mgmt_frame_stats *mgmt_stats;
+	struct ath11k_peer *peer;
+	struct ath11k_sta *arsta;
 	u16 frm_type;
 
 	spin_lock_bh(&ar->data_lock);
@@ -6386,6 +6393,18 @@
 			mgmt_stats->tx_compl_fail[frm_type]++;
 	}
 
+	if (ieee80211_has_protected(hdr->frame_control) &&
+	    ieee80211_is_disassoc(hdr->frame_control)) {
+		spin_lock_bh(&ar->ab->base_lock);
+		peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr1);
+		if (peer && peer->sta) {
+			arsta = (struct ath11k_sta *)peer->sta->drv_priv;
+			complete_all(&arsta->disassoc_comp);
+			arsta->tx_disassoc = false;
+		}
+		spin_unlock_bh(&ar->ab->base_lock);
+	}
+
 skip_mgmt_stats:
 	spin_unlock_bh(&ar->data_lock);
 
@@ -6457,6 +6476,8 @@
 		break;
 	case ATH11K_SCAN_STARTING:
 		ar->scan.state = ATH11K_SCAN_RUNNING;
+		if (ar->scan.is_roc)
+			ieee80211_ready_on_channel(ar->hw);
 		complete(&ar->scan.started);
 		break;
 	}
@@ -6539,6 +6560,8 @@
 	case ATH11K_SCAN_RUNNING:
 	case ATH11K_SCAN_ABORTING:
 		ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+		if (ar->scan.is_roc && ar->scan.roc_freq == freq)
+			complete(&ar->scan.on_channel);
 		break;
 	}
 }
@@ -6863,10 +6886,12 @@
 	return 0;
 }
 
-static void ath11k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
+static void ath11k_wmi_pull_pdev_stats_base(struct ath11k *ar,
+					    const struct wmi_pdev_stats_base *src,
 					    struct ath11k_fw_stats_pdev *dst)
 {
 	dst->ch_noise_floor = src->chan_nf;
+	ar->chan_noise_floor = src->chan_nf;
 	dst->tx_frame_count = src->tx_frame_count;
 	dst->rx_frame_count = src->rx_frame_count;
 	dst->rx_clear_count = src->rx_clear_count;
@@ -7045,7 +7070,7 @@
 		if (!dst)
 			continue;
 
-		ath11k_wmi_pull_pdev_stats_base(&src->base, dst);
+		ath11k_wmi_pull_pdev_stats_base(ar, &src->base, dst);
 		ath11k_wmi_pull_pdev_stats_tx(&src->tx, dst);
 		ath11k_wmi_pull_pdev_stats_rx(&src->rx, dst);
 		list_add_tail(&dst->list, &stats->pdevs);
@@ -8393,7 +8418,6 @@
 	spin_lock_bh(&ab->base_lock);
 
 	peer = ath11k_peer_find_by_addr(ab, arg.mac_addr);
-
 	if (!peer) {
 		spin_unlock_bh(&ab->base_lock);
 		ath11k_warn(ab, "peer not found %pM\n",
@@ -10063,7 +10087,6 @@
 	spin_lock_bh(&ab->base_lock);
 
 	peer = ath11k_peer_find_by_addr(ab, peer_addr);
-
 	if (!peer) {
 		ath11k_warn(ab, "peer not found %pM\n",
 			   peer_addr);
@@ -10074,11 +10097,9 @@
 	}
 
 	ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
-
 	if (!ar) {
 		ath11k_warn(ab, "invalid vdev id in peer sta ps state change ev %d",
 			    peer->vdev_id);
-
 		spin_unlock_bh(&ab->base_lock);
 		goto exit;
 	}
@@ -10223,6 +10244,130 @@
 	}
 }
 
+static int ath11k_wmi_tbtt_offset_subtlv_parser(struct ath11k_base *ab, u16 tag,
+						u16 len, const void *ptr,
+						void *data)
+{
+	int ret = 0;
+	struct ath11k *ar;
+	u64 tx_delay = 0;
+	struct wmi_tbtt_offset_info *tbtt_offset_info;
+	struct ieee80211_chanctx_conf *conf;
+	struct ath11k_vif *arvif;
+
+	tbtt_offset_info = (struct wmi_tbtt_offset_info *)ptr;
+
+	rcu_read_lock();
+	ar = ath11k_mac_get_ar_by_vdev_id(ab, tbtt_offset_info->vdev_id);
+	if (!ar) {
+		ath11k_warn(ab, "ar not found, vdev_id %d\n", tbtt_offset_info->vdev_id);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	arvif = ath11k_mac_get_arvif(ar, tbtt_offset_info->vdev_id);
+	if (!arvif) {
+		ath11k_warn(ab, "arvif not found, vdev_id %d\n",
+			    tbtt_offset_info->vdev_id);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+		ret = 0;
+		goto exit;
+	}
+
+	arvif->tbtt_offset = tbtt_offset_info->tbtt_offset;
+
+	conf = rcu_dereference(arvif->vif->chanctx_conf);
+	if (conf && conf->def.chan->band == NL80211_BAND_2GHZ) {
+		/* 1Mbps Beacon: */
+		/* 144 us ( LPREAMBLE) + 48 (PLCP Header)
+		 * + 192 (1Mbps, 24 ytes)
+		 * = 384 us + 2us(MAC/BB DELAY
+		 */
+		tx_delay = 386;
+	} else if (conf && (conf->def.chan->band == NL80211_BAND_5GHZ ||
+			    conf->def.chan->band == NL80211_BAND_6GHZ)) {
+		/* 6Mbps Beacon: */
+		/*20(lsig)+2(service)+32(6mbps, 24 bytes)
+		 *= 54us + 2us(MAC/BB DELAY)
+		 */
+		tx_delay = 56;
+	}
+	arvif->tbtt_offset -= tx_delay;
+
+	ieee80211_queue_work(ar->hw, &arvif->update_bcn_template_work);
+exit:
+	rcu_read_unlock();
+	return ret;
+}
+
+static int ath11k_wmi_tbtt_offset_event_parser(struct ath11k_base *ab,
+					       u16 tag, u16 len,
+					       const void *ptr, void *data)
+{
+	int ret = 0;
+
+	ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi tbtt offset event tag 0x%x of len %d rcvd\n",
+		   tag, len);
+
+	switch (tag) {
+	case WMI_TAG_TBTT_OFFSET_EXT_EVENT:
+		break;
+	case WMI_TAG_ARRAY_STRUCT:
+		ret = ath11k_wmi_tlv_iter(ab, ptr, len,
+					  ath11k_wmi_tbtt_offset_subtlv_parser,
+					  data);
+		break;
+	default:
+		ath11k_warn(ab, "Received invalid tag for wmi tbtt offset event\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int ath11k_wmi_pull_tbtt_offset(struct ath11k_base *ab, struct sk_buff *skb,
+				       struct wmi_tbtt_offset_ev_arg *arg)
+{
+	struct wmi_tbtt_offset_event *ev = NULL;
+	struct wmi_tbtt_offset_info tbtt_offset_info = {0};
+	struct wmi_tlv *tlv;
+	int ret;
+	u8 *ptr;
+	u16 tlv_tag;
+
+	ptr = skb->data;
+
+	if (skb->len < (sizeof(*ev) + TLV_HDR_SIZE)) {
+		ath11k_warn(ab, "wmi_tbtt_offset event size invalid\n");
+		return -EINVAL;
+	}
+
+	tlv = (struct wmi_tlv *)ptr;
+	tlv_tag = FIELD_GET(WMI_TLV_TAG, tlv->header);
+	ptr += sizeof(*tlv);
+
+	if (tlv_tag == WMI_TAG_TBTT_OFFSET_EXT_EVENT) {
+		ev = (struct wmi_tbtt_offset_event *)ptr;
+	} else {
+		ath11k_warn(ab, "tbtt event received with invalid tag\n");
+		return -EINVAL;
+	}
+
+	ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
+				  ath11k_wmi_tbtt_offset_event_parser,
+				  &tbtt_offset_info);
+	if (ret) {
+		ath11k_warn(ab, "failed to parse tbtt tlv %d\n", ret);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int ath11k_wmi_tlv_cfr_capture_evt_parse(struct ath11k_base *ab,
 						u16 tag, u16 len,
 						const void *ptr, void *data)
@@ -10267,6 +10412,16 @@
 			   "failed to process cfr cpature ret = %d\n", ret);
 }
 
+void ath11k_wmi_event_tbttoffset_update(struct ath11k_base *ab, struct sk_buff *skb)
+{
+	struct wmi_tbtt_offset_ev_arg arg = {};
+	int ret;
+
+	ret = ath11k_wmi_pull_tbtt_offset(ab, skb, &arg);
+	if (ret)
+		ath11k_warn(ab, "failed to parse tbtt offset event: %d\n", ret);
+}
+
 static int ath11k_wmi_peer_ratecode_subtlv_parser(struct ath11k_base *ab,
 						  u16 tag, u16 len,
 						  const void *ptr, void *data)
@@ -10795,6 +10950,87 @@
 	return ret;
 }
 
+int ath11k_wmi_pdev_get_ani_status(struct ath11k *ar)
+{
+	struct ath11k_pdev_wmi *wmi = ar->wmi;
+	struct wmi_pdev_get_ani_status_cmd *cmd = NULL;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_get_ani_status_cmd *)skb->data;
+	cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+				     WMI_TAG_PDEV_GET_CAL_STATUS_CONFIG_CMD) |
+			  FIELD_PREP(WMI_TLV_LEN,
+				     sizeof(*cmd) - TLV_HDR_SIZE);
+	cmd->pdev_id = ar->pdev->pdev_id;
+
+	ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_GET_CAL_STATUS_CMDID);
+	if (ret) {
+		ath11k_warn(ar->ab, "failed to send get cal status cmd\n");
+		dev_kfree_skb(skb);
+		return ret;
+	}
+
+	ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+		   "wmi cal status cmd pdev id %d\n",
+		   ar->pdev->pdev_id);
+
+	return 0;
+}
+
+static int ath11k_wmi_event_get_ani_status(struct ath11k_base *ab,
+					   struct sk_buff *skb)
+{
+	const void **tb;
+	const struct wmi_pdev_cal_status_event *ev;
+	struct ath11k *ar;
+	int ret;
+
+
+	if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
+		return 0;
+
+	tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath11k_warn(ab, "failed to parse tlv of ani status event: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TAG_PDEV_CAL_STATUS_EVENT];
+
+	if (!ev) {
+		ath11k_warn(ab, "failed to fetch ani status ev");
+		kfree(tb);
+		return -EINVAL;
+	}
+
+	if (ATH11K_TEST_CAL_STATUS(ev->cal_valid_bitmap, WMI_CAL_ANI)) {
+		rcu_read_lock();
+		ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id);
+		if (!ar) {
+			ath11k_warn(ab, "ani enabled event in invalid pdev %d\n",
+				    ev->pdev_id);
+			rcu_read_unlock();
+			return -EINVAL;
+		}
+		spin_lock_bh(&ar->data_lock);
+		ar->ani_enabled = ATH11K_TEST_CAL_STATUS(ev->cal_status_bitmap, WMI_CAL_ANI);
+		spin_unlock_bh(&ar->data_lock);
+		if (!completion_done(&ar->ani_status_event))
+			complete(&ar->ani_status_event);
+		ath11k_dbg(ab, ATH11K_DBG_WMI,
+			   "pdev id %d ani status %d\n",
+			   ev->pdev_id, ar->ani_enabled);
+		rcu_read_unlock();
+	}
+	return 0;
+}
+
 static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
@@ -10907,8 +11143,10 @@
 	case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID:
 		ath11k_wmi_obss_color_collision_event(ab, skb);
 		break;
-	/* add Unsupported events here */
 	case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
+		ath11k_wmi_event_tbttoffset_update(ab, skb);
+		break;
+	/* add Unsupported events here */
 	case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
 	case WMI_TWT_ENABLE_EVENTID:
 	case WMI_TWT_DISABLE_EVENTID:
@@ -10959,6 +11197,9 @@
 	case WMI_PDEV_ANI_OFDM_LEVEL_EVENTID:
 		ath11k_wmi_event_ani_ofdm_level(ab, skb);
 		break;
+	case WMI_PDEV_GET_CAL_STATUS_EVENTID:
+		ath11k_wmi_event_get_ani_status(ab, skb);
+		break;
 	case WMI_PEER_RATECODE_LIST_EVENTID:
 		ath11k_wmi_event_peer_ratecode_list(ab, skb);
 		break;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 9704dba..a3ade7c 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -301,6 +301,11 @@
 	WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
 	WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
 	WMI_PDEV_GET_TPC_STATS_CMDID,
+	WMI_PDEV_ENABLE_DURATION_BASED_TX_MODE_SELECTION_CMDID,
+	WMI_PDEV_GET_DPD_STATUS_CMDID,
+	WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID,
+	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID,
+	WMI_PDEV_GET_CAL_STATUS_CMDID,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
 	WMI_VDEV_START_REQUEST_CMDID,
@@ -690,6 +695,8 @@
 	WMI_SERVICE_READY_EXT2_EVENTID,
 	WMI_PDEV_MULTIPLE_VDEV_RESTART_RESP_EVENTID,
 	WMI_PDEV_GET_TPC_STATS_EVENTID,
+	WMI_PDEV_GET_DPD_STATUS_EVENTID,
+	WMI_PDEV_GET_CAL_STATUS_EVENTID,
 	WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_STOPPED_EVENTID,
 	WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
@@ -1973,6 +1980,9 @@
 	WMI_TAG_AFC_6G_CHANNEL_INFO,
 	WMI_TAG_AFC_CHAN_EIRP_POWER_INFO,
 
+	WMI_TAG_PDEV_GET_CAL_STATUS_CONFIG_CMD = 0x3DA,
+	WMI_TAG_PDEV_CAL_STATUS_EVENT,
+
 	WMI_TAG_MAX
 };
 
@@ -2844,6 +2854,31 @@
 	u32 start_time;
 };
 
+enum wmi_cal_list {
+	WMI_CAL_ADC,
+	WMI_CAL_BWFILTER,
+	WMI_CAL_PDET_AND_PAL,
+	WMI_CAL_RXDCO,
+	WMI_CAL_COMB_TXLO_TXIQ_RXIQ,
+	WMI_CAL_IBF,
+	WMI_CAL_PA_DROOP,
+	WMI_CAL_DAC,
+	WMI_CAL_ANI,
+	WMI_CAL_NOISE_FLOOR,
+	WMI_CAL_MAX_CAL_LIST
+};
+
+struct wmi_pdev_cal_status_event {
+	u32  pdev_id;
+	u32  cal_valid_bitmap;
+	u32  cal_status_bitmap;
+} __packed;
+
+struct wmi_pdev_get_ani_status_cmd {
+	u32 tlv_header;
+	u32 pdev_id;
+} __packed;
+
 struct wmi_pdev_ani_event {
 	u32 tlv_header;
 	u32 ani_level;
@@ -4633,6 +4668,24 @@
 	u32 vdev_id;
 } __packed;
 
+struct wmi_tbtt_offset_info {
+	u32 vdev_id;
+	u32 tbtt_offset;
+	u32 tbtt_qtime_low_us;
+	u32 tbtt_qtime_high_us;
+} __packed;
+
+struct wmi_tbtt_offset_event {
+	u32 num_vdevs;
+} __packed;
+
+struct wmi_tbtt_offset_ev_arg {
+	u32 vdev_id;
+	u32 tbtt_offset;
+	u32 tbtt_qtime_low_us;
+	u32 tbtt_qtime_high_us;
+} __packed;
+
 #define WMI_REG_CLIENT_MAX 4
 
 struct wmi_reg_chan_list_cc_ext_event {
@@ -7209,5 +7262,5 @@
 				       u32 vdev_id,
 				       struct ath11k_reg_tpc_power_info *param);
 int ath11k_wmi_send_afc_resp_rx_ind(struct ath11k *ar, int data_type);
-
+int ath11k_wmi_pdev_get_ani_status(struct ath11k *ar);
 #endif
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c
index f3906db..9ed2559 100644
--- a/drivers/net/wireless/ath/ath6kl/testmode.c
+++ b/drivers/net/wireless/ath/ath6kl/testmode.c
@@ -58,7 +58,7 @@
 	if (nla_put_u32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD) ||
 	    nla_put(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf))
 		goto nla_put_failure;
-	cfg80211_testmode_event(skb, GFP_KERNEL);
+	cfg80211_testmode_event(skb, GFP_KERNEL, false);
 	return;
 
 nla_put_failure:
diff --git a/drivers/soc/qcom/bt_ipc.c b/drivers/soc/qcom/bt_ipc.c
index 57927fc..7e2dd76 100644
--- a/drivers/soc/qcom/bt_ipc.c
+++ b/drivers/soc/qcom/bt_ipc.c
@@ -476,14 +476,6 @@
 
 static uint32_t RX_CTXT_OFFSET = 0xe000;
 
-static bool is_rx_ctxt_valid(struct context_info * rx_ctxt)
-{
-	uint8_t ridx = rx_ctxt->sring_buf_info.ridx;
-	uint32_t rbuf = rx_ctxt->sring_buf_info.rbuf;
-	return (ridx == 0 &&
-		rbuf == (RX_CTXT_OFFSET + sizeof(*rx_ctxt)));
-}
-
 static void bt_ipc_worker(struct work_struct *work)
 {
 	struct ring_buffer_info *rinfo;
@@ -503,14 +495,6 @@
 	if (unlikely(!atomic_read(&btDesc->state))) {
 		btmem->rx_ctxt =
 			(struct context_info *)(btmem->virt + RX_CTXT_OFFSET);
-		if (!is_rx_ctxt_valid(btmem->rx_ctxt)) {
-			// rx_ctrx not valid
-			// BTSS not ready
-			// skip this irq
-			spin_unlock(&btDesc->lock);
-			enable_irq(ipc->irq);
-			return;
-		}
         }
 	else
 		bt_ipc_process_ack(btDesc);
@@ -573,6 +557,9 @@
 
 	INIT_WORK(&ipc->work, bt_ipc_worker);
 
+	irq_set_irqchip_state(ipc->irq, IRQCHIP_STATE_PENDING, 0);
+	irq_set_status_flags(ipc->irq, IRQ_NOAUTOEN);
+
 	ret = devm_request_threaded_irq(dev, ipc->irq, NULL, bt_ipc_irq_handler,
                                           IRQF_TRIGGER_RISING | IRQF_ONESHOT, "bt_ipc_irq", btDesc);
 
diff --git a/drivers/soc/qcom/bt_tty.c b/drivers/soc/qcom/bt_tty.c
index 78c8a4c..6eca6a3 100644
--- a/drivers/soc/qcom/bt_tty.c
+++ b/drivers/soc/qcom/bt_tty.c
@@ -35,6 +35,9 @@
 static bool btss_debug;
 module_param(btss_debug, bool, 0644);
 
+static unsigned short btss_boot_delay = 500;
+module_param(btss_boot_delay, ushort, 0644);
+
 unsigned int pid_distinct(struct bt_descriptor *btDesc, enum pid_ops action)
 {
 	int ret;
@@ -77,6 +80,11 @@
 	pid_cursor->pid = pid;
 	atomic_inc(&pid_cursor->refcnt);
 	list_add_tail(&pid_cursor->list, pid_q);
+
+	if (!atomic_read(&btDesc->state)) {
+		mdelay(btss_boot_delay);
+		enable_irq(btDesc->ipc.irq);
+	}
 out:
 	return pid_cursor ? atomic_read(&pid_cursor->refcnt) : 0;
 }
@@ -191,36 +199,6 @@
 }
 
 static
-int bt_rproc_fully_boot(struct bt_descriptor *btDesc, struct rproc *rproc)
-{
-	int retries = 3;
-	struct device *dev = &btDesc->pdev->dev;
-	while (retries) {
-		unsigned int wait_ms = 200;
-		const unsigned int interval_ms = wait_ms / 10;
-		int ret = rproc_boot(rproc);
-		if (ret)
-			return ret;
-		do {
-			if (atomic_read(&btDesc->state))
-				return ret;
-			wait_ms -= interval_ms;
-			msleep(interval_ms);
-		} while(wait_ms >= interval_ms);
-
-		if (!atomic_read(&btDesc->state)) {
-			rproc_shutdown(rproc);
-			--retries;
-			if (retries)
-				dev_warn(dev, "bt ipc doesn't start, retry\n");
-		}
-		else
-			return ret;
-	}
-	return -ETIMEDOUT;
-}
-
-static
 int bt_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 {
 	int ret = 0;
@@ -233,7 +211,7 @@
 	switch (cmd) {
 	case IOCTL_IPC_BOOT:
 		if (arg) {
-			ret = bt_rproc_fully_boot(btDesc, rproc);
+			ret = rproc_boot(rproc);
 			if (ret)
 				dev_err(dev, "m0 boot fail, ret = %d\n", ret);
 			else
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index ed46fd7..c7a8c43 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1928,6 +1928,9 @@
 				if (w_index != 0x5 || (w_value >> 8))
 					break;
 				interface = w_value & 0xFF;
+				if (interface >= MAX_CONFIG_INTERFACES ||
+				    !os_desc_cfg->interface[interface])
+					break;
 				buf[6] = w_index;
 				count = count_ext_prop(os_desc_cfg,
 					interface);
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 04c142c..ab827c1 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -637,14 +637,17 @@
 	rndis_set_cmplt_type *resp;
 	rndis_resp_t *r;
 
+	BufLength = le32_to_cpu(buf->InformationBufferLength);
+	BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+	if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
+	    (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
+		    return -EINVAL;
+
 	r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
 	if (!r)
 		return -ENOMEM;
 	resp = (rndis_set_cmplt_type *)r->buf;
 
-	BufLength = le32_to_cpu(buf->InformationBufferLength);
-	BufOffset = le32_to_cpu(buf->InformationBufferOffset);
-
 #ifdef	VERBOSE_DEBUG
 	pr_debug("%s: Length: %d\n", __func__, BufLength);
 	pr_debug("%s: Offset: %d\n", __func__, BufOffset);
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index cabcbb4..3521d04 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1815,8 +1815,9 @@
 	spin_lock_irq (&dev->lock);
 	value = -EINVAL;
 	if (dev->buf) {
+		spin_unlock_irq(&dev->lock);
 		kfree(kbuf);
-		goto fail;
+		return value;
 	}
 	dev->buf = kbuf;
 
@@ -1863,8 +1864,8 @@
 
 	value = usb_gadget_probe_driver(&gadgetfs_driver);
 	if (value != 0) {
-		kfree (dev->buf);
-		dev->buf = NULL;
+		spin_lock_irq(&dev->lock);
+		goto fail;
 	} else {
 		/* at this point "good" hardware has for the first time
 		 * let the USB the host see us.  alternatively, if users
@@ -1881,6 +1882,9 @@
 	return value;
 
 fail:
+	dev->config = NULL;
+	dev->hs_config = NULL;
+	dev->dev = NULL;
 	spin_unlock_irq (&dev->lock);
 	pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev);
 	kfree (dev->buf);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index c7044a1..854e68d 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -829,6 +829,11 @@
 	return hdev->ll_driver == driver;
 }
 
+static inline bool hid_is_usb(struct hid_device *hdev)
+{
+	return hid_is_using_ll_driver(hdev, &usb_hid_driver);
+}
+
 #define	PM_HINT_FULLON	1<<5
 #define PM_HINT_NORMAL	1<<1
 
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 9535b62..39a1ed5 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -58,6 +58,7 @@
 					  struct sk_buff *skb,
 					  unsigned int cookie);
 extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr);
+extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid);
 extern void br_dev_update_stats(struct net_device *dev,
 				struct rtnl_link_stats64 *nlstats);
 extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2f3f85f..723d002 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1342,6 +1342,11 @@
 	u8 color;
 };
 
+struct cfg80211_6ghz_power_mode_settings {
+       u8 he_6ghz_pwr_mode;
+       struct cfg80211_beacon_data beacon_next;
+};
+
 #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
 #define CFG80211_MAX_NUM_DIFFERENT_BI		16
 
@@ -4096,6 +4101,7 @@
  * @set_unsol_bcast_probe_resp: Set unsolicited broadcast probe response
  * 	transmission parameters.
  * @color_change: initiate a color change (with color change).
+ * @power_mode_change_6ghz: initiate power mode change for 6 GHZ.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4432,6 +4438,8 @@
 	int     (*color_change)(struct wiphy *wiphy,
 				struct net_device *dev,
 				struct cfg80211_color_change_settings *params);
+	int (*power_mode_change_6ghz)(struct wiphy *wiphy, struct net_device *dev,
+				    struct cfg80211_6ghz_power_mode_settings *params);
 };
 
 /*
@@ -6828,7 +6836,7 @@
 					   int vendor_event_idx,
 					   int approxlen, gfp_t gfp);
 
-void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp);
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp, bool testlogs);
 
 /**
  * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
@@ -6958,7 +6966,7 @@
  */
 static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp)
 {
-	__cfg80211_send_event_skb(skb, gfp);
+	__cfg80211_send_event_skb(skb, gfp, false);
 }
 
 #ifdef CONFIG_NL80211_TESTMODE
@@ -7059,9 +7067,10 @@
  * by cfg80211_testmode_alloc_event_skb(), as an event. It always
  * consumes it.
  */
-static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp,
+					   bool testlogs)
 {
-	__cfg80211_send_event_skb(skb, gfp);
+	__cfg80211_send_event_skb(skb, gfp, testlogs);
 }
 
 #define CFG80211_TESTMODE_CMD(cmd)	.testmode_cmd = (cmd),
@@ -7825,6 +7834,14 @@
 				       struct cfg80211_chan_def *chandef,
 				       u8 count, bool quiet);
 
+/*cfg80211_6ghz_power_mode_notify - Notify new HE 6GHZ power mode
+ * @dev: the device on which power mode change is done
+ * @gfp: allocation flags
+ * @cmd: the actual event to be notified
+ */
+void cfg80211_6ghz_power_mode_notify(struct net_device *dev,
+                                     gfp_t gfp, enum nl80211_commands cmd);
+
 /**
  * ieee80211_operating_class_to_band - convert operating class to band
  *
@@ -8433,4 +8450,14 @@
 				  0, 0);
 }
 
+/*cfg80211_6ghz_power_mode_change_notify -notify 6GHZ power mode change
+ * @dev: the device on which the power mode change is done
+ *
+ * Inform the userspace about the successful change in 6GHZ power mode
+ */
+static inline void cfg80211_6ghz_power_mode_change_notify(struct net_device *dev)
+{
+	cfg80211_6ghz_power_mode_notify(dev, GFP_KERNEL,
+					NL80211_CMD_POWER_MODE_CHANGE_COMPLETED);
+}
 #endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 96b25c1..6136b3f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -360,7 +360,8 @@
 	BSS_CHANGED_HE_OBSS_PD		= 1<<28,
 	BSS_CHANGED_HE_BSS_COLOR	= 1<<29,
 	BSS_CHANGED_FILS_DISCOVERY      = 1<<30,
-	BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31,
+	BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1ULL<<31,
+	BSS_CHANGED_6G_POWER_MODE	= 1ULL<<32,
 
 	/* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -1829,6 +1830,7 @@
 	bool color_change_active;
 	u8 color_change_color;
 	u8 bmiss_threshold;
+	bool noqueue_enable;
 
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
@@ -4067,10 +4069,10 @@
 	void (*bss_info_changed)(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *info,
-				 u32 changed);
+				 u64 changed);
 	void (*nss_bss_info_changed)(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif,
-				 u32 changed);
+				 u64 changed);
 
 	int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 	void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
@@ -5257,6 +5259,16 @@
 void ieee80211_csa_finish(struct ieee80211_vif *vif);
 
 /**
+ * ieee80211_6ghz_power_mode_switch_done - notify mac80211 about power mode
+ * change.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * After power change for 6 GHZ interface successful, this function must
+ * be called by the driver to notify mac80211 about power mode change.
+ */
+void ieee80211_6ghz_power_mode_switch_done (struct ieee80211_vif *vif);
+
+/**
  * ieee80211_beacon_cntdwn_is_complete - find out if countdown reached 1
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index ddbf9e7..12266ef 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -176,6 +176,7 @@
 	REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
 	REGULATORY_IGNORE_STALE_KICKOFF         = BIT(6),
 	REGULATORY_WIPHY_SELF_MANAGED		= BIT(7),
+	REGULATORY_SET_BY_6GHZ_AFC		= BIT(8),
 };
 
 struct ieee80211_freq_range {
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index e8ccb6f..06f1dfc 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -51,6 +51,7 @@
 #define NL80211_MULTICAST_GROUP_VENDOR		"vendor"
 #define NL80211_MULTICAST_GROUP_NAN		"nan"
 #define NL80211_MULTICAST_GROUP_TESTMODE	"testmode"
+#define NL80211_MULTICAST_GROUP_TESTLOGS	"testlogs"
 
 #define NL80211_EDMG_BW_CONFIG_MIN	4
 #define NL80211_EDMG_BW_CONFIG_MAX	15
@@ -1213,7 +1214,11 @@
  * @NL80211_CMD_AWGN_DETECT: Once AWGN interference is detected on the operating
  *	channel, userspace is notified with the interference bitmap using
  *	%NL80211_ATTR_AWGN_INTERFERENCE_BITMAP
-
+ * @NL80211_CMD_SET_6GHZ_POWER_MODE: User can set HE 6 GHZ power mode using userspace
+ * 	application controlling AP cli(i.e hostapd_cli).This command is used to set this
+ * 	power mode to the driver.
+ * @NL80211_CMD_POWER_MODE_CHANGE_COMPLETED: Notify the successful 6GHZ power mode change
+ * 	to userspace to update its power mode
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1459,6 +1464,9 @@
 	NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_COMPLETED,
 
 	NL80211_CMD_AWGN_DETECT,
+	NL80211_CMD_SET_6GHZ_POWER_MODE,
+	NL80211_CMD_POWER_MODE_CHANGE_COMPLETED,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -4033,6 +4041,7 @@
 	NL80211_REGDOM_SET_BY_USER,
 	NL80211_REGDOM_SET_BY_DRIVER,
 	NL80211_REGDOM_SET_BY_COUNTRY_IE,
+	NL80211_REGDOM_SET_BY_AFC,
 };
 
 /**
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 79682c2..4c7f75f 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -914,6 +914,8 @@
 	opt = fs_parse(fc, &cgroup1_fs_parameters, param, &result);
 	if (opt == -ENOPARAM) {
 		if (strcmp(param->key, "source") == 0) {
+			if (param->type != fs_value_is_string)
+				return invalf(fc, "Non-string source");
 			if (fc->source)
 				return invalf(fc, "Multiple sources not supported");
 			fc->source = param->string;
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 639d5e7..332cc2b 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -398,6 +398,7 @@
 		return 0;
 	pipe->nrbufs++;
 	buf->ops = &page_cache_pipe_buf_ops;
+	buf->flags = 0;
 	get_page(buf->page = page);
 	buf->offset = offset;
 	buf->len = bytes;
@@ -523,6 +524,7 @@
 		if (!page)
 			break;
 		pipe->nrbufs++;
+		pipe->bufs[idx].flags = 0;
 		pipe->bufs[idx].ops = &default_pipe_buf_ops;
 		pipe->bufs[idx].page = page;
 		pipe->bufs[idx].offset = 0;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 353690b..a9d1a05 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -686,6 +686,24 @@
 }
 EXPORT_SYMBOL_GPL(br_refresh_fdb_entry);
 
+/* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */
+void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid)
+{
+	struct net_bridge_fdb_entry *fdb;
+	struct net_bridge_port *p = br_port_get_rcu(dev);
+
+	if (!p || p->state == BR_STATE_DISABLED)
+		return;
+
+	rcu_read_lock();
+	fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid);
+	if (likely(fdb)) {
+		fdb->updated = jiffies;
+	}
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(br_fdb_entry_refresh);
+
 /* Look up the MAC address in the device's bridge fdb table */
 struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
 					      const char *addr, __u16 vid)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index c2ee61b..eb90194 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -842,14 +842,16 @@
 		return;
 
 	br = netdev_priv(dev);
-	stats = per_cpu_ptr(br->stats, 0);
+	stats = this_cpu_ptr(br->stats);
 
+	local_bh_disable();
 	u64_stats_update_begin(&stats->syncp);
 	stats->rx_packets += nlstats->rx_packets;
 	stats->rx_bytes += nlstats->rx_bytes;
 	stats->tx_packets += nlstats->tx_packets;
 	stats->tx_bytes += nlstats->tx_bytes;
 	u64_stats_update_end(&stats->syncp);
+	local_bh_enable();
 }
 EXPORT_SYMBOL_GPL(br_dev_update_stats);
 
diff --git a/net/core/skbuff_recycle.h b/net/core/skbuff_recycle.h
index ab14aec..c93c87c 100644
--- a/net/core/skbuff_recycle.h
+++ b/net/core/skbuff_recycle.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 2022, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -43,7 +43,7 @@
 #define SKB_RECYCLE_SIZE	2304
 #define SKB_RECYCLE_MIN_SIZE	SKB_RECYCLE_SIZE
 #define SKB_RECYCLE_MAX_SIZE	(3904 - NET_SKB_PAD)
-#define SKB_RECYCLE_MAX_SKBS	1024
+#define SKB_RECYCLE_MAX_SKBS	8192
 
 #define SKB_RECYCLE_SPARE_MAX_SKBS		256
 
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 480d0b2..8b72b31 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -2722,6 +2722,7 @@
 		rv = 1;
 	} else if (im) {
 		if (src_addr) {
+			spin_lock_bh(&im->lock);
 			for (psf = im->sources; psf; psf = psf->sf_next) {
 				if (psf->sf_inaddr == src_addr)
 					break;
@@ -2732,6 +2733,7 @@
 					im->sfcount[MCAST_EXCLUDE];
 			else
 				rv = im->sfcount[MCAST_EXCLUDE] != 0;
+			spin_unlock_bh(&im->lock);
 		} else
 			rv = 1; /* unspecified source; tentatively allow */
 	}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 07504da..7611a1a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -927,19 +927,26 @@
 	struct ieee80211_fils_discovery *fd;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (!params->tmpl || !params->tmpl_len)
-		return -EINVAL;
-
 	fd = &sdata->vif.bss_conf.fils_discovery;
 	fd->min_interval = params->min_interval;
 	fd->max_interval = params->max_interval;
 
 	old = sdata_dereference(sdata->u.ap.fils_discovery, sdata);
+
+	if (!fd->max_interval) {
+		new = NULL;
+		goto free_old_fils;
+	}
+
+	if (!params->tmpl || !params->tmpl_len)
+                return -EINVAL;
+
 	new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
 	if (!new)
 		return -ENOMEM;
 	new->len = params->tmpl_len;
 	memcpy(new->data, params->tmpl, params->tmpl_len);
+free_old_fils:
 	rcu_assign_pointer(sdata->u.ap.fils_discovery, new);
 
 	if (old)
@@ -957,17 +964,24 @@
 	struct unsol_bcast_probe_resp_data *new, *old = NULL;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (!params->tmpl || !params->tmpl_len)
-		return -EINVAL;
-
 	sdata->vif.bss_conf.unsol_bcast_probe_resp_interval = params->interval;
 
 	old = sdata_dereference(sdata->u.ap.unsol_bcast_probe_resp, sdata);
+
+	if (!params->interval) {
+		 new = NULL;
+		 goto free_old_ubpr;
+	}
+
+	if (!params->tmpl || !params->tmpl_len)
+                return -EINVAL;
+
 	new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
 	if (!new)
 		return -ENOMEM;
 	new->len = params->tmpl_len;
 	memcpy(new->data, params->tmpl, params->tmpl_len);
+free_old_ubpr:
 	rcu_assign_pointer(sdata->u.ap.unsol_bcast_probe_resp, new);
 
 	if (old)
@@ -2923,18 +2937,18 @@
 
 static int ieee80211_get_tx_power(struct wiphy *wiphy,
 				  struct wireless_dev *wdev,
-				  int *dbm)
+				  int *mbm)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
 	if (local->ops->get_txpower)
-		return drv_get_txpower(local, sdata, dbm);
+		return drv_get_txpower(local, sdata, mbm);
 
 	if (!local->use_chanctx)
-		*dbm = local->hw.conf.power_level;
+		*mbm = DBM_TO_MBM(local->hw.conf.power_level);
 	else
-		*dbm = sdata->vif.bss_conf.txpower;
+		*mbm = DBM_TO_MBM(sdata->vif.bss_conf.txpower);
 
 	return 0;
 }
@@ -3451,6 +3465,39 @@
 	}
 }
 
+void ieee80211_power_mode_switch_work(struct work_struct *work)
+{
+	int ret;
+	u32 changed = 0;
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data,
+			     power_mode_switch_work);
+	struct ieee80211_local *local = sdata->local;
+
+	sdata_lock(sdata);
+	mutex_lock(&local->mtx);
+
+	if (sdata->vif.csa_active || !sdata->u.ap.next_beacon)
+		goto unlock;
+
+	ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
+				      NULL, NULL);
+	kfree(sdata->u.ap.next_beacon);
+	sdata->u.ap.next_beacon = NULL;
+
+        if (ret < 0) {
+                 goto unlock;
+	}
+        changed = ret;
+
+	ieee80211_bss_info_change_notify(sdata, changed);
+	cfg80211_6ghz_power_mode_change_notify(sdata->dev);
+
+unlock:
+	mutex_unlock(&local->mtx);
+	sdata_unlock(sdata);
+}
+
 void ieee80211_csa_finalize_work(struct work_struct *work)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -4343,6 +4390,62 @@
 	return local->ops->set_sar_specs(&local->hw, sar);
 }
 
+void ieee80211_6ghz_power_mode_switch_done(struct ieee80211_vif *vif)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+	ieee80211_queue_work(&sdata->local->hw, &sdata->power_mode_switch_work);
+}
+EXPORT_SYMBOL(ieee80211_6ghz_power_mode_switch_done);
+
+static int ieee80211_set_power_mode_changed_beacon(struct ieee80211_sub_if_data *sdata,
+						   struct cfg80211_6ghz_power_mode_settings *params)
+{
+
+	if (sdata->vif.type != NL80211_IFTYPE_AP)
+		return -EOPNOTSUPP;
+
+	sdata->u.ap.next_beacon =
+		cfg80211_beacon_dup(&params->beacon_next);
+
+	if (!sdata->u.ap.next_beacon)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int
+ieee80211_6ghz_power_mode_change(struct wiphy *wiphy, struct net_device *dev,
+				 struct cfg80211_6ghz_power_mode_settings *params)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+	u64 changed = 0;
+
+	sdata_assert_lock(sdata);
+	mutex_lock(&local->mtx);
+
+	if (sdata->vif.csa_active) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	err = ieee80211_set_power_mode_changed_beacon(sdata, params);
+	if (err)
+		goto out;
+
+	wdev->reg_6g_power_mode = params->he_6ghz_pwr_mode;
+
+	changed = BSS_CHANGED_6G_POWER_MODE;
+	ieee80211_bss_info_change_notify(sdata, changed);
+out:
+	mutex_unlock(&local->mtx);
+
+	return err;
+}
+
 static int ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata,
 						   u32 *changed)
 {
@@ -4661,4 +4764,5 @@
 	.set_fils_discovery = ieee80211_set_fils_discovery,
 	.set_unsol_bcast_probe_resp = ieee80211_set_unsol_bcast_probe_resp,
 	.color_change = ieee80211_color_change,
+	.power_mode_change_6ghz = ieee80211_6ghz_power_mode_change,
 };
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 491661a..01b1851 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -329,6 +329,32 @@
 
 IEEE80211_IF_FILE_RW(bmiss_threshold);
 
+static ssize_t ieee80211_if_fmt_noqueue_enable(const struct ieee80211_sub_if_data *sdata,
+					       char *buf, int buflen)
+{
+	return snprintf(buf, buflen, "%u\n", sdata->vif.noqueue_enable);
+}
+
+static ssize_t ieee80211_if_parse_noqueue_enable(struct ieee80211_sub_if_data *sdata,
+						 const char *buf, int buflen)
+{
+	int ret;
+	u8 val;
+
+	ret = kstrtou8(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	sdata->vif.noqueue_enable = val;
+
+	return buflen;
+}
+
+IEEE80211_IF_FILE_RW(noqueue_enable);
+
 static ssize_t
 ieee80211_if_parse_wmm_param(struct ieee80211_sub_if_data *sdata,
 			     const char *user_buf, int count)
@@ -839,6 +865,7 @@
 	DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
 	DEBUGFS_ADD_MODE(bmiss_threshold, 0600);
 	DEBUGFS_ADD_MODE(wmm_param, 0200);
+	DEBUGFS_ADD_MODE(noqueue_enable, 0600);
 }
 
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
@@ -861,6 +888,7 @@
 	DEBUGFS_ADD_MODE(estab_plinks, 0400);
 	DEBUGFS_ADD_MODE(bmiss_threshold, 0600);
 	DEBUGFS_ADD_MODE(wmm_param, 0200);
+	DEBUGFS_ADD_MODE(noqueue_enable, 0600);
 }
 
 static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index c9cc451..1883e6c 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -68,6 +68,9 @@
 	if (ret == 0)
 		sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
 
+	if (sdata->vif.type == NL80211_IFTYPE_AP)
+		sdata->vif.noqueue_enable = true;
+
 	return ret;
 }
 
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 386059a..20f4e92 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -150,7 +150,7 @@
 static inline void drv_bss_info_changed(struct ieee80211_local *local,
 					struct ieee80211_sub_if_data *sdata,
 					struct ieee80211_bss_conf *info,
-					u32 changed)
+					u64 changed)
 {
 	might_sleep();
 
@@ -181,7 +181,7 @@
 static inline void drv_nss_bss_info_changed(struct ieee80211_local *local,
 					struct ieee80211_sub_if_data *sdata,
 					struct ieee80211_bss_conf *info,
-					u32 changed)
+					u64 changed)
 {
 	might_sleep();
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e4f3dcc..e9e6e16 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -247,6 +247,8 @@
 
 	u32 tkip_iv32;
 	u16 tkip_iv16;
+	u16 last_legacy_rate_idx;
+	enum nl80211_band last_legacy_band;
 };
 
 struct ieee80211_csa_settings {
@@ -952,6 +954,7 @@
 	struct cfg80211_chan_def csa_chandef;
 
 	struct work_struct color_change_finalize_work;
+	struct work_struct power_mode_switch_work;
 
 	struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
 	struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
@@ -1658,7 +1661,7 @@
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
-				      u32 changed);
+				      u64 changed);
 void ieee80211_nss_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 				      u32 changed);
 void ieee80211_configure_filter(struct ieee80211_local *local);
@@ -1787,6 +1790,7 @@
 
 /* channel switch handling */
 void ieee80211_csa_finalize_work(struct work_struct *work);
+void ieee80211_power_mode_switch_work(struct work_struct *work);
 int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 			     struct cfg80211_csa_settings *params);
 /* awgn interference handling */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ba47dd0..25701fa 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -490,6 +490,7 @@
 	}
 
 	cancel_work_sync(&sdata->color_change_finalize_work);
+	cancel_work_sync(&sdata->power_mode_switch_work);
 
 	/* APs need special treatment */
 	if (sdata->vif.type == NL80211_IFTYPE_AP) {
@@ -1623,6 +1624,7 @@
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 	INIT_WORK(&sdata->color_change_finalize_work, ieee80211_color_change_finalize_work);
+	INIT_WORK(&sdata->power_mode_switch_work,  ieee80211_power_mode_switch_work);
 	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
 	INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index e453a9b..224e801 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -200,7 +200,7 @@
 }
 
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
-				      u32 changed)
+				      u64 changed)
 {
 	struct ieee80211_local *local = sdata->local;
 
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index fc465bf..cd316b0 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -299,6 +299,7 @@
 {
 	struct ieee80211_tx_info *txinfo = st->info;
 	int failed = 0;
+	u32 fail_avg;
 	struct rate_info rinfo;
 
 	failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);
@@ -316,6 +317,11 @@
 		sta->mesh->fail_cnt = 0;
 	}
 
+	fail_avg = ewma_mesh_fail_avg_read(&sta->mesh->fail_avg);
+	if (!fail_avg)
+		/* init it at a low value - 0 is tricky */
+		ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1);
+
 	/* moving average, scaled to 100.
 	 * feed failure as 100 and success as 0
 	 */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index efc6cf6..b71c3ca 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3927,6 +3927,14 @@
 		status = IEEE80211_SKB_RXCB((rx->skb));
 
 		sband = rx->local->hw.wiphy->bands[status->band];
+		if (!status || !sband) {
+			printk(KERN_ERR "status %pM or sband %pM is Null rate_idx %u legacy_band %d\n",
+			       status, sband, rx->last_legacy_rate_idx, rx->last_legacy_band);
+			if (status) {
+				printk(KERN_ERR "STATUS idx %d\n", status->rate_idx);
+				printk(KERN_ERR "rate %pM\n", &sband->bitrates[status->rate_idx]);
+			}
+		}
 		if (status->encoding == RX_ENC_LEGACY)
 			rate = &sband->bitrates[status->rate_idx];
 
@@ -4576,6 +4584,16 @@
 			return;
 	}
 
+	/* Get the multicat broadcast stats */
+	ieee80211_mc_bc_stats(((struct ethhdr *)rx->skb->data)->h_dest, rx);
+
+	if (!ieee80211_mc_bc_rx_limit(((struct ethhdr *)rx->skb->data)->h_dest,
+				      rx)) {
+		/* free the omitted skb's before returning from here */
+		dev_kfree_skb(skb);
+		return;
+        }
+
 	/* deliver to local stack */
 	skb->protocol = eth_type_trans(skb, fast_rx->dev);
 	memset(skb->cb, 0, sizeof(skb->cb));
@@ -4585,7 +4603,6 @@
 		netif_receive_skb(skb);
 
 	atomic_inc(&sta->rx_netif_pkts);
-
 }
 
 static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
@@ -4760,54 +4777,7 @@
 	/* push the addresses in front */
 	memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
 
-	skb->dev = fast_rx->dev;
-
-	ieee80211_rx_stats(fast_rx->dev, skb->len);
-
-	/* The seqno index has the same property as needed
-	 * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
-	 * for non-QoS-data frames. Here we know it's a data
-	 * frame, so count MSDUs.
-	 */
-	u64_stats_update_begin(&stats->syncp);
-	stats->msdu[rx->seqno_idx]++;
-	stats->bytes += orig_len;
-	u64_stats_update_end(&stats->syncp);
-
-	if (fast_rx->internal_forward) {
-		struct sk_buff *xmit_skb = NULL;
-		if (is_multicast_ether_addr(addrs.da)) {
-			xmit_skb = skb_copy(skb, GFP_ATOMIC);
-		} else if (!ether_addr_equal(addrs.da, addrs.sa) &&
-			   sta_info_get(rx->sdata, addrs.da)) {
-			xmit_skb = skb;
-			skb = NULL;
-		}
-
-		if (xmit_skb) {
-			/*
-			 * Send to wireless media and increase priority by 256
-			 * to keep the received priority instead of
-			 * reclassifying the frame (see cfg80211_classify8021d).
-			 */
-			xmit_skb->priority += 256;
-			xmit_skb->protocol = htons(ETH_P_802_3);
-			skb_reset_network_header(xmit_skb);
-			skb_reset_mac_header(xmit_skb);
-			dev_queue_xmit(xmit_skb);
-		}
-
-		if (!skb)
-			return true;
-	}
-
-	/* deliver to local stack */
-	skb->protocol = eth_type_trans(skb, fast_rx->dev);
-	memset(skb->cb, 0, sizeof(skb->cb));
-	if (rx->list)
-		list_add_tail(&skb->list, rx->list);
-	else
-		netif_receive_skb(skb);
+	ieee80211_rx_8023(rx, fast_rx, orig_len);
 
 	return true;
  drop:
@@ -4915,6 +4885,7 @@
 					 struct list_head *list)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_hdr *hdr;
 	__le16 fc;
@@ -4929,6 +4900,14 @@
 	rx.local = local;
 	rx.list = list;
 
+	if (status && status->encoding == RX_ENC_LEGACY) {
+		rx.last_legacy_rate_idx = status->rate_idx;
+		rx.last_legacy_band = status->band;
+	}
+
+	if (!status)
+		pr_err("STATUS not found\n");
+
 	if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
 		I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
 
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 644a7de..517da04 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2138,7 +2138,7 @@
 }
 
 static struct ieee80211_sta_rx_stats *
-sta_get_last_rx_stats(struct sta_info *sta)
+sta_get_last_rx_stats(struct sta_info *sta, bool is_rx_bitrate)
 {
 	struct ieee80211_sta_rx_stats *stats = &sta->rx_stats;
 	struct ieee80211_local *local = sta->local;
@@ -2147,15 +2147,17 @@
 	if (ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD))
 		return stats;
 
- 	if (!ieee80211_hw_check(&local->hw, USES_RSS))
+	if (!ieee80211_hw_check(&local->hw, USES_RSS) || !sta->pcpu_rx_stats)
 		return stats;
 
 	for_each_possible_cpu(cpu) {
 		struct ieee80211_sta_rx_stats *cpustats;
+		u16 rate;
 
 		cpustats = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
+		rate = READ_ONCE(cpustats->last_rate);
 
-		if(!cpustats->last_rx)
+		if(!cpustats->last_rx || (is_rx_bitrate && (rate == STA_STATS_RATE_INVALID)))
 			continue;
 
 		if (time_after(cpustats->last_rx, stats->last_rx))
@@ -2219,7 +2221,7 @@
 
 static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
 {
-	u16 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate);
+	u16 rate = READ_ONCE(sta_get_last_rx_stats(sta, true)->last_rate);
 
 	if (rate == STA_STATS_RATE_INVALID)
 		return -EINVAL;
@@ -2319,7 +2321,7 @@
 	int i, ac, cpu;
 	struct ieee80211_sta_rx_stats *last_rxstats;
 
-	last_rxstats = sta_get_last_rx_stats(sta);
+	last_rxstats = sta_get_last_rx_stats(sta, false);
 
 	sinfo->generation = sdata->local->sta_generation;
 
@@ -2599,7 +2601,7 @@
 
 unsigned long ieee80211_sta_last_active(struct sta_info *sta)
 {
-	struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta);
+	struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta, false);
 
 	if (!sta->status_stats.last_ack ||
 	    time_after(stats->last_rx, sta->status_stats.last_ack))
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 912019c..a6c0174 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -414,8 +414,12 @@
 			if (ac_queue == queue ||
 			    (sdata->vif.cab_queue == queue &&
 			     local->queue_stop_reasons[ac_queue] == 0 &&
-			     skb_queue_empty(&local->pending[ac_queue])))
+			     skb_queue_empty(&local->pending[ac_queue]))) {
+				if (sdata->vif.noqueue_enable)
+					continue;
+
 				netif_wake_subqueue(sdata->dev, ac);
+			}
 		}
 	}
 }
@@ -514,6 +518,9 @@
 		for (ac = 0; ac < n_acs; ac++) {
 			if (sdata->vif.hw_queue[ac] == queue ||
 			    sdata->vif.cab_queue == queue) {
+				if (!local->ops->wake_tx_queue && sdata->vif.noqueue_enable)
+					continue;
+
 				if (!local->ops->wake_tx_queue) {
 					netif_stop_subqueue(sdata->dev, ac);
 					continue;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 57e7703..4a59bf6 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -334,11 +334,17 @@
 	struct wireless_dev *wdev, *tmp;
 
 	ASSERT_RTNL();
-	lockdep_assert_wiphy(&rdev->wiphy);
 
 	list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
-		if (wdev->nl_owner_dead)
+		if (wdev->nl_owner_dead) {
+			if (wdev->netdev)
+				dev_close(wdev->netdev);
+
+			wiphy_lock(&rdev->wiphy);
+			cfg80211_leave(rdev, wdev);
 			rdev_del_virtual_intf(rdev, wdev);
+			wiphy_unlock(&rdev->wiphy);
+		}
 	}
 }
 
@@ -350,9 +356,7 @@
 			    destroy_work);
 
 	rtnl_lock();
-	wiphy_lock(&rdev->wiphy);
 	cfg80211_destroy_ifaces(rdev);
-	wiphy_unlock(&rdev->wiphy);
 	rtnl_unlock();
 }
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 472549a..dd890dc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -47,7 +47,8 @@
 	NL80211_MCGRP_MLME,
 	NL80211_MCGRP_VENDOR,
 	NL80211_MCGRP_NAN,
-	NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
+	NL80211_MCGRP_TESTMODE,
+	NL80211_MCGRP_TESTLOGS /* keep last - ifdef! */
 };
 
 static const struct genl_multicast_group nl80211_mcgrps[] = {
@@ -58,7 +59,8 @@
 	[NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
 	[NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
 #ifdef CONFIG_NL80211_TESTMODE
-	[NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
+	[NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE },
+	[NL80211_MCGRP_TESTLOGS] = { .name = NL80211_MULTICAST_GROUP_TESTLOGS }
 #endif
 };
 
@@ -3021,6 +3023,7 @@
 {
 	struct netlink_ext_ack *extack = info->extack;
 	struct nlattr **attrs = info->attrs;
+	struct wireless_dev *wdev = info->user_ptr[1];
 	enum nl80211_regulatory_power_modes mode = NL80211_REG_AP_LPI;
 	u32 control_freq;
 
@@ -3033,10 +3036,12 @@
 		control_freq +=
 		    nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);
 
-	if (info->attrs[NL80211_ATTR_6G_REG_POWER_MODE])
+	if (info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]) {
 		mode = nla_get_u8(info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]);
-	else
-		mode = chandef->mode;
+	} else {
+		if (wdev)
+			mode = wdev->reg_6g_power_mode;
+	}
 
 	memset(chandef, 0, sizeof(*chandef));
 
@@ -3632,12 +3637,12 @@
 	}
 
 	if (rdev->ops->get_tx_power) {
-		int dbm, ret;
+		int mbm, ret;
 
-		ret = rdev_get_tx_power(rdev, wdev, &dbm);
+		ret = rdev_get_tx_power(rdev, wdev, &mbm);
 		if (ret == 0 &&
 		    nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
-				DBM_TO_MBM(dbm)))
+				mbm))
 			goto nla_put_failure;
 	}
 
@@ -3986,7 +3991,7 @@
 	return err;
 }
 
-static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
+static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct vif_params params;
@@ -3995,9 +4000,6 @@
 	int err;
 	enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
 
-	/* to avoid failing a new interface creation due to pending removal */
-	cfg80211_destroy_ifaces(rdev);
-
 	memset(&params, 0, sizeof(params));
 
 	if (!info->attrs[NL80211_ATTR_IFNAME])
@@ -4085,6 +4087,21 @@
 	return genlmsg_reply(msg, info);
 }
 
+static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	int ret;
+
+	/* to avoid failing a new interface creation due to pending removal */
+	cfg80211_destroy_ifaces(rdev);
+
+	wiphy_lock(&rdev->wiphy);
+	ret = _nl80211_new_interface(skb, info);
+	wiphy_unlock(&rdev->wiphy);
+
+	return ret;
+}
+
 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -5245,6 +5262,11 @@
 	if (ret)
 		return ret;
 
+	fd.max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]);
+	if (!fd.max_interval) {
+		goto set_fils;
+	}
+
 	if (!tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN] ||
 	    !tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX] ||
 	    !tb[NL80211_FILS_DISCOVERY_ATTR_TMPL])
@@ -5253,8 +5275,8 @@
 	fd.tmpl_len = nla_len(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
 	fd.tmpl = nla_data(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
 	fd.min_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN]);
-	fd.max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]);
 
+set_fils:
 	wdev_lock(wdev);
 	ret = rdev_set_fils_discovery(rdev, dev, &fd);
 	wdev_unlock(wdev);
@@ -5283,14 +5305,19 @@
 	if (ret)
 		return ret;
 
+	params.interval = nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT]);
+
+	if (!params.interval)
+		goto set_ubpr;
+
 	if (!tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] ||
 	    !tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL])
 		return -EINVAL;
 
 	params.tmpl = nla_data(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]);
 	params.tmpl_len = nla_len(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]);
-	params.interval = nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT]);
 
+set_ubpr:
 	wdev_lock(wdev);
 	ret = rdev_set_unsol_bcast_probe_resp(rdev, dev, &params);
 	wdev_unlock(wdev);
@@ -10698,7 +10725,7 @@
 }
 EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
 
-void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp, bool testlogs)
 {
 	struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
 	void *hdr = ((void **)skb->cb)[1];
@@ -10719,6 +10746,9 @@
 		if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
 			mcgrp = NL80211_MCGRP_VENDOR;
 
+		if (testlogs)
+			mcgrp = NL80211_MCGRP_TESTLOGS;
+
 		genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
 					skb, 0, mcgrp, gfp);
 	}
@@ -15001,6 +15031,74 @@
 	return ret;
 }
 
+static int nl80211_6ghz_power_mode_change(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct cfg80211_6ghz_power_mode_settings params = {};
+	struct net_device *dev = info->user_ptr[1];
+	struct ieee80211_channel *chan;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_chan_def *chan_def = &wdev->chandef;
+	const struct ieee80211_reg_rule *reg_rule;
+	u32 width;
+	int i, err, num_20mhz_channels, center_freq;
+
+	if (!rdev->ops->power_mode_change_6ghz)
+		return -EOPNOTSUPP;
+
+	if (wdev->iftype != NL80211_IFTYPE_AP)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_6G_REG_POWER_MODE])
+		return -EINVAL;
+
+	params.he_6ghz_pwr_mode = nla_get_u8(info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]);	
+
+	if (params.he_6ghz_pwr_mode < NL80211_REG_AP_LPI ||
+	    params.he_6ghz_pwr_mode > NL80211_REG_AP_VLP ||
+	    params.he_6ghz_pwr_mode == wdev->reg_6g_power_mode) {
+		GENL_SET_ERR_MSG(info, "Invalid 6GHZ power mode configuration\n");
+		return -EINVAL;
+	}
+
+	if (chan_def->width == NL80211_CHAN_WIDTH_20) {
+		width = 20;
+	} else if (chan_def->width == NL80211_CHAN_WIDTH_40) {
+		width = 40;
+	} else if (chan_def->width == NL80211_CHAN_WIDTH_80) {
+		width = 80;
+	} else if (chan_def->width == NL80211_CHAN_WIDTH_160) {
+		width = 160;
+	} else {
+		 GENL_SET_ERR_MSG(info, "Unsupported channel width for configuring power mode\n");
+		 return -EINVAL;
+	}
+
+	num_20mhz_channels = width / 20 ;
+
+	for (i = 0; i < num_20mhz_channels; i++) {
+		center_freq = chan_def->chan->center_freq + i * 20;
+		chan = ieee80211_get_6g_channel_khz(&rdev->wiphy,
+					  MHZ_TO_KHZ(center_freq),
+					  params.he_6ghz_pwr_mode);
+
+		if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+		        GENL_SET_ERR_MSG(info, "Current channel does not support configured power mode\n");
+			return -ENOTSUPP;
+		}
+	}
+
+	err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_next);
+	if (err)
+		return err;
+
+	wdev_lock(wdev);
+	err = rdev_6g_power_mode_change(rdev, dev, &params);
+	wdev_unlock(wdev);
+
+	return err;
+}
+
 static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -15088,6 +15186,7 @@
 #define NL80211_FLAG_NEED_WDEV_UP	(NL80211_FLAG_NEED_WDEV |\
 					 NL80211_FLAG_CHECK_NETDEV_UP)
 #define NL80211_FLAG_CLEAR_SKB		0x20
+#define NL80211_FLAG_NO_WIPHY_MTX	0x40
 
 static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
 			    struct genl_info *info)
@@ -15139,7 +15238,7 @@
 		info->user_ptr[0] = rdev;
 	}
 
-	if (rdev) {
+	if (rdev && !(ops->internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) {
 		wiphy_lock(&rdev->wiphy);
 		/* we keep the mutex locked until post_doit */
 		__release(&rdev->wiphy.mtx);
@@ -15164,7 +15263,8 @@
 		}
 	}
 
-	if (info->user_ptr[0]) {
+	if (info->user_ptr[0] &&
+	    !(ops->internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) {
 		struct cfg80211_registered_device *rdev = info->user_ptr[0];
 
 		/* we kept the mutex locked since pre_doit */
@@ -15330,7 +15430,9 @@
 		.doit = nl80211_new_interface,
 		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
-				  NL80211_FLAG_NEED_RTNL,
+				  NL80211_FLAG_NEED_RTNL |
+				  /* we take the wiphy mutex later ourselves */
+				  NL80211_FLAG_NO_WIPHY_MTX,
 	},
 	{
 		.cmd = NL80211_CMD_DEL_INTERFACE,
@@ -15625,7 +15727,9 @@
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 		.doit = nl80211_wiphy_netns,
 		.flags = GENL_UNS_ADMIN_PERM,
-		.internal_flags = NL80211_FLAG_NEED_WIPHY,
+		.internal_flags = NL80211_FLAG_NEED_WIPHY |
+				  NL80211_FLAG_NEED_RTNL |
+				  NL80211_FLAG_NO_WIPHY_MTX,
 	},
 	{
 		.cmd = NL80211_CMD_GET_SURVEY,
@@ -16090,6 +16194,14 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_SET_6GHZ_POWER_MODE,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = nl80211_6ghz_power_mode_change,
+		.flags = GENL_UNS_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
@@ -17775,6 +17887,46 @@
 }
 EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
 
+void cfg80211_6ghz_power_mode_notify(struct net_device *dev,
+				     gfp_t gfp, enum nl80211_commands cmd)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	struct sk_buff *msg;
+	void *hdr;
+	u8 he_6ghz_power_mode = wdev->reg_6g_power_mode;
+
+	ASSERT_WDEV_LOCK(wdev);
+	trace_cfg80211_6ghz_power_mode_notify(dev, cmd, he_6ghz_power_mode);
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
+		goto nla_put_failure;
+
+	if(nla_put_u32(msg, NL80211_ATTR_6G_REG_POWER_MODE, he_6ghz_power_mode))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+				NL80211_MCGRP_MLME, gfp);
+	return;
+
+nla_put_failure:
+	nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_6ghz_power_mode_notify);
+
 void cfg80211_bss_color_notify(struct net_device *dev,
 			       gfp_t gfp, enum nl80211_commands cmd,
 			       u8 count, u64 color_bitmap)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 5f5b9c3..efc83d4 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -573,12 +573,12 @@
 }
 
 static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
-				    struct wireless_dev *wdev, int *dbm)
+				    struct wireless_dev *wdev, int *mbm)
 {
 	int ret;
 	trace_rdev_get_tx_power(&rdev->wiphy, wdev);
-	ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm);
-	trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
+	ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, mbm);
+	trace_rdev_return_int_int(&rdev->wiphy, ret, MBM_TO_DBM(*mbm));
 	return ret;
 }
 
@@ -1382,6 +1382,19 @@
 	return ret;
 }
 
+static inline int rdev_6g_power_mode_change(struct cfg80211_registered_device *rdev,
+					    struct net_device *dev,
+					    struct cfg80211_6ghz_power_mode_settings *params)
+{
+	int ret;
+
+	trace_rdev_power_mode_change(&rdev->wiphy, dev, params);
+	ret = rdev->ops->power_mode_change_6ghz(&rdev->wiphy, dev, params);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+
+	return ret;
+}
+
 static inline int rdev_color_change(struct cfg80211_registered_device *rdev,
 				    struct net_device *dev,
 				    struct cfg80211_color_change_settings *params)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6d70f11..9b4763f 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -3159,7 +3159,10 @@
 	request.wiphy_idx = get_wiphy_idx(wiphy);
 	request.alpha2[0] = regd->alpha2[0];
 	request.alpha2[1] = regd->alpha2[1];
-	request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+	if (wiphy->regulatory_flags & REGULATORY_SET_BY_6GHZ_AFC)
+		request.initiator = NL80211_REGDOM_SET_BY_AFC;
+	else
+		request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
 
 	nl80211_send_wiphy_reg_change_event(&request);
 }
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 9d34885..3a70072 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3612,6 +3612,26 @@
 		  __entry->interval, __entry->tmpl_len)
 );
 
+TRACE_EVENT(rdev_power_mode_change,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		 struct cfg80211_6ghz_power_mode_settings *params),
+	TP_ARGS(wiphy, netdev, params),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(u8, pwr_mode)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->pwr_mode = params->he_6ghz_pwr_mode;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
+		  ", pwr_mode: %u",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG,
+		  __entry->pwr_mode)
+);
+
 TRACE_EVENT(rdev_color_change,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
 		 struct cfg80211_color_change_settings *params),
@@ -3636,6 +3656,25 @@
 		  __entry->count)
 );
 
+TRACE_EVENT(cfg80211_6ghz_power_mode_notify,
+	TP_PROTO(struct net_device *netdev,
+		 enum nl80211_commands cmd,
+		 u8 he_6ghz_power_mode),
+	TP_ARGS(netdev, cmd,he_6ghz_power_mode),
+	TP_STRUCT__entry(
+		NETDEV_ENTRY
+		__field(enum nl80211_commands,cmd)
+		__field(u8,he_6ghz_power_mode)
+	),
+	TP_fast_assign(
+		NETDEV_ASSIGN;
+		__entry->cmd = cmd;
+		__entry->he_6ghz_power_mode = he_6ghz_power_mode;
+	),
+	TP_printk(NETDEV_PR_FMT ", cmd: %x, he_6ghz_power_mode: %u",
+		  NETDEV_PR_ARG, __entry->cmd, __entry->he_6ghz_power_mode)
+);
+
 TRACE_EVENT(cfg80211_bss_color_notify,
 	TP_PROTO(struct net_device *netdev,
 		 enum nl80211_commands cmd,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index a55f41a..5d8cb26 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1379,7 +1379,7 @@
 		 25599, /*  4.166666... */
 		 17067, /*  2.777777... */
 		 12801, /*  2.083333... */
-		 11769, /*  1.851851... */
+		 11377, /*  1.851725... */
 		 10239, /*  1.666666... */
 		  8532, /*  1.388888... */
 		  7680, /*  1.250000... */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index a8320dc..baa7511 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -964,7 +964,7 @@
 	/* well... oh well */
 	data->txpower.fixed = 1;
 	data->txpower.disabled = rfkill_blocked(rdev->rfkill);
-	data->txpower.value = val;
+	data->txpower.value = MBM_TO_DBM(val);
 	data->txpower.flags = IW_TXPOW_DBM;
 
 	return 0;