diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Kconfig | 58 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ahb.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_aic.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_hw.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c | 214 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/dynack.c | 101 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_init.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_hst.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/wmi.c | 1 |
16 files changed, 355 insertions, 73 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 5601cfd6a293..78620c6b64a2 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -144,34 +144,50 @@ config ATH9K_RFKILL a platform that can toggle the RF-Kill GPIO. config ATH9K_CHANNEL_CONTEXT - bool "Channel Context support" - depends on ATH9K - default n - ---help--- - This option enables channel context support in ath9k, which is needed - for multi-channel concurrency. Enable this if P2P PowerSave support - is required. + bool "Channel Context support" + depends on ATH9K + default n + ---help--- + This option enables channel context support in ath9k, which is needed + for multi-channel concurrency. Enable this if P2P PowerSave support + is required. config ATH9K_PCOEM bool "Atheros ath9k support for PC OEM cards" if EXPERT depends on ATH9K default y +config ATH9K_PCI_NO_EEPROM + tristate "Atheros ath9k pci loader for EEPROM-less chips" + depends on ATH9K_PCI + default n + help + This separate driver provides a loader in order to support the + AR500X to AR92XX-generation of ath9k PCI(e) WiFi chips, which have + their initialization data (which contains the real PCI Device ID + that ath9k will need) stored together with the calibration data out + of reach for the ath9k chip. + + These devices are usually various network appliances, routers or + access Points and such. + + If unsure say N. + config ATH9K_HTC - tristate "Atheros HTC based wireless cards support" - depends on USB && MAC80211 - select ATH9K_HW - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - select ATH9K_COMMON - ---help--- - Support for Atheros HTC based cards. - Chipsets supported: AR9271 - - For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc - - The built module will be ath9k_htc. + tristate "Atheros HTC based wireless cards support" + depends on USB && MAC80211 + select ATH9K_HW + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS + select ATH9K_COMMON + ---help--- + Support for Atheros HTC based cards. + Chipsets supported: AR9271 + + For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc + + The built module will be ath9k_htc. config ATH9K_HTC_DEBUGFS bool "Atheros ath9k_htc debugging" diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 15af0a836925..eff94bcd1f0a 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -77,3 +77,5 @@ ath9k_htc-y += htc_hst.o \ ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o + +obj-$(CONFIG_ATH9K_PCI_NO_EEPROM) += ath9k_pci_owl_loader.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 63019c3de034..cdefb8e2daf1 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -92,7 +92,7 @@ static int ath_ahb_probe(struct platform_device *pdev) return -ENXIO; } - mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); + mem = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (mem == NULL) { dev_err(&pdev->dev, "ioremap failed\n"); return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 547cd46da260..d0f1e8bcc846 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -406,7 +406,7 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) sram.com_att_6db = ar9003_aic_find_index(1, fixed_com_att_db); - sram.valid = 1; + sram.valid = true; sram.rot_dir_att_db = min(max(rot_dir_path_att_db, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 2b29bf4730f6..b4885a700296 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4183,7 +4183,7 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah) static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah) { - u32 data, ko, kg; + u32 data = 0, ko, kg; if (!AR_SREV_9462_20_OR_LATER(ah)) return; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 2fe12b0de5b4..42f00a2a8c80 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -1037,7 +1037,7 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, } /* - * Configire PCIE after Ini init. SERDES values now come from ini file + * Configure PCIE after Ini init. SERDES values now come from ini file * This enables PCIe low power mode. */ array = power_off ? &ah->iniPcieSerdes : diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c new file mode 100644 index 000000000000..56d1a7764b9f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: ISC +/* Initialize Owl Emulation Devices + * + * Copyright (C) 2016 Christian Lamparter <chunkeey@gmail.com> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * + * Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway) + * need to be able to initialize the PCIe wifi device. Normally, this is done + * during the early stages as a pci quirk. + * However, this isn't possible for devices which have the init code for the + * Atheros chip stored on UBI Volume on NAND. Hence, this module can be used to + * initialize the chip when the user-space is ready to extract the init code. + */ +#include <linux/module.h> +#include <linux/completion.h> +#include <linux/etherdevice.h> +#include <linux/firmware.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/ath9k_platform.h> + +struct owl_ctx { + struct completion eeprom_load; +}; + +#define EEPROM_FILENAME_LEN 100 + +#define AR5416_EEPROM_MAGIC 0xa55a + +static int ath9k_pci_fixup(struct pci_dev *pdev, const u16 *cal_data, + size_t cal_len) +{ + void __iomem *mem; + const void *cal_end = (void *)cal_data + cal_len; + const struct { + u16 reg; + u16 low_val; + u16 high_val; + } __packed * data; + u16 cmd; + u32 bar0; + bool swap_needed = false; + + if (*cal_data != AR5416_EEPROM_MAGIC) { + if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) { + dev_err(&pdev->dev, "invalid calibration data\n"); + return -EINVAL; + } + + dev_dbg(&pdev->dev, "calibration data needs swapping\n"); + swap_needed = true; + } + + dev_info(&pdev->dev, "fixup device configuration\n"); + + mem = pcim_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "ioremap error\n"); + return -EINVAL; + } + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, + pci_resource_start(pdev, 0)); + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + /* set pointer to first reg address */ + for (data = (const void *)(cal_data + 3); + (const void *)data <= cal_end && data->reg != (u16)~0; + data++) { + u32 val; + u16 reg; + + reg = data->reg; + val = data->low_val; + val |= ((u32)data->high_val) << 16; + + if (swap_needed) { + reg = swab16(reg); + val = swahb32(val); + } + + iowrite32(val, mem + reg); + usleep_range(100, 120); + } + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, bar0); + pcim_iounmap(pdev, mem); + + pci_disable_device(pdev); + + return 0; +} + +static void owl_fw_cb(const struct firmware *fw, void *context) +{ + struct pci_dev *pdev = (struct pci_dev *)context; + struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev); + struct pci_bus *bus; + + complete(&ctx->eeprom_load); + + if (!fw) { + dev_err(&pdev->dev, "no eeprom data received.\n"); + goto release; + } + + /* also note that we are doing *u16 operations on the file */ + if (fw->size > 4096 || fw->size < 0x200 || (fw->size & 1) == 1) { + dev_err(&pdev->dev, "eeprom file has an invalid size.\n"); + goto release; + } + + if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size)) + goto release; + + pci_lock_rescan_remove(); + bus = pdev->bus; + pci_stop_and_remove_bus_device(pdev); + /* the device should come back with the proper + * ProductId. But we have to initiate a rescan. + */ + pci_rescan_bus(bus); + pci_unlock_rescan_remove(); + +release: + release_firmware(fw); +} + +static const char *owl_get_eeprom_name(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + char *eeprom_name; + + dev_dbg(dev, "using auto-generated eeprom filename\n"); + + eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL); + if (!eeprom_name) + return NULL; + + /* this should match the pattern used in ath9k/init.c */ + scnprintf(eeprom_name, EEPROM_FILENAME_LEN, "ath9k-eeprom-pci-%s.bin", + dev_name(dev)); + + return eeprom_name; +} + +static int owl_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct owl_ctx *ctx; + const char *eeprom_name; + int err = 0; + + if (pcim_enable_device(pdev)) + return -EIO; + + pcim_pin_device(pdev); + + eeprom_name = owl_get_eeprom_name(pdev); + if (!eeprom_name) { + dev_err(&pdev->dev, "no eeprom filename found.\n"); + return -ENODEV; + } + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + init_completion(&ctx->eeprom_load); + + pci_set_drvdata(pdev, ctx); + err = request_firmware_nowait(THIS_MODULE, true, eeprom_name, + &pdev->dev, GFP_KERNEL, pdev, owl_fw_cb); + if (err) + dev_err(&pdev->dev, "failed to request caldata (%d).\n", err); + + return err; +} + +static void owl_remove(struct pci_dev *pdev) +{ + struct owl_ctx *ctx = pci_get_drvdata(pdev); + + if (ctx) { + wait_for_completion(&ctx->eeprom_load); + pci_set_drvdata(pdev, NULL); + } +} + +static const struct pci_device_id owl_pci_table[] = { + { PCI_VDEVICE(ATHEROS, 0xff1c) }, /* PCIe */ + { PCI_VDEVICE(ATHEROS, 0xff1d) }, /* PCI */ + { }, +}; +MODULE_DEVICE_TABLE(pci, owl_pci_table); + +static struct pci_driver owl_driver = { + .name = KBUILD_MODNAME, + .id_table = owl_pci_table, + .probe = owl_probe, + .remove = owl_remove, +}; +module_pci_driver(owl_driver); +MODULE_AUTHOR("Christian Lamparter <chunkeey@gmail.com>"); +MODULE_DESCRIPTION("External EEPROM data loader for Atheros AR500X to AR92XX"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c index f112fa5b2eac..fbeb4a739d32 100644 --- a/drivers/net/wireless/ath/ath9k/dynack.c +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -20,12 +20,31 @@ #define COMPUTE_TO (5 * HZ) #define LATEACK_DELAY (10 * HZ) -#define LATEACK_TO 256 -#define MAX_DELAY 300 #define EWMA_LEVEL 96 #define EWMA_DIV 128 /** + * ath_dynack_get_max_to - set max timeout according to channel width + * @ah: ath hw + * + */ +static u32 ath_dynack_get_max_to(struct ath_hw *ah) +{ + const struct ath9k_channel *chan = ah->curchan; + + if (!chan) + return 300; + + if (IS_CHAN_HT40(chan)) + return 300; + if (IS_CHAN_HALF_RATE(chan)) + return 750; + if (IS_CHAN_QUARTER_RATE(chan)) + return 1500; + return 600; +} + +/** * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation * */ @@ -79,6 +98,24 @@ static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac) } /** + * ath_dynack_set_timeout - configure timeouts/slottime registers + * @ah: ath hw + * @to: timeout value + * + */ +static void ath_dynack_set_timeout(struct ath_hw *ah, int to) +{ + struct ath_common *common = ath9k_hw_common(ah); + int slottime = (to - 3) / 2; + + ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n", + to, slottime); + ath9k_hw_setslottime(ah, slottime); + ath9k_hw_set_ack_timeout(ah, to); + ath9k_hw_set_cts_timeout(ah, to); +} + +/** * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout * @ah: ath hw * @@ -86,7 +123,6 @@ static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac) */ static void ath_dynack_compute_ackto(struct ath_hw *ah) { - struct ath_common *common = ath9k_hw_common(ah); struct ath_dynack *da = &ah->dynack; struct ath_node *an; int to = 0; @@ -96,15 +132,8 @@ static void ath_dynack_compute_ackto(struct ath_hw *ah) to = an->ackto; if (to && da->ackto != to) { - u32 slottime; - - slottime = (to - 3) / 2; + ath_dynack_set_timeout(ah, to); da->ackto = to; - ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n", - da->ackto, slottime); - ath9k_hw_setslottime(ah, slottime); - ath9k_hw_set_ack_timeout(ah, da->ackto); - ath9k_hw_set_cts_timeout(ah, da->ackto); } } @@ -116,15 +145,16 @@ static void ath_dynack_compute_ackto(struct ath_hw *ah) */ static void ath_dynack_compute_to(struct ath_hw *ah) { - u32 ackto, ack_ts; - u8 *dst, *src; + struct ath_dynack *da = &ah->dynack; + u32 ackto, ack_ts, max_to; struct ieee80211_sta *sta; - struct ath_node *an; struct ts_info *st_ts; - struct ath_dynack *da = &ah->dynack; + struct ath_node *an; + u8 *dst, *src; rcu_read_lock(); + max_to = ath_dynack_get_max_to(ah); while (da->st_rbf.h_rb != da->st_rbf.t_rb && da->ack_rbf.h_rb != da->ack_rbf.t_rb) { ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb]; @@ -140,7 +170,7 @@ static void ath_dynack_compute_to(struct ath_hw *ah) if (ack_ts > st_ts->tstamp + st_ts->dur) { ackto = ack_ts - st_ts->tstamp - st_ts->dur; - if (ackto < MAX_DELAY) { + if (ackto < max_to) { sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst, src); if (sta) { @@ -197,11 +227,10 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, if (ieee80211_is_assoc_req(hdr->frame_control) || ieee80211_is_assoc_resp(hdr->frame_control) || ieee80211_is_auth(hdr->frame_control)) { - ath_dbg(common, DYNACK, "late ack\n"); + u32 max_to = ath_dynack_get_max_to(ah); - ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2); - ath9k_hw_set_ack_timeout(ah, LATEACK_TO); - ath9k_hw_set_cts_timeout(ah, LATEACK_TO); + ath_dbg(common, DYNACK, "late ack\n"); + ath_dynack_set_timeout(ah, max_to); if (sta) { struct ath_node *an; @@ -292,15 +321,13 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts); */ void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) { - /* ackto = slottime + sifs + air delay */ - u32 ackto = 9 + 16 + 64; struct ath_dynack *da = &ah->dynack; - an->ackto = ackto; + an->ackto = da->ackto; - spin_lock(&da->qlock); + spin_lock_bh(&da->qlock); list_add_tail(&an->list, &da->nodes); - spin_unlock(&da->qlock); + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_node_init); @@ -314,9 +341,9 @@ void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) { struct ath_dynack *da = &ah->dynack; - spin_lock(&da->qlock); + spin_lock_bh(&da->qlock); list_del(&an->list); - spin_unlock(&da->qlock); + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_node_deinit); @@ -327,22 +354,26 @@ EXPORT_SYMBOL(ath_dynack_node_deinit); */ void ath_dynack_reset(struct ath_hw *ah) { - /* ackto = slottime + sifs + air delay */ - u32 ackto = 9 + 16 + 64; struct ath_dynack *da = &ah->dynack; + struct ath_node *an; + + spin_lock_bh(&da->qlock); - da->lto = jiffies; - da->ackto = ackto; + da->lto = jiffies + COMPUTE_TO; da->st_rbf.t_rb = 0; da->st_rbf.h_rb = 0; da->ack_rbf.t_rb = 0; da->ack_rbf.h_rb = 0; + da->ackto = ath_dynack_get_max_to(ah); + list_for_each_entry(an, &da->nodes, list) + an->ackto = da->ackto; + /* init acktimeout */ - ath9k_hw_setslottime(ah, (ackto - 3) / 2); - ath9k_hw_set_ack_timeout(ah, ackto); - ath9k_hw_set_cts_timeout(ah, ackto); + ath_dynack_set_timeout(ah, da->ackto); + + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_reset); @@ -359,6 +390,8 @@ void ath_dynack_init(struct ath_hw *ah) spin_lock_init(&da->qlock); INIT_LIST_HEAD(&da->nodes); + /* ackto = slottime + sifs + air delay */ + da->ackto = 9 + 16 + 64; ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION; } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index fb649d85b8fc..dd0c32379375 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1216,7 +1216,7 @@ err_fw: static int send_eject_command(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc = &interface->altsetting[0]; + struct usb_host_interface *iface_desc = interface->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 214c68269a69..d961095ab01f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -463,7 +463,7 @@ static void ath9k_enable_rmw_buffer(void *hw_priv) atomic_inc(&priv->wmi->m_rmw_cnt); } -static u32 ath9k_reg_rmw_single(void *hw_priv, +static void ath9k_reg_rmw_single(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { struct ath_hw *ah = hw_priv; @@ -471,7 +471,6 @@ static u32 ath9k_reg_rmw_single(void *hw_priv, struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; struct register_rmw buf, buf_ret; int ret; - u32 val = 0; buf.reg = cpu_to_be32(reg_offset); buf.set = cpu_to_be32(set); @@ -485,7 +484,6 @@ static u32 ath9k_reg_rmw_single(void *hw_priv, ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n", reg_offset, ret); } - return val; } static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index a82ad739ab80..791f6633667c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1674,7 +1674,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid); if (!ret) - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 4e8e80ac8341..9cec5c216e1f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -973,6 +973,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ath_htc_rx_status *rxstatus; struct ath_rx_status rx_stats; bool decrypt_error = false; + __be16 rs_datalen; + bool is_phyerr; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -982,11 +984,24 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rxstatus = (struct ath_htc_rx_status *)skb->data; - if (be16_to_cpu(rxstatus->rs_datalen) - - (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { + rs_datalen = be16_to_cpu(rxstatus->rs_datalen); + if (unlikely(rs_datalen - + (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) { ath_err(common, "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", - rxstatus->rs_datalen, skb->len); + rs_datalen, skb->len); + goto rx_next; + } + + is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY; + /* + * Discard zero-length packets and packets smaller than an ACK + * which are not PHY_ERROR (short radar pulses have a length of 3) + */ + if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) { + ath_warn(common, + "Short RX data len, dropping (dlen: %d)\n", + rs_datalen); goto rx_next; } @@ -1011,7 +1026,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, * Process PHY errors and return so that the packet * can be dropped. */ - if (rx_stats.rs_status & ATH9K_RXERR_PHY) { + if (unlikely(is_phyerr)) { /* TODO: Not using DFS processing now. */ if (ath_cmn_process_fft(&priv->spec_priv, hdr, &rx_stats, rx_status->mactime)) { diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 1bf63a4efb4c..d091c8ebdcf0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -170,6 +170,7 @@ static int htc_config_pipe_credits(struct htc_target *target) time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); if (!time_left) { dev_err(target->dev, "HTC credit config timeout\n"); + kfree_skb(skb); return -ETIMEDOUT; } @@ -205,6 +206,7 @@ static int htc_setup_complete(struct htc_target *target) time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); if (!time_left) { dev_err(target->dev, "HTC start timeout\n"); + kfree_skb(skb); return -ETIMEDOUT; } @@ -277,6 +279,7 @@ int htc_connect_service(struct htc_target *target, if (!time_left) { dev_err(target->dev, "Service connection timeout for: %d\n", service_connreq->service_id); + kfree_skb(skb); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f23cb2f3d296..0548aa3702e3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1921,7 +1921,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: @@ -2392,7 +2392,8 @@ out: return ret; } -static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) +static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 92b2dd396436..f3461b193c7a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -1021,13 +1021,12 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = dev_get_drvdata(device); struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { - dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); + dev_info(device, "WOW is enabled, bypassing PCI suspend\n"); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index d1f6710ca63b..cdc146091194 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -336,6 +336,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", wmi_cmd_to_name(cmd_id)); mutex_unlock(&wmi->op_mutex); + kfree_skb(skb); return -ETIMEDOUT; } |