From 9e52512b6afec49573f464a9ad9ce237a8301926 Mon Sep 17 00:00:00 2001 From: vanhofen Date: Thu, 19 May 2022 21:31:25 +0200 Subject: [PATCH] - hd60: fix kernel build --- package/kernel/files/kernel-hd6x.defconfig | 1 + ..._4_0001-remote.patch => 0001-remote.patch} | 0 ...ve-up-on-gcc-constant-optimizations.patch} | 0 ...=> 0003-dont-mark-register-as-const.patch} | 0 ...-linux-fix-buffer-size-warning-error.patch | 24 + .../gfutures/0005-xbox-one-tuner-4.4.patch | 238 + ...a18250-support-for-new-silicon-tuner.patch | 1192 +++ .../gfutures/0007-dvb-mn88472-staging.patch | 834 ++ .../gfutures/0008-HauppaugeWinTV-dualHD.patch | 629 ++ .../gfutures/0009-dib7000-linux_4.4.179.patch | 158 + .../gfutures/0010-dvb-usb-linux_4.4.179.patch | 67 + .../gfutures/0011-wifi-linux_4.4.183.patch | 8663 +++++++++++++++++ .../0012-move-default-dialect-to-SMB3.patch | 36 + ..._inittest__exittest_as__maybe_unused.patch | 50 + ...it__exit_attrs_to_initcleanup_module.patch | 84 + ...mpiler_attributes_h_to_support_GCC_9.patch | 51 + ..._reset_stream_ID_reg_if_no_PLP_given.patch | 33 + ...211-increase-scan-result-expire-time.patch | 11 - 18 files changed, 12060 insertions(+), 11 deletions(-) rename package/kernel/patches/gfutures/{4_4_0001-remote.patch => 0001-remote.patch} (100%) rename package/kernel/patches/gfutures/{4_4_0002-log2-give-up-on-gcc-constant-optimizations.patch => 0002-log2-give-up-on-gcc-constant-optimizations.patch} (100%) rename package/kernel/patches/gfutures/{4_4_0003-dont-mark-register-as-const.patch => 0003-dont-mark-register-as-const.patch} (100%) create mode 100644 package/kernel/patches/gfutures/0004-linux-fix-buffer-size-warning-error.patch create mode 100644 package/kernel/patches/gfutures/0005-xbox-one-tuner-4.4.patch create mode 100644 package/kernel/patches/gfutures/0006-dvb-media-tda18250-support-for-new-silicon-tuner.patch create mode 100644 package/kernel/patches/gfutures/0007-dvb-mn88472-staging.patch create mode 100644 package/kernel/patches/gfutures/0008-HauppaugeWinTV-dualHD.patch create mode 100644 package/kernel/patches/gfutures/0009-dib7000-linux_4.4.179.patch create mode 100644 package/kernel/patches/gfutures/0010-dvb-usb-linux_4.4.179.patch create mode 100644 package/kernel/patches/gfutures/0011-wifi-linux_4.4.183.patch create mode 100644 package/kernel/patches/gfutures/0012-move-default-dialect-to-SMB3.patch create mode 100644 package/kernel/patches/gfutures/0013-modules_mark__inittest__exittest_as__maybe_unused.patch create mode 100644 package/kernel/patches/gfutures/0014-includelinuxmodule_h_copy__init__exit_attrs_to_initcleanup_module.patch create mode 100644 package/kernel/patches/gfutures/0015-Backport_minimal_compiler_attributes_h_to_support_GCC_9.patch create mode 100644 package/kernel/patches/gfutures/0016-mn88472_reset_stream_ID_reg_if_no_PLP_given.patch delete mode 100644 package/kernel/patches/gfutures/4_4_ieee80211-increase-scan-result-expire-time.patch diff --git a/package/kernel/files/kernel-hd6x.defconfig b/package/kernel/files/kernel-hd6x.defconfig index 93ddd97b..b74668b8 100644 --- a/package/kernel/files/kernel-hd6x.defconfig +++ b/package/kernel/files/kernel-hd6x.defconfig @@ -2773,6 +2773,7 @@ CONFIG_MEDIA_TUNER=y # Customize TV tuners # CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA18250=y CONFIG_MEDIA_TUNER_TDA8290=y CONFIG_MEDIA_TUNER_TDA827X=y CONFIG_MEDIA_TUNER_TDA18271=y diff --git a/package/kernel/patches/gfutures/4_4_0001-remote.patch b/package/kernel/patches/gfutures/0001-remote.patch similarity index 100% rename from package/kernel/patches/gfutures/4_4_0001-remote.patch rename to package/kernel/patches/gfutures/0001-remote.patch diff --git a/package/kernel/patches/gfutures/4_4_0002-log2-give-up-on-gcc-constant-optimizations.patch b/package/kernel/patches/gfutures/0002-log2-give-up-on-gcc-constant-optimizations.patch similarity index 100% rename from package/kernel/patches/gfutures/4_4_0002-log2-give-up-on-gcc-constant-optimizations.patch rename to package/kernel/patches/gfutures/0002-log2-give-up-on-gcc-constant-optimizations.patch diff --git a/package/kernel/patches/gfutures/4_4_0003-dont-mark-register-as-const.patch b/package/kernel/patches/gfutures/0003-dont-mark-register-as-const.patch similarity index 100% rename from package/kernel/patches/gfutures/4_4_0003-dont-mark-register-as-const.patch rename to package/kernel/patches/gfutures/0003-dont-mark-register-as-const.patch diff --git a/package/kernel/patches/gfutures/0004-linux-fix-buffer-size-warning-error.patch b/package/kernel/patches/gfutures/0004-linux-fix-buffer-size-warning-error.patch new file mode 100644 index 00000000..ba38a35b --- /dev/null +++ b/package/kernel/patches/gfutures/0004-linux-fix-buffer-size-warning-error.patch @@ -0,0 +1,24 @@ +--- a/drivers/hisilicon/atags/tag-chiptrim.c ++++ b/drivers/hisilicon/atags/tag-chiptrim.c +@@ -59,7 +59,7 @@ static int __init parse_chiptrim(const struct tag *tag, void *fdt) + int ix; + int ret; + int node; +- char buf[12]; ++ char buf[20]; + + if (tag->hdr.size <= (sizeof(struct tag_header) >> 2)) { + pr_err("%s: bad tag format.\n", __func__); +--- a/drivers/hisilicon/atags/tag-net.c 2020-03-25 11:27:19.138225245 +0000 ++++ b/drivers/hisilicon/atags/tag-net.c 2020-03-25 11:27:02.498266476 +0000 +@@ -91,7 +91,7 @@ + { + int err; + int node, index = 0; +- char path[16]; ++ char path[20]; + char phy_intf[16]; + char *str, *nxt; + int count; +-- +2.17.1 diff --git a/package/kernel/patches/gfutures/0005-xbox-one-tuner-4.4.patch b/package/kernel/patches/gfutures/0005-xbox-one-tuner-4.4.patch new file mode 100644 index 00000000..550a9c38 --- /dev/null +++ b/package/kernel/patches/gfutures/0005-xbox-one-tuner-4.4.patch @@ -0,0 +1,238 @@ +--- + drivers/media/dvb-core/dvb-usb-ids.h | 2 + + drivers/media/usb/dvb-usb/Kconfig | 2 + + drivers/media/usb/dvb-usb/dib0700.h | 2 + + drivers/media/usb/dvb-usb/dib0700_core.c | 25 ++++- + drivers/media/usb/dvb-usb/dib0700_devices.c | 105 ++++++++++++++++++++ + 5 files changed, 135 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h +index 0a46580b..512275c7 100644 +--- a/drivers/media/dvb-core/dvb-usb-ids.h ++++ b/drivers/media/dvb-core/dvb-usb-ids.h +@@ -70,6 +70,7 @@ + #define USB_VID_EVOLUTEPC 0x1e59 + #define USB_VID_AZUREWAVE 0x13d3 + #define USB_VID_TECHNISAT 0x14f7 ++#define USB_VID_MICROSOFT 0x045e + + /* Product IDs */ + #define USB_PID_ADSTECH_USB2_COLD 0xa333 +@@ -389,4 +390,5 @@ + #define USB_PID_PCTV_2002E_SE 0x025d + #define USB_PID_SVEON_STV27 0xd3af + #define USB_PID_TURBOX_DTT_2000 0xd3a4 ++#define USB_PID_XBOX_ONE_TUNER 0x02d5 + #endif +diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig +index 128eee61..d8e3106d 100644 +--- a/drivers/media/usb/dvb-usb/Kconfig ++++ b/drivers/media/usb/dvb-usb/Kconfig +@@ -75,6 +75,7 @@ config DVB_USB_DIB0700 + select DVB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT + select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT ++ select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT +@@ -83,6 +84,7 @@ config DVB_USB_DIB0700 + select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT ++ select MEDIA_TUNER_TDA18250 if MEDIA_SUBDRV_AUTOSELECT + help + Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The + USB bridge is also present in devices having the DiB7700 DVB-T-USB +diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h +index 8fd8f5b4..5f291284 100644 +--- a/drivers/media/usb/dvb-usb/dib0700.h ++++ b/drivers/media/usb/dvb-usb/dib0700.h +@@ -51,6 +51,8 @@ struct dib0700_state { + int (*read_status)(struct dvb_frontend *, enum fe_status *); + int (*sleep)(struct dvb_frontend* fe); + u8 buf[255]; ++ struct i2c_client *i2c_client_demod; ++ struct i2c_client *i2c_client_tuner; + }; + + extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, +diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c +index 49dd3ea2..e4f3793a 100644 +--- a/drivers/media/usb/dvb-usb/dib0700_core.c ++++ b/drivers/media/usb/dvb-usb/dib0700_core.c +@@ -872,10 +872,33 @@ static int dib0700_probe(struct usb_interface *intf, + return -ENODEV; + } + ++static void dib0700_disconnect(struct usb_interface *intf) ++{ ++ struct dvb_usb_device *d = usb_get_intfdata(intf); ++ struct dib0700_state *st = d->priv; ++ struct i2c_client *client; ++ ++ /* remove I2C client for tuner */ ++ client = st->i2c_client_tuner; ++ if (client) { ++ module_put(client->dev.driver->owner); ++ i2c_unregister_device(client); ++ } ++ ++ /* remove I2C client for demodulator */ ++ client = st->i2c_client_demod; ++ if (client) { ++ module_put(client->dev.driver->owner); ++ i2c_unregister_device(client); ++ } ++ ++ dvb_usb_device_exit(intf); ++} ++ + static struct usb_driver dib0700_driver = { + .name = "dvb_usb_dib0700", + .probe = dib0700_probe, +- .disconnect = dvb_usb_device_exit, ++ .disconnect = dib0700_disconnect, + .id_table = dib0700_usb_id_table, + }; + +diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c +index e1316c7b..2b6c9d3c 100644 +--- a/drivers/media/usb/dvb-usb/dib0700_devices.c ++++ b/drivers/media/usb/dvb-usb/dib0700_devices.c +@@ -23,6 +23,8 @@ + #include "dib0090.h" + #include "lgdt3305.h" + #include "mxl5007t.h" ++#include "mn88472.h" ++#include "tda18250.h" + + static int force_lna_activation; + module_param(force_lna_activation, int, 0644); +@@ -3705,6 +3708,89 @@ + &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; + } + ++static int xbox_one_attach(struct dvb_usb_adapter *adap) ++{ ++ struct dib0700_state *st = adap->dev->priv; ++ struct i2c_client *client_demod, *client_tuner; ++ struct dvb_usb_device *d = adap->dev; ++ struct mn88472_config mn88472_config = { }; ++ struct tda18250_config tda18250_config; ++ struct i2c_board_info info; ++ ++ st->fw_use_new_i2c_api = 1; ++ st->disable_streaming_master_mode = 1; ++ ++ /* fe power enable */ ++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); ++ msleep(30); ++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); ++ msleep(30); ++ ++ /* demod reset */ ++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); ++ msleep(30); ++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); ++ msleep(30); ++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); ++ msleep(30); ++ ++ /* attach demod */ ++ mn88472_config.fe = &adap->fe_adap[0].fe; ++ mn88472_config.i2c_wr_max = 22; ++ mn88472_config.xtal = 20500000; ++ mn88472_config.ts_mode = PARALLEL_TS_MODE; ++ mn88472_config.ts_clock = FIXED_TS_CLOCK; ++ memset(&info, 0, sizeof(struct i2c_board_info)); ++ strlcpy(info.type, "mn88472", I2C_NAME_SIZE); ++ info.addr = 0x18; ++ info.platform_data = &mn88472_config; ++ request_module(info.type); ++ client_demod = i2c_new_device(&d->i2c_adap, &info); ++ if (client_demod == NULL || client_demod->dev.driver == NULL) ++ goto fail_demod_device; ++ if (!try_module_get(client_demod->dev.driver->owner)) ++ goto fail_demod_module; ++ ++ st->i2c_client_demod = client_demod; ++ ++ adap->fe_adap[0].fe = mn88472_config.get_dvb_frontend(client_demod); ++ ++ /* attach tuner */ ++ memset(&tda18250_config, 0, sizeof(tda18250_config)); ++ tda18250_config.if_dvbt_6 = 3950; ++ tda18250_config.if_dvbt_7 = 4450; ++ tda18250_config.if_dvbt_8 = 4950; ++ tda18250_config.if_dvbc_6 = 4950; ++ tda18250_config.if_dvbc_8 = 4950; ++ tda18250_config.if_atsc = 4079; ++ tda18250_config.loopthrough = true; ++ tda18250_config.xtal_freq = TDA18250_XTAL_FREQ_27MHZ; ++ tda18250_config.fe = adap->fe_adap[0].fe; ++ ++ memset(&info, 0, sizeof(struct i2c_board_info)); ++ strlcpy(info.type, "tda18250", I2C_NAME_SIZE); ++ info.addr = 0x60; ++ info.platform_data = &tda18250_config; ++ ++ request_module(info.type); ++ client_tuner = i2c_new_device(&adap->dev->i2c_adap, &info); ++ if (client_tuner == NULL || client_tuner->dev.driver == NULL) ++ goto fail_tuner_device; ++ if (!try_module_get(client_tuner->dev.driver->owner)) ++ goto fail_tuner_module; ++ ++ st->i2c_client_tuner = client_tuner; ++ return 0; ++ ++fail_tuner_module: ++ i2c_unregister_device(client_tuner); ++fail_tuner_device: ++ module_put(client_demod->dev.driver->owner); ++fail_demod_module: ++ i2c_unregister_device(client_demod); ++fail_demod_device: ++ return -ENODEV; ++} + + /* DVB-USB and USB stuff follows */ + struct usb_device_id dib0700_usb_id_table[] = { +@@ -3794,6 +3880,7 @@ + /* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) }, ++ { USB_DEVICE(USB_VID_MICROSOFT, USB_PID_XBOX_ONE_TUNER) }, + { 0 } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); +@@ -4959,6 +5046,25 @@ + RC_BIT_NEC, + .change_protocol = dib0700_change_protocol, + }, ++ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, ++ .num_adapters = 1, ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = {{ ++ .frontend_attach = xbox_one_attach, ++ ++ DIB0700_DEFAULT_STREAMING_CONFIG(0x82), ++ } }, ++ }, ++ }, ++ .num_device_descs = 1, ++ .devices = { ++ { "Microsoft Xbox One Digital TV Tuner", ++ { &dib0700_usb_id_table[83], NULL }, ++ { NULL }, ++ }, ++ }, + }, + }; + +-- +2.17.1 + diff --git a/package/kernel/patches/gfutures/0006-dvb-media-tda18250-support-for-new-silicon-tuner.patch b/package/kernel/patches/gfutures/0006-dvb-media-tda18250-support-for-new-silicon-tuner.patch new file mode 100644 index 00000000..a983c6ed --- /dev/null +++ b/package/kernel/patches/gfutures/0006-dvb-media-tda18250-support-for-new-silicon-tuner.patch @@ -0,0 +1,1192 @@ +From f724afe58782ccbcb2f0aaea9cca204b35859904 Mon Sep 17 00:00:00 2001 +From: Olli Salonen +Date: Thu, 23 Nov 2017 03:24:45 -0500 +Subject: [PATCH 2/4] media: tda18250: support for new silicon tuner + +NXP TDA18250 silicon tuner driver. + +Version 4 includes some checkpatch fixes. + +Signed-off-by: Olli Salonen +Signed-off-by: Mauro Carvalho Chehab +--- + MAINTAINERS | 9 + + drivers/media/tuners/Kconfig | 7 + + drivers/media/tuners/Makefile | 1 + + drivers/media/tuners/tda18250.c | 902 +++++++++++++++++++++++++++ + drivers/media/tuners/tda18250.h | 51 ++ + drivers/media/tuners/tda18250_priv.h | 145 +++++ + 6 files changed, 1115 insertions(+) + create mode 100644 drivers/media/tuners/tda18250.c + create mode 100644 drivers/media/tuners/tda18250.h + create mode 100644 drivers/media/tuners/tda18250_priv.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index 4764180d..9a0a8f15 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -10434,6 +10434,15 @@ T: git git://linuxtv.org/anttip/media_tree.git + S: Maintained + F: drivers/media/tuners/tda18218* + ++TDA18250 MEDIA DRIVER ++M: Olli Salonen ++L: linux-media@vger.kernel.org ++W: https://linuxtv.org ++Q: http://patchwork.linuxtv.org/project/linux-media/list/ ++T: git git://linuxtv.org/media_tree.git ++S: Maintained ++F: drivers/media/tuners/tda18250* ++ + TDA18271 MEDIA DRIVER + M: Michael Krufky + L: linux-media@vger.kernel.org +diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig +index 05998f02..6687514d 100644 +--- a/drivers/media/tuners/Kconfig ++++ b/drivers/media/tuners/Kconfig +@@ -26,6 +26,13 @@ config MEDIA_TUNER_SIMPLE + help + Say Y here to include support for various simple tuners. + ++config MEDIA_TUNER_TDA18250 ++ tristate "NXP TDA18250 silicon tuner" ++ depends on MEDIA_SUPPORT && I2C ++ default m if !MEDIA_SUBDRV_AUTOSELECT ++ help ++ Say Y here to include support for TDA18250 tuner. ++ + config MEDIA_TUNER_TDA8290 + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + depends on MEDIA_SUPPORT && I2C +diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile +index 06a9ab65..4b9444be 100644 +--- a/drivers/media/tuners/Makefile ++++ b/drivers/media/tuners/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o + obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o + obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o + obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o ++obj-$(CONFIG_MEDIA_TUNER_TDA18250) += tda18250.o + + ccflags-y += -I$(srctree)/drivers/media/dvb-core + ccflags-y += -I$(srctree)/drivers/media/dvb-frontends +diff --git a/drivers/media/tuners/tda18250.c b/drivers/media/tuners/tda18250.c +new file mode 100644 +index 00000000..20d12b06 +--- /dev/null ++++ b/drivers/media/tuners/tda18250.c +@@ -0,0 +1,902 @@ ++/* ++ * NXP TDA18250 silicon tuner driver ++ * ++ * Copyright (C) 2017 Olli Salonen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include "tda18250_priv.h" ++#include ++ ++static const struct dvb_tuner_ops tda18250_ops; ++ ++static int tda18250_power_control(struct dvb_frontend *fe, ++ unsigned int power_state) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ int ret; ++ unsigned int utmp; ++ ++ dev_dbg(&client->dev, "power state: %d", power_state); ++ ++ switch (power_state) { ++ case TDA18250_POWER_NORMAL: ++ ret = regmap_write_bits(dev->regmap, R06_POWER2, 0x07, 0x00); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, R25_REF, 0xc0, 0xc0); ++ if (ret) ++ goto err; ++ break; ++ case TDA18250_POWER_STANDBY: ++ if (dev->loopthrough) { ++ ret = regmap_write_bits(dev->regmap, ++ R25_REF, 0xc0, 0x80); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, ++ R06_POWER2, 0x07, 0x02); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, ++ R10_LT1, 0x80, 0x00); ++ if (ret) ++ goto err; ++ } else { ++ ret = regmap_write_bits(dev->regmap, ++ R25_REF, 0xc0, 0x80); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, ++ R06_POWER2, 0x07, 0x01); ++ if (ret) ++ goto err; ++ ret = regmap_read(dev->regmap, ++ R0D_AGC12, &utmp); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, ++ R0D_AGC12, 0x03, 0x03); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, ++ R10_LT1, 0x80, 0x80); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, ++ R0D_AGC12, 0x03, utmp & 0x03); ++ if (ret) ++ goto err; ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static int tda18250_wait_for_irq(struct dvb_frontend *fe, ++ int maxwait, int step, u8 irq) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ int ret; ++ unsigned long timeout; ++ bool triggered; ++ unsigned int utmp; ++ ++ triggered = false; ++ timeout = jiffies + msecs_to_jiffies(maxwait); ++ while (!time_after(jiffies, timeout)) { ++ // check for the IRQ ++ ret = regmap_read(dev->regmap, R08_IRQ1, &utmp); ++ if (ret) ++ goto err; ++ if ((utmp & irq) == irq) { ++ triggered = true; ++ break; ++ } ++ msleep(step); ++ } ++ ++ dev_dbg(&client->dev, "waited IRQ (0x%02x) %d ms, triggered: %s", irq, ++ jiffies_to_msecs(jiffies) - ++ (jiffies_to_msecs(timeout) - maxwait), ++ triggered ? "true" : "false"); ++ ++ if (!triggered) ++ return -ETIMEDOUT; ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static int tda18250_init(struct dvb_frontend *fe) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ int ret, i; ++ ++ /* default values for various regs */ ++ static const u8 init_regs[][2] = { ++ { R0C_AGC11, 0xc7 }, ++ { R0D_AGC12, 0x5d }, ++ { R0E_AGC13, 0x40 }, ++ { R0F_AGC14, 0x0e }, ++ { R10_LT1, 0x47 }, ++ { R11_LT2, 0x4e }, ++ { R12_AGC21, 0x26 }, ++ { R13_AGC22, 0x60 }, ++ { R18_AGC32, 0x37 }, ++ { R19_AGC33, 0x09 }, ++ { R1A_AGCK, 0x00 }, ++ { R1E_WI_FI, 0x29 }, ++ { R1F_RF_BPF, 0x06 }, ++ { R20_IR_MIX, 0xc6 }, ++ { R21_IF_AGC, 0x00 }, ++ { R2C_PS1, 0x75 }, ++ { R2D_PS2, 0x06 }, ++ { R2E_PS3, 0x07 }, ++ { R30_RSSI2, 0x0e }, ++ { R31_IRQ_CTRL, 0x00 }, ++ { R39_SD5, 0x00 }, ++ { R3B_REGU, 0x55 }, ++ { R3C_RCCAL1, 0xa7 }, ++ { R3F_IRCAL2, 0x85 }, ++ { R40_IRCAL3, 0x87 }, ++ { R41_IRCAL4, 0xc0 }, ++ { R43_PD1, 0x40 }, ++ { R44_PD2, 0xc0 }, ++ { R46_CPUMP, 0x0c }, ++ { R47_LNAPOL, 0x64 }, ++ { R4B_XTALOSC1, 0x30 }, ++ { R59_AGC2_UP2, 0x05 }, ++ { R5B_AGC_AUTO, 0x07 }, ++ { R5C_AGC_DEBUG, 0x00 }, ++ }; ++ ++ /* crystal related regs depend on frequency */ ++ static const u8 xtal_regs[][5] = { ++ /* reg: 4d 4e 4f 50 51 */ ++ [TDA18250_XTAL_FREQ_16MHZ] = { 0x3e, 0x80, 0x50, 0x00, 0x20 }, ++ [TDA18250_XTAL_FREQ_24MHZ] = { 0x5d, 0xc0, 0xec, 0x00, 0x18 }, ++ [TDA18250_XTAL_FREQ_25MHZ] = { 0x61, 0xa8, 0xec, 0x80, 0x19 }, ++ [TDA18250_XTAL_FREQ_27MHZ] = { 0x69, 0x78, 0x8d, 0x80, 0x1b }, ++ [TDA18250_XTAL_FREQ_30MHZ] = { 0x75, 0x30, 0x8f, 0x00, 0x1e }, ++ }; ++ ++ dev_dbg(&client->dev, "\n"); ++ ++ ret = tda18250_power_control(fe, TDA18250_POWER_NORMAL); ++ if (ret) ++ goto err; ++ ++ msleep(20); ++ ++ if (dev->warm) ++ goto warm; ++ ++ /* set initial register values */ ++ for (i = 0; i < ARRAY_SIZE(init_regs); i++) { ++ ret = regmap_write(dev->regmap, init_regs[i][0], ++ init_regs[i][1]); ++ if (ret) ++ goto err; ++ } ++ ++ /* set xtal related regs */ ++ ret = regmap_bulk_write(dev->regmap, R4D_XTALFLX1, ++ xtal_regs[dev->xtal_freq], 5); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R10_LT1, 0x80, ++ dev->loopthrough ? 0x00 : 0x80); ++ if (ret) ++ goto err; ++ ++ /* clear IRQ */ ++ ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_HW_INIT); ++ if (ret) ++ goto err; ++ ++ /* start HW init */ ++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x70); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); ++ if (ret) ++ goto err; ++ ++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_HW_INIT); ++ if (ret) ++ goto err; ++ ++ /* tuner calibration */ ++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x02); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); ++ if (ret) ++ goto err; ++ ++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_CAL); ++ if (ret) ++ goto err; ++ ++ dev->warm = true; ++ ++warm: ++ /* power up LNA */ ++ ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00); ++ if (ret) ++ goto err; ++ ++ return 0; ++err: ++ dev_dbg(&client->dev, "failed=%d", ret); ++ return ret; ++} ++ ++static int tda18250_set_agc(struct dvb_frontend *fe) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret; ++ u8 utmp, utmp2; ++ ++ dev_dbg(&client->dev, "\n"); ++ ++ ret = regmap_write_bits(dev->regmap, R1F_RF_BPF, 0x87, 0x06); ++ if (ret) ++ goto err; ++ ++ utmp = ((c->frequency < 100000000) && ++ ((c->delivery_system == SYS_DVBC_ANNEX_A) || ++ (c->delivery_system == SYS_DVBC_ANNEX_C)) && ++ (c->bandwidth_hz == 6000000)) ? 0x80 : 0x00; ++ ret = regmap_write(dev->regmap, R5A_H3H5, utmp); ++ if (ret) ++ goto err; ++ ++ /* AGC1 */ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ utmp = 4; ++ break; ++ default: /* DVB-C/QAM */ ++ switch (c->bandwidth_hz) { ++ case 6000000: ++ utmp = (c->frequency < 800000000) ? 6 : 4; ++ break; ++ default: /* 7.935 and 8 MHz */ ++ utmp = (c->frequency < 100000000) ? 2 : 3; ++ break; ++ } ++ break; ++ } ++ ++ ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x07, utmp); ++ if (ret) ++ goto err; ++ ++ /* AGC2 */ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ utmp = (c->frequency < 320000000) ? 20 : 16; ++ utmp2 = (c->frequency < 320000000) ? 22 : 18; ++ break; ++ default: /* DVB-C/QAM */ ++ switch (c->bandwidth_hz) { ++ case 6000000: ++ if (c->frequency < 600000000) { ++ utmp = 18; ++ utmp2 = 22; ++ } else if (c->frequency < 800000000) { ++ utmp = 16; ++ utmp2 = 20; ++ } else { ++ utmp = 14; ++ utmp2 = 16; ++ } ++ break; ++ default: /* 7.935 and 8 MHz */ ++ utmp = (c->frequency < 320000000) ? 16 : 18; ++ utmp2 = (c->frequency < 320000000) ? 18 : 20; ++ break; ++ } ++ break; ++ } ++ ret = regmap_write_bits(dev->regmap, R58_AGC2_UP1, 0x1f, utmp2+8); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, R13_AGC22, 0x1f, utmp); ++ if (ret) ++ goto err; ++ ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x1f, utmp2); ++ if (ret) ++ goto err; ++ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ utmp = 98; ++ break; ++ default: /* DVB-C/QAM */ ++ utmp = 90; ++ break; ++ } ++ ret = regmap_write_bits(dev->regmap, R16_AGC25, 0xf8, utmp); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R12_AGC21, 0x60, ++ (c->frequency > 800000000) ? 0x40 : 0x20); ++ if (ret) ++ goto err; ++ ++ /* AGC3 */ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ utmp = (c->frequency < 320000000) ? 5 : 7; ++ utmp2 = (c->frequency < 320000000) ? 10 : 12; ++ break; ++ default: /* DVB-C/QAM */ ++ utmp = 7; ++ utmp2 = 12; ++ break; ++ } ++ ret = regmap_write(dev->regmap, R17_AGC31, (utmp << 4) | utmp2); ++ if (ret) ++ goto err; ++ ++ /* S2D */ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ if (c->bandwidth_hz == 8000000) ++ utmp = 0x04; ++ else ++ utmp = (c->frequency < 320000000) ? 0x04 : 0x02; ++ break; ++ default: /* DVB-C/QAM */ ++ if (c->bandwidth_hz == 6000000) ++ utmp = ((c->frequency > 172544000) && ++ (c->frequency < 320000000)) ? 0x04 : 0x02; ++ else /* 7.935 and 8 MHz */ ++ utmp = ((c->frequency > 320000000) && ++ (c->frequency < 600000000)) ? 0x02 : 0x04; ++ break; ++ } ++ ret = regmap_write_bits(dev->regmap, R20_IR_MIX, 0x06, utmp); ++ if (ret) ++ goto err; ++ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ utmp = 0; ++ break; ++ default: /* DVB-C/QAM */ ++ utmp = (c->frequency < 600000000) ? 0 : 3; ++ break; ++ } ++ ret = regmap_write_bits(dev->regmap, R16_AGC25, 0x03, utmp); ++ if (ret) ++ goto err; ++ ++ utmp = 0x09; ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ if (c->bandwidth_hz == 8000000) ++ utmp = 0x0c; ++ break; ++ default: /* DVB-C/QAM */ ++ utmp = 0x0c; ++ break; ++ } ++ ret = regmap_write_bits(dev->regmap, R0F_AGC14, 0x3f, utmp); ++ if (ret) ++ goto err; ++ ++ return 0; ++err: ++ dev_dbg(&client->dev, "failed=%d", ret); ++ return ret; ++} ++ ++static int tda18250_pll_calc(struct dvb_frontend *fe, u8 *rdiv, ++ u8 *ndiv, u8 *icp) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret; ++ unsigned int uval, exp, lopd, scale; ++ unsigned long fvco; ++ ++ ret = regmap_read(dev->regmap, R34_MD1, &uval); ++ if (ret) ++ goto err; ++ ++ exp = (uval & 0x70) >> 4; ++ if (exp > 5) ++ exp = 0; ++ lopd = 1 << (exp - 1); ++ scale = uval & 0x0f; ++ fvco = lopd * scale * ((c->frequency / 1000) + dev->if_frequency); ++ ++ switch (dev->xtal_freq) { ++ case TDA18250_XTAL_FREQ_16MHZ: ++ *rdiv = 1; ++ *ndiv = 0; ++ *icp = (fvco < 6622000) ? 0x05 : 0x02; ++ break; ++ case TDA18250_XTAL_FREQ_24MHZ: ++ case TDA18250_XTAL_FREQ_25MHZ: ++ *rdiv = 3; ++ *ndiv = 1; ++ *icp = (fvco < 6622000) ? 0x05 : 0x02; ++ break; ++ case TDA18250_XTAL_FREQ_27MHZ: ++ if (fvco < 6643000) { ++ *rdiv = 2; ++ *ndiv = 0; ++ *icp = 0x05; ++ } else if (fvco < 6811000) { ++ *rdiv = 2; ++ *ndiv = 0; ++ *icp = 0x06; ++ } else { ++ *rdiv = 3; ++ *ndiv = 1; ++ *icp = 0x02; ++ } ++ break; ++ case TDA18250_XTAL_FREQ_30MHZ: ++ *rdiv = 2; ++ *ndiv = 0; ++ *icp = (fvco < 6811000) ? 0x05 : 0x02; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ dev_dbg(&client->dev, ++ "lopd=%d scale=%u fvco=%lu, rdiv=%d ndiv=%d icp=%d", ++ lopd, scale, fvco, *rdiv, *ndiv, *icp); ++ return 0; ++err: ++ return ret; ++} ++ ++static int tda18250_set_params(struct dvb_frontend *fe) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ u32 if_khz; ++ int ret; ++ unsigned int i, j; ++ u8 utmp; ++ u8 buf[3]; ++ ++ #define REG 0 ++ #define MASK 1 ++ #define DVBT_6 2 ++ #define DVBT_7 3 ++ #define DVBT_8 4 ++ #define DVBC_6 5 ++ #define DVBC_8 6 ++ #define ATSC 7 ++ ++ static const u8 delsys_params[][16] = { ++ [REG] = { 0x22, 0x23, 0x24, 0x21, 0x0d, 0x0c, 0x0f, 0x14, ++ 0x0e, 0x12, 0x58, 0x59, 0x1a, 0x19, 0x1e, 0x30 }, ++ [MASK] = { 0x77, 0xff, 0xff, 0x87, 0xf0, 0x78, 0x07, 0xe0, ++ 0x60, 0x0f, 0x60, 0x0f, 0x33, 0x30, 0x80, 0x06 }, ++ [DVBT_6] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0, ++ 0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 }, ++ [DVBT_7] = { 0x52, 0x03, 0x85, 0x82, 0x40, 0x48, 0x01, 0xe0, ++ 0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 }, ++ [DVBT_8] = { 0x53, 0x03, 0x87, 0x82, 0x40, 0x48, 0x06, 0xe0, ++ 0x60, 0x07, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 }, ++ [DVBC_6] = { 0x32, 0x05, 0x86, 0x82, 0x50, 0x00, 0x06, 0x60, ++ 0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 }, ++ [DVBC_8] = { 0x53, 0x03, 0x88, 0x82, 0x50, 0x00, 0x06, 0x60, ++ 0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 }, ++ [ATSC] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0, ++ 0x40, 0x0e, 0x60, 0x05, 0x03, 0x00, 0x80, 0x04 }, ++ }; ++ ++ dev_dbg(&client->dev, ++ "delivery_system=%d frequency=%u bandwidth_hz=%u", ++ c->delivery_system, c->frequency, c->bandwidth_hz); ++ ++ ++ switch (c->delivery_system) { ++ case SYS_ATSC: ++ j = ATSC; ++ if_khz = dev->if_atsc; ++ break; ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ if (c->bandwidth_hz == 0) { ++ ret = -EINVAL; ++ goto err; ++ } else if (c->bandwidth_hz <= 6000000) { ++ j = DVBT_6; ++ if_khz = dev->if_dvbt_6; ++ } else if (c->bandwidth_hz <= 7000000) { ++ j = DVBT_7; ++ if_khz = dev->if_dvbt_7; ++ } else if (c->bandwidth_hz <= 8000000) { ++ j = DVBT_8; ++ if_khz = dev->if_dvbt_8; ++ } else { ++ ret = -EINVAL; ++ goto err; ++ } ++ break; ++ case SYS_DVBC_ANNEX_A: ++ case SYS_DVBC_ANNEX_C: ++ if (c->bandwidth_hz == 0) { ++ ret = -EINVAL; ++ goto err; ++ } else if (c->bandwidth_hz <= 6000000) { ++ j = DVBC_6; ++ if_khz = dev->if_dvbc_6; ++ } else if (c->bandwidth_hz <= 8000000) { ++ j = DVBC_8; ++ if_khz = dev->if_dvbc_8; ++ } else { ++ ret = -EINVAL; ++ goto err; ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ dev_err(&client->dev, "unsupported delivery system=%d", ++ c->delivery_system); ++ goto err; ++ } ++ ++ /* set delivery system dependent registers */ ++ for (i = 0; i < 16; i++) { ++ ret = regmap_write_bits(dev->regmap, delsys_params[REG][i], ++ delsys_params[MASK][i], delsys_params[j][i]); ++ if (ret) ++ goto err; ++ } ++ ++ /* set IF if needed */ ++ if (dev->if_frequency != if_khz) { ++ utmp = DIV_ROUND_CLOSEST(if_khz, 50); ++ ret = regmap_write(dev->regmap, R26_IF, utmp); ++ if (ret) ++ goto err; ++ dev->if_frequency = if_khz; ++ dev_dbg(&client->dev, "set IF=%u kHz", if_khz); ++ ++ } ++ ++ ret = tda18250_set_agc(fe); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x01); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x00); ++ if (ret) ++ goto err; ++ ++ /* set frequency */ ++ buf[0] = ((c->frequency / 1000) >> 16) & 0xff; ++ buf[1] = ((c->frequency / 1000) >> 8) & 0xff; ++ buf[2] = ((c->frequency / 1000) >> 0) & 0xff; ++ ret = regmap_bulk_write(dev->regmap, R27_RF1, buf, 3); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE); ++ if (ret) ++ goto err; ++ ++ /* initial tune */ ++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x01); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); ++ if (ret) ++ goto err; ++ ++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE); ++ if (ret) ++ goto err; ++ ++ /* calc ndiv and rdiv */ ++ ret = tda18250_pll_calc(fe, &buf[0], &buf[1], &buf[2]); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R4F_XTALFLX3, 0xe0, ++ (buf[0] << 6) | (buf[1] << 5)); ++ if (ret) ++ goto err; ++ ++ /* clear IRQ */ ++ ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, 0x00); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R39_SD5, 0x03, 0x00); ++ if (ret) ++ goto err; ++ ++ /* tune again */ ++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x01); /* tune */ ++ if (ret) ++ goto err; ++ ++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); /* go */ ++ if (ret) ++ goto err; ++ ++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE); ++ if (ret) ++ goto err; ++ ++ /* pll locking */ ++ msleep(20); ++ ++ ret = regmap_write_bits(dev->regmap, R2B_MSM2, 0x04, 0x04); ++ if (ret) ++ goto err; ++ ++ msleep(20); ++ ++ /* restore AGCK */ ++ ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x03); ++ if (ret) ++ goto err; ++ ++ ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x40); ++ if (ret) ++ goto err; ++ ++ /* charge pump */ ++ ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, buf[2]); ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static int tda18250_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ ++ *frequency = dev->if_frequency * 1000; ++ return 0; ++} ++ ++static int tda18250_sleep(struct dvb_frontend *fe) ++{ ++ struct i2c_client *client = fe->tuner_priv; ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ int ret; ++ ++ dev_dbg(&client->dev, "\n"); ++ ++ /* power down LNA */ ++ ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00); ++ if (ret) ++ return ret; ++ ++ /* set if freq to 0 in order to make sure it's set after wake up */ ++ dev->if_frequency = 0; ++ ++ ret = tda18250_power_control(fe, TDA18250_POWER_STANDBY); ++ return ret; ++} ++ ++static const struct dvb_tuner_ops tda18250_ops = { ++ .info = { ++ .name = "NXP TDA18250", ++ .frequency_min = 42000000, ++ .frequency_max = 870000000, ++ }, ++ ++ .init = tda18250_init, ++ .set_params = tda18250_set_params, ++ .get_if_frequency = tda18250_get_if_frequency, ++ .sleep = tda18250_sleep, ++}; ++ ++static int tda18250_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct tda18250_config *cfg = client->dev.platform_data; ++ struct dvb_frontend *fe = cfg->fe; ++ struct tda18250_dev *dev; ++ int ret; ++ unsigned char chip_id[3]; ++ ++ /* some registers are always read from HW */ ++ static const struct regmap_range tda18250_yes_ranges[] = { ++ regmap_reg_range(R05_POWER1, R0B_IRQ4), ++ regmap_reg_range(R21_IF_AGC, R21_IF_AGC), ++ regmap_reg_range(R2A_MSM1, R2B_MSM2), ++ regmap_reg_range(R2F_RSSI1, R31_IRQ_CTRL), ++ }; ++ ++ static const struct regmap_access_table tda18250_volatile_table = { ++ .yes_ranges = tda18250_yes_ranges, ++ .n_yes_ranges = ARRAY_SIZE(tda18250_yes_ranges), ++ }; ++ ++ static const struct regmap_config tda18250_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = TDA18250_NUM_REGS - 1, ++ .volatile_table = &tda18250_volatile_table, ++ }; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ i2c_set_clientdata(client, dev); ++ ++ dev->fe = cfg->fe; ++ dev->loopthrough = cfg->loopthrough; ++ if (cfg->xtal_freq < TDA18250_XTAL_FREQ_MAX) { ++ dev->xtal_freq = cfg->xtal_freq; ++ } else { ++ ret = -EINVAL; ++ dev_err(&client->dev, "xtal_freq invalid=%d", cfg->xtal_freq); ++ goto err_kfree; ++ } ++ dev->if_dvbt_6 = cfg->if_dvbt_6; ++ dev->if_dvbt_7 = cfg->if_dvbt_7; ++ dev->if_dvbt_8 = cfg->if_dvbt_8; ++ dev->if_dvbc_6 = cfg->if_dvbc_6; ++ dev->if_dvbc_8 = cfg->if_dvbc_8; ++ dev->if_atsc = cfg->if_atsc; ++ ++ dev->if_frequency = 0; ++ dev->warm = false; ++ ++ dev->regmap = devm_regmap_init_i2c(client, &tda18250_regmap_config); ++ if (IS_ERR(dev->regmap)) { ++ ret = PTR_ERR(dev->regmap); ++ goto err_kfree; ++ } ++ ++ /* read the three chip ID registers */ ++ regmap_bulk_read(dev->regmap, R00_ID1, &chip_id, 3); ++ dev_dbg(&client->dev, "chip_id=%02x:%02x:%02x", ++ chip_id[0], chip_id[1], chip_id[2]); ++ ++ switch (chip_id[0]) { ++ case 0xc7: ++ dev->slave = false; ++ break; ++ case 0x47: ++ dev->slave = true; ++ break; ++ default: ++ ret = -ENODEV; ++ goto err_kfree; ++ } ++ ++ if (chip_id[1] != 0x4a) { ++ ret = -ENODEV; ++ goto err_kfree; ++ } ++ ++ switch (chip_id[2]) { ++ case 0x20: ++ dev_info(&client->dev, ++ "NXP TDA18250AHN/%s successfully identified", ++ dev->slave ? "S" : "M"); ++ break; ++ case 0x21: ++ dev_info(&client->dev, ++ "NXP TDA18250BHN/%s successfully identified", ++ dev->slave ? "S" : "M"); ++ break; ++ default: ++ ret = -ENODEV; ++ goto err_kfree; ++ } ++ ++ fe->tuner_priv = client; ++ memcpy(&fe->ops.tuner_ops, &tda18250_ops, ++ sizeof(struct dvb_tuner_ops)); ++ ++ /* put the tuner in standby */ ++ tda18250_power_control(fe, TDA18250_POWER_STANDBY); ++ ++ return 0; ++err_kfree: ++ kfree(dev); ++err: ++ dev_dbg(&client->dev, "failed=%d", ret); ++ return ret; ++} ++ ++static int tda18250_remove(struct i2c_client *client) ++{ ++ struct tda18250_dev *dev = i2c_get_clientdata(client); ++ struct dvb_frontend *fe = dev->fe; ++ ++ dev_dbg(&client->dev, "\n"); ++ ++ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); ++ fe->tuner_priv = NULL; ++ kfree(dev); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id tda18250_id_table[] = { ++ {"tda18250", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, tda18250_id_table); ++ ++static struct i2c_driver tda18250_driver = { ++ .driver = { ++ .name = "tda18250", ++ }, ++ .probe = tda18250_probe, ++ .remove = tda18250_remove, ++ .id_table = tda18250_id_table, ++}; ++ ++module_i2c_driver(tda18250_driver); ++ ++MODULE_DESCRIPTION("NXP TDA18250 silicon tuner driver"); ++MODULE_AUTHOR("Olli Salonen "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/tuners/tda18250.h b/drivers/media/tuners/tda18250.h +new file mode 100644 +index 00000000..fb569060 +--- /dev/null ++++ b/drivers/media/tuners/tda18250.h +@@ -0,0 +1,51 @@ ++/* ++ * NXP TDA18250BHN silicon tuner driver ++ * ++ * Copyright (C) 2017 Olli Salonen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef TDA18250_H ++#define TDA18250_H ++ ++#include ++#include ++#include "dvb_frontend.h" ++ ++#define TDA18250_XTAL_FREQ_16MHZ 0 ++#define TDA18250_XTAL_FREQ_24MHZ 1 ++#define TDA18250_XTAL_FREQ_25MHZ 2 ++#define TDA18250_XTAL_FREQ_27MHZ 3 ++#define TDA18250_XTAL_FREQ_30MHZ 4 ++#define TDA18250_XTAL_FREQ_MAX 5 ++ ++struct tda18250_config { ++ u16 if_dvbt_6; ++ u16 if_dvbt_7; ++ u16 if_dvbt_8; ++ u16 if_dvbc_6; ++ u16 if_dvbc_8; ++ u16 if_atsc; ++ u8 xtal_freq; ++ bool loopthrough; ++ ++ /* ++ * frontend ++ */ ++ struct dvb_frontend *fe; ++ ++#if defined(CONFIG_MEDIA_CONTROLLER) ++ struct media_device *mdev; ++#endif ++}; ++ ++#endif +diff --git a/drivers/media/tuners/tda18250_priv.h b/drivers/media/tuners/tda18250_priv.h +new file mode 100644 +index 00000000..4a6f8017 +--- /dev/null ++++ b/drivers/media/tuners/tda18250_priv.h +@@ -0,0 +1,145 @@ ++/* ++ * NXP TDA18250BHN silicon tuner driver ++ * ++ * Copyright (C) 2017 Olli Salonen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef TDA18250_PRIV_H ++#define TDA18250_PRIV_H ++ ++#include "tda18250.h" ++ ++#define R00_ID1 0x00 /* ID byte 1 */ ++#define R01_ID2 0x01 /* ID byte 2 */ ++#define R02_ID3 0x02 /* ID byte 3 */ ++#define R03_THERMO1 0x03 /* Thermo byte 1 */ ++#define R04_THERMO2 0x04 /* Thermo byte 2 */ ++#define R05_POWER1 0x05 /* Power byte 1 */ ++#define R06_POWER2 0x06 /* Power byte 2 */ ++#define R07_GPIO 0x07 /* GPIO */ ++#define R08_IRQ1 0x08 /* IRQ */ ++#define R09_IRQ2 0x09 /* IRQ */ ++#define R0A_IRQ3 0x0a /* IRQ */ ++#define R0B_IRQ4 0x0b /* IRQ */ ++#define R0C_AGC11 0x0c /* AGC1 byte 1 */ ++#define R0D_AGC12 0x0d /* AGC1 byte 2 */ ++#define R0E_AGC13 0x0e /* AGC1 byte 3 */ ++#define R0F_AGC14 0x0f /* AGC1 byte 4 */ ++#define R10_LT1 0x10 /* LT byte 1 */ ++#define R11_LT2 0x11 /* LT byte 2 */ ++#define R12_AGC21 0x12 /* AGC2 byte 1 */ ++#define R13_AGC22 0x13 /* AGC2 byte 2 */ ++#define R14_AGC23 0x14 /* AGC2 byte 3 */ ++#define R15_AGC24 0x15 /* AGC2 byte 4 */ ++#define R16_AGC25 0x16 /* AGC2 byte 5 */ ++#define R17_AGC31 0x17 /* AGC3 byte 1 */ ++#define R18_AGC32 0x18 /* AGC3 byte 2 */ ++#define R19_AGC33 0x19 /* AGC3 byte 3 */ ++#define R1A_AGCK 0x1a ++#define R1B_GAIN1 0x1b ++#define R1C_GAIN2 0x1c ++#define R1D_GAIN3 0x1d ++#define R1E_WI_FI 0x1e /* Wireless Filter */ ++#define R1F_RF_BPF 0x1f /* RF Band Pass Filter */ ++#define R20_IR_MIX 0x20 /* IR Mixer */ ++#define R21_IF_AGC 0x21 ++#define R22_IF1 0x22 /* IF byte 1 */ ++#define R23_IF2 0x23 /* IF byte 2 */ ++#define R24_IF3 0x24 /* IF byte 3 */ ++#define R25_REF 0x25 /* reference byte */ ++#define R26_IF 0x26 /* IF frequency */ ++#define R27_RF1 0x27 /* RF frequency byte 1 */ ++#define R28_RF2 0x28 /* RF frequency byte 2 */ ++#define R29_RF3 0x29 /* RF frequency byte 3 */ ++#define R2A_MSM1 0x2a ++#define R2B_MSM2 0x2b ++#define R2C_PS1 0x2c /* power saving mode byte 1 */ ++#define R2D_PS2 0x2d /* power saving mode byte 2 */ ++#define R2E_PS3 0x2e /* power saving mode byte 3 */ ++#define R2F_RSSI1 0x2f ++#define R30_RSSI2 0x30 ++#define R31_IRQ_CTRL 0x31 ++#define R32_DUMMY 0x32 ++#define R33_TEST 0x33 ++#define R34_MD1 0x34 ++#define R35_SD1 0x35 ++#define R36_SD2 0x36 ++#define R37_SD3 0x37 ++#define R38_SD4 0x38 ++#define R39_SD5 0x39 ++#define R3A_SD_TEST 0x3a ++#define R3B_REGU 0x3b ++#define R3C_RCCAL1 0x3c ++#define R3D_RCCAL2 0x3d ++#define R3E_IRCAL1 0x3e ++#define R3F_IRCAL2 0x3f ++#define R40_IRCAL3 0x40 ++#define R41_IRCAL4 0x41 ++#define R42_IRCAL5 0x42 ++#define R43_PD1 0x43 /* power down byte 1 */ ++#define R44_PD2 0x44 /* power down byte 2 */ ++#define R45_PD 0x45 /* power down */ ++#define R46_CPUMP 0x46 /* charge pump */ ++#define R47_LNAPOL 0x47 /* LNA polar casc */ ++#define R48_SMOOTH1 0x48 /* smooth test byte 1 */ ++#define R49_SMOOTH2 0x49 /* smooth test byte 2 */ ++#define R4A_SMOOTH3 0x4a /* smooth test byte 3 */ ++#define R4B_XTALOSC1 0x4b ++#define R4C_XTALOSC2 0x4c ++#define R4D_XTALFLX1 0x4d ++#define R4E_XTALFLX2 0x4e ++#define R4F_XTALFLX3 0x4f ++#define R50_XTALFLX4 0x50 ++#define R51_XTALFLX5 0x51 ++#define R52_IRLOOP0 0x52 ++#define R53_IRLOOP1 0x53 ++#define R54_IRLOOP2 0x54 ++#define R55_IRLOOP3 0x55 ++#define R56_IRLOOP4 0x56 ++#define R57_PLL_LOG 0x57 ++#define R58_AGC2_UP1 0x58 ++#define R59_AGC2_UP2 0x59 ++#define R5A_H3H5 0x5a ++#define R5B_AGC_AUTO 0x5b ++#define R5C_AGC_DEBUG 0x5c ++ ++#define TDA18250_NUM_REGS 93 ++ ++#define TDA18250_POWER_STANDBY 0 ++#define TDA18250_POWER_NORMAL 1 ++ ++#define TDA18250_IRQ_CAL 0x81 ++#define TDA18250_IRQ_HW_INIT 0x82 ++#define TDA18250_IRQ_TUNE 0x88 ++ ++struct tda18250_dev { ++ struct mutex i2c_mutex; ++ struct dvb_frontend *fe; ++ struct i2c_adapter *i2c; ++ struct regmap *regmap; ++ u8 xtal_freq; ++ /* IF in kHz */ ++ u16 if_dvbt_6; ++ u16 if_dvbt_7; ++ u16 if_dvbt_8; ++ u16 if_dvbc_6; ++ u16 if_dvbc_8; ++ u16 if_atsc; ++ u16 if_frequency; ++ bool slave; ++ bool loopthrough; ++ bool warm; ++ u8 regs[TDA18250_NUM_REGS]; ++}; ++ ++#endif +-- +2.17.1 + diff --git a/package/kernel/patches/gfutures/0007-dvb-mn88472-staging.patch b/package/kernel/patches/gfutures/0007-dvb-mn88472-staging.patch new file mode 100644 index 00000000..7d5ce1f6 --- /dev/null +++ b/package/kernel/patches/gfutures/0007-dvb-mn88472-staging.patch @@ -0,0 +1,834 @@ +--- + drivers/media/dvb-frontends/mn88472.h | 45 +- + drivers/staging/media/mn88472/mn88472.c | 525 ++++++++++--------- + drivers/staging/media/mn88472/mn88472_priv.h | 11 +- + 3 files changed, 310 insertions(+), 271 deletions(-) + +diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h +index 095294d2..32363252 100644 +--- a/drivers/media/dvb-frontends/mn88472.h ++++ b/drivers/media/dvb-frontends/mn88472.h +@@ -19,23 +19,33 @@ + + #include + +-enum ts_clock { +- VARIABLE_TS_CLOCK, +- FIXED_TS_CLOCK, +-}; ++/** ++ * struct mn88472_config - Platform data for the mn88472 driver ++ * @xtal: Clock frequency. ++ * @ts_mode: TS mode. ++ * @ts_clock: TS clock config. ++ * @i2c_wr_max: Max number of bytes driver writes to I2C at once. ++ * @get_dvb_frontend: Get DVB frontend. ++ */ + +-enum ts_mode { +- SERIAL_TS_MODE, +- PARALLEL_TS_MODE, +-}; ++/* Define old names for backward compatibility */ ++#define VARIABLE_TS_CLOCK MN88472_TS_CLK_VARIABLE ++#define FIXED_TS_CLOCK MN88472_TS_CLK_FIXED ++#define SERIAL_TS_MODE MN88472_TS_MODE_SERIAL ++#define PARALLEL_TS_MODE MN88472_TS_MODE_PARALLEL + + struct mn88472_config { +- /* +- * Max num of bytes given I2C adapter could write at once. +- * Default: none +- */ +- u16 i2c_wr_max; ++ unsigned int xtal; ++ ++#define MN88472_TS_MODE_SERIAL 0 ++#define MN88472_TS_MODE_PARALLEL 1 ++ int ts_mode; + ++#define MN88472_TS_CLK_FIXED 0 ++#define MN88472_TS_CLK_VARIABLE 1 ++ int ts_clock; ++ ++ u16 i2c_wr_max; + + /* Everything after that is returned by the driver. */ + +@@ -43,14 +53,7 @@ struct mn88472_config { + * DVB frontend. + */ + struct dvb_frontend **fe; +- +- /* +- * Xtal frequency. +- * Hz +- */ +- u32 xtal; +- int ts_mode; +- int ts_clock; ++ struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); + }; + + #endif +diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c +index cf2e96bc..18fb2df1 100644 +--- a/drivers/staging/media/mn88472/mn88472.c ++++ b/drivers/staging/media/mn88472/mn88472.c +@@ -17,28 +17,90 @@ + #include "mn88472_priv.h" + + static int mn88472_get_tune_settings(struct dvb_frontend *fe, +- struct dvb_frontend_tune_settings *s) ++ struct dvb_frontend_tune_settings *s) + { +- s->min_delay_ms = 800; ++ s->min_delay_ms = 1000; + return 0; + } + ++static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) ++{ ++ struct i2c_client *client = fe->demodulator_priv; ++ struct mn88472_dev *dev = i2c_get_clientdata(client); ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ int ret; ++ unsigned int utmp; ++ ++ if (!dev->active) { ++ ret = -EAGAIN; ++ goto err; ++ } ++ ++ switch (c->delivery_system) { ++ case SYS_DVBT: ++ ret = regmap_read(dev->regmap[0], 0x7f, &utmp); ++ if (ret) ++ goto err; ++ if ((utmp & 0x0f) >= 0x09) ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; ++ else ++ *status = 0; ++ break; ++ case SYS_DVBT2: ++ ret = regmap_read(dev->regmap[2], 0x92, &utmp); ++ if (ret) ++ goto err; ++ if ((utmp & 0x0f) >= 0x0d) ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; ++ else if ((utmp & 0x0f) >= 0x0a) ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI; ++ else if ((utmp & 0x0f) >= 0x07) ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; ++ else ++ *status = 0; ++ break; ++ case SYS_DVBC_ANNEX_A: ++ ret = regmap_read(dev->regmap[1], 0x84, &utmp); ++ if (ret) ++ goto err; ++ if ((utmp & 0x0f) >= 0x08) ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | ++ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; ++ else ++ *status = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ return 0; ++err: ++ dev_dbg(&client->dev, "failed=%d\n", ret); ++ return ret; ++} ++ + static int mn88472_set_frontend(struct dvb_frontend *fe) + { + struct i2c_client *client = fe->demodulator_priv; + struct mn88472_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i; +- u32 if_frequency = 0; +- u64 tmp; +- u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; ++ unsigned int utmp; ++ u32 if_frequency; ++ u8 buf[3], delivery_system_val, bandwidth_val, *bandwidth_vals_ptr; ++ u8 reg_bank0_b4_val, reg_bank0_cd_val, reg_bank0_d4_val; ++ u8 reg_bank0_d6_val; + + dev_dbg(&client->dev, +- "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n", +- c->delivery_system, c->modulation, +- c->frequency, c->symbol_rate, c->inversion); ++ "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n", ++ c->delivery_system, c->modulation, c->frequency, ++ c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id); + +- if (!dev->warm) { ++ if (!dev->active) { + ret = -EAGAIN; + goto err; + } +@@ -46,39 +108,64 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) + switch (c->delivery_system) { + case SYS_DVBT: + delivery_system_val = 0x02; ++ reg_bank0_b4_val = 0x00; ++ reg_bank0_cd_val = 0x1f; ++ reg_bank0_d4_val = 0x0a; ++ reg_bank0_d6_val = 0x48; + break; + case SYS_DVBT2: + delivery_system_val = 0x03; ++ reg_bank0_b4_val = 0xf6; ++ reg_bank0_cd_val = 0x01; ++ reg_bank0_d4_val = 0x09; ++ reg_bank0_d6_val = 0x46; + break; + case SYS_DVBC_ANNEX_A: + delivery_system_val = 0x04; ++ reg_bank0_b4_val = 0x00; ++ reg_bank0_cd_val = 0x17; ++ reg_bank0_d4_val = 0x09; ++ reg_bank0_d6_val = 0x48; + break; + default: + ret = -EINVAL; + goto err; + } + +- if (c->bandwidth_hz <= 5000000) { +- memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7); +- bw_val2 = 0x03; +- } else if (c->bandwidth_hz <= 6000000) { +- /* IF 3570000 Hz, BW 6000000 Hz */ +- memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); +- bw_val2 = 0x02; +- } else if (c->bandwidth_hz <= 7000000) { +- /* IF 4570000 Hz, BW 7000000 Hz */ +- memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); +- bw_val2 = 0x01; +- } else if (c->bandwidth_hz <= 8000000) { +- /* IF 4570000 Hz, BW 8000000 Hz */ +- memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); +- bw_val2 = 0x00; +- } else { +- ret = -EINVAL; +- goto err; ++ switch (c->delivery_system) { ++ case SYS_DVBT: ++ case SYS_DVBT2: ++ switch (c->bandwidth_hz) { ++ case 5000000: ++ bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9"; ++ bandwidth_val = 0x03; ++ break; ++ case 6000000: ++ bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b"; ++ bandwidth_val = 0x02; ++ break; ++ case 7000000: ++ bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c"; ++ bandwidth_val = 0x01; ++ break; ++ case 8000000: ++ bandwidth_vals_ptr = "\x8f\x80\x00\x08\xee\x08\xee"; ++ bandwidth_val = 0x00; ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ break; ++ case SYS_DVBC_ANNEX_A: ++ bandwidth_vals_ptr = NULL; ++ bandwidth_val = 0x00; ++ break; ++ default: ++ break; + } + +- /* program tuner */ ++ /* Program tuner */ + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (ret) +@@ -91,20 +178,10 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) + goto err; + + dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); +- } +- +- /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ +- tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), +- dev->xtal); +- if_val[0] = ((tmp >> 16) & 0xff); +- if_val[1] = ((tmp >> 8) & 0xff); +- if_val[2] = ((tmp >> 0) & 0xff); +- +- ret = regmap_write(dev->regmap[2], 0xfb, 0x13); +- ret = regmap_write(dev->regmap[2], 0xef, 0x13); +- ret = regmap_write(dev->regmap[2], 0xf9, 0x13); +- if (ret) ++ } else { ++ ret = -EINVAL; + goto err; ++ } + + ret = regmap_write(dev->regmap[2], 0x00, 0x66); + if (ret) +@@ -118,157 +195,81 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) + ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); + if (ret) + goto err; +- ret = regmap_write(dev->regmap[2], 0x04, bw_val2); ++ ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val); + if (ret) + goto err; + +- for (i = 0; i < sizeof(if_val); i++) { +- ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]); ++ /* IF */ ++ utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, dev->clk); ++ buf[0] = (utmp >> 16) & 0xff; ++ buf[1] = (utmp >> 8) & 0xff; ++ buf[2] = (utmp >> 0) & 0xff; ++ for (i = 0; i < 3; i++) { ++ ret = regmap_write(dev->regmap[2], 0x10 + i, buf[i]); + if (ret) + goto err; + } + +- for (i = 0; i < sizeof(bw_val); i++) { +- ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]); +- if (ret) +- goto err; ++ /* Bandwidth */ ++ if (bandwidth_vals_ptr) { ++ for (i = 0; i < 7; i++) { ++ ret = regmap_write(dev->regmap[2], 0x13 + i, ++ bandwidth_vals_ptr[i]); ++ if (ret) ++ goto err; ++ } + } + ++ ret = regmap_write(dev->regmap[0], 0xb4, reg_bank0_b4_val); ++ if (ret) ++ goto err; ++ ret = regmap_write(dev->regmap[0], 0xcd, reg_bank0_cd_val); ++ if (ret) ++ goto err; ++ ret = regmap_write(dev->regmap[0], 0xd4, reg_bank0_d4_val); ++ if (ret) ++ goto err; ++ ret = regmap_write(dev->regmap[0], 0xd6, reg_bank0_d6_val); ++ if (ret) ++ goto err; ++ + switch (c->delivery_system) { + case SYS_DVBT: + ret = regmap_write(dev->regmap[0], 0x07, 0x26); +- ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); +- ret = regmap_write(dev->regmap[0], 0xb4, 0x00); +- ret = regmap_write(dev->regmap[0], 0xcd, 0x1f); +- ret = regmap_write(dev->regmap[0], 0xd4, 0x0a); +- ret = regmap_write(dev->regmap[0], 0xd6, 0x48); ++ if (ret) ++ goto err; + ret = regmap_write(dev->regmap[0], 0x00, 0xba); ++ if (ret) ++ goto err; + ret = regmap_write(dev->regmap[0], 0x01, 0x13); + if (ret) + goto err; + break; + case SYS_DVBT2: + ret = regmap_write(dev->regmap[2], 0x2b, 0x13); ++ if (ret) ++ goto err; + ret = regmap_write(dev->regmap[2], 0x4f, 0x05); ++ if (ret) ++ goto err; + ret = regmap_write(dev->regmap[1], 0xf6, 0x05); +- ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); +- ret = regmap_write(dev->regmap[0], 0xb4, 0xf6); +- ret = regmap_write(dev->regmap[0], 0xcd, 0x01); +- ret = regmap_write(dev->regmap[0], 0xd4, 0x09); +- ret = regmap_write(dev->regmap[0], 0xd6, 0x46); +- ret = regmap_write(dev->regmap[2], 0x30, 0x80); +- ret = regmap_write(dev->regmap[2], 0x32, 0x00); + if (ret) + goto err; +- break; +- case SYS_DVBC_ANNEX_A: +- ret = regmap_write(dev->regmap[0], 0xb0, 0x0b); +- ret = regmap_write(dev->regmap[0], 0xb4, 0x00); +- ret = regmap_write(dev->regmap[0], 0xcd, 0x17); +- ret = regmap_write(dev->regmap[0], 0xd4, 0x09); +- ret = regmap_write(dev->regmap[0], 0xd6, 0x48); +- ret = regmap_write(dev->regmap[1], 0x00, 0xb0); ++ ret = regmap_write(dev->regmap[2], 0x32, c->stream_id); + if (ret) + goto err; + break; +- default: +- ret = -EINVAL; +- goto err; +- } +- +- ret = regmap_write(dev->regmap[0], 0x46, 0x00); +- ret = regmap_write(dev->regmap[0], 0xae, 0x00); +- +- switch (dev->ts_mode) { +- case SERIAL_TS_MODE: +- ret = regmap_write(dev->regmap[2], 0x08, 0x1d); +- break; +- case PARALLEL_TS_MODE: +- ret = regmap_write(dev->regmap[2], 0x08, 0x00); ++ case SYS_DVBC_ANNEX_A: + break; + default: +- dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode); +- ret = -EINVAL; +- goto err; +- } +- +- switch (dev->ts_clock) { +- case VARIABLE_TS_CLOCK: +- ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); + break; +- case FIXED_TS_CLOCK: +- ret = regmap_write(dev->regmap[0], 0xd9, 0xe1); +- break; +- default: +- dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock); +- ret = -EINVAL; +- goto err; + } + +- /* Reset demod */ ++ /* Reset FSM */ + ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); + if (ret) + goto err; + +- dev->delivery_system = c->delivery_system; +- +- return 0; +-err: +- dev_dbg(&client->dev, "failed=%d\n", ret); +- return ret; +-} +- +-static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) +-{ +- struct i2c_client *client = fe->demodulator_priv; +- struct mn88472_dev *dev = i2c_get_clientdata(client); +- struct dtv_frontend_properties *c = &fe->dtv_property_cache; +- int ret; +- unsigned int utmp; +- int lock = 0; +- +- *status = 0; +- +- if (!dev->warm) { +- ret = -EAGAIN; +- goto err; +- } +- +- switch (c->delivery_system) { +- case SYS_DVBT: +- ret = regmap_read(dev->regmap[0], 0x7F, &utmp); +- if (ret) +- goto err; +- if ((utmp & 0xF) >= 0x09) +- lock = 1; +- break; +- case SYS_DVBT2: +- ret = regmap_read(dev->regmap[2], 0x92, &utmp); +- if (ret) +- goto err; +- if ((utmp & 0xF) >= 0x07) +- *status |= FE_HAS_SIGNAL; +- if ((utmp & 0xF) >= 0x0a) +- *status |= FE_HAS_CARRIER; +- if ((utmp & 0xF) >= 0x0d) +- *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; +- break; +- case SYS_DVBC_ANNEX_A: +- ret = regmap_read(dev->regmap[1], 0x84, &utmp); +- if (ret) +- goto err; +- if ((utmp & 0xF) >= 0x08) +- lock = 1; +- break; +- default: +- ret = -EINVAL; +- goto err; +- } +- +- if (lock) +- *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | +- FE_HAS_SYNC | FE_HAS_LOCK; +- + return 0; + err: + dev_dbg(&client->dev, "failed=%d\n", ret); +@@ -279,93 +280,107 @@ static int mn88472_init(struct dvb_frontend *fe) + { + struct i2c_client *client = fe->demodulator_priv; + struct mn88472_dev *dev = i2c_get_clientdata(client); +- int ret, len, remaining; +- const struct firmware *fw = NULL; +- u8 *fw_file = MN88472_FIRMWARE; +- unsigned int tmp; ++ int ret, len, rem; ++ unsigned int utmp; ++ const struct firmware *firmware; ++ const char *name = MN88472_FIRMWARE; + + dev_dbg(&client->dev, "\n"); + +- /* set cold state by default */ +- dev->warm = false; +- +- /* power on */ ++ /* Power up */ + ret = regmap_write(dev->regmap[2], 0x05, 0x00); + if (ret) + goto err; +- +- ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2); ++ ret = regmap_write(dev->regmap[2], 0x0b, 0x00); + if (ret) + goto err; +- +- /* check if firmware is already running */ +- ret = regmap_read(dev->regmap[0], 0xf5, &tmp); ++ ret = regmap_write(dev->regmap[2], 0x0c, 0x00); + if (ret) + goto err; + +- if (!(tmp & 0x1)) { +- dev_info(&client->dev, "firmware already running\n"); +- dev->warm = true; +- return 0; +- } ++ /* Check if firmware is already running */ ++ ret = regmap_read(dev->regmap[0], 0xf5, &utmp); ++ if (ret) ++ goto err; ++ if (!(utmp & 0x01)) ++ goto warm; + +- /* request the firmware, this will block and timeout */ +- ret = request_firmware(&fw, fw_file, &client->dev); ++ ret = request_firmware(&firmware, name, &client->dev); + if (ret) { +- dev_err(&client->dev, "firmare file '%s' not found\n", +- fw_file); ++ dev_err(&client->dev, "firmware file '%s' not found\n", name); + goto err; + } + +- dev_info(&client->dev, "downloading firmware from file '%s'\n", +- fw_file); ++ dev_info(&client->dev, "downloading firmware from file '%s'\n", name); + + ret = regmap_write(dev->regmap[0], 0xf5, 0x03); + if (ret) +- goto firmware_release; +- +- for (remaining = fw->size; remaining > 0; +- remaining -= (dev->i2c_wr_max - 1)) { +- len = remaining; +- if (len > (dev->i2c_wr_max - 1)) +- len = dev->i2c_wr_max - 1; ++ goto err_release_firmware; + ++ for (rem = firmware->size; rem > 0; rem -= (dev->i2c_write_max - 1)) { ++ len = min(dev->i2c_write_max - 1, rem); + ret = regmap_bulk_write(dev->regmap[0], 0xf6, +- &fw->data[fw->size - remaining], len); ++ &firmware->data[firmware->size - rem], ++ len); + if (ret) { +- dev_err(&client->dev, +- "firmware download failed=%d\n", ret); +- goto firmware_release; ++ dev_err(&client->dev, "firmware download failed %d\n", ++ ret); ++ goto err_release_firmware; + } + } + +- /* parity check of firmware */ +- ret = regmap_read(dev->regmap[0], 0xf8, &tmp); +- if (ret) { +- dev_err(&client->dev, +- "parity reg read failed=%d\n", ret); +- goto firmware_release; +- } +- if (tmp & 0x10) { +- dev_err(&client->dev, +- "firmware parity check failed=0x%x\n", tmp); +- goto firmware_release; ++ /* Parity check of firmware */ ++ ret = regmap_read(dev->regmap[0], 0xf8, &utmp); ++ if (ret) ++ goto err_release_firmware; ++ if (utmp & 0x10) { ++ ret = -EINVAL; ++ dev_err(&client->dev, "firmware did not run\n"); ++ goto err_release_firmware; + } +- dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); + + ret = regmap_write(dev->regmap[0], 0xf5, 0x00); + if (ret) +- goto firmware_release; ++ goto err_release_firmware; ++ ++ release_firmware(firmware); ++warm: ++ /* TS config */ ++ switch (dev->ts_mode) { ++ case SERIAL_TS_MODE: ++ utmp = 0x1d; ++ break; ++ case PARALLEL_TS_MODE: ++ utmp = 0x00; ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ ret = regmap_write(dev->regmap[2], 0x08, utmp); ++ if (ret) ++ goto err; + +- release_firmware(fw); +- fw = NULL; ++ switch (dev->ts_clk) { ++ case VARIABLE_TS_CLOCK: ++ utmp = 0xe3; ++ break; ++ case FIXED_TS_CLOCK: ++ utmp = 0xe1; ++ break; ++ default: ++ ret = -EINVAL; ++ goto err; ++ } ++ ret = regmap_write(dev->regmap[0], 0xd9, utmp); ++ if (ret) ++ goto err; + +- /* warm state */ +- dev->warm = true; ++ dev->active = true; + + return 0; +-firmware_release: +- release_firmware(fw); ++err_release_firmware: ++ release_firmware(firmware); + err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +@@ -379,18 +394,17 @@ static int mn88472_sleep(struct dvb_frontend *fe) + + dev_dbg(&client->dev, "\n"); + +- /* power off */ ++ /* Power down */ ++ ret = regmap_write(dev->regmap[2], 0x0c, 0x30); ++ if (ret) ++ goto err; + ret = regmap_write(dev->regmap[2], 0x0b, 0x30); +- + if (ret) + goto err; +- + ret = regmap_write(dev->regmap[2], 0x05, 0x3e); + if (ret) + goto err; + +- dev->delivery_system = SYS_UNDEFINED; +- + return 0; + err: + dev_dbg(&client->dev, "failed=%d\n", ret); +@@ -434,10 +448,19 @@ static struct dvb_frontend_ops mn88472_ops = { + .read_status = mn88472_read_status, + }; + ++static struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client) ++{ ++ struct mn88472_dev *dev = i2c_get_clientdata(client); ++ ++ dev_dbg(&client->dev, "\n"); ++ ++ return &dev->fe; ++} ++ + static int mn88472_probe(struct i2c_client *client, +- const struct i2c_device_id *id) ++ const struct i2c_device_id *id) + { +- struct mn88472_config *config = client->dev.platform_data; ++ struct mn88472_config *pdata = client->dev.platform_data; + struct mn88472_dev *dev; + int ret; + unsigned int utmp; +@@ -448,23 +471,16 @@ static int mn88472_probe(struct i2c_client *client, + + dev_dbg(&client->dev, "\n"); + +- /* Caller really need to provide pointer for frontend we create. */ +- if (config->fe == NULL) { +- dev_err(&client->dev, "frontend pointer not defined\n"); +- ret = -EINVAL; +- goto err; +- } +- + dev = kzalloc(sizeof(*dev), GFP_KERNEL); +- if (dev == NULL) { ++ if (!dev) { + ret = -ENOMEM; + goto err; + } + +- dev->i2c_wr_max = config->i2c_wr_max; +- dev->xtal = config->xtal; +- dev->ts_mode = config->ts_mode; +- dev->ts_clock = config->ts_clock; ++ dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0; ++ dev->clk = pdata->xtal; ++ dev->ts_mode = pdata->ts_mode; ++ dev->ts_clk = pdata->ts_clock; + dev->client[0] = client; + dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); + if (IS_ERR(dev->regmap[0])) { +@@ -472,18 +488,28 @@ static int mn88472_probe(struct i2c_client *client, + goto err_kfree; + } + +- /* check demod answers to I2C */ +- ret = regmap_read(dev->regmap[0], 0x00, &utmp); ++ /* Check demod answers with correct chip id */ ++ ret = regmap_read(dev->regmap[0], 0xff, &utmp); + if (ret) + goto err_regmap_0_regmap_exit; + ++ dev_dbg(&client->dev, "chip id=%02x\n", utmp); ++ ++ if (utmp != 0x02) { ++ ret = -ENODEV; ++ goto err_regmap_0_regmap_exit; ++ } ++ + /* +- * Chip has three I2C addresses for different register pages. Used ++ * Chip has three I2C addresses for different register banks. Used + * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, +- * 0x1a and 0x1c, in order to get own I2C client for each register page. ++ * 0x1a and 0x1c, in order to get own I2C client for each register bank. ++ * ++ * Also, register bank 2 do not support sequential I/O. Only single ++ * register write or read is allowed to that bank. + */ + dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); +- if (dev->client[1] == NULL) { ++ if (!dev->client[1]) { + ret = -ENODEV; + dev_err(&client->dev, "I2C registration failed\n"); + if (ret) +@@ -497,7 +523,7 @@ static int mn88472_probe(struct i2c_client *client, + i2c_set_clientdata(dev->client[1], dev); + + dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); +- if (dev->client[2] == NULL) { ++ if (!dev->client[2]) { + ret = -ENODEV; + dev_err(&client->dev, "2nd I2C registration failed\n"); + if (ret) +@@ -510,15 +536,25 @@ static int mn88472_probe(struct i2c_client *client, + } + i2c_set_clientdata(dev->client[2], dev); + +- /* create dvb_frontend */ ++ /* Sleep because chip is active by default */ ++ ret = regmap_write(dev->regmap[2], 0x05, 0x3e); ++ if (ret) ++ goto err_regmap_2_regmap_exit; ++ ++ /* Create dvb frontend */ + memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); + dev->fe.demodulator_priv = client; +- *config->fe = &dev->fe; ++ *pdata->fe = &dev->fe; + i2c_set_clientdata(client, dev); + +- dev_info(&client->dev, "Panasonic MN88472 successfully attached\n"); +- return 0; ++ /* Setup callbacks */ ++ pdata->get_dvb_frontend = mn88472_get_dvb_frontend; + ++ dev_info(&client->dev, "Panasonic MN88472 successfully identified\n"); ++ ++ return 0; ++err_regmap_2_regmap_exit: ++ regmap_exit(dev->regmap[2]); + err_client_2_i2c_unregister_device: + i2c_unregister_device(dev->client[2]); + err_regmap_1_regmap_exit: +@@ -561,11 +597,12 @@ MODULE_DEVICE_TABLE(i2c, mn88472_id_table); + + static struct i2c_driver mn88472_driver = { + .driver = { +- .name = "mn88472", ++ .name = "mn88472", ++ .suppress_bind_attrs = true, + }, +- .probe = mn88472_probe, +- .remove = mn88472_remove, +- .id_table = mn88472_id_table, ++ .probe = mn88472_probe, ++ .remove = mn88472_remove, ++ .id_table = mn88472_id_table, + }; + + module_i2c_driver(mn88472_driver); +diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h +index 1a0de9e4..cdf2597a 100644 +--- a/drivers/staging/media/mn88472/mn88472_priv.h ++++ b/drivers/staging/media/mn88472/mn88472_priv.h +@@ -28,12 +28,11 @@ struct mn88472_dev { + struct i2c_client *client[3]; + struct regmap *regmap[3]; + struct dvb_frontend fe; +- u16 i2c_wr_max; +- enum fe_delivery_system delivery_system; +- bool warm; /* FW running */ +- u32 xtal; +- int ts_mode; +- int ts_clock; ++ u16 i2c_write_max; ++ unsigned int clk; ++ unsigned int active:1; ++ unsigned int ts_mode:1; ++ unsigned int ts_clk:1; + }; + + #endif +-- +2.17.1 + diff --git a/package/kernel/patches/gfutures/0008-HauppaugeWinTV-dualHD.patch b/package/kernel/patches/gfutures/0008-HauppaugeWinTV-dualHD.patch new file mode 100644 index 00000000..ea472285 --- /dev/null +++ b/package/kernel/patches/gfutures/0008-HauppaugeWinTV-dualHD.patch @@ -0,0 +1,629 @@ +diff -Nur a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx +--- a/Documentation/video4linux/CARDLIST.em28xx 2017-07-31 15:25:12.000000000 +0200 ++++ b/Documentation/video4linux/CARDLIST.em28xx 2019-04-02 08:35:00.919204500 +0200 +@@ -96,3 +96,5 @@ + 95 -> Leadtek VC100 (em2861) [0413:6f07] + 96 -> Terratec Cinergy T2 Stick HD (em28178) + 97 -> Elgato EyeTV Hybrid 2008 INT (em2884) [0fd9:0018] ++ 98 -> Hauppauge WinTV-dualHD DVB (em28174) [2040:0265] ++ +diff -Nur a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h +--- a/drivers/media/usb/em28xx/em28xx.h 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/em28xx/em28xx.h 2019-04-02 08:30:40.196114900 +0200 +@@ -145,6 +145,7 @@ + #define EM2861_BOARD_LEADTEK_VC100 95 + #define EM28178_BOARD_TERRATEC_T2_STICK_HD 96 + #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 97 ++#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB 98 + + /* Limits minimum and default number of buffers */ + #define EM28XX_MIN_BUF 4 +@@ -213,6 +214,9 @@ + /* max. number of button state polling addresses */ + #define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5 + ++#define PRIMARY_TS 0 ++#define SECONDARY_TS 1 ++ + enum em28xx_mode { + EM28XX_SUSPEND, + EM28XX_ANALOG_MODE, +@@ -412,6 +416,7 @@ + enum em28xx_led_role { + EM28XX_LED_ANALOG_CAPTURING = 0, + EM28XX_LED_DIGITAL_CAPTURING, ++ EM28XX_LED_DIGITAL_CAPTURING_TS2, + EM28XX_LED_ILLUMINATION, + EM28XX_NUM_LED_ROLES, /* must be the last */ + }; +@@ -458,6 +463,7 @@ + unsigned int mts_firmware:1; + unsigned int max_range_640_480:1; + unsigned int has_dvb:1; ++ unsigned int has_dual_ts:1; + unsigned int is_webcam:1; + unsigned int valid:1; + unsigned int has_ir_i2c:1; +@@ -608,7 +614,6 @@ + struct em28xx_IR *ir; + + /* generic device properties */ +- char name[30]; /* name (including minor) of the device */ + int model; /* index in the device_data struct */ + int devno; /* marks the number of this device */ + enum em28xx_chip_id chip_id; +@@ -619,6 +624,7 @@ + unsigned int is_audio_only:1; + enum em28xx_int_audio_type int_audio_type; + enum em28xx_usb_audio_type usb_audio_type; ++ unsigned char name[32]; + + struct em28xx_board board; + +@@ -677,9 +683,12 @@ + + /* usb transfer */ + struct usb_device *udev; /* the usb device */ ++ struct usb_interface *intf; // the usb interface + u8 ifnum; /* number of the assigned usb interface */ + u8 analog_ep_isoc; /* address of isoc endpoint for analog */ + u8 analog_ep_bulk; /* address of bulk endpoint for analog */ ++ u8 dvb_ep_isoc_ts2; /* address of isoc endpoint for DVB TS2*/ ++ u8 dvb_ep_bulk_ts2; /* address of bulk endpoint for DVB TS2*/ + u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ + u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */ + int alt; /* alternate setting */ +@@ -693,6 +702,8 @@ + int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */ + unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the + selected DVB ep at dvb_alt */ ++ unsigned int dvb_max_pkt_size_isoc_ts2; /* isoc max packet size of the ++ selected DVB ep at dvb_alt */ + unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc + transfers for DVB */ + char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ +@@ -718,6 +729,15 @@ + /* Snapshot button input device */ + char snapshot_button_path[30]; /* path of the input dev */ + struct input_dev *sbutton_input_dev; ++ ++#ifdef CONFIG_MEDIA_CONTROLLER ++ struct media_device *media_dev; ++ struct media_entity input_ent[MAX_EM28XX_INPUT]; ++ struct media_pad input_pad[MAX_EM28XX_INPUT]; ++#endif ++ ++ struct em28xx *dev_next; ++ int ts; + }; + + #define kref_to_dev(d) container_of(d, struct em28xx, ref) +diff -Nur a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +--- a/drivers/media/usb/em28xx/em28xx-cards.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/em28xx/em28xx-cards.c 2019-04-02 08:43:27.288403900 +0200 +@@ -491,6 +491,30 @@ + {-1, -1, -1, -1}, + }; + ++/* 2040:0265 Hauppauge WinTV-dualHD DVB Isoc ++ * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk ++ * reg 0x80/0x84: ++ * GPIO_0: Yellow LED tuner 1, 0=on, 1=off ++ * GPIO_1: Green LED tuner 1, 0=on, 1=off ++ * GPIO_2: Yellow LED tuner 2, 0=on, 1=off ++ * GPIO_3: Green LED tuner 2, 0=on, 1=off ++ * GPIO_5: Reset #2, 0=active ++ * GPIO_6: Reset #1, 0=active ++ */ ++static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = { ++ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, ++ {0x0d, 0xff, 0xff, 200}, ++ {0x50, 0x04, 0xff, 300}, ++ {EM2874_R80_GPIO_P0_CTRL, 0xbf, 0xff, 100}, /* demod 1 reset */ ++ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, ++ {EM2874_R80_GPIO_P0_CTRL, 0xdf, 0xff, 100}, /* demod 2 reset */ ++ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, ++ {EM2874_R5F_TS_ENABLE, 0x44, 0xff, 50}, ++ {EM2874_R5D_TS1_PKT_SIZE, 0x05, 0xff, 50}, ++ {EM2874_R5E_TS2_PKT_SIZE, 0x05, 0xff, 50}, ++ {-1, -1, -1, -1}, ++}; ++ + /* + * Button definitions + */ +@@ -560,6 +584,22 @@ + {-1, 0, 0, 0}, + }; + ++static struct em28xx_led hauppauge_dualhd_leds[] = { ++ { ++ .role = EM28XX_LED_DIGITAL_CAPTURING, ++ .gpio_reg = EM2874_R80_GPIO_P0_CTRL, ++ .gpio_mask = EM_GPIO_1, ++ .inverted = 1, ++ }, ++ { ++ .role = EM28XX_LED_DIGITAL_CAPTURING_TS2, ++ .gpio_reg = EM2874_R80_GPIO_P0_CTRL, ++ .gpio_mask = EM_GPIO_3, ++ .inverted = 1, ++ }, ++ {-1, 0, 0, 0}, ++}; ++ + /* + * Board definitions + */ +@@ -2288,6 +2328,20 @@ + .has_dvb = 1, + .ir_codes = RC_MAP_TERRATEC_SLIM_2, + }, ++ /* 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc. ++ * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk. ++ * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 */ ++ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = { ++ .name = "Hauppauge WinTV-dualHD DVB", ++ .def_i2c_bus = 1, ++ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, ++ .tuner_type = TUNER_ABSENT, ++ .tuner_gpio = hauppauge_dualhd_dvb, ++ .has_dvb = 1, ++ .has_dual_ts = 1, ++ .ir_codes = RC_MAP_HAUPPAUGE, ++ .leds = hauppauge_dualhd_leds, ++ }, + }; + EXPORT_SYMBOL_GPL(em28xx_boards); + +@@ -2411,6 +2465,10 @@ + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x651f), + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, ++ { USB_DEVICE(0x2040, 0x0265), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, ++ { USB_DEVICE(0x2040, 0x8265), ++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB }, + { USB_DEVICE(0x0438, 0xb002), + .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, + { USB_DEVICE(0x2001, 0xf112), +@@ -2804,6 +2862,7 @@ + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: ++ case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: + { + struct tveeprom tv; + +@@ -3013,6 +3072,8 @@ + */ + static void em28xx_release_resources(struct em28xx *dev) + { ++ struct usb_device *udev = interface_to_usbdev(dev->intf); ++ + /*FIXME: I2C IR should be disconnected */ + + mutex_lock(&dev->lock); +@@ -3021,7 +3082,8 @@ + em28xx_i2c_unregister(dev, 1); + em28xx_i2c_unregister(dev, 0); + +- usb_put_dev(dev->udev); ++ if (dev->ts == PRIMARY_TS) ++ usb_put_dev(udev); + + /* Mark device as unused */ + clear_bit(dev->devno, em28xx_devused); +@@ -3063,6 +3125,7 @@ + const char *chip_name = default_chip_name; + + dev->udev = udev; ++ dev->intf = interface; + mutex_init(&dev->ctrl_urb_lock); + spin_lock_init(&dev->slock); + +@@ -3220,6 +3283,35 @@ + return 0; + } + ++int em28xx_duplicate_dev(struct em28xx *dev) ++{ ++ int nr; ++ struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL); ++ ++ if (sec_dev == NULL) { ++ dev->dev_next = NULL; ++ return -ENOMEM; ++ } ++ memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev))); ++ /* Check to see next free device and mark as used */ ++ do { ++ nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); ++ if (nr >= EM28XX_MAXBOARDS) { ++ /* No free device slots */ ++ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", ++ EM28XX_MAXBOARDS); ++ kfree(sec_dev); ++ dev->dev_next = NULL; ++ return -ENOMEM; ++ } ++ } while (test_and_set_bit(nr, em28xx_devused)); ++ sec_dev->devno = nr; ++ snprintf(sec_dev->name, 28, "em28xx #%d", nr); ++ sec_dev->dev_next = NULL; ++ dev->dev_next = sec_dev; ++ return 0; ++} ++ + /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ + #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + +@@ -3340,6 +3432,17 @@ + } + } + break; ++ case 0x85: ++ if (usb_endpoint_xfer_isoc(e)) { ++ if (size > dev->dvb_max_pkt_size_isoc_ts2) { ++ dev->dvb_ep_isoc_ts2 = e->bEndpointAddress; ++ dev->dvb_max_pkt_size_isoc_ts2 = size; ++ dev->dvb_alt_isoc = i; ++ } ++ } else { ++ dev->dvb_ep_bulk_ts2 = e->bEndpointAddress; ++ } ++ break; + } + } + /* NOTE: +@@ -3354,6 +3457,8 @@ + * 0x83 isoc* => audio + * 0x84 isoc => digital + * 0x84 bulk => analog or digital** ++ * 0x85 isoc => digital TS2 ++ * 0x85 bulk => digital TS2 + * (*: audio should always be isoc) + * (**: analog, if ep 0x82 is isoc, otherwise digital) + * +@@ -3422,6 +3527,10 @@ + dev->has_video = has_video; + dev->ifnum = ifnum; + ++ dev->ts = PRIMARY_TS; ++ snprintf(dev->name, 28, "em28xx"); ++ dev->dev_next = NULL; ++ + if (has_vendor_audio) { + printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n", + ifnum, "(Vendor Class)"); +@@ -3491,6 +3600,65 @@ + dev->dvb_xfer_bulk ? "bulk" : "isoc"); + } + ++ if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) { ++ dev->dev_next->ts = SECONDARY_TS; ++ dev->dev_next->alt = -1; ++ dev->dev_next->is_audio_only = has_vendor_audio && ++ !(has_video || has_dvb); ++ dev->dev_next->has_video = false; ++ dev->dev_next->ifnum = ifnum; ++ dev->dev_next->model = id->driver_info; ++ ++ mutex_init(&dev->dev_next->lock); ++ retval = em28xx_init_dev(dev->dev_next, udev, interface, ++ dev->dev_next->devno); ++ if (retval) ++ goto err_free; ++ ++ dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */ ++ dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */ ++ ++ if (usb_xfer_mode < 0) { ++ if (dev->dev_next->board.is_webcam) ++ try_bulk = 1; ++ else ++ try_bulk = 0; ++ } else { ++ try_bulk = usb_xfer_mode > 0; ++ } ++ ++ /* Select USB transfer types to use */ ++ if (has_dvb) { ++ if (!dev->dvb_ep_isoc_ts2 || ++ (try_bulk && dev->dvb_ep_bulk_ts2)) ++ dev->dev_next->dvb_xfer_bulk = 1; ++ printk(DRIVER_NAME "dvb ts2 set to %s mode.\n", ++ dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc"); ++ } ++ ++ dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2; ++ dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2; ++ dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2; ++ dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc; ++ ++ /* Configuare hardware to support TS2*/ ++ if (dev->dvb_xfer_bulk) { ++ /* The ep4 and ep5 are configuared for BULK */ ++ em28xx_write_reg(dev, 0x0b, 0x96); ++ mdelay(100); ++ em28xx_write_reg(dev, 0x0b, 0x80); ++ mdelay(100); ++ } else { ++ /* The ep4 and ep5 are configuared for ISO */ ++ em28xx_write_reg(dev, 0x0b, 0x96); ++ mdelay(100); ++ em28xx_write_reg(dev, 0x0b, 0x82); ++ mdelay(100); ++ } ++ ++ kref_init(&dev->dev_next->ref); ++ } ++ + kref_init(&dev->ref); + + request_modules(dev); +@@ -3528,6 +3696,13 @@ + if (!dev) + return; + ++ if (dev->dev_next != NULL) { ++ dev->dev_next->disconnected = 1; ++ printk(DRIVER_NAME "Disconnecting %s\n", ++ dev->dev_next->name); ++ flush_request_modules(dev->dev_next); ++ } ++ + dev->disconnected = 1; + + em28xx_info("Disconnecting %s\n", dev->name); +@@ -3536,7 +3711,14 @@ + + em28xx_close_extension(dev); + ++ if (dev->dev_next != NULL) ++ em28xx_release_resources(dev->dev_next); + em28xx_release_resources(dev); ++ ++ if (dev->dev_next != NULL) { ++ kref_put(&dev->dev_next->ref, em28xx_free_device); ++ dev->dev_next = NULL; ++ } + kref_put(&dev->ref, em28xx_free_device); + } + +diff -Nur a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c +--- a/drivers/media/usb/em28xx/em28xx-core.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/em28xx/em28xx-core.c 2019-04-02 08:30:40.204091800 +0200 +@@ -636,10 +636,19 @@ + dev->chip_id == CHIP_ID_EM28174 || + dev->chip_id == CHIP_ID_EM28178) { + /* The Transport Stream Enable Register moved in em2874 */ +- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, +- start ? +- EM2874_TS1_CAPTURE_ENABLE : 0x00, +- EM2874_TS1_CAPTURE_ENABLE); ++ if (dev->ts == PRIMARY_TS) { ++ rc = em28xx_write_reg_bits(dev, ++ EM2874_R5F_TS_ENABLE, ++ start ? ++ EM2874_TS1_CAPTURE_ENABLE : 0x00, ++ EM2874_TS1_CAPTURE_ENABLE); ++ } else { ++ rc = em28xx_write_reg_bits(dev, ++ EM2874_R5F_TS_ENABLE, ++ start ? ++ EM2874_TS2_CAPTURE_ENABLE : 0x00, ++ EM2874_TS2_CAPTURE_ENABLE); ++ } + } else { + /* FIXME: which is the best order? */ + /* video registers are sampled by VREF */ +@@ -1073,7 +1082,11 @@ + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&ops->next, &em28xx_extension_devlist); + list_for_each_entry(dev, &em28xx_devlist, devlist) { +- ops->init(dev); ++ if (ops->init) { ++ ops->init(dev); ++ if (dev->dev_next != NULL) ++ ops->init(dev->dev_next); ++ } + } + mutex_unlock(&em28xx_devlist_mutex); + printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name); +@@ -1087,7 +1100,11 @@ + + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(dev, &em28xx_devlist, devlist) { +- ops->fini(dev); ++ if (ops->fini) { ++ if (dev->dev_next != NULL) ++ ops->fini(dev->dev_next); ++ ops->fini(dev); ++ } + } + list_del(&ops->next); + mutex_unlock(&em28xx_devlist_mutex); +@@ -1102,8 +1119,11 @@ + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&dev->devlist, &em28xx_devlist); + list_for_each_entry(ops, &em28xx_extension_devlist, next) { +- if (ops->init) +- ops->init(dev); ++ if (ops->init) { ++ ops->init(dev); ++ if (dev->dev_next != NULL) ++ ops->init(dev->dev_next); ++ } + } + mutex_unlock(&em28xx_devlist_mutex); + } +@@ -1114,8 +1134,11 @@ + + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(ops, &em28xx_extension_devlist, next) { +- if (ops->fini) +- ops->fini(dev); ++ if (ops->fini) { ++ if (dev->dev_next != NULL) ++ ops->fini(dev->dev_next); ++ ops->fini(dev); ++ } + } + list_del(&dev->devlist); + mutex_unlock(&em28xx_devlist_mutex); +@@ -1130,6 +1153,8 @@ + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->suspend) + ops->suspend(dev); ++ if (dev->dev_next != NULL) ++ ops->suspend(dev->dev_next); + } + mutex_unlock(&em28xx_devlist_mutex); + return 0; +@@ -1144,6 +1169,8 @@ + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->resume) + ops->resume(dev); ++ if (dev->dev_next != NULL) ++ ops->resume(dev->dev_next); + } + mutex_unlock(&em28xx_devlist_mutex); + return 0; +diff -Nur a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c +--- a/drivers/media/usb/em28xx/em28xx-dvb.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/em28xx/em28xx-dvb.c 2019-04-02 08:30:40.206087100 +0200 +@@ -211,7 +211,6 @@ + dvb_alt = dev->dvb_alt_isoc; + } + +- usb_set_interface(dev->udev, dev->ifnum, dvb_alt); + rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); + if (rc < 0) + return rc; +@@ -1031,8 +1030,9 @@ + + static int em28xx_dvb_init(struct em28xx *dev) + { +- int result = 0; ++ int result = 0, dvb_alt = 0; + struct em28xx_dvb *dvb; ++ struct usb_device *udev; + + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ +@@ -1726,6 +1726,76 @@ + dvb->i2c_client_tuner = client; + } + break; ++ case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: ++ { ++ struct i2c_adapter *adapter; ++ struct i2c_client *client; ++ struct i2c_board_info info; ++ struct si2168_config si2168_config; ++ struct si2157_config si2157_config; ++ ++ /* attach demod */ ++ memset(&si2168_config, 0, sizeof(si2168_config)); ++ si2168_config.i2c_adapter = &adapter; ++ si2168_config.fe = &dvb->fe[0]; ++ si2168_config.ts_mode = SI2168_TS_SERIAL; ++ memset(&info, 0, sizeof(struct i2c_board_info)); ++ strlcpy(info.type, "si2168", I2C_NAME_SIZE); ++ if (dev->ts == PRIMARY_TS) ++ info.addr = 0x64; ++ else ++ info.addr = 0x67; ++ info.platform_data = &si2168_config; ++ request_module(info.type); ++ client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); ++ if (client == NULL || client->dev.driver == NULL) { ++ result = -ENODEV; ++ goto out_free; ++ } ++ ++ if (!try_module_get(client->dev.driver->owner)) { ++ i2c_unregister_device(client); ++ result = -ENODEV; ++ goto out_free; ++ } ++ ++ dvb->i2c_client_demod = client; ++ ++ /* attach tuner */ ++ memset(&si2157_config, 0, sizeof(si2157_config)); ++ si2157_config.fe = dvb->fe[0]; ++ si2157_config.if_port = 1; ++#ifdef CONFIG_MEDIA_CONTROLLER_DVB ++ si2157_config.mdev = dev->media_dev; ++#endif ++ memset(&info, 0, sizeof(struct i2c_board_info)); ++ strlcpy(info.type, "si2157", I2C_NAME_SIZE); ++ if (dev->ts == PRIMARY_TS) ++ info.addr = 0x60; ++ else ++ info.addr = 0x63; ++ info.platform_data = &si2157_config; ++ request_module(info.type); ++ client = i2c_new_device(adapter, &info); ++ if (client == NULL || client->dev.driver == NULL) { ++ module_put(dvb->i2c_client_demod->dev.driver->owner); ++ i2c_unregister_device(dvb->i2c_client_demod); ++ result = -ENODEV; ++ goto out_free; ++ } ++ ++ if (!try_module_get(client->dev.driver->owner)) { ++ i2c_unregister_device(client); ++ module_put(dvb->i2c_client_demod->dev.driver->owner); ++ i2c_unregister_device(dvb->i2c_client_demod); ++ result = -ENODEV; ++ goto out_free; ++ } ++ ++ dvb->i2c_client_tuner = client; ++ ++ } ++ break; + default: + em28xx_errdev("/2: The frontend of your DVB/ATSC card" + " isn't supported yet\n"); +@@ -1747,6 +1817,14 @@ + if (result < 0) + goto out_free; + ++ if (dev->dvb_xfer_bulk) { ++ dvb_alt = 0; ++ } else { /* isoc */ ++ dvb_alt = dev->dvb_alt_isoc; ++ } ++ ++ udev = interface_to_usbdev(dev->intf); ++ usb_set_interface(udev, dev->ifnum, dvb_alt); + em28xx_info("DVB extension successfully initialized\n"); + + kref_get(&dev->ref); +diff -Nur a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h +--- a/drivers/media/usb/em28xx/em28xx-reg.h 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/em28xx/em28xx-reg.h 2019-04-02 08:30:40.209080400 +0200 +@@ -193,6 +193,19 @@ + /* em2874 registers */ + #define EM2874_R50_IR_CONFIG 0x50 + #define EM2874_R51_IR 0x51 ++#define EM2874_R5D_TS1_PKT_SIZE 0x5d ++#define EM2874_R5E_TS2_PKT_SIZE 0x5e ++ /* ++ * For both TS1 and TS2, In isochronous mode: ++ * 0x01 188 bytes ++ * 0x02 376 bytes ++ * 0x03 564 bytes ++ * 0x04 752 bytes ++ * 0x05 940 bytes ++ * In bulk mode: ++ * 0x01..0xff total packet count in 188-byte ++ */ ++ + #define EM2874_R5F_TS_ENABLE 0x5f + + /* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */ diff --git a/package/kernel/patches/gfutures/0009-dib7000-linux_4.4.179.patch b/package/kernel/patches/gfutures/0009-dib7000-linux_4.4.179.patch new file mode 100644 index 00000000..8caf1645 --- /dev/null +++ b/package/kernel/patches/gfutures/0009-dib7000-linux_4.4.179.patch @@ -0,0 +1,158 @@ +diff -Nur a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c +--- a/drivers/media/usb/dvb-usb/dib0700_core.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/dvb-usb/dib0700_core.c 2019-02-23 09:05:14.000000000 +0100 +@@ -783,6 +783,9 @@ + + /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ + ++ if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1) ++ return -ENODEV; ++ + purb = usb_alloc_urb(0, GFP_KERNEL); + if (purb == NULL) { + err("rc usb alloc urb failed"); +diff -Nur a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c +--- a/drivers/media/usb/dvb-usb/dib0700_devices.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/dvb-usb/dib0700_devices.c 2019-02-23 09:05:14.000000000 +0100 +@@ -294,7 +294,7 @@ + stk7700d_dib7000p_mt2266_config) + != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + } +@@ -328,7 +328,7 @@ + stk7700d_dib7000p_mt2266_config) + != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + } +@@ -433,6 +433,7 @@ + state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + break; + case XC2028_RESET_CLK: ++ case XC2028_I2C_FLUSH: + break; + default: + err("%s: unknown command %d, arg %d\n", __func__, +@@ -481,7 +482,7 @@ + &stk7700ph_dib7700_xc3028_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", + __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +@@ -1012,7 +1013,7 @@ + &dib7070p_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", + __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +@@ -1070,7 +1071,7 @@ + &dib7770p_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", + __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +@@ -3038,7 +3039,7 @@ + + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); +@@ -3091,7 +3092,7 @@ + /* initialize IC 0 */ + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +@@ -3121,7 +3122,7 @@ + i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +@@ -3196,7 +3197,7 @@ + 1, 0x10, &tfe7790p_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", + __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, +@@ -3291,7 +3292,7 @@ + stk7070pd_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", + __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +@@ -3366,7 +3367,7 @@ + stk7070pd_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", + __func__); +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + } +@@ -3602,7 +3603,7 @@ + + if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) { + /* Demodulator not found for some reason? */ +- dvb_detach(&state->dib7000p_ops); ++ dvb_detach(state->dib7000p_ops.set_wbd_ref); + return -ENODEV; + } + +diff -Nur a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c +--- a/drivers/media/usb/dvb-usb/dibusb-common.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/dvb-usb/dibusb-common.c 2019-02-23 09:05:14.000000000 +0100 +@@ -179,8 +179,20 @@ + + int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) + { +- u8 wbuf[1] = { offs }; +- return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); ++ u8 *buf; ++ int rc; ++ ++ buf = kmalloc(2, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ buf[0] = offs; ++ ++ rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1); ++ *val = buf[1]; ++ kfree(buf); ++ ++ return rc; + } + EXPORT_SYMBOL(dibusb_read_eeprom_byte); + diff --git a/package/kernel/patches/gfutures/0010-dvb-usb-linux_4.4.179.patch b/package/kernel/patches/gfutures/0010-dvb-usb-linux_4.4.179.patch new file mode 100644 index 00000000..ec672ce0 --- /dev/null +++ b/package/kernel/patches/gfutures/0010-dvb-usb-linux_4.4.179.patch @@ -0,0 +1,67 @@ +diff -Nur a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c +--- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c 2017-07-31 15:25:15.000000000 +0200 ++++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c 2019-02-23 09:05:14.000000000 +0100 +@@ -35,42 +35,51 @@ + + int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) + { +- struct hexline hx; +- u8 reset; +- int ret,pos=0; ++ struct hexline *hx; ++ u8 *buf; ++ int ret, pos = 0; ++ u16 cpu_cs_register = cypress[type].cpu_cs_register; ++ ++ buf = kmalloc(sizeof(*hx), GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ hx = (struct hexline *)buf; + + /* stop the CPU */ +- reset = 1; +- if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) ++ buf[0] = 1; ++ if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) + err("could not stop the USB controller CPU."); + +- while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { +- deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); +- ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); ++ while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) { ++ deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk); ++ ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len); + +- if (ret != hx.len) { ++ if (ret != hx->len) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", +- ret,hx.len); ++ ret, hx->len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); ++ kfree(buf); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ +- reset = 0; +- if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { ++ buf[0] = 0; ++ if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + } else + ret = -EIO; + ++ kfree(buf); ++ + return ret; + } + EXPORT_SYMBOL(usb_cypress_load_firmware); diff --git a/package/kernel/patches/gfutures/0011-wifi-linux_4.4.183.patch b/package/kernel/patches/gfutures/0011-wifi-linux_4.4.183.patch new file mode 100644 index 00000000..5eb94026 --- /dev/null +++ b/package/kernel/patches/gfutures/0011-wifi-linux_4.4.183.patch @@ -0,0 +1,8663 @@ +--- + drivers/net/wireless/at76c50x-usb.c | 4 +- + drivers/net/wireless/ath/ath10k/core.c | 25 ++- + drivers/net/wireless/ath/ath10k/core.h | 4 + + drivers/net/wireless/ath/ath10k/debug.c | 9 + + drivers/net/wireless/ath/ath10k/htt_rx.c | 110 ++++++++-- + drivers/net/wireless/ath/ath10k/mac.c | 105 ++++++++-- + drivers/net/wireless/ath/ath10k/pci.c | 2 +- + drivers/net/wireless/ath/ath10k/spectral.c | 2 +- + drivers/net/wireless/ath/ath10k/trace.h | 12 +- + drivers/net/wireless/ath/ath10k/wmi-ops.h | 6 + + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 25 ++- + drivers/net/wireless/ath/ath10k/wmi-tlv.h | 5 + + drivers/net/wireless/ath/ath10k/wmi.c | 10 +- + drivers/net/wireless/ath/ath10k/wmi.h | 3 +- + drivers/net/wireless/ath/ath5k/debug.c | 5 +- + drivers/net/wireless/ath/ath5k/mac80211-ops.c | 3 +- + .../net/wireless/ath/ath9k/ar9003_eeprom.h | 4 +- + drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 - + drivers/net/wireless/ath/ath9k/ath9k.h | 1 + + .../net/wireless/ath/ath9k/common-spectral.c | 8 +- + drivers/net/wireless/ath/ath9k/hif_usb.c | 4 + + drivers/net/wireless/ath/ath9k/htc_drv_main.c | 7 +- + drivers/net/wireless/ath/ath9k/hw.c | 4 + + drivers/net/wireless/ath/ath9k/init.c | 1 + + drivers/net/wireless/ath/ath9k/mac.c | 44 +++- + drivers/net/wireless/ath/ath9k/mac.h | 1 + + drivers/net/wireless/ath/ath9k/main.c | 35 ++-- + drivers/net/wireless/ath/ath9k/pci.c | 7 +- + drivers/net/wireless/ath/ath9k/tx99.c | 18 +- + drivers/net/wireless/ath/carl9170/main.c | 8 +- + drivers/net/wireless/ath/regd.c | 19 +- + drivers/net/wireless/ath/regd.h | 5 + + drivers/net/wireless/ath/regd_common.h | 13 ++ + drivers/net/wireless/ath/wcn36xx/main.c | 8 +- + drivers/net/wireless/ath/wcn36xx/txrx.c | 2 +- + drivers/net/wireless/ath/wil6210/main.c | 35 +++- + drivers/net/wireless/ath/wil6210/wmi.c | 8 +- + drivers/net/wireless/b43/phy_common.c | 2 +- + drivers/net/wireless/b43/phy_lp.c | 6 +- + .../net/wireless/brcm80211/brcmfmac/bcmsdh.c | 8 +- + drivers/net/wireless/brcm80211/brcmfmac/bus.h | 4 +- + .../wireless/brcm80211/brcmfmac/cfg80211.c | 70 ++++--- + .../net/wireless/brcm80211/brcmfmac/core.c | 68 +++--- + .../net/wireless/brcm80211/brcmfmac/fweh.c | 57 ++--- + .../net/wireless/brcm80211/brcmfmac/fweh.h | 82 ++++++-- + .../wireless/brcm80211/brcmfmac/fwil_types.h | 5 + + .../net/wireless/brcm80211/brcmfmac/msgbuf.c | 42 ++-- + drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 34 +-- + .../net/wireless/brcm80211/brcmfmac/sdio.c | 46 +++- + drivers/net/wireless/brcm80211/brcmfmac/usb.c | 29 +-- + .../net/wireless/brcm80211/brcmfmac/vendor.c | 5 +- + .../wireless/brcm80211/brcmsmac/mac80211_if.c | 8 +- + .../wireless/brcm80211/brcmsmac/phy/phy_n.c | 197 +++++++++--------- + drivers/net/wireless/cw1200/cw1200_spi.c | 9 +- + drivers/net/wireless/cw1200/main.c | 5 + + drivers/net/wireless/cw1200/pm.h | 9 +- + drivers/net/wireless/cw1200/scan.c | 18 +- + drivers/net/wireless/cw1200/sta.c | 4 +- + drivers/net/wireless/cw1200/sta.h | 4 +- + drivers/net/wireless/cw1200/wsm.c | 24 +-- + drivers/net/wireless/hostap/hostap_hw.c | 15 +- + drivers/net/wireless/iwlegacy/4965-mac.c | 8 +- + drivers/net/wireless/iwlegacy/4965.h | 4 +- + drivers/net/wireless/iwlwifi/dvm/mac80211.c | 9 +- + drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 70 +++++-- + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 31 ++- + drivers/net/wireless/iwlwifi/mvm/nvm.c | 5 +- + drivers/net/wireless/iwlwifi/pcie/rx.c | 2 + + drivers/net/wireless/mac80211_hwsim.c | 90 +++++--- + .../net/wireless/mediatek/mt7601u/eeprom.h | 2 +- + drivers/net/wireless/mediatek/mt7601u/main.c | 8 +- + drivers/net/wireless/mediatek/mt7601u/mcu.c | 10 +- + drivers/net/wireless/mwifiex/11n_aggr.c | 19 +- + drivers/net/wireless/mwifiex/cfg80211.c | 25 ++- + drivers/net/wireless/mwifiex/cfp.c | 3 + + drivers/net/wireless/mwifiex/debugfs.c | 3 +- + drivers/net/wireless/mwifiex/pcie.c | 7 + + drivers/net/wireless/mwifiex/scan.c | 6 + + drivers/net/wireless/mwifiex/sta_ioctl.c | 2 - + drivers/net/wireless/mwifiex/usb.c | 3 + + drivers/net/wireless/mwifiex/util.c | 8 +- + drivers/net/wireless/mwifiex/wmm.c | 12 +- + drivers/net/wireless/mwl8k.c | 10 +- + drivers/net/wireless/p54/fwio.c | 2 +- + drivers/net/wireless/ray_cs.c | 7 +- + .../wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.c | 6 +- + drivers/net/wireless/realtek/rtlwifi/base.c | 13 +- + drivers/net/wireless/realtek/rtlwifi/core.c | 18 +- + drivers/net/wireless/realtek/rtlwifi/pci.c | 25 ++- + drivers/net/wireless/realtek/rtlwifi/pci.h | 4 +- + drivers/net/wireless/realtek/rtlwifi/ps.c | 36 +++- + .../wireless/realtek/rtlwifi/rtl8192cu/rf.c | 3 - + .../wireless/realtek/rtlwifi/rtl8192ee/fw.c | 6 +- + .../wireless/realtek/rtlwifi/rtl8192ee/hw.c | 2 +- + .../wireless/realtek/rtlwifi/rtl8723be/hw.c | 3 +- + .../wireless/realtek/rtlwifi/rtl8821ae/dm.c | 6 +- + .../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 6 +- + .../wireless/realtek/rtlwifi/rtl8821ae/phy.c | 122 +++++++++-- + .../wireless/realtek/rtlwifi/rtl8821ae/reg.h | 1 + + drivers/net/wireless/realtek/rtlwifi/usb.c | 19 ++ + drivers/net/wireless/realtek/rtlwifi/usb.h | 3 +- + drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 + + drivers/net/wireless/rndis_wlan.c | 6 + + drivers/net/wireless/rsi/rsi_91x_mac80211.c | 19 +- + drivers/net/wireless/rsi/rsi_91x_sdio.c | 2 - + drivers/net/wireless/rsi/rsi_common.h | 1 - + drivers/net/wireless/rt2x00/rt2800lib.c | 7 +- + drivers/net/wireless/rt2x00/rt2800lib.h | 4 +- + drivers/net/wireless/ti/wl1251/main.c | 4 +- + drivers/net/wireless/ti/wl18xx/event.c | 28 +++ + drivers/net/wireless/ti/wl18xx/event.h | 1 + + drivers/net/wireless/ti/wl18xx/main.c | 3 +- + drivers/net/wireless/ti/wlcore/acx.c | 5 +- + drivers/net/wireless/ti/wlcore/acx.h | 3 +- + drivers/net/wireless/ti/wlcore/init.c | 5 - + drivers/net/wireless/ti/wlcore/main.c | 21 +- + drivers/net/wireless/ti/wlcore/sdio.c | 5 + + drivers/net/wireless/ti/wlcore/spi.c | 2 +- + drivers/staging/rtl8188eu/core/rtw_ap.c | 2 +- + drivers/staging/rtl8188eu/core/rtw_recv.c | 3 + + drivers/staging/rtl8188eu/include/rtw_debug.h | 2 +- + .../staging/rtl8188eu/os_dep/ioctl_linux.c | 14 +- + drivers/staging/rtl8188eu/os_dep/usb_intf.c | 3 + + .../staging/rtl8192e/rtl8192e/r8192E_dev.c | 24 ++- + drivers/staging/rtl8192u/r8192U_core.c | 2 + + drivers/staging/rtl8712/ieee80211.h | 84 ++++---- + drivers/staging/rtl8712/rtl871x_ioctl_linux.c | 2 +- + drivers/staging/rtl8712/rtl871x_recv.c | 7 +- + drivers/staging/rtl8712/rtl871x_xmit.c | 7 +- + drivers/staging/wlan-ng/p80211netdev.c | 2 +- + drivers/staging/wlan-ng/prism2mgmt.c | 2 +- + include/linux/mmc/sdio_ids.h | 1 + + include/linux/nospec.h | 68 ++++++ + include/net/cfg80211.h | 13 +- + include/net/mac80211.h | 64 ++++-- + include/uapi/linux/nl80211.h | 2 + + net/mac80211/agg-rx.c | 32 ++- + net/mac80211/agg-tx.c | 53 +++-- + net/mac80211/cfg.c | 10 +- + net/mac80211/debugfs.c | 7 +- + net/mac80211/driver-ops.c | 10 +- + net/mac80211/driver-ops.h | 7 +- + net/mac80211/ibss.c | 28 +-- + net/mac80211/ieee80211_i.h | 1 - + net/mac80211/iface.c | 4 +- + net/mac80211/key.c | 77 +++++-- + net/mac80211/main.c | 39 +++- + net/mac80211/mesh.c | 7 +- + net/mac80211/mesh_hwmp.c | 19 +- + net/mac80211/mesh_plink.c | 14 +- + net/mac80211/mesh_sync.c | 11 - + net/mac80211/mlme.c | 84 ++++++-- + net/mac80211/offchannel.c | 2 + + net/mac80211/pm.c | 1 + + net/mac80211/rx.c | 39 +++- + net/mac80211/sta_info.c | 5 +- + net/mac80211/status.c | 10 +- + net/mac80211/trace.h | 43 ++-- + net/mac80211/tx.c | 19 +- + net/mac80211/util.c | 8 +- + net/mac80211/wep.c | 3 +- + net/mac80211/wpa.c | 54 +++-- + net/rfkill/Kconfig | 5 - + net/rfkill/core.c | 4 +- + net/rfkill/rfkill-gpio.c | 7 +- + net/wireless/core.c | 11 +- + net/wireless/core.h | 2 + + net/wireless/mlme.c | 12 ++ + net/wireless/nl80211.c | 192 +++++++++-------- + net/wireless/reg.c | 5 +- + net/wireless/scan.c | 71 ++++++- + net/wireless/sme.c | 14 ++ + net/wireless/util.c | 2 +- + 174 files changed, 2220 insertions(+), 1047 deletions(-) + create mode 100644 include/linux/nospec.h + +diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c +index dab25136..da14eca2 100644 +--- a/drivers/net/wireless/at76c50x-usb.c ++++ b/drivers/net/wireless/at76c50x-usb.c +@@ -2582,8 +2582,8 @@ static int __init at76_mod_init(void) + if (result < 0) + printk(KERN_ERR DRIVER_NAME + ": usb_register failed (status %d)\n", result); +- +- led_trigger_register_simple("at76_usb-tx", &ledtrig_tx); ++ else ++ led_trigger_register_simple("at76_usb-tx", &ledtrig_tx); + return result; + } + +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 531de256..0c23768a 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -67,6 +67,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA988X_BOARD_DATA_SZ, + .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + { + .id = QCA6174_HW_2_1_VERSION, +@@ -85,6 +86,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + { + .id = QCA6174_HW_2_1_VERSION, +@@ -103,6 +105,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + { + .id = QCA6174_HW_3_0_VERSION, +@@ -121,6 +124,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + { + .id = QCA6174_HW_3_2_VERSION, +@@ -140,6 +144,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + { + .id = QCA99X0_HW_2_0_DEV_VERSION, +@@ -159,6 +164,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA99X0_BOARD_DATA_SZ, + .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 1, + }, + { + .id = QCA9377_HW_1_0_DEV_VERSION, +@@ -177,6 +183,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA9377_BOARD_DATA_SZ, + .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + { + .id = QCA9377_HW_1_1_DEV_VERSION, +@@ -195,6 +202,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .board_size = QCA9377_BOARD_DATA_SZ, + .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, + }, ++ .decap_align_bytes = 4, + }, + }; + +@@ -548,8 +556,11 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) + "boot get otp board id result 0x%08x board_id %d chip_id %d\n", + result, board_id, chip_id); + +- if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0) ++ if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 || ++ (board_id == 0)) { ++ ath10k_warn(ar, "board id is not exist in otp, ignore it\n"); + return -EOPNOTSUPP; ++ } + + ar->id.bmi_ids_valid = true; + ar->id.bmi_board_id = board_id; +@@ -1607,6 +1618,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) + goto err_wmi_detach; + } + ++ /* If firmware indicates Full Rx Reorder support it must be used in a ++ * slightly different manner. Let HTT code know. ++ */ ++ ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, ++ ar->wmi.svc_map)); ++ + status = ath10k_htt_rx_alloc(&ar->htt); + if (status) { + ath10k_err(ar, "failed to alloc htt rx: %d\n", status); +@@ -1669,12 +1686,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) + goto err_hif_stop; + } + +- /* If firmware indicates Full Rx Reorder support it must be used in a +- * slightly different manner. Let HTT code know. +- */ +- ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, +- ar->wmi.svc_map)); +- + status = ath10k_htt_rx_ring_refill(ar); + if (status) { + ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); +diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h +index 858d75f4..257836a0 100644 +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -670,6 +670,10 @@ struct ath10k { + size_t board_size; + size_t board_ext_size; + } fw; ++ ++ /* Number of bytes used for alignment in rx_hdr_status */ ++ int decap_align_bytes; ++ + } hw_params; + + const struct firmware *board; +diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c +index 1a88a24f..30c35756 100644 +--- a/drivers/net/wireless/ath/ath10k/debug.c ++++ b/drivers/net/wireless/ath/ath10k/debug.c +@@ -1892,6 +1892,15 @@ static ssize_t ath10k_write_simulate_radar(struct file *file, + size_t count, loff_t *ppos) + { + struct ath10k *ar = file->private_data; ++ struct ath10k_vif *arvif; ++ ++ /* Just check for for the first vif alone, as all the vifs will be ++ * sharing the same channel and if the channel is disabled, all the ++ * vifs will share the same 'is_started' state. ++ */ ++ arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); ++ if (!arvif->is_started) ++ return -EINVAL; + + ieee80211_radar_detected(ar->hw); + +diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c +index 6060dda4..a65b5d7f 100644 +--- a/drivers/net/wireless/ath/ath10k/htt_rx.c ++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c +@@ -212,11 +212,12 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar) + spin_lock_bh(&htt->rx_ring.lock); + ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level - + htt->rx_ring.fill_cnt)); +- spin_unlock_bh(&htt->rx_ring.lock); + + if (ret) + ath10k_htt_rx_ring_free(htt); + ++ spin_unlock_bh(&htt->rx_ring.lock); ++ + return ret; + } + +@@ -230,7 +231,9 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) + skb_queue_purge(&htt->rx_compl_q); + skb_queue_purge(&htt->rx_in_ord_compl_q); + ++ spin_lock_bh(&htt->rx_ring.lock); + ath10k_htt_rx_ring_free(htt); ++ spin_unlock_bh(&htt->rx_ring.lock); + + dma_free_coherent(htt->ar->dev, + (htt->rx_ring.size * +@@ -979,7 +982,7 @@ static void ath10k_process_rx(struct ath10k *ar, + *status = *rx_status; + + ath10k_dbg(ar, ATH10K_DBG_DATA, +- "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", ++ "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%llx fcs-err %i mic-err %i amsdu-more %i\n", + skb, + skb->len, + ieee80211_get_SA(hdr), +@@ -1076,7 +1079,21 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, + hdr = (void *)msdu->data; + + /* Tail */ +- skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype)); ++ if (status->flag & RX_FLAG_IV_STRIPPED) { ++ skb_trim(msdu, msdu->len - ++ ath10k_htt_rx_crypto_tail_len(ar, enctype)); ++ } else { ++ /* MIC */ ++ if ((status->flag & RX_FLAG_MIC_STRIPPED) && ++ enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) ++ skb_trim(msdu, msdu->len - 8); ++ ++ /* ICV */ ++ if (status->flag & RX_FLAG_ICV_STRIPPED && ++ enctype != HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) ++ skb_trim(msdu, msdu->len - ++ ath10k_htt_rx_crypto_tail_len(ar, enctype)); ++ } + + /* MMIC */ + if (!ieee80211_has_morefrags(hdr->frame_control) && +@@ -1095,12 +1112,14 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, + static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, +- const u8 first_hdr[64]) ++ const u8 first_hdr[64], ++ enum htt_rx_mpdu_encrypt_type enctype) + { + struct ieee80211_hdr *hdr; + size_t hdr_len; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; ++ int bytes_aligned = ar->hw_params.decap_align_bytes; + + /* Delivered decapped frame: + * [nwifi 802.11 header] <-- replaced with 802.11 hdr +@@ -1123,6 +1142,14 @@ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar, + /* push original 802.11 header */ + hdr = (struct ieee80211_hdr *)first_hdr; + hdr_len = ieee80211_hdrlen(hdr->frame_control); ++ ++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) { ++ memcpy(skb_push(msdu, ++ ath10k_htt_rx_crypto_param_len(ar, enctype)), ++ (void *)hdr + round_up(hdr_len, bytes_aligned), ++ ath10k_htt_rx_crypto_param_len(ar, enctype)); ++ } ++ + memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); + + /* original 802.11 header has a different DA and in +@@ -1142,6 +1169,7 @@ static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, + size_t hdr_len, crypto_len; + void *rfc1042; + bool is_first, is_last, is_amsdu; ++ int bytes_aligned = ar->hw_params.decap_align_bytes; + + rxd = (void *)msdu->data - sizeof(*rxd); + hdr = (void *)rxd->rx_hdr_status; +@@ -1158,8 +1186,8 @@ static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, + hdr_len = ieee80211_hdrlen(hdr->frame_control); + crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); + +- rfc1042 += round_up(hdr_len, 4) + +- round_up(crypto_len, 4); ++ rfc1042 += round_up(hdr_len, bytes_aligned) + ++ round_up(crypto_len, bytes_aligned); + } + + if (is_amsdu) +@@ -1180,6 +1208,7 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar, + void *rfc1042; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; ++ int bytes_aligned = ar->hw_params.decap_align_bytes; + + /* Delivered decapped frame: + * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc +@@ -1203,6 +1232,14 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar, + /* push original 802.11 header */ + hdr = (struct ieee80211_hdr *)first_hdr; + hdr_len = ieee80211_hdrlen(hdr->frame_control); ++ ++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) { ++ memcpy(skb_push(msdu, ++ ath10k_htt_rx_crypto_param_len(ar, enctype)), ++ (void *)hdr + round_up(hdr_len, bytes_aligned), ++ ath10k_htt_rx_crypto_param_len(ar, enctype)); ++ } ++ + memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); + + /* original 802.11 header has a different DA and in +@@ -1216,10 +1253,12 @@ static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar, + static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar, + struct sk_buff *msdu, + struct ieee80211_rx_status *status, +- const u8 first_hdr[64]) ++ const u8 first_hdr[64], ++ enum htt_rx_mpdu_encrypt_type enctype) + { + struct ieee80211_hdr *hdr; + size_t hdr_len; ++ int bytes_aligned = ar->hw_params.decap_align_bytes; + + /* Delivered decapped frame: + * [amsdu header] <-- replaced with 802.11 hdr +@@ -1231,6 +1270,14 @@ static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar, + + hdr = (struct ieee80211_hdr *)first_hdr; + hdr_len = ieee80211_hdrlen(hdr->frame_control); ++ ++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) { ++ memcpy(skb_push(msdu, ++ ath10k_htt_rx_crypto_param_len(ar, enctype)), ++ (void *)hdr + round_up(hdr_len, bytes_aligned), ++ ath10k_htt_rx_crypto_param_len(ar, enctype)); ++ } ++ + memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); + } + +@@ -1265,13 +1312,15 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, + is_decrypted); + break; + case RX_MSDU_DECAP_NATIVE_WIFI: +- ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr); ++ ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr, ++ enctype); + break; + case RX_MSDU_DECAP_ETHERNET2_DIX: + ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype); + break; + case RX_MSDU_DECAP_8023_SNAP_LLC: +- ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr); ++ ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr, ++ enctype); + break; + } + } +@@ -1314,7 +1363,8 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) + + static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, + struct sk_buff_head *amsdu, +- struct ieee80211_rx_status *status) ++ struct ieee80211_rx_status *status, ++ bool fill_crypt_header) + { + struct sk_buff *first; + struct sk_buff *last; +@@ -1324,7 +1374,6 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, + enum htt_rx_mpdu_encrypt_type enctype; + u8 first_hdr[64]; + u8 *qos; +- size_t hdr_len; + bool has_fcs_err; + bool has_crypto_err; + bool has_tkip_err; +@@ -1345,15 +1394,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, + * decapped header. It'll be used for undecapping of each MSDU. + */ + hdr = (void *)rxd->rx_hdr_status; +- hdr_len = ieee80211_hdrlen(hdr->frame_control); +- memcpy(first_hdr, hdr, hdr_len); ++ memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN); + + /* Each A-MSDU subframe will use the original header as the base and be + * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl. + */ + hdr = (void *)first_hdr; +- qos = ieee80211_get_qos_ctl(hdr); +- qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; ++ ++ if (ieee80211_is_data_qos(hdr->frame_control)) { ++ qos = ieee80211_get_qos_ctl(hdr); ++ qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; ++ } + + /* Some attention flags are valid only in the last MSDU. */ + last = skb_peek_tail(amsdu); +@@ -1387,11 +1438,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, + if (has_tkip_err) + status->flag |= RX_FLAG_MMIC_ERROR; + +- if (is_decrypted) ++ if (is_decrypted) { + status->flag |= RX_FLAG_DECRYPTED | +- RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; + ++ if (fill_crypt_header) ++ status->flag |= RX_FLAG_MIC_STRIPPED | ++ RX_FLAG_ICV_STRIPPED; ++ else ++ status->flag |= RX_FLAG_IV_STRIPPED; ++ } ++ + skb_queue_walk(amsdu, msdu) { + ath10k_htt_rx_h_csum_offload(msdu); + ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, +@@ -1404,6 +1461,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, + if (!is_decrypted) + continue; + ++ if (fill_crypt_header) ++ continue; ++ + hdr = (void *)msdu->data; + hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + } +@@ -1414,6 +1474,9 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar, + struct ieee80211_rx_status *status) + { + struct sk_buff *msdu; ++ struct sk_buff *first_subframe; ++ ++ first_subframe = skb_peek(amsdu); + + while ((msdu = __skb_dequeue(amsdu))) { + /* Setup per-MSDU flags */ +@@ -1422,6 +1485,13 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar, + else + status->flag |= RX_FLAG_AMSDU_MORE; + ++ if (msdu == first_subframe) { ++ first_subframe = NULL; ++ status->flag &= ~RX_FLAG_ALLOW_SAME_PN; ++ } else { ++ status->flag |= RX_FLAG_ALLOW_SAME_PN; ++ } ++ + ath10k_process_rx(ar, status, msdu); + } + } +@@ -1607,7 +1677,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, + ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); + ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); + ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); +- ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); ++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true); + ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); + } + +@@ -1653,7 +1723,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, + + ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); + ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); +- ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); ++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true); + ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); + + if (fw_desc_len > 0) { +@@ -1952,7 +2022,7 @@ static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) + */ + ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); + ath10k_htt_rx_h_filter(ar, &amsdu, status); +- ath10k_htt_rx_h_mpdu(ar, &amsdu, status); ++ ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false); + ath10k_htt_rx_h_deliver(ar, &amsdu, status); + break; + case -EAGAIN: +diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c +index 1e1bef34..398068ad 100644 +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -1127,6 +1127,36 @@ static int ath10k_monitor_recalc(struct ath10k *ar) + return ath10k_monitor_stop(ar); + } + ++static bool ath10k_mac_can_set_cts_prot(struct ath10k_vif *arvif) ++{ ++ struct ath10k *ar = arvif->ar; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ if (!arvif->is_started) { ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "defer cts setup, vdev is not ready yet\n"); ++ return false; ++ } ++ ++ return true; ++} ++ ++static int ath10k_mac_set_cts_prot(struct ath10k_vif *arvif) ++{ ++ struct ath10k *ar = arvif->ar; ++ u32 vdev_param; ++ ++ lockdep_assert_held(&ar->conf_mutex); ++ ++ vdev_param = ar->wmi.vdev_param->protection_mode; ++ ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_protection %d\n", ++ arvif->vdev_id, arvif->use_cts_prot); ++ ++ return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ++ arvif->use_cts_prot ? 1 : 0); ++} ++ + static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) + { + struct ath10k *ar = arvif->ar; +@@ -2871,6 +2901,13 @@ static int ath10k_update_channel_list(struct ath10k *ar) + passive = channel->flags & IEEE80211_CHAN_NO_IR; + ch->passive = passive; + ++ /* the firmware is ignoring the "radar" flag of the ++ * channel and is scanning actively using Probe Requests ++ * on "Radar detection"/DFS channels which are not ++ * marked as "available" ++ */ ++ ch->passive |= ch->chan_radar; ++ + ch->freq = channel->center_freq; + ch->band_center_freq1 = channel->center_freq; + ch->min_power = 0; +@@ -4180,7 +4217,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar) + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { +- WARN_ON(arvif->txpower < 0); ++ if (arvif->txpower <= 0) ++ continue; + + if (txpower == -1) + txpower = arvif->txpower; +@@ -4188,8 +4226,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar) + txpower = min(txpower, arvif->txpower); + } + +- if (WARN_ON(txpower == -1)) +- return -EINVAL; ++ if (txpower == -1) ++ return 0; + + ret = ath10k_mac_txpower_setup(ar, txpower); + if (ret) { +@@ -4432,7 +4470,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, + } + + ar->free_vdev_map &= ~(1LL << arvif->vdev_id); ++ spin_lock_bh(&ar->data_lock); + list_add(&arvif->list, &ar->arvifs); ++ spin_unlock_bh(&ar->data_lock); + + /* It makes no sense to have firmware do keepalives. mac80211 already + * takes care of this with idle connection polling. +@@ -4565,7 +4605,9 @@ err_peer_delete: + err_vdev_delete: + ath10k_wmi_vdev_delete(ar, arvif->vdev_id); + ar->free_vdev_map |= 1LL << arvif->vdev_id; ++ spin_lock_bh(&ar->data_lock); + list_del(&arvif->list); ++ spin_unlock_bh(&ar->data_lock); + + err: + if (arvif->beacon_buf) { +@@ -4609,7 +4651,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, + arvif->vdev_id, ret); + + ar->free_vdev_map |= 1LL << arvif->vdev_id; ++ spin_lock_bh(&ar->data_lock); + list_del(&arvif->list); ++ spin_unlock_bh(&ar->data_lock); + + if (arvif->vdev_type == WMI_VDEV_TYPE_AP || + arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { +@@ -4787,20 +4831,18 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + arvif->use_cts_prot = info->use_cts_prot; +- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n", +- arvif->vdev_id, info->use_cts_prot); + + ret = ath10k_recalc_rtscts_prot(arvif); + if (ret) + ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); + +- vdev_param = ar->wmi.vdev_param->protection_mode; +- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, +- info->use_cts_prot ? 1 : 0); +- if (ret) +- ath10k_warn(ar, "failed to set protection mode %d on vdev %i: %d\n", +- info->use_cts_prot, arvif->vdev_id, ret); ++ if (ath10k_mac_can_set_cts_prot(arvif)) { ++ ret = ath10k_mac_set_cts_prot(arvif); ++ if (ret) ++ ath10k_warn(ar, "failed to set cts protection for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ } + } + + if (changed & BSS_CHANGED_ERP_SLOT) { +@@ -5256,9 +5298,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) + sta->addr, smps, err); + } + +- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || +- changed & IEEE80211_RC_NSS_CHANGED) { +- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", ++ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", + sta->addr); + + err = ath10k_station_assoc(ar, arvif->vif, sta, true); +@@ -5468,6 +5509,16 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, + "mac vdev %d peer delete %pM (sta gone)\n", + arvif->vdev_id, sta->addr); + ++ if (sta->tdls) { ++ ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, ++ sta, ++ WMI_TDLS_PEER_STATE_TEARDOWN); ++ if (ret) ++ ath10k_warn(ar, "failed to update tdls peer state for %pM state %d: %i\n", ++ sta->addr, ++ WMI_TDLS_PEER_STATE_TEARDOWN, ret); ++ } ++ + ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); + if (ret) + ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", +@@ -6273,10 +6324,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, + { + struct ath10k *ar = hw->priv; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; ++ struct ath10k_vif *arvif = (void *)vif->drv_priv; ++ struct ath10k_peer *peer; + u32 bw, smps; + + spin_lock_bh(&ar->data_lock); + ++ peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); ++ if (!peer) { ++ spin_unlock_bh(&ar->data_lock); ++ ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n", ++ sta->addr, arvif->vdev_id); ++ return; ++ } ++ + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", + sta->addr, changed, sta->bandwidth, sta->rx_nss, +@@ -6351,12 +6412,13 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) + + static int ath10k_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", + arvif->vdev_id, sta->addr, tid, action); +@@ -6397,7 +6459,7 @@ ath10k_mac_update_rx_channel(struct ath10k *ar, + lockdep_assert_held(&ar->data_lock); + + WARN_ON(ctx && vifs); +- WARN_ON(vifs && n_vifs != 1); ++ WARN_ON(vifs && !n_vifs); + + /* FIXME: Sort of an optimization and a workaround. Peers and vifs are + * on a linked list now. Doing a lookup peer -> vif -> chanctx for each +@@ -6711,6 +6773,13 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, + arvif->is_up = true; + } + ++ if (ath10k_mac_can_set_cts_prot(arvif)) { ++ ret = ath10k_mac_set_cts_prot(arvif); ++ if (ret) ++ ath10k_warn(ar, "failed to set cts protection for vdev %d: %d\n", ++ arvif->vdev_id, ret); ++ } ++ + mutex_unlock(&ar->conf_mutex); + return 0; + +diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c +index 930785a7..907fd60c 100644 +--- a/drivers/net/wireless/ath/ath10k/pci.c ++++ b/drivers/net/wireless/ath/ath10k/pci.c +@@ -3050,7 +3050,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, + goto err_core_destroy; + } + +- if (QCA_REV_6174(ar)) ++ if (QCA_REV_6174(ar) || QCA_REV_9377(ar)) + ath10k_pci_override_ce_config(ar); + + ret = ath10k_pci_alloc_pipes(ar); +diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c +index 4671cfbc..a0e7eebc 100644 +--- a/drivers/net/wireless/ath/ath10k/spectral.c ++++ b/drivers/net/wireless/ath/ath10k/spectral.c +@@ -338,7 +338,7 @@ static ssize_t write_file_spec_scan_ctl(struct file *file, + } else { + res = -EINVAL; + } +- } else if (strncmp("background", buf, 9) == 0) { ++ } else if (strncmp("background", buf, 10) == 0) { + res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND); + } else if (strncmp("manual", buf, 6) == 0) { + res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL); +diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h +index 71bdb368..0194bebb 100644 +--- a/drivers/net/wireless/ath/ath10k/trace.h ++++ b/drivers/net/wireless/ath/ath10k/trace.h +@@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump, + ); + + TRACE_EVENT(ath10k_wmi_cmd, +- TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, +- int ret), ++ TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len), + +- TP_ARGS(ar, id, buf, buf_len, ret), ++ TP_ARGS(ar, id, buf, buf_len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) +@@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd, + __field(unsigned int, id) + __field(size_t, buf_len) + __dynamic_array(u8, buf, buf_len) +- __field(int, ret) + ), + + TP_fast_assign( +@@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd, + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->id = id; + __entry->buf_len = buf_len; +- __entry->ret = ret; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), + + TP_printk( +- "%s %s id %d len %zu ret %d", ++ "%s %s id %d len %zu", + __get_str(driver), + __get_str(device), + __entry->id, +- __entry->buf_len, +- __entry->ret ++ __entry->buf_len + ) + ); + +diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h +index 8f4f6a89..cfed5808 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h ++++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h +@@ -639,6 +639,9 @@ ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, + struct sk_buff *skb; + u32 cmd_id; + ++ if (!ar->wmi.ops->gen_vdev_spectral_conf) ++ return -EOPNOTSUPP; ++ + skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); +@@ -654,6 +657,9 @@ ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, + struct sk_buff *skb; + u32 cmd_id; + ++ if (!ar->wmi.ops->gen_vdev_spectral_enable) ++ return -EOPNOTSUPP; ++ + skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger, + enable); + if (IS_ERR(skb)) +diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +index 6fbd17b6..c27fff39 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -1105,8 +1105,10 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, + struct ath10k_fw_stats_pdev *dst; + + src = data; +- if (data_len < sizeof(*src)) ++ if (data_len < sizeof(*src)) { ++ kfree(tb); + return -EPROTO; ++ } + + data += sizeof(*src); + data_len -= sizeof(*src); +@@ -1126,8 +1128,10 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, + struct ath10k_fw_stats_vdev *dst; + + src = data; +- if (data_len < sizeof(*src)) ++ if (data_len < sizeof(*src)) { ++ kfree(tb); + return -EPROTO; ++ } + + data += sizeof(*src); + data_len -= sizeof(*src); +@@ -1145,8 +1149,10 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, + struct ath10k_fw_stats_peer *dst; + + src = data; +- if (data_len < sizeof(*src)) ++ if (data_len < sizeof(*src)) { ++ kfree(tb); + return -EPROTO; ++ } + + data += sizeof(*src); + data_len -= sizeof(*src); +@@ -1418,6 +1424,11 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) + cfg->keep_alive_pattern_size = __cpu_to_le32(0); + cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1); + cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1); ++ cfg->wmi_send_separate = __cpu_to_le32(0); ++ cfg->num_ocb_vdevs = __cpu_to_le32(0); ++ cfg->num_ocb_channels = __cpu_to_le32(0); ++ cfg->num_ocb_schedules = __cpu_to_le32(0); ++ cfg->host_capab = __cpu_to_le32(0); + + ath10k_wmi_put_host_mem_chunks(ar, chunks); + +@@ -1448,10 +1459,10 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, + bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr); + ie_len = roundup(arg->ie_len, 4); + len = (sizeof(*tlv) + sizeof(*cmd)) + +- (arg->n_channels ? sizeof(*tlv) + chan_len : 0) + +- (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) + +- (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) + +- (arg->ie_len ? sizeof(*tlv) + ie_len : 0); ++ sizeof(*tlv) + chan_len + ++ sizeof(*tlv) + ssid_len + ++ sizeof(*tlv) + bssid_len + ++ sizeof(*tlv) + ie_len; + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) +diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h +index ad655c44..f5031f39 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h +@@ -1209,6 +1209,11 @@ struct wmi_tlv_resource_config { + __le32 keep_alive_pattern_size; + __le32 max_tdls_concurrent_sleep_sta; + __le32 max_tdls_concurrent_buffer_sta; ++ __le32 wmi_send_separate; ++ __le32 num_ocb_vdevs; ++ __le32 num_ocb_channels; ++ __le32 num_ocb_schedules; ++ __le32 host_capab; + } __packed; + + struct wmi_tlv_init_cmd { +diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c +index 7569db0f..b867875a 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -1642,8 +1642,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, + cmd_hdr->cmd_id = __cpu_to_le32(cmd); + + memset(skb_cb, 0, sizeof(*skb_cb)); ++ trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len); + ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); +- trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret); + + if (ret) + goto err_pull; +@@ -1749,6 +1749,12 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) + if (ret) + dev_kfree_skb_any(skb); + ++ if (ret == -EAGAIN) { ++ ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n", ++ cmd_id); ++ queue_work(ar->workqueue, &ar->restart_work); ++ } ++ + return ret; + } + +@@ -4059,7 +4065,7 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar, + rate_code[i], + type); + snprintf(buff, sizeof(buff), "%8d ", tpc[j]); +- strncat(tpc_value, buff, strlen(buff)); ++ strlcat(tpc_value, buff, sizeof(tpc_value)); + } + tpc_stats->tpc_table[type].pream_idx[i] = pream_idx; + tpc_stats->tpc_table[type].rate_code[i] = rate_code[i]; +diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h +index 72a4ef70..a8b2553e 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi.h ++++ b/drivers/net/wireless/ath/ath10k/wmi.h +@@ -4826,7 +4826,8 @@ enum wmi_10_4_vdev_param { + #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) + + #define WMI_TXBF_STS_CAP_OFFSET_LSB 4 +-#define WMI_TXBF_STS_CAP_OFFSET_MASK 0xf0 ++#define WMI_TXBF_STS_CAP_OFFSET_MASK 0x70 ++#define WMI_TXBF_CONF_IMPLICIT_BF BIT(7) + #define WMI_BF_SOUND_DIM_OFFSET_LSB 8 + #define WMI_BF_SOUND_DIM_OFFSET_MASK 0xf00 + +diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c +index 654a1e33..7c5f189c 100644 +--- a/drivers/net/wireless/ath/ath5k/debug.c ++++ b/drivers/net/wireless/ath/ath5k/debug.c +@@ -939,7 +939,10 @@ static int open_file_eeprom(struct inode *inode, struct file *file) + } + + for (i = 0; i < eesize; ++i) { +- AR5K_EEPROM_READ(i, val); ++ if (!ath5k_hw_nvram_read(ah, i, &val)) { ++ ret = -EIO; ++ goto freebuf; ++ } + buf[i] = val; + } + +diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c +index dc44cfef..16e052d0 100644 +--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c ++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c +@@ -502,8 +502,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + break; + return -EOPNOTSUPP; + default: +- WARN_ON(1); +- return -EINVAL; ++ return -EOPNOTSUPP; + } + + mutex_lock(&ah->lock); +diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +index 694ca2e6..74670e08 100644 +--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h ++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +@@ -73,13 +73,13 @@ + #define AR9300_OTP_BASE \ + ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000) + #define AR9300_OTP_STATUS \ +- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18) ++ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x31018 : 0x15f18) + #define AR9300_OTP_STATUS_TYPE 0x7 + #define AR9300_OTP_STATUS_VALID 0x4 + #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 + #define AR9300_OTP_STATUS_SM_BUSY 0x1 + #define AR9300_OTP_READ_DATA \ +- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c) ++ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3101c : 0x15f1c) + + enum targetPowerHTRates { + HT_TARGET_RATE_0_8_16, +diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +index 201425e7..fbc8c9a9 100644 +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -1815,8 +1815,6 @@ static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah) + static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum) + { + REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR); +- REG_SET_BIT(ah, 0x9864, 0x7f000); +- REG_SET_BIT(ah, 0x9924, 0x7f00fe); + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + REG_WRITE(ah, AR_CR, AR_CR_RXD); + REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); +diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h +index b42f4a96..a660e40f 100644 +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -959,6 +959,7 @@ struct ath_softc { + struct survey_info *cur_survey; + struct survey_info survey[ATH9K_NUM_CHANNELS]; + ++ spinlock_t intr_lock; + struct tasklet_struct intr_tq; + struct tasklet_struct bcon_tasklet; + struct ath_hw *sc_ah; +diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c +index a8762711..03945731 100644 +--- a/drivers/net/wireless/ath/ath9k/common-spectral.c ++++ b/drivers/net/wireless/ath/ath9k/common-spectral.c +@@ -528,6 +528,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) + return 0; + ++ if (!spec_priv->rfs_chan_spec_scan) ++ return 1; ++ + /* Output buffers are full, no need to process anything + * since there is no space to put the result anyway + */ +@@ -1072,7 +1075,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = { + + void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) + { +- if (config_enabled(CONFIG_ATH9K_DEBUGFS)) { ++ if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) { + relay_close(spec_priv->rfs_chan_spec_scan); + spec_priv->rfs_chan_spec_scan = NULL; + } +@@ -1086,6 +1089,9 @@ void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, + debugfs_phy, + 1024, 256, &rfs_spec_scan_cb, + NULL); ++ if (!spec_priv->rfs_chan_spec_scan) ++ return; ++ + debugfs_create_file("spectral_scan_ctl", + S_IRUSR | S_IWUSR, + debugfs_phy, spec_priv, +diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c +index 165dd202..c92564b3 100644 +--- a/drivers/net/wireless/ath/ath9k/hif_usb.c ++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c +@@ -37,6 +37,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { + { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */ + { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ + { USB_DEVICE(0x0471, 0x209e) }, /* Philips (or NXP) PTA01 */ ++ { USB_DEVICE(0x1eda, 0x2315) }, /* AirTies */ + + { USB_DEVICE(0x0cf3, 0x7015), + .driver_info = AR9287_USB }, /* Atheros */ +@@ -1216,6 +1217,9 @@ static int send_eject_command(struct usb_interface *interface) + u8 bulk_out_ep; + int r; + ++ if (iface_desc->desc.bNumEndpoints < 2) ++ return -ENODEV; ++ + /* Find bulk out endpoint */ + for (r = 1; r >= 0; r--) { + endpoint = &iface_desc->endpoint[r].desc; +diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c +index a680a970..e4281438 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c +@@ -1657,13 +1657,14 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, + + static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, +- u16 tid, u16 *ssn, u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_sta *ista; + int ret = 0; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; + + mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); +diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c +index 41382f89..4435c7bb 100644 +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1595,6 +1595,10 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) + int count = 50; + u32 reg, last_val; + ++ /* Check if chip failed to wake up */ ++ if (REG_READ(ah, AR_CFG) == 0xdeadbeef) ++ return false; ++ + if (AR_SREV_9300(ah)) + return !ath9k_hw_detect_mac_hang(ah); + +diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c +index bc70ce62..0f5672f5 100644 +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -619,6 +619,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, + common->bt_ant_diversity = 1; + + spin_lock_init(&common->cc_lock); ++ spin_lock_init(&sc->intr_lock); + spin_lock_init(&sc->sc_serial_rw); + spin_lock_init(&sc->sc_pm_lock); + spin_lock_init(&sc->chan_lock); +diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c +index bba85d1a..d937c39b 100644 +--- a/drivers/net/wireless/ath/ath9k/mac.c ++++ b/drivers/net/wireless/ath/ath9k/mac.c +@@ -805,21 +805,12 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) + } + EXPORT_SYMBOL(ath9k_hw_disable_interrupts); + +-void ath9k_hw_enable_interrupts(struct ath_hw *ah) ++static void __ath9k_hw_enable_interrupts(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); + u32 sync_default = AR_INTR_SYNC_DEFAULT; + u32 async_mask; + +- if (!(ah->imask & ATH9K_INT_GLOBAL)) +- return; +- +- if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { +- ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", +- atomic_read(&ah->intr_ref_cnt)); +- return; +- } +- + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; +@@ -841,6 +832,39 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) + ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); + } ++ ++void ath9k_hw_resume_interrupts(struct ath_hw *ah) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ ++ if (!(ah->imask & ATH9K_INT_GLOBAL)) ++ return; ++ ++ if (atomic_read(&ah->intr_ref_cnt) != 0) { ++ ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", ++ atomic_read(&ah->intr_ref_cnt)); ++ return; ++ } ++ ++ __ath9k_hw_enable_interrupts(ah); ++} ++EXPORT_SYMBOL(ath9k_hw_resume_interrupts); ++ ++void ath9k_hw_enable_interrupts(struct ath_hw *ah) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ ++ if (!(ah->imask & ATH9K_INT_GLOBAL)) ++ return; ++ ++ if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { ++ ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", ++ atomic_read(&ah->intr_ref_cnt)); ++ return; ++ } ++ ++ __ath9k_hw_enable_interrupts(ah); ++} + EXPORT_SYMBOL(ath9k_hw_enable_interrupts); + + void ath9k_hw_set_interrupts(struct ath_hw *ah) +diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h +index 7fbf7f96..1b63d26f 100644 +--- a/drivers/net/wireless/ath/ath9k/mac.h ++++ b/drivers/net/wireless/ath/ath9k/mac.h +@@ -748,6 +748,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah); + void ath9k_hw_enable_interrupts(struct ath_hw *ah); + void ath9k_hw_disable_interrupts(struct ath_hw *ah); + void ath9k_hw_kill_interrupts(struct ath_hw *ah); ++void ath9k_hw_resume_interrupts(struct ath_hw *ah); + + void ar9002_hw_attach_mac_ops(struct ath_hw *ah); + +diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c +index 8c5d2cf9..3abc6457 100644 +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -373,21 +373,20 @@ void ath9k_tasklet(unsigned long data) + struct ath_common *common = ath9k_hw_common(ah); + enum ath_reset_type type; + unsigned long flags; +- u32 status = sc->intrstatus; ++ u32 status; + u32 rxmask; + ++ spin_lock_irqsave(&sc->intr_lock, flags); ++ status = sc->intrstatus; ++ sc->intrstatus = 0; ++ spin_unlock_irqrestore(&sc->intr_lock, flags); ++ + ath9k_ps_wakeup(sc); + spin_lock(&sc->sc_pcu_lock); + + if (status & ATH9K_INT_FATAL) { + type = RESET_TYPE_FATAL_INT; + ath9k_queue_reset(sc, type); +- +- /* +- * Increment the ref. counter here so that +- * interrupts are enabled in the reset routine. +- */ +- atomic_inc(&ah->intr_ref_cnt); + ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); + goto out; + } +@@ -403,11 +402,6 @@ void ath9k_tasklet(unsigned long data) + type = RESET_TYPE_BB_WATCHDOG; + ath9k_queue_reset(sc, type); + +- /* +- * Increment the ref. counter here so that +- * interrupts are enabled in the reset routine. +- */ +- atomic_inc(&ah->intr_ref_cnt); + ath_dbg(common, RESET, + "BB_WATCHDOG: Skipping interrupts\n"); + goto out; +@@ -420,7 +414,6 @@ void ath9k_tasklet(unsigned long data) + if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) { + type = RESET_TYPE_TX_GTT; + ath9k_queue_reset(sc, type); +- atomic_inc(&ah->intr_ref_cnt); + ath_dbg(common, RESET, + "GTT: Skipping interrupts\n"); + goto out; +@@ -477,7 +470,7 @@ void ath9k_tasklet(unsigned long data) + ath9k_btcoex_handle_interrupt(sc, status); + + /* re-enable hardware interrupt */ +- ath9k_hw_enable_interrupts(ah); ++ ath9k_hw_resume_interrupts(ah); + out: + spin_unlock(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); +@@ -541,7 +534,9 @@ irqreturn_t ath_isr(int irq, void *dev) + return IRQ_NONE; + + /* Cache the status */ +- sc->intrstatus = status; ++ spin_lock(&sc->intr_lock); ++ sc->intrstatus |= status; ++ spin_unlock(&sc->intr_lock); + + if (status & SCHED_INTR) + sched = true; +@@ -587,7 +582,7 @@ chip_reset: + + if (sched) { + /* turn off every interrupt */ +- ath9k_hw_disable_interrupts(ah); ++ ath9k_hw_kill_interrupts(ah); + tasklet_schedule(&sc->intr_tq); + } + +@@ -1860,14 +1855,16 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) + + static int ath9k_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, +- u16 tid, u16 *ssn, u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool flush = false; + int ret = 0; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + + mutex_lock(&sc->mutex); + +diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c +index 7cdaf40c..ea7b8c25 100644 +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -27,7 +27,6 @@ static const struct pci_device_id ath_pci_id_table[] = { + { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ + { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ +- { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ + + #ifdef CONFIG_ATH9K_PCOEM + /* Mini PCI AR9220 MB92 cards: Compex WLM200NX, Wistron DNMA-92 */ +@@ -38,7 +37,7 @@ static const struct pci_device_id ath_pci_id_table[] = { + .driver_data = ATH9K_PCI_LED_ACT_HI }, + #endif + +- { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ ++ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ + + #ifdef CONFIG_ATH9K_PCOEM + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +@@ -86,7 +85,11 @@ static const struct pci_device_id ath_pci_id_table[] = { + 0x10CF, /* Fujitsu */ + 0x1536), + .driver_data = ATH9K_PCI_D3_L1_WAR }, ++#endif + ++ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ ++ ++#ifdef CONFIG_ATH9K_PCOEM + /* AR9285 card for Asus */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002B, +diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c +index ac4781f3..7ee1a318 100644 +--- a/drivers/net/wireless/ath/ath9k/tx99.c ++++ b/drivers/net/wireless/ath/ath9k/tx99.c +@@ -180,6 +180,9 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, + ssize_t len; + int r; + ++ if (count < 1) ++ return -EINVAL; ++ + if (sc->cur_chan->nvifs > 1) + return -EOPNOTSUPP; + +@@ -187,25 +190,32 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + ++ buf[len] = '\0'; ++ + if (strtobool(buf, &start)) + return -EINVAL; + ++ mutex_lock(&sc->mutex); ++ + if (start == sc->tx99_state) { + if (!start) +- return count; ++ goto out; + ath_dbg(common, XMIT, "Resetting TX99\n"); + ath9k_tx99_deinit(sc); + } + + if (!start) { + ath9k_tx99_deinit(sc); +- return count; ++ goto out; + } + + r = ath9k_tx99_init(sc); +- if (r) ++ if (r) { ++ mutex_unlock(&sc->mutex); + return r; +- ++ } ++out: ++ mutex_unlock(&sc->mutex); + return count; + } + +diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c +index 19d3d644..4d1527a2 100644 +--- a/drivers/net/wireless/ath/carl9170/main.c ++++ b/drivers/net/wireless/ath/carl9170/main.c +@@ -1413,10 +1413,12 @@ static void carl9170_ampdu_work(struct work_struct *work) + + static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, +- u16 tid, u16 *ssn, u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + struct ar9170 *ar = hw->priv; + struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; + struct carl9170_sta_tid *tid_info; +diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c +index 06ea6cc9..62077bda 100644 +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -254,8 +254,12 @@ bool ath_is_49ghz_allowed(u16 regdomain) + EXPORT_SYMBOL(ath_is_49ghz_allowed); + + /* Frequency is one where radar detection is required */ +-static bool ath_is_radar_freq(u16 center_freq) ++static bool ath_is_radar_freq(u16 center_freq, ++ struct ath_regulatory *reg) ++ + { ++ if (reg->country_code == CTRY_INDIA) ++ return (center_freq >= 5500 && center_freq <= 5700); + return (center_freq >= 5260 && center_freq <= 5700); + } + +@@ -306,7 +310,7 @@ __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, + struct ieee80211_channel *ch) + { +- if (ath_is_radar_freq(ch->center_freq) || ++ if (ath_is_radar_freq(ch->center_freq, reg) || + (ch->flags & IEEE80211_CHAN_RADAR)) + return; + +@@ -395,8 +399,9 @@ ath_reg_apply_ir_flags(struct wiphy *wiphy, + } + } + +-/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ +-static void ath_reg_apply_radar_flags(struct wiphy *wiphy) ++/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */ ++static void ath_reg_apply_radar_flags(struct wiphy *wiphy, ++ struct ath_regulatory *reg) + { + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; +@@ -409,7 +414,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; +- if (!ath_is_radar_freq(ch->center_freq)) ++ if (!ath_is_radar_freq(ch->center_freq, reg)) + continue; + /* We always enable radar detection/DFS on this + * frequency range. Additionally we also apply on +@@ -505,7 +510,7 @@ void ath_reg_notifier_apply(struct wiphy *wiphy, + struct ath_common *common = container_of(reg, struct ath_common, + regulatory); + /* We always apply this */ +- ath_reg_apply_radar_flags(wiphy); ++ ath_reg_apply_radar_flags(wiphy, reg); + + /* + * This would happen when we have sent a custom regulatory request +@@ -653,7 +658,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, + } + + wiphy_apply_custom_regulatory(wiphy, regd); +- ath_reg_apply_radar_flags(wiphy); ++ ath_reg_apply_radar_flags(wiphy, reg); + ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); + return 0; + } +diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h +index 37f53bd8..184b6810 100644 +--- a/drivers/net/wireless/ath/regd.h ++++ b/drivers/net/wireless/ath/regd.h +@@ -68,12 +68,14 @@ enum CountryCode { + CTRY_AUSTRALIA = 36, + CTRY_AUSTRIA = 40, + CTRY_AZERBAIJAN = 31, ++ CTRY_BAHAMAS = 44, + CTRY_BAHRAIN = 48, + CTRY_BANGLADESH = 50, + CTRY_BARBADOS = 52, + CTRY_BELARUS = 112, + CTRY_BELGIUM = 56, + CTRY_BELIZE = 84, ++ CTRY_BERMUDA = 60, + CTRY_BOLIVIA = 68, + CTRY_BOSNIA_HERZ = 70, + CTRY_BRAZIL = 76, +@@ -159,6 +161,7 @@ enum CountryCode { + CTRY_ROMANIA = 642, + CTRY_RUSSIA = 643, + CTRY_SAUDI_ARABIA = 682, ++ CTRY_SERBIA = 688, + CTRY_SERBIA_MONTENEGRO = 891, + CTRY_SINGAPORE = 702, + CTRY_SLOVAKIA = 703, +@@ -170,11 +173,13 @@ enum CountryCode { + CTRY_SWITZERLAND = 756, + CTRY_SYRIA = 760, + CTRY_TAIWAN = 158, ++ CTRY_TANZANIA = 834, + CTRY_THAILAND = 764, + CTRY_TRINIDAD_Y_TOBAGO = 780, + CTRY_TUNISIA = 788, + CTRY_TURKEY = 792, + CTRY_UAE = 784, ++ CTRY_UGANDA = 800, + CTRY_UKRAINE = 804, + CTRY_UNITED_KINGDOM = 826, + CTRY_UNITED_STATES = 840, +diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h +index bdd2b4d6..15bbd1e0 100644 +--- a/drivers/net/wireless/ath/regd_common.h ++++ b/drivers/net/wireless/ath/regd_common.h +@@ -35,6 +35,7 @@ enum EnumRd { + FRANCE_RES = 0x31, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, ++ FCC3_ETSIC = 0x3F, + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, +@@ -44,6 +45,7 @@ enum EnumRd { + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, ++ ETSI8_WORLD = 0x3D, + ETSI_RESERVED = 0x33, + + MKK1_MKKA = 0x40, +@@ -59,6 +61,7 @@ enum EnumRd { + MKK1_MKKA1 = 0x4A, + MKK1_MKKA2 = 0x4B, + MKK1_MKKC = 0x4C, ++ APL2_FCCA = 0x4D, + + APL3_FCCA = 0x50, + APL1_WORLD = 0x52, +@@ -67,6 +70,7 @@ enum EnumRd { + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, + APL5_WORLD = 0x58, ++ APL13_WORLD = 0x5A, + APL6_WORLD = 0x5B, + APL7_FCCA = 0x5C, + APL8_WORLD = 0x5D, +@@ -168,6 +172,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { + {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC3_FCCA, CTL_FCC, CTL_FCC}, + {FCC3_WORLD, CTL_FCC, CTL_ETSI}, ++ {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC4_FCCA, CTL_FCC, CTL_FCC}, + {FCC5_FCCA, CTL_FCC, CTL_FCC}, + {FCC6_FCCA, CTL_FCC, CTL_FCC}, +@@ -179,6 +184,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { + {ETSI4_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI5_WORLD, CTL_ETSI, CTL_ETSI}, + {ETSI6_WORLD, CTL_ETSI, CTL_ETSI}, ++ {ETSI8_WORLD, CTL_ETSI, CTL_ETSI}, + + /* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */ + {ETSI3_ETSIA, CTL_ETSI, CTL_ETSI}, +@@ -188,9 +194,11 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { + {FCC1_FCCA, CTL_FCC, CTL_FCC}, + {APL1_WORLD, CTL_FCC, CTL_ETSI}, + {APL2_WORLD, CTL_FCC, CTL_ETSI}, ++ {APL2_FCCA, CTL_FCC, CTL_FCC}, + {APL3_WORLD, CTL_FCC, CTL_ETSI}, + {APL4_WORLD, CTL_FCC, CTL_ETSI}, + {APL5_WORLD, CTL_FCC, CTL_ETSI}, ++ {APL13_WORLD, CTL_ETSI, CTL_ETSI}, + {APL6_WORLD, CTL_ETSI, CTL_ETSI}, + {APL8_WORLD, CTL_ETSI, CTL_ETSI}, + {APL9_WORLD, CTL_ETSI, CTL_ETSI}, +@@ -298,6 +306,7 @@ static struct country_code_to_enum_rd allCountries[] = { + {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, ++ {CTRY_BAHAMAS, FCC3_WORLD, "BS"}, + {CTRY_BAHRAIN, APL6_WORLD, "BH"}, + {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, + {CTRY_BARBADOS, FCC2_WORLD, "BB"}, +@@ -305,6 +314,7 @@ static struct country_code_to_enum_rd allCountries[] = { + {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, + {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, + {CTRY_BELIZE, APL1_ETSIC, "BZ"}, ++ {CTRY_BERMUDA, FCC3_FCCA, "BM"}, + {CTRY_BOLIVIA, APL1_ETSIC, "BO"}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"}, + {CTRY_BRAZIL, FCC3_WORLD, "BR"}, +@@ -444,6 +454,7 @@ static struct country_code_to_enum_rd allCountries[] = { + {CTRY_ROMANIA, NULL1_WORLD, "RO"}, + {CTRY_RUSSIA, NULL1_WORLD, "RU"}, + {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, ++ {CTRY_SERBIA, ETSI1_WORLD, "RS"}, + {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"}, + {CTRY_SINGAPORE, APL6_WORLD, "SG"}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK"}, +@@ -455,10 +466,12 @@ static struct country_code_to_enum_rd allCountries[] = { + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH"}, + {CTRY_SYRIA, NULL1_WORLD, "SY"}, + {CTRY_TAIWAN, APL3_FCCA, "TW"}, ++ {CTRY_TANZANIA, APL1_WORLD, "TZ"}, + {CTRY_THAILAND, FCC3_WORLD, "TH"}, + {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, + {CTRY_TURKEY, ETSI3_WORLD, "TR"}, ++ {CTRY_UGANDA, FCC3_WORLD, "UG"}, + {CTRY_UKRAINE, NULL1_WORLD, "UA"}, + {CTRY_UAE, NULL1_WORLD, "AE"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, +diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c +index 7c169abd..a27279c2 100644 +--- a/drivers/net/wireless/ath/wcn36xx/main.c ++++ b/drivers/net/wireless/ath/wcn36xx/main.c +@@ -857,12 +857,14 @@ static int wcn36xx_resume(struct ieee80211_hw *hw) + + static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct wcn36xx *wcn = hw->priv; + struct wcn36xx_sta *sta_priv = NULL; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", + action, tid); +diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c +index 9bec8237..99c21aac 100644 +--- a/drivers/net/wireless/ath/wcn36xx/txrx.c ++++ b/drivers/net/wireless/ath/wcn36xx/txrx.c +@@ -57,7 +57,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) + RX_FLAG_MMIC_STRIPPED | + RX_FLAG_DECRYPTED; + +- wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag); ++ wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%llx\n", status.flag); + + memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); + +diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c +index bb69a594..f09fafaa 100644 +--- a/drivers/net/wireless/ath/wil6210/main.c ++++ b/drivers/net/wireless/ath/wil6210/main.c +@@ -125,9 +125,15 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, + u32 *d = dst; + const volatile u32 __iomem *s = src; + +- /* size_t is unsigned, if (count%4 != 0) it will wrap */ +- for (count += 4; count > 4; count -= 4) ++ for (; count >= 4; count -= 4) + *d++ = __raw_readl(s++); ++ ++ if (unlikely(count)) { ++ /* count can be 1..3 */ ++ u32 tmp = __raw_readl(s); ++ ++ memcpy(d, &tmp, count); ++ } + } + + void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, +@@ -136,8 +142,16 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, + volatile u32 __iomem *d = dst; + const u32 *s = src; + +- for (count += 4; count > 4; count -= 4) ++ for (; count >= 4; count -= 4) + __raw_writel(*s++, d++); ++ ++ if (unlikely(count)) { ++ /* count can be 1..3 */ ++ u32 tmp = 0; ++ ++ memcpy(&tmp, s, count); ++ __raw_writel(tmp, d); ++ } + } + + static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, +@@ -330,18 +344,19 @@ static void wil_fw_error_worker(struct work_struct *work) + + wil->last_fw_recovery = jiffies; + ++ wil_info(wil, "fw error recovery requested (try %d)...\n", ++ wil->recovery_count); ++ if (!no_fw_recovery) ++ wil->recovery_state = fw_recovery_running; ++ if (wil_wait_for_recovery(wil) != 0) ++ return; ++ + mutex_lock(&wil->mutex); + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_MONITOR: +- wil_info(wil, "fw error recovery requested (try %d)...\n", +- wil->recovery_count); +- if (!no_fw_recovery) +- wil->recovery_state = fw_recovery_running; +- if (0 != wil_wait_for_recovery(wil)) +- break; +- ++ /* silent recovery, upper layers will see disconnect */ + __wil_down(wil); + __wil_up(wil); + break; +diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c +index 6ed26bac..7af8479a 100644 +--- a/drivers/net/wireless/ath/wil6210/wmi.c ++++ b/drivers/net/wireless/ath/wil6210/wmi.c +@@ -1035,8 +1035,14 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) + }; + int rc; + u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; +- struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); ++ struct wmi_set_appie_cmd *cmd; + ++ if (len < ie_len) { ++ rc = -EINVAL; ++ goto out; ++ } ++ ++ cmd = kzalloc(len, GFP_KERNEL); + if (!cmd) { + rc = -ENOMEM; + goto out; +diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c +index ec2b9c57..3644c9ed 100644 +--- a/drivers/net/wireless/b43/phy_common.c ++++ b/drivers/net/wireless/b43/phy_common.c +@@ -616,7 +616,7 @@ struct b43_c32 b43_cordic(int theta) + u8 i; + s32 tmp; + s8 signx = 1; +- u32 angle = 0; ++ s32 angle = 0; + struct b43_c32 ret = { .i = 39797, .q = 0, }; + + while (theta > (180 << 16)) +diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c +index 058a9f23..55cb0769 100644 +--- a/drivers/net/wireless/b43/phy_lp.c ++++ b/drivers/net/wireless/b43/phy_lp.c +@@ -1834,7 +1834,7 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains, + static void lpphy_papd_cal_txpwr(struct b43_wldev *dev) + { + struct b43_phy_lp *lpphy = dev->phy.lp; +- struct lpphy_tx_gains gains, oldgains; ++ struct lpphy_tx_gains oldgains; + int old_txpctl, old_afe_ovr, old_rf, old_bbmult; + + lpphy_read_tx_pctl_mode_from_hardware(dev); +@@ -1848,9 +1848,9 @@ static void lpphy_papd_cal_txpwr(struct b43_wldev *dev) + lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); + + if (dev->dev->chip_id == 0x4325 && dev->dev->chip_rev == 0) +- lpphy_papd_cal(dev, gains, 0, 1, 30); ++ lpphy_papd_cal(dev, oldgains, 0, 1, 30); + else +- lpphy_papd_cal(dev, gains, 0, 1, 65); ++ lpphy_papd_cal(dev, oldgains, 0, 1, 65); + + if (old_afe_ovr) + lpphy_set_tx_gains(dev, oldgains); +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +index 59cef6c6..72e1796c 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +@@ -705,7 +705,7 @@ done: + int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, + struct sk_buff_head *pktq, uint totlen) + { +- struct sk_buff *glom_skb; ++ struct sk_buff *glom_skb = NULL; + struct sk_buff *skb; + u32 addr = sdiodev->sbwad; + int err = 0; +@@ -726,10 +726,8 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, + return -ENOMEM; + err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, + glom_skb); +- if (err) { +- brcmu_pkt_buf_free_skb(glom_skb); ++ if (err) + goto done; +- } + + skb_queue_walk(pktq, skb) { + memcpy(skb->data, glom_skb->data, skb->len); +@@ -740,6 +738,7 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, + pktq); + + done: ++ brcmu_pkt_buf_free_skb(glom_skb); + return err; + } + +@@ -1109,6 +1108,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), ++ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43364), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345), +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h +index 230cad78..84b8b1ea 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h +@@ -214,7 +214,9 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, + int prec); + + /* Receive frame for delivery to OS. Callee disposes of rxp. */ +-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp); ++void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event); ++/* Receive async event packet from firmware. Callee disposes of rxp. */ ++void brcmf_rx_event(struct device *dev, struct sk_buff *rxp); + + /* Indication from bus module regarding presence/insertion of dongle. */ + int brcmf_attach(struct device *dev); +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +index 70a69853..231c0ba6 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +@@ -876,7 +876,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + + eth_broadcast_addr(params_le->bssid); + params_le->bss_type = DOT11_BSSTYPE_ANY; +- params_le->scan_type = 0; ++ params_le->scan_type = BRCMF_SCANTYPE_ACTIVE; + params_le->channel_num = 0; + params_le->nprobes = cpu_to_le32(-1); + params_le->active_time = cpu_to_le32(-1); +@@ -884,12 +884,9 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + params_le->home_time = cpu_to_le32(-1); + memset(¶ms_le->ssid_le, 0, sizeof(params_le->ssid_le)); + +- /* if request is null exit so it will be all channel broadcast scan */ +- if (!request) +- return; +- + n_ssids = request->n_ssids; + n_channels = request->n_channels; ++ + /* Copy channel array if applicable */ + brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n", + n_channels); +@@ -926,16 +923,8 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, + ptr += sizeof(ssid_le); + } + } else { +- brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids); +- if ((request->ssids) && request->ssids->ssid_len) { +- brcmf_dbg(SCAN, "SSID %s len=%d\n", +- params_le->ssid_le.SSID, +- request->ssids->ssid_len); +- params_le->ssid_le.SSID_len = +- cpu_to_le32(request->ssids->ssid_len); +- memcpy(¶ms_le->ssid_le.SSID, request->ssids->ssid, +- request->ssids->ssid_len); +- } ++ brcmf_dbg(SCAN, "Performing passive scan\n"); ++ params_le->scan_type = BRCMF_SCANTYPE_PASSIVE; + } + /* Adding mask to channel numbers */ + params_le->channel_num = +@@ -2914,6 +2903,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; + s32 status; + struct brcmf_escan_result_le *escan_result_le; ++ u32 escan_buflen; + struct brcmf_bss_info_le *bss_info_le; + struct brcmf_bss_info_le *bss = NULL; + u32 bi_length; +@@ -2930,11 +2920,23 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, + + if (status == BRCMF_E_STATUS_PARTIAL) { + brcmf_dbg(SCAN, "ESCAN Partial result\n"); ++ if (e->datalen < sizeof(*escan_result_le)) { ++ brcmf_err("invalid event data length\n"); ++ goto exit; ++ } + escan_result_le = (struct brcmf_escan_result_le *) data; + if (!escan_result_le) { + brcmf_err("Invalid escan result (NULL pointer)\n"); + goto exit; + } ++ escan_buflen = le32_to_cpu(escan_result_le->buflen); ++ if (escan_buflen > WL_ESCAN_BUF_SIZE || ++ escan_buflen > e->datalen || ++ escan_buflen < sizeof(*escan_result_le)) { ++ brcmf_err("Invalid escan buffer length: %d\n", ++ escan_buflen); ++ goto exit; ++ } + if (le16_to_cpu(escan_result_le->bss_count) != 1) { + brcmf_err("Invalid bss_count %d: ignoring\n", + escan_result_le->bss_count); +@@ -2951,9 +2953,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, + } + + bi_length = le32_to_cpu(bss_info_le->length); +- if (bi_length != (le32_to_cpu(escan_result_le->buflen) - +- WL_ESCAN_RESULTS_FIXED_SIZE)) { +- brcmf_err("Invalid bss_info length %d: ignoring\n", ++ if (bi_length != escan_buflen - WL_ESCAN_RESULTS_FIXED_SIZE) { ++ brcmf_err("Ignoring invalid bss_info length: %d\n", + bi_length); + goto exit; + } +@@ -3327,9 +3328,15 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, + struct brcmf_pno_scanresults_le *pfn_result; + u32 result_count; + u32 status; ++ u32 datalen; + + brcmf_dbg(SCAN, "Enter\n"); + ++ if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + if (e->event_code == BRCMF_E_PFN_NET_LOST) { + brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n"); + return 0; +@@ -3348,6 +3355,14 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, + if (result_count > 0) { + int i; + ++ data += sizeof(struct brcmf_pno_scanresults_le); ++ netinfo_start = (struct brcmf_pno_net_info_le *)data; ++ datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result); ++ if (datalen < result_count * sizeof(*netinfo)) { ++ brcmf_err("insufficient event data\n"); ++ goto out_err; ++ } ++ + request = kzalloc(sizeof(*request), GFP_KERNEL); + ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL); + channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL); +@@ -3357,9 +3372,6 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, + } + + request->wiphy = wiphy; +- data += sizeof(struct brcmf_pno_scanresults_le); +- netinfo_start = (struct brcmf_pno_net_info_le *)data; +- + for (i = 0; i < result_count; i++) { + netinfo = &netinfo_start[i]; + if (!netinfo) { +@@ -3369,6 +3381,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, + goto out_err; + } + ++ if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN) ++ netinfo->SSID_len = IEEE80211_MAX_SSID_LEN; + brcmf_dbg(SCAN, "SSID:%s Channel:%d\n", + netinfo->SSID, netinfo->channel); + memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len); +@@ -4294,9 +4308,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); + if (err < 0) + brcmf_err("setting AP mode failed %d\n", err); +- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); +- if (err < 0) +- brcmf_err("setting INFRA mode failed %d\n", err); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) + brcmf_fil_iovar_int_set(ifp, "mbss", 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, +@@ -4472,6 +4483,11 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, + GFP_KERNEL); + } else if (ieee80211_is_action(mgmt->frame_control)) { ++ if (len > BRCMF_FIL_ACTION_FRAME_SIZE + DOT11_MGMT_HDR_LEN) { ++ brcmf_err("invalid action frame length\n"); ++ err = -EINVAL; ++ goto exit; ++ } + af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); + if (af_params == NULL) { + brcmf_err("unable to allocate frame\n"); +@@ -4833,6 +4849,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, + conn_info->req_ie = + kmemdup(cfg->extra_buf, conn_info->req_ie_len, + GFP_KERNEL); ++ if (!conn_info->req_ie) ++ conn_info->req_ie_len = 0; + } else { + conn_info->req_ie_len = 0; + conn_info->req_ie = NULL; +@@ -4849,6 +4867,8 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, + conn_info->resp_ie = + kmemdup(cfg->extra_buf, conn_info->resp_ie_len, + GFP_KERNEL); ++ if (!conn_info->resp_ie) ++ conn_info->resp_ie_len = 0; + } else { + conn_info->resp_ie_len = 0; + conn_info->resp_ie = NULL; +@@ -6164,7 +6184,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + req->alpha2[0], req->alpha2[1]); + + /* ignore non-ISO3166 country codes */ +- for (i = 0; i < sizeof(req->alpha2); i++) ++ for (i = 0; i < 2; i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { + brcmf_err("not a ISO3166 code\n"); + return; +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c +index b5ab98ee..3082391c 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c +@@ -211,7 +211,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, + int ret; + struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_pub *drvr = ifp->drvr; +- struct ethhdr *eh = (struct ethhdr *)(skb->data); ++ struct ethhdr *eh; + + brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx); + +@@ -232,22 +232,13 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, + goto done; + } + +- /* Make sure there's enough room for any header */ +- if (skb_headroom(skb) < drvr->hdrlen) { +- struct sk_buff *skb2; +- +- brcmf_dbg(INFO, "%s: insufficient headroom\n", ++ /* Make sure there's enough writable headroom*/ ++ ret = skb_cow_head(skb, drvr->hdrlen); ++ if (ret < 0) { ++ brcmf_err("%s: skb_cow_head failed\n", + brcmf_ifname(drvr, ifp->bssidx)); +- drvr->bus_if->tx_realloc++; +- skb2 = skb_realloc_headroom(skb, drvr->hdrlen); + dev_kfree_skb(skb); +- skb = skb2; +- if (skb == NULL) { +- brcmf_err("%s: skb_realloc_headroom failed\n", +- brcmf_ifname(drvr, ifp->bssidx)); +- ret = -ENOMEM; +- goto done; +- } ++ goto done; + } + + /* validate length for ether packet */ +@@ -257,6 +248,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, + goto done; + } + ++ eh = (struct ethhdr *)(skb->data); ++ + if (eh->h_proto == htons(ETH_P_PAE)) + atomic_inc(&ifp->pend_8021x_cnt); + +@@ -310,15 +303,9 @@ void brcmf_txflowblock(struct device *dev, bool state) + + void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) + { +- skb->dev = ifp->ndev; +- skb->protocol = eth_type_trans(skb, skb->dev); +- + if (skb->pkt_type == PACKET_MULTICAST) + ifp->stats.multicast++; + +- /* Process special event packets */ +- brcmf_fweh_process_skb(ifp->drvr, skb); +- + if (!(ifp->ndev->flags & IFF_UP)) { + brcmu_pkt_buf_free_skb(skb); + return; +@@ -533,7 +520,7 @@ netif_rx: + } + } + +-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb) ++void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event) + { + struct brcmf_if *ifp; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); +@@ -553,11 +540,44 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb) + return; + } + ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ + rd = (struct brcmf_skb_reorder_data *)skb->cb; +- if (rd->reorder) ++ if (rd->reorder) { + brcmf_rxreorder_process_info(ifp, rd->reorder, skb); +- else ++ } else { ++ /* Process special event packets */ ++ if (handle_event) ++ brcmf_fweh_process_skb(ifp->drvr, skb, ++ BCMILCP_SUBTYPE_VENDOR_LONG); ++ + brcmf_netif_rx(ifp, skb); ++ } ++} ++ ++void brcmf_rx_event(struct device *dev, struct sk_buff *skb) ++{ ++ struct brcmf_if *ifp; ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_pub *drvr = bus_if->drvr; ++ int ret; ++ ++ brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb); ++ ++ /* process and remove protocol-specific header */ ++ ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); ++ ++ if (ret || !ifp || !ifp->ndev) { ++ if (ret != -ENODATA && ifp) ++ ifp->stats.rx_errors++; ++ brcmu_pkt_buf_free_skb(skb); ++ return; ++ } ++ ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ ++ brcmf_fweh_process_skb(ifp->drvr, skb, 0); ++ brcmu_pkt_buf_free_skb(skb); + } + + void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +index 3878b6f6..f9aa3703 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +@@ -25,50 +25,6 @@ + #include "fweh.h" + #include "fwil.h" + +-/** +- * struct brcm_ethhdr - broadcom specific ether header. +- * +- * @subtype: subtype for this packet. +- * @length: TODO: length of appended data. +- * @version: version indication. +- * @oui: OUI of this packet. +- * @usr_subtype: subtype for this OUI. +- */ +-struct brcm_ethhdr { +- __be16 subtype; +- __be16 length; +- u8 version; +- u8 oui[3]; +- __be16 usr_subtype; +-} __packed; +- +-struct brcmf_event_msg_be { +- __be16 version; +- __be16 flags; +- __be32 event_type; +- __be32 status; +- __be32 reason; +- __be32 auth_type; +- __be32 datalen; +- u8 addr[ETH_ALEN]; +- char ifname[IFNAMSIZ]; +- u8 ifidx; +- u8 bsscfgidx; +-} __packed; +- +-/** +- * struct brcmf_event - contents of broadcom event packet. +- * +- * @eth: standard ether header. +- * @hdr: broadcom specific ether header. +- * @msg: common part of the actual event message. +- */ +-struct brcmf_event { +- struct ethhdr eth; +- struct brcm_ethhdr hdr; +- struct brcmf_event_msg_be msg; +-} __packed; +- + /** + * struct brcmf_fweh_queue_item - event item on event queue. + * +@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item { + u8 ifidx; + u8 ifaddr[ETH_ALEN]; + struct brcmf_event_msg_be emsg; ++ u32 datalen; + u8 data[0]; + }; + +@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work) + brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data, + min_t(u32, emsg.datalen, 64), + "event payload, len=%d\n", emsg.datalen); ++ if (emsg.datalen > event->datalen) { ++ brcmf_err("event invalid length header=%d, msg=%d\n", ++ event->datalen, emsg.datalen); ++ goto event_free; ++ } + + /* special handling of interface event */ + if (event->code == BRCMF_E_IF) { +@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp) + * dispatch the event to a registered handler (using worker). + */ + void brcmf_fweh_process_event(struct brcmf_pub *drvr, +- struct brcmf_event *event_packet) ++ struct brcmf_event *event_packet, ++ u32 packet_len) + { + enum brcmf_fweh_event_code code; + struct brcmf_fweh_info *fweh = &drvr->fweh; +@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, + if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + return; + ++ if (datalen > BRCMF_DCMD_MAXLEN) ++ return; ++ + if (in_interrupt()) + alloc_flag = GFP_ATOMIC; + +@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, + /* use memcpy to get aligned event message */ + memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); + memcpy(event->data, data, datalen); ++ event->datalen = datalen; + memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); + + brcmf_fweh_queue_event(fweh, event); +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +index d9a94284..b53db923 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +@@ -27,7 +27,6 @@ + struct brcmf_pub; + struct brcmf_if; + struct brcmf_cfg80211_info; +-struct brcmf_event; + + /* list of firmware events */ + #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ +@@ -180,11 +179,53 @@ enum brcmf_fweh_event_code { + /** + * definitions for event packet validation. + */ +-#define BRCMF_EVENT_OUI_OFFSET 19 +-#define BRCM_OUI "\x00\x10\x18" +-#define DOT11_OUI_LEN 3 +-#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define BRCM_OUI "\x00\x10\x18" ++#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 + ++/** ++ * struct brcm_ethhdr - broadcom specific ether header. ++ * ++ * @subtype: subtype for this packet. ++ * @length: TODO: length of appended data. ++ * @version: version indication. ++ * @oui: OUI of this packet. ++ * @usr_subtype: subtype for this OUI. ++ */ ++struct brcm_ethhdr { ++ __be16 subtype; ++ __be16 length; ++ u8 version; ++ u8 oui[3]; ++ __be16 usr_subtype; ++} __packed; ++ ++struct brcmf_event_msg_be { ++ __be16 version; ++ __be16 flags; ++ __be32 event_type; ++ __be32 status; ++ __be32 reason; ++ __be32 auth_type; ++ __be32 datalen; ++ u8 addr[ETH_ALEN]; ++ char ifname[IFNAMSIZ]; ++ u8 ifidx; ++ u8 bsscfgidx; ++} __packed; ++ ++/** ++ * struct brcmf_event - contents of broadcom event packet. ++ * ++ * @eth: standard ether header. ++ * @hdr: broadcom specific ether header. ++ * @msg: common part of the actual event message. ++ */ ++struct brcmf_event { ++ struct ethhdr eth; ++ struct brcm_ethhdr hdr; ++ struct brcmf_event_msg_be msg; ++} __packed; + + /** + * struct brcmf_event_msg - firmware event message. +@@ -256,34 +297,43 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, + enum brcmf_fweh_event_code code); + int brcmf_fweh_activate_events(struct brcmf_if *ifp); + void brcmf_fweh_process_event(struct brcmf_pub *drvr, +- struct brcmf_event *event_packet); ++ struct brcmf_event *event_packet, ++ u32 packet_len); + void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing); + + static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr, +- struct sk_buff *skb) ++ struct sk_buff *skb, u16 stype) + { + struct brcmf_event *event_packet; +- u8 *data; +- u16 usr_stype; ++ u16 subtype, usr_stype; + + /* only process events when protocol matches */ + if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL)) + return; + +- /* check for BRCM oui match */ ++ if ((skb->len + ETH_HLEN) < sizeof(*event_packet)) ++ return; ++ + event_packet = (struct brcmf_event *)skb_mac_header(skb); +- data = (u8 *)event_packet; +- data += BRCMF_EVENT_OUI_OFFSET; +- if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN)) ++ ++ /* check subtype if needed */ ++ if (unlikely(stype)) { ++ subtype = get_unaligned_be16(&event_packet->hdr.subtype); ++ if (subtype != stype) ++ return; ++ } ++ ++ /* check for BRCM oui match */ ++ if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0], ++ sizeof(event_packet->hdr.oui))) + return; + + /* final match on usr_subtype */ +- data += DOT11_OUI_LEN; +- usr_stype = get_unaligned_be16(data); ++ usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype); + if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT) + return; + +- brcmf_fweh_process_event(drvr, event_packet); ++ brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN); + } + + #endif /* FWEH_H_ */ +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +index daa427b4..4320c4ca 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h ++++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +@@ -45,6 +45,11 @@ + #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff + #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 + ++/* scan type definitions */ ++#define BRCMF_SCANTYPE_DEFAULT 0xFF ++#define BRCMF_SCANTYPE_ACTIVE 0 ++#define BRCMF_SCANTYPE_PASSIVE 1 ++ + /* primary (ie tx) key */ + #define BRCMF_PRIMARY_KEY (1 << 1) + #define DOT11_BSSTYPE_ANY 2 +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +index 44e618f9..6f7138ce 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + #include + #include +@@ -1076,28 +1077,13 @@ static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf) + } + + +-static void +-brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb, +- u8 ifidx) +-{ +- struct brcmf_if *ifp; +- +- ifp = brcmf_get_ifp(msgbuf->drvr, ifidx); +- if (!ifp || !ifp->ndev) { +- brcmf_err("Received pkt for invalid ifidx %d\n", ifidx); +- brcmu_pkt_buf_free_skb(skb); +- return; +- } +- brcmf_netif_rx(ifp, skb); +-} +- +- + static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf) + { + struct msgbuf_rx_event *event; + u32 idx; + u16 buflen; + struct sk_buff *skb; ++ struct brcmf_if *ifp; + + event = (struct msgbuf_rx_event *)buf; + idx = le32_to_cpu(event->msg.request_id); +@@ -1117,7 +1103,19 @@ static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf) + + skb_trim(skb, buflen); + +- brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx); ++ ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx); ++ if (!ifp || !ifp->ndev) { ++ brcmf_err("Received pkt for invalid ifidx %d\n", ++ event->msg.ifidx); ++ goto exit; ++ } ++ ++ skb->protocol = eth_type_trans(skb, ifp->ndev); ++ ++ brcmf_fweh_process_skb(ifp->drvr, skb, 0); ++ ++exit: ++ brcmu_pkt_buf_free_skb(skb); + } + + +@@ -1129,6 +1127,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) + u16 data_offset; + u16 buflen; + u32 idx; ++ struct brcmf_if *ifp; + + brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1); + +@@ -1149,7 +1148,14 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) + + skb_trim(skb, buflen); + +- brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx); ++ ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx); ++ if (!ifp || !ifp->ndev) { ++ brcmf_err("Received pkt for invalid ifidx %d\n", ++ rx_complete->msg.ifidx); ++ brcmu_pkt_buf_free_skb(skb); ++ return; ++ } ++ brcmf_netif_rx(ifp, skb); + } + + +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +index d224b3dd..e6c8b0d5 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +@@ -461,25 +461,23 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) + * @dev_addr: optional device address. + * + * P2P needs mac addresses for P2P device and interface. If no device +- * address it specified, these are derived from the primary net device, ie. +- * the permanent ethernet address of the device. ++ * address it specified, these are derived from a random ethernet ++ * address. + */ + static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) + { +- struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; +- bool local_admin = false; ++ bool random_addr = false; + +- if (!dev_addr || is_zero_ether_addr(dev_addr)) { +- dev_addr = pri_ifp->mac_addr; +- local_admin = true; +- } ++ if (!dev_addr || is_zero_ether_addr(dev_addr)) ++ random_addr = true; + +- /* Generate the P2P Device Address. This consists of the device's +- * primary MAC address with the locally administered bit set. ++ /* Generate the P2P Device Address obtaining a random ethernet ++ * address with the locally administered bit set. + */ +- memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); +- if (local_admin) +- p2p->dev_addr[0] |= 0x02; ++ if (random_addr) ++ eth_random_addr(p2p->dev_addr); ++ else ++ memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); + + /* Generate the P2P Interface Address. If the discovery and connection + * BSSCFGs need to simultaneously co-exist, then this address must be +@@ -1367,6 +1365,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, + u16 mgmt_type; + u8 action; + ++ if (e->datalen < sizeof(*rxframe)) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + ch.chspec = be16_to_cpu(rxframe->chanspec); + cfg->d11inf.decchspec(&ch); + /* Check if wpa_supplicant has registered for this frame */ +@@ -1864,6 +1867,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, + brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, + e->reason); + ++ if (e->datalen < sizeof(*rxframe)) { ++ brcmf_dbg(SCAN, "Event data to small. Ignore\n"); ++ return 0; ++ } ++ + ch.chspec = be16_to_cpu(rxframe->chanspec); + cfg->d11inf.decchspec(&ch); + +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +index bcf29bf6..9954e641 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +@@ -1394,6 +1394,17 @@ static inline u8 brcmf_sdio_getdatoffset(u8 *swheader) + return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT); + } + ++static inline bool brcmf_sdio_fromevntchan(u8 *swheader) ++{ ++ u32 hdrvalue; ++ u8 ret; ++ ++ hdrvalue = *(u32 *)swheader; ++ ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT); ++ ++ return (ret == SDPCM_EVENT_CHANNEL); ++} ++ + static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header, + struct brcmf_sdio_hdrinfo *rd, + enum brcmf_sdio_frmtype type) +@@ -1754,7 +1765,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) + pfirst->len, pfirst->next, + pfirst->prev); + skb_unlink(pfirst, &bus->glom); +- brcmf_rx_frame(bus->sdiodev->dev, pfirst); ++ if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN])) ++ brcmf_rx_event(bus->sdiodev->dev, pfirst); ++ else ++ brcmf_rx_frame(bus->sdiodev->dev, pfirst, ++ false); + bus->sdcnt.rxglompkts++; + } + +@@ -2081,18 +2096,19 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) + __skb_trim(pkt, rd->len); + skb_pull(pkt, rd->dat_offset); + ++ if (pkt->len == 0) ++ brcmu_pkt_buf_free_skb(pkt); ++ else if (rd->channel == SDPCM_EVENT_CHANNEL) ++ brcmf_rx_event(bus->sdiodev->dev, pkt); ++ else ++ brcmf_rx_frame(bus->sdiodev->dev, pkt, ++ false); ++ + /* prepare the descriptor for the next read */ + rd->len = rd->len_nxtfrm << 4; + rd->len_nxtfrm = 0; + /* treat all packet as event if we don't know */ + rd->channel = SDPCM_EVENT_CHANNEL; +- +- if (pkt->len == 0) { +- brcmu_pkt_buf_free_skb(pkt); +- continue; +- } +- +- brcmf_rx_frame(bus->sdiodev->dev, pkt); + } + + rxcount = maxframes - rxleft; +@@ -3401,6 +3417,10 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, + goto err; + } + ++ /* Allow full data communication using DPC from now on. */ ++ brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); ++ bcmerror = 0; ++ + err: + brcmf_sdio_clkctl(bus, CLK_SDONLY, false); + sdio_release_host(bus->sdiodev->func[1]); +@@ -4108,9 +4128,6 @@ static void brcmf_sdio_firmware_callback(struct device *dev, + } + + if (err == 0) { +- /* Allow full data communication using DPC from now on. */ +- brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA); +- + err = brcmf_sdiod_intr_register(sdiodev); + if (err != 0) + brcmf_err("intr register failed:%d\n", err); +@@ -4290,6 +4307,13 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) + brcmf_dbg(TRACE, "Enter\n"); + + if (bus) { ++ /* Stop watchdog task */ ++ if (bus->watchdog_tsk) { ++ send_sig(SIGTERM, bus->watchdog_tsk, 1); ++ kthread_stop(bus->watchdog_tsk); ++ bus->watchdog_tsk = NULL; ++ } ++ + /* De-register interrupt handler */ + brcmf_sdiod_intr_unregister(bus->sdiodev); + +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c +index 689e64d0..3002268e 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c +@@ -144,7 +144,7 @@ struct brcmf_usbdev_info { + + struct usb_device *usbdev; + struct device *dev; +- struct mutex dev_init_lock; ++ struct completion dev_init_done; + + int ctl_in_pipe, ctl_out_pipe; + struct urb *ctl_urb; /* URB for control endpoint */ +@@ -502,7 +502,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) + + if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { + skb_put(skb, urb->actual_length); +- brcmf_rx_frame(devinfo->dev, skb); ++ brcmf_rx_frame(devinfo->dev, skb, true); + brcmf_usb_rx_refill(devinfo, req); + } else { + brcmu_pkt_buf_free_skb(skb); +@@ -669,12 +669,18 @@ static int brcmf_usb_up(struct device *dev) + + static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo) + { ++ int i; ++ + if (devinfo->ctl_urb) + usb_kill_urb(devinfo->ctl_urb); + if (devinfo->bulk_urb) + usb_kill_urb(devinfo->bulk_urb); +- brcmf_usb_free_q(&devinfo->tx_postq, true); +- brcmf_usb_free_q(&devinfo->rx_postq, true); ++ if (devinfo->tx_reqs) ++ for (i = 0; i < devinfo->bus_pub.ntxq; i++) ++ usb_kill_urb(devinfo->tx_reqs[i].urb); ++ if (devinfo->rx_reqs) ++ for (i = 0; i < devinfo->bus_pub.nrxq; i++) ++ usb_kill_urb(devinfo->rx_reqs[i].urb); + } + + static void brcmf_usb_down(struct device *dev) +@@ -1226,11 +1232,11 @@ static void brcmf_usb_probe_phase2(struct device *dev, + if (ret) + goto error; + +- mutex_unlock(&devinfo->dev_init_lock); ++ complete(&devinfo->dev_init_done); + return; + error: + brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret); +- mutex_unlock(&devinfo->dev_init_lock); ++ complete(&devinfo->dev_init_done); + device_release_driver(dev); + } + +@@ -1268,7 +1274,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) + if (ret) + goto fail; + /* we are done */ +- mutex_unlock(&devinfo->dev_init_lock); ++ complete(&devinfo->dev_init_done); + return 0; + } + bus->chip = bus_pub->devid; +@@ -1322,11 +1328,10 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) + + devinfo->usbdev = usb; + devinfo->dev = &usb->dev; +- /* Take an init lock, to protect for disconnect while still loading. ++ /* Init completion, to protect for disconnect while still loading. + * Necessary because of the asynchronous firmware load construction + */ +- mutex_init(&devinfo->dev_init_lock); +- mutex_lock(&devinfo->dev_init_lock); ++ init_completion(&devinfo->dev_init_done); + + usb_set_intfdata(intf, devinfo); + +@@ -1402,7 +1407,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) + return 0; + + fail: +- mutex_unlock(&devinfo->dev_init_lock); ++ complete(&devinfo->dev_init_done); + kfree(devinfo); + usb_set_intfdata(intf, NULL); + return ret; +@@ -1417,7 +1422,7 @@ brcmf_usb_disconnect(struct usb_interface *intf) + devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf); + + if (devinfo) { +- mutex_lock(&devinfo->dev_init_lock); ++ wait_for_completion(&devinfo->dev_init_done); + /* Make sure that devinfo still exists. Firmware probe routines + * may have released the device and cleared the intfdata. + */ +diff --git a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c +index 8eff2753..d493021f 100644 +--- a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c ++++ b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c +@@ -35,9 +35,10 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, + struct brcmf_if *ifp; + const struct brcmf_vndr_dcmd_hdr *cmdhdr = data; + struct sk_buff *reply; +- int ret, payload, ret_len; ++ unsigned int payload, ret_len; + void *dcmd_buf = NULL, *wr_pointer; + u16 msglen, maxmsglen = PAGE_SIZE - 0x100; ++ int ret; + + if (len < sizeof(*cmdhdr)) { + brcmf_err("vendor command too short: %d\n", len); +@@ -65,7 +66,7 @@ static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, + brcmf_err("oversize return buffer %d\n", ret_len); + ret_len = BRCMF_DCMD_MAXLEN; + } +- payload = max(ret_len, len) + 1; ++ payload = max_t(unsigned int, ret_len, len) + 1; + dcmd_buf = vzalloc(payload); + if (NULL == dcmd_buf) + return -ENOMEM; +diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +index bec2dc1c..61ae2768 100644 +--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +@@ -818,13 +818,15 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + static int + brcms_ops_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct brcms_info *wl = hw->priv; + struct scb *scb = &wl->wlc->pri_scb; + int status; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u8 buf_size = params->buf_size; + + if (WARN_ON(scb->magic != SCB_MAGIC)) + return -EIDRM; +diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +index 99dac9b8..c75bfd3f 100644 +--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +@@ -14764,8 +14764,8 @@ static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi) + } + + static void +-wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys, +- u8 len) ++wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, const u8 *events, ++ const u8 *dlys, u8 len) + { + u32 t1_offset, t2_offset; + u8 ctr; +@@ -15240,16 +15240,16 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi) + static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) + { + u16 currband; +- s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 }; +- s8 *lna1_gain_db = NULL; +- s8 *lna1_gain_db_2 = NULL; +- s8 *lna2_gain_db = NULL; +- s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 }; +- s8 *tia_gain_db; +- s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 }; +- s8 *tia_gainbits; +- u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f }; +- u16 *rfseq_init_gain; ++ static const s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 }; ++ const s8 *lna1_gain_db = NULL; ++ const s8 *lna1_gain_db_2 = NULL; ++ const s8 *lna2_gain_db = NULL; ++ static const s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 }; ++ const s8 *tia_gain_db; ++ static const s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 }; ++ const s8 *tia_gainbits; ++ static const u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f }; ++ const u16 *rfseq_init_gain; + u16 init_gaincode; + u16 clip1hi_gaincode; + u16 clip1md_gaincode = 0; +@@ -15310,10 +15310,9 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) + + if ((freq <= 5080) || (freq == 5825)) { + +- s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 }; +- s8 lna1A_gain_db_2_rev7[] = { +- 11, 17, 22, 25}; +- s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; ++ static const s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 }; ++ static const s8 lna1A_gain_db_2_rev7[] = { 11, 17, 22, 25}; ++ static const s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; + + crsminu_th = 0x3e; + lna1_gain_db = lna1A_gain_db_rev7; +@@ -15321,10 +15320,9 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) + lna2_gain_db = lna2A_gain_db_rev7; + } else if ((freq >= 5500) && (freq <= 5700)) { + +- s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 }; +- s8 lna1A_gain_db_2_rev7[] = { +- 12, 18, 22, 26}; +- s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 }; ++ static const s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 }; ++ static const s8 lna1A_gain_db_2_rev7[] = { 12, 18, 22, 26}; ++ static const s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 }; + + crsminu_th = 0x45; + clip1md_gaincode_B = 0x14; +@@ -15335,10 +15333,9 @@ static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) + lna2_gain_db = lna2A_gain_db_rev7; + } else { + +- s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 }; +- s8 lna1A_gain_db_2_rev7[] = { +- 12, 18, 22, 26}; +- s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; ++ static const s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 }; ++ static const s8 lna1A_gain_db_2_rev7[] = { 12, 18, 22, 26}; ++ static const s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; + + crsminu_th = 0x41; + lna1_gain_db = lna1A_gain_db_rev7; +@@ -15450,65 +15447,65 @@ static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) + NPHY_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_RFSEQ_CMD_SET_HPF_BW + }; +- u8 rfseq_updategainu_dlys[] = { 10, 30, 1 }; +- s8 lna1G_gain_db[] = { 7, 11, 16, 23 }; +- s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 }; +- s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 }; +- s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 }; +- s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 }; +- s8 lna1A_gain_db[] = { 7, 11, 17, 23 }; +- s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 }; +- s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 }; +- s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 }; +- s8 *lna1_gain_db = NULL; +- s8 lna2G_gain_db[] = { -5, 6, 10, 14 }; +- s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 }; +- s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 }; +- s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 }; +- s8 lna2A_gain_db[] = { -6, 2, 6, 10 }; +- s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 }; +- s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 }; +- s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 }; +- s8 *lna2_gain_db = NULL; +- s8 tiaG_gain_db[] = { ++ static const u8 rfseq_updategainu_dlys[] = { 10, 30, 1 }; ++ static const s8 lna1G_gain_db[] = { 7, 11, 16, 23 }; ++ static const s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 }; ++ static const s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 }; ++ static const s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 }; ++ static const s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 }; ++ static const s8 lna1A_gain_db[] = { 7, 11, 17, 23 }; ++ static const s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 }; ++ static const s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 }; ++ static const s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 }; ++ const s8 *lna1_gain_db = NULL; ++ static const s8 lna2G_gain_db[] = { -5, 6, 10, 14 }; ++ static const s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 }; ++ static const s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 }; ++ static const s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 }; ++ static const s8 lna2A_gain_db[] = { -6, 2, 6, 10 }; ++ static const s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 }; ++ static const s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 }; ++ static const s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 }; ++ const s8 *lna2_gain_db = NULL; ++ static const s8 tiaG_gain_db[] = { + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A }; +- s8 tiaA_gain_db[] = { ++ static const s8 tiaA_gain_db[] = { + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 }; +- s8 tiaA_gain_db_rev4[] = { ++ static const s8 tiaA_gain_db_rev4[] = { + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; +- s8 tiaA_gain_db_rev5[] = { ++ static const s8 tiaA_gain_db_rev5[] = { + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; +- s8 tiaA_gain_db_rev6[] = { ++ static const s8 tiaA_gain_db_rev6[] = { + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; +- s8 *tia_gain_db; +- s8 tiaG_gainbits[] = { ++ const s8 *tia_gain_db; ++ static const s8 tiaG_gainbits[] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; +- s8 tiaA_gainbits[] = { ++ static const s8 tiaA_gainbits[] = { + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 }; +- s8 tiaA_gainbits_rev4[] = { ++ static const s8 tiaA_gainbits_rev4[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; +- s8 tiaA_gainbits_rev5[] = { ++ static const s8 tiaA_gainbits_rev5[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; +- s8 tiaA_gainbits_rev6[] = { ++ static const s8 tiaA_gainbits_rev6[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; +- s8 *tia_gainbits; +- s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 }; +- s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 }; +- u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f }; +- u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f }; +- u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f }; +- u16 rfseqG_init_gain_rev5_elna[] = { ++ const s8 *tia_gainbits; ++ static const s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 }; ++ static const s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 }; ++ static const u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f }; ++ static const u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f }; ++ static const u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f }; ++ static const u16 rfseqG_init_gain_rev5_elna[] = { + 0x013f, 0x013f, 0x013f, 0x013f }; +- u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f }; +- u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f }; +- u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f }; +- u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f }; +- u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f }; +- u16 rfseqA_init_gain_rev4_elna[] = { ++ static const u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f }; ++ static const u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f }; ++ static const u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f }; ++ static const u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f }; ++ static const u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f }; ++ static const u16 rfseqA_init_gain_rev4_elna[] = { + 0x314f, 0x314f, 0x314f, 0x314f }; +- u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f }; +- u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f }; +- u16 *rfseq_init_gain; ++ static const u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f }; ++ static const u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f }; ++ const u16 *rfseq_init_gain; + u16 initG_gaincode = 0x627e; + u16 initG_gaincode_rev4 = 0x527e; + u16 initG_gaincode_rev5 = 0x427e; +@@ -15538,10 +15535,10 @@ static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) + u16 clip1mdA_gaincode_rev6 = 0x2084; + u16 clip1md_gaincode = 0; + u16 clip1loG_gaincode = 0x0074; +- u16 clip1loG_gaincode_rev5[] = { ++ static const u16 clip1loG_gaincode_rev5[] = { + 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c + }; +- u16 clip1loG_gaincode_rev6[] = { ++ static const u16 clip1loG_gaincode_rev6[] = { + 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e + }; + u16 clip1loG_gaincode_rev6_224B0 = 0x1074; +@@ -16066,7 +16063,7 @@ static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) + + static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + { +- u8 rfseq_rx2tx_events[] = { ++ static const u8 rfseq_rx2tx_events[] = { + NPHY_RFSEQ_CMD_NOP, + NPHY_RFSEQ_CMD_RXG_FBW, + NPHY_RFSEQ_CMD_TR_SWITCH, +@@ -16076,7 +16073,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + NPHY_RFSEQ_CMD_EXT_PA + }; + u8 rfseq_rx2tx_dlys[] = { 8, 6, 6, 2, 4, 60, 1 }; +- u8 rfseq_tx2rx_events[] = { ++ static const u8 rfseq_tx2rx_events[] = { + NPHY_RFSEQ_CMD_NOP, + NPHY_RFSEQ_CMD_EXT_PA, + NPHY_RFSEQ_CMD_TX_GAIN, +@@ -16085,8 +16082,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + NPHY_RFSEQ_CMD_RXG_FBW, + NPHY_RFSEQ_CMD_CLR_HIQ_DIS + }; +- u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 }; +- u8 rfseq_tx2rx_events_rev3[] = { ++ static const u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 }; ++ static const u8 rfseq_tx2rx_events_rev3[] = { + NPHY_REV3_RFSEQ_CMD_EXT_PA, + NPHY_REV3_RFSEQ_CMD_INT_PA_PU, + NPHY_REV3_RFSEQ_CMD_TX_GAIN, +@@ -16096,7 +16093,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_REV3_RFSEQ_CMD_END + }; +- u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 }; ++ static const u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 }; + u8 rfseq_rx2tx_events_rev3[] = { + NPHY_REV3_RFSEQ_CMD_NOP, + NPHY_REV3_RFSEQ_CMD_RXG_FBW, +@@ -16110,7 +16107,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + }; + u8 rfseq_rx2tx_dlys_rev3[] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 }; + +- u8 rfseq_rx2tx_events_rev3_ipa[] = { ++ static const u8 rfseq_rx2tx_events_rev3_ipa[] = { + NPHY_REV3_RFSEQ_CMD_NOP, + NPHY_REV3_RFSEQ_CMD_RXG_FBW, + NPHY_REV3_RFSEQ_CMD_TR_SWITCH, +@@ -16121,15 +16118,15 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + NPHY_REV3_RFSEQ_CMD_INT_PA_PU, + NPHY_REV3_RFSEQ_CMD_END + }; +- u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; +- u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f }; ++ static const u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; ++ static const u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f }; + + s16 alpha0, alpha1, alpha2; + s16 beta0, beta1, beta2; + u32 leg_data_weights, ht_data_weights, nss1_data_weights, + stbc_data_weights; + u8 chan_freq_range = 0; +- u16 dac_control = 0x0002; ++ static const u16 dac_control = 0x0002; + u16 aux_adc_vmid_rev7_core0[] = { 0x8e, 0x96, 0x96, 0x96 }; + u16 aux_adc_vmid_rev7_core1[] = { 0x8f, 0x9f, 0x9f, 0x96 }; + u16 aux_adc_vmid_rev4[] = { 0xa2, 0xb4, 0xb4, 0x89 }; +@@ -16139,8 +16136,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + u16 aux_adc_gain_rev4[] = { 0x02, 0x02, 0x02, 0x00 }; + u16 aux_adc_gain_rev3[] = { 0x02, 0x02, 0x02, 0x00 }; + u16 *aux_adc_gain; +- u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 }; +- u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 }; ++ static const u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 }; ++ static const u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 }; + s32 min_nvar_val = 0x18d; + s32 min_nvar_offset_6mbps = 20; + u8 pdetrange; +@@ -16151,9 +16148,9 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) + u16 rfseq_rx2tx_lpf_h_hpc_rev7 = 0x77; + u16 rfseq_tx2rx_lpf_h_hpc_rev7 = 0x77; + u16 rfseq_pktgn_lpf_h_hpc_rev7 = 0x77; +- u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 }; +- u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; +- u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; ++ static const u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 }; ++ static const u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; ++ static const u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; + u16 ipalvlshift_3p3_war_en = 0; + u16 rccal_bcap_val, rccal_scap_val; + u16 rccal_tx20_11b_bcap = 0; +@@ -24291,13 +24288,13 @@ static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core) + u16 bbmult; + u16 tblentry; + +- struct nphy_txiqcal_ladder ladder_lo[] = { ++ static const struct nphy_txiqcal_ladder ladder_lo[] = { + {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, + {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5}, + {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7} + }; + +- struct nphy_txiqcal_ladder ladder_iq[] = { ++ static const struct nphy_txiqcal_ladder ladder_iq[] = { + {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, + {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1}, + {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7} +@@ -25773,67 +25770,67 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, + u16 cal_gain[2]; + struct nphy_iqcal_params cal_params[2]; + u32 tbl_len; +- void *tbl_ptr; ++ const void *tbl_ptr; + bool ladder_updated[2]; + u8 mphase_cal_lastphase = 0; + int bcmerror = 0; + bool phyhang_avoid_state = false; + +- u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { ++ static const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { + 0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901, + 0x1902, + 0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607, + 0x6407 + }; + +- u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { ++ static const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { + 0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400, + 0x3200, + 0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406, + 0x6407 + }; + +- u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { ++ static const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { + 0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201, + 0x1202, + 0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207, + 0x4707 + }; + +- u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { ++ static const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { + 0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900, + 0x2300, + 0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706, + 0x4707 + }; + +- u16 tbl_tx_iqlo_cal_startcoefs[] = { ++ static const u16 tbl_tx_iqlo_cal_startcoefs[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 + }; + +- u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { ++ static const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { + 0x8123, 0x8264, 0x8086, 0x8245, 0x8056, + 0x9123, 0x9264, 0x9086, 0x9245, 0x9056 + }; + +- u16 tbl_tx_iqlo_cal_cmds_recal[] = { ++ static const u16 tbl_tx_iqlo_cal_cmds_recal[] = { + 0x8101, 0x8253, 0x8053, 0x8234, 0x8034, + 0x9101, 0x9253, 0x9053, 0x9234, 0x9034 + }; + +- u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = { ++ static const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 + }; + +- u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { ++ static const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { + 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234, + 0x9434, 0x9334, 0x9084, 0x9267, 0x9056, 0x9234 + }; + +- u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { ++ static const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { + 0x8423, 0x8323, 0x8073, 0x8256, 0x8045, 0x8223, + 0x9423, 0x9323, 0x9073, 0x9256, 0x9045, 0x9223 + }; +diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c +index a7400836..63f95e9c 100644 +--- a/drivers/net/wireless/cw1200/cw1200_spi.c ++++ b/drivers/net/wireless/cw1200/cw1200_spi.c +@@ -446,8 +446,7 @@ static int cw1200_spi_disconnect(struct spi_device *func) + return 0; + } + +-#ifdef CONFIG_PM +-static int cw1200_spi_suspend(struct device *dev) ++static int __maybe_unused cw1200_spi_suspend(struct device *dev) + { + struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); + +@@ -460,16 +459,12 @@ static int cw1200_spi_suspend(struct device *dev) + + static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL); + +-#endif +- + static struct spi_driver spi_driver = { + .probe = cw1200_spi_probe, + .remove = cw1200_spi_disconnect, + .driver = { + .name = "cw1200_wlan_spi", +-#ifdef CONFIG_PM +- .pm = &cw1200_pm_ops, +-#endif ++ .pm = IS_ENABLED(CONFIG_PM) ? &cw1200_pm_ops : NULL, + }, + }; + +diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c +index 0e51e27d..317daa96 100644 +--- a/drivers/net/wireless/cw1200/main.c ++++ b/drivers/net/wireless/cw1200/main.c +@@ -345,6 +345,11 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, + mutex_init(&priv->wsm_cmd_mux); + mutex_init(&priv->conf_mutex); + priv->workqueue = create_singlethread_workqueue("cw1200_wq"); ++ if (!priv->workqueue) { ++ ieee80211_free_hw(hw); ++ return NULL; ++ } ++ + sema_init(&priv->scan.lock, 1); + INIT_WORK(&priv->scan.work, cw1200_scan_work); + INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); +diff --git a/drivers/net/wireless/cw1200/pm.h b/drivers/net/wireless/cw1200/pm.h +index 3ed90ff2..53454847 100644 +--- a/drivers/net/wireless/cw1200/pm.h ++++ b/drivers/net/wireless/cw1200/pm.h +@@ -31,13 +31,18 @@ int cw1200_pm_init(struct cw1200_pm_state *pm, + void cw1200_pm_deinit(struct cw1200_pm_state *pm); + int cw1200_wow_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan); +-int cw1200_wow_resume(struct ieee80211_hw *hw); + int cw1200_can_suspend(struct cw1200_common *priv); ++int cw1200_wow_resume(struct ieee80211_hw *hw); + void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, + unsigned long tmo); + #else + static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, +- unsigned long tmo) { ++ unsigned long tmo) ++{ ++} ++static inline int cw1200_can_suspend(struct cw1200_common *priv) ++{ ++ return 0; + } + #endif + #endif +diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c +index bff81b8d..2ce01936 100644 +--- a/drivers/net/wireless/cw1200/scan.c ++++ b/drivers/net/wireless/cw1200/scan.c +@@ -78,27 +78,30 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, + if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) + return -EINVAL; + ++ /* will be unlocked in cw1200_scan_work() */ ++ down(&priv->scan.lock); ++ mutex_lock(&priv->conf_mutex); ++ + frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, + req->ie_len); +- if (!frame.skb) ++ if (!frame.skb) { ++ mutex_unlock(&priv->conf_mutex); ++ up(&priv->scan.lock); + return -ENOMEM; ++ } + + if (req->ie_len) + memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len); + +- /* will be unlocked in cw1200_scan_work() */ +- down(&priv->scan.lock); +- mutex_lock(&priv->conf_mutex); +- + ret = wsm_set_template_frame(priv, &frame); + if (!ret) { + /* Host want to be the probe responder. */ + ret = wsm_set_probe_responder(priv, true); + } + if (ret) { ++ dev_kfree_skb(frame.skb); + mutex_unlock(&priv->conf_mutex); + up(&priv->scan.lock); +- dev_kfree_skb(frame.skb); + return ret; + } + +@@ -120,10 +123,9 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, + ++priv->scan.n_ssids; + } + +- mutex_unlock(&priv->conf_mutex); +- + if (frame.skb) + dev_kfree_skb(frame.skb); ++ mutex_unlock(&priv->conf_mutex); + queue_work(priv->workqueue, &priv->scan.work); + return 0; + } +diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c +index 95a7fdb3..c602a1e6 100644 +--- a/drivers/net/wireless/cw1200/sta.c ++++ b/drivers/net/wireless/cw1200/sta.c +@@ -2135,9 +2135,7 @@ void cw1200_mcast_timeout(unsigned long arg) + + int cw1200_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + /* Aggregation is implemented fully in firmware, + * including block ack negotiation. Do not allow +diff --git a/drivers/net/wireless/cw1200/sta.h b/drivers/net/wireless/cw1200/sta.h +index bebb3379..a0bacaa3 100644 +--- a/drivers/net/wireless/cw1200/sta.h ++++ b/drivers/net/wireless/cw1200/sta.h +@@ -109,9 +109,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, + u32 changed); + int cw1200_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu); ++ struct ieee80211_ampdu_params *params); + + void cw1200_suspend_resume(struct cw1200_common *priv, + struct wsm_suspend_resume *arg); +diff --git a/drivers/net/wireless/cw1200/wsm.c b/drivers/net/wireless/cw1200/wsm.c +index 9e0ca304..5a595f9f 100644 +--- a/drivers/net/wireless/cw1200/wsm.c ++++ b/drivers/net/wireless/cw1200/wsm.c +@@ -379,7 +379,6 @@ static int wsm_multi_tx_confirm(struct cw1200_common *priv, + { + int ret; + int count; +- int i; + + count = WSM_GET32(buf); + if (WARN_ON(count <= 0)) +@@ -395,11 +394,10 @@ static int wsm_multi_tx_confirm(struct cw1200_common *priv, + } + + cw1200_debug_txed_multi(priv, count); +- for (i = 0; i < count; ++i) { ++ do { + ret = wsm_tx_confirm(priv, buf, link_id); +- if (ret) +- return ret; +- } ++ } while (!ret && --count); ++ + return ret; + + underflow: +@@ -1807,16 +1805,18 @@ static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size) + { + size_t pos = buf->data - buf->begin; + size_t size = pos + extra_size; ++ u8 *tmp; + + size = round_up(size, FWLOAD_BLOCK_SIZE); + +- buf->begin = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA); +- if (buf->begin) { +- buf->data = &buf->begin[pos]; +- buf->end = &buf->begin[size]; +- return 0; +- } else { +- buf->end = buf->data = buf->begin; ++ tmp = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA); ++ if (!tmp) { ++ wsm_buf_deinit(buf); + return -ENOMEM; + } ++ ++ buf->begin = tmp; ++ buf->data = &buf->begin[pos]; ++ buf->end = &buf->begin[size]; ++ return 0; + } +diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c +index 6df3ee56..515aa3f9 100644 +--- a/drivers/net/wireless/hostap/hostap_hw.c ++++ b/drivers/net/wireless/hostap/hostap_hw.c +@@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, + spin_lock_bh(&local->baplock); + + res = hfa384x_setup_bap(dev, BAP0, rid, 0); +- if (!res) +- res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); ++ if (res) ++ goto unlock; ++ ++ res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); ++ if (res) ++ goto unlock; + + if (le16_to_cpu(rec.len) == 0) { + /* RID not available */ + res = -ENODATA; ++ goto unlock; + } + + rlen = (le16_to_cpu(rec.len) - 1) * 2; +- if (!res && exact_len && rlen != len) { ++ if (exact_len && rlen != len) { + printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " + "rid=0x%04x, len=%d (expected %d)\n", + dev->name, rid, rlen, len); + res = -ENODATA; + } + +- if (!res) +- res = hfa384x_from_bap(dev, BAP0, buf, len); ++ res = hfa384x_from_bap(dev, BAP0, buf, len); + ++unlock: + spin_unlock_bh(&local->baplock); + mutex_unlock(&local->rid_bap_mtx); + +diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c +index 6656215a..04b0349a 100644 +--- a/drivers/net/wireless/iwlegacy/4965-mac.c ++++ b/drivers/net/wireless/iwlegacy/4965-mac.c +@@ -5982,12 +5982,14 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + + int + il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 * ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct il_priv *il = hw->priv; + int ret = -EINVAL; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + + D_HT("A-MPDU action on addr %pM tid %d\n", sta->addr, tid); + +diff --git a/drivers/net/wireless/iwlegacy/4965.h b/drivers/net/wireless/iwlegacy/4965.h +index 8ab8706f..e432715e 100644 +--- a/drivers/net/wireless/iwlegacy/4965.h ++++ b/drivers/net/wireless/iwlegacy/4965.h +@@ -182,9 +182,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u32 iv32, + u16 *phase1key); + int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 * ssn, +- u8 buf_size, bool amsdu); ++ struct ieee80211_ampdu_params *params); + int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + void +diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c +index b3ad34e8..1eb1a823 100644 +--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c ++++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c +@@ -729,12 +729,15 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) + + static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); + int ret = -EINVAL; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; ++ u8 buf_size = params->buf_size; + struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; + + IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", +diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +index d8298491..95b82cc1 100644 +--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c ++++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +@@ -73,6 +73,7 @@ + /* NVM offsets (in words) definitions */ + enum wkp_nvm_offsets { + /* NVM HW-Section offset (in words) definitions */ ++ SUBSYSTEM_ID = 0x0A, + HW_ADDR = 0x15, + + /* NVM SW-Section offset (in words) definitions */ +@@ -257,13 +258,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, + static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + const __le16 * const nvm_ch_flags, +- bool lar_supported) ++ bool lar_supported, bool no_wide_in_5ghz) + { + int ch_idx; + int n_channels = 0; + struct ieee80211_channel *channel; + u16 ch_flags; +- bool is_5ghz; + int num_of_ch, num_2ghz_channels; + const u8 *nvm_chan; + +@@ -278,12 +278,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, + } + + for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { ++ bool is_5ghz = (ch_idx >= num_2ghz_channels); ++ + ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); + +- if (ch_idx >= num_2ghz_channels && +- !data->sku_cap_band_52GHz_enable) ++ if (is_5ghz && !data->sku_cap_band_52GHz_enable) + continue; + ++ /* workaround to disable wide channels in 5GHz */ ++ if (no_wide_in_5ghz && is_5ghz) { ++ ch_flags &= ~(NVM_CHANNEL_40MHZ | ++ NVM_CHANNEL_80MHZ | ++ NVM_CHANNEL_160MHZ); ++ } ++ + if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) { + /* + * Channels might become valid later if lar is +@@ -303,8 +311,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, + n_channels++; + + channel->hw_value = nvm_chan[ch_idx]; +- channel->band = (ch_idx < num_2ghz_channels) ? +- IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; ++ channel->band = is_5ghz ? ++ IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; + channel->center_freq = + ieee80211_channel_to_frequency( + channel->hw_value, channel->band); +@@ -316,7 +324,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, + * is not used in mvm, and is used for backwards compatibility + */ + channel->max_power = IWL_DEFAULT_MAX_TX_POWER; +- is_5ghz = channel->band == IEEE80211_BAND_5GHZ; + + /* don't put limitations in case we're using LAR */ + if (!lar_supported) +@@ -405,7 +412,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, + static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, + struct iwl_nvm_data *data, + const __le16 *ch_section, +- u8 tx_chains, u8 rx_chains, bool lar_supported) ++ u8 tx_chains, u8 rx_chains, bool lar_supported, ++ bool no_wide_in_5ghz) + { + int n_channels; + int n_used = 0; +@@ -414,12 +422,14 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + n_channels = iwl_init_channel_map( + dev, cfg, data, +- &ch_section[NVM_CHANNELS], lar_supported); ++ &ch_section[NVM_CHANNELS], lar_supported, ++ no_wide_in_5ghz); + else + n_channels = iwl_init_channel_map( + dev, cfg, data, + &ch_section[NVM_CHANNELS_FAMILY_8000], +- lar_supported); ++ lar_supported, ++ no_wide_in_5ghz); + + sband = &data->bands[IEEE80211_BAND_2GHZ]; + sband->band = IEEE80211_BAND_2GHZ; +@@ -582,6 +592,39 @@ static void iwl_set_hw_address_family_8000(struct device *dev, + + #define IWL_4165_DEVICE_ID 0x5501 + ++static bool ++iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg, ++ const __le16 *nvm_hw) ++{ ++ /* ++ * Workaround a bug in Indonesia SKUs where the regulatory in ++ * some 7000-family OTPs erroneously allow wide channels in ++ * 5GHz. To check for Indonesia, we take the SKU value from ++ * bits 1-4 in the subsystem ID and check if it is either 5 or ++ * 9. In those cases, we need to force-disable wide channels ++ * in 5GHz otherwise the FW will throw a sysassert when we try ++ * to use them. ++ */ ++ if (cfg->device_family == IWL_DEVICE_FAMILY_7000) { ++ /* ++ * Unlike the other sections in the NVM, the hw ++ * section uses big-endian. ++ */ ++ u16 subsystem_id = be16_to_cpup((const __be16 *)nvm_hw ++ + SUBSYSTEM_ID); ++ u8 sku = (subsystem_id & 0x1e) >> 1; ++ ++ if (sku == 5 || sku == 9) { ++ IWL_DEBUG_EEPROM(dev, ++ "disabling wide channels in 5GHz (0x%0x %d)\n", ++ subsystem_id, sku); ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + struct iwl_nvm_data * + iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, + const __le16 *nvm_hw, const __le16 *nvm_sw, +@@ -591,6 +634,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, + u32 mac_addr0, u32 mac_addr1, u32 hw_id) + { + struct iwl_nvm_data *data; ++ bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw); + u32 sku; + u32 radio_cfg; + u16 lar_config; +@@ -657,7 +701,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, + iwl_set_hw_address(cfg, data, nvm_hw); + + iwl_init_sbands(dev, cfg, data, nvm_sw, +- tx_chains, rx_chains, lar_fw_supported); ++ tx_chains, rx_chains, lar_fw_supported, ++ no_wide_in_5ghz); + } else { + u16 lar_offset = data->nvm_version < 0xE39 ? + NVM_LAR_OFFSET_FAMILY_8000_OLD : +@@ -673,7 +718,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, + + iwl_init_sbands(dev, cfg, data, regulatory, + tx_chains, rx_chains, +- lar_fw_supported && data->lar_enabled); ++ lar_fw_supported && data->lar_enabled, ++ no_wide_in_5ghz); + } + + data->calib_version = 255; +diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c +index ce12717e..7b2a7d84 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c +@@ -322,8 +322,12 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, + goto out; + } + +- if (changed) +- *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE); ++ if (changed) { ++ u32 status = le32_to_cpu(resp->status); ++ ++ *changed = (status == MCC_RESP_NEW_CHAN_PROFILE || ++ status == MCC_RESP_ILLEGAL); ++ } + + regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, + __le32_to_cpu(resp->n_channels), +@@ -826,13 +830,16 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + + static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, +- u16 *ssn, u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + bool tx_agg_ref = false; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; ++ u8 buf_size = params->buf_size; + + IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n", + sta->addr, tid, action); +@@ -1903,6 +1910,11 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac, + struct iwl_mvm_mc_iter_data *data = _data; + struct iwl_mvm *mvm = data->mvm; + struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd; ++ struct iwl_host_cmd hcmd = { ++ .id = MCAST_FILTER_CMD, ++ .flags = CMD_ASYNC, ++ .dataflags[0] = IWL_HCMD_DFL_NOCOPY, ++ }; + int ret, len; + + /* if we don't have free ports, mcast frames will be dropped */ +@@ -1917,7 +1929,10 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac, + memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); + len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4); + +- ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd); ++ hcmd.len[0] = len; ++ hcmd.data[0] = cmd; ++ ++ ret = iwl_mvm_send_cmd(mvm, &hcmd); + if (ret) + IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret); + } +@@ -4039,10 +4054,6 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + +- if (!fw_has_capa(&mvm->fw->ucode_capa, +- IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS)) +- return; +- + /* if beacon filtering isn't on mac80211 does it anyway */ + if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) + return; +diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c +index 2ee0f6fe..5509c502 100644 +--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c ++++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c +@@ -667,9 +667,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, + + n_channels = __le32_to_cpu(mcc_resp->n_channels); + IWL_DEBUG_LAR(mvm, +- "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", +- status, mcc, mcc >> 8, mcc & 0xff, +- !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels); ++ "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') n_chans: %d\n", ++ status, mcc, mcc >> 8, mcc & 0xff, n_channels); + + resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32); + resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); +diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c +index e06591f6..d6f9858f 100644 +--- a/drivers/net/wireless/iwlwifi/pcie/rx.c ++++ b/drivers/net/wireless/iwlwifi/pcie/rx.c +@@ -713,6 +713,8 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) + WQ_HIGHPRI | WQ_UNBOUND, 1); + INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work); + ++ cancel_work_sync(&rba->rx_alloc); ++ + spin_lock(&rba->lock); + atomic_set(&rba->req_pending, 0); + atomic_set(&rba->req_ready, 0); +diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c +index 0cd95120..0f582117 100644 +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -699,16 +699,21 @@ static int hwsim_fops_ps_write(void *dat, u64 val) + val != PS_MANUAL_POLL) + return -EINVAL; + +- old_ps = data->ps; +- data->ps = val; +- +- local_bh_disable(); + if (val == PS_MANUAL_POLL) { ++ if (data->ps != PS_ENABLED) ++ return -EINVAL; ++ local_bh_disable(); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_ps_poll, data); +- data->ps_poll_pending = true; +- } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { ++ local_bh_enable(); ++ return 0; ++ } ++ old_ps = data->ps; ++ data->ps = val; ++ ++ local_bh_disable(); ++ if (old_ps == PS_DISABLED && val != PS_DISABLED) { + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_ps, data); +@@ -1817,10 +1822,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, + + static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ + switch (action) { + case IEEE80211_AMPDU_TX_START: + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); +@@ -2446,9 +2453,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_TXSTBC | +- IEEE80211_VHT_CAP_RXSTBC_1 | +- IEEE80211_VHT_CAP_RXSTBC_2 | +- IEEE80211_VHT_CAP_RXSTBC_3 | + IEEE80211_VHT_CAP_RXSTBC_4 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + sband->vht_cap.vht_mcs.rx_mcs_map = +@@ -2511,6 +2515,10 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, + if (param->no_vif) + ieee80211_hw_set(hw, NO_AUTO_VIF); + ++ tasklet_hrtimer_init(&data->beacon_timer, ++ mac80211_hwsim_beacon, ++ CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ++ + err = ieee80211_register_hw(hw); + if (err < 0) { + printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", +@@ -2535,16 +2543,11 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, + data->debugfs, + data, &hwsim_simulate_radar); + +- tasklet_hrtimer_init(&data->beacon_timer, +- mac80211_hwsim_beacon, +- CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); +- + spin_lock_bh(&hwsim_radio_lock); + list_add_tail(&data->list, &hwsim_radios); + spin_unlock_bh(&hwsim_radio_lock); + +- if (idx > 0) +- hwsim_mcast_new_radio(idx, info, param); ++ hwsim_mcast_new_radio(idx, info, param); + + return idx; + +@@ -2882,6 +2885,8 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2, + static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) + { + struct hwsim_new_radio_params param = { 0 }; ++ const char *hwname = NULL; ++ int ret; + + param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; + param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; +@@ -2895,8 +2900,14 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) + if (info->attrs[HWSIM_ATTR_NO_VIF]) + param.no_vif = true; + +- if (info->attrs[HWSIM_ATTR_RADIO_NAME]) +- param.hwname = nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]); ++ if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { ++ hwname = kasprintf(GFP_KERNEL, "%.*s", ++ nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), ++ (char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME])); ++ if (!hwname) ++ return -ENOMEM; ++ param.hwname = hwname; ++ } + + if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) + param.use_chanctx = true; +@@ -2910,12 +2921,16 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) + if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { + u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); + +- if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) ++ if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) { ++ kfree(hwname); + return -EINVAL; ++ } + param.regd = hwsim_world_regdom_custom[idx]; + } + +- return mac80211_hwsim_new_radio(info, ¶m); ++ ret = mac80211_hwsim_new_radio(info, ¶m); ++ kfree(hwname); ++ return ret; + } + + static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) +@@ -2924,11 +2939,15 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) + s64 idx = -1; + const char *hwname = NULL; + +- if (info->attrs[HWSIM_ATTR_RADIO_ID]) ++ if (info->attrs[HWSIM_ATTR_RADIO_ID]) { + idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); +- else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) +- hwname = (void *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]); +- else ++ } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { ++ hwname = kasprintf(GFP_KERNEL, "%.*s", ++ nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), ++ (char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME])); ++ if (!hwname) ++ return -ENOMEM; ++ } else + return -EINVAL; + + spin_lock_bh(&hwsim_radio_lock); +@@ -2937,7 +2956,8 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) + if (data->idx != idx) + continue; + } else { +- if (strcmp(hwname, wiphy_name(data->hw->wiphy))) ++ if (!hwname || ++ strcmp(hwname, wiphy_name(data->hw->wiphy))) + continue; + } + +@@ -2945,10 +2965,12 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) + spin_unlock_bh(&hwsim_radio_lock); + mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), + info); ++ kfree(hwname); + return 0; + } + spin_unlock_bh(&hwsim_radio_lock); + ++ kfree(hwname); + return -ENODEV; + } + +@@ -2980,7 +3002,7 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) + goto out_err; + } + +- genlmsg_reply(skb, info); ++ res = genlmsg_reply(skb, info); + break; + } + +@@ -3173,16 +3195,16 @@ static int __init init_mac80211_hwsim(void) + if (err) + return err; + ++ err = hwsim_init_netlink(); ++ if (err) ++ goto out_unregister_driver; ++ + hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); + if (IS_ERR(hwsim_class)) { + err = PTR_ERR(hwsim_class); +- goto out_unregister_driver; ++ goto out_exit_netlink; + } + +- err = hwsim_init_netlink(); +- if (err < 0) +- goto out_unregister_driver; +- + for (i = 0; i < radios; i++) { + struct hwsim_new_radio_params param = { 0 }; + +@@ -3288,6 +3310,8 @@ out_free_mon: + free_netdev(hwsim_mon); + out_free_radios: + mac80211_hwsim_free(); ++out_exit_netlink: ++ hwsim_exit_netlink(); + out_unregister_driver: + platform_driver_unregister(&mac80211_hwsim_driver); + return err; +diff --git a/drivers/net/wireless/mediatek/mt7601u/eeprom.h b/drivers/net/wireless/mediatek/mt7601u/eeprom.h +index 662d1270..57b503ae 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/eeprom.h ++++ b/drivers/net/wireless/mediatek/mt7601u/eeprom.h +@@ -17,7 +17,7 @@ + + struct mt7601u_dev; + +-#define MT7601U_EE_MAX_VER 0x0c ++#define MT7601U_EE_MAX_VER 0x0d + #define MT7601U_EEPROM_SIZE 256 + + #define MT7601U_DEFAULT_TX_POWER 6 +diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c +index f715eee3..e70dd952 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/main.c ++++ b/drivers/net/wireless/mediatek/mt7601u/main.c +@@ -334,11 +334,13 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value) + + static int + mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, +- bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct mt7601u_dev *dev = hw->priv; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + + WARN_ON(msta->wcid.idx > GROUP_WCID(0)); +diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c +index fbb1986e..686b1b5d 100644 +--- a/drivers/net/wireless/mediatek/mt7601u/mcu.c ++++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c +@@ -66,8 +66,10 @@ mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) + WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */ + + skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); +- skb_reserve(skb, MT_DMA_HDR_LEN); +- memcpy(skb_put(skb, len), data, len); ++ if (skb) { ++ skb_reserve(skb, MT_DMA_HDR_LEN); ++ memcpy(skb_put(skb, len), data, len); ++ } + + return skb; + } +@@ -170,6 +172,8 @@ static int mt7601u_mcu_function_select(struct mt7601u_dev *dev, + }; + + skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); ++ if (!skb) ++ return -ENOMEM; + return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); + } + +@@ -205,6 +209,8 @@ mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val) + }; + + skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); ++ if (!skb) ++ return -ENOMEM; + return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); + } + +diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c +index aa498e0d..49f3e17c 100644 +--- a/drivers/net/wireless/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/mwifiex/11n_aggr.c +@@ -101,13 +101,6 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, + { + struct txpd *local_tx_pd; + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); +- unsigned int pad; +- int headroom = (priv->adapter->iface_type == +- MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; +- +- pad = ((void *)skb->data - sizeof(*local_tx_pd) - +- headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1); +- skb_push(skb, pad); + + skb_push(skb, sizeof(*local_tx_pd)); + +@@ -121,12 +114,10 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + /* Always zero as the data is followed by struct txpd */ +- local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + +- pad); ++ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); + local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - +- sizeof(*local_tx_pd) - +- pad); ++ sizeof(*local_tx_pd)); + + if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) + local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET; +@@ -190,7 +181,11 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + ra_list_flags); + return -1; + } +- skb_reserve(skb_aggr, MWIFIEX_MIN_DATA_HEADER_LEN); ++ ++ /* skb_aggr->data already 64 byte align, just reserve bus interface ++ * header and txpd. ++ */ ++ skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); + + memset(tx_info_aggr, 0, sizeof(*tx_info_aggr)); +diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c +index 4073116e..1e074eaf 100644 +--- a/drivers/net/wireless/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/mwifiex/cfg80211.c +@@ -1150,6 +1150,12 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, + priv->adapter->curr_iface_comb.p2p_intf--; + priv->adapter->curr_iface_comb.sta_intf++; + dev->ieee80211_ptr->iftype = type; ++ if (mwifiex_deinit_priv_params(priv)) ++ return -1; ++ if (mwifiex_init_new_priv_params(priv, dev, type)) ++ return -1; ++ if (mwifiex_sta_init_cmd(priv, false, false)) ++ return -1; + break; + case NL80211_IFTYPE_ADHOC: + if (mwifiex_cfg80211_deinit_p2p(priv)) +@@ -2144,8 +2150,9 @@ done: + is_scanning_required = 1; + } else { + mwifiex_dbg(priv->adapter, MSG, +- "info: trying to associate to '%s' bssid %pM\n", +- (char *)req_ssid.ssid, bss->bssid); ++ "info: trying to associate to '%.*s' bssid %pM\n", ++ req_ssid.ssid_len, (char *)req_ssid.ssid, ++ bss->bssid); + memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); + break; + } +@@ -2202,8 +2209,8 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + } + + mwifiex_dbg(adapter, INFO, +- "info: Trying to associate to %s and bssid %pM\n", +- (char *)sme->ssid, sme->bssid); ++ "info: Trying to associate to %.*s and bssid %pM\n", ++ (int)sme->ssid_len, (char *)sme->ssid, sme->bssid); + + ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, + priv->bss_mode, sme->channel, sme, 0); +@@ -2333,8 +2340,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + } + + mwifiex_dbg(priv->adapter, MSG, +- "info: trying to join to %s and bssid %pM\n", +- (char *)params->ssid, params->bssid); ++ "info: trying to join to %.*s and bssid %pM\n", ++ params->ssid_len, (char *)params->ssid, params->bssid); + + mwifiex_set_ibss_params(priv, params); + +@@ -2838,8 +2845,10 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) + + mwifiex_stop_net_dev_queue(priv->netdev, adapter); + +- skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) ++ skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) { ++ skb_unlink(skb, &priv->bypass_txq); + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); ++ } + + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); +@@ -3739,7 +3748,7 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) + if (adapter->config_bands & BAND_A) + n_channels_a = mwifiex_band_5ghz.n_channels; + +- adapter->num_in_chan_stats = max_t(u32, n_channels_bg, n_channels_a); ++ adapter->num_in_chan_stats = n_channels_bg + n_channels_a; + adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) * + adapter->num_in_chan_stats); + +diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c +index 3ddb8ec6..6dd331df 100644 +--- a/drivers/net/wireless/mwifiex/cfp.c ++++ b/drivers/net/wireless/mwifiex/cfp.c +@@ -533,5 +533,8 @@ u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, + rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ? + rx_rate - 1 : rx_rate; + ++ if (rate_index >= MWIFIEX_MAX_AC_RX_RATES) ++ rate_index = MWIFIEX_MAX_AC_RX_RATES - 1; ++ + return rate_index; + } +diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c +index 9824d8dd..45d97b64 100644 +--- a/drivers/net/wireless/mwifiex/debugfs.c ++++ b/drivers/net/wireless/mwifiex/debugfs.c +@@ -115,7 +115,8 @@ mwifiex_info_read(struct file *file, char __user *ubuf, + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + p += sprintf(p, "multicast_count=\"%d\"\n", + netdev_mc_count(netdev)); +- p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); ++ p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len, ++ info.ssid.ssid); + p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); + p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); + p += sprintf(p, "country_code = \"%s\"\n", info.country_code); +diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c +index 21192b6f..268e50ba 100644 +--- a/drivers/net/wireless/mwifiex/pcie.c ++++ b/drivers/net/wireless/mwifiex/pcie.c +@@ -947,6 +947,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) + if (card && card->cmd_buf) { + mwifiex_unmap_pci_memory(adapter, card->cmd_buf, + PCI_DMA_TODEVICE); ++ dev_kfree_skb_any(card->cmd_buf); + } + return 0; + } +@@ -1513,6 +1514,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + return -1; + + card->cmd_buf = skb; ++ /* ++ * Need to keep a reference, since core driver might free up this ++ * buffer before we've unmapped it. ++ */ ++ skb_get(skb); + + /* To send a command, the driver will: + 1. Write the 64bit physical address of the data buffer to +@@ -1610,6 +1616,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) + if (card->cmd_buf) { + mwifiex_unmap_pci_memory(adapter, card->cmd_buf, + PCI_DMA_TODEVICE); ++ dev_kfree_skb_any(card->cmd_buf); + card->cmd_buf = NULL; + } + +diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c +index c20017ce..fb98f42c 100644 +--- a/drivers/net/wireless/mwifiex/scan.c ++++ b/drivers/net/wireless/mwifiex/scan.c +@@ -2170,6 +2170,12 @@ mwifiex_update_chan_statistics(struct mwifiex_private *priv, + sizeof(struct mwifiex_chan_stats); + + for (i = 0 ; i < num_chan; i++) { ++ if (adapter->survey_idx >= adapter->num_in_chan_stats) { ++ mwifiex_dbg(adapter, WARN, ++ "FW reported too many channel results (max %d)\n", ++ adapter->num_in_chan_stats); ++ return; ++ } + chan_stats.chan_num = fw_chan_stats->chan_num; + chan_stats.bandcfg = fw_chan_stats->bandcfg; + chan_stats.flags = fw_chan_stats->flags; +diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c +index d6c4f0f6..6cfa2969 100644 +--- a/drivers/net/wireless/mwifiex/sta_ioctl.c ++++ b/drivers/net/wireless/mwifiex/sta_ioctl.c +@@ -1098,8 +1098,6 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp, + encrypt_key.is_rx_seq_valid = true; + } + } else { +- if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) +- return 0; + encrypt_key.key_disable = true; + if (mac_addr) + memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); +diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c +index e43aff93..1a1b1de8 100644 +--- a/drivers/net/wireless/mwifiex/usb.c ++++ b/drivers/net/wireless/mwifiex/usb.c +@@ -624,6 +624,9 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) + MWIFIEX_FUNC_SHUTDOWN); + } + ++ if (adapter->workqueue) ++ flush_workqueue(adapter->workqueue); ++ + mwifiex_usb_free(card); + + mwifiex_dbg(adapter, FATAL, +diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c +index 0cec8a64..eb5ffa5b 100644 +--- a/drivers/net/wireless/mwifiex/util.c ++++ b/drivers/net/wireless/mwifiex/util.c +@@ -702,12 +702,14 @@ void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, + s8 nflr) + { + struct mwifiex_histogram_data *phist_data = priv->hist_data; ++ s8 nf = -nflr; ++ s8 rssi = snr - nflr; + + atomic_inc(&phist_data->num_samples); + atomic_inc(&phist_data->rx_rate[rx_rate]); +- atomic_inc(&phist_data->snr[snr]); +- atomic_inc(&phist_data->noise_flr[128 + nflr]); +- atomic_inc(&phist_data->sig_str[nflr - snr]); ++ atomic_inc(&phist_data->snr[snr + 128]); ++ atomic_inc(&phist_data->noise_flr[nf + 128]); ++ atomic_inc(&phist_data->sig_str[rssi + 128]); + } + + /* function to reset histogram data during init/reset */ +diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c +index acccd673..ed8b69d1 100644 +--- a/drivers/net/wireless/mwifiex/wmm.c ++++ b/drivers/net/wireless/mwifiex/wmm.c +@@ -501,8 +501,10 @@ mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; + +- skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) ++ skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) { ++ skb_unlink(skb, &ra_list->skb_head); + mwifiex_write_data_complete(adapter, skb, 0, -1); ++ } + } + + /* +@@ -598,11 +600,15 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) + priv->adapter->if_ops.clean_pcie_ring(priv->adapter); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + +- skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) ++ skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) { ++ skb_unlink(skb, &priv->tdls_txq); + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); ++ } + +- skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) ++ skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) { ++ skb_unlink(skb, &priv->bypass_txq); + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); ++ } + atomic_set(&priv->adapter->bypass_tx_pending, 0); + + idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL); +diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c +index 30e3aaae..088429d0 100644 +--- a/drivers/net/wireless/mwl8k.c ++++ b/drivers/net/wireless/mwl8k.c +@@ -5421,11 +5421,13 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, + + static int + mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { +- ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; ++ u8 buf_size = params->buf_size; + int i, rc = 0; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_ampdu_stream *stream; +diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c +index 257a9ead..4ac6764f 100644 +--- a/drivers/net/wireless/p54/fwio.c ++++ b/drivers/net/wireless/p54/fwio.c +@@ -488,7 +488,7 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) + + entry += sizeof(__le16); + chan->pa_points_per_curve = 8; +- memset(chan->curve_data, 0, sizeof(*chan->curve_data)); ++ memset(chan->curve_data, 0, sizeof(chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, curve_data->points_per_channel)); +diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c +index 0881ba85..c78abfc7 100644 +--- a/drivers/net/wireless/ray_cs.c ++++ b/drivers/net/wireless/ray_cs.c +@@ -247,7 +247,10 @@ static const UCHAR b4_default_startup_parms[] = { + 0x04, 0x08, /* Noise gain, limit offset */ + 0x28, 0x28, /* det rssi, med busy offsets */ + 7, /* det sync thresh */ +- 0, 2, 2 /* test mode, min, max */ ++ 0, 2, 2, /* test mode, min, max */ ++ 0, /* rx/tx delay */ ++ 0, 0, 0, 0, 0, 0, /* current BSS id */ ++ 0 /* hop set */ + }; + + /*===========================================================================*/ +@@ -598,7 +601,7 @@ static void init_startup_params(ray_dev_t *local) + * a_beacon_period = hops a_beacon_period = KuS + *//* 64ms = 010000 */ + if (local->fw_ver == 0x55) { +- memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms, ++ memcpy(&local->sparm.b4, b4_default_startup_parms, + sizeof(struct b4_startup_params)); + /* Translate sane kus input values to old build 4/5 format */ + /* i = hop time in uS truncated to 3 bytes */ +diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +index b7f72f9c..b3691712 100644 +--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c ++++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +@@ -1454,6 +1454,7 @@ static int rtl8187_probe(struct usb_interface *intf, + goto err_free_dev; + } + mutex_init(&priv->io_mutex); ++ mutex_init(&priv->conf_mutex); + + SET_IEEE80211_DEV(dev, &intf->dev); + usb_set_intfdata(intf, dev); +@@ -1627,7 +1628,6 @@ static int rtl8187_probe(struct usb_interface *intf, + printk(KERN_ERR "rtl8187: Cannot register device\n"); + goto err_free_dmabuf; + } +- mutex_init(&priv->conf_mutex); + skb_queue_head_init(&priv->b_tx_status.queue); + + wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n", +diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +index 6aed923a..7d820c39 100644 +--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c ++++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c +@@ -5375,13 +5375,13 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + + static int + rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, +- bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + u8 ampdu_factor, ampdu_density; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; + + switch (action) { + case IEEE80211_AMPDU_TX_START: +diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c +index 7a40d8df..5013d8c1 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/base.c ++++ b/drivers/net/wireless/realtek/rtlwifi/base.c +@@ -466,6 +466,11 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) + /* <2> work queue */ + rtlpriv->works.hw = hw; + rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name); ++ if (unlikely(!rtlpriv->works.rtl_wq)) { ++ pr_err("Failed to allocate work queue\n"); ++ return; ++ } ++ + INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, + (void *)rtl_watchdog_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, +@@ -1303,12 +1308,13 @@ EXPORT_SYMBOL_GPL(rtl_action_proc); + + static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) + { ++ struct ieee80211_hw *hw = rtlpriv->hw; ++ + rtlpriv->ra.is_special_data = true; + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( + rtlpriv, 1); +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); ++ rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + +@@ -1381,8 +1387,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + + if (is_tx) { + rtlpriv->ra.is_special_data = true; +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); ++ rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + +diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c +index c925a4df..8006f097 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/core.c ++++ b/drivers/net/wireless/realtek/rtlwifi/core.c +@@ -135,7 +135,6 @@ found_alt: + firmware->size); + rtlpriv->rtlhal.wowlan_fwsize = firmware->size; + } +- rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + } + +@@ -1153,10 +1152,8 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, + } else { + mstatus = RT_MEDIA_DISCONNECT; + +- if (mac->link_state == MAC80211_LINKED) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); +- } ++ if (mac->link_state == MAC80211_LINKED) ++ rtl_lps_leave(hw); + if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE) + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + mac->link_state = MAC80211_NOLINK; +@@ -1371,11 +1368,13 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw, + + static int rtl_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + + switch (action) { + case IEEE80211_AMPDU_TX_START: +@@ -1432,8 +1431,7 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw, + } + + if (mac->link_state == MAC80211_LINKED) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); ++ rtl_lps_leave(hw); + mac->link_state = MAC80211_LINKED_SCANNING; + } else { + rtl_ips_nic_on(hw); +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index 5b404804..b51815ec 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -664,11 +664,9 @@ tx_status_ok: + } + + if (((rtlpriv->link_info.num_rx_inperiod + +- rtlpriv->link_info.num_tx_inperiod) > 8) || +- (rtlpriv->link_info.num_rx_inperiod > 2)) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); +- } ++ rtlpriv->link_info.num_tx_inperiod) > 8) || ++ (rtlpriv->link_info.num_rx_inperiod > 2)) ++ rtl_lps_leave(hw); + } + + static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, +@@ -919,10 +917,8 @@ new_trx_end: + } + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || +- (rtlpriv->link_info.num_rx_inperiod > 2)) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); +- } ++ (rtlpriv->link_info.num_rx_inperiod > 2)) ++ rtl_lps_leave(hw); + skb = new_skb; + no_new: + if (rtlpriv->use_new_trx_flow) { +@@ -1576,7 +1572,14 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) + dev_kfree_skb_irq(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } ++ ++ if (rtlpriv->use_new_trx_flow) { ++ rtlpci->tx_ring[i].cur_tx_rp = 0; ++ rtlpci->tx_ring[i].cur_tx_wp = 0; ++ } ++ + ring->idx = 0; ++ ring->entries = rtlpci->txringcount[i]; + } + } + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +@@ -2273,7 +2276,7 @@ int rtl_pci_probe(struct pci_dev *pdev, + /* find adapter */ + if (!_rtl_pci_find_adapter(pdev, hw)) { + err = -ENODEV; +- goto fail3; ++ goto fail2; + } + + /* Init IO handler */ +@@ -2343,10 +2346,10 @@ fail3: + pci_set_drvdata(pdev, NULL); + rtl_deinit_core(hw); + ++fail2: + if (rtlpriv->io.pci_mem_start != 0) + pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); + +-fail2: + pci_release_regions(pdev); + complete(&rtlpriv->firmware_loading_complete); + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h +index 5da67039..672f81ea 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.h ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.h +@@ -275,10 +275,10 @@ struct mp_adapter { + }; + + struct rtl_pci_priv { ++ struct bt_coexist_info bt_coexist; ++ struct rtl_led_ctl ledctl; + struct rtl_pci dev; + struct mp_adapter ndis_adapter; +- struct rtl_led_ctl ledctl; +- struct bt_coexist_info bt_coexist; + }; + + #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c +index b69321d4..626ff300 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/ps.c ++++ b/drivers/net/wireless/realtek/rtlwifi/ps.c +@@ -414,8 +414,8 @@ void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) + } + } + +-/*Enter the leisure power save mode.*/ +-void rtl_lps_enter(struct ieee80211_hw *hw) ++/* Interrupt safe routine to enter the leisure power save mode.*/ ++static void rtl_lps_enter_core(struct ieee80211_hw *hw) + { + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +@@ -455,10 +455,9 @@ void rtl_lps_enter(struct ieee80211_hw *hw) + + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + } +-EXPORT_SYMBOL(rtl_lps_enter); + +-/*Leave the leisure power save mode.*/ +-void rtl_lps_leave(struct ieee80211_hw *hw) ++/* Interrupt safe routine to leave the leisure power save mode.*/ ++static void rtl_lps_leave_core(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +@@ -488,7 +487,6 @@ void rtl_lps_leave(struct ieee80211_hw *hw) + } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + } +-EXPORT_SYMBOL(rtl_lps_leave); + + /* For sw LPS*/ + void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +@@ -681,12 +679,34 @@ void rtl_lps_change_work_callback(struct work_struct *work) + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->enter_ps) +- rtl_lps_enter(hw); ++ rtl_lps_enter_core(hw); + else +- rtl_lps_leave(hw); ++ rtl_lps_leave_core(hw); + } + EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); + ++void rtl_lps_enter(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (!in_interrupt()) ++ return rtl_lps_enter_core(hw); ++ rtlpriv->enter_ps = true; ++ schedule_work(&rtlpriv->works.lps_change_work); ++} ++EXPORT_SYMBOL_GPL(rtl_lps_enter); ++ ++void rtl_lps_leave(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (!in_interrupt()) ++ return rtl_lps_leave_core(hw); ++ rtlpriv->enter_ps = false; ++ schedule_work(&rtlpriv->works.lps_change_work); ++} ++EXPORT_SYMBOL_GPL(rtl_lps_leave); ++ + void rtl_swlps_wq_callback(void *data) + { + struct rtl_works *rtlworks = container_of_dwork_rtl(data, +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +index 5624ade9..c2a156a8 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +@@ -304,9 +304,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, + writeVal = 0x00000000; + if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) + writeVal = writeVal - 0x06060606; +- else if (rtlpriv->dm.dynamic_txhighpower_lvl == +- TXHIGHPWRLEVEL_BT2) +- writeVal = writeVal; + *(p_outwriteval + rf) = writeVal; + } + } +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +index 0708eedd..1c69e814 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +@@ -664,7 +664,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; +- ++ bool rtstatus; + u32 totalpacketlen; + u8 u1rsvdpageloc[5] = { 0 }; + bool b_dlok = false; +@@ -727,7 +727,9 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) + memcpy((u8 *)skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + +- b_dlok = true; ++ rtstatus = rtl_cmd_send_packet(hw, skb); ++ if (rtstatus) ++ b_dlok = true; + + if (b_dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +index 5f14308e..b1601441 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +@@ -1003,7 +1003,7 @@ static void _rtl92ee_hw_configure(struct ieee80211_hw *hw) + rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a); + + /* Note Data sheet don't define */ +- rtl_write_word(rtlpriv, 0x4C7, 0x80); ++ rtl_write_byte(rtlpriv, 0x4C7, 0x80); + + rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20); + +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +index 5a3df919..89515f02 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +@@ -1123,7 +1123,8 @@ static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw) + + /* Configuration Space offset 0x70f BIT7 is used to control L0S */ + tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f); +- _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7)); ++ _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7) | ++ ASPM_L1_LATENCY << 3); + + /* Configuration Space offset 0x719 Bit3 is for L1 + * BIT4 is for clock request +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +index b57cfd96..7b13962e 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +@@ -2488,9 +2488,9 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter( + for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) + rtldm->swing_idx_ofdm_base[p] = rtldm->swing_idx_ofdm[p]; + +- RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +- "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n", +- rtldm->thermalvalue, thermal_value); ++ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ++ "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n", ++ rtldm->thermalvalue, thermal_value); + /*Record last Power Tracking Thermal Value*/ + rtldm->thermalvalue = thermal_value; + } +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +index bbb789f8..348ed1b0 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +@@ -1127,7 +1127,7 @@ static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr) + } + if (0 == tmp) { + read_addr = REG_DBI_RDATA + addr % 4; +- ret = rtl_read_word(rtlpriv, read_addr); ++ ret = rtl_read_byte(rtlpriv, read_addr); + } + return ret; + } +@@ -1169,7 +1169,8 @@ static void _rtl8821ae_enable_aspm_back_door(struct ieee80211_hw *hw) + } + + tmp = _rtl8821ae_dbi_read(rtlpriv, 0x70f); +- _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7)); ++ _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7) | ++ ASPM_L1_LATENCY << 3); + + tmp = _rtl8821ae_dbi_read(rtlpriv, 0x719); + _rtl8821ae_dbi_write(rtlpriv, 0x719, tmp | BIT(3) | BIT(4)); +@@ -1377,6 +1378,7 @@ static void _rtl8821ae_get_wakeup_reason(struct ieee80211_hw *hw) + + ppsc->wakeup_reason = 0; + ++ do_gettimeofday(&ts); + rtlhal->last_suspend_sec = ts.tv_sec; + + switch (fw_reason) { +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +index 9b4d8a63..4b354918 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +@@ -359,6 +359,107 @@ bool rtl8821ae_phy_rf_config(struct ieee80211_hw *hw) + return rtl8821ae_phy_rf6052_config(hw); + } + ++static void _rtl8812ae_phy_set_rfe_reg_24g(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ u8 tmp; ++ ++ switch (rtlhal->rfe_type) { ++ case 3: ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x54337770); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x54337770); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010); ++ rtl_set_bbreg(hw, 0x900, 0x00000303, 0x1); ++ break; ++ case 4: ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77777777); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x001); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x001); ++ break; ++ case 5: ++ rtl_write_byte(rtlpriv, RA_RFE_PINMUX + 2, 0x77); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777); ++ tmp = rtl_read_byte(rtlpriv, RA_RFE_INV + 3); ++ rtl_write_byte(rtlpriv, RA_RFE_INV + 3, tmp & ~0x1); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000); ++ break; ++ case 1: ++ if (rtlpriv->btcoexist.bt_coexistence) { ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xffffff, 0x777777); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, ++ 0x77777777); ++ rtl_set_bbreg(hw, RA_RFE_INV, 0x33f00000, 0x000); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000); ++ break; ++ } ++ case 0: ++ case 2: ++ default: ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77777777); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77777777); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x000); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000); ++ break; ++ } ++} ++ ++static void _rtl8812ae_phy_set_rfe_reg_5g(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); ++ u8 tmp; ++ ++ switch (rtlhal->rfe_type) { ++ case 0: ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77337717); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337717); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010); ++ break; ++ case 1: ++ if (rtlpriv->btcoexist.bt_coexistence) { ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xffffff, 0x337717); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, ++ 0x77337717); ++ rtl_set_bbreg(hw, RA_RFE_INV, 0x33f00000, 0x000); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000); ++ } else { ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, ++ 0x77337717); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, ++ 0x77337717); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x000); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x000); ++ } ++ break; ++ case 3: ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x54337717); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x54337717); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010); ++ rtl_set_bbreg(hw, 0x900, 0x00000303, 0x1); ++ break; ++ case 5: ++ rtl_write_byte(rtlpriv, RA_RFE_PINMUX + 2, 0x33); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337777); ++ tmp = rtl_read_byte(rtlpriv, RA_RFE_INV + 3); ++ rtl_write_byte(rtlpriv, RA_RFE_INV + 3, tmp | 0x1); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010); ++ break; ++ case 2: ++ case 4: ++ default: ++ rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, 0x77337777); ++ rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, 0x77337777); ++ rtl_set_bbreg(hw, RA_RFE_INV, BMASKRFEINV, 0x010); ++ rtl_set_bbreg(hw, RB_RFE_INV, BMASKRFEINV, 0x010); ++ break; ++ } ++} ++ + u32 phy_get_tx_swing_8812A(struct ieee80211_hw *hw, u8 band, + u8 rf_path) + { +@@ -553,14 +654,9 @@ void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) + /* 0x82C[1:0] = 2b'00 */ + rtl_set_bbreg(hw, 0x82c, 0x3, 0); + } +- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { +- rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, +- 0x77777777); +- rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, +- 0x77777777); +- rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x000); +- rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x000); +- } ++ ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) ++ _rtl8812ae_phy_set_rfe_reg_24g(hw); + + rtl_set_bbreg(hw, RTXPATH, 0xf0, 0x1); + rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, 0x1); +@@ -615,14 +711,8 @@ void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band) + /* 0x82C[1:0] = 2'b00 */ + rtl_set_bbreg(hw, 0x82c, 0x3, 1); + +- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { +- rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD, +- 0x77337777); +- rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD, +- 0x77337777); +- rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x010); +- rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x010); +- } ++ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) ++ _rtl8812ae_phy_set_rfe_reg_5g(hw); + + rtl_set_bbreg(hw, RTXPATH, 0xf0, 0); + rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, 0xf); +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h +index 1d6110f9..ed69dbe1 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h +@@ -2424,6 +2424,7 @@ + #define BMASKH4BITS 0xf0000000 + #define BMASKOFDM_D 0xffc00000 + #define BMASKCCK 0x3f3f3f3f ++#define BMASKRFEINV 0x3ff00000 + + #define BRFREGOFFSETMASK 0xfffff + +diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c +index aac1ed3f..ad8390d2 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/usb.c ++++ b/drivers/net/wireless/realtek/rtlwifi/usb.c +@@ -834,12 +834,30 @@ static void rtl_usb_stop(struct ieee80211_hw *hw) + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); ++ struct urb *urb; + + /* should after adapter start and interrupt enable. */ + set_hal_stop(rtlhal); + cancel_work_sync(&rtlpriv->works.fill_h2c_cmd); + /* Enable software */ + SET_USB_STOP(rtlusb); ++ ++ /* free pre-allocated URBs from rtl_usb_start() */ ++ usb_kill_anchored_urbs(&rtlusb->rx_submitted); ++ ++ tasklet_kill(&rtlusb->rx_work_tasklet); ++ cancel_work_sync(&rtlpriv->works.lps_change_work); ++ ++ flush_workqueue(rtlpriv->works.rtl_wq); ++ ++ skb_queue_purge(&rtlusb->rx_queue); ++ ++ while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { ++ usb_free_coherent(urb->dev, urb->transfer_buffer_length, ++ urb->transfer_buffer, urb->transfer_dma); ++ usb_free_urb(urb); ++ } ++ + rtlpriv->cfg->ops->hw_disable(hw); + } + +@@ -1073,6 +1091,7 @@ int rtl_usb_probe(struct usb_interface *intf, + return -ENOMEM; + } + rtlpriv = hw->priv; ++ rtlpriv->hw = hw; + rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), + GFP_KERNEL); + if (!rtlpriv->usb_data) +diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.h b/drivers/net/wireless/realtek/rtlwifi/usb.h +index 685273ca..441c4412 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/usb.h ++++ b/drivers/net/wireless/realtek/rtlwifi/usb.h +@@ -150,8 +150,9 @@ struct rtl_usb { + }; + + struct rtl_usb_priv { +- struct rtl_usb dev; ++ struct bt_coexist_info bt_coexist; + struct rtl_led_ctl ledctl; ++ struct rtl_usb dev; + }; + + #define rtl_usbpriv(hw) (((struct rtl_usb_priv *)(rtl_priv(hw))->priv)) +diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h +index b6faf624..d676d055 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h ++++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h +@@ -99,6 +99,7 @@ + #define RTL_USB_MAX_RX_COUNT 100 + #define QBSS_LOAD_SIZE 5 + #define MAX_WMMELE_LENGTH 64 ++#define ASPM_L1_LATENCY 7 + + #define TOTAL_CAM_ENTRY 32 + +diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c +index a13d1f2b..c76e0cfb 100644 +--- a/drivers/net/wireless/rndis_wlan.c ++++ b/drivers/net/wireless/rndis_wlan.c +@@ -2919,6 +2919,8 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, + + while (buflen >= sizeof(*auth_req)) { + auth_req = (void *)buf; ++ if (buflen < le32_to_cpu(auth_req->length)) ++ return; + type = "unknown"; + flags = le32_to_cpu(auth_req->flags); + pairwise_error = false; +@@ -3425,6 +3427,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) + + /* because rndis_command() sleeps we need to use workqueue */ + priv->workqueue = create_singlethread_workqueue("rndis_wlan"); ++ if (!priv->workqueue) { ++ wiphy_free(wiphy); ++ return -ENOMEM; ++ } + INIT_WORK(&priv->work, rndis_wlan_worker); + INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); + INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); +diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +index b5bcc933..4df992de 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c ++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c +@@ -659,29 +659,24 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, + * informs the f/w regarding this. + * @hw: Pointer to the ieee80211_hw structure. + * @vif: Pointer to the ieee80211_vif structure. +- * @action: ieee80211_ampdu_mlme_action enum. +- * @sta: Pointer to the ieee80211_sta structure. +- * @tid: Traffic identifier. +- * @ssn: Pointer to ssn value. +- * @buf_size: Buffer size (for kernel version > 2.6.38). +- * @amsdu: is AMSDU in AMPDU allowed ++ * @params: Pointer to A-MPDU action parameters + * + * Return: status: 0 on success, negative error code on failure. + */ + static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, +- unsigned short tid, +- unsigned short *ssn, +- unsigned char buf_size, +- bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + int status = -EOPNOTSUPP; + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + u16 seq_no = 0; + u8 ii = 0; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; ++ u8 buf_size = params->buf_size; + + for (ii = 0; ii < RSI_MAX_VIFS; ii++) { + if (vif == adapter->vifs[ii]) +diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c +index 84288582..fc895b46 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c ++++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c +@@ -155,7 +155,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) + int err; + struct mmc_card *card = pfunction->card; + struct mmc_host *host = card->host; +- s32 bit = (fls(host->ocr_avail) - 1); + u8 cmd52_resp; + u32 clock, resp, i; + u16 rca; +@@ -175,7 +174,6 @@ static void rsi_reset_card(struct sdio_func *pfunction) + msleep(20); + + /* Initialize the SDIO card */ +- host->ios.vdd = bit; + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.power_mode = MMC_POWER_UP; +diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h +index d3fbe33d..a13f08fd 100644 +--- a/drivers/net/wireless/rsi/rsi_common.h ++++ b/drivers/net/wireless/rsi/rsi_common.h +@@ -75,7 +75,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle) + atomic_inc(&handle->thread_done); + rsi_set_event(&handle->event); + +- wait_for_completion(&handle->completion); + return kthread_stop(handle->task); + } + +diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c +index 9733b31a..69c1c096 100644 +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -7935,10 +7935,11 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) + EXPORT_SYMBOL_GPL(rt2800_get_tsf); + + int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; + struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv; + int ret = 0; + +diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h +index 440790b9..83f1a44f 100644 +--- a/drivers/net/wireless/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/rt2x00/rt2800lib.h +@@ -218,9 +218,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, + const struct ieee80211_tx_queue_params *params); + u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu); ++ struct ieee80211_ampdu_params *params); + int rt2800_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev); +diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c +index cd477795..869411f5 100644 +--- a/drivers/net/wireless/ti/wl1251/main.c ++++ b/drivers/net/wireless/ti/wl1251/main.c +@@ -1196,8 +1196,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + + enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; +- wl1251_acx_arp_ip_filter(wl, enable, addr); +- ++ ret = wl1251_acx_arp_ip_filter(wl, enable, addr); + if (ret < 0) + goto out_sleep; + } +@@ -1567,6 +1566,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) + + wl->state = WL1251_STATE_OFF; + mutex_init(&wl->mutex); ++ spin_lock_init(&wl->wl_lock); + + wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; + wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; +diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c +index 09c7e098..085ef5c8 100644 +--- a/drivers/net/wireless/ti/wl18xx/event.c ++++ b/drivers/net/wireless/ti/wl18xx/event.c +@@ -206,5 +206,33 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) + mbox->sc_pwd_len, + mbox->sc_pwd); + ++ if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) { ++ struct wl12xx_vif *wlvif; ++ struct ieee80211_vif *vif; ++ struct ieee80211_sta *sta; ++ u8 link_id = mbox->rx_ba_link_id; ++ u8 win_size = mbox->rx_ba_win_size; ++ const u8 *addr; ++ ++ wlvif = wl->links[link_id].wlvif; ++ vif = wl12xx_wlvif_to_vif(wlvif); ++ ++ /* Update RX aggregation window size and call ++ * MAC routine to stop active RX aggregations for this link ++ */ ++ if (wlvif->bss_type != BSS_TYPE_AP_BSS) ++ addr = vif->bss_conf.bssid; ++ else ++ addr = wl->links[link_id].addr; ++ ++ sta = ieee80211_find_sta(vif, addr); ++ if (sta) { ++ sta->max_rx_aggregation_subframes = win_size; ++ ieee80211_stop_rx_ba_session(vif, ++ wl->links[link_id].ba_bitmap, ++ addr); ++ } ++ } ++ + return 0; + } +diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h +index f3d4f133..9495fadc 100644 +--- a/drivers/net/wireless/ti/wl18xx/event.h ++++ b/drivers/net/wireless/ti/wl18xx/event.h +@@ -38,6 +38,7 @@ enum { + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), + DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), + PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), ++ RX_BA_WIN_SIZE_CHANGE_EVENT_ID = BIT(21), + SMART_CONFIG_SYNC_EVENT_ID = BIT(22), + SMART_CONFIG_DECODE_EVENT_ID = BIT(23), + TIME_SYNC_EVENT_ID = BIT(24), +diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c +index 50cce420..47f355e9 100644 +--- a/drivers/net/wireless/ti/wl18xx/main.c ++++ b/drivers/net/wireless/ti/wl18xx/main.c +@@ -1029,7 +1029,8 @@ static int wl18xx_boot(struct wl1271 *wl) + DFS_CHANNELS_CONFIG_COMPLETE_EVENT | + SMART_CONFIG_SYNC_EVENT_ID | + SMART_CONFIG_DECODE_EVENT_ID | +- TIME_SYNC_EVENT_ID; ++ TIME_SYNC_EVENT_ID | ++ RX_BA_WIN_SIZE_CHANGE_EVENT_ID; + + wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; + +diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c +index f28fa3b5..0646c9b6 100644 +--- a/drivers/net/wireless/ti/wlcore/acx.c ++++ b/drivers/net/wireless/ti/wlcore/acx.c +@@ -1419,7 +1419,8 @@ out: + + /* setup BA session receiver setting in the FW. */ + int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, +- u16 ssn, bool enable, u8 peer_hlid) ++ u16 ssn, bool enable, u8 peer_hlid, ++ u8 win_size) + { + struct wl1271_acx_ba_receiver_setup *acx; + int ret; +@@ -1435,7 +1436,7 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + acx->hlid = peer_hlid; + acx->tid = tid_index; + acx->enable = enable; +- acx->win_size = wl->conf.ht.rx_ba_win_size; ++ acx->win_size = win_size; + acx->ssn = ssn; + + ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx, +diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h +index 954d57ec..524aea49 100644 +--- a/drivers/net/wireless/ti/wlcore/acx.h ++++ b/drivers/net/wireless/ti/wlcore/acx.h +@@ -1112,7 +1112,8 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, + int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, + struct wl12xx_vif *wlvif); + int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, +- u16 ssn, bool enable, u8 peer_hlid); ++ u16 ssn, bool enable, u8 peer_hlid, ++ u8 win_size); + int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u64 *mactime); + int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, +diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c +index 9fd3c6af..e92f2639 100644 +--- a/drivers/net/wireless/ti/wlcore/init.c ++++ b/drivers/net/wireless/ti/wlcore/init.c +@@ -549,11 +549,6 @@ static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) + { + int ret; + +- /* Disable filtering */ +- ret = wl1271_acx_group_address_tbl(wl, wlvif, false, NULL, 0); +- if (ret < 0) +- return ret; +- + ret = wl1271_acx_ap_max_tx_retry(wl, wlvif); + if (ret < 0) + return ret; +diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c +index ec7f6af3..cc10b726 100644 +--- a/drivers/net/wireless/ti/wlcore/main.c ++++ b/drivers/net/wireless/ti/wlcore/main.c +@@ -1123,8 +1123,11 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) + goto out; + + ret = wl12xx_fetch_firmware(wl, plt); +- if (ret < 0) +- goto out; ++ if (ret < 0) { ++ kfree(wl->fw_status); ++ kfree(wl->raw_fw_status); ++ kfree(wl->tx_res_if); ++ } + + out: + return ret; +@@ -5261,14 +5264,16 @@ out: + + static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; + u8 hlid, *ba_bitmap; ++ struct ieee80211_sta *sta = params->sta; ++ enum ieee80211_ampdu_mlme_action action = params->action; ++ u16 tid = params->tid; ++ u16 *ssn = ¶ms->ssn; + + wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, + tid); +@@ -5326,7 +5331,9 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true, +- hlid); ++ hlid, ++ params->buf_size); ++ + if (!ret) { + *ba_bitmap |= BIT(tid); + wl->ba_rx_session_count++; +@@ -5347,7 +5354,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false, +- hlid); ++ hlid, 0); + if (!ret) { + *ba_bitmap &= ~BIT(tid); + wl->ba_rx_session_count--; +diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c +index c172da56..e4a8280c 100644 +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -388,6 +388,11 @@ static int wl1271_suspend(struct device *dev) + mmc_pm_flag_t sdio_flags; + int ret = 0; + ++ if (!wl) { ++ dev_err(dev, "no wilink module was probed\n"); ++ goto out; ++ } ++ + dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n", + wl->wow_enabled); + +diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c +index 44f059f7..9ebe00ea 100644 +--- a/drivers/net/wireless/ti/wlcore/spi.c ++++ b/drivers/net/wireless/ti/wlcore/spi.c +@@ -71,7 +71,7 @@ + * only support SPI for 12xx - this code should be reworked when 18xx + * support is introduced + */ +-#define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) ++#define SPI_AGGR_BUFFER_SIZE (4 * SZ_4K) + + /* Maximum number of SPI write chunks */ + #define WSPI_MAX_NUM_OF_CHUNKS \ +diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c +index 3cdb40fe..f5cedbbc 100644 +--- a/drivers/staging/rtl8188eu/core/rtw_ap.c ++++ b/drivers/staging/rtl8188eu/core/rtw_ap.c +@@ -894,7 +894,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) + return _FAIL; + + +- if (len > MAX_IE_SZ) ++ if (len < 0 || len > MAX_IE_SZ) + return _FAIL; + + pbss_network->IELength = len; +diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c +index 110b8c0b..0f2fe34e 100644 +--- a/drivers/staging/rtl8188eu/core/rtw_recv.c ++++ b/drivers/staging/rtl8188eu/core/rtw_recv.c +@@ -1405,6 +1405,9 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe) + ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); + } + ++ if (!ptr) ++ return _FAIL; ++ + memcpy(ptr, pattrib->dst, ETH_ALEN); + memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); + +diff --git a/drivers/staging/rtl8188eu/include/rtw_debug.h b/drivers/staging/rtl8188eu/include/rtw_debug.h +index 971bf457..e75a3863 100644 +--- a/drivers/staging/rtl8188eu/include/rtw_debug.h ++++ b/drivers/staging/rtl8188eu/include/rtw_debug.h +@@ -75,7 +75,7 @@ extern u32 GlobalDebugLevel; + #define DBG_88E_LEVEL(_level, fmt, arg...) \ + do { \ + if (_level <= GlobalDebugLevel) \ +- pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg); \ ++ pr_info(DRIVER_PREFIX fmt, ##arg); \ + } while (0) + + #define DBG_88E(...) \ +diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +index a076ede5..ec90f278 100644 +--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c ++++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +@@ -1399,19 +1399,13 @@ static int rtw_wx_get_essid(struct net_device *dev, + if ((check_fwstate(pmlmepriv, _FW_LINKED)) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) { + len = pcur_bss->Ssid.SsidLength; +- +- wrqu->essid.length = len; +- + memcpy(extra, pcur_bss->Ssid.Ssid, len); +- +- wrqu->essid.flags = 1; + } else { +- ret = -1; +- goto exit; ++ len = 0; ++ *extra = 0; + } +- +-exit: +- ++ wrqu->essid.length = len; ++ wrqu->essid.flags = 1; + + return ret; + } +diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c +index 82a7c27c..951f2226 100644 +--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c ++++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c +@@ -47,7 +47,10 @@ static struct usb_device_id rtw_usb_id_tbl[] = { + {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ + {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ + {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ ++ {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ ++ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ + {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ + {} /* Terminating entry */ + }; + +diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +index e9c4f973..7a8ceb96 100644 +--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c ++++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +@@ -97,8 +97,9 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) + + switch (variable) { + case HW_VAR_BSSID: +- rtl92e_writel(dev, BSSIDR, ((u32 *)(val))[0]); +- rtl92e_writew(dev, BSSIDR+2, ((u16 *)(val+2))[0]); ++ /* BSSIDR 2 byte alignment */ ++ rtl92e_writew(dev, BSSIDR, *(u16 *)val); ++ rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(val + 2)); + break; + + case HW_VAR_MEDIA_STATUS: +@@ -626,7 +627,7 @@ void rtl92e_get_eeprom_size(struct net_device *dev) + struct r8192_priv *priv = rtllib_priv(dev); + + RT_TRACE(COMP_INIT, "===========>%s()\n", __func__); +- curCR = rtl92e_readl(dev, EPROM_CMD); ++ curCR = rtl92e_readw(dev, EPROM_CMD); + RT_TRACE(COMP_INIT, "read from Reg Cmd9346CR(%x):%x\n", EPROM_CMD, + curCR); + priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EEPROM_93C56 : +@@ -963,8 +964,8 @@ static void _rtl92e_net_update(struct net_device *dev) + rtl92e_config_rate(dev, &rate_config); + priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; + priv->basic_rate = rate_config &= 0x15f; +- rtl92e_writel(dev, BSSIDR, ((u32 *)net->bssid)[0]); +- rtl92e_writew(dev, BSSIDR+4, ((u16 *)net->bssid)[2]); ++ rtl92e_writew(dev, BSSIDR, *(u16 *)net->bssid); ++ rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(net->bssid + 2)); + + if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { + rtl92e_writew(dev, ATIMWND, 2); +@@ -1184,8 +1185,7 @@ void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, + struct cb_desc *cb_desc, struct sk_buff *skb) + { + struct r8192_priv *priv = rtllib_priv(dev); +- dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, +- PCI_DMA_TODEVICE); ++ dma_addr_t mapping; + struct tx_fwinfo_8190pci *pTxFwInfo = NULL; + + pTxFwInfo = (struct tx_fwinfo_8190pci *)skb->data; +@@ -1196,8 +1196,6 @@ void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, + pTxFwInfo->Short = _rtl92e_query_is_short(pTxFwInfo->TxHT, + pTxFwInfo->TxRate, cb_desc); + +- if (pci_dma_mapping_error(priv->pdev, mapping)) +- netdev_err(dev, "%s(): DMA Mapping error\n", __func__); + if (cb_desc->bAMPDUEnable) { + pTxFwInfo->AllowAggregation = 1; + pTxFwInfo->RxMF = cb_desc->ampdu_factor; +@@ -1232,6 +1230,14 @@ void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, + } + + memset((u8 *)pdesc, 0, 12); ++ ++ mapping = pci_map_single(priv->pdev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); ++ if (pci_dma_mapping_error(priv->pdev, mapping)) { ++ netdev_err(dev, "%s(): DMA Mapping error\n", __func__); ++ return; ++ } ++ + pdesc->LINIP = 0; + pdesc->CmdInit = 1; + pdesc->Offset = sizeof(struct tx_fwinfo_8190pci) + 8; +diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c +index e06864f6..0f6bc6b8 100644 +--- a/drivers/staging/rtl8192u/r8192U_core.c ++++ b/drivers/staging/rtl8192u/r8192U_core.c +@@ -1749,6 +1749,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev) + + priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL); + priv->oldaddr = kmalloc(16, GFP_KERNEL); ++ if (!priv->oldaddr) ++ return -ENOMEM; + oldaddr = priv->oldaddr; + align = ((long)oldaddr) & 3; + if (align) { +diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h +index d374824c..7b16c05b 100644 +--- a/drivers/staging/rtl8712/ieee80211.h ++++ b/drivers/staging/rtl8712/ieee80211.h +@@ -143,52 +143,52 @@ struct ieee_ibss_seq { + }; + + struct ieee80211_hdr { +- u16 frame_ctl; +- u16 duration_id; ++ __le16 frame_ctl; ++ __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; +- u16 seq_ctl; ++ __le16 seq_ctl; + u8 addr4[ETH_ALEN]; +-} __packed; ++} __packed __aligned(2); + + struct ieee80211_hdr_3addr { +- u16 frame_ctl; +- u16 duration_id; ++ __le16 frame_ctl; ++ __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; +- u16 seq_ctl; +-} __packed; ++ __le16 seq_ctl; ++} __packed __aligned(2); + + + struct ieee80211_hdr_qos { +- u16 frame_ctl; +- u16 duration_id; ++ __le16 frame_ctl; ++ __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; +- u16 seq_ctl; ++ __le16 seq_ctl; + u8 addr4[ETH_ALEN]; +- u16 qc; +-} __packed; ++ __le16 qc; ++} __packed __aligned(2); + + struct ieee80211_hdr_3addr_qos { +- u16 frame_ctl; +- u16 duration_id; ++ __le16 frame_ctl; ++ __le16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; +- u16 seq_ctl; +- u16 qc; ++ __le16 seq_ctl; ++ __le16 qc; + } __packed; + + struct eapol { + u8 snap[6]; +- u16 ethertype; ++ __be16 ethertype; + u8 version; + u8 type; +- u16 length; ++ __le16 length; + } __packed; + + +@@ -528,13 +528,13 @@ struct ieee80211_security { + */ + + struct ieee80211_header_data { +- u16 frame_ctl; +- u16 duration_id; ++ __le16 frame_ctl; ++ __le16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; +- u16 seq_ctrl; +-}; ++ __le16 seq_ctrl; ++} __packed __aligned(2); + + #define BEACON_PROBE_SSID_ID_POSITION 12 + +@@ -566,18 +566,18 @@ struct ieee80211_info_element { + /* + * These are the data types that can make up management packets + * +- u16 auth_algorithm; +- u16 auth_sequence; +- u16 beacon_interval; +- u16 capability; ++ __le16 auth_algorithm; ++ __le16 auth_sequence; ++ __le16 beacon_interval; ++ __le16 capability; + u8 current_ap[ETH_ALEN]; +- u16 listen_interval; ++ __le16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __packed; +- u32 time_stamp[2]; +- u16 reason; +- u16 status; ++ __le32 time_stamp[2]; ++ __le16 reason; ++ __le16 status; + */ + + #define IEEE80211_DEFAULT_TX_ESSID "Penguin" +@@ -585,16 +585,16 @@ struct ieee80211_info_element { + + struct ieee80211_authentication { + struct ieee80211_header_data header; +- u16 algorithm; +- u16 transaction; +- u16 status; ++ __le16 algorithm; ++ __le16 transaction; ++ __le16 status; + } __packed; + + struct ieee80211_probe_response { + struct ieee80211_header_data header; +- u32 time_stamp[2]; +- u16 beacon_interval; +- u16 capability; ++ __le32 time_stamp[2]; ++ __le16 beacon_interval; ++ __le16 capability; + struct ieee80211_info_element info_element; + } __packed; + +@@ -604,16 +604,16 @@ struct ieee80211_probe_request { + + struct ieee80211_assoc_request_frame { + struct ieee80211_hdr_3addr header; +- u16 capability; +- u16 listen_interval; ++ __le16 capability; ++ __le16 listen_interval; + struct ieee80211_info_element_hdr info_element; + } __packed; + + struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; +- u16 capability; +- u16 status; +- u16 aid; ++ __le16 capability; ++ __le16 status; ++ __le16 aid; + } __packed; + + struct ieee80211_txb { +diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +index edfc6805..2b348439 100644 +--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c ++++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +@@ -199,7 +199,7 @@ static inline char *translate_scan(struct _adapter *padapter, + iwe.cmd = SIOCGIWMODE; + memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs), + 2); +- cap = le16_to_cpu(cap); ++ le16_to_cpus(&cap); + if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) { + if (cap & WLAN_CAPABILITY_BSS) + iwe.u.mode = (u32)IW_MODE_MASTER; +diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c +index 4ff53015..04ac23cc 100644 +--- a/drivers/staging/rtl8712/rtl871x_recv.c ++++ b/drivers/staging/rtl8712/rtl871x_recv.c +@@ -641,11 +641,16 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe) + /* append rx status for mp test packets */ + ptr = recvframe_pull(precvframe, (rmv_len - + sizeof(struct ethhdr) + 2) - 24); ++ if (!ptr) ++ return _FAIL; + memcpy(ptr, get_rxmem(precvframe), 24); + ptr += 24; +- } else ++ } else { + ptr = recvframe_pull(precvframe, (rmv_len - + sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); ++ if (!ptr) ++ return _FAIL; ++ } + + memcpy(ptr, pattrib->dst, ETH_ALEN); + memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); +diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c +index 68d65d23..d3ad89c7 100644 +--- a/drivers/staging/rtl8712/rtl871x_xmit.c ++++ b/drivers/staging/rtl8712/rtl871x_xmit.c +@@ -339,7 +339,8 @@ sint r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, + /* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite + * some settings above.*/ + if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) +- pattrib->priority = (txdesc.txdw1 >> QSEL_SHT) & 0x1f; ++ pattrib->priority = ++ (le32_to_cpu(txdesc.txdw1) >> QSEL_SHT) & 0x1f; + return _SUCCESS; + } + +@@ -479,7 +480,7 @@ static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr, + struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; +- u16 *fctrl = &pwlanhdr->frame_ctl; ++ __le16 *fctrl = &pwlanhdr->frame_ctl; + + memset(hdr, 0, WLANHDR_OFFSET); + SetFrameSubType(fctrl, pattrib->subtype); +@@ -568,7 +569,7 @@ static sint r8712_put_snap(u8 *data, u16 h_proto) + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; +- *(u16 *)(data + SNAP_SIZE) = htons(h_proto); ++ *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); + return SNAP_SIZE + sizeof(u16); + } + +diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c +index a9c1e0ba..e35fbece 100644 +--- a/drivers/staging/wlan-ng/p80211netdev.c ++++ b/drivers/staging/wlan-ng/p80211netdev.c +@@ -232,7 +232,7 @@ static int p80211_convert_to_ether(wlandevice_t *wlandev, struct sk_buff *skb) + struct p80211_hdr_a3 *hdr; + + hdr = (struct p80211_hdr_a3 *) skb->data; +- if (p80211_rx_typedrop(wlandev, hdr->fc)) ++ if (p80211_rx_typedrop(wlandev, le16_to_cpu(hdr->fc))) + return CONV_TO_ETHER_SKIPPED; + + /* perform mcast filtering: allow my local address through but reject +diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c +index 013a6240..c1ad0aea 100644 +--- a/drivers/staging/wlan-ng/prism2mgmt.c ++++ b/drivers/staging/wlan-ng/prism2mgmt.c +@@ -169,7 +169,7 @@ int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) + hw->ident_sta_fw.variant) > + HFA384x_FIRMWARE_VERSION(1, 5, 0)) { + if (msg->scantype.data != P80211ENUM_scantype_active) +- word = cpu_to_le16(msg->maxchanneltime.data); ++ word = msg->maxchanneltime.data; + else + word = 0; + +diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h +index 83430f2e..e0325706 100644 +--- a/include/linux/mmc/sdio_ids.h ++++ b/include/linux/mmc/sdio_ids.h +@@ -33,6 +33,7 @@ + #define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d + #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 + #define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 ++#define SDIO_DEVICE_ID_BROADCOM_43364 0xa9a4 + #define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 + #define SDIO_DEVICE_ID_BROADCOM_4345 0x4345 + #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 +diff --git a/include/linux/nospec.h b/include/linux/nospec.h +new file mode 100644 +index 00000000..0c5ef54f +--- /dev/null ++++ b/include/linux/nospec.h +@@ -0,0 +1,68 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright(c) 2018 Linus Torvalds. All rights reserved. ++// Copyright(c) 2018 Alexei Starovoitov. All rights reserved. ++// Copyright(c) 2018 Intel Corporation. All rights reserved. ++ ++#ifndef _LINUX_NOSPEC_H ++#define _LINUX_NOSPEC_H ++#include ++ ++struct task_struct; ++ ++/** ++ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise ++ * @index: array element index ++ * @size: number of elements in array ++ * ++ * When @index is out of bounds (@index >= @size), the sign bit will be ++ * set. Extend the sign bit to all bits and invert, giving a result of ++ * zero for an out of bounds index, or ~0 if within bounds [0, @size). ++ */ ++#ifndef array_index_mask_nospec ++static inline unsigned long array_index_mask_nospec(unsigned long index, ++ unsigned long size) ++{ ++ /* ++ * Always calculate and emit the mask even if the compiler ++ * thinks the mask is not needed. The compiler does not take ++ * into account the value of @index under speculation. ++ */ ++ OPTIMIZER_HIDE_VAR(index); ++ return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1); ++} ++#endif ++ ++/* ++ * array_index_nospec - sanitize an array index after a bounds check ++ * ++ * For a code sequence like: ++ * ++ * if (index < size) { ++ * index = array_index_nospec(index, size); ++ * val = array[index]; ++ * } ++ * ++ * ...if the CPU speculates past the bounds check then ++ * array_index_nospec() will clamp the index within the range of [0, ++ * size). ++ */ ++#define array_index_nospec(index, size) \ ++({ \ ++ typeof(index) _i = (index); \ ++ typeof(size) _s = (size); \ ++ unsigned long _mask = array_index_mask_nospec(_i, _s); \ ++ \ ++ BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ ++ BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ ++ \ ++ (typeof(_i)) (_i & _mask); \ ++}) ++ ++/* Speculation control prctl */ ++int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which); ++int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, ++ unsigned long ctrl); ++/* Speculation control for seccomp enforced mitigation */ ++void arch_seccomp_spec_mitigate(struct task_struct *task); ++ ++#endif /* _LINUX_NOSPEC_H */ +diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h +index 2c7bdb81..c05748cc 100644 +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -933,9 +933,9 @@ enum rate_info_flags { + * @RATE_INFO_BW_160: 160 MHz bandwidth + */ + enum rate_info_bw { ++ RATE_INFO_BW_20 = 0, + RATE_INFO_BW_5, + RATE_INFO_BW_10, +- RATE_INFO_BW_20, + RATE_INFO_BW_40, + RATE_INFO_BW_80, + RATE_INFO_BW_160, +@@ -4257,6 +4257,17 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, + */ + void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss); + ++/** ++ * cfg80211_abandon_assoc - notify cfg80211 of abandoned association attempt ++ * @dev: network device ++ * @bss: The BSS entry with which association was abandoned. ++ * ++ * Call this whenever - for reasons reported through other API, like deauth RX, ++ * an association attempt was abandoned. ++ * This function may sleep. The caller must hold the corresponding wdev's mutex. ++ */ ++void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss); ++ + /** + * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame + * @dev: network device +diff --git a/include/net/mac80211.h b/include/net/mac80211.h +index 760bc4d5..ec11cb1c 100644 +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -975,7 +975,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) + * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. + * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, + * verification has been done by the hardware. +- * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. ++ * @RX_FLAG_IV_STRIPPED: The IV and ICV are stripped from this frame. + * If this flag is set, the stack cannot do any replay detection + * hence the driver or hardware will have to do that. + * @RX_FLAG_PN_VALIDATED: Currently only valid for CCMP/GCMP frames, this +@@ -1013,6 +1013,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) + * on this subframe + * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC + * is stored in the @ampdu_delimiter_crc field) ++ * @RX_FLAG_MIC_STRIPPED: The mic was stripped of this packet. Decryption was ++ * done by the hardware + * @RX_FLAG_LDPC: LDPC was used + * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3 + * @RX_FLAG_10MHZ: 10 MHz (half channel) was used +@@ -1029,6 +1031,11 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) + * @RX_FLAG_RADIOTAP_VENDOR_DATA: This frame contains vendor-specific + * radiotap data in the skb->data (before the frame) as described by + * the &struct ieee80211_vendor_radiotap. ++ * @RX_FLAG_ALLOW_SAME_PN: Allow the same PN as same packet before. ++ * This is used for AMSDU subframes which can have the same PN as ++ * the first subframe. ++ * @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must ++ * be done in the hardware. + */ + enum mac80211_rx_flags { + RX_FLAG_MMIC_ERROR = BIT(0), +@@ -1059,6 +1066,9 @@ enum mac80211_rx_flags { + RX_FLAG_5MHZ = BIT(29), + RX_FLAG_AMSDU_MORE = BIT(30), + RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(31), ++ RX_FLAG_MIC_STRIPPED = BIT_ULL(32), ++ RX_FLAG_ALLOW_SAME_PN = BIT_ULL(33), ++ RX_FLAG_ICV_STRIPPED = BIT_ULL(34), + }; + + #define RX_FLAG_STBC_SHIFT 26 +@@ -1113,7 +1123,7 @@ struct ieee80211_rx_status { + u64 mactime; + u32 device_timestamp; + u32 ampdu_reference; +- u32 flag; ++ u64 flag; + u16 freq; + u8 vht_flag; + u8 rate_idx; +@@ -1662,6 +1672,9 @@ struct ieee80211_sta_rates { + * @supp_rates: Bitmap of supported rates (per band) + * @ht_cap: HT capabilities of this STA; restricted to our own capabilities + * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities ++ * @max_rx_aggregation_subframes: maximal amount of frames in a single AMPDU ++ * that this station is allowed to transmit to us. ++ * Can be modified by driver. + * @wme: indicates whether the STA supports QoS/WME (if local devices does, + * otherwise always false) + * @drv_priv: data area for driver use, will always be aligned to +@@ -1688,6 +1701,7 @@ struct ieee80211_sta { + u16 aid; + struct ieee80211_sta_ht_cap ht_cap; + struct ieee80211_sta_vht_cap vht_cap; ++ u8 max_rx_aggregation_subframes; + bool wme; + u8 uapsd_queues; + u8 max_sp; +@@ -2673,6 +2687,33 @@ enum ieee80211_ampdu_mlme_action { + IEEE80211_AMPDU_TX_OPERATIONAL, + }; + ++/** ++ * struct ieee80211_ampdu_params - AMPDU action parameters ++ * ++ * @action: the ampdu action, value from %ieee80211_ampdu_mlme_action. ++ * @sta: peer of this AMPDU session ++ * @tid: tid of the BA session ++ * @ssn: start sequence number of the session. TX/RX_STOP can pass 0. When ++ * action is set to %IEEE80211_AMPDU_RX_START the driver passes back the ++ * actual ssn value used to start the session and writes the value here. ++ * @buf_size: reorder buffer size (number of subframes). Valid only when the ++ * action is set to %IEEE80211_AMPDU_RX_START or ++ * %IEEE80211_AMPDU_TX_OPERATIONAL ++ * @amsdu: indicates the peer's ability to receive A-MSDU within A-MPDU. ++ * valid when the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL ++ * @timeout: BA session timeout. Valid only when the action is set to ++ * %IEEE80211_AMPDU_RX_START ++ */ ++struct ieee80211_ampdu_params { ++ enum ieee80211_ampdu_mlme_action action; ++ struct ieee80211_sta *sta; ++ u16 tid; ++ u16 ssn; ++ u8 buf_size; ++ bool amsdu; ++ u16 timeout; ++}; ++ + /** + * enum ieee80211_frame_release_type - frame release reason + * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll +@@ -3017,13 +3058,9 @@ enum ieee80211_reconfig_type { + * @ampdu_action: Perform a certain A-MPDU action + * The RA/TID combination determines the destination and TID we want + * the ampdu action to be performed for. The action is defined through +- * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) +- * is the first frame we expect to perform the action on. Notice +- * that TX/RX_STOP can pass NULL for this parameter. +- * The @buf_size parameter is only valid when the action is set to +- * %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder +- * buffer size (number of subframes) for this session -- the driver +- * may neither send aggregates containing more subframes than this ++ * ieee80211_ampdu_mlme_action. ++ * When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver ++ * may neither send aggregates containing more subframes than @buf_size + * nor send aggregates in a way that lost frames would exceed the + * buffer size. If just limiting the aggregate size, this would be + * possible with a buf_size of 8: +@@ -3034,9 +3071,6 @@ enum ieee80211_reconfig_type { + * buffer size of 8. Correct ways to retransmit #1 would be: + * - TX: 1 or 18 or 81 + * Even "189" would be wrong since 1 could be lost again. +- * The @amsdu parameter is valid when the action is set to +- * %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability +- * to receive A-MSDU within A-MPDU. + * + * Returns a negative error code on failure. + * The callback can sleep. +@@ -3378,9 +3412,7 @@ struct ieee80211_ops { + int (*tx_last_beacon)(struct ieee80211_hw *hw); + int (*ampdu_action)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, u16 *ssn, +- u8 buf_size, bool amsdu); ++ struct ieee80211_ampdu_params *params); + int (*get_survey)(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + void (*rfkill_poll)(struct ieee80211_hw *hw); +@@ -3866,7 +3898,7 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, + * The TX headroom reserved by mac80211 for its own tx_status functions. + * This is enough for the radiotap header. + */ +-#define IEEE80211_TX_STATUS_HEADROOM 14 ++#define IEEE80211_TX_STATUS_HEADROOM ALIGN(14, 4) + + /** + * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames +diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h +index 1f0b4cf5..d3aea4f1 100644 +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -2195,6 +2195,8 @@ enum nl80211_attrs { + #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS + #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS + ++#define NL80211_WIPHY_NAME_MAXLEN 64 ++ + #define NL80211_MAX_SUPP_RATES 32 + #define NL80211_MAX_SUPP_HT_RATES 77 + #define NL80211_MAX_SUPP_REG_RULES 64 +diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c +index 367784be..a830356b 100644 +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -7,6 +7,7 @@ + * Copyright 2006-2007 Jiri Benc + * Copyright 2007, Michael Wu + * Copyright 2007-2010, Intel Corporation ++ * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -61,6 +62,14 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, + { + struct ieee80211_local *local = sta->local; + struct tid_ampdu_rx *tid_rx; ++ struct ieee80211_ampdu_params params = { ++ .sta = &sta->sta, ++ .action = IEEE80211_AMPDU_RX_STOP, ++ .tid = tid, ++ .amsdu = false, ++ .timeout = 0, ++ .ssn = 0, ++ }; + + lockdep_assert_held(&sta->ampdu_mlme.mtx); + +@@ -78,8 +87,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, + initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", + (int)reason); + +- if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, +- &sta->sta, tid, NULL, 0, false)) ++ if (drv_ampdu_action(local, sta->sdata, ¶ms)) + sdata_info(sta->sdata, + "HW problem - can not stop rx aggregation for %pM tid %d\n", + sta->sta.addr, tid); +@@ -237,6 +245,15 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + { + struct ieee80211_local *local = sta->sdata->local; + struct tid_ampdu_rx *tid_agg_rx; ++ struct ieee80211_ampdu_params params = { ++ .sta = &sta->sta, ++ .action = IEEE80211_AMPDU_RX_START, ++ .tid = tid, ++ .amsdu = false, ++ .timeout = timeout, ++ .ssn = start_seq_num, ++ }; ++ + int i, ret = -EOPNOTSUPP; + u16 status = WLAN_STATUS_REQUEST_DECLINED; + +@@ -273,8 +290,12 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + buf_size = IEEE80211_MAX_AMPDU_BUF; + + /* make sure the size doesn't exceed the maximum supported by the hw */ +- if (buf_size > local->hw.max_rx_aggregation_subframes) +- buf_size = local->hw.max_rx_aggregation_subframes; ++ if (buf_size > sta->sta.max_rx_aggregation_subframes) ++ buf_size = sta->sta.max_rx_aggregation_subframes; ++ params.buf_size = buf_size; ++ ++ ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n", ++ buf_size, sta->sta.addr); + + /* examine state machine */ + mutex_lock(&sta->ampdu_mlme.mtx); +@@ -322,8 +343,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, + for (i = 0; i < buf_size; i++) + __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); + +- ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, +- &sta->sta, tid, &start_seq_num, 0, false); ++ ret = drv_ampdu_action(local, sta->sdata, ¶ms); + ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", + sta->sta.addr, tid, ret); + if (ret) { +diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c +index ff757181..4932e9f2 100644 +--- a/net/mac80211/agg-tx.c ++++ b/net/mac80211/agg-tx.c +@@ -7,6 +7,7 @@ + * Copyright 2006-2007 Jiri Benc + * Copyright 2007, Michael Wu + * Copyright 2007-2010, Intel Corporation ++ * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -295,7 +296,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + { + struct ieee80211_local *local = sta->local; + struct tid_ampdu_tx *tid_tx; +- enum ieee80211_ampdu_mlme_action action; ++ struct ieee80211_ampdu_params params = { ++ .sta = &sta->sta, ++ .tid = tid, ++ .buf_size = 0, ++ .amsdu = false, ++ .timeout = 0, ++ .ssn = 0, ++ }; + int ret; + + lockdep_assert_held(&sta->ampdu_mlme.mtx); +@@ -304,10 +312,10 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + case AGG_STOP_DECLINED: + case AGG_STOP_LOCAL_REQUEST: + case AGG_STOP_PEER_REQUEST: +- action = IEEE80211_AMPDU_TX_STOP_CONT; ++ params.action = IEEE80211_AMPDU_TX_STOP_CONT; + break; + case AGG_STOP_DESTROY_STA: +- action = IEEE80211_AMPDU_TX_STOP_FLUSH; ++ params.action = IEEE80211_AMPDU_TX_STOP_FLUSH; + break; + default: + WARN_ON_ONCE(1); +@@ -330,9 +338,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + spin_unlock_bh(&sta->lock); + if (reason != AGG_STOP_DESTROY_STA) + return -EALREADY; +- ret = drv_ampdu_action(local, sta->sdata, +- IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, +- &sta->sta, tid, NULL, 0, false); ++ params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT; ++ ret = drv_ampdu_action(local, sta->sdata, ¶ms); + WARN_ON_ONCE(ret); + return 0; + } +@@ -381,8 +388,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + WLAN_BACK_INITIATOR; + tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST; + +- ret = drv_ampdu_action(local, sta->sdata, action, +- &sta->sta, tid, NULL, 0, false); ++ ret = drv_ampdu_action(local, sta->sdata, ¶ms); + + /* HW shall not deny going back to legacy */ + if (WARN_ON(ret)) { +@@ -445,7 +451,14 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) + struct tid_ampdu_tx *tid_tx; + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; +- u16 start_seq_num; ++ struct ieee80211_ampdu_params params = { ++ .sta = &sta->sta, ++ .action = IEEE80211_AMPDU_TX_START, ++ .tid = tid, ++ .buf_size = 0, ++ .amsdu = false, ++ .timeout = 0, ++ }; + int ret; + + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); +@@ -467,10 +480,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) + */ + synchronize_net(); + +- start_seq_num = sta->tid_seq[tid] >> 4; +- +- ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, +- &sta->sta, tid, &start_seq_num, 0, false); ++ params.ssn = sta->tid_seq[tid] >> 4; ++ ret = drv_ampdu_action(local, sdata, ¶ms); + if (ret) { + ht_dbg(sdata, + "BA request denied - HW unavailable for %pM tid %d\n", +@@ -499,7 +510,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) + + /* send AddBA request */ + ieee80211_send_addba_request(sdata, sta->sta.addr, tid, +- tid_tx->dialog_token, start_seq_num, ++ tid_tx->dialog_token, params.ssn, + IEEE80211_MAX_AMPDU_BUF, + tid_tx->timeout); + } +@@ -684,18 +695,24 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) + { + struct tid_ampdu_tx *tid_tx; ++ struct ieee80211_ampdu_params params = { ++ .sta = &sta->sta, ++ .action = IEEE80211_AMPDU_TX_OPERATIONAL, ++ .tid = tid, ++ .timeout = 0, ++ .ssn = 0, ++ }; + + lockdep_assert_held(&sta->ampdu_mlme.mtx); + + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); ++ params.buf_size = tid_tx->buf_size; ++ params.amsdu = tid_tx->amsdu; + + ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n", + sta->sta.addr, tid); + +- drv_ampdu_action(local, sta->sdata, +- IEEE80211_AMPDU_TX_OPERATIONAL, +- &sta->sta, tid, NULL, tid_tx->buf_size, +- tid_tx->amsdu); ++ drv_ampdu_action(local, sta->sdata, ¶ms); + + /* + * synchronize with TX path, while splicing the TX path +diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c +index 19322c04..7349bf26 100644 +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -219,7 +219,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + /* Keys without a station are used for TX only */ +- if (key->sta && test_sta_flag(key->sta, WLAN_STA_MFP)) ++ if (sta && test_sta_flag(sta, WLAN_STA_MFP)) + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT; + break; + case NL80211_IFTYPE_ADHOC: +@@ -286,7 +286,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, + goto out_unlock; + } + +- ieee80211_key_free(key, true); ++ ieee80211_key_free(key, sdata->vif.type == NL80211_IFTYPE_STATION); + + ret = 0; + out_unlock: +@@ -1228,6 +1228,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) + sta->sta.tdls = true; + ++ if (sta->sta.tdls && sdata->vif.type == NL80211_IFTYPE_STATION && ++ !sdata->u.mgd.associated) ++ return -EINVAL; ++ + err = sta_apply_parameters(local, sta, params); + if (err) { + sta_info_free(local, sta); +@@ -2877,7 +2881,7 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) + } + if (beacon->probe_resp_len) { + new_beacon->probe_resp_len = beacon->probe_resp_len; +- beacon->probe_resp = pos; ++ new_beacon->probe_resp = pos; + memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); + pos += beacon->probe_resp_len; + } +diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c +index 4d2aaebd..e546a987 100644 +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -91,7 +91,7 @@ static const struct file_operations reset_ops = { + }; + #endif + +-static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = { ++static const char *hw_flag_names[] = { + #define FLAG(F) [IEEE80211_HW_##F] = #F + FLAG(HAS_RATE_CONTROL), + FLAG(RX_INCLUDES_FCS), +@@ -125,9 +125,6 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = { + FLAG(TDLS_WIDER_BW), + FLAG(SUPPORTS_AMSDU_IN_AMPDU), + FLAG(BEACON_TX_STATUS), +- +- /* keep last for the build bug below */ +- (void *)0x1 + #undef FLAG + }; + +@@ -147,7 +144,7 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, + /* fail compilation if somebody adds or removes + * a flag without updating the name array above + */ +- BUILD_BUG_ON(hw_flag_names[NUM_IEEE80211_HW_FLAGS] != (void *)0x1); ++ BUILD_BUG_ON(ARRAY_SIZE(hw_flag_names) != NUM_IEEE80211_HW_FLAGS); + + for (i = 0; i < NUM_IEEE80211_HW_FLAGS; i++) { + if (test_bit(i, local->hw.flags)) +diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c +index ca1fe557..c258f104 100644 +--- a/net/mac80211/driver-ops.c ++++ b/net/mac80211/driver-ops.c +@@ -284,9 +284,7 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local, + + int drv_ampdu_action(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, +- u16 *ssn, u8 buf_size, bool amsdu) ++ struct ieee80211_ampdu_params *params) + { + int ret = -EOPNOTSUPP; + +@@ -296,12 +294,10 @@ int drv_ampdu_action(struct ieee80211_local *local, + if (!check_sdata_in_driver(sdata)) + return -EIO; + +- trace_drv_ampdu_action(local, sdata, action, sta, tid, +- ssn, buf_size, amsdu); ++ trace_drv_ampdu_action(local, sdata, params); + + if (local->ops->ampdu_action) +- ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action, +- sta, tid, ssn, buf_size, amsdu); ++ ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); + + trace_drv_return_int(local, ret); + +diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h +index 154ce4b1..6019988b 100644 +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -585,9 +585,7 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) + + int drv_ampdu_action(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, +- u16 *ssn, u8 buf_size, bool amsdu); ++ struct ieee80211_ampdu_params *params); + + static inline int drv_get_survey(struct ieee80211_local *local, int idx, + struct survey_info *survey) +@@ -1159,6 +1157,9 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local, + { + struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif); + ++ if (local->in_reconfig) ++ return; ++ + if (!check_sdata_in_driver(sdata)) + return; + +diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c +index 980e9e9b..f2af1967 100644 +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -66,6 +66,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, + 2 + (IEEE80211_MAX_SUPP_RATES - 8) + + 2 + sizeof(struct ieee80211_ht_cap) + + 2 + sizeof(struct ieee80211_ht_operation) + ++ 2 + sizeof(struct ieee80211_vht_cap) + ++ 2 + sizeof(struct ieee80211_vht_operation) + + ifibss->ie_len; + presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL); + if (!presp) +@@ -486,14 +488,14 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, + struct beacon_data *presp, *old_presp; + struct cfg80211_bss *cbss; + const struct cfg80211_bss_ies *ies; +- u16 capability = 0; ++ u16 capability = WLAN_CAPABILITY_IBSS; + u64 tsf; + int ret = 0; + + sdata_assert_lock(sdata); + + if (ifibss->privacy) +- capability = WLAN_CAPABILITY_PRIVACY; ++ capability |= WLAN_CAPABILITY_PRIVACY; + + cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, + ifibss->bssid, ifibss->ssid, +@@ -946,8 +948,8 @@ static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, + if (len < IEEE80211_DEAUTH_FRAME_LEN) + return; + +- ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM BSSID=%pM (reason: %d)\n", +- mgmt->sa, mgmt->da, mgmt->bssid, reason); ++ ibss_dbg(sdata, "RX DeAuth SA=%pM DA=%pM\n", mgmt->sa, mgmt->da); ++ ibss_dbg(sdata, "\tBSSID=%pM (reason: %d)\n", mgmt->bssid, reason); + sta_info_destroy_addr(sdata, mgmt->sa); + } + +@@ -965,9 +967,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); + +- ibss_dbg(sdata, +- "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", +- mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); ++ ibss_dbg(sdata, "RX Auth SA=%pM DA=%pM\n", mgmt->sa, mgmt->da); ++ ibss_dbg(sdata, "\tBSSID=%pM (auth_transaction=%d)\n", ++ mgmt->bssid, auth_transaction); + + if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) + return; +@@ -1172,10 +1174,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, + rx_timestamp = drv_get_tsf(local, sdata); + } + +- ibss_dbg(sdata, +- "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", ++ ibss_dbg(sdata, "RX beacon SA=%pM BSSID=%pM TSF=0x%llx\n", + mgmt->sa, mgmt->bssid, +- (unsigned long long)rx_timestamp, ++ (unsigned long long)rx_timestamp); ++ ibss_dbg(sdata, "\tBCN=0x%llx diff=%lld @%lu\n", + (unsigned long long)beacon_timestamp, + (unsigned long long)(rx_timestamp - beacon_timestamp), + jiffies); +@@ -1534,9 +1536,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, + + tx_last_beacon = drv_tx_last_beacon(local); + +- ibss_dbg(sdata, +- "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n", +- mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon); ++ ibss_dbg(sdata, "RX ProbeReq SA=%pM DA=%pM\n", mgmt->sa, mgmt->da); ++ ibss_dbg(sdata, "\tBSSID=%pM (tx_last_beacon=%d)\n", ++ mgmt->bssid, tx_last_beacon); + + if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) + return; +diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h +index 6837a46c..7b271f3d 100644 +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -682,7 +682,6 @@ struct ieee80211_if_mesh { + const struct ieee80211_mesh_sync_ops *sync_ops; + s64 sync_offset_clockdrift_max; + spinlock_t sync_offset_lock; +- bool adjusting_tbtt; + /* mesh power save */ + enum nl80211_mesh_power_mode nonpeer_pm; + int ps_peers_light_sleep; +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index bcb0a1b6..519def0e 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -987,6 +987,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, + if (local->open_count == 0) + ieee80211_clear_tx_pending(local); + ++ sdata->vif.bss_conf.beacon_int = 0; ++ + /* + * If the interface goes down while suspended, presumably because + * the device was unplugged and that happens before our resume, +@@ -1441,7 +1443,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, + break; + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: +- BUG(); ++ WARN_ON(1); + break; + } + +diff --git a/net/mac80211/key.c b/net/mac80211/key.c +index 44388d6a..91a4e606 100644 +--- a/net/mac80211/key.c ++++ b/net/mac80211/key.c +@@ -4,6 +4,7 @@ + * Copyright 2006-2007 Jiri Benc + * Copyright 2007-2008 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH ++ * Copyright 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -18,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include "ieee80211_i.h" + #include "driver-ops.h" +@@ -606,20 +608,54 @@ void ieee80211_key_free_unused(struct ieee80211_key *key) + ieee80211_key_free_common(key); + } + ++static bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_key *old, ++ struct ieee80211_key *new) ++{ ++ u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP]; ++ u8 *tk_old, *tk_new; ++ ++ if (!old || new->conf.keylen != old->conf.keylen) ++ return false; ++ ++ tk_old = old->conf.key; ++ tk_new = new->conf.key; ++ ++ /* ++ * In station mode, don't compare the TX MIC key, as it's never used ++ * and offloaded rekeying may not care to send it to the host. This ++ * is the case in iwlwifi, for example. ++ */ ++ if (sdata->vif.type == NL80211_IFTYPE_STATION && ++ new->conf.cipher == WLAN_CIPHER_SUITE_TKIP && ++ new->conf.keylen == WLAN_KEY_LEN_TKIP && ++ !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) { ++ memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP); ++ memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP); ++ memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8); ++ memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8); ++ tk_old = tkip_old; ++ tk_new = tkip_new; ++ } ++ ++ return !crypto_memneq(tk_old, tk_new, new->conf.keylen); ++} ++ + int ieee80211_key_link(struct ieee80211_key *key, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_key *old_key; +- int idx, ret; +- bool pairwise; +- +- pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; +- idx = key->conf.keyidx; +- key->local = sdata->local; +- key->sdata = sdata; +- key->sta = sta; ++ int idx = key->conf.keyidx; ++ bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; ++ /* ++ * We want to delay tailroom updates only for station - in that ++ * case it helps roaming speed, but in other cases it hurts and ++ * can cause warnings to appear. ++ */ ++ bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; ++ int ret; + + mutex_lock(&sdata->local->key_mtx); + +@@ -630,21 +666,36 @@ int ieee80211_key_link(struct ieee80211_key *key, + else + old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); + ++ /* ++ * Silently accept key re-installation without really installing the ++ * new version of the key to avoid nonce reuse or replay issues. ++ */ ++ if (ieee80211_key_identical(sdata, old_key, key)) { ++ ieee80211_key_free_unused(key); ++ ret = 0; ++ goto out; ++ } ++ ++ key->local = sdata->local; ++ key->sdata = sdata; ++ key->sta = sta; ++ + increment_tailroom_need_count(sdata); + + ieee80211_key_replace(sdata, sta, pairwise, old_key, key); +- ieee80211_key_destroy(old_key, true); ++ ieee80211_key_destroy(old_key, delay_tailroom); + + ieee80211_debugfs_key_add(key); + + if (!local->wowlan) { + ret = ieee80211_key_enable_hw_accel(key); + if (ret) +- ieee80211_key_free(key, true); ++ ieee80211_key_free(key, delay_tailroom); + } else { + ret = 0; + } + ++ out: + mutex_unlock(&sdata->local->key_mtx); + + return ret; +@@ -827,7 +878,8 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, + ieee80211_key_replace(key->sdata, key->sta, + key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, + key, NULL); +- __ieee80211_key_destroy(key, true); ++ __ieee80211_key_destroy(key, key->sdata->vif.type == ++ NL80211_IFTYPE_STATION); + } + + for (i = 0; i < NUM_DEFAULT_KEYS; i++) { +@@ -837,7 +889,8 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, + ieee80211_key_replace(key->sdata, key->sta, + key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, + key, NULL); +- __ieee80211_key_destroy(key, true); ++ __ieee80211_key_destroy(key, key->sdata->vif.type == ++ NL80211_IFTYPE_STATION); + } + + mutex_unlock(&local->key_mtx); +diff --git a/net/mac80211/main.c b/net/mac80211/main.c +index 175ffcf7..15d23aee 100644 +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -253,8 +253,27 @@ static void ieee80211_restart_work(struct work_struct *work) + "%s called with hardware scan in progress\n", __func__); + + rtnl_lock(); +- list_for_each_entry(sdata, &local->interfaces, list) ++ list_for_each_entry(sdata, &local->interfaces, list) { ++ /* ++ * XXX: there may be more work for other vif types and even ++ * for station mode: a good thing would be to run most of ++ * the iface type's dependent _stop (ieee80211_mg_stop, ++ * ieee80211_ibss_stop) etc... ++ * For now, fix only the specific bug that was seen: race ++ * between csa_connection_drop_work and us. ++ */ ++ if (sdata->vif.type == NL80211_IFTYPE_STATION) { ++ /* ++ * This worker is scheduled from the iface worker that ++ * runs on mac80211's workqueue, so we can't be ++ * scheduling this worker after the cancel right here. ++ * The exception is ieee80211_chswitch_done. ++ * Then we can have a race... ++ */ ++ cancel_work_sync(&sdata->u.mgd.csa_connection_drop_work); ++ } + flush_delayed_work(&sdata->dec_tailroom_needed_wk); ++ } + ieee80211_scan_cancel(local); + ieee80211_reconfig(local); + rtnl_unlock(); +@@ -460,10 +479,7 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { + cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_SHORT_GI_160 | +- IEEE80211_VHT_CAP_RXSTBC_1 | +- IEEE80211_VHT_CAP_RXSTBC_2 | +- IEEE80211_VHT_CAP_RXSTBC_3 | +- IEEE80211_VHT_CAP_RXSTBC_4 | ++ IEEE80211_VHT_CAP_RXSTBC_MASK | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | +@@ -891,12 +907,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) + supp_ht = supp_ht || sband->ht_cap.ht_supported; + supp_vht = supp_vht || sband->vht_cap.vht_supported; + +- if (sband->ht_cap.ht_supported) +- local->rx_chains = +- max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), +- local->rx_chains); ++ if (!sband->ht_cap.ht_supported) ++ continue; + + /* TODO: consider VHT for RX chains, hopefully it's the same */ ++ local->rx_chains = ++ max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), ++ local->rx_chains); ++ ++ /* no need to mask, SM_PS_DISABLED has all bits set */ ++ sband->ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED << ++ IEEE80211_HT_CAP_SM_PS_SHIFT; + } + + /* if low-level driver supports AP, we also support VLAN */ +diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c +index f7bb6829..1cbc7bd2 100644 +--- a/net/mac80211/mesh.c ++++ b/net/mac80211/mesh.c +@@ -295,10 +295,6 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, + /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ + *pos |= ifmsh->ps_peers_deep_sleep ? + IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00; +- *pos++ |= ifmsh->adjusting_tbtt ? +- IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; +- *pos++ = 0x00; +- + return 0; + } + +@@ -355,7 +351,7 @@ int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata, + /* fast-forward to vendor IEs */ + offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0); + +- if (offset) { ++ if (offset < ifmsh->ie_len) { + len = ifmsh->ie_len - offset; + data = ifmsh->ie + offset; + if (skb_tailroom(skb) < len) +@@ -866,7 +862,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) + ifmsh->mesh_cc_id = 0; /* Disabled */ + /* register sync ops from extensible synchronization framework */ + ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); +- ifmsh->adjusting_tbtt = false; + ifmsh->sync_offset_clockdrift_max = 0; + set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); + ieee80211_mesh_root_setup(ifmsh); +diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c +index b6dc2d7c..466922f0 100644 +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -552,6 +552,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, + forward = false; + reply = true; + target_metric = 0; ++ ++ if (SN_GT(target_sn, ifmsh->sn)) ++ ifmsh->sn = target_sn; ++ + if (time_after(jiffies, ifmsh->last_sn_update + + net_traversal_jiffies(sdata)) || + time_before(jiffies, ifmsh->last_sn_update)) { +@@ -776,7 +780,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + struct mesh_path *mpath; + u8 ttl, flags, hopcount; + const u8 *orig_addr; +- u32 orig_sn, metric, metric_txsta, interval; ++ u32 orig_sn, new_metric, orig_metric, last_hop_metric, interval; + bool root_is_gate; + + ttl = rann->rann_ttl; +@@ -787,7 +791,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + interval = le32_to_cpu(rann->rann_interval); + hopcount = rann->rann_hopcount; + hopcount++; +- metric = le32_to_cpu(rann->rann_metric); ++ orig_metric = le32_to_cpu(rann->rann_metric); + + /* Ignore our own RANNs */ + if (ether_addr_equal(orig_addr, sdata->vif.addr)) +@@ -804,7 +808,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + return; + } + +- metric_txsta = airtime_link_metric_get(local, sta); ++ last_hop_metric = airtime_link_metric_get(local, sta); ++ new_metric = orig_metric + last_hop_metric; ++ if (new_metric < orig_metric) ++ new_metric = MAX_METRIC; + + mpath = mesh_path_lookup(sdata, orig_addr); + if (!mpath) { +@@ -817,7 +824,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + } + + if (!(SN_LT(mpath->sn, orig_sn)) && +- !(mpath->sn == orig_sn && metric < mpath->rann_metric)) { ++ !(mpath->sn == orig_sn && new_metric < mpath->rann_metric)) { + rcu_read_unlock(); + return; + } +@@ -835,7 +842,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + } + + mpath->sn = orig_sn; +- mpath->rann_metric = metric + metric_txsta; ++ mpath->rann_metric = new_metric; + mpath->is_root = true; + /* Recording RANNs sender address to send individually + * addressed PREQs destined for root mesh STA */ +@@ -855,7 +862,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, + mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, + orig_sn, 0, NULL, 0, broadcast_addr, + hopcount, ttl, interval, +- metric + metric_txsta, 0, sdata); ++ new_metric, 0, sdata); + } + + rcu_read_unlock(); +diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c +index bd3d55eb..9f02e54a 100644 +--- a/net/mac80211/mesh_plink.c ++++ b/net/mac80211/mesh_plink.c +@@ -495,12 +495,14 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, + + /* Userspace handles station allocation */ + if (sdata->u.mesh.user_mpm || +- sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) +- cfg80211_notify_new_peer_candidate(sdata->dev, addr, +- elems->ie_start, +- elems->total_len, +- GFP_KERNEL); +- else ++ sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { ++ if (mesh_peer_accepts_plinks(elems) && ++ mesh_plink_availables(sdata)) ++ cfg80211_notify_new_peer_candidate(sdata->dev, addr, ++ elems->ie_start, ++ elems->total_len, ++ GFP_KERNEL); ++ } else + sta = __mesh_sta_info_alloc(sdata, addr); + + return sta; +diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c +index 64bc22ad..16ed43fe 100644 +--- a/net/mac80211/mesh_sync.c ++++ b/net/mac80211/mesh_sync.c +@@ -119,7 +119,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, + */ + + if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { +- clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); + msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", + sta->sta.addr); + goto no_sync; +@@ -168,11 +167,9 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata, + struct beacon_data *beacon) + { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- u8 cap; + + WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); + WARN_ON(!rcu_read_lock_held()); +- cap = beacon->meshconf->meshconf_cap; + + spin_lock_bh(&ifmsh->sync_offset_lock); + +@@ -186,21 +183,13 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata, + "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n", + ifmsh->sync_offset_clockdrift_max); + set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags); +- +- ifmsh->adjusting_tbtt = true; + } else { + msync_dbg(sdata, + "TBTT : max clockdrift=%lld; too small to adjust\n", + (long long)ifmsh->sync_offset_clockdrift_max); + ifmsh->sync_offset_clockdrift_max = 0; +- +- ifmsh->adjusting_tbtt = false; + } + spin_unlock_bh(&ifmsh->sync_offset_lock); +- +- beacon->meshconf->meshconf_cap = ifmsh->adjusting_tbtt ? +- IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING | cap : +- ~IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING & cap; + } + + static const struct sync_method sync_methods[] = { +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 83097c38..08384dbf 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -1021,6 +1021,10 @@ static void ieee80211_chswitch_work(struct work_struct *work) + */ + + if (sdata->reserved_chanctx) { ++ struct ieee80211_supported_band *sband = NULL; ++ struct sta_info *mgd_sta = NULL; ++ enum ieee80211_sta_rx_bandwidth bw = IEEE80211_STA_RX_BW_20; ++ + /* + * with multi-vif csa driver may call ieee80211_csa_finish() + * many times while waiting for other interfaces to use their +@@ -1029,6 +1033,48 @@ static void ieee80211_chswitch_work(struct work_struct *work) + if (sdata->reserved_ready) + goto out; + ++ if (sdata->vif.bss_conf.chandef.width != ++ sdata->csa_chandef.width) { ++ /* ++ * For managed interface, we need to also update the AP ++ * station bandwidth and align the rate scale algorithm ++ * on the bandwidth change. Here we only consider the ++ * bandwidth of the new channel definition (as channel ++ * switch flow does not have the full HT/VHT/HE ++ * information), assuming that if additional changes are ++ * required they would be done as part of the processing ++ * of the next beacon from the AP. ++ */ ++ switch (sdata->csa_chandef.width) { ++ case NL80211_CHAN_WIDTH_20_NOHT: ++ case NL80211_CHAN_WIDTH_20: ++ default: ++ bw = IEEE80211_STA_RX_BW_20; ++ break; ++ case NL80211_CHAN_WIDTH_40: ++ bw = IEEE80211_STA_RX_BW_40; ++ break; ++ case NL80211_CHAN_WIDTH_80: ++ bw = IEEE80211_STA_RX_BW_80; ++ break; ++ case NL80211_CHAN_WIDTH_80P80: ++ case NL80211_CHAN_WIDTH_160: ++ bw = IEEE80211_STA_RX_BW_160; ++ break; ++ } ++ ++ mgd_sta = sta_info_get(sdata, ifmgd->bssid); ++ sband = ++ local->hw.wiphy->bands[sdata->csa_chandef.chan->band]; ++ } ++ ++ if (sdata->vif.bss_conf.chandef.width > ++ sdata->csa_chandef.width) { ++ mgd_sta->sta.bandwidth = bw; ++ rate_control_rate_update(local, sband, mgd_sta, ++ IEEE80211_RC_BW_CHANGED); ++ } ++ + ret = ieee80211_vif_use_reserved_context(sdata); + if (ret) { + sdata_info(sdata, +@@ -1039,6 +1085,13 @@ static void ieee80211_chswitch_work(struct work_struct *work) + goto out; + } + ++ if (sdata->vif.bss_conf.chandef.width < ++ sdata->csa_chandef.width) { ++ mgd_sta->sta.bandwidth = bw; ++ rate_control_rate_update(local, sband, mgd_sta, ++ IEEE80211_RC_BW_CHANGED); ++ } ++ + goto out; + } + +@@ -1051,9 +1104,6 @@ static void ieee80211_chswitch_work(struct work_struct *work) + goto out; + } + +- /* XXX: shouldn't really modify cfg80211-owned data! */ +- ifmgd->associated->channel = sdata->csa_chandef.chan; +- + ifmgd->csa_waiting_bcn = true; + + ieee80211_sta_reset_beacon_monitor(sdata); +@@ -1833,7 +1883,8 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, + params[ac].acm = acm; + params[ac].uapsd = uapsd; + +- if (params[ac].cw_min > params[ac].cw_max) { ++ if (params[ac].cw_min == 0 || ++ params[ac].cw_min > params[ac].cw_max) { + sdata_info(sdata, + "AP has invalid WMM params (CWmin/max=%d/%d for ACI %d), using defaults\n", + params[ac].cw_min, params[ac].cw_max, aci); +@@ -2517,7 +2568,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, + } + + static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, +- bool assoc) ++ bool assoc, bool abandon) + { + struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; + +@@ -2539,6 +2590,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, + mutex_lock(&sdata->local->mtx); + ieee80211_vif_release_channel(sdata); + mutex_unlock(&sdata->local->mtx); ++ ++ if (abandon) ++ cfg80211_abandon_assoc(sdata->dev, assoc_data->bss); + } + + kfree(assoc_data); +@@ -2768,7 +2822,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, + bssid, reason_code, + ieee80211_get_reason_code_string(reason_code)); + +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, true); + + cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); + return; +@@ -3173,14 +3227,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + if (status_code != WLAN_STATUS_SUCCESS) { + sdata_info(sdata, "%pM denied association (code=%d)\n", + mgmt->sa, status_code); +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, false); + event.u.mlme.status = MLME_DENIED; + event.u.mlme.reason = status_code; + drv_event_callback(sdata->local, sdata, &event); + } else { + if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { + /* oops -- internal error -- send timeout for now */ +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, false); + cfg80211_assoc_timeout(sdata->dev, bss); + return; + } +@@ -3193,7 +3247,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + * recalc after assoc_data is NULL but before associated + * is set can cause the interface to go idle + */ +- ieee80211_destroy_assoc_data(sdata, true); ++ ieee80211_destroy_assoc_data(sdata, true, false); + + /* get uapsd queues configuration */ + uapsd_queues = 0; +@@ -3888,7 +3942,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) + .u.mlme.status = MLME_TIMEOUT, + }; + +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, false); + cfg80211_assoc_timeout(sdata->dev, bss); + drv_event_callback(sdata->local, sdata, &event); + } +@@ -4029,7 +4083,7 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) + WLAN_REASON_DEAUTH_LEAVING, + false, frame_buf); + if (ifmgd->assoc_data) +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, true); + if (ifmgd->auth_data) + ieee80211_destroy_auth_data(sdata, false); + cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, +@@ -4323,6 +4377,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, + if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) + return -EINVAL; + ++ /* If a reconfig is happening, bail out */ ++ if (local->in_reconfig) ++ return -EBUSY; ++ + if (assoc) { + rcu_read_lock(); + have_sta = sta_info_get(sdata, cbss->bssid); +@@ -4905,7 +4963,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + IEEE80211_STYPE_DEAUTH, + req->reason_code, tx, + frame_buf); +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, true); + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, + req->reason_code); +@@ -4980,7 +5038,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) + sdata_lock(sdata); + if (ifmgd->assoc_data) { + struct cfg80211_bss *bss = ifmgd->assoc_data->bss; +- ieee80211_destroy_assoc_data(sdata, false); ++ ieee80211_destroy_assoc_data(sdata, false, false); + cfg80211_assoc_timeout(sdata->dev, bss); + } + if (ifmgd->auth_data) +diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c +index 04401037..b6be5194 100644 +--- a/net/mac80211/offchannel.c ++++ b/net/mac80211/offchannel.c +@@ -469,6 +469,8 @@ void ieee80211_roc_purge(struct ieee80211_local *local, + struct ieee80211_roc_work *roc, *tmp; + LIST_HEAD(tmp_list); + ++ flush_work(&local->hw_roc_start); ++ + mutex_lock(&local->mtx); + list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { + if (sdata && roc->sdata != sdata) +diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c +index 00a43a70..0402fa45 100644 +--- a/net/mac80211/pm.c ++++ b/net/mac80211/pm.c +@@ -168,6 +168,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) + break; + } + ++ flush_delayed_work(&sdata->dec_tailroom_needed_wk); + drv_remove_interface(local, sdata); + } + +diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c +index 2b528389..833ad779 100644 +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -149,6 +149,9 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, + /* allocate extra bitmaps */ + if (status->chains) + len += 4 * hweight8(status->chains); ++ /* vendor presence bitmap */ ++ if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) ++ len += 4; + + if (ieee80211_have_rx_timestamp(status)) { + len = ALIGN(len, 8); +@@ -185,8 +188,6 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, + if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { + struct ieee80211_vendor_radiotap *rtap = (void *)skb->data; + +- /* vendor presence bitmap */ +- len += 4; + /* alignment for fixed 6-byte vendor data header */ + len = ALIGN(len, 2); + /* vendor data header */ +@@ -1109,6 +1110,7 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) + return RX_CONTINUE; + + if (ieee80211_is_ctl(hdr->frame_control) || ++ ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) + return RX_CONTINUE; +@@ -1455,12 +1457,16 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) + */ + if (!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS) && + !ieee80211_has_morefrags(hdr->frame_control) && ++ !ieee80211_is_back_req(hdr->frame_control) && + !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && + (rx->sdata->vif.type == NL80211_IFTYPE_AP || + rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && +- /* PM bit is only checked in frames where it isn't reserved, ++ /* ++ * PM bit is only checked in frames where it isn't reserved, + * in AP mode it's reserved in non-bufferable management frames + * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field) ++ * BAR frames should be ignored as specified in ++ * IEEE 802.11-2012 10.2.1.2. + */ + (!ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_bufferable_mmpdu(hdr->frame_control))) { +@@ -2334,7 +2340,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) + skb_set_queue_mapping(skb, q); + + if (!--mesh_hdr->ttl) { +- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); ++ if (!is_multicast_ether_addr(hdr->addr1)) ++ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, ++ dropped_frames_ttl); + goto out; + } + +@@ -3363,6 +3371,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) + } + return true; + case NL80211_IFTYPE_MESH_POINT: ++ if (ether_addr_equal(sdata->vif.addr, hdr->addr2)) ++ return false; + if (multicast) + return true; + return ether_addr_equal(sdata->vif.addr, hdr->addr1); +@@ -3396,6 +3406,27 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) + !ether_addr_equal(bssid, hdr->addr1)) + return false; + } ++ ++ /* ++ * 802.11-2016 Table 9-26 says that for data frames, A1 must be ++ * the BSSID - we've checked that already but may have accepted ++ * the wildcard (ff:ff:ff:ff:ff:ff). ++ * ++ * It also says: ++ * The BSSID of the Data frame is determined as follows: ++ * a) If the STA is contained within an AP or is associated ++ * with an AP, the BSSID is the address currently in use ++ * by the STA contained in the AP. ++ * ++ * So we should not accept data frames with an address that's ++ * multicast. ++ * ++ * Accepting it also opens a security problem because stations ++ * could encrypt it with the GTK and inject traffic that way. ++ */ ++ if (ieee80211_is_data(hdr->frame_control) && multicast) ++ return false; ++ + return true; + case NL80211_IFTYPE_WDS: + if (bssid || !ieee80211_is_data(hdr->frame_control)) +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 67066d04..7e7b9ef2 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -329,6 +329,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + + memcpy(sta->addr, addr, ETH_ALEN); + memcpy(sta->sta.addr, addr, ETH_ALEN); ++ sta->sta.max_rx_aggregation_subframes = ++ local->hw.max_rx_aggregation_subframes; ++ + sta->local = local; + sta->sdata = sdata; + sta->rx_stats.last_rx = jiffies; +@@ -658,7 +661,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) + } + + /* No need to do anything if the driver does all */ +- if (ieee80211_hw_check(&local->hw, AP_LINK_PS)) ++ if (ieee80211_hw_check(&local->hw, AP_LINK_PS) && !local->ops->set_tim) + return; + + if (sta->dead) +diff --git a/net/mac80211/status.c b/net/mac80211/status.c +index 5bad05e9..d221300e 100644 +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -194,6 +194,7 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) + } + + if (ieee80211_is_action(mgmt->frame_control) && ++ !ieee80211_has_protected(mgmt->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_HT && + mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS && + ieee80211_sdata_running(sdata)) { +@@ -465,11 +466,6 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, + if (!skb) + return; + +- if (dropped) { +- dev_kfree_skb_any(skb); +- return; +- } +- + if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { + u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie; + struct ieee80211_sub_if_data *sdata; +@@ -490,6 +486,8 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local, + } + rcu_read_unlock(); + ++ dev_kfree_skb_any(skb); ++ } else if (dropped) { + dev_kfree_skb_any(skb); + } else { + /* consumes skb */ +@@ -650,6 +648,8 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw, + /* Track when last TDLS packet was ACKed */ + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) + sta->status_stats.last_tdls_pkt_time = jiffies; ++ } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) { ++ return; + } else { + ieee80211_lost_packet(sta, info); + } +diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h +index 56c6d6cf..913e959b 100644 +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -80,7 +80,23 @@ + #define KEY_PR_FMT " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d" + #define KEY_PR_ARG __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx + +- ++#define AMPDU_ACTION_ENTRY __field(enum ieee80211_ampdu_mlme_action, \ ++ ieee80211_ampdu_mlme_action) \ ++ STA_ENTRY \ ++ __field(u16, tid) \ ++ __field(u16, ssn) \ ++ __field(u8, buf_size) \ ++ __field(bool, amsdu) \ ++ __field(u16, timeout) ++#define AMPDU_ACTION_ASSIGN STA_NAMED_ASSIGN(params->sta); \ ++ __entry->tid = params->tid; \ ++ __entry->ssn = params->ssn; \ ++ __entry->buf_size = params->buf_size; \ ++ __entry->amsdu = params->amsdu; \ ++ __entry->timeout = params->timeout; ++#define AMPDU_ACTION_PR_FMT STA_PR_FMT " tid %d, ssn %d, buf_size %u, amsdu %d, timeout %d" ++#define AMPDU_ACTION_PR_ARG STA_PR_ARG, __entry->tid, __entry->ssn, \ ++ __entry->buf_size, __entry->amsdu, __entry->timeout + + /* + * Tracing for driver callbacks. +@@ -970,38 +986,25 @@ DEFINE_EVENT(local_only_evt, drv_tx_last_beacon, + TRACE_EVENT(drv_ampdu_action, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, +- enum ieee80211_ampdu_mlme_action action, +- struct ieee80211_sta *sta, u16 tid, +- u16 *ssn, u8 buf_size, bool amsdu), ++ struct ieee80211_ampdu_params *params), + +- TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu), ++ TP_ARGS(local, sdata, params), + + TP_STRUCT__entry( + LOCAL_ENTRY +- STA_ENTRY +- __field(u32, action) +- __field(u16, tid) +- __field(u16, ssn) +- __field(u8, buf_size) +- __field(bool, amsdu) + VIF_ENTRY ++ AMPDU_ACTION_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; +- STA_ASSIGN; +- __entry->action = action; +- __entry->tid = tid; +- __entry->ssn = ssn ? *ssn : 0; +- __entry->buf_size = buf_size; +- __entry->amsdu = amsdu; ++ AMPDU_ACTION_ASSIGN; + ), + + TP_printk( +- LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d", +- LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, +- __entry->tid, __entry->buf_size, __entry->amsdu ++ LOCAL_PR_FMT VIF_PR_FMT AMPDU_ACTION_PR_FMT, ++ LOCAL_PR_ARG, VIF_PR_ARG, AMPDU_ACTION_PR_ARG + ) + ); + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index e1225b39..41f3eb56 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -431,8 +431,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) + if (ieee80211_hw_check(&tx->local->hw, QUEUE_CONTROL)) + info->hw_queue = tx->sdata->vif.cab_queue; + +- /* no stations in PS mode */ +- if (!atomic_read(&ps->num_sta_ps)) ++ /* no stations in PS mode and no buffered packets */ ++ if (!atomic_read(&ps->num_sta_ps) && skb_queue_empty(&ps->bc_buf)) + return TX_CONTINUE; + + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; +@@ -1599,9 +1599,16 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, + int head_need, bool may_encrypt) + { + struct ieee80211_local *local = sdata->local; ++ struct ieee80211_hdr *hdr; ++ bool enc_tailroom; + int tail_need = 0; + +- if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) { ++ hdr = (struct ieee80211_hdr *) skb->data; ++ enc_tailroom = may_encrypt && ++ (sdata->crypto_tx_tailroom_needed_cnt || ++ ieee80211_is_mgmt(hdr->frame_control)); ++ ++ if (enc_tailroom) { + tail_need = IEEE80211_ENCRYPT_TAILROOM; + tail_need -= skb_tailroom(skb); + tail_need = max_t(int, tail_need, 0); +@@ -1609,8 +1616,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, + + if (skb_cloned(skb) && + (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) || +- !skb_clone_writable(skb, ETH_HLEN) || +- (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt))) ++ !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom)) + I802_DEBUG_INC(local->tx_expand_skb_head_cloned); + else if (head_need || tail_need) + I802_DEBUG_INC(local->tx_expand_skb_head); +@@ -2699,7 +2705,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, + int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2); + int hw_headroom = sdata->local->hw.extra_tx_headroom; + struct ethhdr eth; +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_tx_info *info; + struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; + struct ieee80211_tx_data tx; + ieee80211_tx_result r; +@@ -2761,6 +2767,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, + memcpy(skb->data + fast_tx->da_offs, eth.h_dest, ETH_ALEN); + memcpy(skb->data + fast_tx->sa_offs, eth.h_source, ETH_ALEN); + ++ info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + info->band = fast_tx->band; + info->control.vif = &sdata->vif; +diff --git a/net/mac80211/util.c b/net/mac80211/util.c +index 33344f5a..2214c77d 100644 +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -2006,7 +2006,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) + if (!sta->uploaded) + continue; + +- if (sta->sdata->vif.type != NL80211_IFTYPE_AP) ++ if (sta->sdata->vif.type != NL80211_IFTYPE_AP && ++ sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN) + continue; + + for (state = IEEE80211_STA_NOTEXIST; +@@ -2663,8 +2664,9 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + + rate = cfg80211_calculate_bitrate(&ri); + if (WARN_ONCE(!rate, +- "Invalid bitrate: flags=0x%x, idx=%d, vht_nss=%d\n", +- status->flag, status->rate_idx, status->vht_nss)) ++ "Invalid bitrate: flags=0x%llx, idx=%d, vht_nss=%d\n", ++ (unsigned long long)status->flag, status->rate_idx, ++ status->vht_nss)) + return 0; + + /* rewind from end of MPDU */ +diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c +index efa3f48f..73e8f347 100644 +--- a/net/mac80211/wep.c ++++ b/net/mac80211/wep.c +@@ -293,7 +293,8 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) + return RX_DROP_UNUSABLE; + ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); + /* remove ICV */ +- if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) ++ if (!(status->flag & RX_FLAG_ICV_STRIPPED) && ++ pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) + return RX_DROP_UNUSABLE; + } + +diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c +index d824c389..cb439e06 100644 +--- a/net/mac80211/wpa.c ++++ b/net/mac80211/wpa.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include "ieee80211_i.h" + #include "michael.h" +@@ -152,7 +153,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) + data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; + key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; + michael_mic(key, hdr, data, data_len, mic); +- if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) ++ if (crypto_memneq(mic, data + data_len, MICHAEL_MIC_LEN)) + goto mic_fail; + + /* remove Michael MIC from payload */ +@@ -297,7 +298,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) + return RX_DROP_UNUSABLE; + + /* Trim ICV */ +- skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN); ++ if (!(status->flag & RX_FLAG_ICV_STRIPPED)) ++ skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN); + + /* Remove IV */ + memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen); +@@ -507,25 +509,31 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, + !ieee80211_is_robust_mgmt_frame(skb)) + return RX_CONTINUE; + +- data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - mic_len; +- if (!rx->sta || data_len < 0) +- return RX_DROP_UNUSABLE; +- + if (status->flag & RX_FLAG_DECRYPTED) { + if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_CCMP_HDR_LEN)) + return RX_DROP_UNUSABLE; ++ if (status->flag & RX_FLAG_MIC_STRIPPED) ++ mic_len = 0; + } else { + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + } + ++ data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - mic_len; ++ if (!rx->sta || data_len < 0) ++ return RX_DROP_UNUSABLE; ++ + if (!(status->flag & RX_FLAG_PN_VALIDATED)) { ++ int res; ++ + ccmp_hdr2pn(pn, skb->data + hdrlen); + + queue = rx->security_idx; + +- if (memcmp(pn, key->u.ccmp.rx_pn[queue], +- IEEE80211_CCMP_PN_LEN) <= 0) { ++ res = memcmp(pn, key->u.ccmp.rx_pn[queue], ++ IEEE80211_CCMP_PN_LEN); ++ if (res < 0 || ++ (!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) { + key->u.ccmp.replays++; + return RX_DROP_UNUSABLE; + } +@@ -723,8 +731,7 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) + struct sk_buff *skb = rx->skb; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + u8 pn[IEEE80211_GCMP_PN_LEN]; +- int data_len; +- int queue; ++ int data_len, queue, mic_len = IEEE80211_GCMP_MIC_LEN; + + hdrlen = ieee80211_hdrlen(hdr->frame_control); + +@@ -732,26 +739,31 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) + !ieee80211_is_robust_mgmt_frame(skb)) + return RX_CONTINUE; + +- data_len = skb->len - hdrlen - IEEE80211_GCMP_HDR_LEN - +- IEEE80211_GCMP_MIC_LEN; +- if (!rx->sta || data_len < 0) +- return RX_DROP_UNUSABLE; +- + if (status->flag & RX_FLAG_DECRYPTED) { + if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_GCMP_HDR_LEN)) + return RX_DROP_UNUSABLE; ++ if (status->flag & RX_FLAG_MIC_STRIPPED) ++ mic_len = 0; + } else { + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; + } + ++ data_len = skb->len - hdrlen - IEEE80211_GCMP_HDR_LEN - mic_len; ++ if (!rx->sta || data_len < 0) ++ return RX_DROP_UNUSABLE; ++ + if (!(status->flag & RX_FLAG_PN_VALIDATED)) { ++ int res; ++ + gcmp_hdr2pn(pn, skb->data + hdrlen); + + queue = rx->security_idx; + +- if (memcmp(pn, key->u.gcmp.rx_pn[queue], +- IEEE80211_GCMP_PN_LEN) <= 0) { ++ res = memcmp(pn, key->u.gcmp.rx_pn[queue], ++ IEEE80211_GCMP_PN_LEN); ++ if (res < 0 || ++ (!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) { + key->u.gcmp.replays++; + return RX_DROP_UNUSABLE; + } +@@ -775,7 +787,7 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) + } + + /* Remove GCMP header and MIC */ +- if (pskb_trim(skb, skb->len - IEEE80211_GCMP_MIC_LEN)) ++ if (pskb_trim(skb, skb->len - mic_len)) + return RX_DROP_UNUSABLE; + memmove(skb->data + IEEE80211_GCMP_HDR_LEN, skb->data, hdrlen); + skb_pull(skb, IEEE80211_GCMP_HDR_LEN); +@@ -1044,7 +1056,7 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) + bip_aad(skb, aad); + ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mic); +- if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { ++ if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { + key->u.aes_cmac.icverrors++; + return RX_DROP_UNUSABLE; + } +@@ -1094,7 +1106,7 @@ ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx) + bip_aad(skb, aad); + ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, + skb->data + 24, skb->len - 24, mic); +- if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { ++ if (crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { + key->u.aes_cmac.icverrors++; + return RX_DROP_UNUSABLE; + } +@@ -1198,7 +1210,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) + if (ieee80211_aes_gmac(key->u.aes_gmac.tfm, aad, nonce, + skb->data + 24, skb->len - 24, + mic) < 0 || +- memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { ++ crypto_memneq(mic, mmie->mic, sizeof(mmie->mic))) { + key->u.aes_gmac.icverrors++; + return RX_DROP_UNUSABLE; + } +diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig +index 44c3be9d..598d374f 100644 +--- a/net/rfkill/Kconfig ++++ b/net/rfkill/Kconfig +@@ -10,11 +10,6 @@ menuconfig RFKILL + To compile this driver as a module, choose M here: the + module will be called rfkill. + +-config RFKILL_PM +- bool "Power off on suspend" +- depends on RFKILL && PM +- default y +- + # LED trigger support + config RFKILL_LEDS + bool +diff --git a/net/rfkill/core.c b/net/rfkill/core.c +index d778d993..cf5b69ab 100644 +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -802,7 +802,7 @@ void rfkill_resume_polling(struct rfkill *rfkill) + } + EXPORT_SYMBOL(rfkill_resume_polling); + +-#ifdef CONFIG_RFKILL_PM ++#ifdef CONFIG_PM_SLEEP + static int rfkill_suspend(struct device *dev) + { + struct rfkill *rfkill = to_rfkill(dev); +@@ -838,9 +838,7 @@ static struct class rfkill_class = { + .dev_release = rfkill_release, + .dev_groups = rfkill_dev_groups, + .dev_uevent = rfkill_dev_uevent, +-#ifdef CONFIG_RFKILL_PM + .pm = RFKILL_PM_OPS, +-#endif + }; + + bool rfkill_blocked(struct rfkill *rfkill) +diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c +index 93127220..e6e249cc 100644 +--- a/net/rfkill/rfkill-gpio.c ++++ b/net/rfkill/rfkill-gpio.c +@@ -140,13 +140,18 @@ static int rfkill_gpio_probe(struct platform_device *pdev) + + ret = rfkill_register(rfkill->rfkill_dev); + if (ret < 0) +- return ret; ++ goto err_destroy; + + platform_set_drvdata(pdev, rfkill); + + dev_info(&pdev->dev, "%s device registered.\n", rfkill->name); + + return 0; ++ ++err_destroy: ++ rfkill_destroy(rfkill->rfkill_dev); ++ ++ return ret; + } + + static int rfkill_gpio_remove(struct platform_device *pdev) +diff --git a/net/wireless/core.c b/net/wireless/core.c +index 8f0bac7e..a1e909ae 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -94,6 +94,9 @@ static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, + + ASSERT_RTNL(); + ++ if (strlen(newname) > NL80211_WIPHY_NAME_MAXLEN) ++ return -EINVAL; ++ + /* prohibit calling the thing phy%d when %d is not its number */ + sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); + if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { +@@ -390,6 +393,8 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, + if (rv) + goto use_default_name; + } else { ++ int rv; ++ + use_default_name: + /* NOTE: This is *probably* safe w/out holding rtnl because of + * the restrictions on phy names. Probably this call could +@@ -397,7 +402,11 @@ use_default_name: + * phyX. But, might should add some locking and check return + * value, and use a different name if this one exists? + */ +- dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); ++ rv = dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); ++ if (rv < 0) { ++ kfree(rdev); ++ return NULL; ++ } + } + + INIT_LIST_HEAD(&rdev->wdev_list); +diff --git a/net/wireless/core.h b/net/wireless/core.h +index a618b4b8..47ea169a 100644 +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -72,6 +72,7 @@ struct cfg80211_registered_device { + struct list_head bss_list; + struct rb_root bss_tree; + u32 bss_generation; ++ u32 bss_entries; + struct cfg80211_scan_request *scan_req; /* protected by RTNL */ + struct sk_buff *scan_msg; + struct cfg80211_sched_scan_request __rcu *sched_scan_req; +@@ -397,6 +398,7 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev); + void cfg80211_sme_deauth(struct wireless_dev *wdev); + void cfg80211_sme_auth_timeout(struct wireless_dev *wdev); + void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev); ++void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev); + + /* internal helpers */ + bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); +diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c +index fb44fa3b..c0e02f72 100644 +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -149,6 +149,18 @@ void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss) + } + EXPORT_SYMBOL(cfg80211_assoc_timeout); + ++void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct wiphy *wiphy = wdev->wiphy; ++ ++ cfg80211_sme_abandon_assoc(wdev); ++ ++ cfg80211_unhold_bss(bss_from_pub(bss)); ++ cfg80211_put_bss(wiphy, bss); ++} ++EXPORT_SYMBOL(cfg80211_abandon_assoc); ++ + void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) + { + struct wireless_dev *wdev = dev->ieee80211_ptr; +diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c +index bf65f31b..1968998e 100644 +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -302,8 +303,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, + [NL80211_ATTR_PID] = { .type = NLA_U32 }, + [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, +- [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, +- .len = WLAN_PMKID_LEN }, ++ [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN }, + [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, + [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, + [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, +@@ -359,6 +359,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, + [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, + [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, ++ [NL80211_ATTR_LOCAL_MESH_POWER_MODE] = {. type = NLA_U32 }, + [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, + [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, +@@ -485,6 +486,14 @@ nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = { + [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 }, + }; + ++/* policy for packet pattern attributes */ ++static const struct nla_policy ++nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = { ++ [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, }, ++ [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, }, ++ [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 }, ++}; ++ + static int nl80211_prepare_wdev_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct cfg80211_registered_device **rdev, +@@ -492,21 +501,17 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, + { + int err; + +- rtnl_lock(); +- + if (!cb->args[0]) { + err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, + nl80211_fam.attrbuf, nl80211_fam.maxattr, + nl80211_policy); + if (err) +- goto out_unlock; ++ return err; + + *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), + nl80211_fam.attrbuf); +- if (IS_ERR(*wdev)) { +- err = PTR_ERR(*wdev); +- goto out_unlock; +- } ++ if (IS_ERR(*wdev)) ++ return PTR_ERR(*wdev); + *rdev = wiphy_to_rdev((*wdev)->wiphy); + /* 0 is the first index - add 1 to parse only once */ + cb->args[0] = (*rdev)->wiphy_idx + 1; +@@ -516,10 +521,8 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, + struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1); + struct wireless_dev *tmp; + +- if (!wiphy) { +- err = -ENODEV; +- goto out_unlock; +- } ++ if (!wiphy) ++ return -ENODEV; + *rdev = wiphy_to_rdev(wiphy); + *wdev = NULL; + +@@ -530,21 +533,11 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, + } + } + +- if (!*wdev) { +- err = -ENODEV; +- goto out_unlock; +- } ++ if (!*wdev) ++ return -ENODEV; + } + + return 0; +- out_unlock: +- rtnl_unlock(); +- return err; +-} +- +-static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) +-{ +- rtnl_unlock(); + } + + /* IE validation */ +@@ -1887,20 +1880,22 @@ static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { + static int parse_txq_params(struct nlattr *tb[], + struct ieee80211_txq_params *txq_params) + { ++ u8 ac; ++ + if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] || + !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || + !tb[NL80211_TXQ_ATTR_AIFS]) + return -EINVAL; + +- txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]); ++ ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]); + txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); + txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); + txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); + txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); + +- if (txq_params->ac >= NL80211_NUM_ACS) ++ if (ac >= NL80211_NUM_ACS) + return -EINVAL; +- ++ txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS); + return 0; + } + +@@ -3583,6 +3578,7 @@ static int parse_station_flags(struct genl_info *info, + params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_MFP) | + BIT(NL80211_STA_FLAG_AUTHORIZED); ++ break; + default: + return -EINVAL; + } +@@ -3884,9 +3880,10 @@ static int nl80211_dump_station(struct sk_buff *skb, + int sta_idx = cb->args[2]; + int err; + ++ rtnl_lock(); + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + if (err) +- return err; ++ goto out_err; + + if (!wdev->netdev) { + err = -EINVAL; +@@ -3922,7 +3919,7 @@ static int nl80211_dump_station(struct sk_buff *skb, + cb->args[2] = sta_idx; + err = skb->len; + out_err: +- nl80211_finish_wdev_dump(rdev); ++ rtnl_unlock(); + + return err; + } +@@ -4639,9 +4636,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, + int path_idx = cb->args[2]; + int err; + ++ rtnl_lock(); + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + if (err) +- return err; ++ goto out_err; + + if (!rdev->ops->dump_mpath) { + err = -EOPNOTSUPP; +@@ -4675,7 +4673,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, + cb->args[2] = path_idx; + err = skb->len; + out_err: +- nl80211_finish_wdev_dump(rdev); ++ rtnl_unlock(); + return err; + } + +@@ -4835,9 +4833,10 @@ static int nl80211_dump_mpp(struct sk_buff *skb, + int path_idx = cb->args[2]; + int err; + ++ rtnl_lock(); + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + if (err) +- return err; ++ goto out_err; + + if (!rdev->ops->dump_mpp) { + err = -EOPNOTSUPP; +@@ -4870,7 +4869,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb, + cb->args[2] = path_idx; + err = skb->len; + out_err: +- nl80211_finish_wdev_dump(rdev); ++ rtnl_unlock(); + return err; + } + +@@ -5718,6 +5717,10 @@ static int validate_scan_freqs(struct nlattr *freqs) + struct nlattr *attr1, *attr2; + int n_channels = 0, tmp1, tmp2; + ++ nla_for_each_nested(attr1, freqs, tmp1) ++ if (nla_len(attr1) != sizeof(u32)) ++ return 0; ++ + nla_for_each_nested(attr1, freqs, tmp1) { + n_channels++; + /* +@@ -6806,9 +6809,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) + int start = cb->args[2], idx = 0; + int err; + ++ rtnl_lock(); + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); +- if (err) ++ if (err) { ++ rtnl_unlock(); + return err; ++ } + + wdev_lock(wdev); + spin_lock_bh(&rdev->bss_lock); +@@ -6831,7 +6837,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) + wdev_unlock(wdev); + + cb->args[2] = idx; +- nl80211_finish_wdev_dump(rdev); ++ rtnl_unlock(); + + return skb->len; + } +@@ -6915,9 +6921,10 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) + int res; + bool radio_stats; + ++ rtnl_lock(); + res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); + if (res) +- return res; ++ goto out_err; + + /* prepare_wdev_dump parsed the attributes */ + radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS]; +@@ -6958,7 +6965,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) + cb->args[2] = survey_idx; + res = skb->len; + out_err: +- nl80211_finish_wdev_dump(rdev); ++ rtnl_unlock(); + return res; + } + +@@ -9415,7 +9422,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) + u8 *mask_pat; + + nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), +- nla_len(pat), NULL); ++ nla_len(pat), nl80211_packet_pattern_policy); + err = -EINVAL; + if (!pat_tb[NL80211_PKTPAT_MASK] || + !pat_tb[NL80211_PKTPAT_PATTERN]) +@@ -9665,7 +9672,7 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev, + u8 *mask_pat; + + nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), +- nla_len(pat), NULL); ++ nla_len(pat), nl80211_packet_pattern_policy); + if (!pat_tb[NL80211_PKTPAT_MASK] || + !pat_tb[NL80211_PKTPAT_PATTERN]) + return -EINVAL; +@@ -9791,6 +9798,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) + if (err) + return err; + ++ if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] || ++ !tb[NL80211_REKEY_DATA_KCK]) ++ return -EINVAL; + if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN) + return -ERANGE; + if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN) +@@ -10004,6 +10014,7 @@ static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_MDID] || ++ !info->attrs[NL80211_ATTR_IE] || + !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + +@@ -10158,17 +10169,13 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, + void *data = NULL; + unsigned int data_len = 0; + +- rtnl_lock(); +- + if (cb->args[0]) { + /* subtract the 1 again here */ + struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1); + struct wireless_dev *tmp; + +- if (!wiphy) { +- err = -ENODEV; +- goto out_unlock; +- } ++ if (!wiphy) ++ return -ENODEV; + *rdev = wiphy_to_rdev(wiphy); + *wdev = NULL; + +@@ -10189,13 +10196,11 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, + nl80211_fam.attrbuf, nl80211_fam.maxattr, + nl80211_policy); + if (err) +- goto out_unlock; ++ return err; + + if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] || +- !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) { +- err = -EINVAL; +- goto out_unlock; +- } ++ !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) ++ return -EINVAL; + + *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), + nl80211_fam.attrbuf); +@@ -10204,10 +10209,8 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, + + *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), + nl80211_fam.attrbuf); +- if (IS_ERR(*rdev)) { +- err = PTR_ERR(*rdev); +- goto out_unlock; +- } ++ if (IS_ERR(*rdev)) ++ return PTR_ERR(*rdev); + + vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]); +@@ -10220,19 +10223,15 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, + if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd) + continue; + +- if (!vcmd->dumpit) { +- err = -EOPNOTSUPP; +- goto out_unlock; +- } ++ if (!vcmd->dumpit) ++ return -EOPNOTSUPP; + + vcmd_idx = i; + break; + } + +- if (vcmd_idx < 0) { +- err = -EOPNOTSUPP; +- goto out_unlock; +- } ++ if (vcmd_idx < 0) ++ return -EOPNOTSUPP; + + if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) { + data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]); +@@ -10249,9 +10248,6 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, + + /* keep rtnl locked in successful case */ + return 0; +- out_unlock: +- rtnl_unlock(); +- return err; + } + + static int nl80211_vendor_cmd_dump(struct sk_buff *skb, +@@ -10266,9 +10262,10 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb, + int err; + struct nlattr *vendor_data; + ++ rtnl_lock(); + err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev); + if (err) +- return err; ++ goto out; + + vcmd_idx = cb->args[2]; + data = (void *)cb->args[3]; +@@ -10277,18 +10274,26 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb, + + if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV)) { +- if (!wdev) +- return -EINVAL; ++ if (!wdev) { ++ err = -EINVAL; ++ goto out; ++ } + if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV && +- !wdev->netdev) +- return -EINVAL; ++ !wdev->netdev) { ++ err = -EINVAL; ++ goto out; ++ } + + if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) { + if (wdev->netdev && +- !netif_running(wdev->netdev)) +- return -ENETDOWN; +- if (!wdev->netdev && !wdev->p2p_started) +- return -ENETDOWN; ++ !netif_running(wdev->netdev)) { ++ err = -ENETDOWN; ++ goto out; ++ } ++ if (!wdev->netdev && !wdev->p2p_started) { ++ err = -ENETDOWN; ++ goto out; ++ } + } + } + +@@ -11716,7 +11721,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, + struct sk_buff *msg; + void *hdr; + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ msg = nlmsg_new(100 + len, gfp); + if (!msg) + return; + +@@ -11868,7 +11873,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, + struct sk_buff *msg; + void *hdr; + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp); + if (!msg) + return; + +@@ -11908,7 +11913,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, + struct sk_buff *msg; + void *hdr; + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp); + if (!msg) + return; + +@@ -11946,7 +11951,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, + struct sk_buff *msg; + void *hdr; + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ msg = nlmsg_new(100 + ie_len, GFP_KERNEL); + if (!msg) + return; + +@@ -12023,7 +12028,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, + + trace_cfg80211_notify_new_peer_candidate(dev, addr); + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ msg = nlmsg_new(100 + ie_len, gfp); + if (!msg) + return; + +@@ -12392,7 +12397,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, + struct sk_buff *msg; + void *hdr; + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + +@@ -12435,7 +12440,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, + + trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ msg = nlmsg_new(100 + len, gfp); + if (!msg) + return; + +@@ -12783,6 +12788,11 @@ void cfg80211_ch_switch_notify(struct net_device *dev, + + wdev->chandef = *chandef; + wdev->preset_chandef = *chandef; ++ ++ if (wdev->iftype == NL80211_IFTYPE_STATION && ++ !WARN_ON(!wdev->current_bss)) ++ wdev->current_bss->pub.channel = chandef->chan; ++ + nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, + NL80211_CMD_CH_SWITCH_NOTIFY, 0); + } +@@ -13168,13 +13178,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb, + + list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { + bool schedule_destroy_work = false; +- bool schedule_scan_stop = false; + struct cfg80211_sched_scan_request *sched_scan_req = + rcu_dereference(rdev->sched_scan_req); + + if (sched_scan_req && notify->portid && +- sched_scan_req->owner_nlportid == notify->portid) +- schedule_scan_stop = true; ++ sched_scan_req->owner_nlportid == notify->portid) { ++ sched_scan_req->owner_nlportid = 0; ++ ++ if (rdev->ops->sched_scan_stop && ++ rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ++ schedule_work(&rdev->sched_scan_stop_wk); ++ } + + list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { + cfg80211_mlme_unregister_socket(wdev, notify->portid); +@@ -13205,12 +13219,6 @@ static int nl80211_netlink_notify(struct notifier_block * nb, + spin_unlock(&rdev->destroy_list_lock); + schedule_work(&rdev->destroy_work); + } +- } else if (schedule_scan_stop) { +- sched_scan_req->owner_nlportid = 0; +- +- if (rdev->ops->sched_scan_stop && +- rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) +- schedule_work(&rdev->sched_scan_stop_wk); + } + } + +@@ -13241,7 +13249,7 @@ void cfg80211_ft_event(struct net_device *netdev, + if (!ft_event->target_ap) + return; + +- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL); + if (!msg) + return; + +diff --git a/net/wireless/reg.c b/net/wireless/reg.c +index 06d050da..429abf42 100644 +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -780,7 +780,7 @@ static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, + * definitions (the "2.4 GHz band", the "5 GHz band" and the "60GHz band"), + * however it is safe for now to assume that a frequency rule should not be + * part of a frequency's band if the start freq or end freq are off by more +- * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 10 GHz for the ++ * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 20 GHz for the + * 60 GHz band. + * This resolution can be lowered and should be considered as we add + * regulatory rule support for other "bands". +@@ -795,7 +795,7 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, + * with the Channel starting frequency above 45 GHz. + */ + u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? +- 10 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; ++ 20 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; + if (abs(freq_khz - freq_range->start_freq_khz) <= limit) + return true; + if (abs(freq_khz - freq_range->end_freq_khz) <= limit) +@@ -2367,6 +2367,7 @@ static int regulatory_hint_core(const char *alpha2) + request->alpha2[0] = alpha2[0]; + request->alpha2[1] = alpha2[1]; + request->initiator = NL80211_REGDOM_SET_BY_CORE; ++ request->wiphy_idx = WIPHY_IDX_INVALID; + + queue_regulatory_request(request); + +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 30f96766..8dde12a1 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -56,7 +56,20 @@ + * also linked into the probe response struct. + */ + +-#define IEEE80211_SCAN_RESULT_EXPIRE (7 * HZ) ++/* ++ * Limit the number of BSS entries stored in mac80211. Each one is ++ * a bit over 4k at most, so this limits to roughly 4-5M of memory. ++ * If somebody wants to really attack this though, they'd likely ++ * use small beacons, and only one type of frame, limiting each of ++ * the entries to a much smaller size (in order to generate more ++ * entries in total, so overhead is bigger.) ++ */ ++static int bss_entries_limit = 1000; ++module_param(bss_entries_limit, int, 0644); ++MODULE_PARM_DESC(bss_entries_limit, ++ "limit to number of scan BSS entries (per wiphy, default 1000)"); ++ ++#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) + + static void bss_free(struct cfg80211_internal_bss *bss) + { +@@ -136,6 +149,10 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev, + + list_del_init(&bss->list); + rb_erase(&bss->rbn, &rdev->bss_tree); ++ rdev->bss_entries--; ++ WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list), ++ "rdev bss entries[%d]/list[empty:%d] corruption\n", ++ rdev->bss_entries, list_empty(&rdev->bss_list)); + bss_ref_put(rdev, bss); + return true; + } +@@ -162,6 +179,40 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev, + rdev->bss_generation++; + } + ++static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev) ++{ ++ struct cfg80211_internal_bss *bss, *oldest = NULL; ++ bool ret; ++ ++ lockdep_assert_held(&rdev->bss_lock); ++ ++ list_for_each_entry(bss, &rdev->bss_list, list) { ++ if (atomic_read(&bss->hold)) ++ continue; ++ ++ if (!list_empty(&bss->hidden_list) && ++ !bss->pub.hidden_beacon_bss) ++ continue; ++ ++ if (oldest && time_before(oldest->ts, bss->ts)) ++ continue; ++ oldest = bss; ++ } ++ ++ if (WARN_ON(!oldest)) ++ return false; ++ ++ /* ++ * The callers make sure to increase rdev->bss_generation if anything ++ * gets removed (and a new entry added), so there's no need to also do ++ * it here. ++ */ ++ ++ ret = __cfg80211_unlink_bss(rdev, oldest); ++ WARN_ON(!ret); ++ return ret; ++} ++ + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, + bool send_message) + { +@@ -687,6 +738,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, + const u8 *ie; + int i, ssidlen; + u8 fold = 0; ++ u32 n_entries = 0; + + ies = rcu_access_pointer(new->pub.beacon_ies); + if (WARN_ON(!ies)) +@@ -710,6 +762,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, + /* This is the bad part ... */ + + list_for_each_entry(bss, &rdev->bss_list, list) { ++ /* ++ * we're iterating all the entries anyway, so take the ++ * opportunity to validate the list length accounting ++ */ ++ n_entries++; ++ + if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid)) + continue; + if (bss->pub.channel != new->pub.channel) +@@ -738,6 +796,10 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, + new->pub.beacon_ies); + } + ++ WARN_ONCE(n_entries != rdev->bss_entries, ++ "rdev bss entries[%d]/list[len:%d] corruption\n", ++ rdev->bss_entries, n_entries); ++ + return true; + } + +@@ -890,7 +952,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, + } + } + ++ if (rdev->bss_entries >= bss_entries_limit && ++ !cfg80211_bss_expire_oldest(rdev)) { ++ kfree(new); ++ goto drop; ++ } ++ + list_add_tail(&new->list, &rdev->bss_list); ++ rdev->bss_entries++; + rb_insert_bss(rdev, new); + found = new; + } +diff --git a/net/wireless/sme.c b/net/wireless/sme.c +index 8020b5b0..18b4a652 100644 +--- a/net/wireless/sme.c ++++ b/net/wireless/sme.c +@@ -39,6 +39,7 @@ struct cfg80211_conn { + CFG80211_CONN_ASSOCIATING, + CFG80211_CONN_ASSOC_FAILED, + CFG80211_CONN_DEAUTH, ++ CFG80211_CONN_ABANDON, + CFG80211_CONN_CONNECTED, + } state; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; +@@ -204,6 +205,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) + cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, + NULL, 0, + WLAN_REASON_DEAUTH_LEAVING, false); ++ /* fall through */ ++ case CFG80211_CONN_ABANDON: + /* free directly, disconnected event already sent */ + cfg80211_sme_free(wdev); + return 0; +@@ -423,6 +426,17 @@ void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) + schedule_work(&rdev->conn_work); + } + ++void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev) ++{ ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); ++ ++ if (!wdev->conn) ++ return; ++ ++ wdev->conn->state = CFG80211_CONN_ABANDON; ++ schedule_work(&rdev->conn_work); ++} ++ + static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev, + const u8 *ies, size_t ies_len, + const u8 **out_ies, size_t *out_ies_len) +diff --git a/net/wireless/util.c b/net/wireless/util.c +index baf7218c..1d239564 100644 +--- a/net/wireless/util.c ++++ b/net/wireless/util.c +@@ -1360,7 +1360,7 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, + u8 *op_class) + { + u8 vht_opclass; +- u16 freq = chandef->center_freq1; ++ u32 freq = chandef->center_freq1; + + if (freq >= 2412 && freq <= 2472) { + if (chandef->width > NL80211_CHAN_WIDTH_40) +-- +2.17.1 + diff --git a/package/kernel/patches/gfutures/0012-move-default-dialect-to-SMB3.patch b/package/kernel/patches/gfutures/0012-move-default-dialect-to-SMB3.patch new file mode 100644 index 00000000..4243c8c0 --- /dev/null +++ b/package/kernel/patches/gfutures/0012-move-default-dialect-to-SMB3.patch @@ -0,0 +1,36 @@ +[SMB3] Improve security, move default dialect to SMB3 from old CIFS +Due to recent publicity about security vulnerabilities in the +much older CIFS dialect, move the default dialect to the +widely accepted (and quite secure) SMB3.0 dialect from the +old default of the CIFS dialect. + +We do not want to be encouraging use of less secure dialects, +and both Microsoft and CERT now strongly recommend not using the +older CIFS dialect (SMB Security Best Practices +"recommends disabling SMBv1"). + +SMB3 is both secure and widely available: in Windows 8 and later, +Samba and Macs. + +Users can still choose to explicitly mount with the less secure +dialect (for old servers) by choosing "vers=1.0" on the cifs +mount + +Signed-off-by: Steve French +Reviewed-by: Pavel Shilovsky + +--- a/fs/cifs/connect.c 2019-10-19 09:34:13.448215659 +0200 ++++ b/fs/cifs/connect.c 2019-10-19 09:41:22.938494534 +0200 +@@ -1274,9 +1274,9 @@ + + vol->actimeo = CIFS_DEF_ACTIMEO; + +- /* FIXME: add autonegotiation -- for now, SMB1 is default */ +- vol->ops = &smb1_operations; +- vol->vals = &smb1_values; ++ /* FIXME: add autonegotiation for SMB3 or later rather than just SMB3 */ ++ vol->ops = &smb30_operations; /* both secure and accepted widely */ ++ vol->vals = &smb302_values; + + if (!mountdata) + goto cifs_parse_mount_err; diff --git a/package/kernel/patches/gfutures/0013-modules_mark__inittest__exittest_as__maybe_unused.patch b/package/kernel/patches/gfutures/0013-modules_mark__inittest__exittest_as__maybe_unused.patch new file mode 100644 index 00000000..8b3a33a5 --- /dev/null +++ b/package/kernel/patches/gfutures/0013-modules_mark__inittest__exittest_as__maybe_unused.patch @@ -0,0 +1,50 @@ +From 89134f0918ec3bf4614ac2f9258543940e611f01 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Wed, 1 Feb 2017 18:00:14 +0100 +Subject: modules: mark __inittest/__exittest as __maybe_unused + +commit 1f318a8bafcfba9f0d623f4870c4e890fd22e659 upstream. + +clang warns about unused inline functions by default: + +arch/arm/crypto/aes-cipher-glue.c:68:1: warning: unused function '__inittest' [-Wunused-function] +arch/arm/crypto/aes-cipher-glue.c:69:1: warning: unused function '__exittest' [-Wunused-function] + +As these appear in every single module, let's just disable the warnings by marking the +two functions as __maybe_unused. + +Signed-off-by: Arnd Bergmann +Reviewed-by: Miroslav Benes +Acked-by: Rusty Russell +Signed-off-by: Jessica Yu +Signed-off-by: Nathan Chancellor +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/module.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +(limited to 'include/linux/module.h') + +diff --git a/include/linux/module.h b/include/linux/module.h +index c9f2f85017ad..dfe5c2e25ba1 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -125,13 +125,13 @@ extern void cleanup_module(void); + + /* Each module must use one module_init(). */ + #define module_init(initfn) \ +- static inline initcall_t __inittest(void) \ ++ static inline initcall_t __maybe_unused __inittest(void) \ + { return initfn; } \ + int init_module(void) __attribute__((alias(#initfn))); + + /* This is only required if you want to be unloadable. */ + #define module_exit(exitfn) \ +- static inline exitcall_t __exittest(void) \ ++ static inline exitcall_t __maybe_unused __exittest(void) \ + { return exitfn; } \ + void cleanup_module(void) __attribute__((alias(#exitfn))); + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/package/kernel/patches/gfutures/0014-includelinuxmodule_h_copy__init__exit_attrs_to_initcleanup_module.patch b/package/kernel/patches/gfutures/0014-includelinuxmodule_h_copy__init__exit_attrs_to_initcleanup_module.patch new file mode 100644 index 00000000..0fa0e041 --- /dev/null +++ b/package/kernel/patches/gfutures/0014-includelinuxmodule_h_copy__init__exit_attrs_to_initcleanup_module.patch @@ -0,0 +1,84 @@ +From 170051d60cf08f9ae2cf296fb8410afdf56a911f Mon Sep 17 00:00:00 2001 +From: Miguel Ojeda +Date: Sat, 19 Jan 2019 20:59:34 +0100 +Subject: include/linux/module.h: copy __init/__exit attrs to + init/cleanup_module + +[ Upstream commit a6e60d84989fa0e91db7f236eda40453b0e44afa ] + +The upcoming GCC 9 release extends the -Wmissing-attributes warnings +(enabled by -Wall) to C and aliases: it warns when particular function +attributes are missing in the aliases but not in their target. + +In particular, it triggers for all the init/cleanup_module +aliases in the kernel (defined by the module_init/exit macros), +ending up being very noisy. + +These aliases point to the __init/__exit functions of a module, +which are defined as __cold (among other attributes). However, +the aliases themselves do not have the __cold attribute. + +Since the compiler behaves differently when compiling a __cold +function as well as when compiling paths leading to calls +to __cold functions, the warning is trying to point out +the possibly-forgotten attribute in the alias. + +In order to keep the warning enabled, we decided to silence +this case. Ideally, we would mark the aliases directly +as __init/__exit. However, there are currently around 132 modules +in the kernel which are missing __init/__exit in their init/cleanup +functions (either because they are missing, or for other reasons, +e.g. the functions being called from somewhere else); and +a section mismatch is a hard error. + +A conservative alternative was to mark the aliases as __cold only. +However, since we would like to eventually enforce __init/__exit +to be always marked, we chose to use the new __copy function +attribute (introduced by GCC 9 as well to deal with this). +With it, we copy the attributes used by the target functions +into the aliases. This way, functions that were not marked +as __init/__exit won't have their aliases marked either, +and therefore there won't be a section mismatch. + +Note that the warning would go away marking either the extern +declaration, the definition, or both. However, we only mark +the definition of the alias, since we do not want callers +(which only see the declaration) to be compiled as if the function +was __cold (and therefore the paths leading to those calls +would be assumed to be unlikely). + +Link: https://lore.kernel.org/lkml/20190123173707.GA16603@gmail.com/ +Link: https://lore.kernel.org/lkml/20190206175627.GA20399@gmail.com/ +Suggested-by: Martin Sebor +Acked-by: Jessica Yu +Signed-off-by: Miguel Ojeda +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +(limited to 'include/linux/module.h') + +diff --git a/include/linux/module.h b/include/linux/module.h +index dfe5c2e25ba1..d237d0574179 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -127,13 +127,13 @@ extern void cleanup_module(void); + #define module_init(initfn) \ + static inline initcall_t __maybe_unused __inittest(void) \ + { return initfn; } \ +- int init_module(void) __attribute__((alias(#initfn))); ++ int init_module(void) __copy(initfn) __attribute__((alias(#initfn))); + + /* This is only required if you want to be unloadable. */ + #define module_exit(exitfn) \ + static inline exitcall_t __maybe_unused __exittest(void) \ + { return exitfn; } \ +- void cleanup_module(void) __attribute__((alias(#exitfn))); ++ void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn))); + + #endif + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/package/kernel/patches/gfutures/0015-Backport_minimal_compiler_attributes_h_to_support_GCC_9.patch b/package/kernel/patches/gfutures/0015-Backport_minimal_compiler_attributes_h_to_support_GCC_9.patch new file mode 100644 index 00000000..5cb57cb1 --- /dev/null +++ b/package/kernel/patches/gfutures/0015-Backport_minimal_compiler_attributes_h_to_support_GCC_9.patch @@ -0,0 +1,51 @@ +From edc966de8725f9186cc9358214da89d335f0e0bd Mon Sep 17 00:00:00 2001 +From: Miguel Ojeda +Date: Fri, 2 Aug 2019 12:37:56 +0200 +Subject: Backport minimal compiler_attributes.h to support GCC 9 + +This adds support for __copy to v4.9.y so that we can use it in +init/exit_module to avoid -Werror=missing-attributes errors on GCC 9. + +Link: https://lore.kernel.org/lkml/259986242.BvXPX32bHu@devpool35/ +Cc: +Suggested-by: Rolf Eike Beer +Signed-off-by: Miguel Ojeda +Signed-off-by: Greg Kroah-Hartman + +Signed-off-by: Sasha Levin +--- + include/linux/compiler.h | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +(limited to 'include/linux') + +diff --git a/include/linux/compiler.h b/include/linux/compiler.h +index ed772311ec1f..5508011cc0c7 100644 +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -52,6 +52,22 @@ extern void __chk_io_ptr(const volatile void __iomem *); + + #ifdef __KERNEL__ + ++/* ++ * Minimal backport of compiler_attributes.h to add support for __copy ++ * to v4.9.y so that we can use it in init/exit_module to avoid ++ * -Werror=missing-attributes errors on GCC 9. ++ */ ++#ifndef __has_attribute ++# define __has_attribute(x) __GCC4_has_attribute_##x ++# define __GCC4_has_attribute___copy__ 0 ++#endif ++ ++#if __has_attribute(__copy__) ++# define __copy(symbol) __attribute__((__copy__(symbol))) ++#else ++# define __copy(symbol) ++#endif ++ + #ifdef __GNUC__ + #include + #endif +-- +cgit 1.2-0.3.lf.el7 + diff --git a/package/kernel/patches/gfutures/0016-mn88472_reset_stream_ID_reg_if_no_PLP_given.patch b/package/kernel/patches/gfutures/0016-mn88472_reset_stream_ID_reg_if_no_PLP_given.patch new file mode 100644 index 00000000..f47fcce4 --- /dev/null +++ b/package/kernel/patches/gfutures/0016-mn88472_reset_stream_ID_reg_if_no_PLP_given.patch @@ -0,0 +1,33 @@ +From 07d45a42fa21b54d83e563565699d25bde9f8cbe Mon Sep 17 00:00:00 2001 +From: Olli Salonen +Date: Sun, 30 Jul 2017 08:34:48 -0400 +Subject: media: mn88472: reset stream ID reg if no PLP given + +If the PLP given is NO_STREAM_ID_FILTER (~0u) don't try to set that into the PLP register. Set PLP to 0 instead. + +Signed-off-by: Olli Salonen +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/dvb-frontends/mn88472.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +(limited to 'drivers/media/dvb-frontends/mn88472.c') + +diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c +index f6938f9607ac..5e8fd63832e9 100644 +--- a/drivers/staging/media/mn88472/mn88472.c ++++ b/drivers/staging/media/mn88472/mn88472.c +@@ -255,7 +255,9 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) + ret = regmap_write(dev->regmap[1], 0xf6, 0x05); + if (ret) + goto err; +- ret = regmap_write(dev->regmap[2], 0x32, c->stream_id); ++ ret = regmap_write(dev->regmap[2], 0x32, ++ (c->stream_id == NO_STREAM_ID_FILTER) ? 0 : ++ c->stream_id ); + if (ret) + goto err; + break; +-- +cgit 1.2.3-1.el7 + diff --git a/package/kernel/patches/gfutures/4_4_ieee80211-increase-scan-result-expire-time.patch b/package/kernel/patches/gfutures/4_4_ieee80211-increase-scan-result-expire-time.patch deleted file mode 100644 index 1ea4cdbd..00000000 --- a/package/kernel/patches/gfutures/4_4_ieee80211-increase-scan-result-expire-time.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/wireless/scan.c -+++ b/net/wireless/scan.c -@@ -56,7 +56,7 @@ - * also linked into the probe response struct. - */ - --#define IEEE80211_SCAN_RESULT_EXPIRE (7 * HZ) -+#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) - - static void bss_free(struct cfg80211_internal_bss *bss) - {